I can't even count how many things I just fixed
No files matched your search
@@ -88,8 +88,6 @@ namespace EHR
|
||||
.Where(x => x.Interface.Team == Team.Impostor)
|
||||
.Do(x => x.pc.MarkDirtySettings());
|
||||
}, Seeker.BlindTime.GetFloat() + 8f, "Blind Time Expire");
|
||||
|
||||
AssignRoles();
|
||||
}
|
||||
|
||||
public static List<CustomRoles> GetAllHnsRoles(IEnumerable<Type> types)
|
||||
@@ -109,7 +107,7 @@ namespace EHR
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private static void AssignRoles()
|
||||
public static void AssignRoles()
|
||||
{
|
||||
Dictionary<PlayerControl, CustomRoles> result = [];
|
||||
List<PlayerControl> allPlayers = [.. Main.AllAlivePlayerControls];
|
||||
@@ -199,6 +197,8 @@ namespace EHR
|
||||
.Where(x => x != null)
|
||||
.ToDictionary(x => x.GetType().Name, x => x);
|
||||
PlayerRoles = result.ToDictionary(x => x.Key.PlayerId, x => (roleInterfaces[x.Value.ToString()], x.Value));
|
||||
|
||||
result.IntersectBy(Main.PlayerStates.Keys, x => x.Key.PlayerId).Do(x => x.Key.RpcSetCustomRole(x.Value));
|
||||
}
|
||||
|
||||
public static void ApplyGameOptions(IGameOptions opt, PlayerControl pc)
|
||||
@@ -343,11 +343,18 @@ namespace EHR
|
||||
name = Utils.ColorString(Main.PlayerColors.GetValueOrDefault(state.Key, Color.white), name);
|
||||
bool isSeeker = PlayerRoles[state.Key].Interface.Team == Team.Impostor;
|
||||
bool alive = !state.Value.IsDead;
|
||||
string stateText;
|
||||
if (isSeeker) stateText = $" ({Utils.ColorString(Utils.GetRoleColor(CustomRoles.Seeker), Translator.GetString("Seeker"))})";
|
||||
else stateText = alive ? string.Empty : " <#ff1313>DEAD</color>";
|
||||
|
||||
TaskState ts = state.Value.TaskState;
|
||||
string stateText = string.Empty;
|
||||
if (PlayersSeeRoles.GetBool()) stateText = $" ({GetRole()}){GetTaskCount()}";
|
||||
else if (isSeeker) stateText = $" ({CustomRoles.Seeker.ToString()})";
|
||||
if (!alive) stateText += $" <color=#ff0000>{Translator.GetString("Dead")}</color>";
|
||||
|
||||
stateText = $"{name}{stateText}";
|
||||
return stateText;
|
||||
|
||||
CustomRoles GetRole() => state.Value.MainRole == CustomRoles.Agent ? CustomRoles.Hider : state.Value.MainRole;
|
||||
string GetTaskCount() => CustomRoles.Agent.IsEnable() || !ts.hasTasks ? string.Empty : $" ({ts.CompletedTasksCount}/{ts.AllTasksCount})";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -375,7 +382,7 @@ namespace EHR
|
||||
{
|
||||
public static void Postfix(PlayerControl __instance)
|
||||
{
|
||||
if (!AmongUsClient.Instance.AmHost || Options.CurrentGameMode != CustomGameMode.HideAndSeek) return;
|
||||
if (!AmongUsClient.Instance.AmHost || !GameStates.IsInTask || Options.CurrentGameMode != CustomGameMode.HideAndSeek) return;
|
||||
|
||||
long now = Utils.TimeStamp;
|
||||
if (LastUpdate == now) return;
|
||||
|
||||
@@ -9,6 +9,9 @@ namespace EHR;
|
||||
|
||||
public static class AntiBlackout
|
||||
{
|
||||
private static Dictionary<byte, (bool isDead, bool Disconnected)> IsDeadCache = [];
|
||||
private static readonly LogHandler Logger = EHR.Logger.Handler("AntiBlackout");
|
||||
|
||||
///<summary>
|
||||
///Whether to override the ejection process
|
||||
///</summary>
|
||||
@@ -44,9 +47,7 @@ public static class AntiBlackout
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsCached { get; private set; }
|
||||
private static Dictionary<byte, (bool isDead, bool Disconnected)> isDeadCache = [];
|
||||
private static readonly LogHandler Logger = EHR.Logger.Handler("AntiBlackout");
|
||||
private static bool IsCached { get; set; }
|
||||
|
||||
public static void SetIsDead(bool doSend = true, [CallerMemberName] string callerMethodName = "")
|
||||
{
|
||||
@@ -57,11 +58,11 @@ public static class AntiBlackout
|
||||
return;
|
||||
}
|
||||
|
||||
isDeadCache.Clear();
|
||||
IsDeadCache.Clear();
|
||||
foreach (var info in GameData.Instance.AllPlayers)
|
||||
{
|
||||
if (info == null) continue;
|
||||
isDeadCache[info.PlayerId] = (info.IsDead, info.Disconnected);
|
||||
IsDeadCache[info.PlayerId] = (info.IsDead, info.Disconnected);
|
||||
info.IsDead = false;
|
||||
info.Disconnected = false;
|
||||
}
|
||||
@@ -76,14 +77,14 @@ public static class AntiBlackout
|
||||
foreach (var info in GameData.Instance.AllPlayers)
|
||||
{
|
||||
if (info == null) continue;
|
||||
if (isDeadCache.TryGetValue(info.PlayerId, out var val))
|
||||
if (IsDeadCache.TryGetValue(info.PlayerId, out var val))
|
||||
{
|
||||
info.IsDead = val.isDead;
|
||||
info.Disconnected = val.Disconnected;
|
||||
}
|
||||
}
|
||||
|
||||
isDeadCache.Clear();
|
||||
IsDeadCache.Clear();
|
||||
IsCached = false;
|
||||
if (doSend) SendGameData();
|
||||
}
|
||||
@@ -113,7 +114,7 @@ public static class AntiBlackout
|
||||
{
|
||||
// Execution conditions: client is host, IsDead is overwritten, player is disconnected
|
||||
if (!AmongUsClient.Instance.AmHost || !IsCached || !player.Disconnected) return;
|
||||
isDeadCache[player.PlayerId] = (true, true);
|
||||
IsDeadCache[player.PlayerId] = (true, true);
|
||||
player.IsDead = player.Disconnected = false;
|
||||
SendGameData();
|
||||
}
|
||||
@@ -149,8 +150,8 @@ public static class AntiBlackout
|
||||
public static void Reset()
|
||||
{
|
||||
Logger.Info("==Reset==");
|
||||
isDeadCache ??= [];
|
||||
isDeadCache.Clear();
|
||||
IsDeadCache ??= [];
|
||||
IsDeadCache.Clear();
|
||||
IsCached = false;
|
||||
}
|
||||
}
|
||||
@@ -78,6 +78,7 @@ internal static class CustomRoleSelector
|
||||
AssignRoleToEveryone(CustomRoles.Potato);
|
||||
return;
|
||||
case CustomGameMode.HideAndSeek:
|
||||
CustomHideAndSeekManager.AssignRoles();
|
||||
RoleResult = CustomHideAndSeekManager.PlayerRoles.ToDictionary(x => Utils.GetPlayerById(x.Key), x => x.Value.Role);
|
||||
return;
|
||||
}
|
||||
@@ -611,7 +612,7 @@ internal static class CustomRoleSelector
|
||||
|
||||
public static void SelectAddonRoles()
|
||||
{
|
||||
if (Options.CurrentGameMode is CustomGameMode.SoloKombat or CustomGameMode.FFA or CustomGameMode.MoveAndStop) return;
|
||||
if (Options.CurrentGameMode is CustomGameMode.SoloKombat or CustomGameMode.FFA or CustomGameMode.MoveAndStop or CustomGameMode.HideAndSeek) return;
|
||||
|
||||
foreach (var id in Main.SetAddOns.Keys.Where(id => Utils.GetPlayerById(id) == null).ToArray()) Main.SetAddOns.Remove(id);
|
||||
|
||||
@@ -640,25 +641,13 @@ internal static class CustomRoleSelector
|
||||
Crewmate
|
||||
}
|
||||
|
||||
public class RoleAssignInfo(CustomRoles role, int spawnChance, int maxCount, int assignedCount = 0)
|
||||
private class RoleAssignInfo(CustomRoles role, int spawnChance, int maxCount, int assignedCount = 0)
|
||||
{
|
||||
public CustomRoles Role
|
||||
{
|
||||
get => role;
|
||||
set => role = value;
|
||||
}
|
||||
public CustomRoles Role => role;
|
||||
|
||||
public int SpawnChance
|
||||
{
|
||||
get => spawnChance;
|
||||
set => spawnChance = value;
|
||||
}
|
||||
public int SpawnChance => spawnChance;
|
||||
|
||||
public int MaxCount
|
||||
{
|
||||
get => maxCount;
|
||||
set => maxCount = value;
|
||||
}
|
||||
public int MaxCount => maxCount;
|
||||
|
||||
public int AssignedCount
|
||||
{
|
||||
|
||||
@@ -82,7 +82,7 @@ internal static class CustomRolesHelper
|
||||
CustomRoles.Lawyer => CustomRoles.Crewmate,
|
||||
CustomRoles.NiceSwapper => CustomRoles.Crewmate,
|
||||
CustomRoles.Ignitor => CustomRoles.Crewmate,
|
||||
CustomRoles.Jailor => CustomRoles.Impostor,
|
||||
CustomRoles.Jailor => UsePets && Jailor.UsePet.GetBool() ? CustomRoles.Crewmate : CustomRoles.Impostor,
|
||||
CustomRoles.Vampire => CustomRoles.Impostor,
|
||||
CustomRoles.BountyHunter => CustomRoles.Impostor,
|
||||
CustomRoles.Trickster => CustomRoles.Impostor,
|
||||
@@ -258,9 +258,20 @@ internal static class CustomRolesHelper
|
||||
CustomRoles.Silencer => Silencer.SilenceMode.GetValue() == 1 ? CustomRoles.Shapeshifter : CustomRoles.Impostor,
|
||||
|
||||
// Hide And Seek
|
||||
CustomRoles.Hider => CustomRoles.Crewmate,
|
||||
CustomRoles.Seeker => CustomRoles.Impostor,
|
||||
CustomRoles.Fox => CustomRoles.Crewmate,
|
||||
CustomRoles.Troll => CustomRoles.Crewmate,
|
||||
CustomRoles.Jumper => CustomRoles.Engineer,
|
||||
CustomRoles.Detector => CustomRoles.Crewmate,
|
||||
CustomRoles.Jet => CustomRoles.Crewmate,
|
||||
CustomRoles.Dasher => CustomRoles.Impostor,
|
||||
CustomRoles.Locator => CustomRoles.Impostor,
|
||||
CustomRoles.Venter => CustomRoles.Impostor,
|
||||
CustomRoles.Agent => CustomRoles.Impostor,
|
||||
CustomRoles.Taskinator => CustomRoles.Crewmate,
|
||||
|
||||
_ => role.IsImpostor() ? CustomRoles.Impostor : CustomRoles.Crewmate,
|
||||
_ => role.IsImpostor() ? CustomRoles.Impostor : CustomRoles.Crewmate
|
||||
};
|
||||
}
|
||||
|
||||
@@ -294,18 +305,6 @@ internal static class CustomRolesHelper
|
||||
CustomRoles.Tasker => RoleTypes.Crewmate,
|
||||
// Hot Potato
|
||||
CustomRoles.Potato => RoleTypes.Crewmate,
|
||||
// Hide And Seek
|
||||
CustomRoles.Hider => RoleTypes.Crewmate,
|
||||
CustomRoles.Seeker => RoleTypes.Impostor,
|
||||
CustomRoles.Fox => RoleTypes.Crewmate,
|
||||
CustomRoles.Troll => RoleTypes.Crewmate,
|
||||
CustomRoles.Detector => RoleTypes.Crewmate,
|
||||
CustomRoles.Jet => RoleTypes.Crewmate,
|
||||
CustomRoles.Dasher => RoleTypes.Impostor,
|
||||
CustomRoles.Locator => RoleTypes.Impostor,
|
||||
CustomRoles.Venter => RoleTypes.Impostor,
|
||||
CustomRoles.Agent => RoleTypes.Impostor,
|
||||
CustomRoles.Taskinator => RoleTypes.Crewmate,
|
||||
// Standard
|
||||
CustomRoles.Executioner => Executioner.CRoleChangeRoles[Executioner.ChangeRolesAfterTargetKilled.GetValue()].GetDYRole(),
|
||||
CustomRoles.Sheriff => UsePets && Sheriff.UsePet.GetBool() ? RoleTypes.GuardianAngel : RoleTypes.Impostor,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using AmongUs.GameOptions;
|
||||
@@ -10,11 +9,11 @@ using static EHR.Translator;
|
||||
|
||||
namespace EHR;
|
||||
|
||||
internal class EAC
|
||||
internal static class EAC
|
||||
{
|
||||
public static int DeNum;
|
||||
|
||||
public static void WarnHost(int denum = 1)
|
||||
private static void WarnHost(int denum = 1)
|
||||
{
|
||||
DeNum += denum;
|
||||
if (ErrorText.Instance != null)
|
||||
@@ -120,9 +119,7 @@ internal class EAC
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pc.Data.DefaultOutfit.ColorId != -1 &&
|
||||
(Main.AllPlayerControls.Count(x => x.Data.DefaultOutfit.ColorId == color) >= 5
|
||||
|| color < 0 || color > 18))
|
||||
if (pc.Data.DefaultOutfit.ColorId != -1 && (Main.AllPlayerControls.Count(x => x.Data.DefaultOutfit.ColorId == color) >= 5 || color > 18))
|
||||
{
|
||||
WarnHost();
|
||||
Report(pc, "Illegal color setting");
|
||||
@@ -180,12 +177,56 @@ internal class EAC
|
||||
|
||||
switch (callId)
|
||||
{
|
||||
case 101:
|
||||
var AUMChat = sr.ReadString();
|
||||
WarnHost();
|
||||
Report(pc, "AUM");
|
||||
HandleCheat(pc, GetString("EAC.CheatDetected.EAC"));
|
||||
return true;
|
||||
case 101: // Aum Chat
|
||||
try
|
||||
{
|
||||
var firstString = reader.ReadString();
|
||||
var secondString = reader.ReadString();
|
||||
reader.ReadInt32();
|
||||
|
||||
var flag = string.IsNullOrEmpty(firstString) && string.IsNullOrEmpty(secondString);
|
||||
|
||||
if (!flag)
|
||||
{
|
||||
Report(pc, "Aum Chat RPC");
|
||||
HandleCheat(pc, "Aum Chat RPC");
|
||||
Logger.Fatal($"Player [{pc.GetClientId()}:{pc.GetRealName()}] sent an AUM chat, which was rejected", "EAC");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
break;
|
||||
case unchecked((byte)42069): // 85 AUM
|
||||
try
|
||||
{
|
||||
var aumid = reader.ReadByte();
|
||||
|
||||
if (aumid == pc.PlayerId)
|
||||
{
|
||||
Report(pc, "Aum RPC");
|
||||
HandleCheat(pc, "Aum RPC");
|
||||
Logger.Fatal($"Player [{pc.GetClientId()}:{pc.GetRealName()}] sent AUM RPC, which was rejected", "EAC");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
break;
|
||||
case unchecked((byte)420): // 164 Sicko
|
||||
if (reader.BytesRemaining == 0)
|
||||
{
|
||||
Report(pc, "Sicko RPC");
|
||||
HandleCheat(pc, "Sicko RPC");
|
||||
Logger.Fatal($"Player [{pc.GetClientId()}:{pc.GetRealName()}] sent Sicko RPC, which was rejected", "EAC");
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
case 7:
|
||||
case 8:
|
||||
if (!GameStates.IsLobby)
|
||||
@@ -198,7 +239,7 @@ internal class EAC
|
||||
|
||||
break;
|
||||
case 5:
|
||||
string name = sr.ReadString();
|
||||
sr.ReadString();
|
||||
if (GameStates.IsInGame)
|
||||
{
|
||||
WarnHost();
|
||||
@@ -282,32 +323,14 @@ internal class EAC
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Dictionary<byte, CustomRoles> OriginalRoles = [];
|
||||
|
||||
public static void LogAllRoles()
|
||||
{
|
||||
foreach (var pc in Main.AllPlayerControls.ToArray())
|
||||
{
|
||||
try
|
||||
{
|
||||
OriginalRoles.Add(pc.PlayerId, pc.GetCustomRole());
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
Logger.Fatal(error.ToString(), "EAC.LogAllRoles");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool RpcUpdateSystemCheck(PlayerControl player, SystemTypes systemType, byte amount)
|
||||
{
|
||||
//Update system rpc can not get received by playercontrol.handlerpc
|
||||
var Mapid = Main.NormalOptions.MapId;
|
||||
Logger.Info("Check sabotage RPC" + ", PlayerName: " + player.GetNameWithRole() + ", SabotageType: " + systemType + ", amount: " + amount, "EAC");
|
||||
// UpdateSystem RPC cannot be received by PlayerControl.HandleRpc
|
||||
if (!AmongUsClient.Instance.AmHost) return false;
|
||||
switch (systemType) //Normal sabotage using buttons
|
||||
var Mapid = Main.NormalOptions.MapId;
|
||||
switch (systemType)
|
||||
{
|
||||
case SystemTypes.Sabotage:
|
||||
case SystemTypes.Sabotage: // Normal sabotage using buttons
|
||||
if (!player.HasKillButton() && !player.CanUseSabotage())
|
||||
{
|
||||
WarnHost();
|
||||
@@ -342,7 +365,7 @@ internal class EAC
|
||||
break;
|
||||
case SystemTypes.Electrical:
|
||||
if (Mapid == 5) goto YesCheat;
|
||||
if (amount >= 5) //0 - 4 normal lights. other sabotage, Should never be sent by client
|
||||
if (amount >= 5) // 0 - 4 normal lights. Other sabotage should never be sent by client
|
||||
{
|
||||
goto YesCheat;
|
||||
}
|
||||
@@ -350,21 +373,22 @@ internal class EAC
|
||||
break;
|
||||
case SystemTypes.Laboratory:
|
||||
if (Mapid != 2) goto YesCheat;
|
||||
if (!(amount is 64 or 65 or 32 or 33)) goto YesCheat;
|
||||
if (amount is not (64 or 65 or 32 or 33)) goto YesCheat;
|
||||
break;
|
||||
case SystemTypes.Reactor:
|
||||
if (Mapid is 2 or 4) goto YesCheat;
|
||||
if (!(amount is 64 or 65 or 32 or 33)) goto YesCheat;
|
||||
//Airship use heli sabotage /Other use 64,65 | 32,33
|
||||
if (amount is not (64 or 65 or 32 or 33)) goto YesCheat;
|
||||
// Airship uses heli sabotage / Other maps use 64,65 | 32,33
|
||||
break;
|
||||
case SystemTypes.HeliSabotage:
|
||||
if (Mapid != 4) goto YesCheat;
|
||||
if (!(amount is 64 or 65 or 16 or 17 or 32 or 33)) goto YesCheat;
|
||||
if (amount is not (64 or 65 or 16 or 17 or 32 or 33)) goto YesCheat;
|
||||
break;
|
||||
case SystemTypes.MushroomMixupSabotage:
|
||||
goto YesCheat;
|
||||
}
|
||||
|
||||
// There may be cases where a player is fixing reactor and a meeting starts, triggering EAC check in a meeting
|
||||
if ((GameStates.IsMeeting && MeetingHud.Instance.state != MeetingHud.VoteStates.Animating) || ExileController.Instance != null)
|
||||
{
|
||||
WarnHost();
|
||||
@@ -372,7 +396,6 @@ internal class EAC
|
||||
Logger.Fatal($"Player【{player.GetClientId()}:{player.GetRealName()}】Bad Sabotage D, rejected", "EAC");
|
||||
return true;
|
||||
}
|
||||
//There may be cases where a player is fixing reactor and a meeting start, triggering EAC check in meeting
|
||||
|
||||
return false;
|
||||
|
||||
@@ -386,12 +409,12 @@ internal class EAC
|
||||
}
|
||||
}
|
||||
|
||||
public static void Report(PlayerControl pc, string reason)
|
||||
private static void Report(PlayerControl pc, string reason)
|
||||
{
|
||||
string msg = $"{pc.GetClientId()}|{pc.FriendCode}|{pc.Data.PlayerName}|{pc.GetClient().GetHashedPuid()}|{reason}";
|
||||
//Cloud.SendData(msg);
|
||||
Logger.Fatal($"EAC report: {msg}", "EAC Cloud");
|
||||
if (Options.CheatResponses.GetInt() != 5) Logger.SendInGame(string.Format(GetString("Message.NoticeByEAC"), $"{pc?.Data?.PlayerName} | {pc.GetClient().GetHashedPuid()}", reason));
|
||||
if (Options.CheatResponses.GetInt() != 5) Logger.SendInGame(string.Format(GetString("Message.NoticeByEAC"), $"{pc.Data?.PlayerName} | {pc.GetClient().GetHashedPuid()}", reason));
|
||||
}
|
||||
|
||||
public static bool ReceiveInvalidRpc(PlayerControl pc, byte callId)
|
||||
@@ -407,7 +430,7 @@ internal class EAC
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void HandleCheat(PlayerControl pc, string text)
|
||||
private static void HandleCheat(PlayerControl pc, string text)
|
||||
{
|
||||
switch (Options.CheatResponses.GetInt())
|
||||
{
|
||||
@@ -427,8 +450,16 @@ internal class EAC
|
||||
Utils.SendMessage(string.Format(GetString("Message.NoticeByEAC"), pc?.Data?.PlayerName, text), PlayerControl.LocalPlayer.PlayerId, Utils.ColorString(Utils.GetRoleColor(CustomRoles.Impostor), GetString("MessageFromEAC")));
|
||||
break;
|
||||
case 3:
|
||||
foreach (var apc in Main.AllPlayerControls.Where(x => x.PlayerId != pc?.Data?.PlayerId).ToArray())
|
||||
Utils.SendMessage(string.Format(GetString("Message.NoticeByEAC"), pc?.Data?.PlayerName, text), pc.PlayerId, Utils.ColorString(Utils.GetRoleColor(CustomRoles.Impostor), GetString("MessageFromEAC")));
|
||||
foreach (var player in Main.AllPlayerControls)
|
||||
{
|
||||
if (player.PlayerId != pc?.Data?.PlayerId)
|
||||
{
|
||||
var message = string.Format(GetString("Message.NoticeByEAC"), pc?.Data?.PlayerName, text);
|
||||
var title = Utils.ColorString(Utils.GetRoleColor(CustomRoles.Impostor), GetString("MessageFromEAC"));
|
||||
Utils.SendMessage(message, player.PlayerId, title);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case 4:
|
||||
if (!BanManager.TempBanWhiteList.Contains(pc.GetClient().GetHashedPuid()))
|
||||
|
||||
@@ -606,6 +606,10 @@ static class ExtendedPlayerControl
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsRoleBlocked(this PlayerControl pc) => RoleBlockManager.RoleBlockedPlayers.ContainsKey(pc.PlayerId);
|
||||
public static bool IsPlayerRoleBlocked(this byte id) => RoleBlockManager.RoleBlockedPlayers.ContainsKey(id);
|
||||
public static void BlockRole(this PlayerControl pc, float duration) => RoleBlockManager.AddRoleBlock(pc, duration);
|
||||
|
||||
public static bool HasKillButton(this PlayerControl pc)
|
||||
{
|
||||
CustomRoles role = pc.GetCustomRole();
|
||||
|
||||
@@ -1,28 +1,17 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using EHR.Modules;
|
||||
using Hazel;
|
||||
using UnityEngine;
|
||||
|
||||
namespace EHR;
|
||||
|
||||
static class LocateArrow
|
||||
{
|
||||
class ArrowInfo(byte from, Vector3 to)
|
||||
{
|
||||
public byte From = from;
|
||||
public Vector3 To = to;
|
||||
|
||||
public bool Equals(ArrowInfo obj)
|
||||
{
|
||||
return From == obj.From && To == obj.To;
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
return $"(From:{From} To:{To})";
|
||||
}
|
||||
}
|
||||
|
||||
static readonly Dictionary<ArrowInfo, string> LocateArrows = [];
|
||||
static readonly string[] Arrows = [
|
||||
|
||||
static readonly string[] Arrows =
|
||||
[
|
||||
"↑",
|
||||
"↗",
|
||||
"→",
|
||||
@@ -38,23 +27,43 @@ static class LocateArrow
|
||||
{
|
||||
LocateArrows.Clear();
|
||||
}
|
||||
|
||||
public static void ReceiveRPC(MessageReader reader)
|
||||
{
|
||||
switch (reader.ReadPackedInt32())
|
||||
{
|
||||
case 1:
|
||||
Add(reader.ReadByte(), Utils.ReadVector3(reader));
|
||||
break;
|
||||
case 2:
|
||||
Remove(reader.ReadByte(), Utils.ReadVector3(reader));
|
||||
break;
|
||||
case 3:
|
||||
RemoveAllTarget(reader.ReadByte());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register a new target arrow object
|
||||
/// </summary>
|
||||
/// <param name="seer"></param>
|
||||
/// <param name="target"></param>
|
||||
/// <param name="coloredArrow"></param>
|
||||
/// <param name="locate"></param>
|
||||
public static void Add(byte seer, Vector3 locate)
|
||||
{
|
||||
var arrowInfo = new ArrowInfo(seer, locate);
|
||||
if (!LocateArrows.Any(a => a.Key.Equals(arrowInfo)))
|
||||
{
|
||||
LocateArrows[arrowInfo] = "・";
|
||||
Utils.SendRPC(CustomRPC.Arrow, false, 1, seer, locate);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete target
|
||||
/// </summary>
|
||||
/// <param name="seer"></param>
|
||||
/// <param name="target"></param>
|
||||
/// <param name="locate"></param>
|
||||
public static void Remove(byte seer, Vector3 locate)
|
||||
{
|
||||
var arrowInfo = new ArrowInfo(seer, locate);
|
||||
@@ -63,7 +72,10 @@ static class LocateArrow
|
||||
{
|
||||
LocateArrows.Remove(a);
|
||||
}
|
||||
|
||||
Utils.SendRPC(CustomRPC.Arrow, false, 2, seer, locate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete all targets for the specified seer
|
||||
/// </summary>
|
||||
@@ -75,7 +87,10 @@ static class LocateArrow
|
||||
{
|
||||
LocateArrows.Remove(arrowInfo);
|
||||
}
|
||||
|
||||
Utils.SendRPC(CustomRPC.Arrow, false, 3, seer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get all visible target arrows
|
||||
/// </summary>
|
||||
@@ -85,6 +100,7 @@ static class LocateArrow
|
||||
{
|
||||
return LocateArrows.Keys.Where(ai => ai.From == seer.PlayerId).Aggregate(string.Empty, (current, arrowInfo) => current + LocateArrows[arrowInfo]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check target arrow every FixedUpdate
|
||||
/// Issue NotifyRoles when there are updates
|
||||
@@ -110,6 +126,7 @@ static class LocateArrow
|
||||
update = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Take the direction vector of the target
|
||||
var dir = loc - seer.transform.position;
|
||||
int index;
|
||||
@@ -127,6 +144,7 @@ static class LocateArrow
|
||||
var angle = Vector3.SignedAngle(Vector3.down, dir, Vector3.back) + 180 + 22.5;
|
||||
index = ((int)(angle / 45)) % 8;
|
||||
}
|
||||
|
||||
var arrow = Arrows[index];
|
||||
if (LocateArrows[arrowInfo] != arrow)
|
||||
{
|
||||
@@ -134,9 +152,26 @@ static class LocateArrow
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (update)
|
||||
{
|
||||
Utils.NotifyRoles(SpecifySeer: seer, ForceLoop: false, SpecifyTarget: seer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ArrowInfo(byte from, Vector3 to)
|
||||
{
|
||||
public byte From = from;
|
||||
public Vector3 To = to;
|
||||
|
||||
public bool Equals(ArrowInfo obj)
|
||||
{
|
||||
return From == obj.From && To == obj.To;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"(From:{From} To:{To})";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -132,9 +132,7 @@ public static class NameColorManager
|
||||
CustomRoles.HeadHunter when ((HeadHunter)Main.PlayerStates[seer.PlayerId].Role).Targets.Contains(target.PlayerId) => "000000",
|
||||
CustomRoles.BountyHunter when (Main.PlayerStates[seer.PlayerId].Role as BountyHunter)?.GetTarget(seer) == target.PlayerId => "000000",
|
||||
CustomRoles.Pyromaniac when ((Pyromaniac)Main.PlayerStates[seer.PlayerId].Role).DousedList.Contains(target.PlayerId) => "#BA4A00",
|
||||
CustomRoles.Glitch when Glitch.hackedIdList.ContainsKey(target.PlayerId) => Main.RoleColors[CustomRoles.Glitch],
|
||||
CustomRoles.Escort when Glitch.hackedIdList.ContainsKey(target.PlayerId) => Main.RoleColors[CustomRoles.Escort],
|
||||
CustomRoles.Consort when Glitch.hackedIdList.ContainsKey(target.PlayerId) => Main.RoleColors[CustomRoles.Glitch],
|
||||
CustomRoles.Glitch when target.IsRoleBlocked() => Main.RoleColors[seerRole],
|
||||
CustomRoles.Aid when Aid.ShieldedPlayers.ContainsKey(target.PlayerId) => Main.RoleColors[CustomRoles.Aid],
|
||||
CustomRoles.Spy when Spy.SpyRedNameList.ContainsKey(target.PlayerId) => "#BA4A00",
|
||||
CustomRoles.Mastermind when Mastermind.ManipulateDelays.ContainsKey(target.PlayerId) => "#00ffa5",
|
||||
|
||||
@@ -51,6 +51,7 @@ public enum CustomRPC
|
||||
KillFlash,
|
||||
SyncAbilityUseLimit,
|
||||
RemoveSubRole,
|
||||
Arrow,
|
||||
|
||||
// Roles
|
||||
SetDrawPlayer,
|
||||
@@ -97,8 +98,6 @@ public enum CustomRPC
|
||||
SetMarkedPlayer,
|
||||
SetMedicalerProtectList,
|
||||
SyncPsychicRedList,
|
||||
SetMorticianArrow,
|
||||
SetTracefinderArrow,
|
||||
SetCleanserCleanLimit,
|
||||
SetJailorTarget,
|
||||
SetDoppelgangerStealLimit,
|
||||
@@ -118,8 +117,6 @@ public enum CustomRPC
|
||||
SyncVengefulRomanticTarget,
|
||||
SetRevealedPlayer,
|
||||
SetCurrentRevealTarget,
|
||||
SetBloodhoundArrow,
|
||||
SetVultureArrow,
|
||||
SetDoomsayerProgress,
|
||||
SetTrackerTarget,
|
||||
RpcPassBomb,
|
||||
@@ -340,6 +337,10 @@ internal class RPCHandlerPatch
|
||||
case CustomRPC.RemoveSubRole:
|
||||
Main.PlayerStates[reader.ReadByte()].RemoveSubRole((CustomRoles)reader.ReadPackedInt32());
|
||||
break;
|
||||
case CustomRPC.Arrow:
|
||||
if (reader.ReadBoolean()) TargetArrow.ReceiveRPC(reader);
|
||||
else LocateArrow.ReceiveRPC(reader);
|
||||
break;
|
||||
case CustomRPC.SyncPostman:
|
||||
{
|
||||
byte id = reader.ReadByte();
|
||||
@@ -613,12 +614,6 @@ internal class RPCHandlerPatch
|
||||
(Main.PlayerStates[id].Role as Mafioso)?.ReceiveRPCSyncPistolCD(reader);
|
||||
}
|
||||
break;
|
||||
case CustomRPC.SetMorticianArrow:
|
||||
Mortician.ReceiveRPC(reader);
|
||||
break;
|
||||
case CustomRPC.SetTracefinderArrow:
|
||||
Tracefinder.ReceiveRPC(reader);
|
||||
break;
|
||||
case CustomRPC.SyncNameNotify:
|
||||
NameNotifyManager.ReceiveRPC(reader);
|
||||
break;
|
||||
@@ -634,9 +629,6 @@ internal class RPCHandlerPatch
|
||||
case CustomRPC.MafiaRevenge:
|
||||
Mafia.ReceiveRPC(reader, __instance);
|
||||
break;
|
||||
//case CustomRPC.RetributionistRevenge:
|
||||
// RetributionistRevengeManager.ReceiveRPC(reader, __instance);
|
||||
// break;
|
||||
case CustomRPC.SetSwooperTimer:
|
||||
{
|
||||
byte id = reader.ReadByte();
|
||||
@@ -687,15 +679,6 @@ internal class RPCHandlerPatch
|
||||
Utils.FlashColor(new(1f, 0f, 0f, 0.3f));
|
||||
if (Constants.ShouldPlaySfx()) RPC.PlaySound(PlayerControl.LocalPlayer.PlayerId, Sounds.KillSound);
|
||||
break;
|
||||
case CustomRPC.SetBloodhoundArrow:
|
||||
Bloodhound.ReceiveRPC(reader);
|
||||
break;
|
||||
case CustomRPC.SetVultureArrow:
|
||||
Vulture.ReceiveRPC(reader);
|
||||
break;
|
||||
//case CustomRPC.DoPoison:
|
||||
// Baker.ReceiveRPC(reader);
|
||||
// break;
|
||||
case CustomRPC.SetCleanserCleanLimit:
|
||||
Cleanser.ReceiveRPC(reader);
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace EHR.Modules
|
||||
{
|
||||
public static class RoleBlockManager
|
||||
{
|
||||
public static Dictionary<byte, (long StartTimeStamp, float Duration)> RoleBlockedPlayers = [];
|
||||
|
||||
public static void Reset() => RoleBlockedPlayers = [];
|
||||
|
||||
public static void AddRoleBlock(PlayerControl pc, float duration)
|
||||
{
|
||||
long now = Utils.TimeStamp;
|
||||
if (RoleBlockedPlayers.TryGetValue(pc.PlayerId, out var data) && (data.Duration - (now - data.StartTimeStamp) + 1) > duration)
|
||||
{
|
||||
Logger.Info($"{pc.GetNameWithRole()} got role blocked, but the duration is less than the previous one", "RoleBlockManager");
|
||||
return;
|
||||
}
|
||||
|
||||
RoleBlockedPlayers[pc.PlayerId] = (now, duration);
|
||||
Logger.Info($"{pc.GetNameWithRole()} is now role blocked for {duration} seconds", "RoleBlockManager");
|
||||
}
|
||||
|
||||
public static void OnFixedUpdate(PlayerControl pc)
|
||||
{
|
||||
if (RoleBlockedPlayers.TryGetValue(pc.PlayerId, out var data))
|
||||
{
|
||||
long now = Utils.TimeStamp;
|
||||
if (now - data.StartTimeStamp >= data.Duration)
|
||||
{
|
||||
RoleBlockedPlayers.Remove(pc.PlayerId);
|
||||
Logger.Info($"{pc.GetNameWithRole()} is no longer role blocked", "RoleBlockManager");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetBlockNotify(this BlockedAction blockedAction)
|
||||
{
|
||||
string blockedActionString = Translator.GetString($"{blockedAction}");
|
||||
string notify = string.Format(Translator.GetString("RoleBlockNotify"), blockedActionString);
|
||||
return Utils.ColorString(Color.yellow, notify);
|
||||
}
|
||||
}
|
||||
|
||||
public enum BlockedAction
|
||||
{
|
||||
Kill,
|
||||
Report,
|
||||
Sabotage,
|
||||
Vent
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,17 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using EHR.Modules;
|
||||
using Hazel;
|
||||
using UnityEngine;
|
||||
|
||||
namespace EHR;
|
||||
|
||||
static class TargetArrow
|
||||
{
|
||||
class ArrowInfo(byte from, byte to)
|
||||
{
|
||||
public readonly byte From = from;
|
||||
public readonly byte To = to;
|
||||
|
||||
public bool Equals(ArrowInfo obj)
|
||||
{
|
||||
return From == obj.From && To == obj.To;
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
return $"(From:{From} To:{To})";
|
||||
}
|
||||
}
|
||||
|
||||
static readonly Dictionary<ArrowInfo, string> TargetArrows = [];
|
||||
static readonly string[] Arrows = [
|
||||
|
||||
static readonly string[] Arrows =
|
||||
[
|
||||
"↑",
|
||||
"↗",
|
||||
"→",
|
||||
@@ -39,6 +28,22 @@ static class TargetArrow
|
||||
TargetArrows.Clear();
|
||||
}
|
||||
|
||||
public static void ReceiveRPC(MessageReader reader)
|
||||
{
|
||||
switch (reader.ReadPackedInt32())
|
||||
{
|
||||
case 1:
|
||||
Add(reader.ReadByte(), reader.ReadByte());
|
||||
break;
|
||||
case 2:
|
||||
Remove(reader.ReadByte(), reader.ReadByte());
|
||||
break;
|
||||
case 3:
|
||||
RemoveAllTarget(reader.ReadByte());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register a new target arrow object
|
||||
/// </summary>
|
||||
@@ -50,8 +55,10 @@ static class TargetArrow
|
||||
if (!TargetArrows.Any(a => a.Key.Equals(arrowInfo)))
|
||||
{
|
||||
TargetArrows[arrowInfo] = "・";
|
||||
Utils.SendRPC(CustomRPC.Arrow, true, 1, seer, target);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete target
|
||||
/// </summary>
|
||||
@@ -65,7 +72,10 @@ static class TargetArrow
|
||||
{
|
||||
TargetArrows.Remove(a);
|
||||
}
|
||||
|
||||
Utils.SendRPC(CustomRPC.Arrow, true, 2, seer, target);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete all targets for the specified seer
|
||||
/// </summary>
|
||||
@@ -77,6 +87,8 @@ static class TargetArrow
|
||||
{
|
||||
TargetArrows.Remove(arrowInfo);
|
||||
}
|
||||
|
||||
Utils.SendRPC(CustomRPC.Arrow, true, 3, seer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -115,6 +127,7 @@ static class TargetArrow
|
||||
update = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Take the direction vector of the target
|
||||
var dir = target.transform.position - seer.transform.position;
|
||||
int index;
|
||||
@@ -132,6 +145,7 @@ static class TargetArrow
|
||||
var angle = Vector3.SignedAngle(Vector3.down, dir, Vector3.back) + 180 + 22.5;
|
||||
index = ((int)(angle / 45)) % 8;
|
||||
}
|
||||
|
||||
var arrow = Arrows[index];
|
||||
if (TargetArrows[arrowInfo] != arrow)
|
||||
{
|
||||
@@ -139,9 +153,26 @@ static class TargetArrow
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (update)
|
||||
{
|
||||
Utils.NotifyRoles(SpecifySeer: seer, ForceLoop: false, SpecifyTarget: seer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ArrowInfo(byte from, byte to)
|
||||
{
|
||||
public readonly byte From = from;
|
||||
public readonly byte To = to;
|
||||
|
||||
public bool Equals(ArrowInfo obj)
|
||||
{
|
||||
return From == obj.From && To == obj.To;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"(From:{From} To:{To})";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -448,6 +448,8 @@ public static class Utils
|
||||
|
||||
public static void SendRPC(CustomRPC rpc, params object[] data)
|
||||
{
|
||||
if (!AmongUsClient.Instance.AmHost) return;
|
||||
|
||||
var w = CreateRPC(rpc);
|
||||
foreach (var o in data)
|
||||
{
|
||||
@@ -471,12 +473,25 @@ public static class Utils
|
||||
case Vector2 v:
|
||||
NetHelpers.WriteVector2(v, w);
|
||||
break;
|
||||
case Vector3 v:
|
||||
w.Write(v.x);
|
||||
w.Write(v.y);
|
||||
w.Write(v.z);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
EndRPC(w);
|
||||
}
|
||||
|
||||
public static Vector3 ReadVector3(MessageReader reader)
|
||||
{
|
||||
float x = reader.ReadSingle();
|
||||
float y = reader.ReadSingle();
|
||||
float z = reader.ReadSingle();
|
||||
return new(x, y, z);
|
||||
}
|
||||
|
||||
public static void IncreaseAbilityUseLimitOnKill(PlayerControl killer)
|
||||
{
|
||||
if (Main.PlayerStates[killer.PlayerId].Role is Mafioso { IsEnable: true } mo) mo.OnMurder(killer, null);
|
||||
@@ -2422,6 +2437,7 @@ public static class Utils
|
||||
Main.DontCancelVoteList.Clear();
|
||||
|
||||
DoorsReset.ResetDoors();
|
||||
RoleBlockManager.Reset();
|
||||
|
||||
if ((MapNames)Main.NormalOptions.MapId == MapNames.Airship && AmongUsClient.Instance.AmHost && PlayerControl.LocalPlayer.Is(CustomRoles.GM))
|
||||
{
|
||||
|
||||
@@ -96,17 +96,31 @@ internal class TitleLogoPatch
|
||||
//private static readonly Color themeColor10 = new(0.18f, 0.2f, 0.59f);
|
||||
//private static readonly Color themeColor11 = new(0.96f, 0.88f, 0.86f);
|
||||
|
||||
private static readonly Color ThemeColor1 = new(0.98f, 0.7f, 0.44f);
|
||||
private static readonly Color ThemeColor2 = new(0.98f, 0.61f, 0.42f);
|
||||
private static readonly Color ThemeColor3 = new(0.04f, 0.41f, 0.75f);
|
||||
private static readonly Color ThemeColor4 = new(0.12f, 0.17f, 0.47f);
|
||||
private static readonly Color ThemeColor5 = new(0.38f, 0.44f, 0.66f);
|
||||
private static readonly Color ThemeColor6 = new(0.72f, 0.68f, 0.79f);
|
||||
private static readonly Color ThemeColor7 = ThemeColor1.ShadeColor(0.1f);
|
||||
private static readonly Color ThemeColor8 = new(0.19f, 0.24f, 0.37f);
|
||||
private static readonly Color ThemeColor9 = ThemeColor5.ShadeColor(0.1f);
|
||||
private static readonly Color ThemeColor10 = ThemeColor4.ShadeColor(0.1f);
|
||||
private static readonly Color ThemeColor11 = ThemeColor6.ShadeColor(0.1f);
|
||||
// Winter BG
|
||||
// private static readonly Color ThemeColor1 = new(0.98f, 0.7f, 0.44f);
|
||||
// private static readonly Color ThemeColor2 = new(0.98f, 0.61f, 0.42f);
|
||||
// private static readonly Color ThemeColor3 = new(0.04f, 0.41f, 0.75f);
|
||||
// private static readonly Color ThemeColor4 = new(0.12f, 0.17f, 0.47f);
|
||||
// private static readonly Color ThemeColor5 = new(0.38f, 0.44f, 0.66f);
|
||||
// private static readonly Color ThemeColor6 = new(0.72f, 0.68f, 0.79f);
|
||||
// private static readonly Color ThemeColor7 = ThemeColor1.ShadeColor(0.1f);
|
||||
// private static readonly Color ThemeColor8 = new(0.19f, 0.24f, 0.37f);
|
||||
// private static readonly Color ThemeColor9 = ThemeColor5.ShadeColor(0.1f);
|
||||
// private static readonly Color ThemeColor10 = ThemeColor4.ShadeColor(0.1f);
|
||||
// private static readonly Color ThemeColor11 = ThemeColor6.ShadeColor(0.1f);
|
||||
|
||||
// Summer BG
|
||||
private static readonly Color ThemeColor1 = new(0.706f, 0.588f, 0.455f);
|
||||
private static readonly Color ThemeColor2 = new(0.827f, 0.827f, 0.643f);
|
||||
private static readonly Color ThemeColor3 = new(0.196f, 0.196f, 0.067f);
|
||||
private static readonly Color ThemeColor4 = new(0.145f, 0.655f, 0.859f);
|
||||
private static readonly Color ThemeColor5 = new(0.580f, 0.780f, 0.820f);
|
||||
private static readonly Color ThemeColor6 = new(0.435f, 0.776f, 0.925f);
|
||||
private static readonly Color ThemeColor7 = new(0.161f, 0.439f, 0.588f);
|
||||
private static readonly Color ThemeColor8 = new(0.388f, 0.565f, 0.537f);
|
||||
private static readonly Color ThemeColor9 = new(0.463f, 0.471f, 0.188f);
|
||||
private static readonly Color ThemeColor10 = Color.black;
|
||||
private static readonly Color ThemeColor11 = ThemeColor4.ShadeColor(0.1f);
|
||||
|
||||
private static void Postfix(MainMenuManager __instance)
|
||||
{
|
||||
@@ -199,7 +213,7 @@ internal class TitleLogoPatch
|
||||
}
|
||||
};
|
||||
var bgRenderer = customBg.AddComponent<SpriteRenderer>();
|
||||
bgRenderer.sprite = Utils.LoadSprite("EHR.Resources.Images.WinterBG.jpg", 180f);
|
||||
bgRenderer.sprite = Utils.LoadSprite("EHR.Resources.Images.SummerBG.jpg", 180f);
|
||||
|
||||
if (__instance.screenTint != null)
|
||||
{
|
||||
|
||||
@@ -159,7 +159,6 @@ class ExileControllerWrapUpPatch
|
||||
static void WrapUpFinalizer(GameData.PlayerInfo exiled)
|
||||
{
|
||||
// Even if an exception occurs in WrapUpPostfix, this part will be executed reliably.
|
||||
bool overrideExiledPlayer = false;
|
||||
if (AmongUsClient.Instance.AmHost)
|
||||
{
|
||||
_ = new LateTask(() =>
|
||||
@@ -171,7 +170,6 @@ class ExileControllerWrapUpPatch
|
||||
exiled.Object != null)
|
||||
{
|
||||
exiled.Object.RpcExileV2();
|
||||
overrideExiledPlayer = true;
|
||||
}
|
||||
}, 0.8f, "Restore IsDead Task");
|
||||
_ = new LateTask(() =>
|
||||
@@ -199,11 +197,14 @@ class ExileControllerWrapUpPatch
|
||||
SoundManager.Instance.ChangeAmbienceVolume(DataManager.Settings.Audio.AmbienceVolume);
|
||||
Logger.Info("Start task phase", "Phase");
|
||||
|
||||
if (Options.EnableKillerLeftCommand.GetBool() && Options.CurrentGameMode == CustomGameMode.Standard && Options.ShowImpRemainOnEject.GetBool())
|
||||
bool showRemainingKillers = Options.EnableKillerLeftCommand.GetBool() && Options.ShowImpRemainOnEject.GetBool();
|
||||
bool appendEjectionNotify = CheckForEndVotingPatch.EjectionText != string.Empty;
|
||||
Logger.Warn($"Ejection Text: {CheckForEndVotingPatch.EjectionText}", "debug");
|
||||
if ((showRemainingKillers || appendEjectionNotify) && Options.CurrentGameMode == CustomGameMode.Standard)
|
||||
{
|
||||
_ = new LateTask(() =>
|
||||
{
|
||||
var text = Utils.GetRemainingKillers(notify: true);
|
||||
var text = showRemainingKillers ? Utils.GetRemainingKillers(notify: true) : string.Empty;
|
||||
text = $"<#ffffff>{text}</color>";
|
||||
var r = IRandom.Instance;
|
||||
foreach (var pc in Main.AllAlivePlayerControls)
|
||||
@@ -214,11 +215,13 @@ class ExileControllerWrapUpPatch
|
||||
finalText = $"\n{notify.TEXT}\n{finalText}";
|
||||
}
|
||||
|
||||
if (overrideExiledPlayer && CheckForEndVotingPatch.EjectionText != string.Empty)
|
||||
if (appendEjectionNotify)
|
||||
{
|
||||
finalText = $"\n{CheckForEndVotingPatch.EjectionText}\n{finalText}";
|
||||
finalText = $"\n<#ffffff>{CheckForEndVotingPatch.EjectionText}</color>\n{finalText}";
|
||||
}
|
||||
|
||||
if (!showRemainingKillers) finalText = finalText.TrimStart();
|
||||
|
||||
pc.Notify(finalText, r.Next(7, 13));
|
||||
}
|
||||
}, 0.5f, log: false);
|
||||
|
||||
@@ -75,15 +75,14 @@ class HudManagerPatch
|
||||
{
|
||||
if (OverriddenRolesText == null)
|
||||
{
|
||||
OverriddenRolesText = Object.Instantiate(__instance.KillButton.cooldownTimerText);
|
||||
OverriddenRolesText = Object.Instantiate(__instance.KillButton.cooldownTimerText, __instance.transform, true);
|
||||
OverriddenRolesText.alignment = TextAlignmentOptions.Right;
|
||||
OverriddenRolesText.verticalAlignment = VerticalAlignmentOptions.Top;
|
||||
OverriddenRolesText.transform.parent = __instance.transform;
|
||||
OverriddenRolesText.transform.localPosition = new(4.9f, 0.8f, 0);
|
||||
OverriddenRolesText.overflowMode = TextOverflowModes.Overflow;
|
||||
OverriddenRolesText.enableWordWrapping = false;
|
||||
OverriddenRolesText.color = Color.white;
|
||||
OverriddenRolesText.fontSize = OverriddenRolesText.fontSizeMax = OverriddenRolesText.fontSizeMin = 2f;
|
||||
OverriddenRolesText.fontSize = OverriddenRolesText.fontSizeMax = OverriddenRolesText.fontSizeMin = 2.5f;
|
||||
}
|
||||
|
||||
if (Main.SetRoles.Count > 0 || Main.SetAddOns.Count > 0)
|
||||
@@ -120,24 +119,17 @@ class HudManagerPatch
|
||||
}
|
||||
}
|
||||
|
||||
bool stop = false;
|
||||
foreach (var roles in Main.SetRoles)
|
||||
foreach (var role in Main.SetRoles)
|
||||
{
|
||||
if (!Main.SetAddOns.ContainsKey(roles.Key)) continue;
|
||||
foreach (var addons in Main.SetAddOns)
|
||||
{
|
||||
if (!Main.SetRoles.ContainsKey(addons.Key)) continue;
|
||||
foreach (var addon in addons.Value)
|
||||
{
|
||||
if (!CustomRolesHelper.CheckAddonConflictV2(addon, roles.Value))
|
||||
{
|
||||
resultText[roles.Key] += " <#ff0000>(!)</color>";
|
||||
stop = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!Main.SetAddOns.TryGetValue(role.Key, out var addons)) continue;
|
||||
|
||||
if (stop) break;
|
||||
foreach (var addon in addons)
|
||||
{
|
||||
if (!CustomRolesHelper.CheckAddonConflictV2(addon, role.Value))
|
||||
{
|
||||
resultText[role.Key] += " <#ff0000>(!)</color>";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -359,14 +351,13 @@ class HudManagerPatch
|
||||
|
||||
if (LowerInfoText == null)
|
||||
{
|
||||
LowerInfoText = Object.Instantiate(__instance.KillButton.cooldownTimerText);
|
||||
LowerInfoText = Object.Instantiate(__instance.KillButton.cooldownTimerText, __instance.transform, true);
|
||||
LowerInfoText.alignment = TextAlignmentOptions.Center;
|
||||
LowerInfoText.transform.parent = __instance.transform;
|
||||
LowerInfoText.transform.localPosition = new(0, -2f, 0);
|
||||
LowerInfoText.overflowMode = TextOverflowModes.Overflow;
|
||||
LowerInfoText.enableWordWrapping = false;
|
||||
LowerInfoText.color = Color.white;
|
||||
LowerInfoText.fontSize = LowerInfoText.fontSizeMax = LowerInfoText.fontSizeMin = 2f;
|
||||
LowerInfoText.fontSize = LowerInfoText.fontSizeMax = LowerInfoText.fontSizeMin = 2.7f;
|
||||
}
|
||||
|
||||
var state = Main.PlayerStates[player.PlayerId];
|
||||
@@ -476,6 +467,8 @@ class HudManagerPatch
|
||||
[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.ToggleHighlight))]
|
||||
class ToggleHighlightPatch
|
||||
{
|
||||
private static readonly int OutlineColor = Shader.PropertyToID("_OutlineColor");
|
||||
|
||||
public static void Postfix(PlayerControl __instance /*[HarmonyArgument(0)] bool active,*/ /*[HarmonyArgument(1)] RoleTeamTypes team*/)
|
||||
{
|
||||
if (!GameStates.IsInTask) return;
|
||||
@@ -483,7 +476,7 @@ class ToggleHighlightPatch
|
||||
|
||||
if (player.CanUseKillButton())
|
||||
{
|
||||
__instance.cosmetics.currentBodySprite.BodySprite.material.SetColor("_OutlineColor", Utils.GetRoleColor(player.GetCustomRole()));
|
||||
__instance.cosmetics.currentBodySprite.BodySprite.material.SetColor(OutlineColor, Utils.GetRoleColor(player.GetCustomRole()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -491,11 +484,14 @@ class ToggleHighlightPatch
|
||||
[HarmonyPatch(typeof(Vent), nameof(Vent.SetOutline))]
|
||||
class SetVentOutlinePatch
|
||||
{
|
||||
private static readonly int OutlineColor = Shader.PropertyToID("_OutlineColor");
|
||||
private static readonly int AddColor = Shader.PropertyToID("_AddColor");
|
||||
|
||||
public static void Postfix(Vent __instance, [HarmonyArgument(1)] ref bool mainTarget)
|
||||
{
|
||||
Color color = PlayerControl.LocalPlayer.GetRoleColor();
|
||||
__instance.myRend.material.SetColor("_OutlineColor", color);
|
||||
__instance.myRend.material.SetColor("_AddColor", mainTarget ? color : Color.clear);
|
||||
__instance.myRend.material.SetColor(OutlineColor, color);
|
||||
__instance.myRend.material.SetColor(AddColor, mainTarget ? color : Color.clear);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -623,10 +619,49 @@ class MapBehaviourShowPatch
|
||||
opts.Mode = MapOptions.Modes.Normal;
|
||||
}
|
||||
|
||||
if (Main.GodMode.Value) opts.ShowLivePlayerPosition = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(InfectedOverlay), nameof(InfectedOverlay.Update))]
|
||||
class SabotageMapPatch
|
||||
{
|
||||
public static Dictionary<SystemTypes, TextMeshPro> TimerTexts = [];
|
||||
|
||||
public static void Postfix(InfectedOverlay __instance)
|
||||
{
|
||||
float perc = __instance.sabSystem.PercentCool;
|
||||
int total = __instance.sabSystem.initialCooldown ? 10 : 30;
|
||||
if (SabotageSystemTypeRepairDamagePatch.IsCooldownModificationEnabled) total = (int)SabotageSystemTypeRepairDamagePatch.ModifiedCooldownSec;
|
||||
int remaining = Math.Clamp(total - (int)Math.Ceiling((1f - perc) * total) + 1, 0, total);
|
||||
|
||||
foreach (var mr in __instance.rooms)
|
||||
{
|
||||
if (mr.special == null || mr.special.transform == null) continue;
|
||||
var room = mr.room;
|
||||
if (!TimerTexts.ContainsKey(room))
|
||||
{
|
||||
TimerTexts[room] = Object.Instantiate(HudManager.Instance.KillButton.cooldownTimerText, mr.special.transform, true);
|
||||
TimerTexts[room].alignment = TextAlignmentOptions.Center;
|
||||
TimerTexts[room].transform.localPosition = mr.special.transform.localPosition;
|
||||
TimerTexts[room].transform.localPosition = new(0, -0.4f, 0f);
|
||||
TimerTexts[room].overflowMode = TextOverflowModes.Overflow;
|
||||
TimerTexts[room].enableWordWrapping = false;
|
||||
TimerTexts[room].color = Color.white;
|
||||
TimerTexts[room].fontSize = TimerTexts[room].fontSizeMax = TimerTexts[room].fontSizeMin = 2.5f;
|
||||
TimerTexts[room].sortingOrder = 100;
|
||||
}
|
||||
|
||||
bool isActive = Utils.IsActive(room);
|
||||
bool isOtherActive = TimerTexts.Keys.Any(Utils.IsActive);
|
||||
TimerTexts[room].text = $"<b><#ff{(isActive || isOtherActive ? "00" : "ff")}00>{(isActive ? remaining : GetString(isOtherActive ? "SabotageDisabledIndicator" : "SabotageActiveIndicator"))}</color></b>";
|
||||
TimerTexts[room].enabled = remaining > 0 || isActive;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(TaskPanelBehaviour), nameof(TaskPanelBehaviour.SetTaskText))]
|
||||
class TaskPanelBehaviourPatch
|
||||
{
|
||||
|
||||
@@ -880,20 +880,28 @@ class MeetingHudStartPatch
|
||||
var seerRole = seer.GetCustomRole();
|
||||
|
||||
// Guesser Mode //
|
||||
if (Options.GuesserMode.GetBool())
|
||||
if (((Options.GuesserMode.GetBool() && !seer.Data.IsDead && !target.Data.IsDead &&
|
||||
((Options.CrewmatesCanGuess.GetBool() && seer.IsCrewmate() && !seer.Is(CustomRoles.Judge) && !seer.Is(CustomRoles.NiceSwapper) && !seer.Is(CustomRoles.Lookout) && !seer.Is(CustomRoles.ParityCop)) ||
|
||||
(Options.ImpostorsCanGuess.GetBool() && seerRole.IsImpostor() && !seer.Is(CustomRoles.Councillor)) ||
|
||||
(Options.NeutralKillersCanGuess.GetBool() && seer.IsNeutralKiller()) ||
|
||||
(Options.PassiveNeutralsCanGuess.GetBool() && seerRole.IsNonNK() && !seer.Is(CustomRoles.Doomsayer)))) ||
|
||||
|
||||
// Other Roles and Add-ons that can see player IDs //
|
||||
(seer.Data.IsDead && !target.Data.IsDead && seerRole is CustomRoles.Mafia) ||
|
||||
(!seer.Data.IsDead && !target.Data.IsDead &&
|
||||
(seer.Is(CustomRoles.Guesser) ||
|
||||
seerRole is
|
||||
CustomRoles.Judge or
|
||||
CustomRoles.NiceSwapper or
|
||||
CustomRoles.Lookout or
|
||||
CustomRoles.ParityCop or
|
||||
CustomRoles.Councillor or
|
||||
CustomRoles.Doomsayer or
|
||||
CustomRoles.EvilGuesser or
|
||||
CustomRoles.NiceGuesser
|
||||
))))
|
||||
{
|
||||
if (Options.CrewmatesCanGuess.GetBool() && seer.IsCrewmate() && !seer.Is(CustomRoles.Judge) && !seer.Is(CustomRoles.NiceSwapper) && !seer.Is(CustomRoles.Lookout) && !seer.Is(CustomRoles.ParityCop))
|
||||
if (!seer.Data.IsDead && !target.Data.IsDead)
|
||||
pva.NameText.text = Utils.ColorString(Utils.GetRoleColor(seerRole), target.PlayerId.ToString()) + " " + pva.NameText.text;
|
||||
if (Options.ImpostorsCanGuess.GetBool() && seerRole.IsImpostor() && !seer.Is(CustomRoles.Councillor))
|
||||
if (!seer.Data.IsDead && !target.Data.IsDead)
|
||||
pva.NameText.text = Utils.ColorString(Utils.GetRoleColor(seerRole), target.PlayerId.ToString()) + " " + pva.NameText.text;
|
||||
if (Options.NeutralKillersCanGuess.GetBool() && seer.IsNeutralKiller())
|
||||
if (!seer.Data.IsDead && !target.Data.IsDead)
|
||||
pva.NameText.text = Utils.ColorString(Utils.GetRoleColor(seerRole), target.PlayerId.ToString()) + " " + pva.NameText.text;
|
||||
if (Options.PassiveNeutralsCanGuess.GetBool() && seerRole.IsNonNK() && !seer.Is(CustomRoles.Doomsayer))
|
||||
if (!seer.Data.IsDead && !target.Data.IsDead)
|
||||
pva.NameText.text = Utils.ColorString(Utils.GetRoleColor(seerRole), target.PlayerId.ToString()) + " " + pva.NameText.text;
|
||||
pva.NameText.text = $"{Utils.ColorString(Utils.GetRoleColor(seerRole), target.PlayerId.ToString())} {pva.NameText.text}";
|
||||
}
|
||||
|
||||
if (seer.KnowDeathReason(target))
|
||||
@@ -940,46 +948,6 @@ class MeetingHudStartPatch
|
||||
if (Psychic.IsRedForPsy(target, seer) && !seer.Data.IsDead)
|
||||
pva.NameText.text = Utils.ColorString(Utils.GetRoleColor(CustomRoles.Impostor), pva.NameText.text);
|
||||
break;
|
||||
case CustomRoles.Mafia:
|
||||
if (seer.Data.IsDead && !target.Data.IsDead)
|
||||
pva.NameText.text = Utils.ColorString(Utils.GetRoleColor(CustomRoles.Mafia), target.PlayerId.ToString()) + " " + pva.NameText.text;
|
||||
break;
|
||||
case CustomRoles.NiceGuesser:
|
||||
case CustomRoles.EvilGuesser:
|
||||
if (!seer.Data.IsDead && !target.Data.IsDead)
|
||||
pva.NameText.text = Utils.ColorString(Utils.GetRoleColor(seer.Is(CustomRoles.NiceGuesser) ? CustomRoles.NiceGuesser : CustomRoles.EvilGuesser), target.PlayerId.ToString()) + " " + pva.NameText.text;
|
||||
break;
|
||||
case CustomRoles.Guesser:
|
||||
if (!seer.Data.IsDead && !target.Data.IsDead)
|
||||
pva.NameText.text = Utils.ColorString(Utils.GetRoleColor(CustomRoles.Guesser), target.PlayerId.ToString()) + " " + pva.NameText.text;
|
||||
break;
|
||||
case CustomRoles.Judge:
|
||||
if (!seer.Data.IsDead && !target.Data.IsDead)
|
||||
pva.NameText.text = Utils.ColorString(Utils.GetRoleColor(CustomRoles.Judge), target.PlayerId.ToString()) + " " + pva.NameText.text;
|
||||
break;
|
||||
case CustomRoles.NiceSwapper:
|
||||
if (!seer.Data.IsDead && !target.Data.IsDead)
|
||||
pva.NameText.text = Utils.ColorString(Utils.GetRoleColor(CustomRoles.NiceSwapper), target.PlayerId.ToString()) + " " + pva.NameText.text;
|
||||
break;
|
||||
case CustomRoles.Lookout:
|
||||
if (!seer.Data.IsDead && !target.Data.IsDead)
|
||||
pva.NameText.text = Utils.ColorString(Utils.GetRoleColor(CustomRoles.Lookout), target.PlayerId.ToString()) + " " + pva.NameText.text;
|
||||
break;
|
||||
case CustomRoles.Doomsayer:
|
||||
if (!seer.Data.IsDead && !target.Data.IsDead)
|
||||
pva.NameText.text = Utils.ColorString(Utils.GetRoleColor(CustomRoles.Doomsayer), target.PlayerId.ToString()) + " " + pva.NameText.text;
|
||||
break;
|
||||
case CustomRoles.ParityCop:
|
||||
if (!seer.Data.IsDead && !target.Data.IsDead)
|
||||
pva.NameText.text = Utils.ColorString(Utils.GetRoleColor(CustomRoles.ParityCop), target.PlayerId.ToString()) + " " + pva.NameText.text;
|
||||
break;
|
||||
|
||||
case CustomRoles.Councillor:
|
||||
if (!seer.Data.IsDead && !target.Data.IsDead)
|
||||
pva.NameText.text = Utils.ColorString(Utils.GetRoleColor(CustomRoles.Councillor), target.PlayerId.ToString()) + " " + pva.NameText.text;
|
||||
|
||||
break;
|
||||
|
||||
case CustomRoles.Gamer:
|
||||
sb.Append(Gamer.TargetMark(seer, target));
|
||||
sb.Append(Snitch.GetWarningMark(seer, target));
|
||||
@@ -992,31 +960,9 @@ class MeetingHudStartPatch
|
||||
if (Silencer.ForSilencer.Contains(target.PlayerId))
|
||||
sb.Append(Utils.ColorString(Utils.GetRoleColor(CustomRoles.Silencer), "╳"));
|
||||
|
||||
List<CustomRoles> list = seer.GetCustomSubRoles();
|
||||
foreach (var SeerSubRole in list)
|
||||
if (target.GetCustomSubRoles().Contains(CustomRoles.Lovers) && (seer.Is(CustomRoles.Lovers) || seer.Data.IsDead))
|
||||
{
|
||||
switch (SeerSubRole)
|
||||
{
|
||||
case CustomRoles.Guesser:
|
||||
if (!seer.Data.IsDead && !target.Data.IsDead)
|
||||
pva.NameText.text = Utils.ColorString(Utils.GetRoleColor(CustomRoles.Guesser), target.PlayerId.ToString()) + " " + pva.NameText.text;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
List<CustomRoles> list1 = target.GetCustomSubRoles();
|
||||
foreach (var subRole in list1)
|
||||
{
|
||||
switch (subRole)
|
||||
{
|
||||
case CustomRoles.Lovers:
|
||||
if (seer.Is(CustomRoles.Lovers) || seer.Data.IsDead)
|
||||
{
|
||||
sb.Append(Utils.ColorString(Utils.GetRoleColor(CustomRoles.Lovers), "♥"));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
sb.Append(Utils.ColorString(Utils.GetRoleColor(CustomRoles.Lovers), "♥"));
|
||||
}
|
||||
|
||||
sb.Append(Witch.GetSpelledMark(target.PlayerId, true));
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AmongUs.GameOptions;
|
||||
using EHR.Modules;
|
||||
using EHR.Patches;
|
||||
using EHR.Roles.AddOns.Common;
|
||||
using EHR.Roles.AddOns.Crewmate;
|
||||
using EHR.Roles.AddOns.Impostor;
|
||||
@@ -50,6 +51,37 @@ internal class ChangeRoleSettings
|
||||
Main.AllPlayerKillCooldown = [];
|
||||
Main.AllPlayerSpeed = [];
|
||||
Main.KillTimers = [];
|
||||
Main.SleuthMsgs = [];
|
||||
Main.CyberStarDead = [];
|
||||
Main.KilledDiseased = [];
|
||||
Main.KilledAntidote = [];
|
||||
Main.BaitAlive = [];
|
||||
Main.DontCancelVoteList = [];
|
||||
Main.LastEnteredVent = [];
|
||||
Main.LastEnteredVentLocation = [];
|
||||
Main.AfterMeetingDeathPlayers = [];
|
||||
Main.ResetCamPlayerList = [];
|
||||
Main.ClientIdList = [];
|
||||
Main.CheckShapeshift = [];
|
||||
Main.ShapeshiftTarget = [];
|
||||
Main.ShieldPlayer = Options.ShieldPersonDiedFirst.GetBool() ? Main.FirstDied : byte.MaxValue;
|
||||
Main.FirstDied = byte.MaxValue;
|
||||
Main.MadmateNum = 0;
|
||||
|
||||
Mayor.MayorUsedButtonCount = [];
|
||||
Paranoia.ParaUsedButtonCount = [];
|
||||
Mario.MarioVentCount = [];
|
||||
Cleaner.CleanerBodies = [];
|
||||
Virus.InfectedBodies = [];
|
||||
Workaholic.WorkaholicAlive = [];
|
||||
Virus.VirusNotify = [];
|
||||
Veteran.VeteranInProtect = [];
|
||||
Witness.AllKillers = [];
|
||||
Grenadier.GrenadierBlinding = [];
|
||||
SecurityGuard.BlockSabo = [];
|
||||
Ventguard.BlockedVents = [];
|
||||
Grenadier.MadGrenadierBlinding = [];
|
||||
OverKiller.OverDeadPlayerList = [];
|
||||
Warlock.WarlockTimer = [];
|
||||
Arsonist.IsDoused = [];
|
||||
Revolutionist.IsDraw = [];
|
||||
@@ -67,45 +99,13 @@ internal class ChangeRoleSettings
|
||||
Warlock.IsCurseAndKill = [];
|
||||
Warlock.IsCursed = false;
|
||||
Detective.DetectiveNotify = [];
|
||||
Main.SleuthMsgs = [];
|
||||
Crusader.ForCrusade = [];
|
||||
Main.CyberStarDead = [];
|
||||
Main.KilledDiseased = [];
|
||||
Main.KilledAntidote = [];
|
||||
Workaholic.WorkaholicAlive = [];
|
||||
Main.BaitAlive = [];
|
||||
Cleaner.CleanerBodies = [];
|
||||
Virus.InfectedBodies = [];
|
||||
Virus.VirusNotify = [];
|
||||
Main.DontCancelVoteList = [];
|
||||
|
||||
Main.LastEnteredVent = [];
|
||||
Main.LastEnteredVentLocation = [];
|
||||
|
||||
Main.AfterMeetingDeathPlayers = [];
|
||||
Main.ResetCamPlayerList = [];
|
||||
Main.ClientIdList = [];
|
||||
|
||||
Main.CheckShapeshift = [];
|
||||
Main.ShapeshiftTarget = [];
|
||||
Mayor.MayorUsedButtonCount = [];
|
||||
Paranoia.ParaUsedButtonCount = [];
|
||||
Mario.MarioVentCount = [];
|
||||
Veteran.VeteranInProtect = [];
|
||||
Witness.AllKillers = [];
|
||||
Grenadier.GrenadierBlinding = [];
|
||||
SecurityGuard.BlockSabo = [];
|
||||
Ventguard.BlockedVents = [];
|
||||
Grenadier.MadGrenadierBlinding = [];
|
||||
OverKiller.OverDeadPlayerList = [];
|
||||
Provocateur.Provoked = [];
|
||||
Main.ShieldPlayer = Options.ShieldPersonDiedFirst.GetBool() ? Main.FirstDied : byte.MaxValue;
|
||||
Main.FirstDied = byte.MaxValue;
|
||||
Main.MadmateNum = 0;
|
||||
Crusader.ForCrusade = [];
|
||||
Godfather.GodfatherTarget = byte.MaxValue;
|
||||
ChatManager.ResetHistory();
|
||||
|
||||
ReportDeadBodyPatch.CanReport = [];
|
||||
SabotageMapPatch.TimerTexts = [];
|
||||
|
||||
Options.UsedButtonCount = 0;
|
||||
|
||||
@@ -213,6 +213,7 @@ internal class ChangeRoleSettings
|
||||
DoorsReset.Initialize();
|
||||
GhostRolesManager.Initialize();
|
||||
CustomTeamManager.LoadCustomTeams();
|
||||
RoleBlockManager.Reset();
|
||||
|
||||
IRandom.SetInstanceById(Options.RoleAssigningAlgorithm.GetValue());
|
||||
|
||||
|
||||
@@ -238,9 +238,9 @@ class CheckMurderPatch
|
||||
if (Pelican.IsEaten(target.PlayerId))
|
||||
return false;
|
||||
|
||||
if (Glitch.hackedIdList.ContainsKey(killer.PlayerId))
|
||||
if (killer.IsRoleBlocked())
|
||||
{
|
||||
killer.Notify(string.Format(GetString("HackedByGlitch"), "Kill"));
|
||||
killer.Notify(BlockedAction.Kill.GetBlockNotify());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -341,9 +341,9 @@ class CheckMurderPatch
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Glitch.hackedIdList.ContainsKey(killer.PlayerId))
|
||||
if (killer.IsRoleBlocked())
|
||||
{
|
||||
killer.Notify(string.Format(GetString("HackedByGlitch"), "Kill"));
|
||||
killer.Notify(BlockedAction.Kill.GetBlockNotify());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1030,9 +1030,9 @@ class FixedUpdatePatch
|
||||
byte id = __instance.PlayerId;
|
||||
if (AmongUsClient.Instance.AmHost && GameStates.IsInTask && ReportDeadBodyPatch.CanReport[id] && ReportDeadBodyPatch.WaitReport[id].Count > 0)
|
||||
{
|
||||
if (Glitch.hackedIdList.ContainsKey(id))
|
||||
if (id.IsPlayerRoleBlocked())
|
||||
{
|
||||
__instance.Notify(string.Format(GetString("HackedByGlitch"), "Report"));
|
||||
__instance.Notify(BlockedAction.Report.GetBlockNotify());
|
||||
Logger.Info("Dead Body Report Blocked (player is hacked by Glitch)", "FixedUpdate.ReportDeadBody");
|
||||
ReportDeadBodyPatch.WaitReport[id].Clear();
|
||||
}
|
||||
@@ -1222,6 +1222,8 @@ class FixedUpdatePatch
|
||||
}
|
||||
|
||||
if (!lowLoad) Randomizer.OnFixedUpdateForPlayers(player);
|
||||
|
||||
RoleBlockManager.OnFixedUpdate(player);
|
||||
}
|
||||
|
||||
if (!lowLoad)
|
||||
@@ -1294,7 +1296,7 @@ class FixedUpdatePatch
|
||||
RoleText.text = RoleTextData.Item1;
|
||||
RoleText.color = RoleTextData.Item2;
|
||||
|
||||
if (Options.CurrentGameMode != CustomGameMode.Standard) RoleText.text = string.Empty;
|
||||
if (Options.CurrentGameMode is not CustomGameMode.Standard and not CustomGameMode.HideAndSeek) RoleText.text = string.Empty;
|
||||
|
||||
RoleText.enabled = IsRoleTextEnabled(__instance);
|
||||
|
||||
@@ -1623,7 +1625,7 @@ class PlayerStartPatch
|
||||
{
|
||||
var roleText = Object.Instantiate(__instance.cosmetics.nameText, __instance.cosmetics.nameText.transform, true);
|
||||
roleText.transform.localPosition = new(0f, 0.2f, 0f);
|
||||
roleText.fontSize -= 0.2f;
|
||||
roleText.fontSize -= 0.9f;
|
||||
roleText.text = "RoleText";
|
||||
roleText.gameObject.name = "RoleText";
|
||||
roleText.enabled = false;
|
||||
@@ -1756,14 +1758,14 @@ class CoEnterVentPatch
|
||||
return true;
|
||||
case CustomGameMode.HideAndSeek:
|
||||
CustomHideAndSeekManager.OnCoEnterVent(__instance, id);
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (Glitch.hackedIdList.ContainsKey(__instance.myPlayer.PlayerId))
|
||||
if (__instance.myPlayer.IsRoleBlocked())
|
||||
{
|
||||
_ = new LateTask(() =>
|
||||
{
|
||||
__instance.myPlayer?.Notify(string.Format(GetString("HackedByGlitch"), "Vent"));
|
||||
__instance.myPlayer?.Notify(BlockedAction.Vent.GetBlockNotify());
|
||||
__instance.myPlayer?.MyPhysics?.RpcBootFromVent(id);
|
||||
}, 0.5f);
|
||||
return true;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Linq;
|
||||
using EHR.Modules;
|
||||
using EHR.Roles.Crewmate;
|
||||
using EHR.Roles.Neutral;
|
||||
using HarmonyLib;
|
||||
@@ -244,27 +244,26 @@ public static class ElectricTaskCompletePatch
|
||||
[HarmonyPatch(typeof(SabotageSystemType), nameof(SabotageSystemType.UpdateSystem))]
|
||||
public static class SabotageSystemTypeRepairDamagePatch
|
||||
{
|
||||
private static bool isCooldownModificationEnabled;
|
||||
private static float modifiedCooldownSec;
|
||||
public static bool IsCooldownModificationEnabled;
|
||||
public static float ModifiedCooldownSec;
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
isCooldownModificationEnabled = Options.SabotageCooldownControl.GetBool();
|
||||
modifiedCooldownSec = Options.SabotageCooldown.GetFloat();
|
||||
IsCooldownModificationEnabled = Options.SabotageCooldownControl.GetBool();
|
||||
ModifiedCooldownSec = Options.SabotageCooldown.GetFloat();
|
||||
}
|
||||
|
||||
public static bool Prefix([HarmonyArgument(0)] PlayerControl player)
|
||||
{
|
||||
if (Options.DisableSabotage.GetBool() || Options.CurrentGameMode != CustomGameMode.Standard) return false;
|
||||
if (SecurityGuard.BlockSabo.Count > 0) return false;
|
||||
if (Glitch.hackedIdList.ContainsKey(player.PlayerId))
|
||||
if (player.IsRoleBlocked())
|
||||
{
|
||||
player.Notify(string.Format(Translator.GetString("HackedByGlitch"), "Sabotage"));
|
||||
player.Notify(BlockedAction.Sabotage.GetBlockNotify());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (player.Is(CustomRoleTypes.Impostor) && !player.IsAlive() && Options.DeadImpCantSabotage.GetBool()) return false;
|
||||
if (player.Is(CustomRoleTypes.Impostor) && (player.IsAlive() || !Options.DeadImpCantSabotage.GetBool()) && player.GetCustomRole() is not CustomRoles.Minimalism and not CustomRoles.Mafioso and not CustomRoles.Generator) return true;
|
||||
bool allow = player.GetCustomRole() switch
|
||||
{
|
||||
CustomRoles.Jackal when Jackal.CanSabotage.GetBool() => true,
|
||||
@@ -282,12 +281,12 @@ public static class SabotageSystemTypeRepairDamagePatch
|
||||
|
||||
public static void Postfix(SabotageSystemType __instance)
|
||||
{
|
||||
if (!isCooldownModificationEnabled || !AmongUsClient.Instance.AmHost)
|
||||
if (!IsCooldownModificationEnabled || !AmongUsClient.Instance.AmHost)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
__instance.Timer = modifiedCooldownSec;
|
||||
__instance.Timer = ModifiedCooldownSec;
|
||||
__instance.IsDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BepInEx;
|
||||
using EHR.Modules;
|
||||
using EHR.Patches;
|
||||
using EHR.Roles.AddOns.Crewmate;
|
||||
using EHR.Roles.AddOns.Impostor;
|
||||
@@ -34,15 +35,19 @@ class ShipFixedUpdatePatch
|
||||
[HarmonyPatch(typeof(ShipStatus), nameof(ShipStatus.UpdateSystem), typeof(SystemTypes), typeof(PlayerControl), typeof(MessageReader))]
|
||||
public static class MessageReaderUpdateSystemPatch
|
||||
{
|
||||
public static void Prefix(ShipStatus __instance, [HarmonyArgument(0)] SystemTypes systemType, [HarmonyArgument(1)] PlayerControl player, [HarmonyArgument(2)] MessageReader reader)
|
||||
public static bool Prefix(ShipStatus __instance, [HarmonyArgument(0)] SystemTypes systemType, [HarmonyArgument(1)] PlayerControl player, [HarmonyArgument(2)] MessageReader reader)
|
||||
{
|
||||
try
|
||||
{
|
||||
RepairSystemPatch.Prefix(__instance, systemType, player, MessageReader.Get(reader).ReadByte());
|
||||
byte amount = MessageReader.Get(reader).ReadByte();
|
||||
if (EAC.RpcUpdateSystemCheck(player, systemType, amount)) return false;
|
||||
RepairSystemPatch.Prefix(__instance, systemType, player, amount);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void Postfix( /*ShipStatus __instance,*/ [HarmonyArgument(0)] SystemTypes systemType, [HarmonyArgument(1)] PlayerControl player, [HarmonyArgument(2)] MessageReader reader)
|
||||
@@ -115,14 +120,13 @@ class RepairSystemPatch
|
||||
case SystemTypes.Sabotage when AmongUsClient.Instance.NetworkMode != NetworkModes.FreePlay:
|
||||
if (Options.CurrentGameMode != CustomGameMode.Standard) return false;
|
||||
if (SecurityGuard.BlockSabo.Count > 0) return false;
|
||||
if (Glitch.hackedIdList.ContainsKey(player.PlayerId))
|
||||
if (player.IsRoleBlocked())
|
||||
{
|
||||
player.Notify(string.Format(Translator.GetString("HackedByGlitch"), "Sabotage"));
|
||||
player.Notify(BlockedAction.Sabotage.GetBlockNotify());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (player.Is(CustomRoleTypes.Impostor) && !player.IsAlive() && Options.DeadImpCantSabotage.GetBool()) return false;
|
||||
if (player.Is(CustomRoleTypes.Impostor) && (player.IsAlive() || !Options.DeadImpCantSabotage.GetBool()) && !player.Is(CustomRoles.Minimalism) && !player.Is(CustomRoles.Mafioso)) return true;
|
||||
return player.GetCustomRole() switch
|
||||
{
|
||||
CustomRoles.Jackal when Jackal.CanSabotage.GetBool() => true,
|
||||
|
||||
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 59 KiB |
|
After Width: | Height: | Size: 749 KiB |
|
Before Width: | Height: | Size: 210 KiB |
|
Before Width: | Height: | Size: 8.1 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 696 KiB |
|
Before Width: | Height: | Size: 2.8 MiB |
@@ -1047,6 +1047,11 @@
|
||||
"TieMode.Default": "No ejects",
|
||||
"TieMode.All": "Eject All",
|
||||
"TieMode.Random": "Eject Random",
|
||||
"Kill": "Kill",
|
||||
"Report": "Report",
|
||||
"Sabotage": "Sabotage",
|
||||
"Vent": "Vent",
|
||||
"Dead": "DEAD",
|
||||
"DisableDevices": "Disable Devices",
|
||||
"DisableSkeldDevices": "Disable Skeld Devices",
|
||||
"DisableMiraHQDevices": "Disable MiraHQ Devices",
|
||||
@@ -1573,7 +1578,9 @@
|
||||
"HackDuration": "Hack Duration",
|
||||
"MimicCooldown": "Mimic Cooldown",
|
||||
"MimicDuration": "Mimic Duration",
|
||||
"HackedByGlitch": "<color=#ffff00>You are hacked, you can't {0}.</color>",
|
||||
"RoleBlockNotify": "You are role blocked, you can't {0}",
|
||||
"RoleBlockDuration": "Role Block Duration",
|
||||
"RoleBlockCooldown": "Role Block Cooldown",
|
||||
"BKProtectDuration": "Protection Duration",
|
||||
"TotocalcioMaxBetTimes": "Maximum Number of Follows",
|
||||
"TotocalcioBetCooldown": "Follow Cooldown",
|
||||
@@ -2124,7 +2131,6 @@
|
||||
"TabGroup.Addons": "Add-Ons",
|
||||
"TabGroup.OtherRoles": "Ghost Roles",
|
||||
"TabGroup.TaskSettings": "Game Modifiers",
|
||||
"TabGroup.CovenRoles": "Coven Roles",
|
||||
"OtherRoles.CrewmateRoles": "★ Crewmate Roles",
|
||||
"OtherRoles.NeutralRoles": "★ Neutral Roles",
|
||||
"OtherRoles.ImpostorRoles": "★ Impostor Roles",
|
||||
@@ -2309,6 +2315,8 @@
|
||||
"FarseerKillButtonText": "Reveal",
|
||||
"PoisonerKillButtonText": "Poison",
|
||||
"SentryPetButtonText": "Monitor",
|
||||
"SabotageActiveIndicator": "▶",
|
||||
"SabotageDisabledIndicator": "⊘",
|
||||
"DisabledBySettings": "Disabled by Settings",
|
||||
"Disabled": "Disabled",
|
||||
"FailToTrack": "Failed To Track",
|
||||
@@ -2797,7 +2805,6 @@
|
||||
"Escort": "Escort",
|
||||
"EscortInfo": "Role-Block Players to Help the Crew!",
|
||||
"EscortInfoLong": "(Crewmates):\\nAs the Escort, you can role-block a player for a specified time using your kill button. A role-blocked player cannot kill, vent, sabotage or report.\\n(Role-Block duration is the same as the hack duration for The Glitch)",
|
||||
"EscortCD": "Role-Block Cooldown",
|
||||
"EscortBlockDuration": "Role-Block Duration",
|
||||
"EscortTargetHacked": "Target successfully role-blocked",
|
||||
"EscortKillButtonText": "Role-Block",
|
||||
|
||||
@@ -2308,7 +2308,7 @@
|
||||
"MonarchKillButtonText": "Посвятить",
|
||||
"FarseerKillButtonText": "Раскрыть",
|
||||
"SentryPetButtonText": "Сенсор",
|
||||
"PoisonerKillButtonText": "Отравить"
|
||||
"PoisonerKillButtonText": "Отравить",
|
||||
"DisabledBySettings": "Выключено настройками",
|
||||
"Disabled": "Выключено",
|
||||
"FailToTrack": "Не удалось отследить",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace EHR.Roles.AddOns.Common
|
||||
{
|
||||
internal class Flash : IAddon
|
||||
internal class Flashman : IAddon
|
||||
{
|
||||
public AddonTypes Type => AddonTypes.Helpful;
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using EHR.Modules;
|
||||
using Hazel;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -88,7 +87,6 @@ namespace EHR.Roles.Crewmate
|
||||
{
|
||||
TargetArrow.RemoveAllTarget(id);
|
||||
LocateArrow.RemoveAllTarget(id);
|
||||
Utils.SendRPC(CustomRPC.SetBloodhoundArrow, id, 1);
|
||||
}
|
||||
|
||||
BloodhoundTargets.Clear();
|
||||
@@ -105,7 +103,6 @@ namespace EHR.Roles.Crewmate
|
||||
|
||||
var pos = target.Pos();
|
||||
LocateArrow.Add(id, pos);
|
||||
Utils.SendRPC(CustomRPC.SetBloodhoundArrow, id, 2, pos);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,13 +117,11 @@ namespace EHR.Roles.Crewmate
|
||||
|
||||
var pos = target.Object.Pos();
|
||||
LocateArrow.Remove(pc.PlayerId, pos);
|
||||
Utils.SendRPC(CustomRPC.SetBloodhoundArrow, pc.PlayerId, 3, pos);
|
||||
|
||||
if (pc.GetAbilityUseLimit() >= 1)
|
||||
{
|
||||
BloodhoundTargets.Add(killer.PlayerId);
|
||||
TargetArrow.Add(pc.PlayerId, killer.PlayerId);
|
||||
Utils.SendRPC(CustomRPC.SetBloodhoundArrow, pc.PlayerId, 4, killer.PlayerId);
|
||||
|
||||
pc.Notify(GetString("BloodhoundTrackRecorded"));
|
||||
pc.RpcRemoveAbilityUse();
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using AmongUs.GameOptions;
|
||||
using EHR.Roles.Neutral;
|
||||
using static EHR.Translator;
|
||||
|
||||
namespace EHR.Roles.Crewmate
|
||||
@@ -12,18 +11,24 @@ namespace EHR.Roles.Crewmate
|
||||
|
||||
private static OptionItem CD;
|
||||
private static OptionItem UseLimit;
|
||||
private static OptionItem Duration;
|
||||
public static OptionItem UsePet;
|
||||
|
||||
public override bool IsEnable => playerIdList.Count > 0;
|
||||
|
||||
public static void SetupCustomOption()
|
||||
{
|
||||
Options.SetupSingleRoleOptions(Id, TabGroup.CrewmateRoles, CustomRoles.Escort);
|
||||
CD = FloatOptionItem.Create(Id + 10, "EscortCD", new(2.5f, 60f, 2.5f), 30f, TabGroup.CrewmateRoles)
|
||||
CD = FloatOptionItem.Create(Id + 10, "RoleBlockCooldown", new(2.5f, 60f, 2.5f), 30f, TabGroup.CrewmateRoles)
|
||||
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Escort])
|
||||
.SetValueFormat(OptionFormat.Seconds);
|
||||
UseLimit = IntegerOptionItem.Create(Id + 11, "AbilityUseLimit", new(1, 20, 1), 3, TabGroup.CrewmateRoles)
|
||||
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Escort])
|
||||
.SetValueFormat(OptionFormat.Times);
|
||||
UsePet = Options.CreatePetUseSetting(Id + 12, CustomRoles.Escort);
|
||||
Duration = FloatOptionItem.Create(Id + 13, "RoleBlockDuration", new(1f, 60f, 1f), 15f, TabGroup.CrewmateRoles)
|
||||
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Escort])
|
||||
.SetValueFormat(OptionFormat.Seconds);
|
||||
}
|
||||
|
||||
public override void Init()
|
||||
@@ -42,8 +47,6 @@ namespace EHR.Roles.Crewmate
|
||||
Main.ResetCamPlayerList.Add(playerId);
|
||||
}
|
||||
|
||||
public override bool IsEnable => playerIdList.Count > 0;
|
||||
|
||||
public override void SetKillCooldown(byte playerId)
|
||||
{
|
||||
Main.AllPlayerKillCooldown[playerId] = playerId.GetAbilityUseLimit() > 0 ? CD.GetFloat() : 300f;
|
||||
@@ -58,7 +61,7 @@ namespace EHR.Roles.Crewmate
|
||||
|
||||
killer.RpcRemoveAbilityUse();
|
||||
killer.SetKillCooldown();
|
||||
Glitch.hackedIdList.TryAdd(target.PlayerId, Utils.TimeStamp);
|
||||
target.BlockRole(Duration.GetFloat());
|
||||
killer.Notify(GetString("EscortTargetHacked"));
|
||||
|
||||
return false;
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using EHR.Modules;
|
||||
using Hazel;
|
||||
using UnityEngine;
|
||||
using static EHR.Options;
|
||||
|
||||
@@ -36,32 +34,6 @@ public class Mortician : RoleBase
|
||||
playerIdList.Add(playerId);
|
||||
}
|
||||
|
||||
private static void SendRPC(byte playerId, bool add, Vector3 loc = new())
|
||||
{
|
||||
if (!Utils.DoRPC) return;
|
||||
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetMorticianArrow, SendOption.Reliable);
|
||||
writer.Write(playerId);
|
||||
writer.Write(add);
|
||||
if (add)
|
||||
{
|
||||
writer.Write(loc.x);
|
||||
writer.Write(loc.y);
|
||||
writer.Write(loc.z);
|
||||
}
|
||||
|
||||
AmongUsClient.Instance.FinishRpcImmediately(writer);
|
||||
}
|
||||
|
||||
public static void ReceiveRPC(MessageReader reader)
|
||||
{
|
||||
byte playerId = reader.ReadByte();
|
||||
bool add = reader.ReadBoolean();
|
||||
if (add)
|
||||
LocateArrow.Add(playerId, new(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()));
|
||||
else
|
||||
LocateArrow.RemoveAllTarget(playerId);
|
||||
}
|
||||
|
||||
public static void OnPlayerDead(PlayerControl target)
|
||||
{
|
||||
var pos = target.Pos();
|
||||
@@ -84,7 +56,6 @@ public class Mortician : RoleBase
|
||||
var player = Utils.GetPlayerById(pc);
|
||||
if (player == null || !player.IsAlive()) continue;
|
||||
LocateArrow.Add(pc, target.transform.position);
|
||||
SendRPC(pc, true, target.transform.position);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +64,6 @@ public class Mortician : RoleBase
|
||||
foreach (byte apc in playerIdList)
|
||||
{
|
||||
LocateArrow.RemoveAllTarget(apc);
|
||||
SendRPC(apc, false);
|
||||
}
|
||||
|
||||
if (!pc.Is(CustomRoles.Mortician) || target == null || pc.PlayerId == target.PlayerId) return;
|
||||
|
||||
@@ -271,7 +271,7 @@ namespace EHR.Roles.Crewmate
|
||||
{
|
||||
var pc = PickRandomPlayer();
|
||||
AddEffectForPlayer(pc, effect);
|
||||
Glitch.hackedIdList.TryAdd(pc.PlayerId, Utils.TimeStamp);
|
||||
pc.BlockRole(IRandom.Instance.Next(MinimumEffectDuration, MaximumEffectDuration));
|
||||
NotifyAboutRNG(pc);
|
||||
}
|
||||
break;
|
||||
@@ -281,7 +281,7 @@ namespace EHR.Roles.Crewmate
|
||||
foreach (var pc in Main.AllAlivePlayerControls)
|
||||
{
|
||||
AddEffectForPlayer(pc, effect);
|
||||
Glitch.hackedIdList.TryAdd(pc.PlayerId, now);
|
||||
pc.BlockRole(IRandom.Instance.Next(MinimumEffectDuration, MaximumEffectDuration));
|
||||
NotifyAboutRNG(pc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using AmongUs.GameOptions;
|
||||
using EHR.Modules;
|
||||
using Hazel;
|
||||
using UnityEngine;
|
||||
using static EHR.Options;
|
||||
|
||||
@@ -50,44 +48,17 @@ public class Tracefinder : RoleBase
|
||||
On = true;
|
||||
}
|
||||
|
||||
private static void SendRPC(byte playerId, bool add, Vector3 loc = new())
|
||||
{
|
||||
if (!Utils.DoRPC) return;
|
||||
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetTracefinderArrow, SendOption.Reliable);
|
||||
writer.Write(playerId);
|
||||
writer.Write(add);
|
||||
if (add)
|
||||
{
|
||||
writer.Write(loc.x);
|
||||
writer.Write(loc.y);
|
||||
writer.Write(loc.z);
|
||||
}
|
||||
|
||||
AmongUsClient.Instance.FinishRpcImmediately(writer);
|
||||
}
|
||||
|
||||
public override void ApplyGameOptions(IGameOptions opt, byte id)
|
||||
{
|
||||
AURoleOptions.ScientistCooldown = VitalsCooldown.GetFloat();
|
||||
AURoleOptions.ScientistBatteryCharge = VitalsDuration.GetFloat();
|
||||
}
|
||||
|
||||
public static void ReceiveRPC(MessageReader reader)
|
||||
{
|
||||
byte playerId = reader.ReadByte();
|
||||
bool add = reader.ReadBoolean();
|
||||
if (add)
|
||||
LocateArrow.Add(playerId, new(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()));
|
||||
else
|
||||
LocateArrow.RemoveAllTarget(playerId);
|
||||
}
|
||||
|
||||
public override void OnReportDeadBody()
|
||||
{
|
||||
foreach (byte apc in playerIdList)
|
||||
{
|
||||
LocateArrow.RemoveAllTarget(apc);
|
||||
SendRPC(apc, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +80,6 @@ public class Tracefinder : RoleBase
|
||||
PlayerControl pc = Utils.GetPlayerById(id);
|
||||
if (pc == null || !pc.IsAlive()) continue;
|
||||
LocateArrow.Add(id, target.transform.position);
|
||||
SendRPC(id, true, target.transform.position);
|
||||
Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,6 @@ namespace EHR.Roles.Crewmate
|
||||
Utils.GetPlayerById(trackerId).RpcRemoveAbilityUse();
|
||||
|
||||
TrackerTarget[trackerId].Add(targetId);
|
||||
TargetArrow.Add(trackerId, targetId);
|
||||
}
|
||||
|
||||
public static string GetTargetMark(PlayerControl seer, PlayerControl target) => !(seer == null || target == null) && TrackerTarget.ContainsKey(seer.PlayerId) && TrackerTarget[seer.PlayerId].Contains(target.PlayerId) ? Utils.ColorString(seer.GetRoleColor(), "◀") : string.Empty;
|
||||
|
||||
@@ -82,7 +82,6 @@ public class BountyHunter : RoleBase
|
||||
public void ReceiveRPC(byte bountyId, byte targetId)
|
||||
{
|
||||
Target = targetId;
|
||||
if (ShowTargetArrow) TargetArrow.Add(bountyId, targetId);
|
||||
}
|
||||
|
||||
public override bool OnCheckMurder(PlayerControl killer, PlayerControl target)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using EHR.Roles.Neutral;
|
||||
using static EHR.Translator;
|
||||
|
||||
namespace EHR.Roles.Impostor
|
||||
@@ -11,16 +10,22 @@ namespace EHR.Roles.Impostor
|
||||
|
||||
private static OptionItem CD;
|
||||
private static OptionItem UseLimit;
|
||||
private static OptionItem Duration;
|
||||
|
||||
public override bool IsEnable => playerIdList.Count > 0;
|
||||
|
||||
public static void SetupCustomOption()
|
||||
{
|
||||
Options.SetupRoleOptions(Id, TabGroup.ImpostorRoles, CustomRoles.Consort);
|
||||
CD = FloatOptionItem.Create(Id + 10, "EscortCD", new(2.5f, 60f, 2.5f), 30f, TabGroup.ImpostorRoles)
|
||||
CD = FloatOptionItem.Create(Id + 10, "RoleBlockCooldown", new(2.5f, 60f, 2.5f), 30f, TabGroup.ImpostorRoles)
|
||||
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Consort])
|
||||
.SetValueFormat(OptionFormat.Seconds);
|
||||
UseLimit = IntegerOptionItem.Create(Id + 11, "AbilityUseLimit", new(1, 20, 1), 3, TabGroup.ImpostorRoles)
|
||||
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Consort])
|
||||
.SetValueFormat(OptionFormat.Times);
|
||||
Duration = FloatOptionItem.Create(Id + 12, "RoleBlockDuration", new(1f, 60f, 1f), 15f, TabGroup.ImpostorRoles)
|
||||
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Consort])
|
||||
.SetValueFormat(OptionFormat.Seconds);
|
||||
}
|
||||
|
||||
public override void Init()
|
||||
@@ -34,8 +39,6 @@ namespace EHR.Roles.Impostor
|
||||
playerId.SetAbilityUseLimit(UseLimit.GetInt());
|
||||
}
|
||||
|
||||
public override bool IsEnable => playerIdList.Count > 0;
|
||||
|
||||
public override bool OnCheckMurder(PlayerControl killer, PlayerControl target)
|
||||
{
|
||||
if (!IsEnable || killer == null || target == null) return false;
|
||||
@@ -44,7 +47,7 @@ namespace EHR.Roles.Impostor
|
||||
return killer.CheckDoubleTrigger(target, () =>
|
||||
{
|
||||
killer.RpcRemoveAbilityUse();
|
||||
Glitch.hackedIdList.TryAdd(target.PlayerId, Utils.TimeStamp);
|
||||
target.BlockRole(Duration.GetFloat());
|
||||
killer.Notify(GetString("EscortTargetHacked"));
|
||||
killer.SetKillCooldown(CD.GetFloat());
|
||||
});
|
||||
|
||||
@@ -237,7 +237,7 @@ namespace EHR.Roles.Impostor
|
||||
SendRPCSyncPistolCD();
|
||||
}
|
||||
|
||||
public override string GetProgressText(byte id, bool comms) => string.Format(GetString("MafiosoProgressText"), Tier, XP);
|
||||
public override string GetProgressText(byte id, bool comms) => id.IsPlayerModClient() ? string.Empty : string.Format(GetString("MafiosoProgressText"), Tier, XP);
|
||||
|
||||
public override string GetSuffix(PlayerControl pc, PlayerControl _, bool hud = false, bool m = false)
|
||||
{
|
||||
|
||||
@@ -136,6 +136,7 @@ namespace EHR.Roles.Impostor
|
||||
|
||||
public override string GetSuffix(PlayerControl seer, PlayerControl target, bool hud = false, bool m = false)
|
||||
{
|
||||
if (seer.IsModClient() && !hud) return string.Empty;
|
||||
if (Main.PlayerStates[seer.PlayerId].Role is YinYanger { IsEnable: true } yy && seer.PlayerId == target.PlayerId)
|
||||
{
|
||||
return yy.YinYangedPlayers.Count == 2 ? $"<color=#00ffa5>{Translator.GetString("Mode")}:</color> {Translator.GetString("YinYangModeNormal")}" : $"<color=#00ffa5>{Translator.GetString("Mode")}:</color> {Translator.GetString("YinYangMode")} ({yy.YinYangedPlayers.Count}/2)";
|
||||
|
||||
@@ -14,8 +14,6 @@ public class Glitch : RoleBase
|
||||
private const int Id = 18125;
|
||||
public static List<byte> playerIdList = [];
|
||||
|
||||
public static Dictionary<byte, long> hackedIdList = [];
|
||||
|
||||
public static OptionItem KillCooldown;
|
||||
public static OptionItem HackCooldown;
|
||||
public static OptionItem HackDuration;
|
||||
@@ -62,7 +60,6 @@ public class Glitch : RoleBase
|
||||
public override void Init()
|
||||
{
|
||||
playerIdList = [];
|
||||
hackedIdList = [];
|
||||
GlitchId = byte.MaxValue;
|
||||
}
|
||||
|
||||
@@ -168,7 +165,7 @@ public class Glitch : RoleBase
|
||||
{
|
||||
Utils.NotifyRoles(SpecifySeer: killer, SpecifyTarget: target);
|
||||
HackCDTimer = HackCooldown.GetInt();
|
||||
hackedIdList.TryAdd(target.PlayerId, Utils.TimeStamp);
|
||||
target.BlockRole(HackDuration.GetFloat());
|
||||
LastHack = Utils.TimeStamp;
|
||||
SendRPCSyncTimers();
|
||||
}
|
||||
@@ -195,23 +192,8 @@ public class Glitch : RoleBase
|
||||
if (MimicCDTimer is > 180 or < 0) MimicCDTimer = 0;
|
||||
if (MimicDurTimer is > 180 or < 0) MimicDurTimer = 0;
|
||||
|
||||
bool change = false;
|
||||
foreach (var pc in hackedIdList)
|
||||
{
|
||||
if (pc.Value + HackDuration.GetInt() < now)
|
||||
{
|
||||
hackedIdList.Remove(pc.Key);
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (player == null) return;
|
||||
|
||||
if (change)
|
||||
{
|
||||
Utils.NotifyRoles(SpecifySeer: player);
|
||||
}
|
||||
|
||||
if (!player.IsAlive())
|
||||
{
|
||||
HackCDTimer = 0;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AmongUs.GameOptions;
|
||||
using EHR.Modules;
|
||||
using Hazel;
|
||||
using UnityEngine;
|
||||
using static EHR.Options;
|
||||
using static EHR.Translator;
|
||||
@@ -91,38 +89,11 @@ public class Vulture : RoleBase
|
||||
AURoleOptions.EngineerInVentMaxTime = 0f;
|
||||
}
|
||||
|
||||
private static void SendRPC(byte playerId, bool add, Vector3 loc = new())
|
||||
{
|
||||
if (!Utils.DoRPC) return;
|
||||
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetVultureArrow, SendOption.Reliable);
|
||||
writer.Write(playerId);
|
||||
writer.Write(add);
|
||||
if (add)
|
||||
{
|
||||
writer.Write(loc.x);
|
||||
writer.Write(loc.y);
|
||||
writer.Write(loc.z);
|
||||
}
|
||||
|
||||
AmongUsClient.Instance.FinishRpcImmediately(writer);
|
||||
}
|
||||
|
||||
public static void ReceiveRPC(MessageReader reader)
|
||||
{
|
||||
byte playerId = reader.ReadByte();
|
||||
bool add = reader.ReadBoolean();
|
||||
if (add)
|
||||
LocateArrow.Add(playerId, new(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()));
|
||||
else
|
||||
LocateArrow.RemoveAllTarget(playerId);
|
||||
}
|
||||
|
||||
public static void Clear()
|
||||
{
|
||||
foreach (byte apc in playerIdList)
|
||||
{
|
||||
LocateArrow.RemoveAllTarget(apc);
|
||||
SendRPC(apc, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,7 +115,6 @@ public class Vulture : RoleBase
|
||||
Utils.GetPlayerById(apc).Notify(GetString("VultureCooldownUp"));
|
||||
}
|
||||
}, VultureReportCD.GetFloat(), "Vulture CD");
|
||||
SendRPC(apc, false);
|
||||
Utils.NotifyRoles(SpecifySeer: player, SpecifyTarget: player);
|
||||
}
|
||||
}
|
||||
@@ -159,7 +129,6 @@ public class Vulture : RoleBase
|
||||
var player = Utils.GetPlayerById(pc);
|
||||
if (player == null || !player.IsAlive()) continue;
|
||||
LocateArrow.Add(pc, target.transform.position);
|
||||
SendRPC(pc, true, target.transform.position);
|
||||
Utils.NotifyRoles(SpecifySeer: player, SpecifyTarget: player);
|
||||
}
|
||||
}
|
||||
@@ -177,7 +146,6 @@ public class Vulture : RoleBase
|
||||
foreach (byte apc in playerIdList)
|
||||
{
|
||||
LocateArrow.Remove(apc, target.Object.transform.position);
|
||||
SendRPC(apc, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,8 +28,8 @@ public class Main : BasePlugin
|
||||
public const string DebugKeyHash = "c0fd562955ba56af3ae20d7ec9e64c664f0facecef4b3e366e109306adeae29d";
|
||||
public const string DebugKeySalt = "59687b";
|
||||
public const string PluginGuid = "com.gurge44.endlesshostroles";
|
||||
public const string PluginVersion = "3.3.0";
|
||||
public const string PluginDisplayVersion = "3.3.0";
|
||||
public const string PluginVersion = "3.4.0";
|
||||
public const string PluginDisplayVersion = "3.4.0";
|
||||
public const string NeutralColor = "#ffab1b";
|
||||
public const string ImpostorColor = "#ff1919";
|
||||
public const string CrewmateColor = "#8cffff";
|
||||
|
||||