From e92042bf54a2974baf2acc1d3f2603e247f8332e Mon Sep 17 00:00:00 2001 From: Gurge44 Date: Tue, 1 Jul 2025 22:16:26 +0200 Subject: [PATCH] a bunch of improvements --- CTA/CustomTeamAssigner/CustomRoles.cs | 2 +- EHR.csproj | 5 +- GameMode/BedWars.cs | 164 +++++++++++++++++--------- GameMode/MoveAndStop.cs | 2 +- Main.cs | 12 +- Modules/Achievements.cs | 2 +- Modules/BanManager.cs | 8 +- Modules/CustomNetObject.cs | 26 ++-- Modules/CustomTeamManager.cs | 4 +- Modules/ExtendedPlayerControl.cs | 157 +++++++++++++++++++++++- Modules/GhostRolesManager.cs | 1 + Modules/ModUpdater.cs | 2 +- Modules/OptionSaver.cs | 2 +- Modules/PrivateTagManager.cs | 2 +- Modules/RPC.cs | 7 ++ Modules/SpamManager.cs | 2 +- Modules/TemplateManager.cs | 2 +- Modules/Translator.cs | 14 +-- Modules/Utils.cs | 96 +++++++++++++-- Patches/ChatCommandPatch.cs | 19 ++- Patches/IntroPatch.cs | 2 +- Patches/LadderPatch.cs | 11 +- Patches/PlayerControlPatch.cs | 10 +- Patches/ShipStatusPatch.cs | 6 +- Patches/TextBoxPatch.cs | 4 +- Resources/Lang/en_US.json | 37 +++++- Roles/AddOns/Common/Asthmatic.cs | 2 +- Roles/Crewmate/Astral.cs | 1 + Roles/Crewmate/Farseer.cs | 2 +- Roles/Crewmate/Tracefinder.cs | 2 +- Roles/Impostor/Assassin.cs | 21 ++++ Roles/Impostor/BallLightning.cs | 2 +- Roles/Impostor/Deathpact.cs | 2 +- Roles/Impostor/FireWorks.cs | 2 +- Roles/Impostor/OverKiller.cs | 20 +--- Roles/Impostor/Penguin.cs | 6 +- Roles/Impostor/Puppeteer.cs | 4 +- Roles/Impostor/RiftMaker.cs | 4 +- Roles/Neutral/Agitater.cs | 4 +- Roles/Neutral/Arsonist.cs | 15 ++- Roles/Neutral/Magician.cs | 12 +- Roles/Neutral/PlagueDoctor.cs | 2 +- Roles/Neutral/QuizMaster.cs | 4 +- Roles/Neutral/Revolutionist.cs | 2 +- Roles/Neutral/WeaponMaster.cs | 2 +- 45 files changed, 528 insertions(+), 180 deletions(-) diff --git a/CTA/CustomTeamAssigner/CustomRoles.cs b/CTA/CustomTeamAssigner/CustomRoles.cs index 0b36cdfe9..90d7e1477 100644 --- a/CTA/CustomTeamAssigner/CustomRoles.cs +++ b/CTA/CustomTeamAssigner/CustomRoles.cs @@ -437,7 +437,7 @@ public enum CustomRoles // The Mind Game TMGPlayer, - + // Bed Wars BedWarsPlayer, diff --git a/EHR.csproj b/EHR.csproj index 2c2dc9841..7d0cfedcf 100644 --- a/EHR.csproj +++ b/EHR.csproj @@ -1,6 +1,7 @@  - net6.0 + net8.0 + net6.0 false false false @@ -27,7 +28,7 @@ - + diff --git a/GameMode/BedWars.cs b/GameMode/BedWars.cs index 858385cf3..c1554f58f 100644 --- a/GameMode/BedWars.cs +++ b/GameMode/BedWars.cs @@ -13,11 +13,11 @@ public static class BedWars private static int SpeedPotionDuration = 30; private static int InvisPotionDuration = 20; private static int ReviveTime = 15; - private static int IronGenerationInterval = 1; + private static int IronGenerationInterval = 2; private static int GoldGenerationInterval = 5; private static int EmeraldGenerationInterval = 10; private static int DiamondGenerationInterval = 10; - private static int GracePeriod = 60; + private static int GracePeriod = 90; private static int HealWaitAfterDamage = 5; private static int MaxHealth = 20; private static int TrapEffectDuration = 10; @@ -89,7 +89,7 @@ public static class BedWars .SetColor(color) .SetGameMode(gameMode); - IronGenerationIntervalOption = new IntegerOptionItem(id++, "BedWars.IronGenerationIntervalOption", new(1, 60, 1), 1, tab) + IronGenerationIntervalOption = new IntegerOptionItem(id++, "BedWars.IronGenerationIntervalOption", new(1, 60, 1), 2, tab) .SetValueFormat(OptionFormat.Seconds) .SetColor(color) .SetGameMode(gameMode); @@ -109,7 +109,7 @@ public static class BedWars .SetColor(color) .SetGameMode(gameMode); - GracePeriodOption = new IntegerOptionItem(id++, "BedWars.GracePeriodOption", new(5, 300, 5), 60, tab) + GracePeriodOption = new IntegerOptionItem(id++, "BedWars.GracePeriodOption", new(5, 300, 5), 90, tab) .SetValueFormat(OptionFormat.Seconds) .SetColor(color) .SetGameMode(gameMode); @@ -229,7 +229,7 @@ public static class BedWars public static string GetStatistics(byte id) { - return !Data.TryGetValue(id, out PlayerData data) ? string.Empty : data.Team.GetName(); + return !Data.TryGetValue(id, out PlayerData data) ? string.Empty : Utils.ColorString(data.Team.GetColor(), data.Team.GetName()); } public static string GetHudText() @@ -248,7 +248,7 @@ public static class BedWars else { int playersLeftInTeam = Main.AllAlivePlayerControls.Count(x => Data.TryGetValue(x.PlayerId, out PlayerData data) && data.Team == team); - sb.AppendLine(Utils.ColorString(team.GetColor(), $"{team.GetName()} {playersLeftInTeam}")); + sb.AppendLine($"{Utils.ColorString(team.GetColor(), team.GetName())} ({playersLeftInTeam})"); } } @@ -275,6 +275,12 @@ public static class BedWars { if (GracePeriodEnd > Utils.TimeStamp || !Data.TryGetValue(killer.PlayerId, out PlayerData killerData) || !Data.TryGetValue(target.PlayerId, out PlayerData targetData) || killerData.Team == targetData.Team) return; + if (AllNetObjects.Values.Any(x => x.Bed.Breaking.Contains(killer.PlayerId))) + { + killer.Notify(Translator.GetString("Bedwars.CannotKillWhileBreakingBed")); + return; + } + float damage = 1; Item? selectedItem = killerData.Inventory.GetSelectedItem(); @@ -290,7 +296,8 @@ public static class BedWars if (Upgrades.TryGetValue(killerData.Team, out HashSet upgrades) && upgrades.Contains(Upgrade.Sharpness)) damage *= 1.25f; - targetData.Damage(target, damage); + targetData.Damage(target, damage, killer); + Utils.NotifyRoles(SpecifySeer: killer, SpecifyTarget: target); killer.SetKillCooldown(); } @@ -345,6 +352,12 @@ public static class BedWars yield return new WaitForSeconds(3f); + if (GameStates.IsEnded || !GameStates.InGame || GameStates.IsLobby) + { + Logger.Error("Cannot start BedWars game due to invalid game state.", "BedWars"); + yield break; + } + // Assign players to teams List players = Main.AllAlivePlayerControls.Shuffle().ToList(); if (Main.GM.Value) players.RemoveAll(x => x.IsHost()); @@ -385,10 +398,16 @@ public static class BedWars yield return new WaitForSeconds(0.2f); } - yield return new WaitForSeconds(0.2f); + yield return new WaitForSeconds(0.5f); - string itemShopText = Translator.GetString("Bedwars.Shop.ItemShop"); - string upgradeShopText = Translator.GetString("Bedwars.Shop.UpgradeShop"); + if (GameStates.IsEnded || !GameStates.InGame || GameStates.IsLobby) + { + Logger.Error("Cannot start BedWars game due to invalid game state.", "BedWars"); + yield break; + } + + string itemShopText = Utils.ColorString(Palette.Orange, Translator.GetString("Bedwars.Shop.ItemShop")); + string upgradeShopText = Utils.ColorString(Color.magenta, Translator.GetString("Bedwars.Shop.UpgradeShop")); List rooms = [Translator.GetString("Bedwars.Rooms")]; foreach ((BedWarsTeam team, (Vector2 bedPos, SystemTypes room, Vector2 itemShopPos, Vector2 upgradeShopPos, _)) in bases) @@ -411,7 +430,7 @@ public static class BedWars yield return new WaitForSeconds(0.2f); - players.NotifyPlayers($"{rooms[0]}\n{string.Join(" | ", rooms.Skip(1))}"); + players.NotifyPlayers($"{rooms[0]}\n{string.Join(" | ", rooms.Skip(1))}", 20f); yield return new WaitForSeconds(0.2f); @@ -474,7 +493,23 @@ public static class BedWars { PlainShipRoom room = __instance.GetPlainShipRoom(); - if (room == null || room.RoomId != data.Base.Room) + bool allowed = (room != null && data.Base.Room == room.RoomId) || (Main.CurrentMap, data.Base.Room) switch + { + (MapNames.Skeld, SystemTypes.Nav) => pos.x > 13f, + (MapNames.Dleks, SystemTypes.Nav) => pos.x < -13f, + (MapNames.MiraHQ, SystemTypes.Launchpad) => pos.x < 5f, + (MapNames.MiraHQ, SystemTypes.Reactor) => pos.y > 10f, + (MapNames.MiraHQ, SystemTypes.Balcony) => pos.y < 2f, + (MapNames.Polus, SystemTypes.LifeSupp) => room != null && room.RoomId == SystemTypes.BoilerRoom, + (MapNames.Airship, SystemTypes.CargoBay) => room != null && room.RoomId == SystemTypes.Ventilation, + (MapNames.Airship, SystemTypes.MeetingRoom) => room != null && room.RoomId == SystemTypes.GapRoom, + (MapNames.Fungle, SystemTypes.Kitchen) => room != null && room.RoomId == SystemTypes.FishingDock, + (MapNames.Fungle, SystemTypes.Comms) => pos is { y: > 8f, x: > 19f }, + (MapNames.Fungle, SystemTypes.Jungle) => pos is { x: > 10f, y: < -11f }, + _ => false + }; + + if (!allowed) { __instance.Notify(Translator.GetString("Bedwars.YouCannotLeaveRoomInGracePeriod")); __instance.TP(data.Base.SpawnPosition); @@ -512,6 +547,7 @@ public static class BedWars if (healPool && shouldRegen) data.Health++; data.Health++; data.LastHeal = now; + Utils.NotifyRoles(SpecifyTarget: __instance); Logger.Info($"{__instance.GetRealName()}'s health: {data.Health}", "BedWars"); } } @@ -577,7 +613,7 @@ public static class BedWars public Base Base; public Item? Armor; - public void Damage(PlayerControl pc, float damage) + public void Damage(PlayerControl pc, float damage, PlayerControl killer = null) { if (Health <= 0 || GracePeriodEnd > Utils.TimeStamp) return; @@ -599,12 +635,16 @@ public static class BedWars { if (!AllNetObjects.TryGetValue(Team, out NetObjectCollection netObjectCollection) || !netObjectCollection.Bed.IsBroken) { - if (Reviving.Add(pc.PlayerId)) Main.Instance.StartCoroutine(ReviveCountdown(pc)); + if (killer != null && Data.TryGetValue(killer.PlayerId, out PlayerData killerData)) + Inventory.Items.DoIf(x => ItemCategories[x.Key] != ItemCategory.Tool, x => killerData.Inventory.Adjust(x.Key, x.Value)); + Inventory.Clear(); + if (Reviving.Add(pc.PlayerId)) Main.Instance.StartCoroutine(ReviveCountdown(pc)); pc.Exiled(); CustomRpcSender.Create("BedWars Death", SendOption.Reliable).AutoStartRpc(pc.NetId, 4).EndRpc().SendMessage(); Main.PlayerStates[pc.PlayerId].SetDead(); pc.RpcSetRoleDesync(RoleTypes.GuardianAngel, pc.OwnerId); + pc.RpcResetAbilityCooldown(); pc.MarkDirtySettings(); } else @@ -628,6 +668,7 @@ public static class BedWars time--; } + Health = MaxHealth; NameNotifyManager.Notifies.Remove(pc.PlayerId); Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc); pc.RpcRevive(); @@ -643,6 +684,9 @@ public static class BedWars var sb = new StringBuilder(); + if (NameNotifyManager.GetNameNotify(pc, out string notify) && notify.Length > 0) + sb.AppendLine(notify); + sb.AppendLine(GracePeriodEnd > Utils.TimeStamp ? Translator.GetString("Bedwars.GracePeriod") : GetHealthInfo()); if (InShop.TryGetValue(pc.PlayerId, out Shop shop)) @@ -651,15 +695,16 @@ public static class BedWars sb.AppendLine(shop.GetSuffix(pc)); } - int lines = 10 - sb.ToString().Count(x => x == '\n'); - Loop.Times(lines, _ => sb.AppendLine()); + int lines = sb.ToString().Count(x => x == '\n'); + sb.Insert(0, Utils.ColorString(Color.clear, ".") + new string('\n', Math.Max(0, 15 - lines))); + sb.Append(new string('\n', Math.Max(0, 5 - lines))); sb.AppendLine(GetArmorInfo()); sb.AppendLine(); sb.Append(Inventory); - return sb.ToString().Trim(); + return $"<#ffffff>{sb.ToString().Trim()}"; } public string GetInfoAsTarget(PlayerControl pc) @@ -677,7 +722,7 @@ public static class BedWars sb.Append(Utils.ColorString(display.Color, $"{display.Icon} {display.Name.Invoke()} {display.Icon}")); } - return sb.ToString().Trim(); + return $"<#ffffff>{sb.ToString().Trim()}"; } private string GetArmorInfo() @@ -722,8 +767,8 @@ public static class BedWars }, [MapNames.MiraHQ] = new() { - [BedWarsTeam.Blue] = new(new(-4.46f, 4.12f), SystemTypes.Launchpad, new(-4.46f, 0.48f), new(2.81f, -1.43f), new(-4.45f, 2.4f)), - [BedWarsTeam.Yellow] = new(new(22.16f, 1.5f), SystemTypes.Cafeteria, new(20.02f, -1.81f), new(27.62f, -1.81f), new(23.77f, -1.58f)), + [BedWarsTeam.Blue] = new(new(2.81f, -1.43f), SystemTypes.Launchpad, new(-4.46f, 0.48f), new(-4.46f, 4.12f), new(-4.45f, 2.4f)), + [BedWarsTeam.Yellow] = new(new(22.16f, 1.5f), SystemTypes.Balcony, new(20.02f, -1.81f), new(27.62f, -1.81f), new(23.77f, -1.58f)), [BedWarsTeam.Red] = new(new(17.8f, 23.17f), SystemTypes.Greenhouse, new(13.58f, 22.4f), new(22.08f, 22.37f), new(17.85f, 25.55f)), [BedWarsTeam.Green] = new(new(6.12f, 12.12f), SystemTypes.Reactor, new(1.69f, 10.63f), new(8.88f, 12.38f), new(2.47f, 11.9f)) }, @@ -757,14 +802,14 @@ public static class BedWars [Item.Iron] = [new(3.69f, -15.7f), new(17.91f, -5.06f), new(-20f, -3.5f), new(-10.61f, -3.81f)], [Item.Gold] = [new(3.69f, -16f), new(17.91f, -5.48f), new(-20f, -4f), new(-10.61f, -4.33f)], [Item.Emerald] = [new(4.53f, -9.67f)], - [Item.Diamond] = [new(9.55f, -9.41f), new(-15.29f, 2.88f)] + [Item.Diamond] = [new(9.55f, -9.41f), new(-15.29f, 2.88f), new(1.61f, 5.38f), new(-9.78f, -7.68f)] }, [MapNames.MiraHQ] = new() { [Item.Iron] = [new(18.15f, 24.21f), new(28f, 0.62f), new(-5.51f, -2f), new(6.23f, 14.35f)], [Item.Gold] = [new(17.52f, 24.21f), new(28f, 0f), new(-5.51f, -1.48f), new(6.23f, 13.82f)], [Item.Emerald] = [new(12.53f, 6.91f)], - [Item.Diamond] = [new(15.37f, 0.37f), new(17.8f, 11.46f)] + [Item.Diamond] = [new(15.41f, -1.46f), new(17.8f, 11.46f)] }, [MapNames.Polus] = new() { @@ -791,8 +836,8 @@ public static class BedWars static BedWars() { - Bases[MapNames.Dleks] = Bases[MapNames.Skeld].Select(x => (key: x.Key, value: new Base(-x.Value.BedPosition, x.Value.Room, -x.Value.ItemShopPosition, -x.Value.UpgradeShopPosition, -x.Value.SpawnPosition))).ToDictionary(x => x.key, x => x.value); - ItemGeneratorPositions[MapNames.Dleks] = ItemGeneratorPositions[MapNames.Skeld].ToDictionary(x => x.Key, x => x.Value.ConvertAll(p => -p)); + Bases[MapNames.Dleks] = Bases[MapNames.Skeld].Select(x => (key: x.Key, value: new Base(new(-x.Value.BedPosition.x, x.Value.BedPosition.y), x.Value.Room, new(-x.Value.ItemShopPosition.x, x.Value.ItemShopPosition.y), new(-x.Value.UpgradeShopPosition.x, x.Value.UpgradeShopPosition.y), new(-x.Value.SpawnPosition.x, x.Value.SpawnPosition.y)))).ToDictionary(x => x.key, x => x.value); + ItemGeneratorPositions[MapNames.Dleks] = ItemGeneratorPositions[MapNames.Skeld].ToDictionary(x => x.Key, x => x.Value.ConvertAll(p => new Vector2(-p.x, p.y))); } private enum BedWarsTeam @@ -905,8 +950,9 @@ public static class BedWars switch (itemCategory) { - case ItemCategory.Armor when !data.Armor.HasValue || data.Armor < selectedItem: + case ItemCategory.Armor when !data.Armor.HasValue || data.Armor.Value < selectedItem: data.Armor = selectedItem; + LateTask.New(() => Utils.NotifyRoles(SpecifyTarget: pc), 0.2f, log: false); break; case ItemCategory.Weapon: List toRemove = []; @@ -919,6 +965,9 @@ public static class BedWars toRemove.ForEach(x => data.Inventory.Items.Remove(x)); break; + case ItemCategory.Utility when selectedItem == Item.TNT: + LateTask.New(() => Utils.NotifyRoles(SpecifyTarget: pc), 0.2f, log: false); + break; } if (itemCategory == ItemCategory.Armor || data.Inventory.Adjust(selectedItem)) @@ -975,7 +1024,8 @@ public static class BedWars itemsInCategory.Add($"{display.Name.Invoke()} {Utils.ColorString(display.Color, display.Icon.ToString())}"); } - return string.Format(Translator.GetString("Bedwars.Shop.ItemShopSuffix.CategorySelection"), Translator.GetString($"BedWars.ItemCategory.{itemCategory}"), string.Join(", ", itemsInCategory)); + Logger.Warn("we got here 0", "debug"); + return string.Format(Translator.GetString("Bedwars.Shop.ItemShopSuffix.CategorySelection"), Translator.GetString($"BedWars.ItemCategory.{itemCategory}"), string.Join(' ', itemsInCategory)); } else { @@ -990,6 +1040,7 @@ public static class BedWars if (!ItemCost.TryGetValue(selectedItem, out (Item Resource, int Count) cost) || !ItemDisplayData.TryGetValue(cost.Resource, out ItemDisplay costDisplay)) return string.Empty; var costString = $"{cost.Count} {Utils.ColorString(costDisplay.Color, costDisplay.Icon.ToString())}"; + Logger.Warn("we got here 1", "debug"); return string.Format(Translator.GetString("Bedwars.Shop.ItemShopSuffix.ItemSelection"), itemName, itemIcon, itemDescription, costString); } } @@ -1040,6 +1091,7 @@ public static class BedWars ? "\n" + Translator.GetString("BedWars.Upgrade.AlreadyBought") : string.Empty; + Logger.Warn("we got here 2", "debug"); return string.Format(Translator.GetString("Bedwars.Shop.UpgradeShopSuffix"), Translator.GetString($"BedWars.Upgrade.{selectedUpgrade}"), Translator.GetString($"BedWars.UpgradeDescription.{selectedUpgrade}"), alreadyBought, costString); } } @@ -1303,7 +1355,7 @@ public static class BedWars { public Dictionary Items = []; private int SelectedSlot; - private const int MaxSlots = 7; + private const int MaxSlots = 9; public void Clear() { @@ -1369,11 +1421,11 @@ public static class BedWars _ = new TNT(pos); break; case Item.InvisibilityPotion: - Main.AllPlayerControls.Without(pc).Do(x => CustomRpcSender.Create("BedWars.InvisibilityPotion", (SendOption)1).AutoStartRpc(pc.NetId, 4, x.OwnerId).EndRpc().SendMessage()); + pc.RpcMakeInvisible(); LateTask.New(() => { if (GameStates.IsEnded || !GameStates.InGame || GameStates.IsLobby) return; - Main.AllPlayerControls.Without(pc).Do(x => pc.RpcSetRoleDesync(RoleTypes.Phantom, x.OwnerId)); + pc.RpcMakeVisible(); }, InvisPotionDuration); break; case Item.SpeedPotion: @@ -1417,18 +1469,20 @@ public static class BedWars } while (itemsDisplays.Count < MaxSlots) - itemsDisplays.Add(Utils.ColorString(Color.clear, "--")); + itemsDisplays.Add(Utils.ColorString(Color.clear, "---")); + const string baseColor = "<#000000>"; + var finalSb = new StringBuilder(); - finalSb.Append("<#555555>"); - finalSb.AppendLine("▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁"); + finalSb.Append(baseColor); + finalSb.AppendLine("▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁"); finalSb.Append(""); i = 0; foreach (string itemsDisplay in itemsDisplays) { bool selected = i == SelectedSlot || i - 1 == SelectedSlot; - if (!selected) finalSb.Append("<#555555>"); + if (!selected) finalSb.Append(baseColor); finalSb.Append(selected ? '┃' : '│'); if (!selected) finalSb.Append(""); finalSb.Append(' '); @@ -1437,9 +1491,12 @@ public static class BedWars i++; } - finalSb.Append(i - 1 == SelectedSlot ? '┃' : '│'); - finalSb.AppendLine("<#555555>"); - finalSb.Append("▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔"); + bool lastSelected = i - 1 == SelectedSlot; + if (!lastSelected) finalSb.Append(baseColor); + finalSb.Append(lastSelected ? '┃' : '│'); + if (!lastSelected) finalSb.Append(""); + finalSb.AppendLine(baseColor); + finalSb.Append("▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔"); finalSb.AppendLine(""); finalSb.AppendLine(); @@ -1455,17 +1512,11 @@ public static class BedWars private string StatusText; public readonly List Layers = []; public bool IsBroken; - private readonly HashSet Breaking = []; + public readonly HashSet Breaking = []; - protected Bed(Vector2 position) + protected string GetSprite() { - UpdateStatus(false); - CreateNetObject(GetSprite(), position); - } - - private string GetSprite() - { - return StatusText + new string('\n', 2 - StatusText.Count(x => x == '\n')) + BaseSprite; + return StatusText + new string('\n', Math.Max(0, 2 - StatusText.Count(x => x == '\n'))) + BaseSprite; } public void UpdateStatus(bool changeSprite = true) @@ -1481,23 +1532,18 @@ public static class BedWars string layers = Layers.Count > 0 ? string.Join(' ', layerStrings) : Translator.GetString("Bedwars.BedStatus.Exposed"); var nextProtectReq = $"{GetNextProtectReq()} {Translator.GetString("Bedwars.BedStatus.ProtectReq")}"; - Dictionary breakTimes = new Item?[] { null, Item.Pickaxe, Item.Axe, Item.Shears }.ToDictionary(x => x, GetBreakTime); - List bt = []; + Dictionary breakTimes = new[] { Item.Pickaxe, Item.Axe, Item.Shears }.ToDictionary(x => x, x => GetBreakTime(x)); + List bt = [$"{GetBreakTime(null)}"]; - foreach ((Item? tool, int time) in breakTimes) + foreach ((Item tool, int time) in breakTimes) { - if (!tool.HasValue) - bt.Add($"{time}"); - else - { - if (!ItemDisplayData.TryGetValue(tool.Value, out ItemDisplay display)) continue; - bt.Add($"{Utils.ColorString(display.Color, display.Icon.ToString())} {time}"); - } + if (!ItemDisplayData.TryGetValue(tool, out ItemDisplay display)) continue; + bt.Add($"{Utils.ColorString(display.Color, display.Icon.ToString())} {time}"); } - var breakTime = $"{Translator.GetString("Bedwars.BedStatus.BreakTime")}: {string.Join(" | ", bt)}"; + var breakTime = $"{Translator.GetString("Bedwars.BedStatus.BreakTime")}: {string.Join(" | ", bt)}"; - StatusText = $"{layers}\n{nextProtectReq}\n{breakTime}"; + StatusText = $"{layers}\n{nextProtectReq}\n{breakTime}\n{Utils.EmptyMessage}"; if (changeSprite) RpcChangeSprite(GetSprite()); Logger.Info($"{GetType().Name} status updated: {StatusText.Replace("\n", " - ")}", "BedWars"); @@ -1543,7 +1589,7 @@ public static class BedWars ItemDisplay layerDisplay = ItemDisplayData[topLayer]; string layerName = Utils.ColorString(layerDisplay.Color, layerDisplay.Icon.ToString()); var str = string.Empty; - const int progressDisplayParts = 5; + const int progressDisplayParts = 10; while (timer > 0f) { @@ -1659,6 +1705,8 @@ public static class BedWars opt.SetFloat(FloatOptionNames.CrewLightMod, TrappedVision); opt.SetFloat(FloatOptionNames.ImpostorLightMod, TrappedVision); } + + AURoleOptions.PhantomCooldown = 0.1f; } public static bool CanUseImpostorVentButton(PlayerControl pc) diff --git a/GameMode/MoveAndStop.cs b/GameMode/MoveAndStop.cs index f573625ff..717a84e6e 100644 --- a/GameMode/MoveAndStop.cs +++ b/GameMode/MoveAndStop.cs @@ -483,7 +483,7 @@ internal static class MoveAndStop Vector2 previousPosition = new(data.PositionX, data.PositionY); // Update the player's position - Vector2 currentPosition = pc.transform.position; + Vector2 currentPosition = pc.Pos(); currentPosition.x += data.PositionX * Time.deltaTime; currentPosition.y += data.PositionY * Time.deltaTime; diff --git a/Main.cs b/Main.cs index cea47e1f5..54bac6794 100644 --- a/Main.cs +++ b/Main.cs @@ -37,8 +37,8 @@ public class Main : BasePlugin private const string DebugKeyHash = "c0fd562955ba56af3ae20d7ec9e64c664f0facecef4b3e366e109306adeae29d"; private const string DebugKeySalt = "59687b"; private const string PluginGuid = "com.gurge44.endlesshostroles"; - public const string PluginVersion = "5.8.0"; - public const string PluginDisplayVersion = "5.8.0"; + public const string PluginVersion = "6.0.0"; + public const string PluginDisplayVersion = "6.0.0"; public const bool TestBuild = false; public const string NeutralColor = "#ffab1b"; @@ -55,6 +55,13 @@ public class Main : BasePlugin public const string ForkId = "EHR"; public const string SupportedAUVersion = "2025.4.15"; + public const string DataPath = +#if ANDROID + Application.persistentDataPath; +#else + "."; +#endif + public static readonly Version Version = Version.Parse(PluginVersion); //public static ManualLogSource Logger; @@ -114,6 +121,7 @@ public class Main : BasePlugin public static string ShieldPlayer = string.Empty; public static readonly Dictionary GamesPlayed = []; public static readonly HashSet GotShieldAnimationInfoThisGame = []; + public static readonly HashSet Invisible = []; public static readonly Dictionary> HasPlayedGM = new() { diff --git a/Modules/Achievements.cs b/Modules/Achievements.cs index 9915ebef9..767142296 100644 --- a/Modules/Achievements.cs +++ b/Modules/Achievements.cs @@ -109,7 +109,7 @@ public static class Achievements ItsJustAPrankBro // As Bomber, Kill half the lobby in 1 bomb } - private const string SaveFilePath = "./EHR_DATA/Achievements.json"; + private const string SaveFilePath = $"{Main.DataPath}/EHR_DATA/Achievements.json"; private const string ApiBaseUrl = "https://gurge44.pythonanywhere.com/achievements"; private const string ApiSaveEndpoint = $"{ApiBaseUrl}/save"; diff --git a/Modules/BanManager.cs b/Modules/BanManager.cs index 35738846f..b4a2b564c 100644 --- a/Modules/BanManager.cs +++ b/Modules/BanManager.cs @@ -14,10 +14,10 @@ namespace EHR; public static class BanManager { - private const string DenyNameListPath = "./EHR_DATA/DenyName.txt"; - private const string BanListPath = "./EHR_DATA/BanList.txt"; - private const string ModeratorListPath = "./EHR_DATA/Moderators.txt"; - private const string WhiteListListPath = "./EHR_DATA/WhiteList.txt"; + private const string DenyNameListPath = $"{Main.DataPath}/EHR_DATA/DenyName.txt"; + private const string BanListPath = $"{Main.DataPath}/EHR_DATA/BanList.txt"; + private const string ModeratorListPath = $"{Main.DataPath}/EHR_DATA/Moderators.txt"; + private const string WhiteListListPath = $"{Main.DataPath}/EHR_DATA/WhiteList.txt"; private static readonly List EACList = []; public static readonly List TempBanWhiteList = []; // To prevent writing to the banlist diff --git a/Modules/CustomNetObject.cs b/Modules/CustomNetObject.cs index 53009ef56..3f86463db 100644 --- a/Modules/CustomNetObject.cs +++ b/Modules/CustomNetObject.cs @@ -571,33 +571,41 @@ namespace EHR internal sealed class BlueBed : BedWars.Bed { - public BlueBed(Vector2 position) : base(position) + public BlueBed(Vector2 position) { BaseSprite = "██████
<#c7deff>█<#c7deff>█<#00aeff>█<#00aeff>█<#00aeff>█<#00aeff>█
<#c7deff>█<#c7deff>█<#00aeff>█<#00aeff>█<#00aeff>█<#00aeff>█
<#c7deff>█<#c7deff>█<#00aeff>█<#00aeff>█<#00aeff>█<#00aeff>█
<#82531a>█████<#82531a>█
██████
"; + UpdateStatus(false); + CreateNetObject(GetSprite(), position); } } internal sealed class GreenBed : BedWars.Bed { - public GreenBed(Vector2 position) : base(position) + public GreenBed(Vector2 position) { BaseSprite = "██████
<#baffd0>█<#baffd0>█<#00ff7b>█<#00ff7b>█<#00ff7b>█<#00ff7b>█
<#baffd0>█<#baffd0>█<#00ff7b>█<#00ff7b>█<#00ff7b>█<#00ff7b>█
<#baffd0>█<#baffd0>█<#00ff7b>█<#00ff7b>█<#00ff7b>█<#00ff7b>█
<#82531a>█████<#82531a>█
██████
"; + UpdateStatus(false); + CreateNetObject(GetSprite(), position); } } internal sealed class YellowBed : BedWars.Bed { - public YellowBed(Vector2 position) : base(position) + public YellowBed(Vector2 position) { BaseSprite = "██████
<#fffebd>█<#fffebd>█<#ffff00>█<#ffff00>█<#ffff00>█<#ffff00>█
<#fffebd>█<#fffebd>█<#ffff00>█<#ffff00>█<#ffff00>█<#ffff00>█
<#fffebd>█<#fffebd>█<#ffff00>█<#ffff00>█<#ffff00>█<#ffff00>█
<#82531a>█████<#82531a>█
██████
"; + UpdateStatus(false); + CreateNetObject(GetSprite(), position); } } internal sealed class RedBed : BedWars.Bed { - public RedBed(Vector2 position) : base(position) + public RedBed(Vector2 position) { BaseSprite = "██████
<#ffbbb5>█<#ffbbb5>█<#ff0008>█<#ff0008>█<#ff0008>█<#ff0008>█
<#ffbbb5>█<#ffbbb5>█<#ff0008>█<#ff0008>█<#ff0008>█<#ff0008>█
<#ffbbb5>█<#ffbbb5>█<#ff0008>█<#ff0008>█<#ff0008>█<#ff0008>█
<#82531a>█████<#82531a>█
██████
"; + UpdateStatus(false); + CreateNetObject(GetSprite(), position); } } @@ -627,14 +635,14 @@ namespace EHR internal sealed class TNT : CustomNetObject { - public Vector2 Position; + private readonly Vector2 Location; private float timer; - public TNT(Vector2 position) + public TNT(Vector2 location) { - Position = position; + Location = location; timer = 4f; - CreateNetObject("████<#000000>█<#ffea00>█
███<#000000>███
█<#ff0004>█<#ff0004>████
<#ff0004>█<#ff0004>█<#ff0004>█<#ff0004>███
<#ff0004>█<#ff0004>█<#ff0004>█<#ff0004>███
█<#ff0004>█<#ff0004>████
", position); + CreateNetObject("████<#000000>█<#ffea00>█
███<#000000>███
█<#ff0004>█<#ff0004>████
<#ff0004>█<#ff0004>█<#ff0004>█<#ff0004>███
<#ff0004>█<#ff0004>█<#ff0004>█<#ff0004>███
█<#ff0004>█<#ff0004>████
", location); } protected override void OnFixedUpdate() @@ -644,7 +652,7 @@ namespace EHR if (timer <= 0f) { - BedWars.OnTNTExplode(Position); + BedWars.OnTNTExplode(Location); Despawn(); } } diff --git a/Modules/CustomTeamManager.cs b/Modules/CustomTeamManager.cs index c3c3c8df4..226958248 100644 --- a/Modules/CustomTeamManager.cs +++ b/Modules/CustomTeamManager.cs @@ -17,9 +17,9 @@ internal static class CustomTeamManager { try { - if (!File.Exists("./EHR_DATA/CTA_Data.txt")) return; + if (!File.Exists($"{Main.DataPath}/EHR_DATA/CTA_Data.txt")) return; - CustomTeams = File.ReadAllLines("./EHR_DATA/CTA_Data.txt").Select(x => new CustomTeam(x)).ToHashSet(); + CustomTeams = File.ReadAllLines($"{Main.DataPath}/EHR_DATA/CTA_Data.txt").Select(x => new CustomTeam(x)).ToHashSet(); RefreshCustomOptions(); UpdateEnabledTeams(); } diff --git a/Modules/ExtendedPlayerControl.cs b/Modules/ExtendedPlayerControl.cs index e51a8e71a..d97dd2bb7 100644 --- a/Modules/ExtendedPlayerControl.cs +++ b/Modules/ExtendedPlayerControl.cs @@ -101,7 +101,7 @@ internal static class ExtendedPlayerControl public static List GetVentsFromClosest(this PlayerControl player) { - Vector2 playerpos = player.transform.position; + Vector2 playerpos = player.Pos(); List vents = ShipStatus.Instance.AllVents.ToList(); vents.Sort((v1, v2) => Vector2.Distance(playerpos, v1.transform.position).CompareTo(Vector2.Distance(playerpos, v2.transform.position))); @@ -606,7 +606,7 @@ internal static class ExtendedPlayerControl if (player == null) return false; var results = new Collider2D[10]; - int overlapPointNonAlloc = Physics2D.OverlapPointNonAlloc(player.transform.position, results, Constants.ShipOnlyMask); + int overlapPointNonAlloc = Physics2D.OverlapPointNonAlloc(player.Pos(), results, Constants.ShipOnlyMask); PlainShipRoom room = player.GetPlainShipRoom(); Vector2 pos = player.Pos(); @@ -1321,9 +1321,160 @@ internal static class ExtendedPlayerControl return Main.PlayerStates.TryGetValue(pc.PlayerId, out PlayerState state) && state.Role.CanUseSabotage(pc); } + // Next 8: From MoreGamemodes by Rabek009 (https://github.com/Rabek009/MoreGamemodes) + public static Vector2 Pos(this PlayerControl pc) { - return new(pc.transform.position.x, pc.transform.position.y); + if (pc.AmOwner) return pc.transform.position; + if (pc.NetTransform.incomingPosQueue.Count > 0 && pc.NetTransform.isActiveAndEnabled && !pc.NetTransform.isPaused) + return pc.NetTransform.incomingPosQueue.ToArray()[^1]; + return pc.transform.position; + } + + public static void MakeInvisible(this PlayerControl player) + { + player.invisibilityAlpha = player.AmOwner ? 0.5f : PlayerControl.LocalPlayer.Data.Role.IsDead ? 0.5f : 0f; + player.cosmetics.SetPhantomRoleAlpha(player.invisibilityAlpha); + + if (!player.AmOwner && !PlayerControl.LocalPlayer.Data.Role.IsDead) + { + player.shouldAppearInvisible = true; + player.Visible = false; + } + } + + public static void MakeVisible(this PlayerControl player) + { + if (!player.AmOwner) + { + player.shouldAppearInvisible = false; + player.Visible = true; + } + + player.invisibilityAlpha = 1f; + player.cosmetics.SetPhantomRoleAlpha(player.invisibilityAlpha); + + if (!player.AmOwner) + { + player.shouldAppearInvisible = false; + player.Visible = !player.inVent; + } + } + + public static void RpcMakeInvisibleModded(this PlayerControl player) + { + player.MakeInvisible(); + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(player.NetId, (byte)CustomRPC.Invisibility, SendOption.Reliable); + writer.Write(true); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + + public static void RpcMakeVisibleModded(this PlayerControl player) + { + player.MakeVisible(); + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(player.NetId, (byte)CustomRPC.Invisibility, SendOption.Reliable); + writer.Write(false); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + + public static void RpcMakeInvisible(this PlayerControl player, bool phantom = false) + { + if (!Main.Invisible.Add(player.PlayerId)) return; + if (phantom && Options.CurrentGameMode != CustomGameMode.Standard) return; + player.RpcSetPet(""); + if (!phantom) player.RpcMakeInvisibleModded(); + + foreach (PlayerControl pc in PlayerControl.AllPlayerControls) + { + if (pc.AmOwner || pc == player || (!phantom && pc.IsModdedClient()) || (phantom && pc.IsImpostor())) continue; + var sender = CustomRpcSender.Create("RpcMakeInvisible", SendOption.Reliable); + sender.StartMessage(pc.GetClientId()); + sender.StartRpc(player.NetTransform.NetId, (byte)RpcCalls.SnapTo) + .WriteVector2(new Vector2(50f, 50f)) + .Write(player.NetTransform.lastSequenceId) + .EndRpc(); + sender.StartRpc(player.NetTransform.NetId, (byte)RpcCalls.SnapTo) + .WriteVector2(new Vector2(50f, 50f)) + .Write((ushort)(player.NetTransform.lastSequenceId + 16383)) + .EndRpc(); + sender.EndMessage(); + sender.SendMessage(); + } + + Logger.Info($"Made {player.GetNameWithRole()} invisible", "RpcMakeInvisible"); + } + + public static void RpcMakeVisible(this PlayerControl player, bool phantom = false) + { + if (!Main.Invisible.Remove(player.PlayerId)) return; + if (phantom && Options.CurrentGameMode != CustomGameMode.Standard) return; + if (Options.UsePets.GetBool()) PetsHelper.SetPet(player, PetsHelper.GetPetId()); + if (!phantom) player.RpcMakeVisibleModded(); + + foreach (PlayerControl pc in PlayerControl.AllPlayerControls) + { + if (pc.AmOwner || pc == player || (!phantom && pc.IsModdedClient()) || (phantom && pc.IsImpostor())) continue; + var sender = CustomRpcSender.Create("RpcMakeVisible", SendOption.Reliable); + sender.StartMessage(pc.GetClientId()); + sender.StartRpc(player.NetTransform.NetId, (byte)RpcCalls.SnapTo) + .WriteVector2(new Vector2(50f, 50f)) + .Write((ushort)(player.NetTransform.lastSequenceId + 32767)) + .EndRpc(); + sender.StartRpc(player.NetTransform.NetId, (byte)RpcCalls.SnapTo) + .WriteVector2(new Vector2(50f, 50f)) + .Write((ushort)(player.NetTransform.lastSequenceId + 32767 + 16383)) + .EndRpc(); + sender.StartRpc(player.NetTransform.NetId, (byte)RpcCalls.SnapTo) + .WriteVector2(player.transform.position) + .Write(player.NetTransform.lastSequenceId) + .EndRpc(); + sender.EndMessage(); + sender.SendMessage(); + } + + Logger.Info($"Made {player.GetNameWithRole()} visible", "RpcMakeVisible"); + } + + public static void RpcResetInvisibility(this PlayerControl player, bool phantom = false) + { + if (!Main.Invisible.Contains(player.PlayerId)) return; + if (phantom && Options.CurrentGameMode != CustomGameMode.Standard) return; + + foreach (PlayerControl pc in PlayerControl.AllPlayerControls) + { + if (pc.AmOwner || pc == player || (!phantom && pc.IsModdedClient()) || (phantom && pc.IsImpostor())) continue; + var sender = CustomRpcSender.Create("RpcResetInvisibility", SendOption.Reliable); + sender.StartMessage(pc.GetClientId()); + sender.StartRpc(player.NetId, (byte)RpcCalls.Exiled) + .EndRpc(); + RoleTypes role = Utils.GetRoleMap(pc.PlayerId, player.PlayerId).RoleType; + sender.StartRpc(player.NetId, (byte)RpcCalls.SetRole) + .Write((ushort)role) + .Write(true) + .EndRpc(); + sender.StartRpc(player.NetId, (byte)RpcCalls.CancelPet) + .EndRpc(); + sender.StartRpc(player.NetTransform.NetId, (byte)RpcCalls.SnapTo) + .WriteVector2(new Vector2(50f, 50f)) + .Write((ushort)(player.NetTransform.lastSequenceId + 32767)) + .EndRpc(); + sender.StartRpc(player.NetTransform.NetId, (byte)RpcCalls.SnapTo) + .WriteVector2(new Vector2(50f, 50f)) + .Write((ushort)(player.NetTransform.lastSequenceId + 32767 + 16383)) + .EndRpc(); + sender.StartRpc(player.NetTransform.NetId, (byte)RpcCalls.SnapTo) + .WriteVector2(new Vector2(50f, 50f)) + .Write(player.NetTransform.lastSequenceId) + .EndRpc(); + sender.StartRpc(player.NetTransform.NetId, (byte)RpcCalls.SnapTo) + .WriteVector2(new Vector2(50f, 50f)) + .Write((ushort)(player.NetTransform.lastSequenceId + 16383)) + .EndRpc(); + sender.EndMessage(); + sender.SendMessage(); + } + + Logger.Info($"Reset invisibility for {player.GetNameWithRole()}", "RpcResetInvisibility"); } public static void AddKillTimerToDict(this PlayerControl pc, bool half = false, float cd = -1f) diff --git a/Modules/GhostRolesManager.cs b/Modules/GhostRolesManager.cs index 437600878..f27df603c 100644 --- a/Modules/GhostRolesManager.cs +++ b/Modules/GhostRolesManager.cs @@ -97,6 +97,7 @@ internal static class GhostRolesManager switch (pc.GetCustomRole()) { + case CustomRoles.GM: case CustomRoles.Curser: case CustomRoles.Backstabber: case CustomRoles.Workaholic when !Workaholic.WorkaholicCannotWinAtDeath.GetBool(): diff --git a/Modules/ModUpdater.cs b/Modules/ModUpdater.cs index 3c634e23e..7518c4619 100644 --- a/Modules/ModUpdater.cs +++ b/Modules/ModUpdater.cs @@ -152,7 +152,7 @@ public static class ModUpdater { try { - if (Directory.Exists("TOH_DATA") && File.Exists("./EHR_DATA/BanWords.txt")) + if (Directory.Exists("TOH_DATA") && File.Exists($"{Main.DataPath}/EHR_DATA/BanWords.txt")) { DirectoryInfo di = new("TOH_DATA"); di.Delete(true); diff --git a/Modules/OptionSaver.cs b/Modules/OptionSaver.cs index f04217be1..99563c411 100644 --- a/Modules/OptionSaver.cs +++ b/Modules/OptionSaver.cs @@ -7,7 +7,7 @@ namespace EHR.Modules; // https://github.com/tukasa0001/TownOfHost/blob/main/Modules/OptionSaver.cs public static class OptionSaver { - private static readonly DirectoryInfo SaveDataDirectoryInfo = new("./EHR_DATA/SaveData/"); + private static readonly DirectoryInfo SaveDataDirectoryInfo = new($"{Main.DataPath}/EHR_DATA/SaveData/"); private static readonly FileInfo OptionSaverFileInfo = new($"{SaveDataDirectoryInfo.FullName}/Options.json"); private static readonly LogHandler Logger = EHR.Logger.Handler(nameof(OptionSaver)); private static readonly FileInfo DefaultPresetFileInfo = new($"{SaveDataDirectoryInfo.FullName}/DefaultPreset.txt"); diff --git a/Modules/PrivateTagManager.cs b/Modules/PrivateTagManager.cs index 3f7848b76..36da9f432 100644 --- a/Modules/PrivateTagManager.cs +++ b/Modules/PrivateTagManager.cs @@ -6,7 +6,7 @@ namespace EHR.Modules; public static class PrivateTagManager { - private const string TagFile = "./EHR_DATA/tags.txt"; + private const string TagFile = $"{Main.DataPath}/EHR_DATA/tags.txt"; public static Dictionary Tags = []; public static void AddTag(string friendcode, string tag) diff --git a/Modules/RPC.cs b/Modules/RPC.cs index 9434e54c1..a9b4ee005 100644 --- a/Modules/RPC.cs +++ b/Modules/RPC.cs @@ -150,6 +150,7 @@ public enum CustomRPC SyncAllergic, SyncAsthmatic, ParityCopCommand, + Invisibility, // Game Modes RoomRushDataSync, @@ -1292,6 +1293,12 @@ internal static class RPCHandlerPatch ParityCop.ReceiveRPC(reader); break; } + case CustomRPC.Invisibility: + { + if (reader.ReadBoolean()) __instance.MakeInvisible(); + else __instance.MakeVisible(); + break; + } } } catch (Exception e) { Utils.ThrowException(e); } diff --git a/Modules/SpamManager.cs b/Modules/SpamManager.cs index 0f00d0ffd..1cb494d4a 100644 --- a/Modules/SpamManager.cs +++ b/Modules/SpamManager.cs @@ -12,7 +12,7 @@ namespace EHR; public static class SpamManager { - private const string BannedWordsFilePath = "./EHR_DATA/BanWords.txt"; + private const string BannedWordsFilePath = $"{Main.DataPath}/EHR_DATA/BanWords.txt"; private static List BanWords = []; public static void Init() diff --git a/Modules/TemplateManager.cs b/Modules/TemplateManager.cs index a2d55d219..bee20ba0c 100644 --- a/Modules/TemplateManager.cs +++ b/Modules/TemplateManager.cs @@ -16,7 +16,7 @@ namespace EHR; public static class TemplateManager { - private const string TemplateFilePath = "./EHR_DATA/template.txt"; + private const string TemplateFilePath = $"{Main.DataPath}/EHR_DATA/template.txt"; private static readonly Dictionary> ReplaceDictionary = new() { diff --git a/Modules/Translator.cs b/Modules/Translator.cs index 55bf07b89..1dfacce4e 100644 --- a/Modules/Translator.cs +++ b/Modules/Translator.cs @@ -148,18 +148,15 @@ public static class Translator try { - if (TranslateMaps.TryGetValue(str, out Dictionary dic) && (!dic.TryGetValue((int)langId, out res) || res == "" || (langId is not SupportedLangs.SChinese and not SupportedLangs.TChinese && Regex.IsMatch(res, @"[\u4e00-\u9fa5]") && res == GetString(str, SupportedLangs.SChinese)))) + if (TranslateMaps.TryGetValue(str, out Dictionary dic) && (!dic.TryGetValue((int)langId, out res) || string.IsNullOrEmpty(res) || (langId is not SupportedLangs.SChinese and not SupportedLangs.TChinese && Regex.IsMatch(res, @"[\u4e00-\u9fa5]") && res == GetString(str, SupportedLangs.SChinese)))) res = langId == SupportedLangs.English ? $"*{str}" : GetString(str, SupportedLangs.English); - if (!TranslateMaps.ContainsKey(str)) - { - StringNames[] stringNames = Enum.GetValues().Where(x => x.ToString() == str).ToArray(); - if (stringNames.Length > 0) res = GetString(stringNames.FirstOrDefault()); - } + if (!TranslateMaps.ContainsKey(str) && Enum.GetValues().FindFirst(x => x.ToString() == str, out StringNames stringNames)) + res = GetString(stringNames); } catch (Exception ex) { - Logger.Fatal($"Error oucured at [{str}] in String.csv", "Translator"); + Logger.Fatal($"Error oucured at [{str}] in the translation file", "Translator"); Logger.Error("Here was the error:\n" + ex, "Translator"); } @@ -168,6 +165,9 @@ public static class Translator public static string GetString(StringNames stringName) { +#if ANDROID + return TranslationController.Instance.GetString(stringName); +#endif return FastDestroyableSingleton.Instance.GetString(stringName, new Il2CppReferenceArray(0)); } diff --git a/Modules/Utils.cs b/Modules/Utils.cs index 1c7834cf6..3a4971331 100644 --- a/Modules/Utils.cs +++ b/Modules/Utils.cs @@ -11,6 +11,7 @@ using System.Text; using System.Text.RegularExpressions; using AmongUs.Data; using AmongUs.GameOptions; +using AmongUs.InnerNet.GameDataMessages; using EHR.AddOns.Common; using EHR.AddOns.Crewmate; using EHR.AddOns.GhostRoles; @@ -393,8 +394,8 @@ public static class Utils public static void SaveComboInfo() { - SaveFile("./EHR_DATA/AlwaysCombos.json"); - SaveFile("./EHR_DATA/NeverCombos.json"); + SaveFile($"{Main.DataPath}/EHR_DATA/AlwaysCombos.json"); + SaveFile($"{Main.DataPath}/EHR_DATA/NeverCombos.json"); return; void SaveFile(string path) @@ -428,8 +429,8 @@ public static class Utils public static void LoadComboInfo() { - LoadFile("./EHR_DATA/AlwaysCombos.json"); - LoadFile("./EHR_DATA/NeverCombos.json"); + LoadFile($"{Main.DataPath}/EHR_DATA/AlwaysCombos.json"); + LoadFile($"{Main.DataPath}/EHR_DATA/NeverCombos.json"); return; void LoadFile(string path) @@ -2594,7 +2595,7 @@ public static class Utils } if (GameStartTimeStamp + 44 > TimeStamp && Main.HasPlayedGM.TryGetValue(Options.CurrentGameMode, out HashSet playedFCs) && !playedFCs.Contains(seer.FriendCode)) - SelfSuffix.Append($"\n\n{GetString($"GameModeTutorial.{Options.CurrentGameMode}")}\n"); + SelfSuffix.Append($"\n\n<#ffffff>{GetString($"GameModeTutorial.{Options.CurrentGameMode}")}\n"); } bool noRoleText = GameStates.IsLobby || Options.CurrentGameMode is CustomGameMode.CaptureTheFlag or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush or CustomGameMode.KingOfTheZones or CustomGameMode.Quiz or CustomGameMode.TheMindGame or CustomGameMode.BedWars; @@ -2631,9 +2632,11 @@ public static class Utils if (!GameStates.IsLobby) { - if (Options.CurrentGameMode == CustomGameMode.Quiz) selfName = string.Empty; + if (Options.CurrentGameMode is CustomGameMode.Quiz or CustomGameMode.BedWars) + selfName = string.Empty; - if (NameNotifyManager.GetNameNotify(seer, out string name) && name.Length > 0) selfName = name; + if (Options.CurrentGameMode != CustomGameMode.BedWars && NameNotifyManager.GetNameNotify(seer, out string name) && name.Length > 0) + selfName = name; switch (Options.CurrentGameMode) { @@ -3989,6 +3992,85 @@ public static class Utils float minTime = Mathf.Max(0.5f, AmongUsClient.Instance.Ping / divice * 6f); return minTime; } + + // Next 2: From MoreGamemodes by Rabek009 + + public static void CreateDeadBody(Vector3 position, byte colorId, PlayerControl deadBodyParent) + { + int baseColorId = deadBodyParent.Data.DefaultOutfit.ColorId; + deadBodyParent.Data.DefaultOutfit.ColorId = colorId; + DeadBody deadBody = Object.Instantiate(GameManager.Instance.DeadBodyPrefab); + deadBody.enabled = false; + deadBody.ParentId = deadBodyParent.PlayerId; + foreach (SpriteRenderer b in deadBody.bodyRenderers) + deadBodyParent.SetPlayerMaterialColors(b); + deadBodyParent.SetPlayerMaterialColors(deadBody.bloodSplatter); + Vector3 vector = position + deadBodyParent.KillAnimations[0].BodyOffset; + vector.z = vector.y / 1000f; + deadBody.transform.position = vector; + deadBodyParent.Data.DefaultOutfit.ColorId = baseColorId; + } + + public static void RpcCreateDeadBody(Vector3 position, byte colorId, PlayerControl deadBodyParent, SendOption sendOption = SendOption.Reliable) + { + if (deadBodyParent == null || !Main.IntroDestroyed) return; + CreateDeadBody(position, colorId, deadBodyParent); + PlayerControl playerControl = Object.Instantiate(AmongUsClient.Instance.PlayerPrefab, Vector2.zero, Quaternion.identity); + playerControl.PlayerId = deadBodyParent.PlayerId; + playerControl.isNew = false; + playerControl.notRealPlayer = true; + playerControl.NetTransform.SnapTo(position); + AmongUsClient.Instance.NetIdCnt += 1U; + var sender = CustomRpcSender.Create("Utils.RpcCreateDeadBody", sendOption); + MessageWriter writer = sender.stream; + writer.StartMessage(5); + writer.Write(AmongUsClient.Instance.GameId); + SpawnGameDataMessage item = AmongUsClient.Instance.CreateSpawnMessage(playerControl, -2, SpawnFlags.None); + item.SerializeValues(writer); + + if (GameStates.CurrentServerType == GameStates.ServerType.Vanilla) + { + for (uint i = 1; i <= 3; ++i) + { + writer.StartMessage(4); + writer.WritePacked(2U); + writer.WritePacked(-2); + writer.Write((byte)SpawnFlags.None); + writer.WritePacked(1); + writer.WritePacked(AmongUsClient.Instance.NetIdCnt - i); + writer.StartMessage(1); + writer.EndMessage(); + writer.EndMessage(); + } + } + + if (PlayerControl.AllPlayerControls.Contains(playerControl)) + PlayerControl.AllPlayerControls.Remove(playerControl); + int baseColorId = playerControl.Data.DefaultOutfit.ColorId; + sender.StartRpc(playerControl.NetId, (byte)RpcCalls.SetColor) + .Write(playerControl.Data.NetId) + .Write(colorId) + .EndRpc(); + sender.StartRpc(playerControl.NetId, (byte)RpcCalls.MurderPlayer) + .WriteNetObject(playerControl) + .Write((int)MurderResultFlags.Succeeded) + .EndRpc(); + sender.StartRpc(playerControl.NetId, (byte)RpcCalls.SetColor) + .Write(playerControl.Data.NetId) + .Write(baseColorId) + .EndRpc(); + writer.StartMessage(1); + writer.WritePacked(playerControl.Data.NetId); + playerControl.Data.Serialize(writer, false); + writer.EndMessage(); + writer.StartMessage(5); + writer.WritePacked(playerControl.NetId); + writer.EndMessage(); + AmongUsClient.Instance.RemoveNetObject(playerControl); + Object.Destroy(playerControl.gameObject); + sender.EndMessage(); + sender.SendMessage(); + } } public class Message(string text, byte sendTo = byte.MaxValue, string title = "") diff --git a/Patches/ChatCommandPatch.cs b/Patches/ChatCommandPatch.cs index 3c9bfbb4c..c12963e77 100644 --- a/Patches/ChatCommandPatch.cs +++ b/Patches/ChatCommandPatch.cs @@ -237,7 +237,7 @@ internal static class ChatCommands if (LastModFileUpdate + 5 > now) { friendCodes = ModsFileCache; } else { - const string friendCodesFilePath = "./EHR_DATA/Moderators.txt"; + const string friendCodesFilePath = $"{Main.DataPath}/EHR_DATA/Moderators.txt"; if (!File.Exists(friendCodesFilePath)) { @@ -265,7 +265,7 @@ internal static class ChatCommands if (LastVIPFileUpdate + 5 > now) { friendCodes = VIPsFileCache; } else { - const string friendCodesFilePath = "./EHR_DATA/VIPs.txt"; + const string friendCodesFilePath = $"{Main.DataPath}/EHR_DATA/VIPs.txt"; if (!File.Exists(friendCodesFilePath)) { @@ -559,8 +559,7 @@ internal static class ChatCommands if (pc == null) return; Color color = ColorUtility.TryParseHtmlString($"#{args[2].ToLower()}", out Color c) ? c : Color.red; - string tag = Utils.ColorString(color, string.Join(' ', args[3..])); - if (!tag.EndsWith(' ') && !tag.EndsWith('-') && !tag.EndsWith('>')) tag += " "; + string tag = Utils.ColorString(color, string.Join(' ', args[3..]) + " "); PrivateTagManager.AddTag(pc.FriendCode, tag); Utils.SendMessage("\n", player.PlayerId, string.Format(GetString("AddTagSuccess"), tag, id.ColoredPlayerName(), id)); @@ -1074,7 +1073,7 @@ internal static class ChatCommands string roleName = GetString(role.ToString()); StringBuilder sb = new(); StringBuilder settings = new(); - var title = $"<{coloredString} {Utils.GetRoleMode(role)}"; + var title = $"{coloredString} {Utils.GetRoleMode(role)}"; sb.Append(GetString($"{role}InfoLong").TrimStart()); if (Options.CustomRoleSpawnChances.TryGetValue(role, out StringOptionItem chance)) AddSettings(chance); if (role is CustomRoles.LovingCrewmate or CustomRoles.LovingImpostor && Options.CustomRoleSpawnChances.TryGetValue(CustomRoles.Lovers, out chance)) AddSettings(chance); @@ -1227,8 +1226,8 @@ internal static class ChatCommands string fc = VIPPc.FriendCode.Replace(':', '#'); if (!IsPlayerVIP(fc)) Utils.SendMessage(GetString("PlayerNotVIP"), player.PlayerId); - string[] lines = File.ReadAllLines("./EHR_DATA/VIPs.txt").Where(line => !line.Contains(fc)).ToArray(); - File.WriteAllLines("./EHR_DATA/VIPs.txt", lines); + string[] lines = File.ReadAllLines($"{Main.DataPath}/EHR_DATA/VIPs.txt").Where(line => !line.Contains(fc)).ToArray(); + File.WriteAllLines($"{Main.DataPath}/EHR_DATA/VIPs.txt", lines); Utils.SendMessage(GetString("PlayerRemovedFromVIPList"), player.PlayerId); } @@ -1242,7 +1241,7 @@ internal static class ChatCommands string fc = newVIPPc.FriendCode.Replace(':', '#'); if (IsPlayerVIP(fc)) Utils.SendMessage(GetString("PlayerAlreadyVIP"), player.PlayerId); - File.AppendAllText("./EHR_DATA/VIPs.txt", $"\n{fc}"); + File.AppendAllText($"{Main.DataPath}/EHR_DATA/VIPs.txt", $"\n{fc}"); Utils.SendMessage(GetString("PlayerAddedToVIPList"), player.PlayerId); } @@ -2301,7 +2300,7 @@ internal static class ChatCommands string remFc = remModPc.FriendCode.Replace(':', '#'); if (!IsPlayerModerator(remFc)) Utils.SendMessage(GetString("PlayerNotMod"), player.PlayerId); - File.WriteAllLines("./EHR_DATA/Moderators.txt", File.ReadAllLines("./EHR_DATA/Moderators.txt").Where(x => !x.Contains(remFc))); + File.WriteAllLines($"{Main.DataPath}/EHR_DATA/Moderators.txt", File.ReadAllLines($"{Main.DataPath}/EHR_DATA/Moderators.txt").Where(x => !x.Contains(remFc))); Utils.SendMessage(GetString("PlayerRemovedFromModList"), player.PlayerId); } @@ -2321,7 +2320,7 @@ internal static class ChatCommands string fc = newModPc.FriendCode.Replace(':', '#'); if (IsPlayerModerator(fc)) Utils.SendMessage(GetString("PlayerAlreadyMod"), player.PlayerId); - File.AppendAllText("./EHR_DATA/Moderators.txt", $"\n{fc}"); + File.AppendAllText($"{Main.DataPath}/EHR_DATA/Moderators.txt", $"\n{fc}"); Utils.SendMessage(GetString("PlayerAddedToModList"), player.PlayerId); } diff --git a/Patches/IntroPatch.cs b/Patches/IntroPatch.cs index e284e8e11..e6f4557bc 100644 --- a/Patches/IntroPatch.cs +++ b/Patches/IntroPatch.cs @@ -986,7 +986,7 @@ internal static class BeginImpostorPatch } } -[HarmonyPatch(typeof(IntroCutscene), nameof(IntroCutscene.OnDestroy))] +[HarmonyPatch(typeof(HudManager), nameof(HudManager.OnGameStart))] internal static class IntroCutsceneDestroyPatch { public static void Postfix( /*IntroCutscene __instance*/) diff --git a/Patches/LadderPatch.cs b/Patches/LadderPatch.cs index d4b8bebd1..133c667ed 100644 --- a/Patches/LadderPatch.cs +++ b/Patches/LadderPatch.cs @@ -17,6 +17,11 @@ public class FallFromLadder public static void OnClimbLadder(PlayerPhysics player, Ladder source) { + PlayerControl pc = player.myPlayer; + + if (pc.shouldAppearInvisible || pc.invisibilityAlpha < 1f) + pc.RpcResetInvisibility(); + if (!Options.LadderDeath.GetBool()) return; Vector3 sourcePos = source.transform.position; @@ -25,7 +30,7 @@ public class FallFromLadder if (sourcePos.y > targetPos.y) { int chance = IRandom.Instance.Next(1, 101); - if (chance <= Chance) TargetLadderData[player.myPlayer.PlayerId] = targetPos; + if (chance <= Chance) TargetLadderData[pc.PlayerId] = targetPos; } } @@ -33,7 +38,7 @@ public class FallFromLadder { if (player.Data.Disconnected) return; - if (TargetLadderData.ContainsKey(player.PlayerId) && Vector2.Distance(TargetLadderData[player.PlayerId], player.transform.position) < 0.5f) + if (TargetLadderData.TryGetValue(player.PlayerId, out Vector3 targetLadderData) && Vector2.Distance(targetLadderData, player.Pos()) < 0.5f) { if (player.Data.IsDead) return; @@ -42,7 +47,7 @@ public class FallFromLadder LateTask.New(() => { - Vector2 targetPos = (Vector2)TargetLadderData[player.PlayerId] + new Vector2(0.1f, 0f); + Vector2 targetPos = (Vector2)targetLadderData + new Vector2(0.1f, 0f); var num = (ushort)(NetHelpers.XRange.ReverseLerp(targetPos.x) * 65535f); var num2 = (ushort)(NetHelpers.YRange.ReverseLerp(targetPos.y) * 65535f); var sender = CustomRpcSender.Create("LadderFallRpc", SendOption.Reliable); diff --git a/Patches/PlayerControlPatch.cs b/Patches/PlayerControlPatch.cs index 2a434f785..6bf752642 100644 --- a/Patches/PlayerControlPatch.cs +++ b/Patches/PlayerControlPatch.cs @@ -1654,6 +1654,7 @@ internal static class FixedUpdatePatch case CustomGameMode.SoloKombat: SoloPVP.GetNameNotify(target, ref realName); break; + case CustomGameMode.BedWars when self: case CustomGameMode.Quiz when self: realName = string.Empty; break; @@ -1661,7 +1662,8 @@ internal static class FixedUpdatePatch if (Deathpact.IsInActiveDeathpact(seer)) realName = Deathpact.GetDeathpactString(seer); - if (NameNotifyManager.GetNameNotify(target, out string name) && name.Length > 0) realName = name; + if (Options.CurrentGameMode != CustomGameMode.BedWars && NameNotifyManager.GetNameNotify(target, out string name) && name.Length > 0) + realName = name; } // Name Color Manager @@ -1830,14 +1832,14 @@ internal static class FixedUpdatePatch break; } - if (self && GameStartTimeStamp + 44 > TimeStamp && Main.HasPlayedGM.TryGetValue(Options.CurrentGameMode, out HashSet playedFCs) && !playedFCs.Contains(seer.FriendCode)) - Suffix.Append($"\n\n{GetString($"GameModeTutorial.{Options.CurrentGameMode}")}\n"); - if (MeetingStates.FirstMeeting && Main.ShieldPlayer == target.FriendCode && !string.IsNullOrEmpty(target.FriendCode) && !self && Options.CurrentGameMode is CustomGameMode.Standard or CustomGameMode.SoloKombat or CustomGameMode.FFA) additionalSuffixes.Add(GetString("DiedR1Warning")); Suffix.Append(string.Join('\n', additionalSuffixes.ConvertAll(x => x.Trim()).FindAll(x => !string.IsNullOrEmpty(x)))); + if (self && GameStartTimeStamp + 44 > TimeStamp && Main.HasPlayedGM.TryGetValue(Options.CurrentGameMode, out HashSet playedFCs) && !playedFCs.Contains(seer.FriendCode)) + Suffix.Append($"\n\n<#ffffff>{GetString($"GameModeTutorial.{Options.CurrentGameMode}")}\n"); + // Devourer if (Devourer.HideNameOfConsumedPlayer.GetBool() && Devourer.PlayerIdList.Any(x => Main.PlayerStates[x].Role is Devourer { IsEnable: true } dv && dv.PlayerSkinsCosumed.Contains(target.PlayerId))) realName = GetString("DevouredName"); diff --git a/Patches/ShipStatusPatch.cs b/Patches/ShipStatusPatch.cs index 63a4bdb5e..057f194da 100644 --- a/Patches/ShipStatusPatch.cs +++ b/Patches/ShipStatusPatch.cs @@ -121,9 +121,9 @@ internal static class RepairSystemPatch { if (Main.NormalOptions.MapId == 4) { - if (Options.DisableAirshipViewingDeckLightsPanel.GetBool() && Vector2.Distance(player.transform.position, new(-12.93f, -11.28f)) <= 2f) return false; - if (Options.DisableAirshipGapRoomLightsPanel.GetBool() && Vector2.Distance(player.transform.position, new(13.92f, 6.43f)) <= 2f) return false; - if (Options.DisableAirshipCargoLightsPanel.GetBool() && Vector2.Distance(player.transform.position, new(30.56f, 2.12f)) <= 2f) return false; + if (Options.DisableAirshipViewingDeckLightsPanel.GetBool() && Vector2.Distance(player.Pos(), new(-12.93f, -11.28f)) <= 2f) return false; + if (Options.DisableAirshipGapRoomLightsPanel.GetBool() && Vector2.Distance(player.Pos(), new(13.92f, 6.43f)) <= 2f) return false; + if (Options.DisableAirshipCargoLightsPanel.GetBool() && Vector2.Distance(player.Pos(), new(30.56f, 2.12f)) <= 2f) return false; } var switchSystem = ShipStatus.Instance?.Systems?[SystemTypes.Electrical]?.CastFast(); diff --git a/Patches/TextBoxPatch.cs b/Patches/TextBoxPatch.cs index 7211f8166..cd4e526c3 100644 --- a/Patches/TextBoxPatch.cs +++ b/Patches/TextBoxPatch.cs @@ -204,7 +204,7 @@ public static class TextBoxPatch "{addon}" => !ChatCommands.GetRoleByName(arg, out CustomRoles role) || !role.IsAdditionRole(), "{letter}" => arg.Length != 1 || !char.IsLetter(arg[0]), "{chance}" => !int.TryParse(arg, out int chance) || chance < 0 || chance > 100 || chance % 5 != 0, - "{color}" => arg.Length != 6 || !arg.All(x => char.IsDigit(x) || x is >= 'a' and <= 'f') || !ColorUtility.TryParseHtmlString($"#{arg}", out _), + "{color}" => arg.Length != 6 || !arg.All(x => char.IsDigit(x) || x is >= 'a' and <= 'f' or >= 'A' and <= 'F') || !ColorUtility.TryParseHtmlString($"#{arg}", out _), _ => false }; @@ -217,7 +217,7 @@ public static class TextBoxPatch "{role}" or "[role]" => ChatCommands.GetRoleByName(arg, out _), "{addon}" => ChatCommands.GetRoleByName(arg, out CustomRoles role) && role.IsAdditionRole(), "{chance}" => int.TryParse(arg, out int chance) && chance is >= 0 and <= 100 && chance % 5 == 0, - "{color}" => arg.Length == 6 && arg.All(x => char.IsDigit(x) || x is >= 'a' and <= 'f') && ColorUtility.TryParseHtmlString($"#{arg.ToLower()}", out _), + "{color}" => arg.Length == 6 && arg.All(x => char.IsDigit(x) || x is >= 'a' and <= 'f' or >= 'A' and <= 'F') && ColorUtility.TryParseHtmlString($"#{arg}", out _), _ => false }; diff --git a/Resources/Lang/en_US.json b/Resources/Lang/en_US.json index 977aee2fb..662eeca28 100644 --- a/Resources/Lang/en_US.json +++ b/Resources/Lang/en_US.json @@ -4823,7 +4823,7 @@ "CTF_WhenFlagCarrierGetsTagged.FlagIsReturned": "Returned", "CTF_SpeedReductionForFlagCarrier": "Speed Reduction for Flag Carriers", "CTF_TagCooldown": "Tag Cooldown", - "CTF_GameEndCriteria": "Game End Criteria (if it's a tie when the game should end, it will continue until the tie is broken)", + "CTF_GameEndCriteria": "Game End Criteria", "CTF_GameEndCriteria.PlayXRounds": "Play X Rounds", "CTF_GameEndCriteria.FirstToXPoints": "First to X Points", "CTF_GameEndCriteria.TimeLimit": "Time Limit", @@ -5062,7 +5062,7 @@ "TMGPlayerInfoLong": "THINK WITH OTHERS' BRAINS TO WIN", "BedWars": "BED WARS", "ModeBedWars": "Gamemode: Bed Wars", - "ModeDescribe.BedWars": "In the Bed Wars gamemode, players are split into teams. Each team has a bed. If a team's bed is destroyed, all players in that team can no longer respawn. The goal is to destroy all other teams' beds and be the last team alive.\\n\\nYou can buy items (blocks, weapons, tool, etc.) and team upgrades (heal pool, haste, trap, etc.) in shops from the resources (iron, gold, diamond, emerald) you can collect from the generators on the map.\\n\\nIn the beginning, there's a grace period, where no attacks are allowed, and players can't leave their own base.\\n\\nEach player has an inventory with all of their items. Cycle through the slots using the Vanish button. Use weapons through the kill button, other items via Pet. To start breaking someone's bed, Pet. Make sure to always have the correct item selected in your inventory (swords when you're fighting, blocks when you protect the bed, tools when you break beds, etc.).", + "ModeDescribe.BedWars": "In the Bed Wars gamemode, players are split into teams. Each team has a bed. If a team's bed is destroyed, all players in that team can no longer respawn. The goal is to destroy all other teams' (via Pet button) beds and be the last team alive.\\n\\nYou can buy items (blocks, weapons, tool, etc.) and team upgrades (heal pool, haste, trap, etc.) in shops from the resources (iron, gold, diamond, emerald) you can collect from the generators on the map. These are useful for protecting the bed with various layers to make it harder to break it, increase your attack damage, increase your defense, or give you or your team various abilities.\\n\\nIn the beginning, there's a grace period, where no attacks are allowed, and players can't leave their own base.\\n\\nEach player has an inventory with all of their items. Cycle through the slots using the Vanish button. Use weapons through the kill button, other items via Pet. To start breaking someone's bed, Pet. Make sure to always have the correct item selected in your inventory (swords when you're fighting, blocks when you protect the bed, tools when you break beds, etc.).\\nYou can break beds with anything, but using the correct tool for each layer will make the process significantly faster.\\n\\nIf you die, you will respawn after a few seconds, unless your bed is broken. If your bed is broken, you will not respawn anymore.", "Bedwars.Shop.ItemShop": "ITEM SHOP", "Bedwars.Shop.UpgradeShop": "UPGRADE SHOP", "Bedwars.Rooms": "Teams are located in the following rooms:", @@ -5070,21 +5070,22 @@ "Bedwars.TrapTriggered": "<#ff0000>TRAP TRIGGERED!\\n{0} entered your base!", "Bedwars.ReviveCountdown": "<#ff0000>YOU DIED!\\nYou will respawn in <#ffff44>{0} seconds.", "Bedwars.GracePeriod": "<#ffff44>GRACE PERIOD\\nDuring this time, you cannot leave your room", + "Bedwars.CannotKillWhileBreakingBed": "<#ff0000>You cannot use your kill button while breaking a bed!", "BedWars.Suffix.Armor": "Armor:", "Bedwars.BlueTeam": "Blue Team", "Bedwars.RedTeam": "Red Team", "Bedwars.GreenTeam": "Green Team", "Bedwars.YellowTeam": "Yellow Team", - "Bedwars.Shop.ItemShopSuffix.CategorySelection": "<#00ffa5>{0}\\n{1}\\n\\nSelect the category that has the item you want to buy.\\nUse the Vanish button to cycle through the categories.\\nPet to enter the category.", + "Bedwars.Shop.ItemShopSuffix.CategorySelection": "<#00ffa5>{0}\\n{1}\\n\\nSelect the category that has the item you want to buy.\\nUse the Vanish button to cycle through the categories.\\nPet to enter the category.", "BedWars.ItemCategory.Resource": "RESOURCES", "BedWars.ItemCategory.Block": "BLOCKS", "BedWars.ItemCategory.Weapon": "WEAPONS", "BedWars.ItemCategory.Armor": "ARMOR", "BedWars.ItemCategory.Tool": "TOOLS", "BedWars.ItemCategory.Utility": "UTILITIES", - "Bedwars.Shop.ItemShopSuffix.ItemSelection": "{0} {1}\\n{2}\\n\\nCost: {3}\\n\\nSelect the item you want to buy.\\nUse the Vanish button to cycle through the items.\\nPet to buy the selected item.", + "Bedwars.Shop.ItemShopSuffix.ItemSelection": "{0} {1}\\n{2}\\nCost: {3}\\n\\nSelect the item you want to buy.\\nUse the Vanish button to cycle through the items.\\nPet to buy the selected item.", "BedWars.Upgrade.AlreadyBought": "<#00ff00>Your team already has this upgrade!", - "Bedwars.Shop.UpgradeShopSuffix": "<#00a5ff>{0}\\n{1}{2}\\n\\nCost: {3}\\n\\nSelect the upgrade you want to buy for your team.\\nUse the Vanish button to cycle through the upgrades.\\nPet to buy the selected upgrade.", + "Bedwars.Shop.UpgradeShopSuffix": "<#00a5ff>{0}\\n{1}{2}\\nCost: {3}\\n\\nSelect the upgrade you want to buy for your team.\\nUse the Vanish button to cycle through the upgrades.\\nPet to buy the selected upgrade.", "BedWars.Upgrade.ReinforcedArmor": "REINFORCED ARMOR", "BedWars.Upgrade.Sharpness": "SHARPNESS", "BedWars.Upgrade.Haste": "HASTE", @@ -5148,6 +5149,32 @@ "Bedwars.BedStatus.Broken": "<#ff0000>BED DESTROYED!\\nYou will no longer respawn!", "Bedwars.BedStatus.EnemyBroken": "{0}'s bed has been destroyed!", "Bedwars.HudText.GracePeriodLeft": "Grace period ends\\nin <#ffff44>{0} seconds", + "BedWars.SpeedPotionDurationOption": "Speed Potion Duration", + "BedWars.InvisPotionDurationOption": "Invisibility Potion Duration", + "BedWars.ReviveTimeOption": "Revive Time", + "BedWars.IronGenerationIntervalOption": "Iron Generation Interval", + "BedWars.GoldGenerationIntervalOption": "Gold Generation Interval", + "BedWars.EmeraldGenerationIntervalOption": "Emerald Generation Interval", + "BedWars.DiamondGenerationIntervalOption": "Diamond Generation Interval", + "BedWars.GracePeriodOption": "Grace Period Duration", + "BedWars.HealWaitAfterDamageOption": "Heal Cooldown After Damage", + "BedWars.MaxHealthOption": "Maximum Health", + "BedWars.TrapEffectDurationOption": "Trap Effect Duration", + "BedWars.TNTDamageOption": "TNT Damage", + "BedWars.TNTBedDamageOption": "TNT Bed Damage", + "BedWars.TNTRangeOption": "TNT Range", + "BedWars.TrapTriggerRangeOption": "Trap Trigger Range", + "BedWars.HealPoolRangeOption": "Heal Pool Range", + "BedWars.ShopAndItemGeneratorRangeOption": "Shop and Item Generators' Pickup Range", + "BedWars.BedBreakAndProtectRangeOption": "Beds' Break and Protect Range", + "BedWars.IronArmorDamageDivisionOption": "Iron Armor Damage Division", + "BedWars.DiamondArmorDamageDivisionOption": "Diamond Armor Damage Division", + "BedWars.SpeedPotionSpeedIncreaseOption": "Speed Potion Speed Increase", + "BedWars.TrappedSpeedDecreaseOption": "Decrease Trapped Players' Speed By", + "BedWars.TrappedVisionOption": "Trapped Players' Vision", + "BedWars.WoodenSwordDamageMultiplierOption": "Wooden Sword Damage Multiplier", + "BedWars.IronSwordDamageMultiplierOption": "Iron Sword Damage Multiplier", + "BedWars.DiamondSwordDamageMultiplierOption": "Diamond Sword Damage Multiplier", "BedWarsPlayer": "BED WARS", "BedWarsPlayerInfo": "DESTROY ALL BEDS TO WIN", "BedWarsPlayerInfoLong": "DESTROY ALL BEDS TO WIN", diff --git a/Roles/AddOns/Common/Asthmatic.cs b/Roles/AddOns/Common/Asthmatic.cs index 63f73a69b..a1c76d39e 100644 --- a/Roles/AddOns/Common/Asthmatic.cs +++ b/Roles/AddOns/Common/Asthmatic.cs @@ -101,7 +101,7 @@ internal class Asthmatic : IAddon { if (!Main.IntroDestroyed || !pc.Is(CustomRoles.Asthmatic) || ExileController.Instance || !RunChecks || !Timers.TryGetValue(pc.PlayerId, out Counter counter)) return; - Vector2 currentPosition = pc.transform.position; + Vector2 currentPosition = pc.Pos(); if (CheckInvalidMovementPatch.ExemptedPlayers.Remove(pc.PlayerId) && CheckInvalidMovementPatch.LastPosition.TryGetValue(pc.PlayerId, out Vector2 position)) LastPosition[pc.PlayerId] = position; diff --git a/Roles/Crewmate/Astral.cs b/Roles/Crewmate/Astral.cs index 6b0dd46ac..b3beca224 100644 --- a/Roles/Crewmate/Astral.cs +++ b/Roles/Crewmate/Astral.cs @@ -76,6 +76,7 @@ public class Astral : RoleBase CustomRpcSender.Create("Astral", (SendOption)1).AutoStartRpc(pc.NetId, 4).EndRpc().SendMessage(); LateTask.New(() => pc.RpcSetRoleDesync(RoleTypes.GuardianAngel, pc.OwnerId), 0.2f, log: false); LateTask.New(pc.RpcResetAbilityCooldown, 0.4f, log: false); + LateTask.New(() => pc.SetChatVisible(false), 0.6f, log: false); pc.MarkDirtySettings(); BackTS = Utils.TimeStamp + AbilityDuration.GetInt() + 1; diff --git a/Roles/Crewmate/Farseer.cs b/Roles/Crewmate/Farseer.cs index 4cb66e842..1ec5d844e 100644 --- a/Roles/Crewmate/Farseer.cs +++ b/Roles/Crewmate/Farseer.cs @@ -129,7 +129,7 @@ public class Farseer : RoleBase else { float range = NormalGameOptionsV09.KillDistances[Mathf.Clamp(player.Is(CustomRoles.Reach) ? 2 : Main.NormalOptions.KillDistance, 0, 2)] + 0.5f; - float dis = Vector2.Distance(player.transform.position, arTarget.transform.position); + float dis = Vector2.Distance(player.Pos(), arTarget.Pos()); if (dis <= range) FarseerTimer[player.PlayerId] = (arTarget, arTime + Time.fixedDeltaTime); diff --git a/Roles/Crewmate/Tracefinder.cs b/Roles/Crewmate/Tracefinder.cs index b7c4e8706..fe5dafc67 100644 --- a/Roles/Crewmate/Tracefinder.cs +++ b/Roles/Crewmate/Tracefinder.cs @@ -92,7 +92,7 @@ public class Tracefinder : RoleBase PlayerControl pc = Utils.GetPlayerById(id); if (pc == null || !pc.IsAlive()) continue; - LocateArrow.Add(id, target.transform.position); + LocateArrow.Add(id, target.Pos()); Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc); } } diff --git a/Roles/Impostor/Assassin.cs b/Roles/Impostor/Assassin.cs index 43954339d..b836fa433 100644 --- a/Roles/Impostor/Assassin.cs +++ b/Roles/Impostor/Assassin.cs @@ -16,6 +16,7 @@ internal class Assassin : RoleBase private static OptionItem MarkCooldownOpt; public static OptionItem AssassinateCooldownOpt; private static OptionItem CanKillAfterAssassinateOpt; + private static OptionItem InvisibilityTimeAfterAssassinateOpt; private float AssassinateCooldown; private bool CanKillAfterAssassinate; @@ -39,6 +40,10 @@ internal class Assassin : RoleBase CanKillAfterAssassinateOpt = new BooleanOptionItem(Id + 12, "AssassinCanKillAfterAssassinate", true, TabGroup.ImpostorRoles) .SetParent(CustomRoleSpawnChances[CustomRoles.Assassin]); + + InvisibilityTimeAfterAssassinateOpt = new FloatOptionItem(Id + 13, "AssassinInvisibilityTimeAfterAssassinate", new(0f, 30f, 0.5f), 5f, TabGroup.ImpostorRoles) + .SetParent(CustomRoleSpawnChances[CustomRoles.Assassin]) + .SetValueFormat(OptionFormat.Seconds); } public override void Init() @@ -156,6 +161,22 @@ internal class Assassin : RoleBase { if (pc == null || !pc.IsAlive() || Pelican.IsEaten(pc.PlayerId)) return false; + if (!IsUndertaker) + { + float time = InvisibilityTimeAfterAssassinateOpt.GetFloat(); + + if (time >= 1f) + { + pc.RpcMakeInvisible(); + + LateTask.New(() => + { + if (!GameStates.IsInTask || ExileController.Instance || AntiBlackout.SkipTasks) return; + pc.RpcMakeVisible(); + }, time, log: false); + } + } + Take(pc); return false; } diff --git a/Roles/Impostor/BallLightning.cs b/Roles/Impostor/BallLightning.cs index 33f8d654c..d35a2d7c5 100644 --- a/Roles/Impostor/BallLightning.cs +++ b/Roles/Impostor/BallLightning.cs @@ -169,7 +169,7 @@ public class BallLightning : RoleBase if (pc.PlayerId != gs.PlayerId && pc.IsAlive() && !pc.Is(CustomRoles.BallLightning) && !IsGhost(pc) && !Pelican.IsEaten(pc.PlayerId)) { - Vector3 pos = gs.transform.position; + Vector3 pos = gs.Pos(); float dis = Vector2.Distance(pos, pc.Pos()); if (dis > 0.3f) continue; diff --git a/Roles/Impostor/Deathpact.cs b/Roles/Impostor/Deathpact.cs index 5dc917d92..3557de6fe 100644 --- a/Roles/Impostor/Deathpact.cs +++ b/Roles/Impostor/Deathpact.cs @@ -192,7 +192,7 @@ public class Deathpact : RoleBase foreach (PlayerControl player in dp.PlayersInDeathpact) { float range = NormalGameOptionsV09.KillDistances[Mathf.Clamp(player.Is(CustomRoles.Reach) ? 2 : Main.NormalOptions.KillDistance, 0, 2)] + 0.5f; - cancelDeathpact = dp.PlayersInDeathpact.Where(a => a.PlayerId != player.PlayerId).Select(otherPlayerInPact => Vector2.Distance(player.transform.position, otherPlayerInPact.transform.position)).Aggregate(cancelDeathpact, (current, dis) => current && dis <= range); + cancelDeathpact = dp.PlayersInDeathpact.Where(a => a.PlayerId != player.PlayerId).Select(otherPlayerInPact => Vector2.Distance(player.Pos(), otherPlayerInPact.Pos())).Aggregate(cancelDeathpact, (current, dis) => current && dis <= range); } if (cancelDeathpact) diff --git a/Roles/Impostor/FireWorks.cs b/Roles/Impostor/FireWorks.cs index 40c671ae7..d37f40c8b 100644 --- a/Roles/Impostor/FireWorks.cs +++ b/Roles/Impostor/FireWorks.cs @@ -165,7 +165,7 @@ public class FireWorks : RoleBase { foreach (Vector3 pos in fireWorksPosition) { - float dis = Vector2.Distance(pos, target.transform.position); + float dis = Vector2.Distance(pos, target.Pos()); if (dis > FireWorksRadius) continue; if (target == pc) diff --git a/Roles/Impostor/OverKiller.cs b/Roles/Impostor/OverKiller.cs index a797b1418..3d48cf372 100644 --- a/Roles/Impostor/OverKiller.cs +++ b/Roles/Impostor/OverKiller.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using EHR.Modules; using Hazel; -using InnerNet; namespace EHR.Impostor; @@ -47,7 +46,7 @@ internal class OverKiller : RoleBase { if (!killer.RpcCheckAndMurder(target, true)) return false; - if (killer.PlayerId != target.PlayerId && !target.Is(CustomRoles.Unreportable) && GameStates.IsInTask) + if (killer.PlayerId != target.PlayerId && !target.Is(CustomRoles.Unreportable) && Main.IntroDestroyed && GameStates.IsInTask && !ExileController.Instance && !AntiBlackout.SkipTasks) { Main.PlayerStates[target.PlayerId].deathReason = PlayerState.DeathReason.Dismembered; @@ -79,25 +78,14 @@ internal class OverKiller : RoleBase IEnumerator SpawnFakeDeadBodies() { - for (var i = 0; i < 26; i++) + for (var i = 0; i < 30; i++) { Vector2 location = new(ops.x + ((float)(rd.Next(0, 201) - 100) / 100), ops.y + ((float)(rd.Next(0, 201) - 100) / 100)); location += new Vector2(0, 0.3636f); - MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(target.NetTransform.NetId, (byte)RpcCalls.SnapTo, SendOption.None); - NetHelpers.WriteVector2(location, writer); - writer.Write(target.NetTransform.lastSequenceId); - AmongUsClient.Instance.FinishRpcImmediately(writer); + Utils.RpcCreateDeadBody(location, (byte)target.CurrentOutfit.ColorId, target, SendOption.None); - target.NetTransform.SnapTo(location); - killer.MurderPlayer(target, ExtendedPlayerControl.ResultFlags); - - MessageWriter messageWriter = AmongUsClient.Instance.StartRpcImmediately(killer.NetId, (byte)RpcCalls.MurderPlayer, SendOption.None); - messageWriter.WriteNetObject(target); - messageWriter.Write((byte)ExtendedPlayerControl.ResultFlags); - AmongUsClient.Instance.FinishRpcImmediately(messageWriter); - - if (i % 6 == 0) yield return null; + if (i % 4 == 0) yield return null; } yield return null; diff --git a/Roles/Impostor/Penguin.cs b/Roles/Impostor/Penguin.cs index fdbbd5639..8ab46ed23 100644 --- a/Roles/Impostor/Penguin.cs +++ b/Roles/Impostor/Penguin.cs @@ -369,14 +369,14 @@ public class Penguin : RoleBase if (IsGoose) return; int sId = abductVictim.NetTransform.lastSequenceId + 5; - abductVictim.NetTransform.SnapTo(Penguin_.transform.position, (ushort)sId); + abductVictim.NetTransform.SnapTo(Penguin_.Pos(), (ushort)sId); Penguin_.Kill(abductVictim); var sender = CustomRpcSender.Create("PenguinMurder", SendOption.Reliable); { sender.AutoStartRpc(abductVictim.NetTransform.NetId, RpcCalls.SnapTo); { - NetHelpers.WriteVector2(Penguin_.transform.position, sender.stream); + NetHelpers.WriteVector2(Penguin_.Pos(), sender.stream); sender.Write(abductVictim.NetTransform.lastSequenceId); } sender.EndRpc(); @@ -396,7 +396,7 @@ public class Penguin : RoleBase // SnapToRPC does not work for players on top of the ladder, and only the host behaves differently, so teleporting is not done uniformly. else if (!AbductVictim.MyPhysics.Animations.IsPlayingAnyLadderAnimation()) { - Vector3 position = Penguin_.transform.position; + Vector3 position = Penguin_.Pos(); if (!Penguin_.IsHost()) Utils.TP(AbductVictim.NetTransform, position, log: false); diff --git a/Roles/Impostor/Puppeteer.cs b/Roles/Impostor/Puppeteer.cs index a168a3f52..87cf80111 100644 --- a/Roles/Impostor/Puppeteer.cs +++ b/Roles/Impostor/Puppeteer.cs @@ -185,7 +185,7 @@ internal class Puppeteer : RoleBase } else if (PuppeteerDelayList[playerId] + PuppeteerDelay[playerId] < now) { - Vector2 puppeteerPos = player.transform.position; + Vector2 puppeteerPos = player.Pos(); Dictionary targetDistance = []; foreach (PlayerControl target in Main.AllAlivePlayerControls) @@ -194,7 +194,7 @@ internal class Puppeteer : RoleBase if (target.Is(CustomRoles.Puppeteer) && !PuppeteerPuppetCanKillPuppeteer.GetBool()) continue; if (target.Is(CustomRoleTypes.Impostor) && !PuppeteerPuppetCanKillImpostors.GetBool()) continue; - float dis = Vector2.Distance(puppeteerPos, target.transform.position); + float dis = Vector2.Distance(puppeteerPos, player.Pos()); targetDistance[target.PlayerId] = dis; } diff --git a/Roles/Impostor/RiftMaker.cs b/Roles/Impostor/RiftMaker.cs index 3b90b75a8..6ed09923f 100644 --- a/Roles/Impostor/RiftMaker.cs +++ b/Roles/Impostor/RiftMaker.cs @@ -87,7 +87,7 @@ public class RiftMaker : RoleBase if (LastTP + 5 > TimeStamp) return; - Vector2 position = player.transform.position; + Vector2 position = player.Pos(); var isTP = false; Vector2 from = Marks[0]; @@ -161,7 +161,7 @@ public class RiftMaker : RoleBase private void Mark(PlayerControl player) { - Marks.Add(player.transform.position); + Marks.Add(player.Pos()); if (Marks.Count == 2) LastTP = TimeStamp; player.Notify(GetString("MarkDone")); diff --git a/Roles/Neutral/Agitater.cs b/Roles/Neutral/Agitater.cs index 1b41bd2d1..938f7c675 100644 --- a/Roles/Neutral/Agitater.cs +++ b/Roles/Neutral/Agitater.cs @@ -181,7 +181,7 @@ public class Agitater : RoleBase ResetBomb(); else { - Vector2 agitaterPos = player.transform.position; + Vector2 agitaterPos = player.Pos(); Dictionary targetDistance = []; foreach (PlayerControl target in PlayerControl.AllPlayerControls) @@ -190,7 +190,7 @@ public class Agitater : RoleBase if (target.PlayerId != playerId && target.PlayerId != LastBombedPlayer && target.IsAlive()) { - float dis = Vector2.Distance(agitaterPos, target.transform.position); + float dis = Vector2.Distance(agitaterPos, player.Pos()); targetDistance[target.PlayerId] = dis; } } diff --git a/Roles/Neutral/Arsonist.cs b/Roles/Neutral/Arsonist.cs index 54c0b072a..6e3bf7b8b 100644 --- a/Roles/Neutral/Arsonist.cs +++ b/Roles/Neutral/Arsonist.cs @@ -186,27 +186,26 @@ internal class Arsonist : RoleBase } else { - PlayerControl ar_target = ArsonistTimer[playerId].Player; - float ar_time = ArsonistTimer[playerId].Timer; + float arTime = ArsonistTimer[playerId].Timer; - if (!ar_target.IsAlive()) + if (!arTarget.IsAlive()) ArsonistTimer.Remove(playerId); - else if (ar_time >= ArsonistDouseTime.GetFloat()) + else if (arTime >= ArsonistDouseTime.GetFloat()) { player.SetKillCooldown(); ArsonistTimer.Remove(playerId); - IsDoused[(playerId, ar_target.PlayerId)] = true; - player.RpcSetDousedPlayer(ar_target, true); + IsDoused[(playerId, arTarget.PlayerId)] = true; + player.RpcSetDousedPlayer(arTarget, true); Utils.NotifyRoles(SpecifySeer: player, SpecifyTarget: arTarget, ForceLoop: true); RPC.ResetCurrentDousingTarget(playerId); } else { float range = NormalGameOptionsV09.KillDistances[Mathf.Clamp(player.Is(CustomRoles.Reach) ? 2 : Main.NormalOptions.KillDistance, 0, 2)] + 0.5f; - float dis = Vector2.Distance(player.transform.position, ar_target.transform.position); + float dis = Vector2.Distance(player.Pos(), arTarget.Pos()); if (dis <= range) - ArsonistTimer[playerId] = (ar_target, ar_time + Time.fixedDeltaTime); + ArsonistTimer[playerId] = (arTarget, arTime + Time.fixedDeltaTime); else { player.SetKillCooldown(0.01f); diff --git a/Roles/Neutral/Magician.cs b/Roles/Neutral/Magician.cs index 72576c9fc..aadbba15f 100644 --- a/Roles/Neutral/Magician.cs +++ b/Roles/Neutral/Magician.cs @@ -442,15 +442,15 @@ public class Magician : RoleBase { if (target.PlayerId == sniper.PlayerId) continue; - Vector3 target_pos = target.transform.position - snipePos; - if (target_pos.magnitude < 1) continue; + Vector3 targetPos = target.transform.position - snipePos; + if (targetPos.magnitude < 1) continue; - Vector3 target_dir = target_pos.normalized; - float target_dot = Vector3.Dot(dir, target_dir); + Vector3 targetDir = targetPos.normalized; + float targetDot = Vector3.Dot(dir, targetDir); - if (target_dot < 0.995) continue; + if (targetDot < 0.995) continue; - float err = target_pos.magnitude; + float err = targetPos.magnitude; targets[target] = err; } diff --git a/Roles/Neutral/PlagueDoctor.cs b/Roles/Neutral/PlagueDoctor.cs index 8d209ffd1..393c394bc 100644 --- a/Roles/Neutral/PlagueDoctor.cs +++ b/Roles/Neutral/PlagueDoctor.cs @@ -216,7 +216,7 @@ public class PlagueDoctor : RoleBase if (oldRate >= 100) continue; // Exclude players outside the range - float distance = Vector3.Distance(player.transform.position, target.transform.position); + float distance = Vector2.Distance(player.Pos(), target.Pos()); if (distance > InfectDistance) continue; float newRate = oldRate + (Time.fixedDeltaTime / InfectTime * 100); diff --git a/Roles/Neutral/QuizMaster.cs b/Roles/Neutral/QuizMaster.cs index 1244ee336..917515f1e 100644 --- a/Roles/Neutral/QuizMaster.cs +++ b/Roles/Neutral/QuizMaster.cs @@ -99,11 +99,11 @@ internal class QuizMaster : RoleBase }, 10f, log: false); CustomQuestions = []; - EnableCustomQuestions = EnableCustomQuestionsOpt.GetBool() && File.Exists("./EHR_DATA/QuizMasterQuestions.txt"); + EnableCustomQuestions = EnableCustomQuestionsOpt.GetBool() && File.Exists($"{Main.DataPath}/EHR_DATA/QuizMasterQuestions.txt"); if (EnableCustomQuestions) { - string[] lines = File.ReadAllLines("./EHR_DATA/QuizMasterQuestions.txt"); + string[] lines = File.ReadAllLines($"{Main.DataPath}/EHR_DATA/QuizMasterQuestions.txt"); IEnumerable questions = lines.Where(x => !string.IsNullOrWhiteSpace(x)).Select(x => { diff --git a/Roles/Neutral/Revolutionist.cs b/Roles/Neutral/Revolutionist.cs index 1f3003973..89af8fde8 100644 --- a/Roles/Neutral/Revolutionist.cs +++ b/Roles/Neutral/Revolutionist.cs @@ -177,7 +177,7 @@ internal class Revolutionist : RoleBase else { float range = NormalGameOptionsV09.KillDistances[Mathf.Clamp(player.Is(CustomRoles.Reach) ? 2 : Main.NormalOptions.KillDistance, 0, 2)] + 0.5f; - float dis = Vector2.Distance(player.transform.position, rvTarget.transform.position); + float dis = Vector2.Distance(player.Pos(), rvTarget.Pos()); if (dis <= range) RevolutionistTimer[playerId] = (rvTarget, rvTime + Time.fixedDeltaTime); diff --git a/Roles/Neutral/WeaponMaster.cs b/Roles/Neutral/WeaponMaster.cs index 1431f325f..5b4a99e2b 100644 --- a/Roles/Neutral/WeaponMaster.cs +++ b/Roles/Neutral/WeaponMaster.cs @@ -195,7 +195,7 @@ public class WeaponMaster : RoleBase { if (Pelican.IsEaten(player.PlayerId) || player == killer || player.Is(CustomRoles.Pestilence) || Veteran.VeteranInProtect.ContainsKey(target.PlayerId)) continue; - if (Vector2.Distance(killer.transform.position, player.transform.position) <= Radius.GetFloat()) + if (Vector2.Distance(killer.Pos(), player.Pos()) <= Radius.GetFloat()) player.Suicide(PlayerState.DeathReason.Kill, killer); }