ban some combos, rename some roles in system

This commit is contained in:
HyperAtill committed 2025-08-25 17:00:35 +03:00
1 parent 2ec0ca13c2
commit a82c1b43db
23 files changed
+675 -674

No files matched your search

+4 -4
View File
@@ -74,10 +74,10 @@ public enum CustomRoles
Mafioso,
Mastermind,
Mafia, // Nemesis
SerialKiller, // Mercenary
Mercenary,
Miner,
Morphling,
Assassin, // Ninja
Ninja,
Nuker,
Nullifier,
Occultist,
@@ -285,7 +285,7 @@ public enum CustomRoles
Collector,
Curser,
Deathknight,
Gamer, // Demon
Demon,
Doppelganger,
Doomsayer,
Eclipse,
@@ -347,7 +347,7 @@ public enum CustomRoles
Samurai,
SchrodingersCat,
Seamstress,
NSerialKiller, // Serial Killer
SerialKiller,
Shifter,
Sidekick,
Simon,
+1 -1
View File
@@ -203,7 +203,7 @@ internal static class HotPotato
if (CanPassViaKillButton)
{
target.RpcChangeRoleBasis(CustomRoles.NSerialKiller);
target.RpcChangeRoleBasis(CustomRoles.SerialKiller);
LateTask.New(() => target.SetKillCooldown(1f), 0.2f, log: false);
}
+1 -1
View File
@@ -500,7 +500,7 @@ public static class Quiz
spectators.Do(x => x.ExileTemporarily());
yield return new WaitForSeconds(0.2f);
var stillLiving = dyingPlayers.ToValidPlayers().FindAll(x => x.IsAlive());
stillLiving.ForEach(x => x.RpcChangeRoleBasis(CustomRoles.NSerialKiller));
stillLiving.ForEach(x => x.RpcChangeRoleBasis(CustomRoles.SerialKiller));
Utils.SendRPC(CustomRPC.QuizSync, AllowKills);
while (Utils.TimeStamp < FFAEndTS)
+1 -1
View File
@@ -76,7 +76,7 @@ public static class Speedrun
Utils.SendRPC(CustomRPC.SpeedrunSync, 2, pc.PlayerId);
int kcd = KillCooldown.GetInt();
Main.AllPlayerKillCooldown[pc.PlayerId] = kcd;
pc.RpcChangeRoleBasis(CustomRoles.NSerialKiller);
pc.RpcChangeRoleBasis(CustomRoles.SerialKiller);
pc.Notify(Translator.GetString("Speedrun_CompletedTasks"));
pc.SyncSettings();
LateTask.New(() => pc.SetKillCooldown(kcd), 0.2f, log: false);
+4 -4
View File
@@ -514,7 +514,7 @@ public class Main : BasePlugin
{ CustomRoles.Revolutionist, "#ba4d06" },
{ CustomRoles.FFF, "#414b66" },
{ CustomRoles.Konan, "#4d4dff" },
{ CustomRoles.Gamer, "#68bc71" },
{ CustomRoles.Demon, "#68bc71" },
{ CustomRoles.DarkHide, "#483d8b" },
{ CustomRoles.Workaholic, "#008b8b" },
{ CustomRoles.Collector, "#9d8892" },
@@ -531,7 +531,7 @@ public class Main : BasePlugin
{ CustomRoles.Deathknight, "#361d12" },
{ CustomRoles.HexMaster, "#ff00ff" },
{ CustomRoles.Wraith, "#4B0082" },
{ CustomRoles.NSerialKiller, "#233fcc" },
{ CustomRoles.SerialKiller, "#233fcc" },
{ CustomRoles.Slenderman, "#2c2e00" },
{ CustomRoles.Amogus, "#ff0000" },
{ CustomRoles.Weatherman, "#347deb" },
@@ -995,7 +995,7 @@ public enum CustomWinner
Pelican = CustomRoles.Pelican,
Youtuber = CustomRoles.Youtuber,
Egoist = CustomRoles.Egoist,
Gamer = CustomRoles.Gamer,
Demon = CustomRoles.Demon,
DarkHide = CustomRoles.DarkHide,
Workaholic = CustomRoles.Workaholic,
Collector = CustomRoles.Collector,
@@ -1006,7 +1006,7 @@ public enum CustomWinner
Succubus = CustomRoles.Succubus,
Necromancer = CustomRoles.Necromancer,
Wraith = CustomRoles.Wraith,
SerialKiller = CustomRoles.NSerialKiller,
SerialKiller = CustomRoles.SerialKiller,
Slenderman = CustomRoles.Slenderman,
Amogus = CustomRoles.Amogus,
Weatherman = CustomRoles.Weatherman,
+18 -17
View File
@@ -77,7 +77,7 @@ internal static class CustomRolesHelper
{
// Roles that use the same code as another role need to be handled here
CustomRoles.Nuker => new Bomber(),
CustomRoles.Undertaker => new Assassin(),
CustomRoles.Undertaker => new Ninja(),
CustomRoles.Chameleon => new Swooper(),
CustomRoles.BloodKnight => new Wildling(),
CustomRoles.HexMaster => new Witch(),
@@ -138,7 +138,7 @@ internal static class CustomRolesHelper
CustomRoles.Wildling => Wildling.CanShapeshiftOpt.GetBool() ? CustomRoles.Shapeshifter : CustomRoles.Impostor,
CustomRoles.Morphling => CustomRoles.Shapeshifter,
CustomRoles.Warlock => UsePets ? CustomRoles.Impostor : CustomRoles.Shapeshifter,
CustomRoles.SerialKiller => CustomRoles.Impostor,
CustomRoles.Mercenary => CustomRoles.Impostor,
CustomRoles.FireWorks => CustomRoles.Shapeshifter,
CustomRoles.SpeedBooster => CustomRoles.Crewmate,
CustomRoles.Dictator => CustomRoles.Crewmate,
@@ -198,7 +198,7 @@ internal static class CustomRolesHelper
CustomRoles.SuperStar => CustomRoles.Crewmate,
CustomRoles.Hacker => CustomRoles.Shapeshifter,
CustomRoles.Visionary => CustomRoles.Shapeshifter,
CustomRoles.Assassin => CustomRoles.Phantom,
CustomRoles.Ninja => CustomRoles.Phantom,
CustomRoles.Undertaker => UsePets ? CustomRoles.Impostor : CustomRoles.Shapeshifter,
CustomRoles.Luckey => CustomRoles.Crewmate,
CustomRoles.Demolitionist => CustomRoles.Crewmate,
@@ -465,7 +465,7 @@ internal static class CustomRolesHelper
CustomRoles.Revolutionist => RoleTypes.Impostor,
CustomRoles.FFF => RoleTypes.Impostor,
CustomRoles.Medic => UsePets && Medic.UsePet.GetBool() ? RoleTypes.GuardianAngel : RoleTypes.Impostor,
CustomRoles.Gamer => RoleTypes.Impostor,
CustomRoles.Demon => RoleTypes.Impostor,
CustomRoles.HexMaster => RoleTypes.Impostor,
CustomRoles.Wraith => RoleTypes.Impostor,
CustomRoles.Glitch => RoleTypes.Shapeshifter,
@@ -476,7 +476,7 @@ internal static class CustomRolesHelper
CustomRoles.Provocateur => RoleTypes.Impostor,
CustomRoles.BloodKnight => RoleTypes.Impostor,
CustomRoles.Poisoner => RoleTypes.Impostor,
CustomRoles.NSerialKiller => RoleTypes.Impostor,
CustomRoles.SerialKiller => RoleTypes.Impostor,
CustomRoles.Slenderman => RoleTypes.Impostor,
CustomRoles.Amogus => RoleTypes.Impostor,
CustomRoles.Weatherman => RoleTypes.Impostor,
@@ -583,7 +583,7 @@ internal static class CustomRolesHelper
CustomRoles.HexMaster or
CustomRoles.Doppelganger or
CustomRoles.Succubus or
CustomRoles.Gamer or
CustomRoles.Demon or
CustomRoles.Crewpostor or
CustomRoles.Hypocrite or
CustomRoles.Cherokious or
@@ -604,7 +604,7 @@ internal static class CustomRolesHelper
CustomRoles.Patroller or
CustomRoles.Rogue or
CustomRoles.Parasite or
CustomRoles.NSerialKiller or
CustomRoles.SerialKiller or
CustomRoles.Slenderman or
CustomRoles.Amogus or
CustomRoles.Weatherman or
@@ -677,13 +677,13 @@ internal static class CustomRolesHelper
CustomRoles.Vindicator or
CustomRoles.Zombie or
CustomRoles.Warlock or
CustomRoles.Assassin or
CustomRoles.Ninja or
CustomRoles.Undertaker or
CustomRoles.Hacker or
CustomRoles.Visionary or
CustomRoles.Miner or
CustomRoles.Escapee or
CustomRoles.SerialKiller or
CustomRoles.Mercenary or
CustomRoles.Overheat or
CustomRoles.Abyssbringer or
CustomRoles.Echo or
@@ -1003,7 +1003,7 @@ internal static class CustomRolesHelper
CustomRoles.Librarian or
CustomRoles.Miner or
CustomRoles.RiftMaker or
CustomRoles.Assassin or
CustomRoles.Ninja or
CustomRoles.QuickShooter or
CustomRoles.Sapper or
CustomRoles.Sniper or
@@ -1042,7 +1042,7 @@ internal static class CustomRolesHelper
CustomRoles.Introvert when pc.GetCustomRole() is CustomRoles.Leery or CustomRoles.Samurai or CustomRoles.Arsonist or CustomRoles.Revolutionist or CustomRoles.Farseer or CustomRoles.Scavenger or CustomRoles.Analyst => false,
CustomRoles.Circumvent when pc.GetCustomRole() is CustomRoles.Swooper or CustomRoles.RiftMaker => false,
CustomRoles.Oblivious when pc.Is(CustomRoles.Altruist) => false,
CustomRoles.AntiTP when pc.GetCustomRole() is CustomRoles.Transmitter or CustomRoles.Miner or CustomRoles.Escapee or CustomRoles.Tunneler => false,
CustomRoles.AntiTP when pc.GetCustomRole() is CustomRoles.Transmitter or CustomRoles.Miner or CustomRoles.Escapee or CustomRoles.Tunneler=> false,
CustomRoles.Swift when pc.Is(CustomRoles.Stealth) => false,
CustomRoles.BananaMan when pc.Is(CustomRoles.Disco) => false,
CustomRoles.Disco when pc.GetCustomRole() is CustomRoles.Chameleon or CustomRoles.Swooper or CustomRoles.Wraith or CustomRoles.Alchemist => false,
@@ -1072,7 +1072,7 @@ internal static class CustomRolesHelper
CustomRoles.Oblivious when pc.Is(CustomRoles.Detective) || pc.Is(CustomRoles.Cleaner) || pc.Is(CustomRoles.Medusa) || pc.Is(CustomRoles.Mortician) || pc.Is(CustomRoles.Mediumshiper) || pc.Is(CustomRoles.GuardianAngelEHR) => false,
CustomRoles.Youtuber when !pc.IsCrewmate() || pc.Is(CustomRoles.Madmate) || pc.Is(CustomRoles.Sheriff) || pc.Is(CustomRoles.GuardianAngelEHR) => false,
CustomRoles.Egoist when !pc.IsImpostor() => false,
CustomRoles.Damocles when pc.GetCustomRole() is CustomRoles.Bomber or CustomRoles.Nuker or CustomRoles.SerialKiller or CustomRoles.Cantankerous => false,
CustomRoles.Damocles when pc.GetCustomRole() is CustomRoles.Bomber or CustomRoles.Nuker or CustomRoles.Mercenary or CustomRoles.Cantankerous => false,
CustomRoles.Damocles when !pc.CanUseKillButton() => false,
CustomRoles.Flashman when pc.Is(CustomRoles.Swiftclaw) || pc.Is(CustomRoles.Giant) || pc.Is(CustomRoles.Spurt) => false,
CustomRoles.Giant when pc.Is(CustomRoles.Flashman) || pc.Is(CustomRoles.Spurt) || pc.Is(CustomRoles.RoomRusher) => false,
@@ -1092,6 +1092,7 @@ internal static class CustomRolesHelper
CustomRoles.Mare when pc.Is(CustomRoles.Vampire) => false,
CustomRoles.Torch when pc.Is(CustomRoles.Lighter) => false,
CustomRoles.Torch when pc.Is(CustomRoles.Ignitor) => false,
CustomRoles.Torch when pc.Is(CustomRoles.Decryptor) => false,
CustomRoles.Bewilder when pc.Is(CustomRoles.Lighter) => false,
CustomRoles.Bewilder when pc.Is(CustomRoles.Ignitor) => false,
CustomRoles.Sunglasses when pc.Is(CustomRoles.Lighter) => false,
@@ -1330,7 +1331,7 @@ internal static class CustomRolesHelper
public static bool IsDevFavoriteRole(this CustomRoles role)
{
return role is CustomRoles.Adventurer or CustomRoles.Chef or CustomRoles.Detour or CustomRoles.NiceHacker or CustomRoles.NiceSwapper or CustomRoles.Sentinel or CustomRoles.Sentry or CustomRoles.Tornado or CustomRoles.Tunneler or CustomRoles.Whisperer or CustomRoles.Wizard or
CustomRoles.Abyssbringer or CustomRoles.Assumer or CustomRoles.Chronomancer or CustomRoles.Echo or CustomRoles.Escapee or CustomRoles.Hypnotist or CustomRoles.Librarian or CustomRoles.Mafioso or CustomRoles.Mastermind or CustomRoles.SerialKiller or CustomRoles.Penguin or CustomRoles.RiftMaker or CustomRoles.Sapper or CustomRoles.Wiper or
CustomRoles.Abyssbringer or CustomRoles.Assumer or CustomRoles.Chronomancer or CustomRoles.Echo or CustomRoles.Escapee or CustomRoles.Hypnotist or CustomRoles.Librarian or CustomRoles.Mafioso or CustomRoles.Mastermind or CustomRoles.Mercenary or CustomRoles.Penguin or CustomRoles.RiftMaker or CustomRoles.Sapper or CustomRoles.Wiper or
CustomRoles.Bargainer or CustomRoles.Bubble or CustomRoles.Doomsayer or CustomRoles.Enderman or CustomRoles.Evolver or CustomRoles.HeadHunter or CustomRoles.Impartial or CustomRoles.Patroller or CustomRoles.Pawn or CustomRoles.PlagueDoctor or CustomRoles.Postman or CustomRoles.Pyromaniac or CustomRoles.Revolutionist or CustomRoles.Rogue or CustomRoles.Romantic or CustomRoles.RoomRusher or CustomRoles.RouleteGrandeur or CustomRoles.Simon or CustomRoles.SoulHunter or CustomRoles.Sprayer or CustomRoles.Technician or CustomRoles.Tank or CustomRoles.Tiger or CustomRoles.Tremor or CustomRoles.Vengeance or CustomRoles.Vortex or CustomRoles.Werewolf or CustomRoles.WeaponMaster or
CustomRoles.Reaper or CustomRoles.VoodooMaster or CustomRoles.Dreamweaver or CustomRoles.Banshee or
CustomRoles.Allergic or CustomRoles.Bloodlust or CustomRoles.Damocles or CustomRoles.Deadlined or CustomRoles.DeadlyQuota or CustomRoles.Dynamo or CustomRoles.DoubleShot or CustomRoles.Energetic or CustomRoles.Haste or CustomRoles.Introvert or CustomRoles.Messenger or CustomRoles.Nimble or CustomRoles.Reach or CustomRoles.Seer or CustomRoles.Stressed;
@@ -1530,7 +1531,7 @@ internal static class CustomRolesHelper
{
CustomRoles.Sans => RoleOptionType.Impostor_Killing,
CustomRoles.Abyssbringer => RoleOptionType.Impostor_Killing,
CustomRoles.Assassin => RoleOptionType.Impostor_Killing,
CustomRoles.Ninja => RoleOptionType.Impostor_Killing,
CustomRoles.Assumer => RoleOptionType.Impostor_Killing,
CustomRoles.Augmenter => RoleOptionType.Impostor_Killing,
CustomRoles.Bomber => RoleOptionType.Impostor_Killing,
@@ -1548,7 +1549,7 @@ internal static class CustomRolesHelper
CustomRoles.Lurker => RoleOptionType.Impostor_Killing,
CustomRoles.Mafioso => RoleOptionType.Impostor_Killing,
CustomRoles.Mafia => RoleOptionType.Impostor_Killing,
CustomRoles.SerialKiller => RoleOptionType.Impostor_Killing,
CustomRoles.Mercenary => RoleOptionType.Impostor_Killing,
CustomRoles.Nuker => RoleOptionType.Impostor_Killing,
CustomRoles.Overheat => RoleOptionType.Impostor_Killing,
CustomRoles.OverKiller => RoleOptionType.Impostor_Killing,
@@ -1832,14 +1833,14 @@ public enum CountTypes
Jackal,
Doppelganger,
Pelican,
Gamer,
Demon,
BloodKnight,
Poisoner,
Succubus,
Necromancer,
HexMaster,
Wraith,
NSerialKiller,
SerialKiller,
Slenderman,
Amogus,
Weatherman,
+1 -1
View File
@@ -185,7 +185,7 @@ public enum ErrorCode
{
//xxxyyyz: ERR-xxx-yyy-z
// xxx: General type of error (HUD-related, banishment-related, etc.)
// yyy: Detailed type of error (BoutyHunter processing, SerialKiller processing, etc.)
// yyy: Detailed type of error (BoutyHunter processing, Mercenary processing, etc.)
// z: Severity
// 0: No action required (hide)
// 1: Abandon village if not working properly (hide after a certain period of time)
+4 -4
View File
@@ -106,7 +106,7 @@ public enum CustomRPC
SetNiceHackerLimit,
SetCurrentDrawTarget,
SetCpTasksDone,
SetGamerHealth,
SetDemonHealth,
SetPelicanEtenNum,
SwordsManKill,
SetGhostPlayer,
@@ -989,9 +989,9 @@ internal static class RPCHandlerPatch
GameStartManagerPatch.TimerStartTS = long.Parse(reader.ReadString());
break;
}
case CustomRPC.SetGamerHealth:
case CustomRPC.SetDemonHealth:
{
Gamer.ReceiveRPC(reader);
Demon.ReceiveRPC(reader);
break;
}
case CustomRPC.SetPelicanEtenNum:
@@ -1049,7 +1049,7 @@ internal static class RPCHandlerPatch
}
case CustomRPC.SetMarkedPlayer:
{
Assassin.ReceiveRPC(reader);
Ninja.ReceiveRPC(reader);
break;
}
case CustomRPC.SyncChronomancer:
+5 -5
View File
@@ -838,7 +838,7 @@ public static class Utils
case CustomRoles.Poisoner:
case CustomRoles.Eclipse:
case CustomRoles.Pyromaniac:
case CustomRoles.NSerialKiller:
case CustomRoles.SerialKiller:
case CustomRoles.Slenderman:
case CustomRoles.Amogus:
case CustomRoles.Weatherman:
@@ -910,7 +910,7 @@ public static class Utils
case CustomRoles.Medusa:
case CustomRoles.Revolutionist:
case CustomRoles.FFF:
case CustomRoles.Gamer:
case CustomRoles.Demon:
case CustomRoles.HexMaster:
case CustomRoles.Wraith:
case CustomRoles.Juggernaut:
@@ -2458,7 +2458,7 @@ public static class Utils
SelfMark.Append(Medic.GetMark(seer, seer));
SelfMark.Append(Gaslighter.GetMark(seer, seer, forMeeting));
SelfMark.Append(Gamer.TargetMark(seer, seer));
SelfMark.Append(Demon.TargetMark(seer, seer));
SelfMark.Append(Sniper.GetShotNotify(seer.PlayerId));
if (Silencer.ForSilencer.Contains(seer.PlayerId)) SelfMark.Append(ColorString(GetRoleColor(CustomRoles.Silencer), "╳"));
@@ -2867,7 +2867,7 @@ public static class Utils
TargetMark.Append(ColorString(GetRoleColor(CustomRoles.Marshall), "★"));
TargetMark.Append(Executioner.TargetMark(seer, target));
TargetMark.Append(Gamer.TargetMark(seer, target));
TargetMark.Append(Demon.TargetMark(seer, target));
TargetMark.Append(Medic.GetMark(seer, target));
TargetMark.Append(Gaslighter.GetMark(seer, target, forMeeting));
TargetMark.Append(Totocalcio.TargetMark(seer, target));
@@ -3210,7 +3210,7 @@ public static class Utils
CustomRoles.ToiletMaster => ToiletMaster.AbilityCooldown.GetInt(),
CustomRoles.AntiAdminer => AntiAdminer.AbilityCooldown.GetInt(),
CustomRoles.Sniper => Options.DefaultShapeshiftCooldown.GetInt(),
CustomRoles.Assassin => Assassin.AssassinateCooldownOpt.GetInt(),
CustomRoles.Ninja => Ninja.AssassinateCooldownOpt.GetInt(),
CustomRoles.Undertaker => Undertaker.UndertakerAssassinateCooldown.GetInt(),
CustomRoles.Bomber => Bomber.BombCooldown.GetInt(),
CustomRoles.Nuker => Bomber.NukeCooldown.GetInt(),
+1 -1
View File
@@ -439,7 +439,7 @@ internal static class ChatCommands
ChatManager.SendMessage(PlayerControl.LocalPlayer, text);
}
if (text.Contains("666") && PlayerControl.LocalPlayer.Is(CustomRoles.Gamer))
if (text.Contains("666") && PlayerControl.LocalPlayer.Is(CustomRoles.Demon))
Achievements.Type.WhatTheHell.Complete();
return !canceled;
+3 -3
View File
@@ -244,7 +244,7 @@ internal static class HudManagerPatch
break;
case CustomRoles.KB_Normal:
case CustomRoles.BedWarsPlayer:
__instance.KillButton?.OverrideText(GetString("GamerButtonText"));
__instance.KillButton?.OverrideText(GetString("DemonButtonText"));
break;
case CustomRoles.Deputy:
usedButton?.OverrideText(GetString("DeputyHandcuffText"));
@@ -257,7 +257,7 @@ internal static class HudManagerPatch
break;
}
if (role.PetActivatedAbility() && Options.CurrentGameMode == CustomGameMode.Standard && player.GetRoleTypes() != RoleTypes.Engineer && !role.OnlySpawnsWithPets() && !role.AlwaysUsesPhantomBase() && !player.GetCustomSubRoles().Any(StartGameHostPatch.BasisChangingAddons.ContainsKey) && role is not CustomRoles.Changeling and not CustomRoles.Assassin && (!role.SimpleAbilityTrigger() || !Options.UsePhantomBasis.GetBool() || !(player.IsNeutralKiller() && Options.UsePhantomBasisForNKs.GetBool())))
if (role.PetActivatedAbility() && Options.CurrentGameMode == CustomGameMode.Standard && player.GetRoleTypes() != RoleTypes.Engineer && !role.OnlySpawnsWithPets() && !role.AlwaysUsesPhantomBase() && !player.GetCustomSubRoles().Any(StartGameHostPatch.BasisChangingAddons.ContainsKey) && role is not CustomRoles.Changeling and not CustomRoles.Ninja && (!role.SimpleAbilityTrigger() || !Options.UsePhantomBasis.GetBool() || !(player.IsNeutralKiller() && Options.UsePhantomBasisForNKs.GetBool())))
__instance.AbilityButton?.Hide();
if (LowerInfoText == null)
@@ -590,7 +590,7 @@ internal static class SetHudActivePatch
case CustomRoles.Pelican:
case CustomRoles.FFF:
case CustomRoles.Medic:
case CustomRoles.Gamer:
case CustomRoles.Demon:
case CustomRoles.DarkHide:
case CustomRoles.Farseer:
case CustomRoles.Crusader:
+4 -4
View File
@@ -167,22 +167,22 @@ public static class HudSpritePatch
break;
}
case CustomRoles.Assassin:
case CustomRoles.Ninja:
case CustomRoles.Undertaker:
{
if (Main.PlayerStates[player.PlayerId].Role is not Assassin assassin) break;
if (Main.PlayerStates[player.PlayerId].Role is not Ninja ninja) break;
if (Options.UsePets.GetBool())
{
newKillButton = CustomButton.Get("Mark");
if (assassin.MarkedPlayer != byte.MaxValue) newPetButton = CustomButton.Get("Assassinate");
if (ninja.MarkedPlayer != byte.MaxValue) newPetButton = CustomButton.Get("Assassinate");
}
else
{
if (!shapeshifting)
{
newKillButton = CustomButton.Get("Mark");
if (assassin.MarkedPlayer != byte.MaxValue) newAbilityButton = CustomButton.Get("Assassinate");
if (ninja.MarkedPlayer != byte.MaxValue) newAbilityButton = CustomButton.Get("Assassinate");
}
}
+2 -2
View File
@@ -1044,8 +1044,8 @@ internal static class MeetingHudStartPatch
case CustomRoles.Psychic when Psychic.IsRedForPsy(target, seer) && !seer.Data.IsDead:
pva.NameText.text = Utils.ColorString(Utils.GetRoleColor(CustomRoles.Impostor), pva.NameText.text);
break;
case CustomRoles.Gamer:
sb.Append(Gamer.TargetMark(seer, target));
case CustomRoles.Demon:
sb.Append(Demon.TargetMark(seer, target));
sb.Append(Snitch.GetWarningMark(seer, target));
break;
case CustomRoles.Scout:
+3 -3
View File
@@ -1577,7 +1577,7 @@ internal static class FixedUpdatePatch
{
foreach (PlayerControl pc in Main.AllPlayerControls)
{
if (pc.Is(CustomRoles.Vampire) || pc.Is(CustomRoles.Warlock) || pc.Is(CustomRoles.Assassin) || pc.Is(CustomRoles.Undertaker) || pc.Is(CustomRoles.Poisoner))
if (pc.Is(CustomRoles.Vampire) || pc.Is(CustomRoles.Warlock) || pc.Is(CustomRoles.Ninja) || pc.Is(CustomRoles.Undertaker) || pc.Is(CustomRoles.Poisoner))
Main.AllPlayerKillCooldown[pc.PlayerId] = Options.AdjustedDefaultKillCooldown * 2;
}
}
@@ -1807,8 +1807,8 @@ internal static class FixedUpdatePatch
case CustomRoles.Executioner:
Mark.Append(Executioner.TargetMark(seer, target));
break;
case CustomRoles.Gamer:
Mark.Append(Gamer.TargetMark(seer, target));
case CustomRoles.Demon:
Mark.Append(Demon.TargetMark(seer, target));
break;
}
+19 -19
View File
@@ -177,7 +177,7 @@
"BountyHunter": "Bounty Hunter",
"Mare": "Mare",
"FireWorks": "Fireworker",
"SerialKiller": "Mercenary",
"Mercenary": "Mercenary",
"Vampire": "Vampire",
"Warlock": "Warlock",
"Assassin": "Ninja",
@@ -295,7 +295,7 @@
"Pelican": "Pelican",
"Revolutionist": "Revolutionist",
"FFF": "Hater",
"Gamer": "Demon",
"Demon": "Demon",
"DarkHide": "Stalker",
"Workaholic": "Workaholic",
"Collector": "Collector",
@@ -309,7 +309,7 @@
"Succubus": "Cultist",
"HexMaster": "Hex Master",
"Wraith": "Wraith",
"NSerialKiller": "Serial Killer",
"SerialKiller": "Serial Killer",
"Juggernaut": "Juggernaut",
"Infectious": "Infectious",
"Virus": "Virus",
@@ -456,7 +456,7 @@
"BountyHunterInfo": "Eliminate your target",
"MareInfo": "Kill in the dark",
"FireWorksInfo": "Go out with a BANG",
"SerialKillerInfo": "Keep killing, else you suicide",
"MercenaryInfo": "Keep killing, else you suicide",
"VampireInfo": "Your kills are delayed",
"WarlockInfo": "Curse crewmates & shift to make them kill",
"AssassinInfo": "Mark a target, then shift to kill them",
@@ -575,7 +575,7 @@
"PelicanInfo": "Eat all players",
"RevolutionistInfo": "Recruit players to win with you",
"FFFInfo": "Kill <color=#ff9ace>Lovers</color> and <color=#ffab1b>Converted</color> players",
"GamerInfo": "Consume blood volumes",
"DemonInfo": "Consume blood volumes",
"DarkHideInfo": "Your kills cause power outages",
"WorkaholicInfo": "Finish all tasks to solo win!",
"CollectorInfo": "Collect votes from players",
@@ -589,7 +589,7 @@
"SuccubusInfo": "Charm everyone",
"HexMasterInfo": "Hex players to kill them in meetings",
"WraithInfo": "Vent to go invisible temporarily",
"NSerialKillerInfo": "Kill everyone to win!",
"SerialKillerInfo": "Kill everyone to win!",
"JuggernautInfo": "Your cooldown decreases with each kill you get",
"InfectiousInfo": "Infect everyone",
"VirusInfo": "Kill and infect everyone",
@@ -685,7 +685,7 @@
"PhantomEHRInfoLong": "(Impostors):\\nAs the Phantom, you can go invisible for a short period. During this time, you can't be seen by Crewmates.",
"BountyHunterInfoLong": "(Impostors):\\nIf you successfully eliminate your assigned target, your next kill cooldown will decrease, but if you eliminate anyone else, your next kill cooldown will increase; the target will switch after a predetermined time.",
"FireWorksInfoLong": "(Impostors):\\nAs a Fireworker, you can plant up to three firework bombs using vanish/by petting. If you're the last impostor standing, you can use vanish/pet to detonate the bombs and cause area damage. But be careful, the bombs can also harm you. If the bombs eliminate all surviving players, it's a victory for the impostors.",
"SerialKillerInfoLong": "(Impostors):\\nYou have a shorter kill cooldown than other impostors, but you will die if you don't kill before the end of your shapeshift cooldown.",
"MercenaryInfoLong": "(Impostors):\\nYou have a shorter kill cooldown than other impostors, but you will die if you don't kill before the end of your shapeshift cooldown.",
"MareInfoLong": "(Add-ons):\\nAs the Mare, you have a low kill cooldown but can only kill during lights. Additionally, your name will appear in red during lights. Only assigned to Impostors and cannot be guessed.",
"VampireInfoLong": "(Impostors):\\nVampire bites delay death. Meeting kills bitten. Biting Bait = normal kill, self-report.",
"WarlockInfoLong": "(Impostors):\\nWarlock can curse a player while not Shapeshifted. If they vanish/pet after cursing, the closest player to the cursed one is killed, regardless of distance. Only one player can be cursed at a time.\\n\\nKilling, shapeshifting/petting, and cursing all have separate cooldowns. The Warlock may freeze in place for a few seconds after killing via cursed player.",
@@ -805,7 +805,7 @@
"PelicanInfoLong": "(Neutrals):\\nAs the Pelican, you can use the kill button and swallow a player alive. Swallowed players are teleported out of the map and cannot interact with the game. In case of an emergency meeting or reporting a dead body, all swallowed players die instantly. This is not a standard way to kill, and role skills such as the Bodyguard and Veteran are ineffective. If you die or disconnect, all previously swallowed players are returned to your location.",
"RevolutionistInfoLong": "(Neutrals):\\nThe Revolutionist can recruit players by clicking the kill button on them and following them for a few seconds. If recruiting is successful, a shield animation is shown as a reminder. Players recruited are likely to be immediately killed, a probability set by the host. The Revolutionist and all recruited players win if the specified number of players vent within the set time, otherwise, the recruited player dies. The Revolutionist dies if killed during a countdown or at a meeting. Players who died after recruitment can still win with the Revolutionist.",
"FFFInfoLong": "(Neutrals):\\nAs the Hater, you can kill as often as you want with no cooldown and have impostor vision. You can only kill Lovers, recruited players, and recruiting roles, or you will die. Winning is possible if you kill at least one player during the game.",
"GamerInfoLong": "(Neutrals):\\nIf the number of Demons is greater than Crewmates, Demons win. Demons have a unique health-based killing system, and killing takes effect when one's health is exhausted. If a Demon's health is consumed but they are not killed, the murderer will see a shield animation as a reminder.",
"DemonInfoLong": "(Neutrals):\\nDemon has a unique health-based killing system, and killing takes effect when one's health is exhausted. If a Demon's health is consumed but they are not killed, the murderer will see a shield animation as a reminder.",
"DarkHideInfoLong": "(Neutrals):\\nThe Stalker can kill anyone and cause electricity sabotage. They cannot vent. If the Stalker is alive and the Impostor or Crewmate wins, the Stalker wins alone.",
"WorkaholicInfoLong": "(Neutrals):\\nWorkaholics win by completing more tasks, maybe even after their death.",
"CollectorInfoLong": "(Neutrals):\\nCollectors can gather all the votes cast by a target in a meeting. When they collect the specified number of votes, they win, even over exiled players.",
@@ -819,7 +819,7 @@
"SuccubusInfoLong": "(Neutrals):\\nIf there are more Cultists than Crewmates and only these two teams remain, the Cultist team wins. The Cultist can charm a non-neutral player by pressing the kill button, making them a part of the Cultist team with new victory conditions.",
"HexMasterInfoLong": "(Neutrals):\\nAs the Hex Master, you can hex players or kill them. Hexing a player works the same as spelling as a Witch.",
"WraithInfoLong": "(Neutrals):\\nAs the Wraith, you can Vent/Vanish to go invisible temporarily. You can kill while being invisible.\\n\\nKill; everyone to win.",
"NSerialKillerInfoLong": "(Neutrals):\\nAs the Serial Killer, your job is to murder everyone to win simply.",
"SerialKillerInfoLong": "(Neutrals):\\nAs the Serial Killer, your job is to murder everyone to win simply.",
"JuggernautInfoLong": "(Neutrals):\\nAs the Juggernaut, your kill cooldown decreases with each kill you make.\\n\\nKill everyone to win.",
"VirusInfoLong": "(Neutrals):\\nThe virus' goal is to eliminate other players. When a crewmate is killed, their corpse is infected, and the reporting crewmate joins the virus team or dies if the Virus isn't voted out. The Virus team wins if they outnumber the Crewmate team.",
"PursuerInfoLong": "(Neutrals):\\nAs the Pursuer, you can use your ability on someone to make them shoot a blank when they try to kill (= reset their kill cooldown).\\n\\nTo win, survive to the end of the game.",
@@ -1456,7 +1456,7 @@
"LawyerCanTargetJester": "Can Target <color=#ec62a5>Jester</color>",
"LawyerChangeRolesAfterTargetKilled": "When Target Dies, <color=#008080>Lawyer</color> becomes",
"LawyerChangeRole": "Your client is dead",
"SerialKillerLimit": "Time Until Suicide",
"MercenaryLimit": "Time Until Suicide",
"ArsonistDouseTime": "Douse Duration",
"CanTerroristSuicideWin": "Can Win By Suicide",
"FireWorksMaxCount": "Fireworks Count",
@@ -1659,11 +1659,11 @@
"ContagiousCountMode.Virus": "<color=#2E8B57>Virus</color>",
"ContagiousCountMode.Original": "Original Team",
"SnatchesWin": "Snatches victory",
"GamerKillCooldown": "Attack Cooldown",
"GamerHealthMax": "Player max health",
"GamerDamage": "Damage ",
"GamerSelfHealthMax": "Demon max health",
"GamerSelfDamage": "Demon damage received",
"DemonKillCooldown": "Attack Cooldown",
"DemonHealthMax": "Player max health",
"DemonDamage": "Damage ",
"DemonSelfHealthMax": "Demon max health",
"DemonSelfDamage": "Demon damage received",
"BallLightningConvertTime": "Duration of the transformation to Quantum Ghost",
"BallLightningKillCooldown": "Lightning Cooldown",
"BallLightningKillerConvertGhost": "Killer can transform into Quantum Ghost",
@@ -3116,7 +3116,7 @@
"SniperSnipeButtonText": "Snipe",
"FireWorksExplosionButtonText": "Detonate",
"FireWorksInstallAtionButtonText": "Install",
"SerialKillerSuicideButtonText": "Suicide Timer",
"MercenarySuicideButtonText": "Suicide Timer",
"WarlockCurseButtonText": "Curse",
"AssassinMarkButtonText": "Mark",
"UndertakerMarkButtonText": "Mark",
@@ -3137,7 +3137,7 @@
"RevolutionistDrawButtonText": "Win over",
"FFFButtonText": "Hatred",
"MedicalerButtonText": "Protect",
"GamerButtonText": "Attack",
"DemonButtonText": "Attack",
"ImperiusCurseButtonText": "Teleport",
"BallLightningButtonText": "Evaporate",
"ProvocateurButtonText": "Greet",
@@ -9638,7 +9638,7 @@
"WinnerRoleText.Pelican": "Pelican Wins!",
"WinnerRoleText.Youtuber": "YouTuber Wins!",
"WinnerRoleText.Egoist": "Egoist Wins!",
"WinnerRoleText.Gamer": "Demon Wins!",
"WinnerRoleText.Demon": "Demon Wins!",
"WinnerRoleText.DarkHide": "Stalker Wins!",
"WinnerRoleText.Workaholic": "Workaholic Wins!",
"WinnerRoleText.Agitater": "Agitator Wins!",
@@ -9649,7 +9649,7 @@
"WinnerRoleText.Succubus": "Cultist Wins!",
"WinnerRoleText.Necromancer": "Undead Faction Wins!",
"WinnerRoleText.Wraith": "Wraith Wins!",
"WinnerRoleText.NSerialKiller": "Serial Killer Wins!",
"WinnerRoleText.SerialKiller": "Serial Killer Wins!",
"WinnerRoleText.Juggernaut": "Juggernaut Wins!",
"WinnerRoleText.Infectious": "Infectious Wins!",
"WinnerRoleText.Virus": "Virus Wins!",
+1 -1
View File
@@ -35,7 +35,7 @@ public class Addict : RoleBase
VentCooldown = new FloatOptionItem(Id + 11, "VentCooldown", new(5f, 70f, 1f), 40f, TabGroup.CrewmateRoles).SetParent(CustomRoleSpawnChances[CustomRoles.Addict])
.SetValueFormat(OptionFormat.Seconds);
TimeLimit = new FloatOptionItem(Id + 12, "SerialKillerLimit", new(5f, 75f, 1f), 45f, TabGroup.CrewmateRoles).SetParent(CustomRoleSpawnChances[CustomRoles.Addict])
TimeLimit = new FloatOptionItem(Id + 12, "MercenaryLimit", new(5f, 75f, 1f), 45f, TabGroup.CrewmateRoles).SetParent(CustomRoleSpawnChances[CustomRoles.Addict])
.SetValueFormat(OptionFormat.Seconds);
ImmortalTimeAfterVent = new FloatOptionItem(Id + 13, "AddictInvulnerbilityTimeAfterVent", new(0f, 30f, 1f), 10f, TabGroup.CrewmateRoles).SetParent(CustomRoleSpawnChances[CustomRoles.Addict])
+1 -1
View File
@@ -103,7 +103,7 @@ public class CopyCat : RoleBase
CustomRoles.AntiAdminer => CustomRoles.Monitor,
CustomRoles.CursedWolf or CustomRoles.Jinx => CustomRoles.Veteran,
CustomRoles.EvilTracker => CustomRoles.TrackerEHR,
CustomRoles.SerialKiller => CustomRoles.Addict,
CustomRoles.Mercenary => CustomRoles.Addict,
CustomRoles.Miner => CustomRoles.Mole,
CustomRoles.Escapee => CustomRoles.Tunneler,
CustomRoles.Twister => CustomRoles.TimeMaster,
+1 -1
View File
@@ -89,7 +89,7 @@ internal class DovesOfNeace : RoleBase
x.RPCPlayCustomSound("Dove");
x.ResetKillCooldown();
x.SetKillCooldown();
if (Main.PlayerStates[x.PlayerId].Role is SerialKiller sk) sk.OnReportDeadBody();
if (Main.PlayerStates[x.PlayerId].Role is Mercenary m) m.OnReportDeadBody();
x.Notify(Utils.ColorString(Utils.GetRoleColor(CustomRoles.DovesOfNeace), Translator.GetString("DovesOfNeaceSkillNotify")));
});
+1 -1
View File
@@ -111,7 +111,7 @@ public class Mastermind : RoleBase
pc.SetKillCooldown(1f);
}
else
pc.RpcChangeRoleBasis(CustomRoles.NSerialKiller);
pc.RpcChangeRoleBasis(CustomRoles.SerialKiller);
NotifyRoles(SpecifySeer: MastermindPC, SpecifyTarget: pc);
}
@@ -1,118 +1,118 @@
using System.Collections.Generic;
using EHR.Modules;
using UnityEngine;
namespace EHR.Impostor;
public class SerialKiller : RoleBase
{
private const int Id = 1700;
public static List<byte> PlayerIdList = [];
private static OptionItem KillCooldown;
private static OptionItem TimeLimit;
private static OptionItem WaitFor1Kill;
private float SuicideTimer;
private int Timer;
public override bool IsEnable => PlayerIdList.Count > 0;
public override void SetupCustomOption()
{
Options.SetupRoleOptions(Id, TabGroup.ImpostorRoles, CustomRoles.SerialKiller);
KillCooldown = new FloatOptionItem(Id + 10, "KillCooldown", new(0f, 180f, 0.5f), 22.5f, TabGroup.ImpostorRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.SerialKiller])
.SetValueFormat(OptionFormat.Seconds);
TimeLimit = new FloatOptionItem(Id + 11, "SerialKillerLimit", new(5f, 180f, 5f), 40f, TabGroup.ImpostorRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.SerialKiller])
.SetValueFormat(OptionFormat.Seconds);
WaitFor1Kill = new BooleanOptionItem(Id + 12, "WaitFor1Kill", true, TabGroup.ImpostorRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.SerialKiller]);
}
public override void Init()
{
PlayerIdList = [];
SuicideTimer = TimeLimit.GetFloat();
Timer = TimeLimit.GetInt();
}
public override void Add(byte serial)
{
PlayerIdList.Add(serial);
Timer = TimeLimit.GetInt();
SuicideTimer = TimeLimit.GetFloat();
}
public override void Remove(byte playerId)
{
PlayerIdList.Remove(playerId);
}
public override void SetKillCooldown(byte id)
{
Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat();
}
private static bool HasKilled(PlayerControl pc)
{
return pc != null && pc.Is(CustomRoles.SerialKiller) && pc.IsAlive() && (Main.PlayerStates[pc.PlayerId].GetKillCount(true) > 0 || !WaitFor1Kill.GetBool());
}
public override bool OnCheckMurder(PlayerControl killer, PlayerControl target)
{
if (!killer.Is(CustomRoles.SerialKiller)) return true;
SuicideTimer = float.NaN;
Timer = TimeLimit.GetInt();
killer.MarkDirtySettings();
return true;
}
public override void OnReportDeadBody()
{
SuicideTimer = float.NaN;
Timer = TimeLimit.GetInt();
}
public override void OnFixedUpdate(PlayerControl player)
{
if (!GameStates.IsInTask) return;
if (!HasKilled(player))
{
SuicideTimer = float.NaN;
Timer = TimeLimit.GetInt();
return;
}
if (float.IsNaN(SuicideTimer)) return;
if (SuicideTimer >= TimeLimit.GetFloat())
{
player.Suicide();
SuicideTimer = float.NaN;
Timer = TimeLimit.GetInt();
if (player.IsLocalPlayer())
Achievements.Type.OutOfTime.Complete();
}
else
{
SuicideTimer += Time.fixedDeltaTime;
int tempTimer = Timer;
Timer = TimeLimit.GetInt() - (int)SuicideTimer;
if (Timer != tempTimer && Timer <= 20 && !player.IsModdedClient()) Utils.NotifyRoles(SpecifySeer: player, SpecifyTarget: player);
}
}
public override void AfterMeetingTasks()
{
SuicideTimer = 0f;
Timer = TimeLimit.GetInt();
}
using System.Collections.Generic;
using EHR.Modules;
using UnityEngine;
namespace EHR.Impostor;
public class Mercenary : RoleBase
{
private const int Id = 1700;
public static List<byte> PlayerIdList = [];
private static OptionItem KillCooldown;
private static OptionItem TimeLimit;
private static OptionItem WaitFor1Kill;
private float SuicideTimer;
private int Timer;
public override bool IsEnable => PlayerIdList.Count > 0;
public override void SetupCustomOption()
{
Options.SetupRoleOptions(Id, TabGroup.ImpostorRoles, CustomRoles.Mercenary);
KillCooldown = new FloatOptionItem(Id + 10, "KillCooldown", new(0f, 180f, 0.5f), 22.5f, TabGroup.ImpostorRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Mercenary])
.SetValueFormat(OptionFormat.Seconds);
TimeLimit = new FloatOptionItem(Id + 11, "MercenaryLimit", new(5f, 180f, 5f), 40f, TabGroup.ImpostorRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Mercenary])
.SetValueFormat(OptionFormat.Seconds);
WaitFor1Kill = new BooleanOptionItem(Id + 12, "WaitFor1Kill", true, TabGroup.ImpostorRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Mercenary]);
}
public override void Init()
{
PlayerIdList = [];
SuicideTimer = TimeLimit.GetFloat();
Timer = TimeLimit.GetInt();
}
public override void Add(byte serial)
{
PlayerIdList.Add(serial);
Timer = TimeLimit.GetInt();
SuicideTimer = TimeLimit.GetFloat();
}
public override void Remove(byte playerId)
{
PlayerIdList.Remove(playerId);
}
public override void SetKillCooldown(byte id)
{
Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat();
}
private static bool HasKilled(PlayerControl pc)
{
return pc != null && pc.Is(CustomRoles.Mercenary) && pc.IsAlive() && (Main.PlayerStates[pc.PlayerId].GetKillCount(true) > 0 || !WaitFor1Kill.GetBool());
}
public override bool OnCheckMurder(PlayerControl killer, PlayerControl target)
{
if (!killer.Is(CustomRoles.Mercenary)) return true;
SuicideTimer = float.NaN;
Timer = TimeLimit.GetInt();
killer.MarkDirtySettings();
return true;
}
public override void OnReportDeadBody()
{
SuicideTimer = float.NaN;
Timer = TimeLimit.GetInt();
}
public override void OnFixedUpdate(PlayerControl player)
{
if (!GameStates.IsInTask) return;
if (!HasKilled(player))
{
SuicideTimer = float.NaN;
Timer = TimeLimit.GetInt();
return;
}
if (float.IsNaN(SuicideTimer)) return;
if (SuicideTimer >= TimeLimit.GetFloat())
{
player.Suicide();
SuicideTimer = float.NaN;
Timer = TimeLimit.GetInt();
if (player.IsLocalPlayer())
Achievements.Type.OutOfTime.Complete();
}
else
{
SuicideTimer += Time.fixedDeltaTime;
int tempTimer = Timer;
Timer = TimeLimit.GetInt() - (int)SuicideTimer;
if (Timer != tempTimer && Timer <= 20 && !player.IsModdedClient()) Utils.NotifyRoles(SpecifySeer: player, SpecifyTarget: player);
}
}
public override void AfterMeetingTasks()
{
SuicideTimer = 0f;
Timer = TimeLimit.GetInt();
}
}
@@ -1,232 +1,232 @@
using System.Collections.Generic;
using AmongUs.GameOptions;
using EHR.Modules;
using EHR.Neutral;
using Hazel;
using static EHR.Options;
using static EHR.Translator;
namespace EHR.Impostor;
internal class Assassin : RoleBase
{
private const int Id = 700;
public static List<byte> PlayerIdList = [];
private static OptionItem MarkCooldownOpt;
public static OptionItem AssassinateCooldownOpt;
private static OptionItem CanKillAfterAssassinateOpt;
private static OptionItem InvisibilityTimeAfterAssassinateOpt;
private float AssassinateCooldown;
private bool CanKillAfterAssassinate;
private bool IsUndertaker;
private float MarkCooldown;
public byte MarkedPlayer;
public override bool IsEnable => PlayerIdList.Count > 0;
public override void SetupCustomOption()
{
SetupRoleOptions(Id, TabGroup.ImpostorRoles, CustomRoles.Assassin);
MarkCooldownOpt = new FloatOptionItem(Id + 10, "AssassinMarkCooldown", new(0f, 180f, 0.5f), 1f, TabGroup.ImpostorRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Assassin])
.SetValueFormat(OptionFormat.Seconds);
AssassinateCooldownOpt = new FloatOptionItem(Id + 11, "AssassinAssassinateCooldown", new(0f, 180f, 0.5f), 18.5f, TabGroup.ImpostorRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Assassin])
.SetValueFormat(OptionFormat.Seconds);
CanKillAfterAssassinateOpt = new BooleanOptionItem(Id + 12, "AssassinCanKillAfterAssassinate", true, TabGroup.ImpostorRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Assassin]);
InvisibilityTimeAfterAssassinateOpt = new FloatOptionItem(Id + 13, "AssassinInvisibilityTimeAfterAssassinate", new(0f, 30f, 0.5f), 5f, TabGroup.ImpostorRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Assassin])
.SetValueFormat(OptionFormat.Seconds);
}
public override void Init()
{
PlayerIdList = [];
MarkedPlayer = byte.MaxValue;
IsUndertaker = false;
}
public override void Add(byte playerId)
{
PlayerIdList.Add(playerId);
MarkedPlayer = byte.MaxValue;
IsUndertaker = Main.PlayerStates[playerId].MainRole == CustomRoles.Undertaker;
if (IsUndertaker)
{
MarkCooldown = Undertaker.UndertakerMarkCooldown.GetFloat();
AssassinateCooldown = Undertaker.UndertakerAssassinateCooldown.GetFloat();
CanKillAfterAssassinate = Undertaker.UndertakerCanKillAfterAssassinate.GetBool();
}
else
{
MarkCooldown = MarkCooldownOpt.GetFloat();
AssassinateCooldown = AssassinateCooldownOpt.GetFloat();
CanKillAfterAssassinate = CanKillAfterAssassinateOpt.GetBool();
}
}
public override void Remove(byte playerId)
{
PlayerIdList.Remove(playerId);
}
private void SendRPC(byte playerId)
{
if (!IsEnable || !Utils.DoRPC) return;
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetMarkedPlayer, SendOption.Reliable);
writer.Write(playerId);
writer.Write(MarkedPlayer);
AmongUsClient.Instance.FinishRpcImmediately(writer);
}
public static void ReceiveRPC(MessageReader reader)
{
byte playerId = reader.ReadByte();
byte targetId = reader.ReadByte();
if (Main.PlayerStates[playerId].Role is not Assassin assassin) return;
assassin.MarkedPlayer = targetId;
}
public override void SetKillCooldown(byte id)
{
Main.AllPlayerKillCooldown[id] = id.IsPlayerShifted() ? AdjustedDefaultKillCooldown : MarkCooldown;
}
public override void ApplyGameOptions(IGameOptions opt, byte id)
{
if (UsePhantomBasis.GetBool())
AURoleOptions.PhantomCooldown = AssassinateCooldown;
else
{
if (UsePets.GetBool()) return;
AURoleOptions.ShapeshifterCooldown = AssassinateCooldown;
}
}
public override bool CanUseKillButton(PlayerControl pc)
{
if (pc == null || !pc.IsAlive()) return false;
return CanKillAfterAssassinate || (!pc.IsShifted() && (pc.Data.Role as PhantomRole) is null or { IsInvisible: false });
}
public override bool OnCheckMurder(PlayerControl killer, PlayerControl target)
{
if (killer.IsShifted())
{
bool canUseKillButton = CanUseKillButton(killer);
if (canUseKillButton)
{
killer.ResetKillCooldown();
killer.SyncSettings();
if (Main.Invisible.Contains(killer.PlayerId) && !target.Is(CustomRoles.Bait))
{
if (!killer.RpcCheckAndMurder(target, true)) return false;
RPC.PlaySoundRPC(killer.PlayerId, Sounds.KillSound);
target.Suicide(PlayerState.DeathReason.Swooped, killer);
killer.SetKillCooldown();
return false;
}
}
return canUseKillButton;
}
MarkedPlayer = target.PlayerId;
SendRPC(killer.PlayerId);
killer.ResetKillCooldown();
killer.SetKillCooldown();
if (killer.IsModdedClient()) killer.RpcResetAbilityCooldown();
killer.SyncSettings();
killer.RPCPlayCustomSound("Clothe");
return false;
}
public override void OnPet(PlayerControl pc)
{
Take(pc);
}
public override bool OnShapeshift(PlayerControl pc, PlayerControl t, bool shapeshifting)
{
if (!pc.IsAlive() || Pelican.IsEaten(pc.PlayerId)) return false;
if (!shapeshifting) return true;
Take(pc);
return false;
}
public override bool OnVanish(PlayerControl pc)
{
if (pc == null || !pc.IsAlive() || Pelican.IsEaten(pc.PlayerId)) return false;
if (!IsUndertaker)
{
float time = InvisibilityTimeAfterAssassinateOpt.GetFloat();
if (time >= 1f)
{
pc.RpcMakeInvisible();
LateTask.New(() =>
{
if (!GameStates.IsInTask || ExileController.Instance || AntiBlackout.SkipTasks) return;
pc.RpcMakeVisible();
}, time, log: false);
}
}
Take(pc);
return false;
}
private void Take(PlayerControl pc)
{
if (MarkedPlayer != byte.MaxValue)
{
PlayerControl target = Utils.GetPlayerById(MarkedPlayer);
bool tpSuccess = IsUndertaker ? target.TP(pc) : pc.TP(target);
if (!(target == null || !target.IsAlive() || Pelican.IsEaten(target.PlayerId) || target.inVent || !GameStates.IsInTask) && tpSuccess && pc.RpcCheckAndMurder(target))
{
MarkedPlayer = byte.MaxValue;
SendRPC(pc.PlayerId);
pc.ResetKillCooldown();
pc.SyncSettings();
pc.SetKillCooldown(AdjustedDefaultKillCooldown);
}
else if (!tpSuccess) pc.Notify(GetString("TargetCannotBeTeleported"));
}
}
public override void SetButtonTexts(HudManager __instance, byte playerId)
{
bool shifted = playerId.IsPlayerShifted();
__instance.KillButton.OverrideText(!shifted ? GetString("AssassinMarkButtonText") : GetString("KillButtonText"));
if (MarkedPlayer != byte.MaxValue && !shifted)
{
if (!UsePets.GetBool())
__instance.AbilityButton.OverrideText(GetString("AssassinShapeshiftText"));
else
__instance.PetButton.OverrideText(GetString("AssassinShapeshiftText"));
}
}
using System.Collections.Generic;
using AmongUs.GameOptions;
using EHR.Modules;
using EHR.Neutral;
using Hazel;
using static EHR.Options;
using static EHR.Translator;
namespace EHR.Impostor;
internal class Ninja : RoleBase
{
private const int Id = 700;
public static List<byte> PlayerIdList = [];
private static OptionItem MarkCooldownOpt;
public static OptionItem AssassinateCooldownOpt;
private static OptionItem CanKillAfterAssassinateOpt;
private static OptionItem InvisibilityTimeAfterAssassinateOpt;
private float AssassinateCooldown;
private bool CanKillAfterAssassinate;
private bool IsUndertaker;
private float MarkCooldown;
public byte MarkedPlayer;
public override bool IsEnable => PlayerIdList.Count > 0;
public override void SetupCustomOption()
{
SetupRoleOptions(Id, TabGroup.ImpostorRoles, CustomRoles.Ninja);
MarkCooldownOpt = new FloatOptionItem(Id + 10, "AssassinMarkCooldown", new(0f, 180f, 0.5f), 1f, TabGroup.ImpostorRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Ninja])
.SetValueFormat(OptionFormat.Seconds);
AssassinateCooldownOpt = new FloatOptionItem(Id + 11, "AssassinAssassinateCooldown", new(0f, 180f, 0.5f), 18.5f, TabGroup.ImpostorRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Ninja])
.SetValueFormat(OptionFormat.Seconds);
CanKillAfterAssassinateOpt = new BooleanOptionItem(Id + 12, "AssassinCanKillAfterAssassinate", true, TabGroup.ImpostorRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Ninja]);
InvisibilityTimeAfterAssassinateOpt = new FloatOptionItem(Id + 13, "AssassinInvisibilityTimeAfterAssassinate", new(0f, 30f, 0.5f), 5f, TabGroup.ImpostorRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Ninja])
.SetValueFormat(OptionFormat.Seconds);
}
public override void Init()
{
PlayerIdList = [];
MarkedPlayer = byte.MaxValue;
IsUndertaker = false;
}
public override void Add(byte playerId)
{
PlayerIdList.Add(playerId);
MarkedPlayer = byte.MaxValue;
IsUndertaker = Main.PlayerStates[playerId].MainRole == CustomRoles.Undertaker;
if (IsUndertaker)
{
MarkCooldown = Undertaker.UndertakerMarkCooldown.GetFloat();
AssassinateCooldown = Undertaker.UndertakerAssassinateCooldown.GetFloat();
CanKillAfterAssassinate = Undertaker.UndertakerCanKillAfterAssassinate.GetBool();
}
else
{
MarkCooldown = MarkCooldownOpt.GetFloat();
AssassinateCooldown = AssassinateCooldownOpt.GetFloat();
CanKillAfterAssassinate = CanKillAfterAssassinateOpt.GetBool();
}
}
public override void Remove(byte playerId)
{
PlayerIdList.Remove(playerId);
}
private void SendRPC(byte playerId)
{
if (!IsEnable || !Utils.DoRPC) return;
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetMarkedPlayer, SendOption.Reliable);
writer.Write(playerId);
writer.Write(MarkedPlayer);
AmongUsClient.Instance.FinishRpcImmediately(writer);
}
public static void ReceiveRPC(MessageReader reader)
{
byte playerId = reader.ReadByte();
byte targetId = reader.ReadByte();
if (Main.PlayerStates[playerId].Role is not Ninja ninja) return;
ninja.MarkedPlayer = targetId;
}
public override void SetKillCooldown(byte id)
{
Main.AllPlayerKillCooldown[id] = id.IsPlayerShifted() ? AdjustedDefaultKillCooldown : MarkCooldown;
}
public override void ApplyGameOptions(IGameOptions opt, byte id)
{
if (UsePhantomBasis.GetBool())
AURoleOptions.PhantomCooldown = AssassinateCooldown;
else
{
if (UsePets.GetBool()) return;
AURoleOptions.ShapeshifterCooldown = AssassinateCooldown;
}
}
public override bool CanUseKillButton(PlayerControl pc)
{
if (pc == null || !pc.IsAlive()) return false;
return CanKillAfterAssassinate || (!pc.IsShifted() && (pc.Data.Role as PhantomRole) is null or { IsInvisible: false });
}
public override bool OnCheckMurder(PlayerControl killer, PlayerControl target)
{
if (killer.IsShifted())
{
bool canUseKillButton = CanUseKillButton(killer);
if (canUseKillButton)
{
killer.ResetKillCooldown();
killer.SyncSettings();
if (Main.Invisible.Contains(killer.PlayerId) && !target.Is(CustomRoles.Bait))
{
if (!killer.RpcCheckAndMurder(target, true)) return false;
RPC.PlaySoundRPC(killer.PlayerId, Sounds.KillSound);
target.Suicide(PlayerState.DeathReason.Swooped, killer);
killer.SetKillCooldown();
return false;
}
}
return canUseKillButton;
}
MarkedPlayer = target.PlayerId;
SendRPC(killer.PlayerId);
killer.ResetKillCooldown();
killer.SetKillCooldown();
if (killer.IsModdedClient()) killer.RpcResetAbilityCooldown();
killer.SyncSettings();
killer.RPCPlayCustomSound("Clothe");
return false;
}
public override void OnPet(PlayerControl pc)
{
Take(pc);
}
public override bool OnShapeshift(PlayerControl pc, PlayerControl t, bool shapeshifting)
{
if (!pc.IsAlive() || Pelican.IsEaten(pc.PlayerId)) return false;
if (!shapeshifting) return true;
Take(pc);
return false;
}
public override bool OnVanish(PlayerControl pc)
{
if (pc == null || !pc.IsAlive() || Pelican.IsEaten(pc.PlayerId)) return false;
if (!IsUndertaker)
{
float time = InvisibilityTimeAfterAssassinateOpt.GetFloat();
if (time >= 1f)
{
pc.RpcMakeInvisible();
LateTask.New(() =>
{
if (!GameStates.IsInTask || ExileController.Instance || AntiBlackout.SkipTasks) return;
pc.RpcMakeVisible();
}, time, log: false);
}
}
Take(pc);
return false;
}
private void Take(PlayerControl pc)
{
if (MarkedPlayer != byte.MaxValue)
{
PlayerControl target = Utils.GetPlayerById(MarkedPlayer);
bool tpSuccess = IsUndertaker ? target.TP(pc) : pc.TP(target);
if (!(target == null || !target.IsAlive() || Pelican.IsEaten(target.PlayerId) || target.inVent || !GameStates.IsInTask) && tpSuccess && pc.RpcCheckAndMurder(target))
{
MarkedPlayer = byte.MaxValue;
SendRPC(pc.PlayerId);
pc.ResetKillCooldown();
pc.SyncSettings();
pc.SetKillCooldown(AdjustedDefaultKillCooldown);
}
else if (!tpSuccess) pc.Notify(GetString("TargetCannotBeTeleported"));
}
}
public override void SetButtonTexts(HudManager __instance, byte playerId)
{
bool shifted = playerId.IsPlayerShifted();
__instance.KillButton.OverrideText(!shifted ? GetString("AssassinMarkButtonText") : GetString("KillButtonText"));
if (MarkedPlayer != byte.MaxValue && !shifted)
{
if (!UsePets.GetBool())
__instance.AbilityButton.OverrideText(GetString("AssassinShapeshiftText"));
else
__instance.PetButton.OverrideText(GetString("AssassinShapeshiftText"));
}
}
}
+206 -206
View File
@@ -1,207 +1,207 @@
using System.Collections.Generic;
using AmongUs.GameOptions;
using EHR.Modules;
using Hazel;
using UnityEngine;
using static EHR.Options;
namespace EHR.Neutral;
public class Gamer : RoleBase
{
private const int Id = 10600;
public static List<byte> PlayerIdList = [];
private static Dictionary<byte, int> PlayerHealth = [];
private static Dictionary<byte, int> GamerHealth = [];
private static OptionItem KillCooldown;
private static OptionItem CanVent;
private static OptionItem HasImpostorVision;
private static OptionItem HealthMax;
private static OptionItem Damage;
private static OptionItem SelfHealthMax;
private static OptionItem SelfDamage;
public override bool IsEnable => PlayerIdList.Count > 0;
public override void SetupCustomOption()
{
SetupRoleOptions(Id, TabGroup.NeutralRoles, CustomRoles.Gamer);
KillCooldown = new FloatOptionItem(Id + 10, "GamerKillCooldown", new(1f, 180f, 1f), 2f, TabGroup.NeutralRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Gamer])
.SetValueFormat(OptionFormat.Seconds);
CanVent = new BooleanOptionItem(Id + 11, "CanVent", true, TabGroup.NeutralRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Gamer]);
HasImpostorVision = new BooleanOptionItem(Id + 13, "ImpostorVision", false, TabGroup.NeutralRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Gamer]);
HealthMax = new IntegerOptionItem(Id + 15, "GamerHealthMax", new(5, 300, 5), 100, TabGroup.NeutralRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Gamer])
.SetValueFormat(OptionFormat.Health);
Damage = new IntegerOptionItem(Id + 16, "GamerDamage", new(1, 100, 1), 15, TabGroup.NeutralRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Gamer])
.SetValueFormat(OptionFormat.Health);
SelfHealthMax = new IntegerOptionItem(Id + 17, "GamerSelfHealthMax", new(100, 100, 5), 100, TabGroup.NeutralRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Gamer])
.SetValueFormat(OptionFormat.Health);
SelfDamage = new IntegerOptionItem(Id + 18, "GamerSelfDamage", new(1, 100, 1), 35, TabGroup.NeutralRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Gamer])
.SetValueFormat(OptionFormat.Health);
}
public override void Init()
{
PlayerIdList = [];
GamerHealth = [];
PlayerHealth = [];
}
public override void Add(byte playerId)
{
PlayerIdList.Add(playerId);
GamerHealth[playerId] = SelfHealthMax.GetInt();
foreach (PlayerControl pc in Main.AllAlivePlayerControls)
PlayerHealth[pc.PlayerId] = HealthMax.GetInt();
}
public override void Remove(byte playerId)
{
PlayerIdList.Remove(playerId);
}
public override void SetKillCooldown(byte id)
{
Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat();
}
public override void ApplyGameOptions(IGameOptions opt, byte id)
{
opt.SetVision(HasImpostorVision.GetBool());
}
public override bool CanUseImpostorVentButton(PlayerControl pc)
{
return CanVent.GetBool();
}
private void SendRPC(byte playerId)
{
if (!IsEnable || !Utils.DoRPC) return;
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetGamerHealth, SendOption.Reliable);
writer.Write(playerId);
writer.Write(GamerHealth.TryGetValue(playerId, out int value) ? value : PlayerHealth[playerId]);
AmongUsClient.Instance.FinishRpcImmediately(writer);
}
public static void ReceiveRPC(MessageReader reader)
{
byte playerId = reader.ReadByte();
int health = reader.ReadInt32();
if (GamerHealth.ContainsKey(playerId))
GamerHealth[playerId] = health;
else
PlayerHealth[playerId] = health;
}
public override bool OnCheckMurder(PlayerControl killer, PlayerControl target)
{
if (killer == null || target == null || target.Is(CustomRoles.Gamer) || !PlayerHealth.TryGetValue(target.PlayerId, out var targetHealth)) return false;
killer.SetKillCooldown();
if (targetHealth - Damage.GetInt() < 1)
{
if (target.Is(CustomRoles.Pestilence))
{
target.Kill(killer);
if (target.IsLocalPlayer())
Achievements.Type.YoureTooLate.Complete();
return false;
}
PlayerHealth.Remove(target.PlayerId);
killer.RpcCheckAndMurder(target);
Utils.NotifyRoles(SpecifySeer: killer, SpecifyTarget: target);
return false;
}
PlayerHealth[target.PlayerId] -= Damage.GetInt();
SendRPC(target.PlayerId);
RPC.PlaySoundRPC(killer.PlayerId, Sounds.KillSound);
Utils.NotifyRoles(SpecifySeer: killer, SpecifyTarget: target);
Logger.Info($"{killer.GetNameWithRole().RemoveHtmlTags()} attacked {target.GetNameWithRole().RemoveHtmlTags()}, did {Damage.GetInt()} damage", "Gamer");
return false;
}
public override bool OnCheckMurderAsTarget(PlayerControl killer, PlayerControl target)
{
if (killer == null || target == null || killer.Is(CustomRoles.Gamer)) return true;
if (GamerHealth[target.PlayerId] - SelfDamage.GetInt() < 1)
{
GamerHealth.Remove(target.PlayerId);
Utils.NotifyRoles(SpecifySeer: target, SpecifyTarget: killer);
return true;
}
killer.SetKillCooldown();
GamerHealth[target.PlayerId] -= SelfDamage.GetInt();
SendRPC(target.PlayerId);
RPC.PlaySoundRPC(target.PlayerId, Sounds.KillSound);
Utils.NotifyRoles(SpecifySeer: target, SpecifyTarget: killer);
Logger.Info($"{killer.GetNameWithRole().RemoveHtmlTags()} attacked {target.GetNameWithRole().RemoveHtmlTags()}, did {SelfDamage.GetInt()} damage", "Gamer");
return false;
}
public static string TargetMark(PlayerControl seer, PlayerControl target)
{
if (!seer.IsAlive() || !PlayerIdList.Contains(seer.PlayerId)) return string.Empty;
if (seer.PlayerId == target.PlayerId)
{
return GamerHealth.TryGetValue(target.PlayerId, out int value) && value > 0
? Utils.ColorString(GetColor(value, true), $"【{value}/{SelfHealthMax.GetInt()}】")
: string.Empty;
}
else
{
return PlayerHealth.TryGetValue(target.PlayerId, out int value) && value > 0
? Utils.ColorString(GetColor(value), $"【{value}/{HealthMax.GetInt()}】")
: string.Empty;
}
}
private static Color32 GetColor(float health, bool self = false)
{
var x = (int)(health / (self ? SelfHealthMax.GetInt() : HealthMax.GetInt()) * 10 * 50);
var r = 255;
var g = 255;
if (x > 255)
r -= x - 255;
else
g = x;
return new((byte)r, (byte)g, 0, byte.MaxValue);
}
public override void SetButtonTexts(HudManager hud, byte id)
{
hud.KillButton?.OverrideText(Translator.GetString("GamerButtonText"));
}
using System.Collections.Generic;
using AmongUs.GameOptions;
using EHR.Modules;
using Hazel;
using UnityEngine;
using static EHR.Options;
namespace EHR.Neutral;
public class Demon : RoleBase
{
private const int Id = 10600;
public static List<byte> PlayerIdList = [];
private static Dictionary<byte, int> PlayerHealth = [];
private static Dictionary<byte, int> DemonHealth = [];
private static OptionItem KillCooldown;
private static OptionItem CanVent;
private static OptionItem HasImpostorVision;
private static OptionItem HealthMax;
private static OptionItem Damage;
private static OptionItem SelfHealthMax;
private static OptionItem SelfDamage;
public override bool IsEnable => PlayerIdList.Count > 0;
public override void SetupCustomOption()
{
SetupRoleOptions(Id, TabGroup.NeutralRoles, CustomRoles.Demon);
KillCooldown = new FloatOptionItem(Id + 10, "DemonKillCooldown", new(1f, 180f, 1f), 2f, TabGroup.NeutralRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Demon])
.SetValueFormat(OptionFormat.Seconds);
CanVent = new BooleanOptionItem(Id + 11, "CanVent", true, TabGroup.NeutralRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Demon]);
HasImpostorVision = new BooleanOptionItem(Id + 13, "ImpostorVision", false, TabGroup.NeutralRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Demon]);
HealthMax = new IntegerOptionItem(Id + 15, "DemonHealthMax", new(5, 300, 5), 100, TabGroup.NeutralRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Demon])
.SetValueFormat(OptionFormat.Health);
Damage = new IntegerOptionItem(Id + 16, "DemonDamage", new(1, 100, 1), 15, TabGroup.NeutralRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Demon])
.SetValueFormat(OptionFormat.Health);
SelfHealthMax = new IntegerOptionItem(Id + 17, "DemonSelfHealthMax", new(100, 100, 5), 100, TabGroup.NeutralRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Demon])
.SetValueFormat(OptionFormat.Health);
SelfDamage = new IntegerOptionItem(Id + 18, "DemonSelfDamage", new(1, 100, 1), 35, TabGroup.NeutralRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Demon])
.SetValueFormat(OptionFormat.Health);
}
public override void Init()
{
PlayerIdList = [];
DemonHealth = [];
PlayerHealth = [];
}
public override void Add(byte playerId)
{
PlayerIdList.Add(playerId);
DemonHealth[playerId] = SelfHealthMax.GetInt();
foreach (PlayerControl pc in Main.AllAlivePlayerControls)
PlayerHealth[pc.PlayerId] = HealthMax.GetInt();
}
public override void Remove(byte playerId)
{
PlayerIdList.Remove(playerId);
}
public override void SetKillCooldown(byte id)
{
Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat();
}
public override void ApplyGameOptions(IGameOptions opt, byte id)
{
opt.SetVision(HasImpostorVision.GetBool());
}
public override bool CanUseImpostorVentButton(PlayerControl pc)
{
return CanVent.GetBool();
}
private void SendRPC(byte playerId)
{
if (!IsEnable || !Utils.DoRPC) return;
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetDemonHealth, SendOption.Reliable);
writer.Write(playerId);
writer.Write(DemonHealth.TryGetValue(playerId, out int value) ? value : PlayerHealth[playerId]);
AmongUsClient.Instance.FinishRpcImmediately(writer);
}
public static void ReceiveRPC(MessageReader reader)
{
byte playerId = reader.ReadByte();
int health = reader.ReadInt32();
if (DemonHealth.ContainsKey(playerId))
DemonHealth[playerId] = health;
else
PlayerHealth[playerId] = health;
}
public override bool OnCheckMurder(PlayerControl killer, PlayerControl target)
{
if (killer == null || target == null || target.Is(CustomRoles.Demon) || !PlayerHealth.TryGetValue(target.PlayerId, out var targetHealth)) return false;
killer.SetKillCooldown();
if (targetHealth - Damage.GetInt() < 1)
{
if (target.Is(CustomRoles.Pestilence))
{
target.Kill(killer);
if (target.IsLocalPlayer())
Achievements.Type.YoureTooLate.Complete();
return false;
}
PlayerHealth.Remove(target.PlayerId);
killer.RpcCheckAndMurder(target);
Utils.NotifyRoles(SpecifySeer: killer, SpecifyTarget: target);
return false;
}
PlayerHealth[target.PlayerId] -= Damage.GetInt();
SendRPC(target.PlayerId);
RPC.PlaySoundRPC(killer.PlayerId, Sounds.KillSound);
Utils.NotifyRoles(SpecifySeer: killer, SpecifyTarget: target);
Logger.Info($"{killer.GetNameWithRole().RemoveHtmlTags()} attacked {target.GetNameWithRole().RemoveHtmlTags()}, did {Damage.GetInt()} damage", "Demon");
return false;
}
public override bool OnCheckMurderAsTarget(PlayerControl killer, PlayerControl target)
{
if (killer == null || target == null || killer.Is(CustomRoles.Demon)) return true;
if (DemonHealth[target.PlayerId] - SelfDamage.GetInt() < 1)
{
DemonHealth.Remove(target.PlayerId);
Utils.NotifyRoles(SpecifySeer: target, SpecifyTarget: killer);
return true;
}
killer.SetKillCooldown();
DemonHealth[target.PlayerId] -= SelfDamage.GetInt();
SendRPC(target.PlayerId);
RPC.PlaySoundRPC(target.PlayerId, Sounds.KillSound);
Utils.NotifyRoles(SpecifySeer: target, SpecifyTarget: killer);
Logger.Info($"{killer.GetNameWithRole().RemoveHtmlTags()} attacked {target.GetNameWithRole().RemoveHtmlTags()}, did {SelfDamage.GetInt()} damage", "Demon");
return false;
}
public static string TargetMark(PlayerControl seer, PlayerControl target)
{
if (!seer.IsAlive() || !PlayerIdList.Contains(seer.PlayerId)) return string.Empty;
if (seer.PlayerId == target.PlayerId)
{
return DemonHealth.TryGetValue(target.PlayerId, out int value) && value > 0
? Utils.ColorString(GetColor(value, true), $"【{value}/{SelfHealthMax.GetInt()}】")
: string.Empty;
}
else
{
return PlayerHealth.TryGetValue(target.PlayerId, out int value) && value > 0
? Utils.ColorString(GetColor(value), $"【{value}/{HealthMax.GetInt()}】")
: string.Empty;
}
}
private static Color32 GetColor(float health, bool self = false)
{
var x = (int)(health / (self ? SelfHealthMax.GetInt() : HealthMax.GetInt()) * 10 * 50);
var r = 255;
var g = 255;
if (x > 255)
r -= x - 255;
else
g = x;
return new((byte)r, (byte)g, 0, byte.MaxValue);
}
public override void SetButtonTexts(HudManager hud, byte id)
{
hud.KillButton?.OverrideText(Translator.GetString("DemonButtonText"));
}
}
@@ -1,47 +1,47 @@
using AmongUs.GameOptions;
namespace EHR.Neutral;
public class NSerialKiller : RoleBase
{
public static bool On;
private static OptionItem KillCooldown;
private static OptionItem CanVent;
private static OptionItem ImpostorVision;
public override bool IsEnable => On;
public override void SetupCustomOption()
{
StartSetup(12800)
.AutoSetupOption(ref KillCooldown, 22.5f, new FloatValueRule(0f, 180f, 0.5f), OptionFormat.Seconds)
.AutoSetupOption(ref CanVent, true)
.AutoSetupOption(ref ImpostorVision, true);
}
public override void Init()
{
On = false;
}
public override void Add(byte playerId)
{
On = true;
}
public override void SetKillCooldown(byte id)
{
Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat();
}
public override void ApplyGameOptions(IGameOptions opt, byte id)
{
opt.SetVision(ImpostorVision.GetBool());
}
public override bool CanUseImpostorVentButton(PlayerControl pc)
{
return CanVent.GetBool();
}
using AmongUs.GameOptions;
namespace EHR.Neutral;
public class SerialKiller : RoleBase
{
public static bool On;
private static OptionItem KillCooldown;
private static OptionItem CanVent;
private static OptionItem ImpostorVision;
public override bool IsEnable => On;
public override void SetupCustomOption()
{
StartSetup(12800)
.AutoSetupOption(ref KillCooldown, 22.5f, new FloatValueRule(0f, 180f, 0.5f), OptionFormat.Seconds)
.AutoSetupOption(ref CanVent, true)
.AutoSetupOption(ref ImpostorVision, true);
}
public override void Init()
{
On = false;
}
public override void Add(byte playerId)
{
On = true;
}
public override void SetKillCooldown(byte id)
{
Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat();
}
public override void ApplyGameOptions(IGameOptions opt, byte id)
{
opt.SetVision(ImpostorVision.GetBool());
}
public override bool CanUseImpostorVentButton(PlayerControl pc)
{
return CanVent.GetBool();
}
}