mirror of
https://github.com/Gurge44/EndlessHostRoles.git
synced 2026-10-19 15:51:58 +00:00
286 lines
11 KiB
C#
286 lines
11 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using AmongUs.GameOptions;
|
|
using EHR.Modules;
|
|
using Hazel;
|
|
using static EHR.Options;
|
|
using static EHR.Translator;
|
|
|
|
namespace EHR.Roles;
|
|
|
|
public class Jackal : RoleBase
|
|
{
|
|
private const int Id = 12100;
|
|
public static List<Jackal> Instances = [];
|
|
|
|
private static OptionItem KillCooldown;
|
|
private static OptionItem CanVent;
|
|
public static OptionItem CanSabotage;
|
|
public static OptionItem HasImpostorVision;
|
|
public static OptionItem ResetKillCooldownWhenSbGetKilled;
|
|
private static OptionItem ResetKillCooldownOn;
|
|
private static OptionItem CanRecruitImpostors;
|
|
private static OptionItem CanRecruitMadmates;
|
|
public static OptionItem SidekickCountMode;
|
|
public static OptionItem SKCanKill;
|
|
public static OptionItem KillCooldownSK;
|
|
public static OptionItem CanVentSK;
|
|
public static OptionItem CanSabotageSK;
|
|
private static OptionItem SKPromotesToJackal;
|
|
private static OptionItem PromotedSKCanRecruit;
|
|
|
|
public static bool On;
|
|
|
|
public byte SidekickId;
|
|
private byte JackalId;
|
|
|
|
public override bool IsEnable => Instances.Count > 0;
|
|
|
|
public override void SetupCustomOption()
|
|
{
|
|
SetupRoleOptions(Id, TabGroup.NeutralRoles, CustomRoles.Jackal);
|
|
|
|
KillCooldown = new FloatOptionItem(Id + 2, "KillCooldown", new(0f, 180f, 0.5f), 22.5f, TabGroup.NeutralRoles)
|
|
.SetParent(CustomRoleSpawnChances[CustomRoles.Jackal])
|
|
.SetValueFormat(OptionFormat.Seconds);
|
|
|
|
CanVent = new BooleanOptionItem(Id + 3, "CanVent", true, TabGroup.NeutralRoles)
|
|
.SetParent(CustomRoleSpawnChances[CustomRoles.Jackal]);
|
|
|
|
CanSabotage = new BooleanOptionItem(Id + 4, "CanSabotage", true, TabGroup.NeutralRoles)
|
|
.SetParent(CustomRoleSpawnChances[CustomRoles.Jackal]);
|
|
|
|
HasImpostorVision = new BooleanOptionItem(Id + 6, "ImpostorVision", true, TabGroup.NeutralRoles)
|
|
.SetParent(CustomRoleSpawnChances[CustomRoles.Jackal]);
|
|
|
|
ResetKillCooldownWhenSbGetKilled = new BooleanOptionItem(Id + 7, "ResetKillCooldownWhenPlayerGetKilled", false, TabGroup.NeutralRoles)
|
|
.SetParent(CustomRoleSpawnChances[CustomRoles.Jackal]);
|
|
|
|
ResetKillCooldownOn = new FloatOptionItem(Id + 8, "ResetKillCooldownOn", new(0f, 180f, 0.5f), 15f, TabGroup.NeutralRoles)
|
|
.SetParent(ResetKillCooldownWhenSbGetKilled)
|
|
.SetValueFormat(OptionFormat.Seconds);
|
|
|
|
OptionItem SKOpts = new BooleanOptionItem(Id + 9, "SidekickSettings", true, TabGroup.NeutralRoles)
|
|
.SetParent(CustomRoleSpawnChances[CustomRoles.Jackal]);
|
|
|
|
CanRecruitImpostors = new BooleanOptionItem(Id + 10, "JackalCanRecruitImpostors", true, TabGroup.NeutralRoles)
|
|
.SetParent(SKOpts);
|
|
|
|
CanRecruitMadmates = new BooleanOptionItem(Id + 11, "JackalCanRecruitMadmates", true, TabGroup.NeutralRoles)
|
|
.SetParent(CanRecruitImpostors);
|
|
|
|
JackalCanKillSidekick = new BooleanOptionItem(Id + 12, "JackalCanKillSidekick", false, TabGroup.NeutralRoles)
|
|
.SetParent(SKOpts);
|
|
|
|
SKCanKill = new BooleanOptionItem(Id + 13, "SKCanKill", true, TabGroup.NeutralRoles)
|
|
.SetParent(SKOpts);
|
|
|
|
KillCooldownSK = new FloatOptionItem(Id + 14, "KillCooldown", new(0f, 180f, 0.5f), 20f, TabGroup.NeutralRoles)
|
|
.SetParent(SKCanKill)
|
|
.SetValueFormat(OptionFormat.Seconds);
|
|
|
|
SidekickCanKillJackal = new BooleanOptionItem(Id + 15, "SidekickCanKillJackal", false, TabGroup.NeutralRoles)
|
|
.SetParent(SKCanKill);
|
|
|
|
SidekickCanKillSidekick = new BooleanOptionItem(Id + 16, "SidekickCanKillSidekick", false, TabGroup.NeutralRoles)
|
|
.SetParent(SKCanKill);
|
|
|
|
CanVentSK = new BooleanOptionItem(Id + 17, "CanVent", true, TabGroup.NeutralRoles)
|
|
.SetParent(SKOpts);
|
|
|
|
CanSabotageSK = new BooleanOptionItem(Id + 18, "CanSabotage", true, TabGroup.NeutralRoles)
|
|
.SetParent(SKOpts);
|
|
|
|
SKPromotesToJackal = new BooleanOptionItem(Id + 19, "SKPromotesToJackal", true, TabGroup.NeutralRoles)
|
|
.SetParent(SKOpts);
|
|
|
|
PromotedSKCanRecruit = new BooleanOptionItem(Id + 20, "PromotedSKCanRecruit", true, TabGroup.NeutralRoles)
|
|
.SetParent(SKPromotesToJackal);
|
|
|
|
SidekickCountMode = new StringOptionItem(Id + 21, "SidekickCountMode", Options.SidekickCountMode, 0, TabGroup.NeutralRoles)
|
|
.SetParent(SKOpts);
|
|
}
|
|
|
|
public override void Init()
|
|
{
|
|
Instances = [];
|
|
On = false;
|
|
}
|
|
|
|
public override void Add(byte playerId)
|
|
{
|
|
On = true;
|
|
Instances.Add(this);
|
|
playerId.SetAbilityUseLimit(1);
|
|
SidekickId = byte.MaxValue;
|
|
JackalId = playerId;
|
|
}
|
|
|
|
public override void Remove(byte playerId)
|
|
{
|
|
Instances.Remove(this);
|
|
}
|
|
|
|
public override void SetKillCooldown(byte id)
|
|
{
|
|
Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat();
|
|
}
|
|
|
|
public override bool CanUseImpostorVentButton(PlayerControl pc)
|
|
{
|
|
return CanVent.GetBool();
|
|
}
|
|
|
|
public override bool CanUseSabotage(PlayerControl pc)
|
|
{
|
|
return base.CanUseSabotage(pc) || CanSabotage.GetBool() && pc.IsAlive();
|
|
}
|
|
|
|
public override void SetButtonTexts(HudManager hud, byte id)
|
|
{
|
|
hud.KillButton.OverrideText(id.GetAbilityUseLimit() > 0 ? $"{GetString("GangsterButtonText")}" : $"{GetString("KillButtonText")}");
|
|
hud.SabotageButton.ToggleVisible(CanSabotage.GetBool());
|
|
}
|
|
|
|
public override void ApplyGameOptions(IGameOptions opt, byte id)
|
|
{
|
|
opt.SetVision(HasImpostorVision.GetBool());
|
|
}
|
|
|
|
public static void AfterPlayerDiedTask(PlayerControl target)
|
|
{
|
|
if (target.Is(CustomRoles.Jackal)) return;
|
|
|
|
Main.EnumerateAlivePlayerControls()
|
|
.Where(x => x.Is(CustomRoles.Jackal))
|
|
.Do(x => x.SetKillCooldown(ResetKillCooldownOn.GetFloat()));
|
|
}
|
|
|
|
public override bool OnCheckMurder(PlayerControl killer, PlayerControl target)
|
|
{
|
|
if (killer.GetAbilityUseLimit() < 1 || !CanBeSidekick(target)) return true;
|
|
|
|
var sender = CustomRpcSender.Create("Jackal.OnCheckMurder", SendOption.Reliable);
|
|
var hasValue = false;
|
|
|
|
killer.RpcRemoveAbilityUse(notify: false);
|
|
target.RpcSetCustomRole(CustomRoles.Sidekick);
|
|
target.RpcChangeRoleBasis(CustomRoles.Sidekick);
|
|
SidekickId = target.PlayerId;
|
|
|
|
Main.ResetCamPlayerList.Add(target.PlayerId);
|
|
|
|
hasValue |= CustomRpcSenderExtensions.Notify(ref sender, killer, CustomRoles.Jackal.ColoredTextByRole(GetString("GangsterSuccessfullyRecruited")), setName: false);
|
|
hasValue |= sender.SetKillCooldown(killer, 3f);
|
|
hasValue |= sender.NotifyRolesSpecific(killer, target, out sender, out bool cleared);
|
|
if (cleared) hasValue = false;
|
|
|
|
hasValue |= CustomRpcSenderExtensions.Notify(ref sender, target, CustomRoles.Jackal.ColoredTextByRole(GetString("BeRecruitedByJackal")), setName: false);
|
|
hasValue |= sender.RpcGuardAndKill(target, killer);
|
|
hasValue |= sender.RpcGuardAndKill(target, target);
|
|
hasValue |= sender.NotifyRolesSpecific(target, killer, out sender, out cleared);
|
|
if (cleared) hasValue = false;
|
|
|
|
sender.SendMessage(!hasValue);
|
|
|
|
Logger.Info($" {target.Data?.PlayerName} = {target.GetCustomRole()} + {CustomRoles.Sidekick}", $"Assign {CustomRoles.Sidekick}");
|
|
|
|
if (killer.AmOwner)
|
|
Achievements.Type.YoureMyFriendNow.Complete();
|
|
|
|
return false;
|
|
}
|
|
|
|
private static bool CanBeSidekick(PlayerControl pc)
|
|
{
|
|
if (!CanRecruitImpostors.GetBool() && pc.Is(CustomRoleTypes.Impostor)) return false;
|
|
if (!CanRecruitMadmates.GetBool() && pc.IsMadmate()) return false;
|
|
return pc && !pc.Is(CustomRoles.Sidekick) && !pc.Is(CustomRoles.Curser) && !pc.Is(CustomRoles.Loyal) && !pc.Is(CustomRoles.Bloodlust) && !pc.IsConverted() && pc.GetCustomRole().IsAbleToBeSidekicked();
|
|
}
|
|
|
|
public void PromoteSidekick()
|
|
{
|
|
try
|
|
{
|
|
if (!SKPromotesToJackal.GetBool()) return;
|
|
|
|
PlayerControl sk = SidekickId.GetPlayer();
|
|
if (!sk || !sk.Is(CustomRoles.Sidekick)) return;
|
|
|
|
GameEndChecker.ShouldNotCheck = true;
|
|
try
|
|
{
|
|
sk.RpcSetCustomRole(CustomRoles.Jackal);
|
|
if (!PromotedSKCanRecruit.GetBool()) sk.SetAbilityUseLimit(0);
|
|
}
|
|
finally { GameEndChecker.ShouldNotCheck = false; }
|
|
}
|
|
catch (Exception e) { Utils.ThrowException(e); }
|
|
}
|
|
|
|
public static void OnAnyoneDead()
|
|
{
|
|
for (var index = Instances.Count - 1; index >= 0; index--)
|
|
{
|
|
Jackal instance = Instances[index];
|
|
var pc = instance.JackalId.GetPlayer();
|
|
if (pc && pc.IsAlive()) return;
|
|
|
|
instance.PromoteSidekick();
|
|
}
|
|
}
|
|
}
|
|
|
|
public class Sidekick : RoleBase
|
|
{
|
|
private static List<byte> PlayerIdList = [];
|
|
|
|
public override bool IsEnable => PlayerIdList.Count > 0;
|
|
|
|
public override void SetupCustomOption() { }
|
|
|
|
public override void Init()
|
|
{
|
|
PlayerIdList = [];
|
|
}
|
|
|
|
public override void Add(byte playerId)
|
|
{
|
|
PlayerIdList.Add(playerId);
|
|
new[] { CustomRoles.Damocles, CustomRoles.Stressed }.Do(x => Main.PlayerStates[playerId].RemoveSubRole(x));
|
|
}
|
|
|
|
public override bool CanUseKillButton(PlayerControl pc)
|
|
{
|
|
return Jackal.SKCanKill.GetBool();
|
|
}
|
|
|
|
public override bool CanUseImpostorVentButton(PlayerControl pc)
|
|
{
|
|
return Jackal.CanVentSK.GetBool();
|
|
}
|
|
|
|
public override void SetKillCooldown(byte id)
|
|
{
|
|
Main.AllPlayerKillCooldown[id] = Jackal.KillCooldownSK.GetFloat();
|
|
}
|
|
|
|
public override void ApplyGameOptions(IGameOptions opt, byte id)
|
|
{
|
|
opt.SetVision(Jackal.HasImpostorVision.GetBool());
|
|
}
|
|
|
|
public override bool CanUseSabotage(PlayerControl pc)
|
|
{
|
|
return base.CanUseSabotage(pc) || Jackal.CanSabotageSK.GetBool() && pc.IsAlive();
|
|
}
|
|
|
|
public override void SetButtonTexts(HudManager __instance, byte id)
|
|
{
|
|
__instance.SabotageButton.ToggleVisible(Jackal.CanSabotageSK.GetBool());
|
|
__instance.KillButton?.OverrideText(GetString("KillButtonText"));
|
|
__instance.ImpostorVentButton?.OverrideText(GetString("ReportButtonText"));
|
|
__instance.SabotageButton?.OverrideText(GetString("SabotageButtonText"));
|
|
}
|
|
} |