mirror of
https://github.com/Gurge44/EndlessHostRoles.git
synced 2026-10-20 01:46:25 +00:00
Add Kamikaze, Fix Disperser, Optimize Pet Suffix
This commit is contained in:
1 parent
1b1add7059
commit
38786daa7e
18 files changed
+249
-28
No files matched your search
@@ -52,6 +52,8 @@ internal static class CustomRolesHelper
|
||||
CustomRoles.SpeedBooster => CustomRoles.Crewmate,
|
||||
CustomRoles.Dictator => CustomRoles.Crewmate,
|
||||
CustomRoles.Inhibitor => CustomRoles.Impostor,
|
||||
CustomRoles.Kidnapper => CustomRoles.Shapeshifter,
|
||||
CustomRoles.Kamikaze => CustomRoles.Impostor,
|
||||
CustomRoles.Librarian => CustomRoles.Shapeshifter,
|
||||
CustomRoles.Cantankerous => CustomRoles.Impostor,
|
||||
CustomRoles.YinYanger => CustomRoles.Impostor,
|
||||
@@ -754,6 +756,8 @@ internal static class CustomRolesHelper
|
||||
CustomRoles.SerialKiller or
|
||||
CustomRoles.Underdog or
|
||||
CustomRoles.Inhibitor or
|
||||
CustomRoles.Kidnapper or
|
||||
CustomRoles.Kamikaze or
|
||||
CustomRoles.Librarian or
|
||||
CustomRoles.Cantankerous or
|
||||
CustomRoles.Duellist or
|
||||
|
||||
@@ -22,10 +22,7 @@ static class DoubleTrigger
|
||||
{
|
||||
PlayerIdList.Add(killer.PlayerId);
|
||||
}
|
||||
public static bool CanDoubleTrigger(this PlayerControl killer)
|
||||
{
|
||||
return PlayerIdList.Contains(killer.PlayerId);
|
||||
}
|
||||
public static bool CanDoubleTrigger(this PlayerControl killer) => PlayerIdList.Contains(killer.PlayerId);
|
||||
|
||||
/// <summary>
|
||||
/// Checks for whether the killer pressed their kill button twice on the same player
|
||||
@@ -41,7 +38,7 @@ static class DoubleTrigger
|
||||
{
|
||||
if (FirstTriggerTarget[killer.PlayerId] != target.PlayerId)
|
||||
{
|
||||
//2回目がターゲットずれてたら最初の相手にシングルアクション
|
||||
// If the second target is off target, single action on the first opponent.
|
||||
return false;
|
||||
}
|
||||
Logger.Info($"{killer.name} DoDoubleAction", "DoubleTrigger");
|
||||
@@ -50,7 +47,7 @@ static class DoubleTrigger
|
||||
if (doAction) FirstTriggerAction.Remove(killer.PlayerId);
|
||||
return true;
|
||||
}
|
||||
//シングルアクション時はキル間隔を無視
|
||||
// Ignore kill interval during single action
|
||||
CheckMurderPatch.TimeSinceLastKill.Remove(killer.PlayerId);
|
||||
FirstTriggerTimer.Add(killer.PlayerId, 1f);
|
||||
FirstTriggerTarget.Add(killer.PlayerId, target.PlayerId);
|
||||
|
||||
@@ -497,6 +497,8 @@ static class ExtendedPlayerControl
|
||||
CustomRoles.RiftMaker => true,
|
||||
CustomRoles.Hitman => true,
|
||||
CustomRoles.Inhibitor => true,
|
||||
CustomRoles.Kidnapper => true,
|
||||
CustomRoles.Kamikaze => true,
|
||||
CustomRoles.Cantankerous => true,
|
||||
CustomRoles.YinYanger => true,
|
||||
CustomRoles.Duellist => true,
|
||||
@@ -588,7 +590,7 @@ static class ExtendedPlayerControl
|
||||
CustomRoles.PlagueBearer => true,
|
||||
CustomRoles.Pestilence => true,
|
||||
|
||||
_ => pc.Is(CustomRoleTypes.Impostor),
|
||||
_ => pc.Is(CustomRoleTypes.Impostor) || pc.GetCustomRole().IsNK() || pc.GetCustomRole().IsTasklessCrewmate(),
|
||||
};
|
||||
}
|
||||
public static bool CanUseKillButton(this PlayerControl pc)
|
||||
@@ -627,6 +629,8 @@ static class ExtendedPlayerControl
|
||||
CustomRoles.YinYanger => pc.IsAlive(),
|
||||
CustomRoles.Librarian => pc.IsAlive() && Librarian.CanUseKillButton(pc),
|
||||
CustomRoles.Cantankerous => pc.IsAlive() && Cantankerous.CanUseKillButton(pc.PlayerId),
|
||||
CustomRoles.Kidnapper => pc.IsAlive(),
|
||||
CustomRoles.Kamikaze => pc.IsAlive(),
|
||||
CustomRoles.Inhibitor => !IsActive(SystemTypes.Electrical) && !IsActive(SystemTypes.Comms) && !IsActive(SystemTypes.MushroomMixupSabotage) && !IsActive(SystemTypes.Laboratory) && !IsActive(SystemTypes.LifeSupp) && !IsActive(SystemTypes.Reactor) && !IsActive(SystemTypes.HeliSabotage),
|
||||
CustomRoles.Saboteur => IsActive(SystemTypes.Electrical) || IsActive(SystemTypes.Comms) || IsActive(SystemTypes.MushroomMixupSabotage) || IsActive(SystemTypes.Laboratory) || IsActive(SystemTypes.LifeSupp) || IsActive(SystemTypes.Reactor) || IsActive(SystemTypes.HeliSabotage),
|
||||
CustomRoles.Sniper => Sniper.CanUseKillButton(pc),
|
||||
|
||||
@@ -652,6 +652,10 @@ public class PlayerGameOptionsSender(PlayerControl player) : GameOptionsSender
|
||||
AURoleOptions.EngineerCooldown = Sentinel.PatrolCooldown.GetFloat();
|
||||
AURoleOptions.EngineerInVentMaxTime = 1f;
|
||||
break;
|
||||
case CustomRoles.Kidnapper:
|
||||
AURoleOptions.ShapeshifterCooldown = Kidnapper.SSCD.GetFloat();
|
||||
AURoleOptions.ShapeshifterDuration = 1f;
|
||||
break;
|
||||
case CustomRoles.Spiritcaller:
|
||||
opt.SetVision(Spiritcaller.ImpostorVision.GetBool());
|
||||
break;
|
||||
|
||||
@@ -250,6 +250,7 @@ public class PlayerState(byte playerId)
|
||||
Demolished,
|
||||
YinYanged,
|
||||
Hack,
|
||||
Kamikazed,
|
||||
|
||||
etc = -1,
|
||||
}
|
||||
|
||||
@@ -1225,6 +1225,10 @@ public static class Options
|
||||
InhibitorCDAfterMeetings = FloatOptionItem.Create(1511, "AfterMeetingKillCooldown", new(0f, 180f, 2.5f), 22.5f, TabGroup.ImpostorRoles, false)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Inhibitor])
|
||||
.SetValueFormat(OptionFormat.Seconds);
|
||||
RoleLoadingText = "Impostor roles\nKamikaze";
|
||||
Kamikaze.SetupCustomOption();
|
||||
RoleLoadingText = "Impostor roles\nKidnapper";
|
||||
Kidnapper.SetupCustomOption();
|
||||
RoleLoadingText = "Impostor roles\nLibrarian";
|
||||
Librarian.SetupCustomOption();
|
||||
RoleLoadingText = "Impostor roles\nCantankerous";
|
||||
|
||||
@@ -58,6 +58,8 @@ enum CustomRPC
|
||||
|
||||
//Roles
|
||||
SetDrawPlayer,
|
||||
SyncKamikazeLimit,
|
||||
KamikazeAddTarget,
|
||||
SyncMycologist,
|
||||
SyncBubble,
|
||||
AddTornado,
|
||||
@@ -593,6 +595,12 @@ internal class RPCHandlerPatch
|
||||
case CustomRPC.SyncBubble:
|
||||
Bubble.ReceiveRPC(reader);
|
||||
break;
|
||||
case CustomRPC.KamikazeAddTarget:
|
||||
Kamikaze.ReceiveRPCAddTarget(reader);
|
||||
break;
|
||||
case CustomRPC.SyncKamikazeLimit:
|
||||
Kamikaze.ReceiveRPCSyncLimit(reader);
|
||||
break;
|
||||
case CustomRPC.SetCurrentDousingTarget:
|
||||
byte arsonistId = reader.ReadByte();
|
||||
byte dousingTargetId = reader.ReadByte();
|
||||
@@ -1266,6 +1274,12 @@ internal static class RPC
|
||||
case CustomRoles.EvilDiviner:
|
||||
EvilDiviner.Add(targetId);
|
||||
break;
|
||||
case CustomRoles.Kamikaze:
|
||||
Kamikaze.Add(targetId);
|
||||
break;
|
||||
case CustomRoles.Disperser:
|
||||
Disperser.Add(targetId);
|
||||
break;
|
||||
case CustomRoles.Medic:
|
||||
Medic.Add(targetId);
|
||||
break;
|
||||
|
||||
+13
-12
@@ -317,23 +317,24 @@ class BeginCrewmatePatch
|
||||
CustomRoles.Disperser
|
||||
=> ShipStatus.Instance.VentMoveSounds.FirstOrDefault(),
|
||||
|
||||
_ => PlayerControl.LocalPlayer.Is(RoleTypes.Impostor) ? PlayerControl.LocalPlayer.Is(RoleTypes.Shapeshifter) ? GetIntroSound(RoleTypes.Shapeshifter) : GetIntroSound(RoleTypes.Impostor) : GetIntroSound(RoleTypes.Crewmate),
|
||||
_ => role.GetCustomRoleTypes() switch
|
||||
{
|
||||
CustomRoleTypes.Impostor => GetIntroSound(RoleTypes.Impostor),
|
||||
CustomRoleTypes.Crewmate => GetIntroSound(RoleTypes.Crewmate),
|
||||
CustomRoleTypes.Neutral => GetIntroSound(RoleTypes.Shapeshifter),
|
||||
_ => GetIntroSound(RoleTypes.Crewmate),
|
||||
}
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
switch (role.GetCustomRoleTypes())
|
||||
PlayerControl.LocalPlayer.Data.Role.IntroSound = role.GetCustomRoleTypes() switch
|
||||
{
|
||||
case CustomRoleTypes.Impostor:
|
||||
PlayerControl.LocalPlayer.Data.Role.IntroSound = GetIntroSound(RoleTypes.Impostor);
|
||||
break;
|
||||
case CustomRoleTypes.Crewmate:
|
||||
PlayerControl.LocalPlayer.Data.Role.IntroSound = GetIntroSound(RoleTypes.Crewmate);
|
||||
break;
|
||||
case CustomRoleTypes.Neutral:
|
||||
PlayerControl.LocalPlayer.Data.Role.IntroSound = GetIntroSound(RoleTypes.Shapeshifter);
|
||||
break;
|
||||
}
|
||||
CustomRoleTypes.Impostor => GetIntroSound(RoleTypes.Impostor),
|
||||
CustomRoleTypes.Crewmate => GetIntroSound(RoleTypes.Crewmate),
|
||||
CustomRoleTypes.Neutral => GetIntroSound(RoleTypes.Shapeshifter),
|
||||
_ => GetIntroSound(RoleTypes.Crewmate),
|
||||
};
|
||||
Logger.Warn($"Could not set intro sound\n{ex}", "IntroSound");
|
||||
}
|
||||
|
||||
|
||||
@@ -217,6 +217,9 @@ class CheckMurderPatch
|
||||
case CustomRoles.BountyHunter:
|
||||
BountyHunter.OnCheckMurder(killer, target);
|
||||
break;
|
||||
case CustomRoles.Kamikaze:
|
||||
if (!Kamikaze.OnCheckMurder(killer, target)) return false;
|
||||
break;
|
||||
case CustomRoles.Reckless:
|
||||
Reckless.OnCheckMurder(killer);
|
||||
break;
|
||||
@@ -1210,6 +1213,7 @@ class MurderPlayerPatch
|
||||
break;
|
||||
case CustomRoles.Hacker:
|
||||
Hacker.HackLimit[killer.PlayerId] += Hacker.HackerAbilityUseGainWithEachKill.GetFloat();
|
||||
Hacker.SendRPC(killer.PlayerId);
|
||||
break;
|
||||
case CustomRoles.Camouflager:
|
||||
Camouflager.CamoLimit[killer.PlayerId] += Camouflager.CamoAbilityUseGainWithEachKill.GetFloat();
|
||||
@@ -1235,6 +1239,10 @@ class MurderPlayerPatch
|
||||
case CustomRoles.Twister:
|
||||
Twister.TwistLimit[killer.PlayerId] += Twister.TwisterAbilityUseGainWithEachKill.GetFloat();
|
||||
break;
|
||||
case CustomRoles.Kamikaze:
|
||||
Kamikaze.MarkLimit[killer.PlayerId] += Kamikaze.KamikazeAbilityUseGainWithEachKill.GetFloat();
|
||||
Kamikaze.SendRPCSyncLimit(killer.PlayerId);
|
||||
break;
|
||||
}
|
||||
|
||||
if (killer.Is(CustomRoles.TicketsStealer) && killer.PlayerId != target.PlayerId)
|
||||
@@ -1367,6 +1375,10 @@ class ShapeshiftPatch
|
||||
EvilTracker.OnShapeshift(shapeshifter, target, shapeshifting);
|
||||
isSSneeded = false;
|
||||
break;
|
||||
case CustomRoles.Kidnapper:
|
||||
Kidnapper.OnShapeshift(shapeshifter, target);
|
||||
isSSneeded = false;
|
||||
break;
|
||||
case CustomRoles.RiftMaker:
|
||||
RiftMaker.OnShapeshift(shapeshifter, shapeshifting);
|
||||
isSSneeded = false;
|
||||
@@ -2011,6 +2023,7 @@ class FixedUpdatePatch
|
||||
private static int LevelKickBufferTime = 10;
|
||||
private static readonly Dictionary<byte, int> BufferTime = [];
|
||||
private static readonly Dictionary<byte, int> DeadBufferTime = [];
|
||||
private static readonly Dictionary<byte, long> LastUpdate = [];
|
||||
|
||||
public static async void Postfix(PlayerControl __instance)
|
||||
{
|
||||
@@ -2137,6 +2150,9 @@ class FixedUpdatePatch
|
||||
case CustomRoles.BountyHunter:
|
||||
BountyHunter.FixedUpdate(player);
|
||||
break;
|
||||
case CustomRoles.Kamikaze when !lowLoad:
|
||||
Kamikaze.OnFixedUpdate();
|
||||
break;
|
||||
case CustomRoles.Glitch when !lowLoad:
|
||||
Glitch.UpdateHackCooldown(player);
|
||||
break;
|
||||
@@ -2233,7 +2249,8 @@ class FixedUpdatePatch
|
||||
}
|
||||
}
|
||||
|
||||
if (!lowLoad && Options.UsePets.GetBool() && GameStates.IsInTask)
|
||||
long now = GetTimeStamp();
|
||||
if (!lowLoad && Options.UsePets.GetBool() && GameStates.IsInTask && (!LastUpdate.TryGetValue(playerId, out var lastPetNotify) || lastPetNotify < now))
|
||||
{
|
||||
if (Main.AbilityCD.TryGetValue(playerId, out var timer))
|
||||
{
|
||||
@@ -2242,6 +2259,7 @@ class FixedUpdatePatch
|
||||
Main.AbilityCD.Remove(playerId);
|
||||
}
|
||||
if (!player.IsModClient()) NotifyRoles(SpecifySeer: player, SpecifyTarget: player);
|
||||
LastUpdate[playerId] = now;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -141,10 +141,14 @@ class OnPlayerLeftPatch
|
||||
Spiritualist.RemoveTarget();
|
||||
if (data.Character.PlayerId == Postman.Target)
|
||||
Postman.SetNewTarget();
|
||||
if (Main.PlayerStates[data.Character.PlayerId].deathReason == PlayerState.DeathReason.etc) //死因が設定されていなかったら
|
||||
PlayerState state = Main.PlayerStates[data.Character.PlayerId];
|
||||
if (state.deathReason == PlayerState.DeathReason.etc) // If no cause of death was established
|
||||
{
|
||||
Main.PlayerStates[data.Character.PlayerId].deathReason = PlayerState.DeathReason.Disconnected;
|
||||
Main.PlayerStates[data.Character.PlayerId].SetDead();
|
||||
state.deathReason = PlayerState.DeathReason.Disconnected;
|
||||
}
|
||||
if (!state.IsDead)
|
||||
{
|
||||
state.SetDead();
|
||||
}
|
||||
NameNotifyManager.Notice.Remove(data.Character.PlayerId);
|
||||
AntiBlackout.OnDisconnect(data.Character.Data);
|
||||
|
||||
@@ -196,6 +196,7 @@ internal class ChangeRoleSettings
|
||||
BountyHunter.Init();
|
||||
SerialKiller.Init();
|
||||
EvilDiviner.Init();
|
||||
Kamikaze.Init();
|
||||
FireWorks.Init();
|
||||
NiceSwapper.Init();
|
||||
Pickpocket.Init();
|
||||
@@ -804,6 +805,9 @@ internal class SelectRolesPatch
|
||||
case CustomRoles.EvilDiviner:
|
||||
EvilDiviner.Add(pc.PlayerId);
|
||||
break;
|
||||
case CustomRoles.Kamikaze:
|
||||
Kamikaze.Add(pc.PlayerId);
|
||||
break;
|
||||
case CustomRoles.Ritualist:
|
||||
Ritualist.Add(pc.PlayerId);
|
||||
break;
|
||||
|
||||
@@ -1604,6 +1604,7 @@
|
||||
"DeathReason.Jinx": "Jinxed",
|
||||
"DeathReason.Demolished": "Demolished",
|
||||
"DeathReason.YinYanged": "Yin Yanged",
|
||||
"DeathReason.Kamikazed": "Kamikazed",
|
||||
"DeathReason.etc": "Other",
|
||||
"DeathReason.Hack": "Hacked",
|
||||
"DeathReason.Curse": "Cursed",
|
||||
@@ -2324,7 +2325,7 @@
|
||||
"DivinatorCheck.Result4": "<b>{0}</b> is either Pestilence, Electric, Plaguebearer, Donut Delivery, Observer, Blood Knight, Guardian, or Wildling",
|
||||
"DivinatorCheck.Result5": "<b>{0}</b> is either Bard, Sentinel, Ricochet, Juggernaut, Security Guard, Arrogance, Killing Machine, or Butcher",
|
||||
"DivinatorCheck.Result6": "<b>{0}</b> is either Coroner, Mole, Stealth, Evil Tracker, Mortician, Tracefinder, Romantic, or Tracker",
|
||||
"DivinatorCheck.Result7": "<b>{0}</b> is either Bodyguard, Bomber, Lookout, Vengeful Romantic, Ruthless Romantic, Fireworker, or Nuker",
|
||||
"DivinatorCheck.Result7": "<b>{0}</b> is either Bodyguard, Bomber, Lookout, Vengeful Romantic, Ruthless Romantic, Kidnapper, Fireworker, or Nuker",
|
||||
"DivinatorCheck.Result8": "<b>{0}</b> is either Bounty Hunter, Sprayer, Mafioso, Detective, Hater, Cleaner, Medusa, or Psychic",
|
||||
"DivinatorCheck.Result9": "<b>{0}</b> is either Convict, Penguin, Hookshot, Executioner, Lawyer, Snitch, Disperser, or Doctor",
|
||||
"DivinatorCheck.Result10": "<b>{0}</b> is either Councillor, Escort, Bubble, Shiftguard, Dictator, Judge, Cleanser, or Cursed Wolf",
|
||||
@@ -2335,7 +2336,7 @@
|
||||
"DivinatorCheck.Result15": "<b>{0}</b> is either Infectious, Detour, Virus, Agitator, Monarch, Revolutionist, Express, or Cultist",
|
||||
"DivinatorCheck.Result16": "<b>{0}</b> is either Innocent, Gaulois, Sapper, Refugee, Bandit, Inhibitor, Mechanic, or Saboteur",
|
||||
"DivinatorCheck.Result17": "<b>{0}</b> is either Medic, Vector, Analyzer, RiftMaker, Jester, The Glitch, Lurker, or Sunnyboy",
|
||||
"DivinatorCheck.Result18": "<b>{0}</b> is either Nemesis, Hitman, Gangster, Glitch, Luckey, or Underdog",
|
||||
"DivinatorCheck.Result18": "<b>{0}</b> is either Nemesis, Hitman, Gangster, Glitch, Kamikaze, Luckey, or Underdog",
|
||||
"DivinatorCheck.Result19": "<b>{0}</b> is either Evil Guesser, Nice Guesser, Blackmailer, Eclipse, Reckless, Stalker, Camouflager, or Chameleon",
|
||||
"DivinatorCheck.Result20": "<b>{0}</b> is either Jackal, Sidekick, Duellist, WeaponMaster, Maverick, Opportunist, Pursuer, or Provocateur",
|
||||
"DivinatorCheck.Result21": "<b>{0}</b> is either Poisoner, Magician, Yin Yanger, Vampire, Pacifist, Head Hunter, Soul Catcher, or Traitor",
|
||||
@@ -2395,6 +2396,13 @@
|
||||
"pet_UFO": "UFO",
|
||||
"pet_D2WormPet": "Worm",
|
||||
"pet_RANDOM_FOR_EVERYONE": "<color=#ffff00>Random</color>",
|
||||
"Kidnapper": "Kidnapper",
|
||||
"KidnapperInfo": "TP Players to you by shifting into them",
|
||||
"KidnapperInfoLong": "(Impostors):\\nAs the Kidnapper, when you shapeshift into someone, they teleport to you.",
|
||||
"Kamikaze": "Kamikaze",
|
||||
"KamikazeInfo": "Mark Players That Die With You",
|
||||
"KamikazeInfoLong": "(Impostors):\\nAs the Kamikaze, you can mark players by clicking your kill button once on them. When you die, all players that you marked will also die. You can kill normally by double clicking your kill button on someone.",
|
||||
"KamikazeMarkCD": "Cooldown After Marking",
|
||||
"Jailor": "Jailor",
|
||||
"JailorInfo": "Lock up your target in Jail",
|
||||
"JailorInfoLong": "(Crewmates):\\nAs the Jailor, use your kill button to lock a player in jail. Jailed players cannot be guessed or judged and jailed players can only guess Jailor.",
|
||||
|
||||
@@ -167,6 +167,7 @@ public static class Divinator
|
||||
CustomRoles.Lookout or
|
||||
CustomRoles.RuthlessRomantic or
|
||||
CustomRoles.VengefulRomantic or
|
||||
CustomRoles.Kidnapper or
|
||||
CustomRoles.Nuker
|
||||
=> "Result7",
|
||||
|
||||
@@ -278,6 +279,7 @@ public static class Divinator
|
||||
CustomRoles.Doppelganger or
|
||||
CustomRoles.Hitman or
|
||||
CustomRoles.Luckey or
|
||||
CustomRoles.Kamikaze or
|
||||
CustomRoles.Underdog
|
||||
=> "Result18",
|
||||
|
||||
|
||||
@@ -80,6 +80,7 @@ namespace TOHE.Roles.Crewmate
|
||||
private static OptionItem OptionCanSellExperimental;
|
||||
private static OptionItem OptionSellOnlyHarmfulToEvil;
|
||||
private static OptionItem OptionSellOnlyHelpfulToCrew;
|
||||
private static OptionItem OptionGivesAllMoneyOnBribe;
|
||||
|
||||
private static int GetCurrentAmountOfMoney(byte playerId) => (addonsSold[playerId] * OptionMoneyPerSell.GetInt()) - (bribedKiller[playerId].Count * OptionMoneyRequiredToBribe.GetInt());
|
||||
|
||||
@@ -101,8 +102,9 @@ namespace TOHE.Roles.Crewmate
|
||||
OptionSellOnlyEnabledAddons = BooleanOptionItem.Create(Id + 16, "MerchantSellOnlyEnabledAddons", false, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Merchant]);
|
||||
OptionSellOnlyHarmfulToEvil = BooleanOptionItem.Create(Id + 14, "MerchantSellHarmfulToEvil", false, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Merchant]);
|
||||
OptionSellOnlyHelpfulToCrew = BooleanOptionItem.Create(Id + 15, "MerchantSellHelpfulToCrew", false, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Merchant]);
|
||||
OptionGivesAllMoneyOnBribe = BooleanOptionItem.Create(Id + 17, "MerchantGivesAllMoneyOnBribe", false, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Merchant]);
|
||||
|
||||
OverrideTasksData.Create(Id + 17, TabGroup.CrewmateRoles, CustomRoles.Merchant);
|
||||
OverrideTasksData.Create(Id + 18, TabGroup.CrewmateRoles, CustomRoles.Merchant);
|
||||
}
|
||||
public static void Init()
|
||||
{
|
||||
@@ -204,7 +206,7 @@ namespace TOHE.Roles.Crewmate
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bribedKiller[target.PlayerId].Contains(killer.PlayerId))
|
||||
if (IsBribedKiller(killer, target))
|
||||
{
|
||||
NotifyBribery(killer, target);
|
||||
return true;
|
||||
@@ -224,6 +226,8 @@ namespace TOHE.Roles.Crewmate
|
||||
|
||||
private static void NotifyBribery(PlayerControl killer, PlayerControl target)
|
||||
{
|
||||
if (OptionGivesAllMoneyOnBribe.GetBool()) addonsSold[target.PlayerId] = 0;
|
||||
|
||||
killer.Notify(Utils.ColorString(Utils.GetRoleColor(CustomRoles.Merchant), GetString("BribedByMerchant")));
|
||||
|
||||
if (OptionNotifyBribery.GetBool())
|
||||
|
||||
@@ -42,7 +42,7 @@ public static class Hacker
|
||||
HackLimit.TryAdd(playerId, HackLimitOpt.GetInt());
|
||||
}
|
||||
public static bool IsEnable => playerIdList.Count > 0;
|
||||
private static void SendRPC(byte playerId)
|
||||
public static void SendRPC(byte playerId)
|
||||
{
|
||||
if (!IsEnable || !Utils.DoRPC) return;
|
||||
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetHackerHackLimit, SendOption.Reliable, -1);
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
using Epic.OnlineServices;
|
||||
using Hazel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static TOHE.Options;
|
||||
using static TOHE.Translator;
|
||||
using static TOHE.Utils;
|
||||
|
||||
namespace TOHE.Roles.Impostor
|
||||
{
|
||||
internal class Kamikaze
|
||||
{
|
||||
private static int Id => 643310;
|
||||
public static bool IsEnable = false;
|
||||
|
||||
private static readonly Dictionary<byte, List<byte>> MarkedPlayers = [];
|
||||
public static readonly Dictionary<byte, float> MarkLimit = [];
|
||||
|
||||
private static OptionItem MarkCD;
|
||||
private static OptionItem KamikazeLimitOpt;
|
||||
public static OptionItem KamikazeAbilityUseGainWithEachKill;
|
||||
|
||||
public static void SetupCustomOption()
|
||||
{
|
||||
SetupRoleOptions(Id, TabGroup.ImpostorRoles, CustomRoles.Kamikaze);
|
||||
MarkCD = FloatOptionItem.Create(Id + 2, "KamikazeMarkCD", new(0f, 180f, 2.5f), 30f, TabGroup.ImpostorRoles, false)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Kamikaze])
|
||||
.SetValueFormat(OptionFormat.Seconds);
|
||||
KamikazeLimitOpt = IntegerOptionItem.Create(Id + 5, "AbilityUseLimit", new(0, 5, 1), 1, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Kamikaze])
|
||||
.SetValueFormat(OptionFormat.Times);
|
||||
KamikazeAbilityUseGainWithEachKill = FloatOptionItem.Create(Id + 6, "AbilityUseGainWithEachKill", new(0f, 5f, 0.1f), 0.5f, TabGroup.ImpostorRoles, false)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Kamikaze])
|
||||
.SetValueFormat(OptionFormat.Times);
|
||||
}
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
MarkedPlayers.Clear();
|
||||
MarkLimit.Clear();
|
||||
IsEnable = false;
|
||||
}
|
||||
|
||||
public static void Add(byte playerId)
|
||||
{
|
||||
MarkedPlayers[playerId] = [];
|
||||
MarkLimit[playerId] = KamikazeLimitOpt.GetInt();
|
||||
IsEnable = true;
|
||||
}
|
||||
|
||||
public static void SendRPCSyncLimit(byte playerId)
|
||||
{
|
||||
if (!IsEnable || !DoRPC || playerId == 0) return;
|
||||
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SyncKamikazeLimit, SendOption.Reliable, -1);
|
||||
writer.Write(playerId);
|
||||
writer.Write(MarkLimit[playerId]);
|
||||
AmongUsClient.Instance.FinishRpcImmediately(writer);
|
||||
}
|
||||
|
||||
private static void SendRPCAddTarget(byte kamikazeId, byte targetId)
|
||||
{
|
||||
if (!IsEnable || !DoRPC || kamikazeId == 0) return;
|
||||
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.KamikazeAddTarget, SendOption.Reliable, -1);
|
||||
writer.Write(kamikazeId);
|
||||
writer.Write(targetId);
|
||||
AmongUsClient.Instance.FinishRpcImmediately(writer);
|
||||
}
|
||||
|
||||
public static void ReceiveRPCSyncLimit(MessageReader reader)
|
||||
{
|
||||
byte playerId = reader.ReadByte();
|
||||
float limit = reader.ReadSingle();
|
||||
MarkLimit[playerId] = limit;
|
||||
}
|
||||
|
||||
public static void ReceiveRPCAddTarget(MessageReader reader)
|
||||
{
|
||||
byte playerId = reader.ReadByte();
|
||||
byte targetId = reader.ReadByte();
|
||||
MarkedPlayers[playerId].Add(targetId);
|
||||
}
|
||||
|
||||
public static bool OnCheckMurder(PlayerControl killer, PlayerControl target)
|
||||
{
|
||||
if (killer == null || target == null) return false;
|
||||
if (MarkLimit.TryGetValue(killer.PlayerId, out var limit) && limit < 1) return true;
|
||||
return killer.CheckDoubleTrigger(target, () =>
|
||||
{
|
||||
MarkedPlayers[killer.PlayerId].Add(target.PlayerId);
|
||||
SendRPCAddTarget(killer.PlayerId, target.PlayerId);
|
||||
killer.SetKillCooldown(MarkCD.GetFloat());
|
||||
MarkLimit[killer.PlayerId]--;
|
||||
SendRPCSyncLimit(killer.PlayerId);
|
||||
});
|
||||
}
|
||||
|
||||
public static void OnFixedUpdate()
|
||||
{
|
||||
if (!IsEnable) return;
|
||||
|
||||
foreach (var kvp in MarkedPlayers)
|
||||
{
|
||||
var kamikazePc = GetPlayerById(kvp.Key);
|
||||
if (kamikazePc.IsAlive()) continue;
|
||||
|
||||
foreach (var id in kvp.Value)
|
||||
{
|
||||
var victim = GetPlayerById(id);
|
||||
if (victim == null || !victim.IsAlive()) continue;
|
||||
victim.Suicide(PlayerState.DeathReason.Kamikazed, kamikazePc);
|
||||
}
|
||||
|
||||
kvp.Value.Clear();
|
||||
MarkedPlayers.Remove(kvp.Key);
|
||||
Logger.Info($"Murder {kamikazePc.GetRealName()}'s targets: {string.Join(", ", kvp.Value.Select(x => GetPlayerById(x).GetNameWithRole()))}", "Kamikaze");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static TOHE.Options;
|
||||
using static TOHE.Translator;
|
||||
using static TOHE.Utils;
|
||||
|
||||
namespace TOHE.Roles.Impostor
|
||||
{
|
||||
internal class Kidnapper
|
||||
{
|
||||
private static int Id => 643300;
|
||||
public static OptionItem SSCD;
|
||||
public static void SetupCustomOption()
|
||||
{
|
||||
SetupRoleOptions(Id, TabGroup.ImpostorRoles, CustomRoles.Kidnapper);
|
||||
SSCD = FloatOptionItem.Create(Id + 2, "ShapeshiftCooldown", new(0f, 180f, 2.5f), 30f, TabGroup.ImpostorRoles, false)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Kidnapper])
|
||||
.SetValueFormat(OptionFormat.Seconds);
|
||||
}
|
||||
public static void OnShapeshift(PlayerControl kidnapper, PlayerControl target)
|
||||
{
|
||||
if (kidnapper == null || target == null) return;
|
||||
target.TP(kidnapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user