mirror of
https://github.com/Gurge44/EndlessHostRoles.git
synced 2026-10-20 01:46:25 +00:00
Start Analyzer, Add /up access, Fix bugs
This commit is contained in:
1 parent
7484c6fb7a
commit
0ccf84c03c
32 files changed
+281
-40
No files matched your search
@@ -129,7 +129,7 @@ public static class Camouflage
|
||||
{
|
||||
//コミュサボ解除または強制解除
|
||||
|
||||
if (Main.CheckShapeshift.TryGetValue(id, out var shapeshifting) && shapeshifting && !RevertToDefault)
|
||||
if (Utils.GetPlayerById(id).shapeshifting && !RevertToDefault)
|
||||
{
|
||||
//シェイプシフターなら今の姿のidに変更
|
||||
id = Main.ShapeshiftTarget[id];
|
||||
|
||||
@@ -107,6 +107,7 @@ internal static class CustomRolesHelper
|
||||
CustomRoles.Aid => CustomRoles.Impostor,
|
||||
CustomRoles.Escort => CustomRoles.Impostor,
|
||||
CustomRoles.DonutDelivery => CustomRoles.Impostor,
|
||||
CustomRoles.Analyzer => CustomRoles.Impostor,
|
||||
CustomRoles.Escapee => Options.UsePets.GetBool() ? CustomRoles.Impostor : CustomRoles.Shapeshifter,
|
||||
CustomRoles.NiceGuesser => CustomRoles.Crewmate,
|
||||
CustomRoles.EvilGuesser => CustomRoles.Impostor,
|
||||
@@ -229,6 +230,7 @@ internal static class CustomRolesHelper
|
||||
CustomRoles.Ricochet => CustomRoles.CrewmateTOHE,
|
||||
CustomRoles.Aid => CustomRoles.CrewmateTOHE,
|
||||
CustomRoles.DonutDelivery => CustomRoles.CrewmateTOHE,
|
||||
CustomRoles.Analyzer => CustomRoles.CrewmateTOHE,
|
||||
CustomRoles.Escort => CustomRoles.CrewmateTOHE,
|
||||
CustomRoles.Doormaster => CustomRoles.EngineerTOHE,
|
||||
CustomRoles.Tether => CustomRoles.EngineerTOHE,
|
||||
@@ -289,6 +291,7 @@ internal static class CustomRolesHelper
|
||||
CustomRoles.Aid => RoleTypes.Impostor,
|
||||
CustomRoles.Escort => RoleTypes.Impostor,
|
||||
CustomRoles.DonutDelivery => RoleTypes.Impostor,
|
||||
CustomRoles.Analyzer => RoleTypes.Impostor,
|
||||
CustomRoles.Witness => RoleTypes.Impostor,
|
||||
CustomRoles.Pursuer => RoleTypes.Impostor,
|
||||
CustomRoles.Revolutionist => RoleTypes.Impostor,
|
||||
@@ -911,6 +914,7 @@ internal static class CustomRolesHelper
|
||||
CustomRoles.Witness or
|
||||
CustomRoles.Aid or
|
||||
CustomRoles.DonutDelivery or
|
||||
CustomRoles.Analyzer or
|
||||
CustomRoles.Escort or
|
||||
CustomRoles.Totocalcio or
|
||||
CustomRoles.Farseer or
|
||||
@@ -1033,6 +1037,7 @@ internal static class CustomRolesHelper
|
||||
CustomRoles.Aid or
|
||||
CustomRoles.Escort or
|
||||
CustomRoles.DonutDelivery or
|
||||
CustomRoles.Analyzer or
|
||||
CustomRoles.Witness or
|
||||
CustomRoles.Monarch or
|
||||
CustomRoles.Jailor or
|
||||
@@ -1084,6 +1089,7 @@ internal static class CustomRolesHelper
|
||||
//CustomRoles.Counterfeiter or
|
||||
CustomRoles.Aid or
|
||||
CustomRoles.DonutDelivery or
|
||||
CustomRoles.Analyzer or
|
||||
CustomRoles.Escort or
|
||||
CustomRoles.Witness or
|
||||
CustomRoles.Monarch or
|
||||
|
||||
@@ -66,6 +66,9 @@ public static class DevManager
|
||||
|
||||
DevUserList.Add(new(code: "radarright#2509", color: "null", tag: "null", isUp: false, isDev: false, deBug: true, colorCmd: false, upName: null));
|
||||
|
||||
// TOHE+ players
|
||||
DevUserList.Add(new(code: "crustzonal#9589", color: "#00ffff", tag: "Translator PT-BR", isUp: true, isDev: false, deBug: false, colorCmd: false, upName: "artyleague01"));
|
||||
|
||||
// Sponsor
|
||||
DevUserList.Add(new(code: "recentduct#6068", color: "#FF00FF", tag: "高冷男模法师", isUp: false, isDev: false, colorCmd: false, deBug: true, upName: null));
|
||||
DevUserList.Add(new(code: "canneddrum#2370", color: "#fffcbe", tag: "我是喜唉awa", isUp: false, isDev: false, colorCmd: false, deBug: false, upName: null));
|
||||
@@ -77,7 +80,7 @@ public static class DevManager
|
||||
DevUserList.Add(new(code: "mallcasual#6075", color: "#f89ccb", tag: "波奇酱", isUp: false, isDev: false, colorCmd: false, deBug: false, upName: null));
|
||||
DevUserList.Add(new(code: "beamelfin#9478", color: "#6495ED", tag: "Amaster-1111", isUp: false, isDev: false, colorCmd: false, deBug: false, upName: null));
|
||||
DevUserList.Add(new(code: "lordcosy#8966", color: "#FFD6EC", tag: "HostTOHE", isUp: false, isDev: false, colorCmd: false, deBug: false, upName: null)); //K
|
||||
// DevUserList.Add(new(code: "honestsofa#2870", color: "#D381D9", tag: "Discord: SolarFlare#0700", isUp: true, isDev: false, colorCmd: false, deBug: false, upName: "SolarFlare")); //SolarFlare
|
||||
DevUserList.Add(new(code: "honestsofa#2870", color: "#D381D9", tag: "Discord: SolarFlare#0700", isUp: true, isDev: false, colorCmd: false, deBug: false, upName: "SolarFlare")); //SolarFlare
|
||||
DevUserList.Add(new(code: "caseeast#7194", color: "#1c2451", tag: "disc.gg/maul", isUp: false, isDev: false, colorCmd: false, deBug: false, upName: null)); //laikrai
|
||||
// lol hi go away
|
||||
//DevUserList.Add(new(code: "gnuedaphic#7196", color: "#ffc0cb", tag: "TOH-RE Developer", isUp: true, isDev: false, deBug: false, colorCmd: true, upName: "Loonie")); //Loonie
|
||||
|
||||
@@ -529,6 +529,7 @@ static class ExtendedPlayerControl
|
||||
CustomRoles.Innocent => true,
|
||||
CustomRoles.Aid => true,
|
||||
CustomRoles.DonutDelivery => true,
|
||||
CustomRoles.Analyzer => true,
|
||||
CustomRoles.Escort => true,
|
||||
CustomRoles.Witness => true,
|
||||
CustomRoles.Pursuer => true,
|
||||
@@ -644,6 +645,7 @@ static class ExtendedPlayerControl
|
||||
CustomRoles.Aid => pc.IsAlive() && Aid.UseLimit[pc.PlayerId] >= 1,
|
||||
CustomRoles.Escort => pc.IsAlive() && Escort.BlockLimit >= 1,
|
||||
CustomRoles.DonutDelivery => pc.IsAlive() && DonutDelivery.DeliverLimit >= 1,
|
||||
CustomRoles.Analyzer => pc.IsAlive() && Analyzer.CanUseKillButton,
|
||||
CustomRoles.Witness => pc.IsAlive(),
|
||||
CustomRoles.Pursuer => Pursuer.CanUseKillButton(pc.PlayerId),
|
||||
CustomRoles.Morphling => Morphling.CanUseKillButton(pc.PlayerId),
|
||||
@@ -784,6 +786,7 @@ static class ExtendedPlayerControl
|
||||
//CustomRoles.Counterfeiter or
|
||||
CustomRoles.Aid or
|
||||
CustomRoles.DonutDelivery or
|
||||
CustomRoles.Analyzer or
|
||||
CustomRoles.Escort or
|
||||
CustomRoles.Pursuer or
|
||||
CustomRoles.Revolutionist or
|
||||
@@ -1097,6 +1100,9 @@ static class ExtendedPlayerControl
|
||||
case CustomRoles.DonutDelivery:
|
||||
DonutDelivery.SetKillCooldown(player.PlayerId);
|
||||
break;
|
||||
case CustomRoles.Analyzer:
|
||||
Analyzer.SetKillCooldown(player.PlayerId);
|
||||
break;
|
||||
case CustomRoles.Witness:
|
||||
Main.AllPlayerKillCooldown[player.PlayerId] = Options.WitnessCD.GetFloat();
|
||||
break;
|
||||
|
||||
@@ -219,6 +219,7 @@ public class PlayerGameOptionsSender(PlayerControl player) : GameOptionsSender
|
||||
case CustomRoles.Aid:
|
||||
case CustomRoles.Escort:
|
||||
case CustomRoles.DonutDelivery:
|
||||
case CustomRoles.Analyzer:
|
||||
case CustomRoles.Witness:
|
||||
case CustomRoles.Succubus:
|
||||
case CustomRoles.CursedSoul:
|
||||
|
||||
@@ -16,7 +16,7 @@ public class MeetingTimeManager
|
||||
{
|
||||
DefaultDiscussionTime = Main.RealOptionsData.GetInt(Int32OptionNames.DiscussionTime);
|
||||
DefaultVotingTime = Main.RealOptionsData.GetInt(Int32OptionNames.VotingTime);
|
||||
Logger.Info($"DefaultDiscussionTime:{DefaultDiscussionTime}, DefaultVotingTime{DefaultVotingTime}", "MeetingTimeManager.Init");
|
||||
Logger.Info($"DefaultDiscussionTime: {DefaultDiscussionTime}s, DefaultVotingTime: {DefaultVotingTime}s", "MeetingTimeManager.Init");
|
||||
ResetMeetingTime();
|
||||
}
|
||||
public static void ApplyGameOptions(IGameOptions opt)
|
||||
|
||||
@@ -1508,6 +1508,8 @@ public static class Options
|
||||
Ricochet.SetupCustomOption();
|
||||
RoleLoadingText = "Crewmate roles\nEscort";
|
||||
Escort.SetupCustomOption();
|
||||
RoleLoadingText = "Crewmate roles\nAnalyzer";
|
||||
Analyzer.SetupCustomOption();
|
||||
RoleLoadingText = "Crewmate roles\nDonut Delivery";
|
||||
DonutDelivery.SetupCustomOption();
|
||||
RoleLoadingText = "Crewmate roles\nAid";
|
||||
|
||||
@@ -58,6 +58,9 @@ enum CustomRPC
|
||||
|
||||
//Roles
|
||||
SetDrawPlayer,
|
||||
SyncYinYanger,
|
||||
SyncAnalyzer,
|
||||
SyncAnalyzerTarget,
|
||||
SyncCantankerousLimit,
|
||||
SyncDuellistTarget,
|
||||
SetDruidLimit,
|
||||
@@ -437,6 +440,12 @@ internal class RPCHandlerPatch
|
||||
case CustomRPC.SniperSync:
|
||||
Sniper.ReceiveRPC(reader);
|
||||
break;
|
||||
case CustomRPC.SyncAnalyzer:
|
||||
Analyzer.ReceiveRPC(reader);
|
||||
break;
|
||||
case CustomRPC.SyncAnalyzerTarget:
|
||||
Analyzer.ReceiveRPCSyncTarget(reader);
|
||||
break;
|
||||
case CustomRPC.SpyRedNameSync:
|
||||
Spy.ReceiveRPC(reader);
|
||||
break;
|
||||
@@ -458,6 +467,9 @@ internal class RPCHandlerPatch
|
||||
case CustomRPC.SetRicochetTarget:
|
||||
Ricochet.ReceiveRPCSyncTarget(reader);
|
||||
break;
|
||||
case CustomRPC.SyncYinYanger:
|
||||
YinYanger.ReceiveRPC(reader);
|
||||
break;
|
||||
case CustomRPC.SetTetherTarget:
|
||||
Tether.ReceiveRPCSyncTarget(reader);
|
||||
break;
|
||||
@@ -1185,6 +1197,9 @@ internal static class RPC
|
||||
case CustomRoles.DonutDelivery:
|
||||
DonutDelivery.Add(targetId);
|
||||
break;
|
||||
case CustomRoles.Analyzer:
|
||||
Analyzer.Add(targetId);
|
||||
break;
|
||||
case CustomRoles.Aid:
|
||||
Aid.Add(targetId);
|
||||
break;
|
||||
|
||||
@@ -17,9 +17,9 @@ public static class Translator
|
||||
public const string LANGUAGE_FOLDER_NAME = "Language";
|
||||
public static void Init()
|
||||
{
|
||||
Logger.Info("加载语言文件...", "Translator");
|
||||
Logger.Info("Loading language file...", "Translator");
|
||||
LoadLangs();
|
||||
Logger.Info("加载语言文件成功", "Translator");
|
||||
Logger.Info("Language file loaded successfully", "Translator");
|
||||
}
|
||||
public static void LoadLangs()
|
||||
{
|
||||
@@ -152,14 +152,14 @@ public static class Translator
|
||||
}
|
||||
catch (KeyNotFoundException)
|
||||
{
|
||||
Logger.Warn($"无效密钥:{tmp[0]}", "LoadCustomTranslation");
|
||||
Logger.Warn($"Invalid key:{tmp[0]}", "LoadCustomTranslation");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Error($"找不到自定义翻译文件:{filename}", "LoadCustomTranslation");
|
||||
Logger.Error($"Custom translation file not found:{filename}", "LoadCustomTranslation");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -568,6 +568,7 @@ public static class Utils
|
||||
case CustomRoles.Aid:
|
||||
case CustomRoles.Escort:
|
||||
case CustomRoles.DonutDelivery:
|
||||
case CustomRoles.Analyzer:
|
||||
case CustomRoles.Witness:
|
||||
case CustomRoles.Pursuer:
|
||||
case CustomRoles.Spiritcaller:
|
||||
|
||||
@@ -66,8 +66,70 @@ internal class ShowDisconnectPopupPatch
|
||||
if (StringReason.Contains("Reliable packet")) __instance.SetText(GetString("DCNotify.DCFromServer"));
|
||||
else if (StringReason.Contains("remote has not responded to")) __instance.SetText(GetString("DCNotify.DCFromServer"));
|
||||
break;
|
||||
case DisconnectReasons.ExitGame:
|
||||
break;
|
||||
case DisconnectReasons.InvalidName:
|
||||
break;
|
||||
case DisconnectReasons.ConnectionLimit:
|
||||
break;
|
||||
case DisconnectReasons.Destroy:
|
||||
break;
|
||||
case DisconnectReasons.IncorrectGame:
|
||||
break;
|
||||
case DisconnectReasons.ServerRequest:
|
||||
break;
|
||||
case DisconnectReasons.ServerFull:
|
||||
break;
|
||||
case DisconnectReasons.InternalPlayerMissing:
|
||||
break;
|
||||
case DisconnectReasons.InternalNonceFailure:
|
||||
break;
|
||||
case DisconnectReasons.InternalConnectionToken:
|
||||
break;
|
||||
case DisconnectReasons.PlatformLock:
|
||||
break;
|
||||
case DisconnectReasons.MatchmakerInactivity:
|
||||
break;
|
||||
case DisconnectReasons.NoServersAvailable:
|
||||
break;
|
||||
case DisconnectReasons.QuickmatchDisabled:
|
||||
break;
|
||||
case DisconnectReasons.TooManyGames:
|
||||
break;
|
||||
case DisconnectReasons.QuickchatLock:
|
||||
break;
|
||||
case DisconnectReasons.MatchmakerFull:
|
||||
break;
|
||||
case DisconnectReasons.Sanctions:
|
||||
break;
|
||||
case DisconnectReasons.ServerError:
|
||||
break;
|
||||
case DisconnectReasons.SelfPlatformLock:
|
||||
break;
|
||||
case DisconnectReasons.TooManyRequests:
|
||||
break;
|
||||
case DisconnectReasons.IntentionalLeaving:
|
||||
break;
|
||||
case DisconnectReasons.FocusLostBackground:
|
||||
break;
|
||||
case DisconnectReasons.FocusLost:
|
||||
break;
|
||||
case DisconnectReasons.NewConnection:
|
||||
break;
|
||||
case DisconnectReasons.PlatformParentalControlsBlock:
|
||||
break;
|
||||
case DisconnectReasons.PlatformUserBlock:
|
||||
break;
|
||||
case DisconnectReasons.PlatformFailedToGetUserBlock:
|
||||
break;
|
||||
case DisconnectReasons.ServerNotFound:
|
||||
break;
|
||||
case DisconnectReasons.ClientTimeout:
|
||||
break;
|
||||
case DisconnectReasons.Unknown:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}, 0.01f, "Override Disconnect Text");
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-2
@@ -57,7 +57,7 @@ class HudManagerPatch
|
||||
|
||||
Utils.CountAlivePlayers();
|
||||
|
||||
bool shapeshifting = Main.CheckShapeshift.TryGetValue(player.PlayerId, out bool ss) && ss;
|
||||
bool shapeshifting = player.shapeshifting;
|
||||
|
||||
if (SetHudActivePatch.IsActive)
|
||||
{
|
||||
@@ -149,6 +149,9 @@ class HudManagerPatch
|
||||
//case CustomRoles.Counterfeiter:
|
||||
// __instance.KillButton.OverrideText(GetString("CounterfeiterButtonText"));
|
||||
// break;
|
||||
case CustomRoles.Analyzer:
|
||||
__instance.KillButton?.OverrideText(GetString("AnalyzerKillButtonText"));
|
||||
break;
|
||||
case CustomRoles.Witness:
|
||||
__instance.KillButton?.OverrideText(GetString("WitnessButtonText"));
|
||||
break;
|
||||
@@ -671,7 +674,7 @@ class SetHudActivePatch
|
||||
|
||||
}
|
||||
|
||||
if (Main.PlayerStates[player.PlayerId].SubRoles.Contains(CustomRoles.Oblivious))
|
||||
if (Main.PlayerStates.TryGetValue(player.PlayerId, out var ps) && ps.SubRoles.Contains(CustomRoles.Oblivious))
|
||||
{
|
||||
__instance.ReportButton?.ToggleVisible(false);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ public static class HudSpritePatch
|
||||
return;
|
||||
}
|
||||
|
||||
bool shapeshifting = Main.CheckShapeshift.TryGetValue(player.PlayerId, out bool ss) && ss;
|
||||
bool shapeshifting = player.shapeshifting;
|
||||
|
||||
if (!Kill) Kill = __instance.KillButton.graphic.sprite;
|
||||
if (!Ability) Ability = __instance.AbilityButton.graphic.sprite;
|
||||
@@ -231,6 +231,7 @@ public static class HudSpritePatch
|
||||
else
|
||||
newPetButton = CustomButton.Get("Mine");
|
||||
break;
|
||||
case CustomRoles.Analyzer:
|
||||
case CustomRoles.Witness:
|
||||
newKillButton = CustomButton.Get("Examine");
|
||||
break;
|
||||
|
||||
@@ -447,7 +447,7 @@ class BeginImpostorPatch
|
||||
__instance.overlayHandle.color = Palette.ImpostorRed;
|
||||
return true;
|
||||
}
|
||||
else if (role is CustomRoles.Sheriff or CustomRoles.Jailor or CustomRoles.SwordsMan or CustomRoles.Medic/* or CustomRoles.Counterfeiter*/ or CustomRoles.Witness or CustomRoles.Aid or CustomRoles.Escort or CustomRoles.DonutDelivery or CustomRoles.Monarch or CustomRoles.Farseer or CustomRoles.Admirer or CustomRoles.Deputy)
|
||||
else if (role is CustomRoles.Sheriff or CustomRoles.Jailor or CustomRoles.SwordsMan or CustomRoles.Medic/* or CustomRoles.Counterfeiter*/ or CustomRoles.Witness or CustomRoles.Analyzer or CustomRoles.Aid or CustomRoles.Escort or CustomRoles.DonutDelivery or CustomRoles.Monarch or CustomRoles.Farseer or CustomRoles.Admirer or CustomRoles.Deputy)
|
||||
{
|
||||
yourTeam = new Il2CppSystem.Collections.Generic.List<PlayerControl>();
|
||||
yourTeam.Add(PlayerControl.LocalPlayer);
|
||||
|
||||
@@ -217,6 +217,9 @@ class CheckMurderPatch
|
||||
case CustomRoles.Magician:
|
||||
Magician.OnCheckMurder(killer);
|
||||
break;
|
||||
case CustomRoles.Analyzer:
|
||||
Analyzer.OnCheckMurder(killer, target);
|
||||
return false;
|
||||
case CustomRoles.DonutDelivery:
|
||||
DonutDelivery.OnCheckMurder(killer, target);
|
||||
return false;
|
||||
@@ -229,12 +232,6 @@ class CheckMurderPatch
|
||||
case CustomRoles.Cantankerous:
|
||||
if (Cantankerous.OnCheckMurder(killer)) return false;
|
||||
break;
|
||||
case CustomRoles.Blackmailer:
|
||||
if (!killer.CheckDoubleTrigger(target, () =>
|
||||
{
|
||||
Blackmailer.ForBlackmailer.Add(target.PlayerId);
|
||||
})) return false;
|
||||
break;
|
||||
case CustomRoles.Postman:
|
||||
Postman.OnCheckMurder(killer, target);
|
||||
return false;
|
||||
@@ -324,7 +321,7 @@ class CheckMurderPatch
|
||||
break;
|
||||
case CustomRoles.Warlock:
|
||||
if (!Main.isCurseAndKill.ContainsKey(killer.PlayerId)) Main.isCurseAndKill[killer.PlayerId] = false;
|
||||
if (!Main.CheckShapeshift[killer.PlayerId] && !Main.isCurseAndKill[killer.PlayerId])
|
||||
if (!killer.shapeshifting && !Main.isCurseAndKill[killer.PlayerId])
|
||||
{ //Warlockが変身時以外にキルしたら、呪われる処理
|
||||
if (target.Is(CustomRoles.Needy) || target.Is(CustomRoles.Lazy)) return false;
|
||||
Main.isCursed = true;
|
||||
@@ -337,7 +334,7 @@ class CheckMurderPatch
|
||||
//RPC.RpcSyncCurseAndKill();
|
||||
return false;
|
||||
}
|
||||
if (Main.CheckShapeshift[killer.PlayerId])
|
||||
if (killer.shapeshifting)
|
||||
{//呪われてる人がいないくて変身してるときに通常キルになる
|
||||
killer.RpcCheckAndMurder(target);
|
||||
return false;
|
||||
@@ -1337,6 +1334,10 @@ class ShapeshiftPatch
|
||||
Sapper.OnShapeshift(shapeshifter);
|
||||
isSSneeded = false;
|
||||
break;
|
||||
case CustomRoles.Blackmailer:
|
||||
Blackmailer.ForBlackmailer.Add(target.PlayerId);
|
||||
isSSneeded = false;
|
||||
break;
|
||||
case CustomRoles.Warlock:
|
||||
if (Main.CursedPlayers[shapeshifter.PlayerId] != null)//呪われた人がいるか確認
|
||||
{
|
||||
@@ -3238,6 +3239,9 @@ class EnterVentPatch
|
||||
case CustomRoles.Addict:
|
||||
Addict.OnEnterVent(pc, __instance);
|
||||
break;
|
||||
case CustomRoles.CameraMan:
|
||||
CameraMan.OnEnterVent(pc);
|
||||
break;
|
||||
case CustomRoles.Alchemist:
|
||||
Alchemist.OnEnterVent(pc, __instance.Id);
|
||||
break;
|
||||
|
||||
@@ -231,6 +231,7 @@ internal class ChangeRoleSettings
|
||||
Benefactor.Init();
|
||||
Aid.Init();
|
||||
DonutDelivery.Init();
|
||||
Analyzer.Init();
|
||||
Escort.Init();
|
||||
Consort.Init();
|
||||
Drainer.Init();
|
||||
@@ -686,6 +687,9 @@ internal class SelectRolesPatch
|
||||
case CustomRoles.DonutDelivery:
|
||||
DonutDelivery.Add(pc.PlayerId);
|
||||
break;
|
||||
case CustomRoles.Analyzer:
|
||||
Analyzer.Add(pc.PlayerId);
|
||||
break;
|
||||
case CustomRoles.Pursuer:
|
||||
Pursuer.Add(pc.PlayerId);
|
||||
break;
|
||||
|
||||
@@ -965,7 +965,6 @@
|
||||
"DisableCalibrateDistributor","禁用校准分电器任务","Disable Calibrate Distributor Task","Отключить Задание ''Откалибровать Распределитель''","",""
|
||||
"DisableChartCourse","禁用标出航线任务","Disable Chart Course Task","Отключить Задание ''Проложить Маршрут''","",""
|
||||
"DisableStabilizeSteering","禁用稳定航向任务","Disable Stabilize Steering Task","Отключить Задание ''Выровнять Курс''","",""
|
||||
"DisableCleanO2Filter","禁用清理树叶任务","Disable Clean O2 Filter Task","Отключить Задание ''Очистить Фильтр O2''","",""
|
||||
"DisableCleanO2Filter","禁用清理氧气过滤器任务","Disable Clean O2 Filter Task","Отключить Задание ''Очистить Фильтр O2''","",""
|
||||
"DisableUnlockManifolds","禁用解锁歧管任务","Disable Unlock Manifolds Task","Отключить Задание ''Открыть Коллекторы''","",""
|
||||
"DisablePrimeShields","禁用开启护盾任务","Disable Prime Shields Task","Отключить Задание ''Запустить Щиты''","",""
|
||||
@@ -1099,9 +1098,6 @@
|
||||
"AllOpen","","Open All","","",""
|
||||
"RandomByDoor","","Random","","",""
|
||||
"KickAndroidPlayer","踢出使用安卓的玩家","Kick mobile players","Кикнуть игроков которые зашли в лобби через телефон","踢出使用Android平台遊玩的玩家","踢出使用安卓的玩家"
|
||||
"KickXboxPlayer","踢出Xbox玩家","Kick Xbox players","","",""
|
||||
"KickPlayStationPlayer","踢出PS玩家","Kick PlayStation players","","",""
|
||||
"KickNintendoPlayer","踢出任天堂Switch玩家","Kick Nintendo Switch players","","",""
|
||||
"ShareLobby","允许车队姬自动群发您的房号","Allow TOHE-Chan Shares Lobby Code To Discord","Отправлять код вашей комнаты в Discord сервер TOHE (Больше не рабоатет)","允許車隊姬自動發送您的房號至Discord","Allow TOHE-chan share your lobby code to Discord"
|
||||
"ShareLobbyMinPlayer","房间人数达到多少时群发","Share Lobby Code When The Number Of Players Reaches","Минимально игроков для отправки кода","房間人數達到多少時發送",""
|
||||
"DisableVanillaRoles","禁用原版职业","Disable Vanilla Roles","Отключить ванильные Роли","禁用原版職業","禁用原版职业"
|
||||
@@ -1136,7 +1132,6 @@
|
||||
"DisableSkeldCamera","禁用骷髅舰监控","Disable Cameras","Отключить Камеры","禁用The Skeld監控","禁用骷髅舰监控"
|
||||
"DisablePolusCamera","禁用波鲁斯监控设备","Disable Cameras","Отключить Камеры","禁用Polus監控","禁用波鲁斯监控设备"
|
||||
"DisableAirshipCamera","禁用飞艇监控","Disable Cameras","Отключить Камеры","禁用The Airship監控","禁用飞艇监控"
|
||||
"DisableFungleCamera","","Disable Cameras","","",""
|
||||
"DisableMiraHQDoorLog","禁用米拉总部门禁记录","Disable DoorLog","Отключить Журналы","禁用Mira HQ通行紀錄","禁用米拉总部门禁记录"
|
||||
"DisablePolusVital","禁用波鲁斯生命监测装置","Disable Vitals","Отключить Пульсы","禁用Polus心電圖","禁用波鲁斯生命监测装置"
|
||||
"DisableAirshipVital","禁用飞艇生命监测装置","Disable Vitals","Отключить Пульсы","禁用The Airship心電圖","禁用飞艇生命监测装置"
|
||||
@@ -2500,7 +2495,7 @@
|
||||
"DivinatorCheck.Result14","<b>{0}</b>是隐匿者、市长、被害妄想症、小偷或卫道士其中之一","<b>{0}</b> is either Anonymous, Mastermind, Spy, Mayor, Paranoid, Pickpocket, or Vindicator","","",""
|
||||
"DivinatorCheck.Result15","<b>{0}</b>是传染性的、病毒的、君主的、革命者的或魅魔的其中之一","<b>{0}</b> is either Infectious, Virus, Agitater, Monarch, Revolutionist, Express, or Cultist","","",""
|
||||
"DivinatorCheck.Result16","<b>{0}</b>是冤罪师、受虐狂、抑制者、修理工或破坏者其中之一","<b>{0}</b> is either Innocent, Sapper, Refugee, Bandit, Inhibitor, Mechanic, or Saboteur","","",""
|
||||
"DivinatorCheck.Result17","<b>{0}</b>是医生、马里奥、小丑、潜伏者还是阳光开朗大男孩其中之一","<b>{0}</b> is either Medic, Vector, RiftMaker, Jester, The Glitch, Lurker, or Sunnyboy","","",""
|
||||
"DivinatorCheck.Result17","<b>{0}</b>是医生、马里奥、小丑、潜伏者还是阳光开朗大男孩其中之一","<b>{0}</b> is either Medic, Vector, Analyzer, RiftMaker, Jester, The Glitch, Lurker, or Sunnyboy","","",""
|
||||
"DivinatorCheck.Result18","<b>{0}</b>是黑手党、惩罚者、教父、缺点者、幸运儿或失败者其中之一","<b>{0}</b> is either Nemesis, Hitman, Retributionist, Gangster, Glitch, Luckey, or Underdog","","",""
|
||||
"DivinatorCheck.Result19","<b>{0}</b>是邪恶赌怪、正义赌怪、潜藏者、梦魇、隐蔽者或变色龙其中之一","<b>{0}</b> is either Evil Guesser, Nice Guesser, Blackmailer, Eclipse, Reckless, Stalker, Camouflager, or Chameleon","","",""
|
||||
"DivinatorCheck.Result20","<b>{0}</b>是豺狼、跟班、独行者、投机者、追击者或自爆卡车其中之一","<b>{0}</b> is either Jackal, Sidekick, Duellist, WeaponMaster, Maverick, Opportunist, Pursuer, or Provocateur","","",""
|
||||
@@ -2553,7 +2548,7 @@
|
||||
"pet_test","","Glitch Pet","","",""
|
||||
"pet_GuiltySpark","","Guilty Spark","","",""
|
||||
"pet_Stickmin","","H. Stickmin","","",""
|
||||
"pet_HamPet","","Hammy","","",""
|
||||
"## pet_HamPet","","Hammy","","",""
|
||||
"pet_Hamster","","Hampton","","",""
|
||||
"pet_Alien","","Headslug","","",""
|
||||
"pet_poro","","Heimerdinger's Poro","","",""
|
||||
@@ -2688,7 +2683,6 @@
|
||||
"Consort","","Consort","","",""
|
||||
"ConsortInfo","","Role-Block and Kill Players","","",""
|
||||
"ConsortInfoLong","","(Impostors):\nAs the Consort, you can role-block a player which prevents them from killing, venting, sabotaging and reporting for some time by clicking your kill button on them once. Double click with your kill button on them to kill them normally.\n(The role-block duraiton is the same as the hack duration for The Glitch)","","",""
|
||||
"Consort","","Consort","","",""
|
||||
|
||||
"## Donut Delivery"
|
||||
"DonutDelivery","","Donut Delivery","","",""
|
||||
@@ -2817,7 +2811,6 @@
|
||||
"PlagueDoctorInfectInactiveTime","","Infect Invalid Time","","",""
|
||||
"PlagueDoctorCanInfectSelf","","Can Infect Self","","",""
|
||||
"PlagueDoctorCanInfectVent","","Can Infect While In Vent","","",""
|
||||
"PlagueDoctorInfectDistance","","Infect Distance","","",""
|
||||
|
||||
"## Penguin"
|
||||
"Penguin","","Penguin","","",""
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -0,0 +1,130 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static TOHE.Options;
|
||||
using static TOHE.Utils;
|
||||
using static TOHE.Translator;
|
||||
using Hazel;
|
||||
|
||||
namespace TOHE.Roles.Crewmate
|
||||
{
|
||||
internal class Analyzer
|
||||
{
|
||||
private static readonly int Id = 643100;
|
||||
private static byte playerId = byte.MaxValue;
|
||||
private static int UseLimit = 0;
|
||||
|
||||
private static OptionItem UseLimitOpt;
|
||||
private static OptionItem CD;
|
||||
private static OptionItem Duration;
|
||||
private static OptionItem SeeKillCount;
|
||||
private static OptionItem SeeVentCount;
|
||||
private static OptionItem SeeRoleBasis;
|
||||
|
||||
public static Dictionary<byte, int> VentCount = [];
|
||||
private static (byte, long) CurrentTarget = (byte.MaxValue, GetTimeStamp());
|
||||
|
||||
public static void SetupCustomOption()
|
||||
{
|
||||
SetupSingleRoleOptions(Id, TabGroup.CrewmateRoles, CustomRoles.Analyzer, 1);
|
||||
UseLimitOpt = IntegerOptionItem.Create(Id + 10, "AbilityUseLimit", new(0, 5, 1), 3, TabGroup.CrewmateRoles, false)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Analyzer])
|
||||
.SetValueFormat(OptionFormat.Times);
|
||||
CD = FloatOptionItem.Create(Id + 11, "AnalyzeCD", new(0f, 60f, 2.5f), 15f, TabGroup.CrewmateRoles, false)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Analyzer])
|
||||
.SetValueFormat(OptionFormat.Seconds);
|
||||
Duration = IntegerOptionItem.Create(Id + 12, "AnalyzeDur", new(1, 30, 1), 5, TabGroup.CrewmateRoles, false)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Analyzer])
|
||||
.SetValueFormat(OptionFormat.Seconds);
|
||||
SeeKillCount = BooleanOptionItem.Create(Id + 13, "AnalyzerSeeKillCount", true, TabGroup.CrewmateRoles, false)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Analyzer]);
|
||||
SeeVentCount = BooleanOptionItem.Create(Id + 14, "AnalyzerSeeVentCount", true, TabGroup.CrewmateRoles, false)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Analyzer]);
|
||||
SeeRoleBasis = BooleanOptionItem.Create(Id + 15, "AnalyzerSeeRoleBasis", true, TabGroup.CrewmateRoles, false)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Analyzer]);
|
||||
}
|
||||
|
||||
public static bool CanUseKillButton =>
|
||||
|
||||
private static string GetRoleBasis(CustomRoles role)
|
||||
{
|
||||
var DYRole = role.GetDYRole();
|
||||
var VNRole = role.GetVNRole();
|
||||
if (DYRole == AmongUs.GameOptions.RoleTypes.Impostor) return ColorString(GetRoleColor(CustomRoles.Impostor), GetString("Impostor"));
|
||||
else return VNRole switch
|
||||
{
|
||||
CustomRoles.Impostor => ColorString(GetRoleColor(CustomRoles.Impostor), GetString("Impostor")),
|
||||
CustomRoles.Shapeshifter => ColorString(GetRoleColor(CustomRoles.Speedrunner), GetString("Shapeshifter")),
|
||||
CustomRoles.Crewmate => ColorString(GetRoleColor(CustomRoles.Crewmate), GetString("Crewmate")),
|
||||
CustomRoles.Engineer => ColorString(GetRoleColor(CustomRoles.Autocrat), GetString("Engineer")),
|
||||
CustomRoles.Scientist => ColorString(GetRoleColor(CustomRoles.Doctor), GetString("Scientist")),
|
||||
_ => string.Empty
|
||||
};
|
||||
}
|
||||
|
||||
private static int GetKillCount(byte id) => Main.PlayerStates.Count(x => x.Value.GetRealKiller() == id);
|
||||
|
||||
private static int GetVentCount(byte id) => VentCount.TryGetValue(id, out var count) ? count : 0;
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
playerId = byte.MaxValue;
|
||||
UseLimit = 0;
|
||||
VentCount = [];
|
||||
CurrentTarget = (byte.MaxValue, GetTimeStamp());
|
||||
}
|
||||
|
||||
public static void Add(byte id)
|
||||
{
|
||||
playerId = id;
|
||||
UseLimit = UseLimitOpt.GetInt();
|
||||
|
||||
if (!AmongUsClient.Instance.AmHost) return;
|
||||
if (!Main.ResetCamPlayerList.Contains(id))
|
||||
Main.ResetCamPlayerList.Add(id);
|
||||
}
|
||||
|
||||
private static void SendRPCSyncTarget()
|
||||
{
|
||||
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SyncAnalyzerTarget, SendOption.Reliable, -1);
|
||||
writer.Write(CurrentTarget.Item1);
|
||||
writer.Write(CurrentTarget.Item2);
|
||||
AmongUsClient.Instance.FinishRpcImmediately(writer);
|
||||
}
|
||||
|
||||
public static void ReceiveRPCSyncTarget(MessageReader reader)
|
||||
{
|
||||
var item1 = reader.ReadByte();
|
||||
var item2 = long.Parse(reader.ReadString());
|
||||
CurrentTarget = (item1, item2);
|
||||
}
|
||||
|
||||
public static void SendRPC()
|
||||
{
|
||||
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SyncAnalyzer, SendOption.Reliable, -1);
|
||||
writer.Write(UseLimit);
|
||||
writer.Write(VentCount.Count);
|
||||
foreach (var item in VentCount)
|
||||
{
|
||||
writer.Write(item.Key);
|
||||
writer.Write(item.Value);
|
||||
}
|
||||
AmongUsClient.Instance.FinishRpcImmediately(writer);
|
||||
}
|
||||
|
||||
public static void ReceiveRPC(MessageReader reader)
|
||||
{
|
||||
UseLimit = reader.ReadInt32();
|
||||
|
||||
int length = reader.ReadInt32();
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
var key = reader.ReadByte();
|
||||
var value = reader.ReadInt32();
|
||||
VentCount.Add(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -200,6 +200,7 @@ public static class CopyCat
|
||||
//bcoz im lazy
|
||||
CustomRoles.Escort or
|
||||
CustomRoles.DonutDelivery or
|
||||
CustomRoles.Analyzer or
|
||||
//bcoz of arrows
|
||||
CustomRoles.Mortician or
|
||||
CustomRoles.Bloodhound or
|
||||
|
||||
@@ -250,6 +250,7 @@ public static class Divinator
|
||||
CustomRoles.Mario or
|
||||
CustomRoles.Jester or
|
||||
CustomRoles.RiftMaker or
|
||||
CustomRoles.Analyzer or
|
||||
CustomRoles.Lurker or
|
||||
CustomRoles.Glitch or
|
||||
CustomRoles.Sunnyboy
|
||||
|
||||
@@ -43,6 +43,7 @@ namespace TOHE.Roles.Crewmate
|
||||
CustomRoles.NiceHacker,
|
||||
CustomRoles.Aid,
|
||||
CustomRoles.DonutDelivery,
|
||||
CustomRoles.Analyzer,
|
||||
CustomRoles.Escort,
|
||||
CustomRoles.Tether,
|
||||
CustomRoles.Spy,
|
||||
|
||||
@@ -55,7 +55,7 @@ internal static class Assassin
|
||||
MarkedPlayer.Add(playerId, targetId);
|
||||
}
|
||||
private static bool Shapeshifting(this PlayerControl pc) => pc.PlayerId.Shapeshifting();
|
||||
private static bool Shapeshifting(this byte id) => Main.CheckShapeshift.TryGetValue(id, out bool shapeshifting) && shapeshifting;
|
||||
private static bool Shapeshifting(this byte id) => Utils.GetPlayerById(id).shapeshifting;
|
||||
public static void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = id.Shapeshifting() ? DefaultKillCooldown : MarkCooldown.GetFloat();
|
||||
public static void ApplyGameOptions() => AURoleOptions.ShapeshifterCooldown = AssassinateCooldown.GetFloat();
|
||||
public static bool CanUseKillButton(PlayerControl pc)
|
||||
|
||||
@@ -15,8 +15,9 @@ public static class Blackmailer
|
||||
public static void SetupCustomOption()
|
||||
{
|
||||
SetupRoleOptions(Id, TabGroup.OtherRoles, CustomRoles.Blackmailer);
|
||||
SkillCooldown = FloatOptionItem.Create(Id + 5, "BlackmailerSkillCooldown", new(2.5f, 60f, 2.5f), 30f, TabGroup.OtherRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Blackmailer])
|
||||
.SetValueFormat(OptionFormat.Seconds);
|
||||
SkillCooldown = FloatOptionItem.Create(Id + 5, "BlackmailerSkillCooldown", new(2.5f, 60f, 2.5f), 30f, TabGroup.OtherRoles, false)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Blackmailer])
|
||||
.SetValueFormat(OptionFormat.Seconds);
|
||||
}
|
||||
public static void Init()
|
||||
{
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace TOHE.Roles.Impostor
|
||||
|
||||
private static void SendRPC(byte playerId, bool isPlus)
|
||||
{
|
||||
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetDruidLimit, SendOption.Reliable, -1);
|
||||
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SyncCantankerousLimit, SendOption.Reliable, -1);
|
||||
writer.Write(playerId);
|
||||
writer.Write(isPlus);
|
||||
AmongUsClient.Instance.FinishRpcImmediately(writer);
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace TOHE.Roles.Impostor
|
||||
|
||||
private static void SendRPC(byte duellistId, byte targetId)
|
||||
{
|
||||
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetDruidLimit, SendOption.Reliable, -1);
|
||||
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SyncDuellistTarget, SendOption.Reliable, -1);
|
||||
writer.Write(duellistId);
|
||||
writer.Write(targetId);
|
||||
AmongUsClient.Instance.FinishRpcImmediately(writer);
|
||||
|
||||
@@ -59,10 +59,10 @@ public static class Hangman
|
||||
|
||||
if (HangLimit[killer.PlayerId] < 1)
|
||||
{
|
||||
if (Main.CheckShapeshift.TryGetValue(killer.PlayerId, out var ss) && ss) return false;
|
||||
if (killer.shapeshifting) return false;
|
||||
};
|
||||
|
||||
if (Main.CheckShapeshift.TryGetValue(killer.PlayerId, out var s) && s)
|
||||
if (killer.shapeshifting)
|
||||
{
|
||||
if (target.Is(CustomRoles.Pestilence)) return false;
|
||||
if (target.Is(CustomRoles.Veteran) && Main.VeteranInProtect.ContainsKey(target.PlayerId)) return false;
|
||||
|
||||
@@ -37,7 +37,7 @@ public static class Morphling
|
||||
}
|
||||
public static bool CanUseKillButton(byte playerId)
|
||||
=> !Main.PlayerStates[playerId].IsDead
|
||||
&& Main.CheckShapeshift[playerId];
|
||||
&& Utils.GetPlayerById(playerId).shapeshifting;
|
||||
|
||||
public static void ApplyGameOptions()
|
||||
{
|
||||
|
||||
@@ -71,6 +71,10 @@ namespace TOHE.Roles.Impostor
|
||||
DonutDelivery.DeliverLimit--;
|
||||
DonutDelivery.SendRPC();
|
||||
break;
|
||||
case CustomRoles.Analyzer:
|
||||
Analyzer.UseLimit--;
|
||||
Analyzer.SendRPC();
|
||||
break;
|
||||
case CustomRoles.Bloodhound:
|
||||
Bloodhound.UseLimit[target.PlayerId]--;
|
||||
Bloodhound.SendRPCPlus(target.PlayerId);
|
||||
|
||||
@@ -55,7 +55,7 @@ internal static class Undertaker
|
||||
MarkedPlayer.Add(playerId, targetId);
|
||||
}
|
||||
private static bool Shapeshifting(this PlayerControl pc) => pc.PlayerId.Shapeshifting();
|
||||
private static bool Shapeshifting(this byte id) => Main.CheckShapeshift.TryGetValue(id, out bool shapeshifting) && shapeshifting;
|
||||
private static bool Shapeshifting(this byte id) => Utils.GetPlayerById(id).shapeshifting;
|
||||
public static void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = id.Shapeshifting() ? DefaultKillCooldown : MarkCooldown.GetFloat();
|
||||
public static void ApplyGameOptions()
|
||||
{
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace TOHE.Roles.Impostor
|
||||
|
||||
public static void SendRPC(bool isClear, byte playerId = byte.MaxValue)
|
||||
{
|
||||
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetDruidLimit, SendOption.Reliable, -1);
|
||||
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SyncYinYanger, SendOption.Reliable, -1);
|
||||
writer.Write(isClear);
|
||||
if (!isClear) writer.Write(playerId);
|
||||
AmongUsClient.Instance.FinishRpcImmediately(writer);
|
||||
|
||||
@@ -130,7 +130,7 @@ public static class Doppelganger
|
||||
{
|
||||
|
||||
if (killer == null || target == null || !IsEnable || Camouflage.IsCamouflage || Camouflager.IsActive) return;
|
||||
if (Main.CheckShapeshift.TryGetValue(target.PlayerId, out bool isShapeshifitng) && isShapeshifitng)
|
||||
if (target.shapeshifting)
|
||||
{
|
||||
Logger.Info("Target was shapeshifting", "Doppelganger");
|
||||
return;
|
||||
|
||||
@@ -370,6 +370,7 @@ public class Main : BasePlugin
|
||||
{CustomRoles.NiceHacker, "#75fa4c"},
|
||||
{CustomRoles.Aid, "#D7BDE2"},
|
||||
{CustomRoles.DonutDelivery, "#a46efa"},
|
||||
{CustomRoles.Analyzer, "#33ddff"},
|
||||
{CustomRoles.Escort, "#ff94e6"},
|
||||
{CustomRoles.Spy, "#34495E"},
|
||||
{CustomRoles.Doormaster, "#7FB3D5"},
|
||||
@@ -738,6 +739,7 @@ public enum CustomRoles
|
||||
GuessManager,
|
||||
Escort,
|
||||
DonutDelivery,
|
||||
Analyzer,
|
||||
Mayor,
|
||||
Jailor,
|
||||
Paranoia,
|
||||
|
||||
Reference in new issue
Block a user