diff --git a/CustomRoles.cs b/CustomRoles.cs index 74a38c3f7..4c0057b7b 100644 --- a/CustomRoles.cs +++ b/CustomRoles.cs @@ -223,6 +223,7 @@ public enum CustomRoles Bargainer, BloodKnight, Bubble, + Chemist, Cherokious, Collector, Deathknight, diff --git a/Modules/CustomRolesHelper.cs b/Modules/CustomRolesHelper.cs index 45f5ecf72..62b8d1338 100644 --- a/Modules/CustomRolesHelper.cs +++ b/Modules/CustomRolesHelper.cs @@ -334,6 +334,7 @@ internal static class CustomRolesHelper CustomRoles.BloodKnight => RoleTypes.Impostor, CustomRoles.Poisoner => RoleTypes.Impostor, CustomRoles.NSerialKiller => RoleTypes.Impostor, + CustomRoles.Chemist => RoleTypes.Impostor, CustomRoles.Samurai => RoleTypes.Impostor, CustomRoles.QuizMaster => RoleTypes.Impostor, CustomRoles.Bargainer => RoleTypes.Impostor, @@ -437,6 +438,7 @@ internal static class CustomRolesHelper CustomRoles.Refugee or CustomRoles.Parasite or CustomRoles.NSerialKiller or + CustomRoles.Chemist or CustomRoles.QuizMaster or CustomRoles.Samurai or CustomRoles.Bargainer or @@ -1158,6 +1160,7 @@ internal static class CustomRolesHelper CustomRoles.PlagueBearer => CountTypes.PlagueBearer, CustomRoles.Parasite => CountTypes.Impostor, CustomRoles.NSerialKiller => CountTypes.NSerialKiller, + CustomRoles.Chemist => CountTypes.Chemist, CustomRoles.Samurai => CountTypes.Samurai, CustomRoles.QuizMaster => CountTypes.QuizMaster, CustomRoles.Bargainer => CountTypes.Bargainer, @@ -1192,7 +1195,7 @@ internal static class CustomRolesHelper CustomRoles.Spiritcaller => CountTypes.Spiritcaller, CustomRoles.Cherokious => CountTypes.Cherokious, CustomRoles.DarkHide => DarkHide.SnatchesWin.GetBool() ? CountTypes.Crew : CountTypes.DarkHide, - CustomRoles.Arsonist => !Options.ArsonistCanIgniteAnytime.GetBool() ? CountTypes.Crew : CountTypes.Arsonist, + CustomRoles.Arsonist => !Options.ArsonistKeepsGameGoing.GetBool() ? CountTypes.Crew : CountTypes.Arsonist, CustomRoles.SchrodingersCat => SchrodingersCat.WinsWithCrewIfNotAttacked.GetBool() ? CountTypes.Crew : CountTypes.OutOfGame, _ => role.Is(Team.Impostor) ? CountTypes.Impostor : CountTypes.Crew @@ -1310,6 +1313,7 @@ public enum CountTypes HexMaster, Wraith, NSerialKiller, + Chemist, QuizMaster, Samurai, Bargainer, diff --git a/Modules/GhostRolesManager.cs b/Modules/GhostRolesManager.cs index 081a81599..23659ec6c 100644 --- a/Modules/GhostRolesManager.cs +++ b/Modules/GhostRolesManager.cs @@ -53,7 +53,7 @@ namespace EHR.Modules try { if (AssignedGhostRoles.Count >= GhostRoles.Count) return false; - if (pc.IsAlive() || pc.GetCountTypes() is CountTypes.None or CountTypes.OutOfGame) return false; + if (pc.IsAlive() || pc.GetCountTypes() is CountTypes.None or CountTypes.OutOfGame || pc.Is(CustomRoles.EvilSpirit)) return false; var suitableRole = GetSuitableGhostRole(pc); return suitableRole.IsGhostRole() && !AssignedGhostRoles.Any(x => x.Key == pc.PlayerId || x.Value.Role == suitableRole); } diff --git a/Modules/GuessManager.cs b/Modules/GuessManager.cs index 6f2b89dc7..c2ff5dfb0 100644 --- a/Modules/GuessManager.cs +++ b/Modules/GuessManager.cs @@ -94,7 +94,11 @@ public static class GuessManager msg = msg.ToLower().TrimStart().TrimEnd(); if (CheckCommand(ref msg, "id|guesslist|gl编号|玩家编号|玩家id|id列表|玩家列表|列表|所有id|全部id")) operate = 1; else if (CheckCommand(ref msg, "shoot|guess|bet|st|gs|bt|猜|赌", false)) operate = 2; - else return false; + else + { + Logger.Msg("Not a guessing command", "Msg Guesser"); + return false; + } Logger.Msg(msg, "Msg Guesser"); Logger.Msg($"{operate}", "Operate"); diff --git a/Modules/NameColorManager.cs b/Modules/NameColorManager.cs index 1363e77fb..c7a6d8c56 100644 --- a/Modules/NameColorManager.cs +++ b/Modules/NameColorManager.cs @@ -120,6 +120,7 @@ public static class NameColorManager // Check if the seer can see the target's role color color = seerRole switch { + CustomRoles.Executioner when Executioner.Target[seer.PlayerId] == target.PlayerId => "000000", CustomRoles.Gangster when target.Is(CustomRoles.Madmate) => Main.RoleColors[CustomRoles.Madmate], CustomRoles.Crewpostor when target.Is(CustomRoleTypes.Impostor) && Options.CrewpostorKnowsAllies.GetBool() => Main.ImpostorColor, CustomRoles.Succubus when target.Is(CustomRoles.Charmed) => Main.RoleColors[CustomRoles.Charmed], diff --git a/Modules/Utils.cs b/Modules/Utils.cs index 5f99c4b12..2eb3d15a1 100644 --- a/Modules/Utils.cs +++ b/Modules/Utils.cs @@ -518,6 +518,7 @@ public static class Utils case CustomRoles.Eclipse: case CustomRoles.Pyromaniac: case CustomRoles.NSerialKiller: + case CustomRoles.Chemist: case CustomRoles.Samurai: case CustomRoles.QuizMaster: case CustomRoles.Bargainer: @@ -1750,7 +1751,7 @@ public static class Utils //if (Options.DeepLowLoad.GetBool()) await Task.Run(() => { DoNotifyRoles(isForMeeting, SpecifySeer, NoCache, ForceLoop, CamouflageIsForMeeting, GuesserIsForMeeting); }); /*else */ - if ((SpecifySeer != null && SpecifySeer.IsModClient()) || !AmongUsClient.Instance.AmHost || Main.AllPlayerControls == null || GameStates.IsMeeting) return; + if ((SpecifySeer != null && SpecifySeer.IsModClient()) || !AmongUsClient.Instance.AmHost || Main.AllPlayerControls == null || GameStates.IsMeeting || GameStates.IsLobby) return; await DoNotifyRoles(isForMeeting, SpecifySeer, SpecifyTarget, NoCache, ForceLoop, CamouflageIsForMeeting, GuesserIsForMeeting, MushroomMixup); } @@ -2051,7 +2052,7 @@ public static class Utils seer.RpcSetNamePrivate(SelfName, true, force: NoCache); // Run the second loop only when necessary, such as when seer is dead - if (GameStates.IsLobby || seer.Data.IsDead || !seer.IsAlive() || NoCache || CamouflageIsForMeeting || MushroomMixup || IsActive(SystemTypes.MushroomMixupSabotage) || ForceLoop || seerList.Length == 1 || targetList.Length == 1) + if (seer.Data.IsDead || !seer.IsAlive() || NoCache || CamouflageIsForMeeting || MushroomMixup || IsActive(SystemTypes.MushroomMixupSabotage) || ForceLoop || seerList.Length == 1 || targetList.Length == 1) { foreach (PlayerControl target in targetList) { diff --git a/Patches/ChatCommandPatch.cs b/Patches/ChatCommandPatch.cs index 4381ca4e5..ebb008c87 100644 --- a/Patches/ChatCommandPatch.cs +++ b/Patches/ChatCommandPatch.cs @@ -839,6 +839,7 @@ internal class ChatCommands "和平之鸽" or "和平之鴿" or "和平的鸽子" or "和平" or "dop" or "dove of peace" => GetString("DovesOfNeace"), "持槍" or "持械" or "手长" => GetString("Reach"), "monarch" => GetString("Monarch"), + "sch" => GetString("SchrodingersCat"), _ => text, }; } diff --git a/Patches/ExilePatch.cs b/Patches/ExilePatch.cs index 668025504..39b656d12 100644 --- a/Patches/ExilePatch.cs +++ b/Patches/ExilePatch.cs @@ -120,6 +120,9 @@ class ExileControllerWrapUpPatch case CustomRoles.Devourer: Devourer.OnDevourerDied(exiled.PlayerId); break; + case CustomRoles.Medic: + Medic.IsDead(exiled.Object); + break; } if (Executioner.CheckExileTarget(exiled, DecidedWinner)) DecidedWinner = true; diff --git a/Patches/HudPatch.cs b/Patches/HudPatch.cs index 11018d208..23e1532d1 100644 --- a/Patches/HudPatch.cs +++ b/Patches/HudPatch.cs @@ -178,7 +178,7 @@ class HudManagerPatch __instance.AbilityButton?.OverrideText((Main.PlayerStates[player.PlayerId].Role as FireWorks).nowFireWorksCount == 0 ? GetString("FireWorksExplosionButtonText") : GetString("FireWorksInstallAtionButtonText")); break; case CustomRoles.Swiftclaw: - __instance.KillButton?.OverrideText(GetString("SwiftclawKillButtonText")); + __instance.PetButton?.OverrideText(GetString("SwiftclawKillButtonText")); break; case CustomRoles.Pestilence: __instance.KillButton?.OverrideText(GetString("KillButtonText")); diff --git a/Patches/MeetingHudPatch.cs b/Patches/MeetingHudPatch.cs index 5733b0711..1e5da8aaf 100644 --- a/Patches/MeetingHudPatch.cs +++ b/Patches/MeetingHudPatch.cs @@ -121,7 +121,7 @@ class CheckForEndVotingPatch } } - if (!shouldSkip && !__instance.playerStates.All(ps => Main.PlayerStates[ps.TargetPlayerId].IsDead || ps.DidVote || Utils.GetPlayerById(ps.TargetPlayerId).Data.Disconnected)) + if (!shouldSkip && !__instance.playerStates.All(ps => ps == null || !Main.PlayerStates.TryGetValue(ps.TargetPlayerId, out var st) || st.IsDead || ps.DidVote || Utils.GetPlayerById(ps.TargetPlayerId) == null || Utils.GetPlayerById(ps.TargetPlayerId).Data == null || Utils.GetPlayerById(ps.TargetPlayerId).Data.Disconnected)) { return false; } diff --git a/Roles/Crewmate/Sentry.cs b/Roles/Crewmate/Sentry.cs index 281b0a40e..181074a13 100644 --- a/Roles/Crewmate/Sentry.cs +++ b/Roles/Crewmate/Sentry.cs @@ -61,14 +61,16 @@ namespace EHR.Roles.Impostor public override void OnPet(PlayerControl pc) { var room = pc.GetPlainShipRoom(); - if (room == default(PlainShipRoom)) + bool hasntChosenRoom = MonitoredRoom == null || MonitoredRoom == default || MonitoredRoom == default(PlainShipRoom); + + if (room == default(PlainShipRoom) && hasntChosenRoom) { pc.AddAbilityCD(1); pc.Notify(Translator.GetString("Sentry.Notify.InvalidRoom")); return; } - if (MonitoredRoom == null || MonitoredRoom == default || MonitoredRoom == default(PlainShipRoom)) MonitoredRoom = room; + if (hasntChosenRoom) MonitoredRoom = room; else DisplayRoomInfo(pc); } @@ -106,13 +108,15 @@ namespace EHR.Roles.Impostor : Utils.ColorString(Main.PlayerColors[ssTarget.PlayerId], ssTarget.GetRealName()), Utils.ColorString(Main.PlayerColors[target.PlayerId], target.GetRealName())); - notify.TEXT += text; - Utils.NotifyRoles(SpecifySeer: SentryPC, SpecifyTarget: SentryPC); + SentryPC.Notify($"{notify.TEXT}{text}", ShowInfoDuration.GetInt() - (Utils.TimeStamp - notify.TIMESTAMP)); _ = new LateTask(() => { if (NameNotifyManager.Notice.TryGetValue(SentryPC.PlayerId, out var laterNotify)) + { laterNotify.TEXT = laterNotify.TEXT.Replace(text, string.Empty); + SentryPC.Notify(laterNotify.TEXT, ShowInfoDuration.GetInt() - (Utils.TimeStamp - laterNotify.TIMESTAMP)); + } }, 3f, log: false); } } diff --git a/Roles/Crewmate/Speedrunner.cs b/Roles/Crewmate/Speedrunner.cs index f48651dc6..e6afc75db 100644 --- a/Roles/Crewmate/Speedrunner.cs +++ b/Roles/Crewmate/Speedrunner.cs @@ -31,6 +31,8 @@ namespace EHR.Roles.Crewmate public override void OnTaskComplete(PlayerControl player, int CompletedTasksCount, int AllTasksCount) { + if (!player.IsAlive()) return; + var completedTasks = CompletedTasksCount + 1; int remainingTasks = AllTasksCount - completedTasks; if (completedTasks >= AllTasksCount) diff --git a/Roles/Impostor/Penguin.cs b/Roles/Impostor/Penguin.cs index 9d0a19b4e..71fbb7690 100644 --- a/Roles/Impostor/Penguin.cs +++ b/Roles/Impostor/Penguin.cs @@ -68,7 +68,7 @@ namespace EHR.Roles.Impostor SpeedDuringDrag = OptionSpeedDuringDrag.GetFloat(); VictimCanUseAbilities = OptionVictimCanUseAbilities.GetBool(); - DefaultSpeed = Main.AllPlayerSpeed[playerId]; + _ = new LateTask(() => { DefaultSpeed = Main.AllPlayerSpeed[playerId]; }, 9f, log: false); PenguinId = playerId; Penguin_ = Utils.GetPlayerById(playerId); @@ -108,11 +108,11 @@ namespace EHR.Roles.Impostor void AddVictim(PlayerControl target) { if (!IsEnable) return; - //Prevent using of moving platform?? AbductVictim = target; AbductTimer = AbductTimerLimit; Main.AllPlayerSpeed[PenguinId] = SpeedDuringDrag; Penguin_.MarkDirtySettings(); + LogSpeed(); Utils.NotifyRoles(SpecifySeer: Penguin_, SpecifyTarget: Penguin_); SendRPC(); } @@ -124,10 +124,13 @@ namespace EHR.Roles.Impostor AbductTimer = 255f; Main.AllPlayerSpeed[PenguinId] = DefaultSpeed; Penguin_.MarkDirtySettings(); + LogSpeed(); Utils.NotifyRoles(SpecifySeer: Penguin_, SpecifyTarget: Penguin_); SendRPC(); } + void LogSpeed() => Logger.Info($"Penguin Speed: {Main.AllPlayerSpeed[PenguinId]}", "Penguin"); + public override bool OnCheckMurder(PlayerControl killer, PlayerControl target) { if (!IsEnable) return true; @@ -168,6 +171,7 @@ namespace EHR.Roles.Impostor if (AbductVictim != null && AbductTimer <= 0f) { Penguin_.Kill(AbductVictim); + RemoveVictim(); } if (MeetingKill) diff --git a/Roles/Neutral/Chemist.cs b/Roles/Neutral/Chemist.cs new file mode 100644 index 000000000..a1d6e814f --- /dev/null +++ b/Roles/Neutral/Chemist.cs @@ -0,0 +1,231 @@ +using AmongUs.GameOptions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static EHR.Options; + +namespace EHR.Roles.Neutral +{ + internal class Chemist : RoleBase + { + public static bool On; + + private static OptionItem KillCooldown; + private static OptionItem CanVent; + private static OptionItem HasImpostorVision; + + private static OptionItem AirGainedPerSecond; + private static OptionItem WaterGainedPerSecond; + private static OptionItem CoalGainedPerTask; + private static OptionItem IronOreGainedPerTask; + + private static OverrideTasksData Tasks; + + public static void SetupCustomOption() + { + const int id = 17670; + SetupRoleOptions(id, TabGroup.NeutralRoles, CustomRoles.Chemist); + KillCooldown = FloatOptionItem.Create(id + 2, "KillCooldown", new(0f, 180f, 2.5f), 22.5f, TabGroup.NeutralRoles) + .SetParent(CustomRoleSpawnChances[CustomRoles.Chemist]) + .SetValueFormat(OptionFormat.Seconds); + CanVent = BooleanOptionItem.Create(id + 3, "CanVent", true, TabGroup.NeutralRoles) + .SetParent(CustomRoleSpawnChances[CustomRoles.Chemist]); + HasImpostorVision = BooleanOptionItem.Create(id + 4, "ImpostorVision", true, TabGroup.NeutralRoles) + .SetParent(CustomRoleSpawnChances[CustomRoles.Chemist]); + + AirGainedPerSecond = IntegerOptionItem.Create(id + 5, "Chemist.AirGainedPerSecond", new(5, 100, 5), 10, TabGroup.NeutralRoles) + .SetParent(CustomRoleSpawnChances[CustomRoles.Chemist]) + .SetValueFormat(OptionFormat.Times); + WaterGainedPerSecond = IntegerOptionItem.Create(id + 6, "Chemist.WaterGainedPerSecond", new(5, 100, 5), 10, TabGroup.NeutralRoles) + .SetParent(CustomRoleSpawnChances[CustomRoles.Chemist]) + .SetValueFormat(OptionFormat.Times); + CoalGainedPerTask = IntegerOptionItem.Create(id + 7, "Chemist.CoalGainedPerTask", new(1, 10, 1), 2, TabGroup.NeutralRoles) + .SetParent(CustomRoleSpawnChances[CustomRoles.Chemist]) + .SetValueFormat(OptionFormat.Times); + IronOreGainedPerTask = IntegerOptionItem.Create(id + 8, "Chemist.IronOreGainedPerTask", new(1, 50, 1), 8, TabGroup.NeutralRoles) + .SetParent(CustomRoleSpawnChances[CustomRoles.Chemist]) + .SetValueFormat(OptionFormat.Times); + + Tasks = OverrideTasksData.Create(id + 9, TabGroup.NeutralRoles, CustomRoles.Chemist); + } + + public override void Init() + { + On = false; + + FactoryLocations = []; + _ = new LateTask(() => + { + FactoryLocations = ShipStatus.Instance.AllRooms + .Zip(EnumHelper.GetAllValues()) + .ToDictionary(x => x.First, x => x.Second); + }, 10f, log: false); + } + + public override void Add(byte playerId) + { + On = true; + LastUpdate = Utils.TimeStamp + 8; + ItemCounts = []; + CurrentFactory = Factory.None; + SelectedProcess = string.Empty; + + foreach (var item in EnumHelper.GetAllValues()) + { + ItemCounts[item] = 0; + } + + if (!AmongUsClient.Instance.AmHost) return; + if (!Main.ResetCamPlayerList.Contains(playerId)) + Main.ResetCamPlayerList.Add(playerId); + } + + public override bool IsEnable => On; + public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); + public override void ApplyGameOptions(IGameOptions opt, byte id) => opt.SetVision(HasImpostorVision.GetBool()); + public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool(); + public override bool CanUseSabotage(PlayerControl pc) => pc.IsAlive(); + + enum Item + { + Air, + AmmoniaGas, + BaseMineralOil, + CarbonDioxide, + CarbonMonoxide, + Coal, + Explosive, + Grenade, + HydrogenGas, + HydrogenSulfideGas, + IronIngot, + IronOre, + IronPlate, + MethanolGas, + MethylamineGas, + MoltenIron, + Naphtha, + NitrogenGas, + OxygenGas, + PurifiedWater, + Steam, + Sulfur, + SulfurDioxideGas, + SulfuricAcid, + SynthesisGas, + ThermalWater, + Water + } + + enum Factory + { + None, + ChemicalPlant, // up to 2 ingredients + AdvancedChemicalPlant, // 3 or more ingredients + SteamCracker, + BlastFurnace, + InductionFurnace, + CastingMachine, + Electrolyzer, + CoolingTower, + WaterTreatmentPlant, + Liquifier, + AssemblingMachine + } + + private static readonly Dictionary Ingredients, List<(int Count, Item Item)> Results)>> Processes = new() + { + [Factory.ChemicalPlant] = + { + ["Synthesis Sulfur"] = ([(60, Item.HydrogenSulfideGas), (40, Item.OxygenGas)], [(3, Item.Sulfur)]), + ["Synthesis Of Naphtha"] = ([(150, Item.SynthesisGas), (50, Item.CarbonMonoxide)], [(100, Item.Naphtha)]), + ["Reversed Water Gas Shift"] = ([(50, Item.HydrogenGas), (50, Item.CarbonDioxide)], [(50, Item.PurifiedWater), (50, Item.CarbonMonoxide)]), + ["Synthesis Sulfur Dioxide"] = ([(1, Item.Sulfur), (60, Item.OxygenGas)], [(60, Item.SulfurDioxideGas)]), + ["Synthesis Sulfuric Acid"] = ([(90, Item.SulfurDioxideGas), (40, Item.PurifiedWater)], [(60, Item.SulfuricAcid)]), + ["Synthesis to Methanol"] = ([(100, Item.SynthesisGas), (40, Item.CarbonDioxide)], [(20, Item.PurifiedWater), (80, Item.MethanolGas)]), + ["Synthesis Gas Separation"] = ([(100, Item.SynthesisGas)], [(40, Item.CarbonMonoxide), (60, Item.HydrogenGas)]), + ["Synthesis Gas Reforming"] = ([(60, Item.CarbonMonoxide), (90, Item.HydrogenGas)], [(100, Item.SynthesisGas)]), + ["Methylamine Gas"] = ([(50, Item.MethanolGas), (250, Item.AmmoniaGas)], [(200, Item.MethylamineGas), (50, Item.PurifiedWater)]), + ["Synthesis Methanol"] = ([(100, Item.CarbonDioxide), (100, Item.HydrogenGas)], [(100, Item.MethanolGas)]), + ["Air Separation"] = ([(100, Item.Air)], [(50, Item.OxygenGas), (50, Item.NitrogenGas)]) + }, + [Factory.AdvancedChemicalPlant] = + { + ["Cracking of Naphtha to Mineral Oil"] = ([(60, Item.Naphtha), (20, Item.ThermalWater), (20, Item.CarbonMonoxide)], [(100, Item.BaseMineralOil)]), + ["Coal Cracking Fischer Tropsch Process"] = ([(5, Item.Coal), (50, Item.Steam), (50, Item.OxygenGas)], [(100, Item.SynthesisGas), (20, Item.CarbonDioxide), (30, Item.HydrogenSulfideGas)]), + ["Explosives"] = ([(1, Item.Sulfur), (1, Item.Coal), (10, Item.Water)], [(2, Item.Explosive)]) + }, + [Factory.SteamCracker] = + { + ["Steam Cracking Mineral Oil to Synthesis Gas"] = ([(100, Item.BaseMineralOil), (100, Item.Steam)], [(200, Item.SynthesisGas)]) + }, + [Factory.BlastFurnace] = + { + ["Iron Ore Smelting"] = ([(24, Item.IronOre)], [(24, Item.IronIngot)]) + }, + [Factory.InductionFurnace] = + { + ["Iron Melting"] = ([(12, Item.IronIngot)], [(120, Item.MoltenIron)]) + }, + [Factory.CastingMachine] = + { + ["Iron Plate Casting"] = ([(40, Item.MoltenIron)], [(4, Item.IronPlate)]) + }, + [Factory.Electrolyzer] = + { + ["Purified Water Electrolysis"] = ([(100, Item.PurifiedWater)], [(40, Item.OxygenGas), (60, Item.HydrogenGas)]) + }, + [Factory.CoolingTower] = + { + ["Steam Cooling"] = ([(100, Item.Steam)], [(100, Item.PurifiedWater)]) + }, + [Factory.WaterTreatmentPlant] = + { + ["Water Purification"] = ([(150, Item.Water)], [(100, Item.PurifiedWater)]), + ["Water Boiling"] = ([(100, Item.Water), (1, Item.Coal)], [(60, Item.Steam)]) + }, + [Factory.Liquifier] = + { + ["Coal Liquefaction"] = ([(1, Item.Coal)], [(50, Item.CarbonDioxide)]) + }, + [Factory.AssemblingMachine] = + { + ["Grenade"] = ([(5, Item.IronPlate), (10, Item.Coal)], [(1, Item.Grenade)]) + } + }; + + static bool IsBasicResource(Item item) => item is + Item.Air or + Item.Coal or + Item.IronOre or + Item.Water; + + static bool IsFinalProduct(Item item) => item is + Item.Explosive or + Item.Grenade or + Item.SulfuricAcid or + Item.MethylamineGas; + + private static Dictionary FactoryLocations = []; + + private long LastUpdate; + private Dictionary ItemCounts; + private Factory CurrentFactory; + private string SelectedProcess; + + public override void OnFixedUpdate(PlayerControl pc) + { + if (!GameStates.IsInTask || !pc.IsAlive() || LastUpdate == Utils.TimeStamp) return; + LastUpdate = Utils.TimeStamp; + + ItemCounts[Item.Air] += AirGainedPerSecond.GetInt(); + ItemCounts[Item.Water] += WaterGainedPerSecond.GetInt(); + + CurrentFactory = FactoryLocations.GetValueOrDefault(pc.GetPlainShipRoom()); + + Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc); + } + } +} diff --git a/Roles/Neutral/Gamer.cs b/Roles/Neutral/Gamer.cs index 66affe79c..a642eab1e 100644 --- a/Roles/Neutral/Gamer.cs +++ b/Roles/Neutral/Gamer.cs @@ -103,8 +103,8 @@ public class Gamer : RoleBase RPC.PlaySoundRPC(killer.PlayerId, Sounds.KillSound); Utils.NotifyRoles(SpecifySeer: killer, SpecifyTarget: target); - Logger.Info($"{killer.GetNameWithRole().RemoveHtmlTags()} 对玩家 {target.GetNameWithRole().RemoveHtmlTags()} 造成了 {Damage.GetInt()} 点伤害", "Gamer"); - return true; + Logger.Info($"{killer.GetNameWithRole().RemoveHtmlTags()} attacked {target.GetNameWithRole().RemoveHtmlTags()}, did {Damage.GetInt()} damage", "Gamer"); + return false; } public override bool OnCheckMurderAsTarget(PlayerControl killer, PlayerControl target) @@ -123,10 +123,9 @@ public class Gamer : RoleBase GamerHealth[target.PlayerId] -= SelfDamage.GetInt(); SendRPC(target.PlayerId); RPC.PlaySoundRPC(target.PlayerId, Sounds.KillSound); - //killer.RpcGuardAndKill(target); Utils.NotifyRoles(SpecifySeer: target, SpecifyTarget: killer); - Logger.Info($"{killer.GetNameWithRole().RemoveHtmlTags()} 对玩家 {target.GetNameWithRole().RemoveHtmlTags()} 造成了 {SelfDamage.GetInt()} 点伤害", "Gamer"); + Logger.Info($"{killer.GetNameWithRole().RemoveHtmlTags()} attacked {target.GetNameWithRole().RemoveHtmlTags()}, did {SelfDamage.GetInt()} damage", "Gamer"); return false; } diff --git a/Roles/Neutral/SchrodingersCat.cs b/Roles/Neutral/SchrodingersCat.cs index a6c376ad4..8cdb21c2d 100644 --- a/Roles/Neutral/SchrodingersCat.cs +++ b/Roles/Neutral/SchrodingersCat.cs @@ -28,6 +28,7 @@ public override bool OnCheckMurderAsTarget(PlayerControl killer, PlayerControl target) { var killerRole = killer.GetCustomRole(); + if (killerRole.IsImpostor()) killerRole = CustomRoles.Refugee; if (Options.SingleRoles.Contains(killerRole)) killerRole = CustomRoles.Amnesiac; target.RpcSetCustomRole(killerRole); diff --git a/main.cs b/main.cs index 676d328d3..4b85046e3 100644 --- a/main.cs +++ b/main.cs @@ -424,6 +424,7 @@ public class Main : BasePlugin { CustomRoles.HexMaster, "#ff00ff" }, { CustomRoles.Wraith, "#4B0082" }, { CustomRoles.NSerialKiller, "#233fcc" }, + { CustomRoles.Chemist, "#4287f5" }, { CustomRoles.Samurai, "#73495c" }, { CustomRoles.QuizMaster, "#CF2472" }, { CustomRoles.Bargainer, "#4f2f36" }, @@ -685,6 +686,7 @@ public enum CustomWinner Necromancer = CustomRoles.Necromancer, Wraith = CustomRoles.Wraith, SerialKiller = CustomRoles.NSerialKiller, + Chemist = CustomRoles.Chemist, Samurai = CustomRoles.Samurai, QuizMaster = CustomRoles.QuizMaster, Bargainer = CustomRoles.Bargainer,