mirror of
https://github.com/Gurge44/EndlessHostRoles.git
synced 2026-10-20 01:46:25 +00:00
Add Quarry
This commit is contained in:
1 parent
7208792921
commit
78ec88b68d
9 files changed
+279
No files matched your search
@@ -359,6 +359,7 @@ public enum CustomRoles
|
||||
Pulse,
|
||||
Pursuer,
|
||||
Pyromaniac,
|
||||
Quarry,
|
||||
QuizMaster,
|
||||
Reckless,
|
||||
Revolutionist,
|
||||
|
||||
@@ -561,6 +561,7 @@ public class Main : BasePlugin
|
||||
{ CustomRoles.Thanos, "#F9D401" },
|
||||
{ CustomRoles.Berserker, "#50538F" },
|
||||
{ CustomRoles.SerialKiller, "#233fcc" },
|
||||
{ CustomRoles.Quarry, "#c1fb2b" },
|
||||
{ CustomRoles.Accumulator, "#2bfbae" },
|
||||
{ CustomRoles.Spider, "#C9E44C" },
|
||||
{ CustomRoles.SoulCollector, "#6021A0" },
|
||||
@@ -1067,6 +1068,7 @@ public enum CustomWinner
|
||||
Necromancer = CustomRoles.Necromancer,
|
||||
Wraith = CustomRoles.Wraith,
|
||||
SerialKiller = CustomRoles.SerialKiller,
|
||||
Quarry = CustomRoles.Quarry,
|
||||
Accumulator = CustomRoles.Accumulator,
|
||||
Spider = CustomRoles.Spider,
|
||||
SoulCollector = CustomRoles.SoulCollector,
|
||||
|
||||
@@ -517,6 +517,7 @@ internal static class CustomRolesHelper
|
||||
CustomRoles.Duality => RoleTypes.Impostor,
|
||||
CustomRoles.Berserker => RoleTypes.Impostor,
|
||||
CustomRoles.SerialKiller => RoleTypes.Impostor,
|
||||
CustomRoles.Quarry => RoleTypes.Shapeshifter,
|
||||
CustomRoles.SoulCollector => RoleTypes.Impostor,
|
||||
CustomRoles.Spider => UsePets ? RoleTypes.Impostor : RoleTypes.Shapeshifter,
|
||||
CustomRoles.Explosivist => UsePets ? RoleTypes.Impostor : RoleTypes.Shapeshifter,
|
||||
@@ -655,6 +656,7 @@ internal static class CustomRolesHelper
|
||||
CustomRoles.Parasite or
|
||||
CustomRoles.Berserker or
|
||||
CustomRoles.SerialKiller or
|
||||
CustomRoles.Quarry or
|
||||
CustomRoles.Accumulator or
|
||||
CustomRoles.Spider or
|
||||
CustomRoles.SoulCollector or
|
||||
@@ -1966,6 +1968,7 @@ public enum CountTypes
|
||||
HexMaster,
|
||||
Wraith,
|
||||
SerialKiller,
|
||||
Quarry,
|
||||
Accumulator,
|
||||
Spider,
|
||||
SoulCollector,
|
||||
|
||||
@@ -209,6 +209,7 @@ public static class NameColorManager
|
||||
CustomRoles.Crewpostor when seer.Is(CustomRoleTypes.Impostor) && Options.AlliesKnowCrewpostor.GetBool() => Main.RoleColors[CustomRoles.Madmate],
|
||||
CustomRoles.Hypocrite when seer.Is(CustomRoleTypes.Impostor) && Hypocrite.AlliesKnowHypocrite.GetBool() => Main.RoleColors[CustomRoles.Madmate],
|
||||
CustomRoles.President when ((President)targetRoleClass).IsRevealed => Main.RoleColors[CustomRoles.President],
|
||||
CustomRoles.Quarry when ((Quarry)targetRoleClass).TargetId == seer.PlayerId => "000000",
|
||||
_ => color
|
||||
};
|
||||
|
||||
|
||||
@@ -825,6 +825,7 @@ public static class Utils
|
||||
case CustomRoles.Eclipse:
|
||||
case CustomRoles.Pyromaniac:
|
||||
case CustomRoles.SerialKiller:
|
||||
case CustomRoles.Quarry:
|
||||
case CustomRoles.Spider:
|
||||
case CustomRoles.SoulCollector:
|
||||
case CustomRoles.Berserker:
|
||||
|
||||
@@ -264,6 +264,7 @@ internal static class CheckMurderPatch
|
||||
|
||||
if (ToiletMaster.OnAnyoneCheckMurderStart(killer, target)) return false;
|
||||
if (Dad.OnAnyoneCheckMurderStart(target)) return false;
|
||||
if (Quarry.OnAnyoneCheckMurderStart(killer, target)) return false;
|
||||
|
||||
Simon.RemoveTarget(killer, Simon.Instruction.Kill);
|
||||
|
||||
@@ -1069,6 +1070,12 @@ internal static class ReportDeadBodyPatch
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Quarry.OnAnyoneCheckReportDeadBody(__instance))
|
||||
{
|
||||
Notify("QuarryTarget");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Librarian.OnAnyoneReport(__instance)) return false; // Player dies, no notify needed
|
||||
if (!Trapster.OnAnyoneCheckReportDeadBody(__instance, target)) return false; // Player dies, no notify needed
|
||||
|
||||
|
||||
@@ -9250,6 +9250,15 @@
|
||||
"Telekinetic.Mode.Shield": "Shield",
|
||||
"Telekinetic.Mode.Speed": "Speed",
|
||||
"Telekinetic.Mode.Doors": "Doors",
|
||||
"Quarry": "Quarry",
|
||||
"QuarryInfo": "Hide From Players",
|
||||
"QuarryInfoLong": "(Neutrals):\\nAs the Quarry, you may shapeshift to select your target and swap places with them, they then have to kill you in a specified time or they die. If they find and kill you, they live. You can also kill normally using the kill button.\\nKill everyone to win!",
|
||||
"Quarry.TargetHasArrowToQuarry": "Target has an arrow to the <#c1fb2b>Quarry</color>",
|
||||
"Quarry.CanVentDuringSeekTime": "Can Vent During Seek Time",
|
||||
"Quarry.TargetDiesOnMeetingCall": "Target Dies on Meeting Call",
|
||||
"Quarry.SeekTime": "Seek Time",
|
||||
"Quarry.TargetSeekBeginNotify": "<#ff0000>You were swapped with the {0}! They have a black name!",
|
||||
"Quarry.TimeLeftSuffix": "<#ffff00>You have <#ffffff>{0}s</color> to kill the {1} <#ffa500>or you die!",
|
||||
"Nonplus": "Nonplus",
|
||||
"NonplusInfo": "Blind Others",
|
||||
"NonplusInfoLong": "(Neutrals):\\nAs the Nonplus, you can blind others by venting or petting. Blinded players can't see anything for a set amount of time.\\nKill everyone to win.",
|
||||
|
||||
@@ -96,6 +96,14 @@ public class Accumulator : RoleBase
|
||||
Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
|
||||
}
|
||||
|
||||
public override void AfterMeetingTasks()
|
||||
{
|
||||
if (!Killing) return;
|
||||
PlayerControl pc = AccumulatorId.GetPlayer();
|
||||
if (pc == null || !pc.IsAlive()) return;
|
||||
pc.RpcSetRoleDesync(RoleTypes.Impostor, pc.OwnerId, setRoleMap: true);
|
||||
}
|
||||
|
||||
public void ReceiveRPC(MessageReader reader)
|
||||
{
|
||||
KCD = reader.ReadSingle();
|
||||
|
||||
@@ -0,0 +1,247 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using AmongUs.GameOptions;
|
||||
using EHR.Modules;
|
||||
using EHR.Modules.Extensions;
|
||||
using Hazel;
|
||||
|
||||
namespace EHR.Roles;
|
||||
|
||||
public class Quarry : RoleBase
|
||||
{
|
||||
public static bool On;
|
||||
private static List<Quarry> Instances = [];
|
||||
|
||||
private static OptionItem TargetHasArrowToQuarry;
|
||||
private static OptionItem CanVentDuringSeekTime;
|
||||
private static OptionItem TargetDiesOnMeetingCall;
|
||||
private static OptionItem SeekTime;
|
||||
private static OptionItem ShapeshiftCooldown;
|
||||
private static OptionItem KillCooldown;
|
||||
private static OptionItem CanVent;
|
||||
private static OptionItem ImpostorVision;
|
||||
private static OptionItem AbilityUseLimit;
|
||||
private static OptionItem AbilityUseGainWithEachKill;
|
||||
private static OptionItem CooldownsResetEachOther;
|
||||
|
||||
public override bool IsEnable => On;
|
||||
|
||||
private byte QuarryId;
|
||||
public byte TargetId;
|
||||
private Stopwatch SeekTimer;
|
||||
private long LastUpdate;
|
||||
|
||||
public override void SetupCustomOption()
|
||||
{
|
||||
StartSetup(657800)
|
||||
.AutoSetupOption(ref TargetHasArrowToQuarry, true)
|
||||
.AutoSetupOption(ref CanVentDuringSeekTime, false)
|
||||
.AutoSetupOption(ref TargetDiesOnMeetingCall, false)
|
||||
.AutoSetupOption(ref SeekTime, 15, new IntegerValueRule(0, 120, 1), OptionFormat.Seconds)
|
||||
.AutoSetupOption(ref ShapeshiftCooldown, 15f, new FloatValueRule(0f, 180f, 0.5f), OptionFormat.Seconds)
|
||||
.AutoSetupOption(ref KillCooldown, 22.5f, new FloatValueRule(0f, 180f, 0.5f), OptionFormat.Seconds)
|
||||
.AutoSetupOption(ref CanVent, true)
|
||||
.AutoSetupOption(ref ImpostorVision, true)
|
||||
.AutoSetupOption(ref AbilityUseLimit, 2f, new FloatValueRule(0, 20, 0.05f), OptionFormat.Times)
|
||||
.AutoSetupOption(ref AbilityUseGainWithEachKill, 1f, new FloatValueRule(0f, 5f, 0.1f), OptionFormat.Times)
|
||||
.AutoSetupOption(ref CooldownsResetEachOther, true);
|
||||
}
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
On = false;
|
||||
Instances = [];
|
||||
}
|
||||
|
||||
public override void Add(byte playerId)
|
||||
{
|
||||
On = true;
|
||||
QuarryId = playerId;
|
||||
TargetId = byte.MaxValue;
|
||||
SeekTimer = new();
|
||||
LastUpdate = 0;
|
||||
Instances.Add(this);
|
||||
playerId.SetAbilityUseLimit(AbilityUseLimit.GetFloat());
|
||||
}
|
||||
|
||||
public override void Remove(byte playerId)
|
||||
{
|
||||
Instances.Remove(this);
|
||||
}
|
||||
|
||||
public override void SetKillCooldown(byte id)
|
||||
{
|
||||
Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat();
|
||||
}
|
||||
|
||||
public override void ApplyGameOptions(IGameOptions opt, byte id)
|
||||
{
|
||||
opt.SetVision(ImpostorVision.GetBool());
|
||||
AURoleOptions.ShapeshifterCooldown = ShapeshiftCooldown.GetFloat();
|
||||
AURoleOptions.ShapeshifterDuration = 1f;
|
||||
}
|
||||
|
||||
public override bool CanUseImpostorVentButton(PlayerControl pc)
|
||||
{
|
||||
return CanVent.GetBool() && (TargetId == byte.MaxValue || CanVentDuringSeekTime.GetBool());
|
||||
}
|
||||
|
||||
public override bool OnCheckMurder(PlayerControl killer, PlayerControl target)
|
||||
{
|
||||
return target.PlayerId != TargetId;
|
||||
}
|
||||
|
||||
public override void OnMurder(PlayerControl killer, PlayerControl target)
|
||||
{
|
||||
if (CooldownsResetEachOther.GetBool())
|
||||
killer.RpcResetAbilityCooldown();
|
||||
}
|
||||
|
||||
public override bool OnShapeshift(PlayerControl shapeshifter, PlayerControl target, bool shapeshifting)
|
||||
{
|
||||
if (!shapeshifting) return true;
|
||||
|
||||
if (shapeshifter.GetAbilityUseLimit() < 1) return false;
|
||||
shapeshifter.RpcRemoveAbilityUse();
|
||||
|
||||
Vector2 pos = shapeshifter.Pos();
|
||||
shapeshifter.TP(target);
|
||||
target.TP(pos);
|
||||
|
||||
TargetId = target.PlayerId;
|
||||
SeekTimer = Stopwatch.StartNew();
|
||||
Utils.SendRPC(CustomRPC.SyncRoleData, QuarryId, 1, TargetId);
|
||||
Main.Instance.StartCoroutine(ContinuouslyResetAbilityCooldown());
|
||||
if (TargetHasArrowToQuarry.GetBool()) TargetArrow.Add(target.PlayerId, shapeshifter.PlayerId);
|
||||
|
||||
var sender = CustomRpcSender.Create("QuarryTarget", SendOption.Reliable);
|
||||
var hasValue = false;
|
||||
hasValue |= sender.Notify(target, string.Format(Translator.GetString("Quarry.TargetSeekBeginNotify"), CustomRoles.Quarry.ToColoredString()));
|
||||
hasValue |= sender.RpcSetRole(target, RoleTypes.Impostor, target.OwnerId);
|
||||
hasValue |= sender.RpcSetRole(shapeshifter, RoleTypes.Crewmate, target.OwnerId);
|
||||
hasValue |= sender.NotifyRolesSpecific(target, shapeshifter, out sender, out bool cleared);
|
||||
if (cleared) hasValue = false;
|
||||
sender.SendMessage(dispose: !hasValue);
|
||||
|
||||
if (CooldownsResetEachOther.GetBool())
|
||||
shapeshifter.SetKillCooldown();
|
||||
|
||||
return false;
|
||||
|
||||
System.Collections.IEnumerator ContinuouslyResetAbilityCooldown()
|
||||
{
|
||||
while (TargetId != byte.MaxValue)
|
||||
{
|
||||
int interval = ShapeshiftCooldown.GetInt() - 2;
|
||||
Stopwatch stopwatch = Stopwatch.StartNew();
|
||||
while (stopwatch.Elapsed.Seconds < interval) yield return null;
|
||||
if (TargetId == byte.MaxValue) yield break;
|
||||
shapeshifter.RpcResetAbilityCooldown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnFixedUpdate(PlayerControl pc)
|
||||
{
|
||||
if (!Main.IntroDestroyed || !GameStates.IsInTask || ExileController.Instance || AntiBlackout.SkipTasks || !pc.IsAlive() || TargetId == byte.MaxValue) return;
|
||||
|
||||
long now = Utils.TimeStamp;
|
||||
if (now == LastUpdate) return;
|
||||
LastUpdate = now;
|
||||
|
||||
PlayerControl target = TargetId.GetPlayer();
|
||||
|
||||
if (target == null || !target.IsAlive())
|
||||
{
|
||||
TargetId = byte.MaxValue;
|
||||
SeekTimer.Reset();
|
||||
Utils.SendRPC(CustomRPC.SyncRoleData, QuarryId, 2);
|
||||
return;
|
||||
}
|
||||
|
||||
if (SeekTimer.GetRemainingTime(SeekTime.GetInt()) <= 0)
|
||||
{
|
||||
target.Suicide();
|
||||
TargetId = byte.MaxValue;
|
||||
SeekTimer.Reset();
|
||||
Utils.SendRPC(CustomRPC.SyncRoleData, QuarryId, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
|
||||
Utils.NotifyRoles(SpecifySeer: target, SpecifyTarget: target);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool OnAnyoneCheckMurderStart(PlayerControl killer, PlayerControl target)
|
||||
{
|
||||
foreach (Quarry instance in Instances)
|
||||
{
|
||||
if (instance.TargetId == killer.PlayerId && instance.QuarryId == target.PlayerId)
|
||||
{
|
||||
killer.Kill(target);
|
||||
killer.RpcSetRoleDesync(killer.GetRoleTypes(), killer.OwnerId);
|
||||
instance.TargetId = byte.MaxValue;
|
||||
instance.SeekTimer.Reset();
|
||||
Utils.SendRPC(CustomRPC.SyncRoleData, instance.QuarryId, 2);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool OnAnyoneCheckReportDeadBody(PlayerControl reporter)
|
||||
{
|
||||
return !Instances.Exists(x => x.TargetId == reporter.PlayerId);
|
||||
}
|
||||
|
||||
public override bool CanUseVent(PlayerControl pc, int ventId)
|
||||
{
|
||||
return pc.PlayerId != TargetId;
|
||||
}
|
||||
|
||||
public override void OnReportDeadBody()
|
||||
{
|
||||
if (TargetId == byte.MaxValue) return;
|
||||
|
||||
TargetId = byte.MaxValue;
|
||||
SeekTimer.Reset();
|
||||
Utils.SendRPC(CustomRPC.SyncRoleData, QuarryId, 2);
|
||||
|
||||
PlayerControl target = TargetId.GetPlayer();
|
||||
if (target == null || !target.IsAlive()) return;
|
||||
|
||||
if (TargetDiesOnMeetingCall.GetBool())
|
||||
target.Suicide();
|
||||
else
|
||||
{
|
||||
PlayerControl pc = QuarryId.GetPlayer();
|
||||
if (pc == null || !pc.IsAlive()) return;
|
||||
|
||||
pc.RpcIncreaseAbilityUseLimitBy(1);
|
||||
}
|
||||
}
|
||||
|
||||
public void ReceiveRPC(MessageReader reader)
|
||||
{
|
||||
switch (reader.ReadPackedInt32())
|
||||
{
|
||||
case 1:
|
||||
TargetId = reader.ReadByte();
|
||||
SeekTimer = Stopwatch.StartNew();
|
||||
break;
|
||||
case 2:
|
||||
TargetId = byte.MaxValue;
|
||||
SeekTimer.Reset();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetSuffix(PlayerControl seer, PlayerControl target, bool hud = false, bool meeting = false)
|
||||
{
|
||||
if ((seer.PlayerId != QuarryId && seer.PlayerId != TargetId) || seer.PlayerId != target.PlayerId || meeting || hud || TargetId == byte.MaxValue) return string.Empty;
|
||||
string timer = string.Format(Translator.GetString("Quarry.TimeLeftSuffix"), SeekTimer.GetRemainingTime(SeekTime.GetInt()) - 1, CustomRoles.Quarry.ToColoredString());
|
||||
return seer.PlayerId == TargetId ? $"{TargetArrow.GetAllArrows(TargetId)}\n{timer}" : timer;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user