Add Moon Dancer

This commit is contained in:
Gurge44 committed 2025-12-13 13:04:07 +01:00
1 parent d3146283ad
commit 18ef8d83df
7 files changed
+156 -7

No files matched your search

+1
View File
@@ -416,6 +416,7 @@ public enum CustomRoles
Enchanter,
Goddess,
Illusionist,
MoonDancer,
Poache,
PotionMaster,
Reaper,
+4 -2
View File
@@ -605,6 +605,7 @@ internal static class CustomRolesHelper
CustomRoles.Enchanter => RoleTypes.Impostor,
CustomRoles.Siren => RoleTypes.Phantom,
CustomRoles.Wyrd => RoleTypes.Shapeshifter,
CustomRoles.MoonDancer => RoleTypes.Phantom,
_ => RoleTypes.GuardianAngel
};
@@ -1116,7 +1117,7 @@ internal static class CustomRolesHelper
public static bool CheckAddonConflict(CustomRoles role, PlayerControl pc)
{
return role.IsAdditionRole() && (!Main.NeverSpawnTogetherCombos.TryGetValue(OptionItem.CurrentPreset, out Dictionary<CustomRoles, List<CustomRoles>> neverList) || !neverList.TryGetValue(pc.GetCustomRole(), out List<CustomRoles> bannedAddonList) || !bannedAddonList.Contains(role)) && pc.GetCustomRole() is not CustomRoles.GuardianAngelEHR and not CustomRoles.God && !pc.Is(CustomRoles.Madmate) && !pc.Is(CustomRoles.GM) && role is not CustomRoles.Lovers && !pc.Is(CustomRoles.LazyGuy) && (!pc.HasSubRole() || pc.GetCustomSubRoles().Count < Options.NoLimitAddonsNumMax.GetInt()) && (!Options.AddonCanBeSettings.TryGetValue(role, out (OptionItem Imp, OptionItem Neutral, OptionItem Crew, OptionItem Coven) o) || ((o.Imp.GetBool() || !pc.GetCustomRole().IsImpostor()) && (o.Neutral.GetBool() || !pc.GetCustomRole().IsNeutral()) && (o.Crew.GetBool() || !pc.IsCrewmate()) && (o.Coven.GetBool() || !pc.Is(Team.Coven)))) && (!role.IsImpOnlyAddon() || (pc.IsImpostor() && !pc.Is(CustomRoles.DoubleAgent)) || (pc.Is(CustomRoles.Traitor) && Traitor.CanGetImpostorOnlyAddons.GetBool())) && role switch
return role.IsAdditionRole() && !(role.IsGhostRole() && pc.IsAlive()) && (!Main.NeverSpawnTogetherCombos.TryGetValue(OptionItem.CurrentPreset, out Dictionary<CustomRoles, List<CustomRoles>> neverList) || !neverList.TryGetValue(pc.GetCustomRole(), out List<CustomRoles> bannedAddonList) || !bannedAddonList.Contains(role)) && pc.GetCustomRole() is not CustomRoles.GuardianAngelEHR and not CustomRoles.God && !pc.Is(CustomRoles.Madmate) && !pc.Is(CustomRoles.GM) && role is not CustomRoles.Lovers && !pc.Is(CustomRoles.LazyGuy) && (!pc.HasSubRole() || pc.GetCustomSubRoles().Count < Options.NoLimitAddonsNumMax.GetInt()) && (!Options.AddonCanBeSettings.TryGetValue(role, out (OptionItem Imp, OptionItem Neutral, OptionItem Crew, OptionItem Coven) o) || ((o.Imp.GetBool() || !pc.GetCustomRole().IsImpostor()) && (o.Neutral.GetBool() || !pc.GetCustomRole().IsNeutral()) && (o.Crew.GetBool() || !pc.IsCrewmate()) && (o.Coven.GetBool() || !pc.Is(Team.Coven)))) && (!role.IsImpOnlyAddon() || (pc.IsImpostor() && !pc.Is(CustomRoles.DoubleAgent)) || (pc.Is(CustomRoles.Traitor) && Traitor.CanGetImpostorOnlyAddons.GetBool())) && role switch
{
CustomRoles.Blind when pc.Is(CustomRoles.Sensor) => false,
CustomRoles.Composter when float.IsNaN(pc.GetAbilityUseLimit()) => false,
@@ -1285,7 +1286,8 @@ internal static class CustomRolesHelper
CustomRoles.Timelord or
CustomRoles.Enchanter or
CustomRoles.Siren or
CustomRoles.Wyrd;
CustomRoles.Wyrd or
CustomRoles.MoonDancer;
}
public static bool IncompatibleWithVenom(this CustomRoles role)
+1
View File
@@ -74,6 +74,7 @@ public class PlayerState(byte playerId)
Deafened,
Patrolled,
Misguess,
LossOfBlood,
// Natural Disasters
Meteor,
+11 -1
View File
@@ -1804,7 +1804,7 @@
"TargetKnowsLawyer": "Target knows their <color=#008080>Lawyer</color>",
"YourLawyerIsNotify": "Your <color=#008080>Lawyer</color> is {0}. They win if you win.",
"ShowLongInfo": "Show Long Role Descriptions instead of Short ones",
"InfectiousBiteCooldownIncrese": "Infect Cooldown Increase Per Use",
"InfectiousBiteCooldownIncrese": "Infect Cooldown Increase Per Kill",
"InfectiousBiteMax": "Maximum Infections",
"InfectiousKnowTargetRole": "Know <color=#7B8968>infected</color> player's role",
"InfectiousTargetKnowOtherTarget": "<color=#7B8968>Infected</color> players know each other",
@@ -1979,6 +1979,7 @@
"DeathReason.Deafened": "Deafened",
"DeathReason.Patrolled": "Patrolled",
"DeathReason.Misguess": "Misguess",
"DeathReason.LossOfBlood": "Loss Of Blood",
"ND_DRLaughMessage.Meteor": "Meteor.... I hardly knew her!",
"ND_DRLaughMessage.Lava": "Lava is not the best place to swim, huh?",
"ND_DRLaughMessage.Tornado": "Out for a spin? I hope this tornado didn't make you dizzy!",
@@ -9462,6 +9463,7 @@
"Bloodmoon.Suffix": "<{1}>You will die in <{2}>{0}s</color></color>",
"Bloodmoon.Speed": "<#ff1919>Bloodmoon</color> Speed",
"Bloodmoon.DieOnMeetingCall": "Targets Die on Meeting Call",
"Bloodmoon.CDCIncreasePerUse": "Cooldown Increase Per Use",
"BloodmoonNearYou": "<#ffff00>The {0} is near you! Stay away to avoid death!</color>",
"Prefix.Bloodmoon": "Bloodmoon",
"GA": "Guardian Angel",
@@ -10084,6 +10086,14 @@
"Wyrd.Suffix.SuicideWarningOnAction.Report": "Reporting a dead body",
"Wyrd.Suffix.SuicideWarningOnAction.Button": "Calling an emergency meeting",
"Wyrd.Suffix.SuicideWarnings": "<#ffff00><size=80%>⚠ The following actions will cause you to suicide: ⚠\\n{0}</size></color>",
"MoonDancer": "Moon Dancer",
"MoonDancerInfo": "Give and Steal Add-ons",
"MoonDancerInfoLong": "(Coven):\\nAs the Moon Dancer, you can assign yourself a random add-on. You can also use your kill button on someone,\\n- once to give them an add-on, that is: helpful if they're a coven member, otherwise harmful (assigned after the next meeting)\\n- twice to steal all add-ons from them<sup>*</sup>\\n\\nWith the Necronomicon, double clicks kill the target, while also stealing all add-ons from them<sup>*</sup>.\\n\\n<sup>*</sup>If settings allow",
"MoonDancer.SelfAssignAddonCooldown": "Self-Assign Add-on Cooldown",
"MoonDancer.OthersAssignAddonCooldown": "Cooldown for Assigning Add-ons to Others",
"MoonDancer.StealAddonCooldown": "Add-on Stealing Cooldown",
"MoonDancer.CanStealAddonsWithoutNecronomicon": "Can Steal Add-ons Without Necronomicon",
"MoonDancer.StealAllAddonsOnKill": "Steal All Add-ons On Kill",
"DCNotify.Hacking": "You were <color=#ff1919>banned</color> for hacking.\\n\\nPlease stop.",
"DCNotify.Banned": "You were <color=#ff1919>banned</color> from this lobby.\\n\\nContact the host if this was a mistake.",
"DCNotify.Kicked": "You were <color=#ffff00>kicked</color> from this lobby.\\n\\nYou may still rejoin.",
+13 -3
View File
@@ -1,4 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using Hazel;
namespace EHR.AddOns.GhostRoles;
@@ -8,18 +10,22 @@ internal class Bloodmoon : IGhostRole
private static OptionItem Duration;
private static OptionItem Speed;
private static OptionItem DieOnMeetingCall;
private static OptionItem CDIncreasePerUse;
private static readonly Dictionary<byte, long> ScheduledDeaths = [];
private long LastUpdate;
private byte BloodmoonID;
public Team Team => Team.Impostor | Team.Neutral;
public int Cooldown => Duration.GetInt() + CD.GetInt();
public int Cooldown => CD.GetInt() + Main.PlayerStates.Values.Count(x => x.GetRealKiller() == BloodmoonID && x.deathReason == PlayerState.DeathReason.LossOfBlood) * CDIncreasePerUse.GetInt();
public void OnAssign(PlayerControl pc)
{
Main.AllPlayerSpeed[pc.PlayerId] = Speed.GetFloat();
pc.MarkDirtySettings();
LastUpdate = Utils.TimeStamp;
BloodmoonID = pc.PlayerId;
}
public void OnProtect(PlayerControl pc, PlayerControl target)
@@ -46,6 +52,10 @@ internal class Bloodmoon : IGhostRole
DieOnMeetingCall = new BooleanOptionItem(649405, "Bloodmoon.DieOnMeetingCall", true, TabGroup.OtherRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Bloodmoon]);
CDIncreasePerUse = new IntegerOptionItem(649406, "Bloodmoon.CDCIncreasePerUse", new(0, 60, 1), 15, TabGroup.OtherRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Bloodmoon])
.SetValueFormat(OptionFormat.Seconds);
}
public static void Update(PlayerControl pc, Bloodmoon instance)
@@ -67,10 +77,10 @@ internal class Bloodmoon : IGhostRole
continue;
}
if (pc.RpcCheckAndMurder(player, true)) player.Suicide(realKiller: pc);
if (pc.RpcCheckAndMurder(player, true)) player.Suicide(PlayerState.DeathReason.LossOfBlood, pc);
}
Utils.GetPlayersInRadius(5f, pc.Pos()).DoIf(x => !x.Is(Team.Impostor), x => x.Notify(string.Format(Translator.GetString("BloodmoonNearYou"), CustomRoles.Bloodmoon.ToColoredString())));
Utils.GetPlayersInRadius(7f, pc.Pos()).DoIf(x => !x.Is(Team.Impostor), x => x.Notify(string.Format(Translator.GetString("BloodmoonNearYou"), CustomRoles.Bloodmoon.ToColoredString()), sendOption: SendOption.None));
}
public static void OnMeetingStart()
+125
View File
@@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
using System.Linq;
using AmongUs.GameOptions;
namespace EHR.Coven;
public class MoonDancer : Coven
{
public static bool On;
public override bool IsEnable => On;
private static OptionItem SelfAssignAddonCooldown;
private static OptionItem OthersAssignAddonCooldown;
private static OptionItem StealAddonCooldown;
private static OptionItem KillCooldown;
private static OptionItem CanStealAddonsWithoutNecronomicon;
private static OptionItem StealAllAddonsOnKill;
private static OptionItem CanVentBeforeNecronomicon;
private static OptionItem CanVentAfterNecronomicon;
protected override NecronomiconReceivePriorities NecronomiconReceivePriority => NecronomiconReceivePriorities.Random;
private Dictionary<byte, List<CustomRoles>> ToAssign = [];
public override void SetupCustomOption()
{
StartSetup(657300)
.AutoSetupOption(ref SelfAssignAddonCooldown, 15f, new FloatValueRule(0f, 120f, 0.5f), OptionFormat.Seconds)
.AutoSetupOption(ref OthersAssignAddonCooldown, 15f, new FloatValueRule(0f, 120f, 0.5f), OptionFormat.Seconds)
.AutoSetupOption(ref StealAddonCooldown, 15f, new FloatValueRule(0f, 120f, 0.5f), OptionFormat.Seconds)
.AutoSetupOption(ref KillCooldown, 30f, new FloatValueRule(0f, 120f, 0.5f), OptionFormat.Seconds)
.AutoSetupOption(ref CanStealAddonsWithoutNecronomicon, true)
.AutoSetupOption(ref StealAllAddonsOnKill, true)
.AutoSetupOption(ref CanVentBeforeNecronomicon, false)
.AutoSetupOption(ref CanVentAfterNecronomicon, true);
}
public override void Init()
{
On = false;
}
public override void Add(byte playerId)
{
On = true;
ToAssign = [];
}
public override bool CanUseImpostorVentButton(PlayerControl pc)
{
return HasNecronomicon ? CanVentAfterNecronomicon.GetBool() : CanVentBeforeNecronomicon.GetBool();
}
public override void ApplyGameOptions(IGameOptions opt, byte playerId)
{
AURoleOptions.PhantomCooldown = SelfAssignAddonCooldown.GetFloat();
AURoleOptions.PhantomDuration = 0.1f;
}
public override void SetKillCooldown(byte id)
{
Main.AllPlayerKillCooldown[id] = HasNecronomicon ? KillCooldown.GetFloat() : OthersAssignAddonCooldown.GetFloat();
}
public override bool OnCheckMurder(PlayerControl killer, PlayerControl target)
{
if (!HasNecronomicon && !CanStealAddonsWithoutNecronomicon.GetBool())
{
GiveAddon();
return false;
}
if (killer.CheckDoubleTrigger(target, GiveAddon))
{
if (HasNecronomicon && !StealAllAddonsOnKill.GetBool()) return true;
PlayerState state = Main.PlayerStates[target.PlayerId];
state.SubRoles.FindAll(x => !killer.Is(x) && !x.IsNotAssignableMidGame() && CustomRolesHelper.CheckAddonConflict(x, killer)).ForEach(x =>
{
killer.RpcSetCustomRole(x);
state.RemoveSubRole(x);
});
if (!HasNecronomicon) killer.SetKillCooldown(StealAddonCooldown.GetFloat());
return HasNecronomicon;
}
return false;
void GiveAddon()
{
CustomRoles addon = Options.GroupedAddons[target.Is(Team.Coven) ? AddonTypes.Helpful : AddonTypes.Harmful].Where(x => !target.Is(x) && !x.IsNotAssignableMidGame() && CustomRolesHelper.CheckAddonConflict(x, target)).RandomElement();
if (addon == default(CustomRoles))
return;
if (ToAssign.TryGetValue(target.PlayerId, out var list))
list.Add(addon);
else
ToAssign[target.PlayerId] = [addon];
killer.SetKillCooldown(OthersAssignAddonCooldown.GetFloat());
}
}
public override bool OnVanish(PlayerControl pc)
{
CustomRoles addon = Enum.GetValues<CustomRoles>().Where(x => x.IsAdditionRole() && !x.IsGhostRole() && !pc.Is(x) && !x.IsNotAssignableMidGame() && CustomRolesHelper.CheckAddonConflict(x, pc)).RandomElement();
if (addon == default(CustomRoles)) return false;
pc.RpcSetCustomRole(addon);
return false;
}
public override void AfterMeetingTasks()
{
foreach ((byte id, List<CustomRoles> addons) in ToAssign)
{
var pc = id.GetPlayer();
if (pc == null || !pc.IsAlive()) continue;
addons.ForEach(x => pc.RpcSetCustomRole(x));
}
ToAssign = [];
}
}
+1 -1
View File
@@ -93,7 +93,7 @@ public class Curser : RoleBase
target.RpcRemoveAbilityUse();
break;
case 1:
CustomRoles addon = Options.GroupedAddons[AddonTypes.Harmful].Where(x => x.IsAdditionRole() && !target.Is(x) && !x.IsNotAssignableMidGame() && CustomRolesHelper.CheckAddonConflict(x, target)).RandomElement();
CustomRoles addon = Options.GroupedAddons[AddonTypes.Harmful].Where(x => !target.Is(x) && !x.IsNotAssignableMidGame() && CustomRolesHelper.CheckAddonConflict(x, target)).RandomElement();
if (addon == default(CustomRoles)) goto Pick;
target.RpcSetCustomRole(addon);
break;