diff --git a/CustomRoles.cs b/CustomRoles.cs
index 9e2761f72..ff5d1d6f8 100644
--- a/CustomRoles.cs
+++ b/CustomRoles.cs
@@ -69,6 +69,7 @@ public enum CustomRoles
Assassin, // Ninja
Nuker,
Nullifier,
+ Overheat,
Parasite,
Penguin,
Puppeteer,
@@ -344,6 +345,7 @@ public enum CustomRoles
DeadlyQuota,
Disco,
Diseased,
+ Dynamo,
Unreportable, // Disregarded
DoubleShot,
Egoist,
diff --git a/GameMode/CustomHideAndSeekManager.cs b/GameMode/CustomHideAndSeekManager.cs
index 805107b5f..73d31f602 100644
--- a/GameMode/CustomHideAndSeekManager.cs
+++ b/GameMode/CustomHideAndSeekManager.cs
@@ -86,22 +86,28 @@ namespace EHR
if (allPlayers.Count == 0) return;
+ int neutralNum = IRandom.Instance.Next(MinNeutrals.GetInt(), MaxNeutrals.GetInt() + 1);
+ int assignedCount = 0;
bool stop = false;
foreach (var role in HideAndSeekRoles)
{
+ int mode = role.Key.GetMode();
+ if (IRandom.Instance.Next(100) >= mode) continue;
+
for (int i = 0; i < role.Value; i++)
{
var pc = allPlayers[0];
result[pc] = role.Key;
allPlayers.Remove(pc);
+ assignedCount++;
- if (allPlayers.Count == 0)
+ if (allPlayers.Count == 0 || assignedCount >= neutralNum)
{
stop = true;
break;
}
- if (IRandom.Instance.Next(100) >= role.Key.GetMode()) break;
+ if (IRandom.Instance.Next(100) >= mode) break;
}
if (stop) break;
diff --git a/Modules/CustomRolesHelper.cs b/Modules/CustomRolesHelper.cs
index 332b92ce3..aa8b8f671 100644
--- a/Modules/CustomRolesHelper.cs
+++ b/Modules/CustomRolesHelper.cs
@@ -96,6 +96,7 @@ internal static class CustomRolesHelper
CustomRoles.Dictator => CustomRoles.Crewmate,
CustomRoles.Inhibitor => CustomRoles.Impostor,
CustomRoles.Kidnapper => CustomRoles.Shapeshifter,
+ CustomRoles.Overheat => UsePets ? CustomRoles.Impostor : CustomRoles.Shapeshifter,
CustomRoles.Generator => CustomRoles.Shapeshifter,
CustomRoles.Blackmailer => CustomRoles.Impostor,
CustomRoles.Commander => CustomRoles.Shapeshifter,
@@ -539,6 +540,7 @@ internal static class CustomRolesHelper
CustomRoles.Miner or
CustomRoles.Escapee or
CustomRoles.SerialKiller or
+ CustomRoles.Overheat or
CustomRoles.Underdog or
CustomRoles.Inhibitor or
CustomRoles.Kidnapper or
diff --git a/Modules/ExtendedPlayerControl.cs b/Modules/ExtendedPlayerControl.cs
index beb3beee6..4f54086c4 100644
--- a/Modules/ExtendedPlayerControl.cs
+++ b/Modules/ExtendedPlayerControl.cs
@@ -998,14 +998,6 @@ static class ExtendedPlayerControl
public static bool Is(this PlayerControl target, CustomRoles role) =>
role > CustomRoles.NotAssigned ? target.GetCustomSubRoles().Contains(role) : target.GetCustomRole() == role;
- ///
- /// Determines whether the player has the specified role class. Doesn't work with subroles.
- ///
- /// The player to check
- /// The type of role class
- /// True, if the player has the specified role class, otherwise, false. This method returns false if the player to check doesn't have a PlayerState assigned.
- public static bool Is(this PlayerControl target, RoleBase role) => Main.PlayerStates.TryGetValue(target.PlayerId, out var state) && state.Role.GetType() == role.GetType();
-
public static bool Is(this PlayerControl target, CustomRoleTypes type) => target.GetCustomRoleTypes() == type;
public static bool Is(this PlayerControl target, RoleTypes type) => (target.Is(CustomRoles.Bloodlust) && type == RoleTypes.Impostor) || target.GetCustomRole().GetRoleTypes() == type;
public static bool Is(this PlayerControl target, CountTypes type) => target.GetCountTypes() == type;
diff --git a/Modules/NameNotifyManager.cs b/Modules/NameNotifyManager.cs
index cc7381d6a..cf18dabac 100644
--- a/Modules/NameNotifyManager.cs
+++ b/Modules/NameNotifyManager.cs
@@ -42,8 +42,8 @@ public static class NameNotifyManager
public static bool GetNameNotify(PlayerControl player, out string name)
{
name = string.Empty;
- if (!Notice.ContainsKey(player.PlayerId)) return false;
- name = Notice[player.PlayerId].TEXT;
+ if (!Notice.TryGetValue(player.PlayerId, out (string TEXT, long TIMESTAMP) value)) return false;
+ name = value.TEXT;
return true;
}
diff --git a/Modules/Utils.cs b/Modules/Utils.cs
index 859b282f3..cdda76e7c 100644
--- a/Modules/Utils.cs
+++ b/Modules/Utils.cs
@@ -1862,6 +1862,9 @@ public static class Utils
case CustomRoles.Penguin:
SelfSuffix.Append(Penguin.GetSuffix(seer));
break;
+ case CustomRoles.Overheat:
+ SelfSuffix.Append(Overheat.GetSuffix(seer));
+ break;
case CustomRoles.BountyHunter:
SelfSuffix.Append(BountyHunter.GetTargetText(seer, false));
SelfSuffix.Append(BountyHunter.GetTargetArrow(seer));
@@ -2537,7 +2540,7 @@ public static class Utils
switch (target.GetCustomRole())
{
case CustomRoles.Terrorist:
- Logger.Info(target?.Data?.PlayerName + "はTerroristだった", "MurderPlayer");
+ Logger.Info(target?.Data?.PlayerName + "Terrorist died", "MurderPlayer");
CheckTerroristWin(target?.Data);
break;
case CustomRoles.Executioner:
diff --git a/Patches/ControlPatch.cs b/Patches/ControlPatch.cs
index c98fd3682..f03efac7b 100644
--- a/Patches/ControlPatch.cs
+++ b/Patches/ControlPatch.cs
@@ -14,10 +14,10 @@ namespace EHR;
internal class ControllerManagerUpdatePatch
{
private static readonly (int, int)[] Resolutions = [(480, 270), (640, 360), (800, 450), (1280, 720), (1600, 900), (1920, 1080)];
- private static int resolutionIndex;
+ private static int ResolutionIndex;
- public static List addDes = [];
- public static int addonIndex = -1;
+ private static List AddDes = [];
+ private static int AddonIndex = -1;
public static void Postfix( /*ControllerManager __instance*/)
{
@@ -30,11 +30,16 @@ internal class ControllerManagerUpdatePatch
for (var i = 0; i < 9; i++)
{
- if (ORGetKeysDown(KeyCode.Alpha1 + i, KeyCode.Keypad1 + i) && OptionShower.Pages.Count >= i + 1)
+ if (OrGetKeysDown(KeyCode.Alpha1 + i, KeyCode.Keypad1 + i) && OptionShower.Pages.Count >= i + 1)
OptionShower.CurrentPage = i;
}
}
+ if (GetKeysDown(KeyCode.LeftShift, KeyCode.LeftControl, KeyCode.X) && Main.CurrentMap == MapNames.Airship)
+ {
+ ExileController.Instance?.ReEnableGameplay();
+ }
+
if (GetKeysDown(KeyCode.LeftAlt, KeyCode.Return))
{
_ = new LateTask(SetResolutionManager.Postfix, 0.01f, "Fix Button Position");
@@ -66,13 +71,13 @@ internal class ControllerManagerUpdatePatch
var lp = PlayerControl.LocalPlayer;
if (Main.PlayerStates[lp.PlayerId].SubRoles.Count == 0) return;
- addDes = [];
+ AddDes = [];
foreach (var subRole in Main.PlayerStates[lp.PlayerId].SubRoles.Where(x => x is not CustomRoles.Charmed))
- addDes.Add(GetString($"{subRole}") + Utils.GetRoleMode(subRole) + GetString($"{subRole}InfoLong"));
+ AddDes.Add(GetString($"{subRole}") + Utils.GetRoleMode(subRole) + GetString($"{subRole}InfoLong"));
- addonIndex++;
- if (addonIndex >= addDes.Count) addonIndex = 0;
- HudManager.Instance.ShowPopUp(addDes[addonIndex]);
+ AddonIndex++;
+ if (AddonIndex >= AddDes.Count) AddonIndex = 0;
+ HudManager.Instance.ShowPopUp(AddDes[AddonIndex]);
}
catch (Exception ex)
{
@@ -83,9 +88,9 @@ internal class ControllerManagerUpdatePatch
if (Input.GetKeyDown(KeyCode.F11))
{
- resolutionIndex++;
- if (resolutionIndex >= Resolutions.Length) resolutionIndex = 0;
- ResolutionManager.SetResolution(Resolutions[resolutionIndex].Item1, Resolutions[resolutionIndex].Item2, false);
+ ResolutionIndex++;
+ if (ResolutionIndex >= Resolutions.Length) ResolutionIndex = 0;
+ ResolutionManager.SetResolution(Resolutions[ResolutionIndex].Item1, Resolutions[ResolutionIndex].Item2, false);
SetResolutionManager.Postfix();
}
@@ -135,13 +140,12 @@ internal class ControllerManagerUpdatePatch
if (Input.GetKeyDown(KeyCode.LeftShift) && GameStates.IsCountDown && !HudManager.Instance.Chat.IsOpenOrOpening)
{
- Logger.Info("倒计时修改为0", "KeyCommand");
+ Logger.Info("Countdown timer set to 0", "KeyCommand");
GameStartManager.Instance.countDownTimer = 0;
}
if (Input.GetKeyDown(KeyCode.C) && GameStates.IsCountDown)
{
- Logger.Info("重置倒计时", "KeyCommand");
GameStartManager.Instance.ResetStartState();
Logger.SendInGame(GetString("CancelStartCountDown"));
}
@@ -286,7 +290,7 @@ internal class ControllerManagerUpdatePatch
return false;
}
- private static bool ORGetKeysDown(params KeyCode[] keys) => keys.Any(Input.GetKeyDown);
+ private static bool OrGetKeysDown(params KeyCode[] keys) => keys.Any(Input.GetKeyDown);
}
[HarmonyPatch(typeof(ConsoleJoystick), nameof(ConsoleJoystick.HandleHUD))]
@@ -307,7 +311,7 @@ internal class KeyboardJoystickHandleHUDPatch
}
}
-internal class HandleHUDPatch
+internal static class HandleHUDPatch
{
public static void Postfix(Player player)
{
diff --git a/Patches/HudPatch.cs b/Patches/HudPatch.cs
index dc7011a49..d0a950875 100644
--- a/Patches/HudPatch.cs
+++ b/Patches/HudPatch.cs
@@ -396,12 +396,13 @@ class HudManagerPatch
CustomRoles.Mafioso => Mafioso.GetHUDText(player),
CustomRoles.Druid => Druid.GetHUDText(player),
CustomRoles.Rabbit => Rabbit.GetSuffix(player),
- CustomRoles.Predator => Predator.GetSuffixAndHudText(player, hud: true),
CustomRoles.Warlock => Warlock.GetSuffixAndHudText(player, hud: true),
CustomRoles.Commander => Commander.GetSuffixText(player, player, hud: true),
CustomRoles.Librarian => Librarian.GetSelfSuffixAndHudText(player.PlayerId),
- CustomRoles.PlagueDoctor => PlagueDoctor.GetLowerTextOthers(player, isForHud: true),
CustomRoles.Stealth => Stealth.GetSuffix(player, isHUD: true),
+ CustomRoles.Overheat => Overheat.GetSuffix(player),
+ CustomRoles.Predator => Predator.GetSuffixAndHudText(player, hud: true),
+ CustomRoles.PlagueDoctor => PlagueDoctor.GetLowerTextOthers(player, isForHud: true),
CustomRoles.Hookshot => Hookshot.SuffixText(player.PlayerId),
CustomRoles.Simon => Simon.GetSuffix(player, player, hud: true),
CustomRoles.Chemist => Chemist.GetSuffix(player, player, hud: true),
diff --git a/Patches/onGameStartedPatch.cs b/Patches/OnGameStartedPatch.cs
similarity index 97%
rename from Patches/onGameStartedPatch.cs
rename to Patches/OnGameStartedPatch.cs
index 2cb96653f..c1fff4e91 100644
--- a/Patches/onGameStartedPatch.cs
+++ b/Patches/OnGameStartedPatch.cs
@@ -544,6 +544,7 @@ internal class SelectRolesPatch
Stressed.Add();
Asthmatic.Add();
Circumvent.Add();
+ Dynamo.Add();
_ = new LateTask(CustomTeamManager.InitializeCustomTeamPlayers, 7f, log: false);
diff --git a/Patches/PlayerControlPatch.cs b/Patches/PlayerControlPatch.cs
index f1defd291..c0ef9cf08 100644
--- a/Patches/PlayerControlPatch.cs
+++ b/Patches/PlayerControlPatch.cs
@@ -1167,15 +1167,19 @@ class FixedUpdatePatch
Asthmatic.OnCheckPlayerPosition(player);
}
- if (!lowLoad && Main.PlayerStates.TryGetValue(playerId, out var playerState) && GameStates.IsInTask && player.IsAlive())
+ if (Main.PlayerStates.TryGetValue(playerId, out var playerState) && GameStates.IsInTask && player.IsAlive())
{
var subRoles = playerState.SubRoles;
- if (subRoles.Contains(CustomRoles.Damocles)) Damocles.Update(player);
- if (subRoles.Contains(CustomRoles.Stressed)) Stressed.Update(player);
- if (subRoles.Contains(CustomRoles.Asthmatic)) Asthmatic.OnFixedUpdate();
- if (subRoles.Contains(CustomRoles.Disco)) Disco.OnFixedUpdate(player);
- if (subRoles.Contains(CustomRoles.Clumsy)) Clumsy.OnFixedUpdate(player);
- if (subRoles.Contains(CustomRoles.Sonar)) Sonar.OnFixedUpdate(player);
+ if (subRoles.Contains(CustomRoles.Dynamo)) Dynamo.OnFixedUpdate(player);
+ if (!lowLoad)
+ {
+ if (subRoles.Contains(CustomRoles.Damocles)) Damocles.Update(player);
+ if (subRoles.Contains(CustomRoles.Stressed)) Stressed.Update(player);
+ if (subRoles.Contains(CustomRoles.Asthmatic)) Asthmatic.OnFixedUpdate();
+ if (subRoles.Contains(CustomRoles.Disco)) Disco.OnFixedUpdate(player);
+ if (subRoles.Contains(CustomRoles.Clumsy)) Clumsy.OnFixedUpdate(player);
+ if (subRoles.Contains(CustomRoles.Sonar)) Sonar.OnFixedUpdate(player);
+ }
}
if (GhostRolesManager.AssignedGhostRoles.TryGetValue(player.PlayerId, out var ghostRole))
diff --git a/Resources/Lang/en_US.json b/Resources/Lang/en_US.json
index e66f2576e..9c6a2bfbd 100644
--- a/Resources/Lang/en_US.json
+++ b/Resources/Lang/en_US.json
@@ -2645,12 +2645,25 @@
"Sentry.Notify.Shapeshifted": "{0} shapeshifted into {1} in your monitored room",
"Sentry.Notify.Vented": "{0} vented in your monitored room",
"Sentry.Notify.InvalidRoom": "You are not in a room",
+ "Dynamo": "Dynamo",
+ "DynamoInfo": "You get faster by walking",
+ "DynamoInfoLong": "(Add-ons):\\nAs the Dynamo, you get faster by walking. The longer you walk, the faster you get. Stopping will reset your speed.",
+ "Prefix.Dynamo": "Dynamo",
"Samurai": "Samurai",
"SamuraiInfo": "Kill Players in Unique Ways",
"SamuraiInfoLong": "(Neutrals):\\nAs the Samurai, you can do delayed kills and normal kills. What decides? Well, if you click your kill button on someone (the kill won't occur immediately) and you stay near them for a few seconds (like an arsonist douse), you get a lower kill cooldown and the kill will be delayed. If you fail to stay near them, you do a normal kill, lunge included.",
"Samurai.NearbyDuration": "Time to Stay Near Target",
"Samurai.SuccessKCD": "Kill Cooldown for Delayed Kills",
"Samurai.KillDelay": "Kill Delay",
+ "Overheat": "Overheat",
+ "OverheatInfo": "Hot = Low Kill Cooldown",
+ "OverheatInfoLong": "(Impostors):\\nAs the Overheat, your kill cooldown is based on your temperature. The more you wat, the hotter you get, and the lower your kill cooldown becomes, but your chance of overheating is also increasing. You can shapeshift or pet your pet to cool down to reset your temperature. This freezes you in place for a few seconds.",
+ "Overheat.Suffix": "Temperature: {0}",
+ "Overheat.ChanceIncrease": "Temperature Increase Rate",
+ "Overheat.ChanceIncreaseFrequency": "Temperature Increase Frequency",
+ "Overheat.RollChanceFrequency": "Frequency of Rolling for Overheat",
+ "Overheat.CoolDownTime": "Cool Down Time",
+ "Overheat.KCDDecreasePerIncreasedTemperature": "Kill Cooldown Decrease per Increased Temperature",
"QuizMaster": "Quiz Master",
"QuizMasterInfo": "Ask Questions to Players",
"QuizMasterInfoLong": "(Neutrals):\\nAs the Quiz Master, you can ask questions to players. If they answer correctly, nothing happens. If they answer incorrectly, they die.\\n\\nKill everyone to win!",
diff --git a/Roles/AddOns/Common/Dynamo.cs b/Roles/AddOns/Common/Dynamo.cs
new file mode 100644
index 000000000..48ee51d48
--- /dev/null
+++ b/Roles/AddOns/Common/Dynamo.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+
+namespace EHR.Roles.AddOns.Common
+{
+ public class Dynamo : IAddon
+ {
+ private static OptionItem IncreaseSpeedBy;
+ private static OptionItem IncreaseSpeedFrequency;
+
+ private static readonly Dictionary LastPosition = [];
+ private static readonly Dictionary StartingSpeed = [];
+ private static readonly Dictionary SpeedIncreaseTimer = [];
+ public AddonTypes Type => AddonTypes.Helpful;
+
+ public void SetupCustomOption()
+ {
+ const int id = 19392;
+ Options.SetupAdtRoleOptions(id, CustomRoles.Dynamo, canSetNum: true, teamSpawnOptions: true);
+ IncreaseSpeedBy = FloatOptionItem.Create(id + 6, "Dynamo.IncreaseSpeedBy", new(0.1f, 1f, 0.1f), 0.1f, TabGroup.CrewmateRoles)
+ .SetParent(Options.CustomRoleSpawnChances[CustomRoles.Dynamo])
+ .SetValueFormat(OptionFormat.Percent);
+ IncreaseSpeedFrequency = FloatOptionItem.Create(id + 7, "Dynamo.IncreaseSpeedFrequency", new(0.5f, 30f, 0.5f), 5f, TabGroup.CrewmateRoles)
+ .SetParent(Options.CustomRoleSpawnChances[CustomRoles.Dynamo])
+ .SetValueFormat(OptionFormat.Seconds);
+ }
+
+ public static void Add()
+ {
+ foreach ((PlayerControl pc, float speed) in Main.AllAlivePlayerControls.Zip(Main.AllPlayerSpeed.Values))
+ {
+ if (pc.Is(CustomRoles.Dynamo))
+ {
+ LastPosition[pc.PlayerId] = pc.Pos();
+ SpeedIncreaseTimer[pc.PlayerId] = -8f;
+ StartingSpeed[pc.PlayerId] = speed;
+ }
+ }
+ }
+
+ public static void OnFixedUpdate(PlayerControl pc)
+ {
+ var pos = pc.Pos();
+ bool moving = Vector2.Distance(pos, LastPosition[pc.PlayerId]) > 0.1f;
+ LastPosition[pc.PlayerId] = pos;
+
+ if (!moving || !pc.IsAlive() || !GameStates.IsInTask)
+ {
+ var speed = Main.AllPlayerSpeed[pc.PlayerId];
+ var defaultSpeed = StartingSpeed[pc.PlayerId];
+ if (Math.Abs(speed - defaultSpeed) > 0.1f)
+ {
+ Main.AllPlayerSpeed[pc.PlayerId] = defaultSpeed;
+ pc.MarkDirtySettings();
+ }
+
+ return;
+ }
+
+ SpeedIncreaseTimer[pc.PlayerId] += Time.fixedDeltaTime;
+ if (SpeedIncreaseTimer[pc.PlayerId] < IncreaseSpeedFrequency.GetFloat()) return;
+ SpeedIncreaseTimer[pc.PlayerId] = 0f;
+
+ Main.AllPlayerSpeed[pc.PlayerId] += IncreaseSpeedBy.GetFloat();
+ pc.MarkDirtySettings();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Roles/Crewmate/Goose.cs b/Roles/Crewmate/Goose.cs
index d75db7d0c..f57b62b9a 100644
--- a/Roles/Crewmate/Goose.cs
+++ b/Roles/Crewmate/Goose.cs
@@ -13,15 +13,15 @@
public void SetupCustomOption()
{
Options.SetupRoleOptions(Id, TabGroup.CrewmateRoles, CustomRoles.Goose);
- OptionAbductTimerLimit = FloatOptionItem.Create(Id + 11, "GooseAbductTimerLimit", new(1f, 20f, 1f), 10f, TabGroup.CrewmateRoles)
+ OptionAbductTimerLimit = FloatOptionItem.Create(Id + 11, "PenguinAbductTimerLimit", new(1f, 20f, 1f), 10f, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Goose])
.SetValueFormat(OptionFormat.Seconds);
- OptionMeetingKill = BooleanOptionItem.Create(Id + 12, "GooseMeetingKill", false, TabGroup.CrewmateRoles)
+ OptionMeetingKill = BooleanOptionItem.Create(Id + 12, "PenguinMeetingKill", false, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Goose]);
- OptionSpeedDuringDrag = FloatOptionItem.Create(Id + 13, "GooseSpeedDuringDrag", new(0.1f, 3f, 0.1f), 1f, TabGroup.CrewmateRoles)
+ OptionSpeedDuringDrag = FloatOptionItem.Create(Id + 13, "PenguinSpeedDuringDrag", new(0.1f, 3f, 0.1f), 1f, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Goose])
.SetValueFormat(OptionFormat.Multiplier);
- OptionVictimCanUseAbilities = BooleanOptionItem.Create(Id + 14, "GooseVictimCanUseAbilities", false, TabGroup.CrewmateRoles)
+ OptionVictimCanUseAbilities = BooleanOptionItem.Create(Id + 14, "PenguinVictimCanUseAbilities", false, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Goose]);
CanBeGuessed = BooleanOptionItem.Create(Id + 15, "CanBeGuessed", true, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Goose]);
diff --git a/Roles/Crewmate/Randomizer.cs b/Roles/Crewmate/Randomizer.cs
index 0f41c30b9..7fe80027e 100644
--- a/Roles/Crewmate/Randomizer.cs
+++ b/Roles/Crewmate/Randomizer.cs
@@ -390,48 +390,6 @@ namespace EHR.Roles.Crewmate
internal class Randomizer : RoleBase
{
- private static int Id => 643490;
- private static List PlayerIdList = [];
-
- private static OptionItem EffectFrequencyOpt;
- private static OptionItem EffectDurMin;
- private static OptionItem EffectDurMax;
- private static OptionItem NotifyOpt;
-
- private static int EffectFrequency;
- public static int MinimumEffectDuration;
- public static int MaximumEffectDuration;
- private static bool Notify;
-
- public static Dictionary> CurrentEffects = [];
- public static Dictionary AllPlayerDefaultSpeed = [];
-
- public static Dictionary Rifts = [];
- public static Dictionary Bombs = [];
-
- public static float TimeSinceLastMeeting;
- private static Dictionary LastEffectPick = [];
- private static Dictionary LastTP = [];
- private static long LastDeathEffect;
-
- private static string RNGString => Utils.ColorString(Utils.GetRoleColor(CustomRoles.Randomizer), Translator.GetString("RNGHasSpoken"));
-
- public static void NotifyAboutRNG(PlayerControl pc)
- {
- if (!Notify) return;
- pc.Notify(text: RNGString, time: IRandom.Instance.Next(2, 7), log: false);
- }
-
- public static bool Exists;
-
- public static float RandomFloat => IRandom.Instance.Next(0, 5) + (IRandom.Instance.Next(0, 10) / 10f);
-
- public override bool IsEnable => Exists;
-
- public static bool IsShielded(PlayerControl pc) => CurrentEffects.TryGetValue(pc.PlayerId, out var effects) && (effects.ContainsKey(Effect.ShieldRandomPlayer) || effects.ContainsKey(Effect.ShieldAll));
- public static bool HasSuperVision(PlayerControl pc) => CurrentEffects.TryGetValue(pc.PlayerId, out var effects) && (effects.ContainsKey(Effect.SuperVisionForRandomPlayer) || effects.ContainsKey(Effect.SuperVisionForAll));
- public static bool IsBlind(PlayerControl pc) => CurrentEffects.TryGetValue(pc.PlayerId, out var effects) && (effects.ContainsKey(Effect.BlindnessForRandomPlayer) || effects.ContainsKey(Effect.BlindnessForAll));
-
public enum Effect
{
ShieldRandomPlayer,
@@ -470,6 +428,48 @@ namespace EHR.Roles.Crewmate
Duel
}
+ private static List PlayerIdList = [];
+
+ private static OptionItem EffectFrequencyOpt;
+ private static OptionItem EffectDurMin;
+ private static OptionItem EffectDurMax;
+ private static OptionItem NotifyOpt;
+
+ private static int EffectFrequency;
+ public static int MinimumEffectDuration;
+ public static int MaximumEffectDuration;
+ private static bool Notify;
+
+ public static Dictionary> CurrentEffects = [];
+ public static Dictionary AllPlayerDefaultSpeed = [];
+
+ public static Dictionary Rifts = [];
+ public static Dictionary Bombs = [];
+
+ public static float TimeSinceLastMeeting;
+ private static Dictionary LastEffectPick = [];
+ private static Dictionary LastTP = [];
+ private static long LastDeathEffect;
+
+ public static bool Exists;
+ private static int Id => 643490;
+
+ private static string RNGString => Utils.ColorString(Utils.GetRoleColor(CustomRoles.Randomizer), Translator.GetString("RNGHasSpoken"));
+
+ public static float RandomFloat => IRandom.Instance.Next(0, 5) + (IRandom.Instance.Next(0, 10) / 10f);
+
+ public override bool IsEnable => Exists;
+
+ public static void NotifyAboutRNG(PlayerControl pc)
+ {
+ if (!Notify) return;
+ pc.Notify(text: RNGString, time: IRandom.Instance.Next(2, 7), log: false);
+ }
+
+ public static bool IsShielded(PlayerControl pc) => CurrentEffects.TryGetValue(pc.PlayerId, out var effects) && (effects.ContainsKey(Effect.ShieldRandomPlayer) || effects.ContainsKey(Effect.ShieldAll));
+ public static bool HasSuperVision(PlayerControl pc) => CurrentEffects.TryGetValue(pc.PlayerId, out var effects) && (effects.ContainsKey(Effect.SuperVisionForRandomPlayer) || effects.ContainsKey(Effect.SuperVisionForAll));
+ public static bool IsBlind(PlayerControl pc) => CurrentEffects.TryGetValue(pc.PlayerId, out var effects) && (effects.ContainsKey(Effect.BlindnessForRandomPlayer) || effects.ContainsKey(Effect.BlindnessForAll));
+
public static void SetupCustomOption()
{
Options.SetupRoleOptions(Id, TabGroup.CrewmateRoles, CustomRoles.Randomizer);
@@ -514,7 +514,7 @@ namespace EHR.Roles.Crewmate
{
Exists = true;
PlayerIdList.Add(playerId);
- AllPlayerDefaultSpeed = Main.AllPlayerSpeed;
+ AllPlayerDefaultSpeed = Main.AllPlayerSpeed.ToDictionary(x => x.Key, x => x.Value);
}
public static PlayerControl PickRandomPlayer()
diff --git a/Roles/Crewmate/Sentry.cs b/Roles/Crewmate/Sentry.cs
index 5e4763e12..c3fbbff86 100644
--- a/Roles/Crewmate/Sentry.cs
+++ b/Roles/Crewmate/Sentry.cs
@@ -108,7 +108,7 @@ namespace EHR.Roles.Impostor
var text = "\n" + string.Format(
Translator.GetString("Sentry.Notify.Shapeshifted"),
Utils.ColorString(Main.PlayerColors[ss.PlayerId], ss.GetRealName()),
- Utils.ColorString(Main.PlayerColors[ssTarget.PlayerId], ssTarget.GetRealName()));
+ Utils.ColorString(Main.PlayerColors[ssTarget.PlayerId], Main.AllPlayerNames[ssTarget.PlayerId]));
SentryPC.Notify($"{notify.TEXT}{text}", ShowInfoDuration.GetInt() - (Utils.TimeStamp - notify.TIMESTAMP));
diff --git a/Roles/Impostor/Overheat.cs b/Roles/Impostor/Overheat.cs
new file mode 100644
index 000000000..7b28c54a2
--- /dev/null
+++ b/Roles/Impostor/Overheat.cs
@@ -0,0 +1,141 @@
+using AmongUs.GameOptions;
+using UnityEngine;
+
+namespace EHR.Roles.Impostor
+{
+ public class Overheat : RoleBase
+ {
+ private const int StartingTemperature = 35;
+ public static bool On;
+
+ private static OptionItem OverheatChanceIncrease;
+ private static OptionItem OverheatChanceIncreaseFrequency;
+ private static OptionItem OverheatRollChanceFrequency;
+ private static OptionItem CoolDownTime;
+ private static OptionItem KCDDecreasePerIncreasedTemperature;
+ private float ChanceIncreaseTimer;
+ private float RollChanceTimer;
+
+ private int Temperature;
+ public override bool IsEnable => On;
+
+ public static void SetupCustomOption()
+ {
+ const int id = 11332;
+ Options.SetupRoleOptions(id, TabGroup.ImpostorRoles, CustomRoles.Overheat);
+ OverheatChanceIncrease = FloatOptionItem.Create(id + 2, "Overheat.ChanceIncrease", new(1f, 10f, 1f), 1f, TabGroup.ImpostorRoles)
+ .SetParent(Options.CustomRoleSpawnChances[CustomRoles.Overheat])
+ .SetValueFormat(OptionFormat.Percent);
+ OverheatChanceIncreaseFrequency = FloatOptionItem.Create(id + 3, "Overheat.ChanceIncreaseFrequency", new(0.5f, 30f, 0.5f), 5f, TabGroup.ImpostorRoles)
+ .SetParent(Options.CustomRoleSpawnChances[CustomRoles.Overheat])
+ .SetValueFormat(OptionFormat.Seconds);
+ OverheatRollChanceFrequency = FloatOptionItem.Create(id + 4, "Overheat.RollChanceFrequency", new(0.5f, 60f, 0.5f), 3f, TabGroup.ImpostorRoles)
+ .SetParent(Options.CustomRoleSpawnChances[CustomRoles.Overheat])
+ .SetValueFormat(OptionFormat.Seconds);
+ CoolDownTime = FloatOptionItem.Create(id + 5, "Overheat.CoolDownTime", new(0.5f, 30f, 0.5f), 4f, TabGroup.ImpostorRoles)
+ .SetParent(Options.CustomRoleSpawnChances[CustomRoles.Overheat])
+ .SetValueFormat(OptionFormat.Seconds);
+ KCDDecreasePerIncreasedTemperature = FloatOptionItem.Create(id + 6, "Overheat.KCDDecreasePerIncreasedTemperature", new(0.5f, 15f, 0.5f), 3f, TabGroup.ImpostorRoles)
+ .SetParent(Options.CustomRoleSpawnChances[CustomRoles.Overheat])
+ .SetValueFormat(OptionFormat.Seconds);
+ }
+
+ static Color GetTemperatureColor(int temperature) => temperature switch
+ {
+ <= 35 => Color.blue,
+ 36 => Color.cyan,
+ 37 => Color.green,
+ 38 => Color.yellow,
+ 39 => Palette.Orange,
+ >= 40 => Color.red
+ };
+
+ public override void Add(byte playerId)
+ {
+ On = true;
+ Temperature = StartingTemperature;
+ ChanceIncreaseTimer = -8f;
+ RollChanceTimer = -8f;
+ }
+
+ public override void Init()
+ {
+ On = false;
+ }
+
+ public override void ApplyGameOptions(IGameOptions opt, byte playerId)
+ {
+ if (Options.UsePets.GetBool()) return;
+
+ AURoleOptions.ShapeshifterCooldown = 1f;
+ AURoleOptions.ShapeshifterDuration = 1f;
+ }
+
+ public override void SetKillCooldown(byte id)
+ {
+ var kcd = Options.DefaultKillCooldown;
+ kcd -= KCDDecreasePerIncreasedTemperature.GetFloat() * (Temperature - StartingTemperature);
+ Main.AllPlayerKillCooldown[id] = kcd;
+ }
+
+ public override void OnFixedUpdate(PlayerControl pc)
+ {
+ if (!GameStates.IsInTask || !pc.IsAlive()) return;
+
+ ChanceIncreaseTimer += Time.fixedDeltaTime;
+ RollChanceTimer += Time.fixedDeltaTime;
+
+ if (ChanceIncreaseTimer >= OverheatChanceIncreaseFrequency.GetFloat())
+ {
+ ChanceIncreaseTimer = 0f;
+ Temperature += OverheatChanceIncrease.GetInt();
+ Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
+ }
+
+ if (RollChanceTimer >= OverheatRollChanceFrequency.GetFloat())
+ {
+ RollChanceTimer = 0f;
+ if (IRandom.Instance.Next(100) < Temperature - StartingTemperature)
+ {
+ pc.Suicide();
+ }
+ }
+ }
+
+ void CoolDown(PlayerControl pc)
+ {
+ Temperature = StartingTemperature;
+ Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
+
+ float speed = Main.AllPlayerSpeed[pc.PlayerId];
+ Main.AllPlayerSpeed[pc.PlayerId] = Main.MinSpeed;
+ pc.MarkDirtySettings();
+
+ _ = new LateTask(() =>
+ {
+ Main.AllPlayerSpeed[pc.PlayerId] = speed;
+ pc.MarkDirtySettings();
+ }, CoolDownTime.GetFloat(), "Overheat Cool Down");
+ }
+
+ public override bool OnShapeshift(PlayerControl shapeshifter, PlayerControl target, bool shapeshifting)
+ {
+ CoolDown(shapeshifter);
+ return false;
+ }
+
+ public override void OnPet(PlayerControl pc)
+ {
+ CoolDown(pc);
+ }
+
+ public static string GetSuffix(PlayerControl seer)
+ {
+ if (Main.PlayerStates[seer.PlayerId].Role is not Overheat oh) return string.Empty;
+
+ var color = GetTemperatureColor(oh.Temperature);
+ var str = Translator.GetString("Overheat.Suffix");
+ return string.Format(str, Utils.ColorString(color, $"{oh.Temperature}°C"));
+ }
+ }
+}
\ No newline at end of file
diff --git a/Roles/Impostor/Penguin.cs b/Roles/Impostor/Penguin.cs
index bb229ab90..d273f02f1 100644
--- a/Roles/Impostor/Penguin.cs
+++ b/Roles/Impostor/Penguin.cs
@@ -96,6 +96,7 @@ namespace EHR.Roles.Impostor
public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = Options.DefaultKillCooldown;
public override bool CanUseImpostorVentButton(PlayerControl pc) => AbductVictim == null;
+ public override bool CanUseKillButton(PlayerControl pc) => pc.IsAlive();
void SendRPC()
{
diff --git a/Roles/Impostor/Scavenger.cs b/Roles/Impostor/Scavenger.cs
index 3a6380e8b..314f3b381 100644
--- a/Roles/Impostor/Scavenger.cs
+++ b/Roles/Impostor/Scavenger.cs
@@ -48,6 +48,7 @@ namespace EHR.Roles.Impostor
if (Vector2.Distance(killer.Pos(), target.Pos()) > 2f) return;
target.TP(Pelican.GetBlackRoomPS());
target.Suicide(PlayerState.DeathReason.Kill, killer);
+ if (target.Is(CustomRoles.Pelican)) Pelican.OnPelicanDied(target.PlayerId);
killer.SetKillCooldown();
RPC.PlaySoundRPC(killer.PlayerId, Sounds.KillSound);
target.Notify(Utils.ColorString(Utils.GetRoleColor(CustomRoles.Scavenger), Translator.GetString("KilledByScavenger")));
diff --git a/Roles/Neutral/Pelican.cs b/Roles/Neutral/Pelican.cs
index 64f537de0..0035fffe4 100644
--- a/Roles/Neutral/Pelican.cs
+++ b/Roles/Neutral/Pelican.cs
@@ -182,13 +182,12 @@ public class Pelican : RoleBase
public static void OnPelicanDied(byte pc)
{
- if (!eatenList.ContainsKey(pc)) return;
- foreach (byte tar in eatenList[pc])
+ if (!eatenList.TryGetValue(pc, out List value)) return;
+ foreach (byte tar in value)
{
var target = Utils.GetPlayerById(tar);
var player = Utils.GetPlayerById(pc);
- if (player == null || target == null)
- continue;
+ if (player == null || target == null) continue;
target.TP(player);
Main.AllPlayerSpeed[tar] = Main.AllPlayerSpeed[tar] - 0.5f + OriginalSpeed[tar];
ReportDeadBodyPatch.CanReport[tar] = true;
diff --git a/Roles/Neutral/Pursuer.cs b/Roles/Neutral/Pursuer.cs
index 9f8a70200..31849afcc 100644
--- a/Roles/Neutral/Pursuer.cs
+++ b/Roles/Neutral/Pursuer.cs
@@ -73,8 +73,8 @@ public class Pursuer : RoleBase
{
foreach (var id in playerIdList)
{
- if (!Main.PlayerStates.ContainsKey(id)) continue;
- if (Main.PlayerStates[id].Role is not Pursuer { IsEnable: true } ps) continue;
+ if (!Main.PlayerStates.TryGetValue(id, out PlayerState state)) continue;
+ if (state.Role is not Pursuer { IsEnable: true } ps) continue;
if (!ps.clientList.Contains(pc.PlayerId) || notActiveList.Contains(pc.PlayerId)) continue;
// Get rid of this nonsense of killing the player for no reason
diff --git a/Roles/Neutral/Vulture.cs b/Roles/Neutral/Vulture.cs
index d8f68f336..a20c74b09 100644
--- a/Roles/Neutral/Vulture.cs
+++ b/Roles/Neutral/Vulture.cs
@@ -59,7 +59,7 @@ public class Vulture : RoleBase
.SetParent(CustomRoleSpawnChances[CustomRoles.Vulture]);
ChangeRoleWhenCantWin = BooleanOptionItem.Create(Id + 16, "VultureChangeRoleWhenCantWin", true, TabGroup.NeutralRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Vulture]);
- ChangeRole = StringOptionItem.Create(Id + 17, "VultureChangeRole", ChangeRoles.Select(x => x.ToColoredString()).ToArray(), 0, TabGroup.NeutralRoles)
+ ChangeRole = StringOptionItem.Create(Id + 17, "VultureChangeRole", ChangeRoles.Select(x => x.ToColoredString()).ToArray(), 0, TabGroup.NeutralRoles, noTranslation: true)
.SetParent(CustomRoleSpawnChances[CustomRoles.Vulture]);
}
diff --git a/main.cs b/main.cs
index 05e1e0e61..9b24f7b5d 100644
--- a/main.cs
+++ b/main.cs
@@ -493,6 +493,7 @@ public class Main : BasePlugin
{ CustomRoles.Madmate, "#ff1919" },
{ CustomRoles.Watcher, "#800080" },
{ CustomRoles.Sleuth, "#30221c" },
+ { CustomRoles.Dynamo, "#ebe534" },
{ CustomRoles.AntiTP, "#fcba03" },
{ CustomRoles.Taskcounter, "#ff1919" },
{ CustomRoles.Stained, "#e6bf91" },