mirror of
https://github.com/Gurge44/EndlessHostRoles.git
synced 2026-10-20 01:46:25 +00:00
Merge remote-tracking branch 'origin/main'
# Conflicts: # Modules/Utils.cs
This commit is contained in:
commit
3a787d18c5
36 files changed
+481
-273
No files matched your search
+1
-1
@@ -7,7 +7,7 @@
|
||||
<Description>EHR</Description>
|
||||
<Authors>Gurge44</Authors>
|
||||
<langVersion>preview</langVersion>
|
||||
<AmongUs>C:\Program Files\Epic Games\AmongUs</AmongUs>
|
||||
<AmongUs>E:\Program Files\AmongUs</AmongUs>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Optimize>True</Optimize>
|
||||
<AssemblyName>$(MSBuildProjectName)</AssemblyName>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CD/@EntryIndexedValue">CD</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CK/@EntryIndexedValue">CK</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CNO/@EntryIndexedValue">CNO</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CRLF/@EntryIndexedValue">CRLF</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CTF/@EntryIndexedValue">CTF</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DLL/@EntryIndexedValue">DLL</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DY/@EntryIndexedValue">DY</s:String>
|
||||
|
||||
+13
-7
@@ -113,7 +113,7 @@ namespace EHR
|
||||
public static void AssignRoles()
|
||||
{
|
||||
Dictionary<PlayerControl, CustomRoles> result = [];
|
||||
List<PlayerControl> allPlayers = [.. Main.AllAlivePlayerControls];
|
||||
List<PlayerControl> allPlayers = [.. Main.AllPlayerControls];
|
||||
|
||||
if (Main.GM.Value)
|
||||
{
|
||||
@@ -270,7 +270,7 @@ namespace EHR
|
||||
|
||||
public static bool HasTasks(NetworkedPlayerInfo playerInfo)
|
||||
{
|
||||
var role = PlayerRoles[playerInfo.PlayerId];
|
||||
if (!PlayerRoles.TryGetValue(playerInfo.PlayerId, out var role)) return false;
|
||||
return role.Interface.Team == Team.Crewmate || role.Role == CustomRoles.Taskinator;
|
||||
}
|
||||
|
||||
@@ -448,11 +448,17 @@ namespace EHR
|
||||
|
||||
PlayerRoles = PlayerRoles.IntersectBy(Main.AllPlayerControls.Select(x => x.PlayerId), x => x.Key).ToDictionary(x => x.Key, x => x.Value);
|
||||
|
||||
var idPosPairs = PlayerRoles.Join(Main.AllPlayerControls, x => x.Key, x => x.PlayerId, (role, pc) => (role.Key, pc)).ToDictionary(x => x.Key, x => x.pc.Pos());
|
||||
var imps = PlayerRoles.Where(x => x.Value.Interface.Team == Team.Impostor).ToDictionary(x => x.Key, x => idPosPairs[x.Key]);
|
||||
var nonImps = PlayerRoles.Where(x => x.Value.Interface.Team is Team.Crewmate or Team.Neutral).ToArray();
|
||||
ClosestImpostor = nonImps.ToDictionary(x => x.Key, x => imps.MinBy(y => Vector2.Distance(y.Value, idPosPairs[x.Key])).Key);
|
||||
Danger = nonImps.ToDictionary(x => x.Key, x => Math.Clamp(((1 + (int)Math.Ceiling(Vector2.Distance(idPosPairs[x.Key], idPosPairs[ClosestImpostor[x.Key]]))) / 3) - 1, 0, 5));
|
||||
try
|
||||
{
|
||||
var idPosPairs = PlayerRoles.Join(Main.AllPlayerControls, x => x.Key, x => x.PlayerId, (role, pc) => (role.Key, pc)).ToDictionary(x => x.Key, x => x.pc.Pos());
|
||||
var imps = PlayerRoles.Where(x => x.Value.Interface.Team == Team.Impostor).ToDictionary(x => x.Key, x => idPosPairs[x.Key]);
|
||||
var nonImps = PlayerRoles.Where(x => x.Value.Interface.Team is Team.Crewmate or Team.Neutral).ToArray();
|
||||
ClosestImpostor = nonImps.ToDictionary(x => x.Key, x => imps.MinBy(y => Vector2.Distance(y.Value, idPosPairs[x.Key])).Key);
|
||||
Danger = nonImps.ToDictionary(x => x.Key, x => Math.Clamp(((1 + (int)Math.Ceiling(Vector2.Distance(idPosPairs[x.Key], idPosPairs[ClosestImpostor[x.Key]]))) / 3) - 1, 0, 5));
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
if (DangerMeter.GetBool() || (TimeLeft + 1) % 60 == 0 || TimeLeft <= 60) Utils.NotifyRoles();
|
||||
}
|
||||
|
||||
@@ -173,8 +173,6 @@ public static class AntiBlackout
|
||||
|
||||
target.RpcSetRoleDesync(changedRoleType, seer.GetClientId());
|
||||
}
|
||||
|
||||
ResetAllCooldowns();
|
||||
}
|
||||
|
||||
private static void ResetAllCooldowns()
|
||||
@@ -197,6 +195,7 @@ public static class AntiBlackout
|
||||
{
|
||||
SkipTasks = false;
|
||||
ExilePlayerId = -1;
|
||||
ResetAllCooldowns();
|
||||
}
|
||||
|
||||
public static void Reset()
|
||||
|
||||
+12
-8
@@ -56,10 +56,6 @@ public static class Camouflage
|
||||
0 => new NetworkedPlayerInfo.PlayerOutfit().Set("", 15, "", "", "", "", ""), // Default
|
||||
1 => new NetworkedPlayerInfo.PlayerOutfit().Set("", DataManager.Player.Customization.Color, DataManager.Player.Customization.Hat, DataManager.Player.Customization.Skin, DataManager.Player.Customization.Visor, DataManager.Player.Customization.Pet, ""), // Host
|
||||
2 => new NetworkedPlayerInfo.PlayerOutfit().Set("", 13, "hat_pk05_Plant", "", "visor_BubbleBumVisor", "", ""), // Karpe
|
||||
3 => new NetworkedPlayerInfo.PlayerOutfit().Set("", 13, "hat_rabbitEars", "skin_Bananaskin", "visor_BubbleBumVisor", "pet_Pusheen", ""), // Lauryn
|
||||
4 => new NetworkedPlayerInfo.PlayerOutfit().Set("", 0, "hat_mira_headset_yellow", "skin_SuitB", "visor_lollipopCrew", "pet_EmptyPet", ""), // Moe
|
||||
5 => new NetworkedPlayerInfo.PlayerOutfit().Set("", 17, "hat_pkHW01_Witch", "skin_greedygrampaskin", "visor_Plsno", "pet_Pusheen", ""), // Pyro
|
||||
6 => new NetworkedPlayerInfo.PlayerOutfit().Set("", 7, "hat_crownDouble", "skin_D2Saint14", "visor_anime", "pet_Bush", ""), // ryuk
|
||||
7 => new NetworkedPlayerInfo.PlayerOutfit().Set("", 7, "hat_pk04_Snowman", "", "", "", ""), // Gurge44
|
||||
8 => new NetworkedPlayerInfo.PlayerOutfit().Set("", 17, "hat_baseball_Black", "skin_Scientist-Darkskin", "visor_pusheenSmileVisor", "pet_Pip", ""), // TommyXL
|
||||
_ => CamouflageOutfit
|
||||
@@ -89,6 +85,8 @@ public static class Camouflage
|
||||
|
||||
if (oldIsCamouflage != IsCamouflage)
|
||||
{
|
||||
Logger.Info($"IsCamouflage: {IsCamouflage}", "CheckCamouflage");
|
||||
|
||||
WaitingForSkinChange = [];
|
||||
|
||||
foreach (var pc in Main.AllPlayerControls)
|
||||
@@ -115,6 +113,8 @@ public static class Camouflage
|
||||
{
|
||||
if (!AmongUsClient.Instance.AmHost || (!Options.CommsCamouflage.GetBool() && !Camouflager.On) || target == null || (BlockCamouflage && !ForceRevert && !RevertToDefault && !GameEnd)) return;
|
||||
|
||||
Logger.Info($"New outfit for {target.GetNameWithRole()}", "Camouflage.RpcSetSkin");
|
||||
|
||||
var id = target.PlayerId;
|
||||
|
||||
if (IsCamouflage && Main.PlayerStates[id].IsDead) return;
|
||||
@@ -140,13 +140,17 @@ public static class Camouflage
|
||||
newOutfit = PlayerSkins[id];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SetPetForOutfitIfNecessary(newOutfit);
|
||||
|
||||
// if the current Outfit is the same, return it
|
||||
if (newOutfit.Compare(target.Data.DefaultOutfit)) return;
|
||||
// if the current Outfit is the same, return
|
||||
if (newOutfit.Compare(target.Data.DefaultOutfit))
|
||||
{
|
||||
Logger.Info("Outfit is the same, returning", "Camouflage.RpcSetSkin");
|
||||
return;
|
||||
}
|
||||
|
||||
Logger.Info($"newOutfit={newOutfit.GetString()}", "RpcSetSkin");
|
||||
Logger.Info($"Setting new outfit: {newOutfit.GetString()}", "Camouflage.RpcSetSkin");
|
||||
|
||||
var sender = CustomRpcSender.Create(name: $"Camouflage.RpcSetSkin({target.Data.PlayerName})");
|
||||
|
||||
|
||||
@@ -167,7 +167,7 @@ internal static class CustomRolesHelper
|
||||
CustomRoles.SuperStar => CustomRoles.Crewmate,
|
||||
CustomRoles.Hacker => CustomRoles.Shapeshifter,
|
||||
CustomRoles.Visionary => CustomRoles.Shapeshifter,
|
||||
CustomRoles.Assassin => UsePets ? CustomRoles.Impostor : CustomRoles.Shapeshifter,
|
||||
CustomRoles.Assassin => CustomRoles.Phantom,
|
||||
CustomRoles.Undertaker => UsePets ? CustomRoles.Impostor : CustomRoles.Shapeshifter,
|
||||
CustomRoles.Luckey => CustomRoles.Crewmate,
|
||||
CustomRoles.CyberStar => CustomRoles.Crewmate,
|
||||
@@ -198,7 +198,7 @@ internal static class CustomRolesHelper
|
||||
CustomRoles.GuessManagerRole => CustomRoles.Crewmate,
|
||||
CustomRoles.Bane => CustomRoles.Crewmate,
|
||||
CustomRoles.Transmitter => CustomRoles.Crewmate,
|
||||
CustomRoles.Altruist => CustomRoles.Engineer,
|
||||
CustomRoles.Altruist => UsePets ? CustomRoles.Crewmate : CustomRoles.Engineer,
|
||||
CustomRoles.Negotiator => CustomRoles.Crewmate,
|
||||
CustomRoles.Grappler => CustomRoles.Crewmate,
|
||||
CustomRoles.Journalist => CustomRoles.Crewmate,
|
||||
@@ -824,7 +824,7 @@ internal static class CustomRolesHelper
|
||||
{
|
||||
CustomRoles.Circumvent when pc.GetCustomRole() is CustomRoles.Swooper or CustomRoles.RiftMaker => false,
|
||||
CustomRoles.Oblivious when pc.Is(CustomRoles.Altruist) => false,
|
||||
CustomRoles.AntiTP when pc.Is(CustomRoles.Transmitter) => false,
|
||||
CustomRoles.AntiTP when pc.GetCustomRole() is CustomRoles.Transmitter or CustomRoles.Miner or CustomRoles.Escapee or CustomRoles.Tunneler => false,
|
||||
CustomRoles.Swift when pc.Is(CustomRoles.Stealth) => false,
|
||||
CustomRoles.Disco when pc.GetCustomRole() is CustomRoles.Chameleon or CustomRoles.Swooper or CustomRoles.Wraith or CustomRoles.Alchemist => false,
|
||||
CustomRoles.Egoist when pc.Is(CustomRoles.Gangster) => false,
|
||||
|
||||
+1
-1
@@ -62,7 +62,7 @@ static class Logger
|
||||
|
||||
private static void SendToFile(string text, LogLevel level = LogLevel.Info, string tag = "", bool escapeCRLF = true, int lineNumber = 0, string fileName = "", bool multiLine = false)
|
||||
{
|
||||
if (!IsEnable || DisableList.Contains(tag)) return;
|
||||
if (!IsEnable || DisableList.Contains(tag) || (level == LogLevel.Debug && !DebugModeManager.AmDebugger)) return;
|
||||
var logger = Main.Logger;
|
||||
|
||||
if (SendToGameList.Contains(tag) || IsAlsoInGame)
|
||||
|
||||
+46
-1
@@ -1,8 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AmongUs.GameOptions;
|
||||
using HarmonyLib;
|
||||
using Hazel;
|
||||
using InnerNet;
|
||||
using UnityEngine;
|
||||
using static EHR.Translator;
|
||||
|
||||
namespace EHR;
|
||||
@@ -392,7 +395,7 @@ internal static class EAC
|
||||
bool HasVent(int ventId) => ShipStatus.Instance.AllVents.Any(v => v.Id == ventId);
|
||||
}
|
||||
|
||||
private static void Report(PlayerControl pc, string reason)
|
||||
internal static void Report(PlayerControl pc, string reason)
|
||||
{
|
||||
string msg = $"{pc.GetClientId()}|{pc.FriendCode}|{pc.Data.PlayerName}|{pc.GetClient().GetHashedPuid()}|{reason}";
|
||||
//Cloud.SendData(msg);
|
||||
@@ -692,4 +695,46 @@ internal static class StartGameHostPatchEAC
|
||||
if (ShipStatus.Instance != null)
|
||||
IsStartingAsHost = false;
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.FixedUpdate))]
|
||||
static class CheckInvalidMovementPatch
|
||||
{
|
||||
private static readonly Dictionary<byte, long> LastCheck = [];
|
||||
public static readonly Dictionary<byte, Vector2> LastPosition = [];
|
||||
public static readonly HashSet<byte> ExemptedPlayers = [];
|
||||
|
||||
public static void Postfix(PlayerControl __instance)
|
||||
{
|
||||
if (!GameStates.IsInTask || !Options.EnableMovementChecking.GetBool() || Main.RealOptionsData.GetFloat(FloatOptionNames.PlayerSpeedMod) >= 1.9f || AmongUsClient.Instance.Ping >= 300 || Utils.GetRegionName() is not ("EU" or "NA" or "AS") || __instance == null || __instance.PlayerId == 255) return;
|
||||
|
||||
var pos = __instance.Pos();
|
||||
var now = Utils.TimeStamp;
|
||||
|
||||
if (!LastPosition.TryGetValue(__instance.PlayerId, out var lastPosition))
|
||||
{
|
||||
SetCurrentData();
|
||||
return;
|
||||
}
|
||||
|
||||
if (LastCheck[__instance.PlayerId] == now) return;
|
||||
|
||||
SetCurrentData();
|
||||
|
||||
if (ExemptedPlayers.Remove(__instance.PlayerId)) return;
|
||||
|
||||
if (Vector2.Distance(lastPosition, pos) > 10f && PhysicsHelpers.AnythingBetween(__instance.Collider, lastPosition, pos, Constants.ShipOnlyMask, false))
|
||||
{
|
||||
EAC.WarnHost();
|
||||
EAC.Report(__instance, "This player is moving too fast, possibly using a speed hack.");
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
void SetCurrentData()
|
||||
{
|
||||
LastPosition[__instance.PlayerId] = pos;
|
||||
LastCheck[__instance.PlayerId] = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,11 +65,9 @@ static class ExtendedPlayerControl
|
||||
return CanUseVent(player, GetClosestVent(player)?.Id ?? int.MaxValue);
|
||||
}
|
||||
|
||||
// VentId is unused for now, but it can be used to block specific vents
|
||||
// ReSharper disable once UnusedParameter.Global
|
||||
public static bool CanUseVent(this PlayerControl player, int ventId)
|
||||
{
|
||||
return GameStates.IsInTask && (player.CanUseImpostorVentButton() || player.GetRoleTypes() == RoleTypes.Engineer || player.inVent);
|
||||
return GameStates.IsInTask && (player.CanUseImpostorVentButton() || player.GetRoleTypes() == RoleTypes.Engineer || player.inVent) && Main.PlayerStates.Values.All(x => x.Role.CanUseVent(player, ventId));
|
||||
}
|
||||
|
||||
// Next 3: https://github.com/Rabek009/MoreGamemodes/blob/master/Modules/ExtendedPlayerControl.cs
|
||||
@@ -84,6 +82,15 @@ static class ExtendedPlayerControl
|
||||
Vector2 playerpos = player.transform.position;
|
||||
List<Vent> vents = ShipStatus.Instance.AllVents.ToList();
|
||||
vents.Sort((v1, v2) => Vector2.Distance(playerpos, v1.transform.position).CompareTo(Vector2.Distance(playerpos, v2.transform.position)));
|
||||
|
||||
if ((player.walkingToVent || player.inVent) && vents[0] != null)
|
||||
{
|
||||
var nextvents = vents[0].NearbyVents.ToList();
|
||||
nextvents.RemoveAll(v => v == null);
|
||||
nextvents.ForEach(v => vents.Remove(v));
|
||||
vents.InsertRange(0, nextvents);
|
||||
}
|
||||
|
||||
return vents;
|
||||
}
|
||||
|
||||
@@ -300,17 +307,18 @@ static class ExtendedPlayerControl
|
||||
// https://github.com/Ultradragon005/TownofHost-Enhanced/blob/ea5f1e8ea87e6c19466231c305d6d36d511d5b2d/Modules/ExtendedPlayerControl.cs
|
||||
public static void RpcChangeRoleBasis(this PlayerControl player, CustomRoles newCustomRole, bool loggerRoleMap = false)
|
||||
{
|
||||
if (!GameStates.IsInGame || !AmongUsClient.Instance.AmHost) return;
|
||||
if (!AmongUsClient.Instance.AmHost || !GameStates.IsInGame || player == null) return;
|
||||
|
||||
var playerId = player.PlayerId;
|
||||
var playerClientId = player.GetClientId();
|
||||
var playerRole = Utils.GetRoleMap(playerId).CustomRole;
|
||||
var newRoleType = newCustomRole.GetRoleTypes();
|
||||
RoleTypes remeberRoleType;
|
||||
|
||||
newRoleType = Options.CurrentGameMode switch
|
||||
{
|
||||
CustomGameMode.Speedrun when newCustomRole == CustomRoles.Runner => SpeedrunManager.CanKill.Contains(player.PlayerId) ? RoleTypes.Impostor : RoleTypes.Crewmate,
|
||||
CustomGameMode.Standard when StartGameHostPatch.BasisChangingAddons.FindFirst(x => x.Value.Contains(player.PlayerId), out var kvp) => kvp.Key switch
|
||||
CustomGameMode.Speedrun when newCustomRole == CustomRoles.Runner => SpeedrunManager.CanKill.Contains(playerId) ? RoleTypes.Impostor : RoleTypes.Crewmate,
|
||||
CustomGameMode.Standard when StartGameHostPatch.BasisChangingAddons.FindFirst(x => x.Value.Contains(playerId), out var kvp) => kvp.Key switch
|
||||
{
|
||||
CustomRoles.Bloodlust when newRoleType is RoleTypes.Crewmate or RoleTypes.Engineer or RoleTypes.Scientist => RoleTypes.Impostor,
|
||||
CustomRoles.Nimble when newRoleType is RoleTypes.Crewmate or RoleTypes.Scientist => RoleTypes.Engineer,
|
||||
@@ -325,6 +333,9 @@ static class ExtendedPlayerControl
|
||||
var oldRoleIsDesync = playerRole.IsDesyncRole();
|
||||
var newRoleIsDesync = newCustomRole.IsDesyncRole();
|
||||
|
||||
var newRoleVN = newCustomRole.GetVNRole();
|
||||
var newRoleDY = newCustomRole.GetDYRole();
|
||||
|
||||
switch (oldRoleIsDesync, newRoleIsDesync)
|
||||
{
|
||||
// Desync role to normal role
|
||||
@@ -334,13 +345,42 @@ static class ExtendedPlayerControl
|
||||
{
|
||||
var seerClientId = seer.GetClientId();
|
||||
if (seerClientId == -1) continue;
|
||||
var seerIsHost = seer.IsHost();
|
||||
var self = player.PlayerId == seer.PlayerId;
|
||||
|
||||
if (player.PlayerId != seer.PlayerId && seer.HasDesyncRole() && !seer.IsHost())
|
||||
remeberRoleType = newCustomRole.GetVNRole() is CustomRoles.Noisemaker ? RoleTypes.Noisemaker : RoleTypes.Scientist;
|
||||
if (!self && seer.HasDesyncRole() && !seerIsHost)
|
||||
remeberRoleType = newRoleVN is CustomRoles.Noisemaker ? RoleTypes.Noisemaker : RoleTypes.Scientist;
|
||||
else remeberRoleType = newRoleType;
|
||||
|
||||
// Set role type for seer
|
||||
StartGameHostPatch.RpcSetRoleReplacer.RoleMap[(seer.PlayerId, playerId)] = (remeberRoleType, newCustomRole);
|
||||
player.RpcSetRoleDesync(remeberRoleType, seerClientId);
|
||||
|
||||
if (self) continue;
|
||||
|
||||
(RoleTypes seerRoleType, CustomRoles seerCustomRole) = seer.GetRoleMap();
|
||||
if (seer.IsAlive())
|
||||
{
|
||||
if (seerCustomRole.IsDesyncRole())
|
||||
remeberRoleType = seerIsHost ? RoleTypes.Crewmate : RoleTypes.Scientist;
|
||||
else
|
||||
remeberRoleType = seerRoleType;
|
||||
}
|
||||
else
|
||||
{
|
||||
var playerIsKiller = playerRole.IsImpostor();
|
||||
|
||||
remeberRoleType = RoleTypes.CrewmateGhost;
|
||||
if (!playerIsKiller && seer.Is(Team.Impostor)) remeberRoleType = RoleTypes.ImpostorGhost;
|
||||
|
||||
StartGameHostPatch.RpcSetRoleReplacer.RoleMap[(playerId, seer.PlayerId)] = (seerCustomRole.IsDesyncRole() ? seerIsHost ? RoleTypes.Crewmate : RoleTypes.Scientist : seerRoleType, seerCustomRole);
|
||||
seer.RpcSetRoleDesync(remeberRoleType, playerClientId);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set role type for player
|
||||
StartGameHostPatch.RpcSetRoleReplacer.RoleMap[(playerId, seer.PlayerId)] = (remeberRoleType, seerCustomRole);
|
||||
seer.RpcSetRoleDesync(remeberRoleType, playerClientId);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -352,23 +392,43 @@ static class ExtendedPlayerControl
|
||||
{
|
||||
var seerClientId = seer.GetClientId();
|
||||
if (seerClientId == -1) continue;
|
||||
var self = player.PlayerId == seer.PlayerId;
|
||||
|
||||
if (player.PlayerId == seer.PlayerId)
|
||||
if (self)
|
||||
{
|
||||
remeberRoleType = player.IsHost() ? RoleTypes.Crewmate : RoleTypes.Impostor;
|
||||
|
||||
// For Desync Shapeshifter
|
||||
if (newCustomRole.GetDYRole() is RoleTypes.Shapeshifter)
|
||||
if (newRoleDY is RoleTypes.Shapeshifter)
|
||||
remeberRoleType = RoleTypes.Shapeshifter;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!player.IsHost() && seer.HasDesyncRole()) remeberRoleType = newCustomRole.GetVNRole() is CustomRoles.Noisemaker ? RoleTypes.Noisemaker : RoleTypes.Scientist;
|
||||
else remeberRoleType = newRoleType;
|
||||
remeberRoleType = newRoleVN is CustomRoles.Noisemaker ? RoleTypes.Noisemaker : RoleTypes.Scientist;
|
||||
}
|
||||
|
||||
StartGameHostPatch.RpcSetRoleReplacer.RoleMap[(seer.PlayerId, playerId)] = (remeberRoleType, newCustomRole);
|
||||
player.RpcSetRoleDesync(remeberRoleType, seerClientId);
|
||||
|
||||
if (self) continue;
|
||||
|
||||
var seerCustomRole = seer.GetRoleMap().CustomRole;
|
||||
if (seer.IsAlive())
|
||||
{
|
||||
remeberRoleType = newRoleVN is CustomRoles.Noisemaker ? RoleTypes.Noisemaker : RoleTypes.Scientist;
|
||||
}
|
||||
else
|
||||
{
|
||||
remeberRoleType = RoleTypes.CrewmateGhost;
|
||||
|
||||
StartGameHostPatch.RpcSetRoleReplacer.RoleMap[(playerId, seer.PlayerId)] = (seerCustomRole.GetVNRole() is CustomRoles.Noisemaker ? RoleTypes.Noisemaker : RoleTypes.Scientist, seerCustomRole);
|
||||
seer.RpcSetRoleDesync(remeberRoleType, playerClientId);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set role type for player
|
||||
StartGameHostPatch.RpcSetRoleReplacer.RoleMap[(playerId, seer.PlayerId)] = (remeberRoleType, seerCustomRole);
|
||||
seer.RpcSetRoleDesync(remeberRoleType, playerClientId);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -399,17 +459,19 @@ static class ExtendedPlayerControl
|
||||
{
|
||||
foreach (var seer in Main.AllPlayerControls)
|
||||
{
|
||||
var seerData = seer.Data;
|
||||
foreach (var target in Main.AllPlayerControls)
|
||||
{
|
||||
if (StartGameHostPatch.RpcSetRoleReplacer.RoleMap.TryGetValue((seer.PlayerId, target.PlayerId), out var map))
|
||||
Logger.Info($"seer {seer.Data?.PlayerName}-{seer.PlayerId}, target {target.Data?.PlayerName}-{target.PlayerId} => {map.RoleType}, {map.CustomRole}", "Role Map");
|
||||
var targetData = target.Data;
|
||||
(RoleTypes roleType, CustomRoles customRole) = seer.GetRoleMap(targetData.PlayerId);
|
||||
Logger.Info($"seer {seerData?.PlayerName}-{seerData?.PlayerId}, target {targetData.PlayerName}-{targetData.PlayerId} => {roleType}, {customRole}", "Role Map");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Main.ChangedRole = true;
|
||||
|
||||
Logger.Info($"{player.GetNameWithRole()}'s role basis was changed to {newRoleType} ({newCustomRole}) (from role: {playerRole}) - oldRoleIsDesync: {oldRoleIsDesync}, newRoleIsDesync: {newRoleIsDesync}", "RpcChangeRoleBasis");
|
||||
|
||||
Main.ChangedRole = true;
|
||||
}
|
||||
|
||||
// https://github.com/Ultradragon005/TownofHost-Enhanced/blob/ea5f1e8ea87e6c19466231c305d6d36d511d5b2d/Modules/Utils.cs
|
||||
@@ -1275,6 +1337,8 @@ static class ExtendedPlayerControl
|
||||
if (target.Is(CustomRoles.Jackal))
|
||||
Jackal.Instances.Do(x => x.PromoteSidekick());
|
||||
|
||||
Main.DiedThisRound.Add(target.PlayerId);
|
||||
|
||||
switch (killer.PlayerId == target.PlayerId)
|
||||
{
|
||||
case true when killer.shapeshifting:
|
||||
|
||||
@@ -126,10 +126,6 @@ public static class Options
|
||||
"CamouflageMode.Default",
|
||||
"CamouflageMode.Host",
|
||||
"CamouflageMode.Karpe",
|
||||
"CamouflageMode.Lauryn",
|
||||
"CamouflageMode.Moe",
|
||||
"CamouflageMode.Pyro",
|
||||
"CamouflageMode.ryuk",
|
||||
"CamouflageMode.Gurge44",
|
||||
"CamouflageMode.TommyXL"
|
||||
];
|
||||
@@ -199,6 +195,7 @@ public static class Options
|
||||
public static OptionItem ShowNKRemainOnEject;
|
||||
public static OptionItem ShowTeamNextToRoleNameOnEject;
|
||||
public static OptionItem CheatResponses;
|
||||
public static OptionItem EnableMovementChecking;
|
||||
public static OptionItem LowLoadMode;
|
||||
public static OptionItem DeepLowLoad;
|
||||
public static OptionItem DisableVoteBan;
|
||||
@@ -1219,6 +1216,9 @@ public static class Options
|
||||
CheatResponses = new StringOptionItem(19319, "CheatResponses", CheatResponsesName, 2, TabGroup.SystemSettings)
|
||||
.SetHeader(true);
|
||||
|
||||
EnableMovementChecking = new BooleanOptionItem(19329, "EnableMovementChecking", true, TabGroup.SystemSettings)
|
||||
.SetHeader(true);
|
||||
|
||||
|
||||
DisableVoteBan = new BooleanOptionItem(19320, "DisableVoteBan", true, TabGroup.SystemSettings, true);
|
||||
|
||||
@@ -1362,11 +1362,9 @@ public static class Options
|
||||
|
||||
// Random Spawn
|
||||
RandomSpawn = new BooleanOptionItem(22000, "RandomSpawn", false, TabGroup.GameSettings)
|
||||
.SetGameMode(CustomGameMode.Standard)
|
||||
.SetColor(new Color32(19, 188, 233, byte.MaxValue));
|
||||
AirshipAdditionalSpawn = new BooleanOptionItem(22010, "AirshipAdditionalSpawn", false, TabGroup.GameSettings)
|
||||
.SetParent(RandomSpawn)
|
||||
.SetGameMode(CustomGameMode.Standard);
|
||||
.SetParent(RandomSpawn);
|
||||
|
||||
// Airship Variable Electrical
|
||||
AirshipVariableElectrical = new BooleanOptionItem(22100, "AirshipVariableElectrical", false, TabGroup.GameSettings)
|
||||
|
||||
@@ -1390,7 +1390,6 @@ internal static class PlayerPhysicsRPCHandlerPatch
|
||||
return false;
|
||||
}
|
||||
|
||||
Logger.Info($"{player.PlayerId}({(host ? "Host" : player.Data.PlayerName)}):{callId}({RPC.GetRpcName(callId)})", "PlayerPhysics_ReceiveRPC");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
+66
-20
@@ -97,6 +97,25 @@ public static class Utils
|
||||
}
|
||||
}
|
||||
|
||||
public static void CheckAndSetVentInteractions()
|
||||
{
|
||||
bool shouldPerformVentInteractions = false;
|
||||
|
||||
foreach (var pc in Main.AllPlayerControls)
|
||||
{
|
||||
if (VentilationSystemDeterioratePatch.BlockVentInteraction(pc))
|
||||
{
|
||||
VentilationSystemDeterioratePatch.LastClosestVent[pc.PlayerId] = pc.GetVentsFromClosest()[0].Id;
|
||||
shouldPerformVentInteractions = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldPerformVentInteractions)
|
||||
{
|
||||
SetAllVentInteractions();
|
||||
}
|
||||
}
|
||||
|
||||
public static void TPAll(Vector2 location, bool log = true)
|
||||
{
|
||||
foreach (PlayerControl pc in Main.AllAlivePlayerControls)
|
||||
@@ -124,6 +143,10 @@ public static class Utils
|
||||
AmongUsClient.Instance.FinishRpcImmediately(messageWriter);
|
||||
|
||||
if (log) Logger.Info($"{pc.GetNameWithRole().RemoveHtmlTags()} => {location}", "TP");
|
||||
|
||||
CheckInvalidMovementPatch.LastPosition[pc.PlayerId] = location;
|
||||
CheckInvalidMovementPatch.ExemptedPlayers.Add(pc.PlayerId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -434,6 +457,8 @@ public static class Utils
|
||||
|
||||
var self = seerId == targetId || Main.PlayerStates[seerId].IsDead;
|
||||
|
||||
if (!self && Main.DiedThisRound.Contains(seerId)) return (string.Empty, Color.white);
|
||||
|
||||
bool isHnsAgentOverride = Options.CurrentGameMode == CustomGameMode.HideAndSeek && targetMainRole == CustomRoles.Agent && HnSManager.PlayerRoles[seerId].Interface.Team != Team.Impostor;
|
||||
bool loversShowDifferentRole = false;
|
||||
if (!GameStates.IsEnded && targetMainRole == CustomRoles.LovingImpostor && !self && seerMainRole != CustomRoles.LovingCrewmate && !seerSubRoles.Contains(CustomRoles.Lovers))
|
||||
@@ -496,7 +521,6 @@ public static class Utils
|
||||
RoleText = GetRoleString("Contagious-") + RoleText;
|
||||
}
|
||||
|
||||
// Bloodlust
|
||||
if (targetSubRoles.Contains(CustomRoles.Bloodlust) && (self || pure || seeTargetBetrayalAddons))
|
||||
{
|
||||
RoleColor = GetRoleColor(CustomRoles.Bloodlust);
|
||||
@@ -618,7 +642,7 @@ public static class Utils
|
||||
StackFrame firstFrame = stFrames.FirstOrDefault();
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.Append($" {ex.GetType().Name}: {ex.Message}\n thrown by {ex.Source}\n at {ex.TargetSite}\n in {fileName}\n at line {lineNumber}\n in method \"{callerMemberName}\"\n------ Method Stack Trace ------");
|
||||
sb.Append($" {ex.GetType().Name}: {ex.Message}\n thrown by {ex.Source}\n at {ex.TargetSite}\n in {fileName.Split('\\')[^1]}\n at line {lineNumber}\n in method \"{callerMemberName}\"\n------ Method Stack Trace ------");
|
||||
|
||||
bool skip = true;
|
||||
foreach (StackFrame sf in stFrames)
|
||||
@@ -638,10 +662,26 @@ public static class Utils
|
||||
}
|
||||
|
||||
sb.Append("\n------ End of Method Stack Trace ------");
|
||||
sb.Append("\n------ Exception Stack Trace ------\n ");
|
||||
sb.Append("\n------ Exception ------\n ");
|
||||
|
||||
sb.Append(ex.StackTrace?.Replace("\r\n", "\n").Replace("\\n", "\n").Replace("\n", "\n "));
|
||||
|
||||
sb.Append("\n------ End of Exception ------");
|
||||
sb.Append("\n------ Exception Stack Trace ------\n");
|
||||
|
||||
var stEx = new StackTrace(ex, true);
|
||||
var stFramesEx = stEx.GetFrames();
|
||||
|
||||
foreach (StackFrame sf in stFramesEx)
|
||||
{
|
||||
var callerMethod = sf.GetMethod();
|
||||
|
||||
string callerMethodName = callerMethod?.Name;
|
||||
string callerClassName = callerMethod?.DeclaringType?.FullName;
|
||||
|
||||
sb.Append($"\n at {callerClassName}.{callerMethodName} in {sf.GetFileName()}, line {sf.GetFileLineNumber()}");
|
||||
}
|
||||
|
||||
sb.Append("\n------ End of Exception Stack Trace ------");
|
||||
|
||||
Logger.Error(sb.ToString(), firstFrame?.GetMethod()?.ToString(), multiLine: true);
|
||||
@@ -861,7 +901,6 @@ public static class Utils
|
||||
pc.Is(CustomRoles.NiceSwapper) ||
|
||||
pc.Is(CustomRoles.Speedrunner) ||
|
||||
pc.Is(CustomRoles.Needy) ||
|
||||
pc.Is(CustomRoles.Lazy) ||
|
||||
pc.Is(CustomRoles.Loyal) ||
|
||||
pc.Is(CustomRoles.SuperStar) ||
|
||||
pc.Is(CustomRoles.CyberStar) ||
|
||||
@@ -874,7 +913,7 @@ public static class Utils
|
||||
{
|
||||
if (Options.CurrentGameMode is CustomGameMode.CaptureTheFlag or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush) return false;
|
||||
if (__instance.PlayerId == PlayerControl.LocalPlayer.PlayerId || Options.CurrentGameMode is CustomGameMode.FFA or CustomGameMode.SoloKombat or CustomGameMode.MoveAndStop or CustomGameMode.HotPotato or CustomGameMode.Speedrun || (Options.CurrentGameMode == CustomGameMode.HideAndSeek && HnSManager.IsRoleTextEnabled(PlayerControl.LocalPlayer, __instance)) || Main.VisibleTasksCount && PlayerControl.LocalPlayer.Data.IsDead && Options.GhostCanSeeOtherRoles.GetBool() || PlayerControl.LocalPlayer.Is(CustomRoles.Mimic) && Main.VisibleTasksCount && __instance.Data.IsDead && Options.MimicCanSeeDeadRoles.GetBool()) return true;
|
||||
if (Altruist.On && Main.DiedThisRound.Contains(PlayerControl.LocalPlayer.PlayerId)) return false;
|
||||
if (CustomRoles.Altruist.RoleExist() && Main.DiedThisRound.Contains(PlayerControl.LocalPlayer.PlayerId)) return false;
|
||||
|
||||
switch (__instance.GetCustomRole())
|
||||
{
|
||||
@@ -1598,19 +1637,26 @@ public static class Utils
|
||||
|
||||
public static void CheckAndSpawnAdditionalRefugee(NetworkedPlayerInfo deadPlayer)
|
||||
{
|
||||
if (Options.CurrentGameMode != CustomGameMode.Standard || deadPlayer == null || deadPlayer.Object.Is(CustomRoles.Refugee) || Main.HasJustStarted || !GameStates.InGame || !Options.SpawnAdditionalRefugeeOnImpsDead.GetBool() || Main.AllAlivePlayerControls.Length < Options.SpawnAdditionalRefugeeMinAlivePlayers.GetInt() || CustomRoles.Refugee.RoleExist(countDead: true) || Main.AllAlivePlayerControls == null || Main.AllAlivePlayerControls.Length == 0 || Main.AllAlivePlayerControls.Any(x => x.PlayerId != deadPlayer.PlayerId && (x.Is(CustomRoleTypes.Impostor) || (x.IsNeutralKiller() && !Options.SpawnAdditionalRefugeeWhenNKAlive.GetBool())))) return;
|
||||
|
||||
PlayerControl[] ListToChooseFrom = Main.AllAlivePlayerControls.Where(x => x.PlayerId != deadPlayer.PlayerId && x.Is(CustomRoleTypes.Crewmate) && !x.Is(CustomRoles.Loyal)).ToArray();
|
||||
|
||||
if (ListToChooseFrom.Length > 0)
|
||||
try
|
||||
{
|
||||
var pc = ListToChooseFrom.RandomElement();
|
||||
pc.RpcSetCustomRole(CustomRoles.Refugee);
|
||||
pc.SetKillCooldown();
|
||||
Main.PlayerStates[pc.PlayerId].RemoveSubRole(CustomRoles.Madmate);
|
||||
Logger.Warn($"{pc.GetRealName()} is now a Refugee since all Impostors are dead", "Add Refugee");
|
||||
if (Options.CurrentGameMode != CustomGameMode.Standard || deadPlayer == null || deadPlayer.Object.Is(CustomRoles.Refugee) || Main.HasJustStarted || !GameStates.InGame || !Options.SpawnAdditionalRefugeeOnImpsDead.GetBool() || Main.AllAlivePlayerControls.Length < Options.SpawnAdditionalRefugeeMinAlivePlayers.GetInt() || CustomRoles.Refugee.RoleExist(countDead: true) || Main.AllAlivePlayerControls == null || Main.AllAlivePlayerControls.Length == 0 || Main.AllAlivePlayerControls.Any(x => x.PlayerId != deadPlayer.PlayerId && (x.Is(CustomRoleTypes.Impostor) || (x.IsNeutralKiller() && !Options.SpawnAdditionalRefugeeWhenNKAlive.GetBool())))) return;
|
||||
|
||||
PlayerControl[] ListToChooseFrom = Main.AllAlivePlayerControls.Where(x => x.PlayerId != deadPlayer.PlayerId && x.Is(CustomRoleTypes.Crewmate) && !x.Is(CustomRoles.Loyal)).ToArray();
|
||||
|
||||
if (ListToChooseFrom.Length > 0)
|
||||
{
|
||||
var pc = ListToChooseFrom.RandomElement();
|
||||
pc.RpcSetCustomRole(CustomRoles.Refugee);
|
||||
pc.SetKillCooldown();
|
||||
Main.PlayerStates[pc.PlayerId].RemoveSubRole(CustomRoles.Madmate);
|
||||
Logger.Warn($"{pc.GetRealName()} is now a Refugee since all Impostors are dead", "Add Refugee");
|
||||
}
|
||||
else Logger.Msg("No Player to change to Refugee.", "Add Refugee");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ThrowException(e);
|
||||
}
|
||||
else Logger.Msg("No Player to change to Refugee.", "Add Refugee");
|
||||
}
|
||||
|
||||
public static void SendMessage(string text, byte sendTo = byte.MaxValue, string title = "", bool noSplit = false)
|
||||
@@ -2033,10 +2079,10 @@ public static class Utils
|
||||
? SeerRealName
|
||||
: seerTeam switch
|
||||
{
|
||||
Team.Impostor when seer.IsMadmate() => $"<size=200%><color=#ff1919>{GetString("YouAreMadmate")}</size></color>\n<size=90%>{(showLongInfo ? longInfo : seer.GetRoleInfo()) + mHelp}</size>",
|
||||
Team.Impostor when seer.IsMadmate() => $"<size=150%><color=#ff1919>{GetString("YouAreMadmate")}</size></color>\n<size=90%>{(showLongInfo ? longInfo : seer.GetRoleInfo()) + mHelp}</size>",
|
||||
Team.Impostor => $"\n<size=90%>{(showLongInfo ? longInfo : seer.GetRoleInfo()) + mHelp}</size>",
|
||||
Team.Crewmate => $"<size=200%><color=#8cffff>{GetString("YouAreCrewmate")}</size></color>\n<size=90%>{(showLongInfo ? longInfo : seer.GetRoleInfo()) + mHelp}</size>",
|
||||
Team.Neutral => $"<size=200%><color=#ffab1b>{GetString("YouAreNeutral")}</size></color>\n<size=90%>{(showLongInfo ? longInfo : seer.GetRoleInfo()) + mHelp}</size>",
|
||||
Team.Crewmate => $"<size=150%><color=#8cffff>{GetString("YouAreCrewmate")}</size></color>\n<size=90%>{(showLongInfo ? longInfo : seer.GetRoleInfo()) + mHelp}</size>",
|
||||
Team.Neutral => $"<size=150%><color=#ffab1b>{GetString("YouAreNeutral")}</size></color>\n<size=90%>{(showLongInfo ? longInfo : seer.GetRoleInfo()) + mHelp}</size>",
|
||||
_ => SeerRealName
|
||||
};
|
||||
}
|
||||
@@ -2229,7 +2275,7 @@ public static class Utils
|
||||
? $"<size={fontSize}>{target.GetDisplayRoleName(seeTargetBetrayalAddons: shouldSeeTargetAddons)}{GetProgressText(target)}</size>\r\n"
|
||||
: string.Empty;
|
||||
|
||||
if (Altruist.On && Main.DiedThisRound.Contains(seer.PlayerId)) TargetRoleText = string.Empty;
|
||||
if (CustomRoles.Altruist.RoleExist() && Main.DiedThisRound.Contains(seer.PlayerId)) TargetRoleText = string.Empty;
|
||||
if (Options.CurrentGameMode is CustomGameMode.CaptureTheFlag or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush) TargetRoleText = string.Empty;
|
||||
|
||||
if (!GameStates.IsLobby)
|
||||
|
||||
@@ -309,7 +309,7 @@ internal static class ChatCommands
|
||||
Main.Instance.StartCoroutine(Countdown());
|
||||
return;
|
||||
|
||||
System.Collections.IEnumerator Countdown()
|
||||
IEnumerator Countdown()
|
||||
{
|
||||
var timer = 30f;
|
||||
while (timer > 0f)
|
||||
@@ -330,7 +330,7 @@ internal static class ChatCommands
|
||||
{
|
||||
ReadyPlayers.Add(player.PlayerId);
|
||||
}
|
||||
|
||||
|
||||
private static void DraftStartCommand(ChatController __instance, PlayerControl player, string text, string[] args)
|
||||
{
|
||||
DraftResult = [];
|
||||
@@ -344,7 +344,7 @@ internal static class ChatCommands
|
||||
return;
|
||||
}
|
||||
|
||||
DraftRoles = allRoles.Shuffle().Partition(allPlayerIds.Length).Zip(allPlayerIds).ToDictionary(x => x.Second, x => x.First.ToList());
|
||||
DraftRoles = allRoles.Shuffle().Partition(allPlayerIds.Length).Zip(allPlayerIds).ToDictionary(x => x.Second, x => x.First.Take(5).ToList());
|
||||
|
||||
foreach ((byte id, List<CustomRoles> roles) in DraftRoles)
|
||||
{
|
||||
@@ -2187,4 +2187,4 @@ internal class RpcSendChatPatch
|
||||
__result = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
+56
-64
@@ -124,10 +124,6 @@ internal class SetResolutionManager
|
||||
{
|
||||
public static void Postfix()
|
||||
{
|
||||
//if (MainMenuManagerPatch.qqButton != null)
|
||||
// MainMenuManagerPatch.qqButton.transform.localPosition = Vector3.Reflect(MainMenuManagerPatch.template.transform.localPosition, Vector3.left);
|
||||
//if (MainMenuManagerPatch.discordButton != null)
|
||||
// MainMenuManagerPatch.discordButton.transform.localPosition = Vector3.Reflect(MainMenuManagerPatch.template.transform.localPosition, Vector3.left);
|
||||
if (MainMenuManagerPatch.UpdateButton != null)
|
||||
MainMenuManagerPatch.UpdateButton.transform.localPosition = MainMenuManagerPatch.Template.transform.localPosition + new Vector3(0.25f, 0.75f);
|
||||
}
|
||||
@@ -143,15 +139,14 @@ internal class InnerNetObjectSerializePatch
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(InnerNetClient))]
|
||||
public static class InnerNetClientPatch
|
||||
{
|
||||
private static byte Timer;
|
||||
|
||||
[HarmonyPatch(typeof(InnerNetClient), nameof(InnerNetClient.SendInitialData))]
|
||||
[HarmonyPrefix]
|
||||
public static bool SendInitialDataPrefix(InnerNetClient __instance, int clientId)
|
||||
{
|
||||
if (!Constants.IsVersionModded() || __instance.NetworkMode != NetworkModes.OnlineGame) return true;
|
||||
if (!Constants.IsVersionModded() || GameStates.IsInGame || __instance.NetworkMode != NetworkModes.OnlineGame) return true;
|
||||
// We make sure other stuff like PlayerControl and LobbyBehavior is spawned properly
|
||||
// Then we spawn the networked data for new clients
|
||||
MessageWriter messageWriter = MessageWriter.Get(SendOption.Reliable);
|
||||
@@ -161,10 +156,10 @@ public static class InnerNetClientPatch
|
||||
List<InnerNetObject> obj = __instance.allObjects;
|
||||
lock (obj)
|
||||
{
|
||||
System.Collections.Generic.HashSet<GameObject> hashSet = [];
|
||||
HashSet<GameObject> hashSet = new();
|
||||
for (int i = 0; i < __instance.allObjects.Count; i++)
|
||||
{
|
||||
InnerNetObject innerNetObject = __instance.allObjects[i];
|
||||
InnerNetObject innerNetObject = __instance.allObjects[i]; // False error
|
||||
if (innerNetObject && (innerNetObject.OwnerId != -4 || __instance.AmModdedHost) && hashSet.Add(innerNetObject.gameObject))
|
||||
{
|
||||
GameManager gameManager = innerNetObject as GameManager;
|
||||
@@ -189,23 +184,26 @@ public static class InnerNetClientPatch
|
||||
return false;
|
||||
}
|
||||
|
||||
// InnerSloth vanilla officials send PlayerInfo in spilt reliable packets
|
||||
private static void DelaySpawnPlayerInfo(InnerNetClient __instance, int clientId)
|
||||
{
|
||||
var players = GameData.Instance.AllPlayers.ToArray();
|
||||
var players = GameData.Instance.AllPlayers.ToArray().ToList();
|
||||
|
||||
// We send 5 players at a time to prevent too large packets
|
||||
foreach (var batch in players.Chunk(5))
|
||||
foreach (var player in players)
|
||||
{
|
||||
MessageWriter messageWriter = MessageWriter.Get(SendOption.Reliable);
|
||||
messageWriter.StartMessage(6);
|
||||
messageWriter.Write(__instance.GameId);
|
||||
messageWriter.WritePacked(clientId);
|
||||
if (player != null && player.ClientId != clientId && !player.Disconnected)
|
||||
{
|
||||
MessageWriter messageWriter = MessageWriter.Get(SendOption.Reliable);
|
||||
messageWriter.StartMessage(6);
|
||||
messageWriter.Write(__instance.GameId);
|
||||
messageWriter.WritePacked(clientId);
|
||||
|
||||
batch.DoIf(p => p != null && p.ClientId != clientId && !p.Disconnected, p => __instance.WriteSpawnMessage(p, p.OwnerId, p.SpawnFlags, messageWriter));
|
||||
__instance.WriteSpawnMessage(player, player.OwnerId, player.SpawnFlags, messageWriter);
|
||||
messageWriter.EndMessage();
|
||||
|
||||
messageWriter.EndMessage();
|
||||
__instance.SendOrDisconnect(messageWriter);
|
||||
messageWriter.Recycle();
|
||||
__instance.SendOrDisconnect(messageWriter);
|
||||
messageWriter.Recycle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +219,7 @@ public static class InnerNetClientPatch
|
||||
{
|
||||
for (int i = 0; i < __instance.allObjects.Count; i++)
|
||||
{
|
||||
InnerNetObject innerNetObject = __instance.allObjects[i];
|
||||
InnerNetObject innerNetObject = __instance.allObjects[i]; // False error
|
||||
if (innerNetObject && innerNetObject is not NetworkedPlayerInfo && innerNetObject.IsDirty && (innerNetObject.AmOwner || (innerNetObject.OwnerId == -2 && __instance.AmHost)))
|
||||
{
|
||||
MessageWriter messageWriter = __instance.Streams[(int)innerNetObject.sendMode];
|
||||
@@ -229,8 +227,14 @@ public static class InnerNetClientPatch
|
||||
messageWriter.WritePacked(innerNetObject.NetId);
|
||||
try
|
||||
{
|
||||
if (innerNetObject.Serialize(messageWriter, false)) messageWriter.EndMessage();
|
||||
else messageWriter.CancelMessage();
|
||||
if (innerNetObject.Serialize(messageWriter, false))
|
||||
{
|
||||
messageWriter.EndMessage();
|
||||
}
|
||||
else
|
||||
{
|
||||
messageWriter.CancelMessage();
|
||||
}
|
||||
|
||||
if (innerNetObject.Chunked && innerNetObject.IsDirty)
|
||||
{
|
||||
@@ -266,62 +270,50 @@ public static class InnerNetClientPatch
|
||||
[HarmonyPostfix]
|
||||
public static void FixedUpdatePostfix(InnerNetClient __instance)
|
||||
{
|
||||
if (!__instance.AmHost || __instance.Streams == null || __instance.NetworkMode != NetworkModes.OnlineGame) return;
|
||||
// Send it with None calls. Who cares?
|
||||
if (!Constants.IsVersionModded() || GameStates.IsInGame || __instance.NetworkMode != NetworkModes.OnlineGame) return;
|
||||
if (!__instance.AmHost || __instance.Streams == null) return;
|
||||
|
||||
if (Timer == 0)
|
||||
var players = GameData.Instance.AllPlayers.ToArray();
|
||||
foreach (var player in players)
|
||||
{
|
||||
Timer = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
var player = GameData.Instance.AllPlayers.ToArray().FirstOrDefault(x => x.IsDirty);
|
||||
if (player != null)
|
||||
{
|
||||
Timer = 0;
|
||||
MessageWriter messageWriter = MessageWriter.Get(SendOption.Reliable);
|
||||
messageWriter.StartMessage(5);
|
||||
messageWriter.Write(__instance.GameId);
|
||||
messageWriter.StartMessage(1);
|
||||
messageWriter.WritePacked(player.NetId);
|
||||
try
|
||||
if (player.IsDirty)
|
||||
{
|
||||
if (player.Serialize(messageWriter, false))
|
||||
MessageWriter messageWriter = MessageWriter.Get();
|
||||
messageWriter.StartMessage(5);
|
||||
messageWriter.Write(__instance.GameId);
|
||||
messageWriter.StartMessage(1);
|
||||
messageWriter.WritePacked(player.NetId);
|
||||
try
|
||||
{
|
||||
if (player.Serialize(messageWriter, false))
|
||||
{
|
||||
messageWriter.EndMessage();
|
||||
}
|
||||
else
|
||||
{
|
||||
messageWriter.CancelMessage();
|
||||
player.ClearDirtyBits();
|
||||
continue;
|
||||
}
|
||||
|
||||
messageWriter.EndMessage();
|
||||
__instance.SendOrDisconnect(messageWriter);
|
||||
messageWriter.Recycle();
|
||||
}
|
||||
else
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Exception(ex, "FixedUpdatePostfix");
|
||||
messageWriter.CancelMessage();
|
||||
player.ClearDirtyBits();
|
||||
return;
|
||||
}
|
||||
|
||||
messageWriter.EndMessage();
|
||||
__instance.SendOrDisconnect(messageWriter);
|
||||
messageWriter.Recycle();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Exception(ex, "FixedUpdatePostfix");
|
||||
messageWriter.CancelMessage();
|
||||
player.ClearDirtyBits();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(GameData), nameof(GameData.DirtyAllData))]
|
||||
internal class DirtyAllDataPatch
|
||||
{
|
||||
// Currently, this function only occurs in CreatePlayer.
|
||||
// It's believed to lag the host, delay the PlayerControl spawn message, blackout new clients
|
||||
// and send huge packets to all clients while there's completely no need to run this.
|
||||
// Temporarily disable it until Innersloth gets a better fix.
|
||||
public static bool Prefix() => false;
|
||||
}
|
||||
|
||||
[HarmonyPatch]
|
||||
internal class AuthTimeoutPatch
|
||||
internal static class AuthTimeoutPatch
|
||||
{
|
||||
[HarmonyPatch(typeof(AuthManager._CoConnect_d__4), nameof(AuthManager._CoConnect_d__4.MoveNext))]
|
||||
[HarmonyPatch(typeof(AuthManager._CoWaitForNonce_d__6), nameof(AuthManager._CoWaitForNonce_d__6.MoveNext))]
|
||||
@@ -339,7 +331,7 @@ internal class AuthTimeoutPatch
|
||||
return false;
|
||||
}
|
||||
|
||||
// If you don't patch this, you still need to wait for 5s.
|
||||
// If you don't patch this, you still need to wait for 5 s.
|
||||
// I have no idea why this is happening
|
||||
[HarmonyPatch(typeof(AmongUsClient._CoJoinOnlinePublicGame_d__1), nameof(AmongUsClient._CoJoinOnlinePublicGame_d__1.MoveNext))]
|
||||
[HarmonyPrefix]
|
||||
|
||||
@@ -108,7 +108,7 @@ static class ExileControllerWrapUpPatch
|
||||
PetsPatch.RpcRemovePet(pc);
|
||||
}
|
||||
|
||||
if (Options.RandomSpawn.GetBool() || Options.CurrentGameMode != CustomGameMode.Standard)
|
||||
if (Options.RandomSpawn.GetBool())
|
||||
{
|
||||
RandomSpawn.SpawnMap map = Main.NormalOptions.MapId switch
|
||||
{
|
||||
@@ -122,13 +122,8 @@ static class ExileControllerWrapUpPatch
|
||||
if (map != null) Main.AllAlivePlayerControls.Do(map.RandomTeleport);
|
||||
}
|
||||
|
||||
Utils.CheckAndSpawnAdditionalRefugee(exiled);
|
||||
|
||||
FallFromLadder.Reset();
|
||||
Utils.CountAlivePlayers(true);
|
||||
Utils.AfterMeetingTasks();
|
||||
Utils.SyncAllSettings();
|
||||
Utils.NotifyRoles(ForceLoop: true);
|
||||
}
|
||||
|
||||
static void WrapUpFinalizer()
|
||||
@@ -140,7 +135,7 @@ static class ExileControllerWrapUpPatch
|
||||
{
|
||||
AntiBlackout.SendGameData();
|
||||
AntiBlackout.SetRealPlayerRoles();
|
||||
}, 1.1f, "Restore IsDead Task");
|
||||
}, 0.7f, "Restore IsDead Task");
|
||||
LateTask.New(() =>
|
||||
{
|
||||
Main.AfterMeetingDeathPlayers.Do(x =>
|
||||
@@ -157,6 +152,10 @@ static class ExileControllerWrapUpPatch
|
||||
});
|
||||
Main.AfterMeetingDeathPlayers.Clear();
|
||||
AntiBlackout.ResetAfterMeeting();
|
||||
Utils.AfterMeetingTasks();
|
||||
Utils.SyncAllSettings();
|
||||
Utils.NotifyRoles(NoCache: true);
|
||||
Utils.CheckAndSetVentInteractions();
|
||||
}, 1.2f, "AfterMeetingDeathPlayers Task");
|
||||
}
|
||||
|
||||
|
||||
+2
-15
@@ -850,7 +850,7 @@ static class IntroCutsceneDestroyPatch
|
||||
Main.PlayerStates[lp.PlayerId].SetDead();
|
||||
}
|
||||
|
||||
if (Options.RandomSpawn.GetBool() || Options.CurrentGameMode != CustomGameMode.Standard)
|
||||
if (Options.RandomSpawn.GetBool())
|
||||
{
|
||||
RandomSpawn.SpawnMap map = Main.NormalOptions.MapId switch
|
||||
{
|
||||
@@ -878,20 +878,7 @@ static class IntroCutsceneDestroyPatch
|
||||
}
|
||||
}
|
||||
|
||||
bool shouldPerformVentInteractions = false;
|
||||
foreach (var pc in Main.AllPlayerControls)
|
||||
{
|
||||
if (VentilationSystemDeterioratePatch.BlockVentInteraction(pc))
|
||||
{
|
||||
VentilationSystemDeterioratePatch.LastClosestVent[pc.PlayerId] = pc.GetVentsFromClosest()[0].Id;
|
||||
shouldPerformVentInteractions = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldPerformVentInteractions)
|
||||
{
|
||||
Utils.SetAllVentInteractions();
|
||||
}
|
||||
Utils.CheckAndSetVentInteractions();
|
||||
|
||||
if (AFKDetector.ActivateOnStart.GetBool())
|
||||
{
|
||||
|
||||
+17
-20
@@ -288,12 +288,13 @@ static class CheckForEndVotingPatch
|
||||
__instance.RpcVotingComplete(states.ToArray(), exiledPlayer, tie);
|
||||
|
||||
CheckForDeathOnExile(PlayerState.DeathReason.Vote, exileId);
|
||||
Utils.CheckAndSpawnAdditionalRefugee(exiledPlayer);
|
||||
|
||||
Main.LastVotedPlayerInfo = exiledPlayer;
|
||||
AntiBlackout.ExilePlayerId = exiledPlayer.PlayerId;
|
||||
AntiBlackout.ExilePlayerId = exileId;
|
||||
if (Main.LastVotedPlayerInfo != null)
|
||||
{
|
||||
AntiBlackout.ExilePlayerId = exiledPlayer.PlayerId;
|
||||
AntiBlackout.ExilePlayerId = exileId;
|
||||
ConfirmEjections(Main.LastVotedPlayerInfo, braked);
|
||||
}
|
||||
|
||||
@@ -501,8 +502,8 @@ static class CheckForEndVotingPatch
|
||||
{
|
||||
try
|
||||
{
|
||||
Witch.OnCheckForEndVoting(deathReason, playerIds);
|
||||
Virus.OnCheckForEndVoting(deathReason, playerIds);
|
||||
if (Witch.playerIdList.Count > 0) Witch.OnCheckForEndVoting(deathReason, playerIds);
|
||||
if (Virus.playerIdList.Count > 0) Virus.OnCheckForEndVoting(deathReason, playerIds);
|
||||
if (deathReason == PlayerState.DeathReason.Vote) Gaslighter.OnExile(playerIds);
|
||||
foreach (var playerId in playerIds)
|
||||
{
|
||||
@@ -975,26 +976,22 @@ static class MeetingHudStartPatch
|
||||
[HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.Update))]
|
||||
static class MeetingHudUpdatePatch
|
||||
{
|
||||
private static int bufferTime = 10;
|
||||
private static int BufferTime = 10;
|
||||
|
||||
private static void ClearShootButton(MeetingHud __instance, bool forceAll = false)
|
||||
=> __instance.playerStates.ToList().ForEach(x =>
|
||||
{
|
||||
if ((forceAll || !Main.PlayerStates.TryGetValue(x.TargetPlayerId, out var ps) || ps.IsDead) && x.transform.FindChild("ShootButton") != null) Object.Destroy(x.transform.FindChild("ShootButton").gameObject);
|
||||
});
|
||||
private static void ClearShootButton(MeetingHud __instance, bool forceAll = false) => __instance.playerStates.DoIf(
|
||||
x => (forceAll || !Main.PlayerStates.TryGetValue(x.TargetPlayerId, out var ps) || ps.IsDead) && x.transform.FindChild("ShootButton") != null,
|
||||
x => Object.Destroy(x.transform.FindChild("ShootButton").gameObject));
|
||||
|
||||
public static void Postfix(MeetingHud __instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Meeting Skip with vote counting on keystroke (m + delete)
|
||||
// Meeting Skip with vote counting on keystroke (F6)
|
||||
if (AmongUsClient.Instance.AmHost && Input.GetKeyDown(KeyCode.F6))
|
||||
{
|
||||
__instance.CheckForEndVoting();
|
||||
}
|
||||
|
||||
//if (Options.DisableCrackedGlass.GetBool()) __instance.CrackedGlass = null;
|
||||
|
||||
if (AmongUsClient.Instance.AmHost && Input.GetMouseButtonUp(1) && Input.GetKey(KeyCode.LeftControl))
|
||||
{
|
||||
__instance.playerStates.DoIf(x => x.HighlightedFX.enabled, x =>
|
||||
@@ -1006,7 +1003,7 @@ static class MeetingHudUpdatePatch
|
||||
player.RpcExileV2();
|
||||
Main.PlayerStates[player.PlayerId].SetDead();
|
||||
Utils.SendMessage(string.Format(GetString("Message.Executed"), player.Data.PlayerName));
|
||||
Logger.Info($"{player.GetNameWithRole().RemoveHtmlTags()}を処刑しました", "Execution");
|
||||
Logger.Info($"{player.GetNameWithRole().RemoveHtmlTags()} was executed by the host", "Execution");
|
||||
__instance.CheckForEndVoting();
|
||||
}
|
||||
});
|
||||
@@ -1022,10 +1019,10 @@ static class MeetingHudUpdatePatch
|
||||
return;
|
||||
}
|
||||
|
||||
bufferTime--;
|
||||
if (bufferTime < 0 && __instance.discussionTimer > 0)
|
||||
BufferTime--;
|
||||
if (BufferTime < 0 && __instance.discussionTimer > 0)
|
||||
{
|
||||
bufferTime = 10;
|
||||
BufferTime = 10;
|
||||
var myRole = PlayerControl.LocalPlayer.GetCustomRole();
|
||||
|
||||
__instance.playerStates.Where(x => (!Main.PlayerStates.TryGetValue(x.TargetPlayerId, out var ps) || ps.IsDead) && !x.AmDead).Do(x => x.SetDead(x.DidReport, true));
|
||||
@@ -1059,7 +1056,7 @@ static class MeetingHudUpdatePatch
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(PlayerVoteArea), nameof(PlayerVoteArea.SetHighlighted))]
|
||||
class SetHighlightedPatch
|
||||
static class SetHighlightedPatch
|
||||
{
|
||||
public static bool Prefix(PlayerVoteArea __instance, bool value)
|
||||
{
|
||||
@@ -1071,7 +1068,7 @@ class SetHighlightedPatch
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.OnDestroy))]
|
||||
class MeetingHudOnDestroyPatch
|
||||
static class MeetingHudOnDestroyPatch
|
||||
{
|
||||
public static void Postfix()
|
||||
{
|
||||
@@ -1088,7 +1085,7 @@ class MeetingHudOnDestroyPatch
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.CastVote))]
|
||||
class MeetingHudCastVotePatch
|
||||
static class MeetingHudCastVotePatch
|
||||
{
|
||||
private static readonly Dictionary<byte, (MeetingHud MeetingHud, PlayerVoteArea SourcePVA, PlayerControl SourcePC)> ShouldCancelVoteList = [];
|
||||
|
||||
|
||||
@@ -7,31 +7,35 @@ namespace EHR;
|
||||
[HarmonyPatch(typeof(MovingPlatformBehaviour))]
|
||||
public static class MovingPlatformBehaviourPatch
|
||||
{
|
||||
private static bool isDisabled;
|
||||
private static bool IsDisabled;
|
||||
|
||||
[HarmonyPatch(nameof(MovingPlatformBehaviour.Start)), HarmonyPrefix]
|
||||
public static void StartPrefix(MovingPlatformBehaviour __instance)
|
||||
{
|
||||
isDisabled = Options.DisableAirshipMovingPlatform.GetBool();
|
||||
IsDisabled = Options.DisableAirshipMovingPlatform.GetBool();
|
||||
|
||||
if (isDisabled)
|
||||
if (IsDisabled)
|
||||
{
|
||||
__instance.transform.localPosition = __instance.DisabledPosition;
|
||||
ShipStatus.Instance.Cast<AirshipStatus>().outOfOrderPlat.SetActive(true);
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(nameof(MovingPlatformBehaviour.IsDirty), MethodType.Getter), HarmonyPrefix]
|
||||
public static bool GetIsDirtyPrefix(ref bool __result)
|
||||
{
|
||||
if (isDisabled)
|
||||
if (IsDisabled)
|
||||
{
|
||||
__result = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[HarmonyPatch(nameof(MovingPlatformBehaviour.Use), typeof(PlayerControl)), HarmonyPrefix]
|
||||
public static bool UsePrefix() => !isDisabled;
|
||||
public static bool UsePrefix() => !IsDisabled;
|
||||
|
||||
[HarmonyPatch(nameof(MovingPlatformBehaviour.SetSide)), HarmonyPrefix]
|
||||
public static bool SetSidePrefix() => !isDisabled;
|
||||
}
|
||||
public static bool SetSidePrefix() => !IsDisabled;
|
||||
}
|
||||
@@ -255,14 +255,18 @@ internal class ChangeRoleSettings
|
||||
|
||||
Camouflage.BlockCamouflage = false;
|
||||
Camouflage.Init();
|
||||
var invalidColor = Main.AllPlayerControls.Where(p => p.Data.DefaultOutfit.ColorId < 0 || Palette.PlayerColors.Length <= p.Data.DefaultOutfit.ColorId).Select(p => $"{p.name}").ToArray();
|
||||
if (invalidColor.Length > 0)
|
||||
|
||||
if (AmongUsClient.Instance.AmHost)
|
||||
{
|
||||
var msg = GetString("Error.InvalidColor");
|
||||
Logger.SendInGame(msg);
|
||||
msg += "\n" + string.Join(",", invalidColor);
|
||||
Utils.SendMessage(msg);
|
||||
Logger.Error(msg, "CoStartGame");
|
||||
var invalidColor = Main.AllPlayerControls.Where(p => p.Data.DefaultOutfit.ColorId < 0 || Palette.PlayerColors.Length <= p.Data.DefaultOutfit.ColorId).Select(p => $"{p.name}").ToArray();
|
||||
if (invalidColor.Length > 0)
|
||||
{
|
||||
var msg = GetString("Error.InvalidColor");
|
||||
Logger.SendInGame(msg);
|
||||
msg += "\n" + string.Join(",", invalidColor);
|
||||
Utils.SendMessage(msg);
|
||||
Logger.Error(msg, "CoStartGame");
|
||||
}
|
||||
}
|
||||
|
||||
RoleResult = [];
|
||||
@@ -1194,4 +1198,4 @@ static class FixIntroPatch
|
||||
DestroyableSingleton<HudManager>.Instance.HideGameLoader();
|
||||
}, 1f, log: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -994,7 +994,7 @@ static class ReportDeadBodyPatch
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utils.ThrowException(e);
|
||||
ThrowException(e);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1229,7 +1229,7 @@ static class FixedUpdatePatch
|
||||
}
|
||||
}
|
||||
|
||||
if (Options.DontUpdateDeadPlayers.GetBool() && !__instance.IsAlive() && (!Altruist.On || Main.PlayerStates[id].Role is not Altruist at || at.ReviveStartTS == 0))
|
||||
if (Options.DontUpdateDeadPlayers.GetBool() && !__instance.IsAlive() && (!Altruist.On || !CustomRoles.Altruist.RoleExist() || Main.PlayerStates[id].Role is not Altruist at || at.ReviveStartTS == 0))
|
||||
{
|
||||
DeadBufferTime.TryAdd(id, 30);
|
||||
DeadBufferTime[id]--;
|
||||
|
||||
@@ -495,4 +495,18 @@ static class InnerNetClientFixedUpdatePatch
|
||||
|
||||
AmongUsClient.Instance.KickNotJoinedPlayers();
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.SetColor))]
|
||||
static class RpcSetColorPatch
|
||||
{
|
||||
public static void Postfix(PlayerControl __instance, byte bodyColor)
|
||||
{
|
||||
if (Main.IntroDestroyed || __instance == null) return;
|
||||
|
||||
Logger.Info($"{__instance.GetRealName()}'s color is {Palette.GetColorName(bodyColor)}", "RpcSetColor");
|
||||
if (bodyColor == 255) return;
|
||||
|
||||
Main.PlayerColors[__instance.PlayerId] = Palette.PlayerColors[bodyColor];
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,7 @@ class RandomSpawn
|
||||
player.RpcResetAbilityCooldown();
|
||||
if (Options.FixFirstKillCooldown.GetBool() && !MeetingStates.MeetingCalled) player.SetKillCooldown(Main.AllPlayerKillCooldown[player.PlayerId]);
|
||||
else if (Options.StartingKillCooldown.GetInt() != 10) player.SetKillCooldown(Options.StartingKillCooldown.GetInt());
|
||||
if (!Options.RandomSpawn.GetBool() && Options.CurrentGameMode == CustomGameMode.Standard) return;
|
||||
if (!Options.RandomSpawn.GetBool()) return;
|
||||
new AirshipSpawnMap().RandomTeleport(player);
|
||||
Penguin.OnSpawnAirship();
|
||||
}
|
||||
|
||||
@@ -375,6 +375,9 @@ static class ShipStatusSpawnPlayerPatch
|
||||
{
|
||||
if (!AmongUsClient.Instance.AmHost || initialSpawn || !player.IsAlive()) return true;
|
||||
|
||||
// Lazy doesn't teleport to the meeting table
|
||||
if (player.Is(CustomRoles.Lazy)) return false;
|
||||
|
||||
Vector2 direction = Vector2.up.Rotate((player.PlayerId - 1) * (360f / numPlayers));
|
||||
Vector2 position = __instance.MeetingSpawnCenter + direction * __instance.SpawnRadius + new Vector2(0.0f, 0.3636f);
|
||||
|
||||
@@ -394,6 +397,9 @@ static class PolusShipStatusSpawnPlayerPatch
|
||||
{
|
||||
if (!AmongUsClient.Instance.AmHost || initialSpawn || !player.IsAlive()) return true;
|
||||
|
||||
// Lazy doesn't teleport to the meeting table
|
||||
if (player.Is(CustomRoles.Lazy)) return false;
|
||||
|
||||
int num1 = Mathf.FloorToInt(numPlayers / 2f);
|
||||
int num2 = player.PlayerId % 15;
|
||||
|
||||
@@ -455,6 +461,7 @@ static class VentilationSystemDeterioratePatch
|
||||
{
|
||||
public static Dictionary<byte, int> LastClosestVent = [];
|
||||
private static readonly Dictionary<byte, bool> LastCanUseVent = [];
|
||||
private static readonly Dictionary<byte, int> LastClosestVentForUpdate = [];
|
||||
|
||||
public static void Postfix(VentilationSystem __instance)
|
||||
{
|
||||
@@ -598,7 +605,14 @@ static class VentilationSystemDeterioratePatch
|
||||
|
||||
public static void CheckVentInteraction(PlayerControl pc)
|
||||
{
|
||||
if (!GameStates.IsInTask) return;
|
||||
if (!GameStates.IsInTask || ExileController.Instance) return;
|
||||
|
||||
int closestVent = pc.GetClosestVent().Id;
|
||||
if (!LastClosestVentForUpdate.TryGetValue(pc.PlayerId, out int lastClosestVent))
|
||||
{
|
||||
LastClosestVentForUpdate[pc.PlayerId] = closestVent;
|
||||
return;
|
||||
}
|
||||
|
||||
bool canUse = pc.CanUseVent();
|
||||
|
||||
@@ -608,10 +622,28 @@ static class VentilationSystemDeterioratePatch
|
||||
return;
|
||||
}
|
||||
|
||||
if (couldUse != canUse)
|
||||
if (couldUse != canUse || lastClosestVent != closestVent)
|
||||
{
|
||||
LastCanUseVent[pc.PlayerId] = canUse;
|
||||
SerializeV2(ShipStatus.Instance.Systems[SystemTypes.Ventilation].Cast<VentilationSystem>(), pc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(VentilationSystem), nameof(VentilationSystem.IsVentCurrentlyBeingCleaned))]
|
||||
static class VentSystemIsVentCurrentlyBeingCleanedPatch
|
||||
{
|
||||
// Patch block use vent for host becouse host always skips RpcSerializeVent
|
||||
public static bool Prefix([HarmonyArgument(0)] int id, ref bool __result)
|
||||
{
|
||||
if (!AmongUsClient.Instance.AmHost) return true;
|
||||
|
||||
if (!PlayerControl.LocalPlayer.CanUseVent(id))
|
||||
{
|
||||
__result = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ using EHR.Impostor;
|
||||
using EHR.Modules;
|
||||
using HarmonyLib;
|
||||
using Il2CppInterop.Runtime.InteropTypes.Arrays;
|
||||
using Il2CppSystem.Collections.Generic;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
namespace EHR;
|
||||
@@ -13,7 +14,7 @@ namespace EHR;
|
||||
class AddTasksFromListPatch
|
||||
{
|
||||
public static void Prefix( /*ShipStatus __instance,*/
|
||||
[HarmonyArgument(4)] Il2CppSystem.Collections.Generic.List<NormalPlayerTask> unusedTasks)
|
||||
[HarmonyArgument(4)] List<NormalPlayerTask> unusedTasks)
|
||||
{
|
||||
if (!AmongUsClient.Instance.AmHost) return;
|
||||
|
||||
@@ -157,8 +158,8 @@ class RpcSetTasksPatch
|
||||
NumShortTasks = Options.MadSnitchTasks.GetInt();
|
||||
}
|
||||
|
||||
// GM and Lazy have no tasks
|
||||
if (pc.Is(CustomRoles.GM) || pc.Is(CustomRoles.Needy) || Options.CurrentGameMode is CustomGameMode.SoloKombat or CustomGameMode.FFA || pc.Is(CustomRoles.Lazy))
|
||||
// GM and Lazy Guy have no tasks
|
||||
if (pc.Is(CustomRoles.GM) || pc.Is(CustomRoles.Needy) || Options.CurrentGameMode is CustomGameMode.SoloKombat or CustomGameMode.FFA or CustomGameMode.HotPotato or CustomGameMode.NaturalDisasters)
|
||||
{
|
||||
hasCommonTasks = false;
|
||||
NumShortTasks = 0;
|
||||
@@ -188,7 +189,7 @@ class RpcSetTasksPatch
|
||||
|
||||
// List containing IDs of assignable tasks
|
||||
// Clone of the second argument of the original RpcSetTasks
|
||||
Il2CppSystem.Collections.Generic.List<byte> TasksList = new();
|
||||
List<byte> TasksList = new();
|
||||
foreach (var num in taskTypeIds)
|
||||
{
|
||||
TasksList.Add(num);
|
||||
@@ -204,18 +205,18 @@ class RpcSetTasksPatch
|
||||
|
||||
// HashSet where assigned tasks will be placed
|
||||
// Prevent multiple assignments of the same task
|
||||
Il2CppSystem.Collections.Generic.HashSet<TaskTypes> usedTaskTypes = new();
|
||||
HashSet<TaskTypes> usedTaskTypes = new();
|
||||
int start2 = 0;
|
||||
int start3 = 0;
|
||||
|
||||
// List of assignable long tasks
|
||||
Il2CppSystem.Collections.Generic.List<NormalPlayerTask> LongTasks = new();
|
||||
List<NormalPlayerTask> LongTasks = new();
|
||||
foreach (var task in ShipStatus.Instance.LongTasks)
|
||||
LongTasks.Add(task);
|
||||
Shuffle(LongTasks);
|
||||
|
||||
// List of assignable short tasks
|
||||
Il2CppSystem.Collections.Generic.List<NormalPlayerTask> ShortTasks = new();
|
||||
List<NormalPlayerTask> ShortTasks = new();
|
||||
foreach (var task in ShipStatus.Instance.ShortTasks)
|
||||
ShortTasks.Add(task);
|
||||
Shuffle(ShortTasks);
|
||||
@@ -244,7 +245,7 @@ class RpcSetTasksPatch
|
||||
}
|
||||
}
|
||||
|
||||
private static void Shuffle<T>(Il2CppSystem.Collections.Generic.List<T> list)
|
||||
private static void Shuffle<T>(List<T> list)
|
||||
{
|
||||
for (int i = 0; i < list.Count - 1; i++)
|
||||
{
|
||||
|
||||
@@ -25,10 +25,10 @@
|
||||
"ShortTeamName.Impostor": "Imp",
|
||||
"ShortTeamName.Crewmate": "Crew",
|
||||
"ShortTeamName.Neutral": "Neut",
|
||||
"YouAreCrewmate": "<size=1.7><color=#ffffff>You are</color> Crewmate</size>",
|
||||
"YouAreImpostor": "<size=1.7><color=#ffffff>You are</color> Impostor</size>",
|
||||
"YouAreNeutral": "<size=1.7><color=#ffffff>You are</color> Neutral</size>",
|
||||
"YouAreMadmate": "<size=1.7><color=#ffffff>You are in</color> Impostors <color=#ffffff>team</color></size>",
|
||||
"YouAreCrewmate": "<size=1.7><color=#ffffff>You are a</color> Crewmate</size>",
|
||||
"YouAreImpostor": "<size=1.7><color=#ffffff>You are an</color> Impostor</size>",
|
||||
"YouAreNeutral": "<size=1.7><color=#ffffff>You are a</color> Neutral</size>",
|
||||
"YouAreMadmate": "<size=1.7><color=#ffffff>You are in the</color> Impostor <color=#ffffff>team</color></size>",
|
||||
"CrewmateSub": "Find and exile the <color=#ff1919>Impostors</color>",
|
||||
"ImpostorSub": "Sabotage and kill everyone",
|
||||
"NeutralSub": "Work alone to achieve your victory",
|
||||
@@ -229,7 +229,6 @@
|
||||
"Pestilence": "Pestilence",
|
||||
"Poisoner": "Poisoner",
|
||||
"Sidekick": "Sidekick",
|
||||
"NWitch": "Controller",
|
||||
"Totocalcio": "Follower",
|
||||
"Succubus": "Cultist",
|
||||
"HexMaster": "Hex Master",
|
||||
@@ -513,7 +512,6 @@
|
||||
"PestilenceInfo": "You're unstoppable",
|
||||
"PoisonerInfo": "Your kills are delayed",
|
||||
"SidekickInfo": "Help the Jackal win",
|
||||
"NWitchInfo": "Control crewmates and live to see them lose",
|
||||
"TotocalcioInfo": "Follow a player and help them",
|
||||
"SuccubusInfo": "Charm everyone",
|
||||
"HexMasterInfo": "Hex players to kill them in meetings",
|
||||
@@ -810,7 +808,7 @@
|
||||
"RascalInfoLong": "(Add-ons):\\nAs the Rascal, you can die to the Sheriff, and Snitch can find you if Snitch can find madmates.\\n\\nOnly assigned to Crewmates, cannot be assigned by the Merchant.",
|
||||
"SoullessInfoLong": "(Add-ons):\\nWhen a Cursed Soul snatches your soul, you get this add-on.\\n\\nYou are not counted as alive.",
|
||||
"GravestoneInfoLong": "(Add-ons):\\nAs the Gravestone, your role is revealed to everyone when you die.",
|
||||
"LazyInfoLong": "(Add-ons):\\nAs the Lazy, you are assigned a single short task and are immune to Warlocks, Puppeteers, and Gangsters.",
|
||||
"LazyInfoLong": "(Add-ons):\\nAs the Lazy, you are too lazy to walk to the meeting table when meetings are called, so you start the next round exactly where you ended the previous one, and you're also immune to Warlocks, Puppeteers, and Gangsters.",
|
||||
"AutopsyInfoLong": "(Add-ons):\\nAs the Autopsy, you can see how people died.\\n\\nCannot be assigned to Doctor, Tracefinder, Scientist, or Sunnyboy.",
|
||||
"LoyalInfoLong": "(Add-ons):\\nAs the Loyal, you cannot be recruited by roles such as Jackal or Cultist.\\n\\nCannot be assigned to neutrals.",
|
||||
"EvilSpiritInfoLong": "(Add-ons):\\nAs Evil Spirit, it's your job to help the Spiritcaller to victory. You can use your Haunt button to freeze players and reduce their vision. Alternatively, you can use your Haunt button to give the Spiritcaller a shield against a kill attempt temporarily.",
|
||||
@@ -1006,6 +1004,7 @@
|
||||
"GameStateCommand.ShowTasks": "Show amount of completed tasks",
|
||||
"MinPlayersForGameStateCommand": "Minimum alive players to use this command",
|
||||
"EveryoneSeesDeathReasons": "Everyone Sees Death Reasons",
|
||||
"BlockVentMovement": "Block Movement Between Vents (while in a vent)",
|
||||
"DoorsResetMode": "Mode",
|
||||
"AllClosed": "Close All",
|
||||
"AllOpen": "Open All",
|
||||
@@ -2606,7 +2605,6 @@
|
||||
"MinerTeleButtonText": "Warp",
|
||||
"ArsonistDouseButtonText": "Douse",
|
||||
"PuppeteerOperateButtonText": "Manipulate",
|
||||
"WitchControlButtonText": "Control",
|
||||
"WarlockShapeshiftButtonText": "Spell",
|
||||
"BountyHunterChangeButtonText": "Swap",
|
||||
"EvilTrackerChangeButtonText": "Track",
|
||||
@@ -2734,6 +2732,7 @@
|
||||
"CountdownText": "<color=#00ffa5>Re-Entering Lobby in</color> <b>{0}</b>s",
|
||||
"EAC.CheatDetected.HighLevel": "Warning: EAC detected High Level of cheats.",
|
||||
"EAC.CheatDetected.LowLevel": "Warning: EAC detected Low Level of cheats. One of the players is hacking.",
|
||||
"EnableMovementChecking": "Enable EAC Checks for Invalid Movement (against speed hacks) (may cause false positives)",
|
||||
"DisableVoteBan": "Disable Vote-Kick (prevent hackers from banning everyone)",
|
||||
"PlayerIsRole": "{0} was {1}.",
|
||||
"PlayerExiled": "{0} was ejected...",
|
||||
@@ -2814,11 +2813,7 @@
|
||||
"FungleChance": "Chance that the map is The Fungle",
|
||||
"CamouflageMode.Default": "Default",
|
||||
"CamouflageMode.Host": "<color=#FFFF00>Host</color>",
|
||||
"CamouflageMode.Karpe": "KARPED1EM",
|
||||
"CamouflageMode.Lauryn": "Lauryn",
|
||||
"CamouflageMode.Moe": "Moe",
|
||||
"CamouflageMode.Pyro": "Pyro",
|
||||
"CamouflageMode.ryuk": "<color=#9e2424>ryuk</color>",
|
||||
"CamouflageMode.Karpe": "<color=#ffc0cb>KARPED1EM</color>",
|
||||
"CamouflageMode.Gurge44": "<color=#ffe600>Gurge44</color>",
|
||||
"CamouflageMode.TommyXL": "<color=#EC7578>TommyXL</color>",
|
||||
"pet_Bedcrab": "Bedcrab",
|
||||
@@ -4566,7 +4561,6 @@
|
||||
"AmnesiacInvalidTarget": "Remember failed",
|
||||
"RememberedNeutralKiller": "You remembered you were a neutral killer!",
|
||||
"RememberedMaverick": "You remembered you were a Maverick!",
|
||||
"RememberedWitch": "You remembered you were a Witch!",
|
||||
"RememberedPursuer": "You remembered you were a Pursuer!",
|
||||
"RememberedTotocalcio": "You remembered you were a Follower!",
|
||||
"RememberedAmnesiac": "You failed to remember your role.",
|
||||
@@ -5003,7 +4997,6 @@
|
||||
"AdditionalWinnerRoleText.Lawyer": "The Lawyer wins along",
|
||||
"AdditionalWinnerRoleText.FFF": "The Hater killed a recruit",
|
||||
"AdditionalWinnerRoleText.Provocateur": "The Provocateur wins along",
|
||||
"AdditionalWinnerRoleText.NWitch": "The Witch survived",
|
||||
"AdditionalWinnerRoleText.Sunnyboy": "And there's endless sunshine!",
|
||||
"AdditionalWinnerRoleText.Totocalcio": "The Follower wins along",
|
||||
"AdditionalWinnerRoleText.Pursuer": "The Pursuer survived",
|
||||
|
||||
@@ -209,7 +209,11 @@ namespace EHR.Crewmate
|
||||
public override bool OnVote(PlayerControl voter, PlayerControl target)
|
||||
{
|
||||
if (voter.PlayerId != PresidentId || !IsRecruiting || Main.DontCancelVoteList.Contains(voter.PlayerId)) return false;
|
||||
if (!target.Is(CustomRoleTypes.Crewmate) || target.IsConverted()) return true;
|
||||
if (!target.Is(CustomRoleTypes.Crewmate) || target.IsConverted())
|
||||
{
|
||||
IsRecruiting = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
CustomRoles role = GovernmentRecruitRoles[DecreeSettings[Decree.GovernmentRecruiting][1].GetValue()];
|
||||
if (role.IsDesyncRole() && target.GetRoleTypes() != role.GetDYRole()) role = CustomRoles.NiceGuesser;
|
||||
|
||||
+25
-23
@@ -7,29 +7,28 @@ namespace EHR.Crewmate;
|
||||
public class Sheriff : RoleBase
|
||||
{
|
||||
private const int Id = 8800;
|
||||
public static List<byte> playerIdList = [];
|
||||
private static List<byte> PlayerIdList = [];
|
||||
|
||||
public static OptionItem KillCooldown;
|
||||
private static OptionItem KillCooldown;
|
||||
private static OptionItem MisfireKillsTarget;
|
||||
public static OptionItem ShotLimitOpt;
|
||||
public static OptionItem ShowShotLimit;
|
||||
private static OptionItem ShotLimitOpt;
|
||||
private static OptionItem ShowShotLimit;
|
||||
private static OptionItem CanKillAllAlive;
|
||||
public static OptionItem CanKillNeutrals;
|
||||
public static OptionItem CanKillNeutralsMode;
|
||||
public static OptionItem CanKillMadmate;
|
||||
public static OptionItem CanKillCharmed;
|
||||
public static OptionItem CanKillLovers;
|
||||
public static OptionItem CanKillSidekicks;
|
||||
public static OptionItem CanKillEgoists;
|
||||
public static OptionItem CanKillContagious;
|
||||
public static OptionItem SidekickSheriffCanGoBerserk;
|
||||
public static OptionItem SetNonCrewCanKill;
|
||||
public static OptionItem NonCrewCanKillCrew;
|
||||
public static OptionItem NonCrewCanKillImp;
|
||||
public static OptionItem NonCrewCanKillNeutral;
|
||||
private static OptionItem CanKillNeutrals;
|
||||
private static OptionItem CanKillNeutralsMode;
|
||||
private static OptionItem CanKillMadmate;
|
||||
private static OptionItem CanKillCharmed;
|
||||
private static OptionItem CanKillLovers;
|
||||
private static OptionItem CanKillSidekicks;
|
||||
private static OptionItem CanKillContagious;
|
||||
private static OptionItem SidekickSheriffCanGoBerserk;
|
||||
private static OptionItem SetNonCrewCanKill;
|
||||
private static OptionItem NonCrewCanKillCrew;
|
||||
private static OptionItem NonCrewCanKillImp;
|
||||
private static OptionItem NonCrewCanKillNeutral;
|
||||
public static OptionItem KeepsGameGoing;
|
||||
public static OptionItem UsePet;
|
||||
public static Dictionary<CustomRoles, OptionItem> KillTargetOptions = [];
|
||||
private static readonly Dictionary<CustomRoles, OptionItem> KillTargetOptions = [];
|
||||
|
||||
public static readonly string[] KillOption =
|
||||
[
|
||||
@@ -37,7 +36,7 @@ public class Sheriff : RoleBase
|
||||
"SheriffCanKillSeparately"
|
||||
];
|
||||
|
||||
public override bool IsEnable => playerIdList.Count > 0;
|
||||
public override bool IsEnable => PlayerIdList.Count > 0;
|
||||
|
||||
public override void SetupCustomOption()
|
||||
{
|
||||
@@ -53,7 +52,6 @@ public class Sheriff : RoleBase
|
||||
CanKillCharmed = new BooleanOptionItem(Id + 22, "SheriffCanKillCharmed", true, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Sheriff]);
|
||||
CanKillLovers = new BooleanOptionItem(Id + 24, "SheriffCanKillLovers", true, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Sheriff]);
|
||||
CanKillSidekicks = new BooleanOptionItem(Id + 23, "SheriffCanKillSidekick", true, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Sheriff]);
|
||||
CanKillEgoists = new BooleanOptionItem(Id + 25, "SheriffCanKillEgoist", true, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Sheriff]);
|
||||
CanKillContagious = new BooleanOptionItem(Id + 27, "SheriffCanKillContagious", true, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Sheriff]);
|
||||
CanKillNeutrals = new BooleanOptionItem(Id + 16, "SheriffCanKillNeutrals", true, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Sheriff]);
|
||||
CanKillNeutralsMode = new StringOptionItem(Id + 14, "SheriffCanKillNeutralsMode", KillOption, 0, TabGroup.CrewmateRoles).SetParent(CanKillNeutrals);
|
||||
@@ -90,12 +88,12 @@ public class Sheriff : RoleBase
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
playerIdList = [];
|
||||
PlayerIdList = [];
|
||||
}
|
||||
|
||||
public override void Add(byte playerId)
|
||||
{
|
||||
playerIdList.Add(playerId);
|
||||
PlayerIdList.Add(playerId);
|
||||
playerId.SetAbilityUseLimit(ShotLimitOpt.GetInt());
|
||||
|
||||
Logger.Info($"{Utils.GetPlayerById(playerId)?.GetNameWithRole().RemoveHtmlTags()} : Shot Limit - {playerId.GetAbilityUseLimit()}", "Sheriff");
|
||||
@@ -153,7 +151,6 @@ public class Sheriff : RoleBase
|
||||
CustomRoles.Charmed => CanKillCharmed.GetBool(),
|
||||
CustomRoles.Lovers => CanKillLovers.GetBool(),
|
||||
CustomRoles.Recruit => CanKillSidekicks.GetBool(),
|
||||
CustomRoles.Egoist => CanKillEgoists.GetBool(),
|
||||
CustomRoles.Contagious => CanKillContagious.GetBool(),
|
||||
CustomRoles.Rascal => true,
|
||||
_ => false
|
||||
@@ -172,4 +169,9 @@ public class Sheriff : RoleBase
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public override string GetProgressText(byte playerId, bool comms)
|
||||
{
|
||||
return ShowShotLimit.GetBool() ? base.GetProgressText(playerId, comms) : Utils.GetTaskCount(playerId, comms);
|
||||
}
|
||||
}
|
||||
@@ -139,6 +139,13 @@ internal class Assassin : RoleBase
|
||||
public override bool OnVanish(PlayerControl pc)
|
||||
{
|
||||
if (pc == null || !pc.IsAlive() || Pelican.IsEaten(pc.PlayerId)) return false;
|
||||
|
||||
if (!IsUndertaker)
|
||||
{
|
||||
LateTask.New(() => Take(pc), 1.5f, "Ninja Vanish");
|
||||
return true;
|
||||
}
|
||||
|
||||
Take(pc);
|
||||
return false;
|
||||
}
|
||||
@@ -148,10 +155,9 @@ internal class Assassin : RoleBase
|
||||
if (MarkedPlayer != byte.MaxValue)
|
||||
{
|
||||
var target = Utils.GetPlayerById(MarkedPlayer);
|
||||
if (IsUndertaker) target.TP(pc);
|
||||
else pc.TP(target);
|
||||
var tpSuccess = IsUndertaker ? target.TP(pc) : pc.TP(target);
|
||||
|
||||
if (!(target == null || !target.IsAlive() || Pelican.IsEaten(target.PlayerId) || target.inVent || !GameStates.IsInTask) && pc.RpcCheckAndMurder(target))
|
||||
if (!(target == null || !target.IsAlive() || Pelican.IsEaten(target.PlayerId) || target.inVent || !GameStates.IsInTask) && tpSuccess && pc.RpcCheckAndMurder(target))
|
||||
{
|
||||
MarkedPlayer = byte.MaxValue;
|
||||
SendRPC(pc.PlayerId);
|
||||
@@ -159,6 +165,7 @@ internal class Assassin : RoleBase
|
||||
pc.SyncSettings();
|
||||
pc.SetKillCooldown(DefaultKillCooldown);
|
||||
}
|
||||
else if (!tpSuccess) pc.Notify(GetString("TargetCannotBeTeleported"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace EHR.Impostor
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pc.GetAbilityUseLimit() < 1)
|
||||
if (pc.GetAbilityUseLimit() < 1 && !Options.DisableShapeshiftAnimations.GetBool())
|
||||
{
|
||||
pc.SetKillCooldown(CamouflageDuration.GetFloat() + 1f);
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ public class Disperser : RoleBase
|
||||
public override bool OnShapeshift(PlayerControl shapeshifter, PlayerControl target, bool shapeshifting)
|
||||
{
|
||||
if (shapeshifter == null || (!shapeshifting && !UseUnshiftTrigger.GetBool())) return false;
|
||||
if (shapeshifter.GetAbilityUseLimit() < 1)
|
||||
if (shapeshifter.GetAbilityUseLimit() < 1 && !DisableShapeshiftAnimations.GetBool())
|
||||
{
|
||||
shapeshifter.SetKillCooldown(DisperserShapeshiftDuration.GetFloat() + 1f);
|
||||
return false;
|
||||
|
||||
@@ -15,11 +15,10 @@ public class Amnesiac : RoleBase
|
||||
private static OptionItem RememberCooldown;
|
||||
private static OptionItem CanRememberCrewPower;
|
||||
private static OptionItem IncompatibleNeutralMode;
|
||||
private static OptionItem CanVent;
|
||||
public static OptionItem RememberMode;
|
||||
public static OptionItem RoleBasis;
|
||||
|
||||
public static readonly CustomRoles[] AmnesiacIncompatibleNeutralMode =
|
||||
private static readonly CustomRoles[] AmnesiacIncompatibleNeutralMode =
|
||||
[
|
||||
CustomRoles.Amnesiac,
|
||||
CustomRoles.Pursuer,
|
||||
@@ -29,8 +28,8 @@ public class Amnesiac : RoleBase
|
||||
|
||||
private static readonly string[] RememberModes =
|
||||
[
|
||||
"AmnesiacRM.ByKillButton",
|
||||
"AmnesiacRM.ByReportingBody"
|
||||
"AmnesiacRM.ByReportingBody",
|
||||
"AmnesiacRM.ByKillButton"
|
||||
];
|
||||
|
||||
private byte AmnesiacId;
|
||||
@@ -43,14 +42,12 @@ public class Amnesiac : RoleBase
|
||||
RememberMode = new StringOptionItem(Id + 9, "RememberMode", RememberModes, 0, TabGroup.NeutralRoles)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Amnesiac]);
|
||||
RememberCooldown = new FloatOptionItem(Id + 10, "RememberCooldown", new(0f, 180f, 0.5f), 5f, TabGroup.NeutralRoles)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Amnesiac])
|
||||
.SetParent(RememberMode)
|
||||
.SetValueFormat(OptionFormat.Seconds);
|
||||
CanRememberCrewPower = new BooleanOptionItem(Id + 11, "CanRememberCrewPower", false, TabGroup.NeutralRoles)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Amnesiac]);
|
||||
IncompatibleNeutralMode = new StringOptionItem(Id + 12, "IncompatibleNeutralMode", AmnesiacIncompatibleNeutralMode.Select(x => x.ToColoredString()).ToArray(), 0, TabGroup.NeutralRoles, noTranslation: true)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Amnesiac]);
|
||||
CanVent = new BooleanOptionItem(Id + 13, "CanVent", false, TabGroup.NeutralRoles)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Amnesiac]);
|
||||
RoleBasis = new StringOptionItem(Id + 14, "AmnesiacRoleBasis", [CustomRoles.Engineer.ToColoredString(), CustomRoles.Crewmate.ToColoredString()], 1, TabGroup.NeutralRoles, noTranslation: true)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Amnesiac]);
|
||||
}
|
||||
@@ -69,7 +66,6 @@ public class Amnesiac : RoleBase
|
||||
|
||||
public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = RememberCooldown.GetFloat();
|
||||
public override bool CanUseKillButton(PlayerControl player) => !player.Data.IsDead && RememberMode.GetValue() == 0;
|
||||
public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool();
|
||||
public override void ApplyGameOptions(IGameOptions opt, byte playerId) => opt.SetVision(false);
|
||||
|
||||
public static void OnAnyoneDeath(PlayerControl target)
|
||||
|
||||
+12
-5
@@ -87,11 +87,7 @@ public class Bandit : RoleBase
|
||||
for (int i = 0; i < AllSubRoles.Count; i++)
|
||||
{
|
||||
var role = AllSubRoles[i];
|
||||
if (role == CustomRoles.Cleansed || // making Bandit unable to steal Cleansed for obvious reasons. Although it can still be cleansed by cleanser.
|
||||
role == CustomRoles.LastImpostor ||
|
||||
role == CustomRoles.Lovers || // Causes issues involving Lovers Suicide
|
||||
(role.IsImpOnlyAddon() && !CanStealImpOnlyAddon.GetBool()) ||
|
||||
(role.IsBetrayalAddon() && !CanStealBetrayalAddon.GetBool()))
|
||||
if (IsBlacklistedAddon(role))
|
||||
{
|
||||
Logger.Info($"Removed {role} from stealable addons", "Bandit");
|
||||
AllSubRoles.Remove(role);
|
||||
@@ -108,6 +104,17 @@ public class Bandit : RoleBase
|
||||
return addon;
|
||||
}
|
||||
|
||||
private static bool IsBlacklistedAddon(CustomRoles role) => (role.IsImpOnlyAddon() && !CanStealImpOnlyAddon.GetBool()) || (role.IsBetrayalAddon() && !CanStealBetrayalAddon.GetBool()) || StartGameHostPatch.BasisChangingAddons.ContainsKey(role) || role is
|
||||
CustomRoles.Egoist or
|
||||
CustomRoles.Workhorse or
|
||||
CustomRoles.Cleansed or
|
||||
CustomRoles.Busy or
|
||||
CustomRoles.Lovers or
|
||||
CustomRoles.Stressed or
|
||||
CustomRoles.Lazy or
|
||||
CustomRoles.Rascal or
|
||||
CustomRoles.LastImpostor;
|
||||
|
||||
public override bool OnCheckMurder(PlayerControl killer, PlayerControl target)
|
||||
{
|
||||
if (!On) return true;
|
||||
|
||||
@@ -288,11 +288,8 @@ public class Glitch : RoleBase
|
||||
|
||||
public override string GetSuffix(PlayerControl seer, PlayerControl target, bool hud = false, bool meeting = false)
|
||||
{
|
||||
Logger.Test("pos0");
|
||||
if (!hud || seer == null || !seer.IsAlive() || meeting) return string.Empty;
|
||||
Logger.Test("pos1");
|
||||
if (Main.PlayerStates[seer.PlayerId].Role is not Glitch gc) return string.Empty;
|
||||
Logger.Test("pos2");
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
|
||||
+11
-6
@@ -13,6 +13,7 @@ namespace EHR.Neutral
|
||||
public static OptionItem SunnyboyChance;
|
||||
public static OptionItem VentCooldown;
|
||||
public static OptionItem MaxInVentTime;
|
||||
public static OptionItem BlockVentMovement;
|
||||
public override bool IsEnable => On;
|
||||
|
||||
public override void SetupCustomOption()
|
||||
@@ -22,14 +23,16 @@ namespace EHR.Neutral
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Jester]);
|
||||
JesterCanVent = new BooleanOptionItem(10911, "CanVent", false, TabGroup.NeutralRoles)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Jester]);
|
||||
VentCooldown = new FloatOptionItem(10913, "VentCooldown", new(0f, 60f, 0.5f), 0f, TabGroup.NeutralRoles)
|
||||
.SetParent(JesterCanVent)
|
||||
.SetValueFormat(OptionFormat.Seconds);
|
||||
MaxInVentTime = new FloatOptionItem(10914, "MaxInVentTime", new(0f, 60f, 0.5f), 30f, TabGroup.NeutralRoles)
|
||||
.SetParent(JesterCanVent)
|
||||
.SetValueFormat(OptionFormat.Seconds);
|
||||
BlockVentMovement = new BooleanOptionItem(10916, "BlockVentMovement", false, TabGroup.NeutralRoles)
|
||||
.SetParent(JesterCanVent);
|
||||
JesterHasImpostorVision = new BooleanOptionItem(10912, "ImpostorVision", false, TabGroup.NeutralRoles)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Jester]);
|
||||
VentCooldown = new FloatOptionItem(10913, "VentCooldown", new(0f, 60f, 0.5f), 0f, TabGroup.NeutralRoles)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Jester])
|
||||
.SetValueFormat(OptionFormat.Seconds);
|
||||
MaxInVentTime = new FloatOptionItem(10914, "MaxInVentTime", new(0f, 900f, 0.5f), 900f, TabGroup.NeutralRoles)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Jester])
|
||||
.SetValueFormat(OptionFormat.Seconds);
|
||||
SunnyboyChance = new IntegerOptionItem(10915, "SunnyboyChance", new(0, 100, 5), 0, TabGroup.NeutralRoles)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Jester])
|
||||
.SetValueFormat(OptionFormat.Percent);
|
||||
@@ -51,5 +54,7 @@ namespace EHR.Neutral
|
||||
AURoleOptions.EngineerInVentMaxTime = MaxInVentTime.GetFloat();
|
||||
opt.SetVision(JesterHasImpostorVision.GetBool());
|
||||
}
|
||||
|
||||
public override bool CanUseVent(PlayerControl pc, int ventId) => !BlockVentMovement.GetBool() || pc.GetClosestVent()?.Id == ventId;
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ namespace EHR.Neutral
|
||||
public class Virus : RoleBase
|
||||
{
|
||||
private const int Id = 13200;
|
||||
private static List<byte> playerIdList = [];
|
||||
public static List<byte> playerIdList = [];
|
||||
public static List<byte> InfectedPlayer = [];
|
||||
public static Dictionary<byte, string> VirusNotify = [];
|
||||
public static List<byte> InfectedBodies = [];
|
||||
|
||||
+6
-1
@@ -53,7 +53,12 @@ namespace EHR
|
||||
|
||||
public virtual bool CanUseImpostorVentButton(PlayerControl pc)
|
||||
{
|
||||
return pc.IsAlive() && (pc.Is(CustomRoleTypes.Impostor) || Amnesiac.WasAmnesiac.Contains(pc.PlayerId) || (pc.Is(CustomRoles.Bloodlust) && Bloodlust.CanVent.GetBool())) && Circumvent.CanUseImpostorVentButton(pc) && pc.Data.Role.Role is not RoleTypes.Engineer;
|
||||
return pc.IsAlive() && (pc.Is(CustomRoleTypes.Impostor) || Amnesiac.WasAmnesiac.Contains(pc.PlayerId) || (pc.Is(CustomRoles.Bloodlust) && Bloodlust.CanVent.GetBool())) && Circumvent.CanUseImpostorVentButton(pc);
|
||||
}
|
||||
|
||||
public virtual bool CanUseVent(PlayerControl pc, int ventId)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool CanUseSabotage(PlayerControl pc)
|
||||
|
||||
Reference in new issue
Block a user