New role Adventurer & Bug Fixes

This commit is contained in:
Gurge44 committed 2024-04-02 19:58:34 +02:00
1 parent 3f9277e88b
commit 3d120a5924
32 files changed
+575 -126

No files matched your search

+1
View File
@@ -114,6 +114,7 @@ public enum CustomRoles
// Crewmate
Addict,
Adventurer,
Aid,
Alchemist,
Altruist,
+1
View File
@@ -114,6 +114,7 @@ public enum CustomRoles
// Crewmate
Addict,
Adventurer,
Aid,
Alchemist,
Altruist,
+2
View File
@@ -15,8 +15,10 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=NE/@EntryIndexedValue">NE</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=NK/@EntryIndexedValue">NK</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=NNK/@EntryIndexedValue">NNK</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=RNG/@EntryIndexedValue">RNG</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=RPC/@EntryIndexedValue">RPC</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SK/@EntryIndexedValue">SK</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=TMP/@EntryIndexedValue">TMP</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=EHR/@EntryIndexedValue">EHR</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UI/@EntryIndexedValue">UI</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=VN/@EntryIndexedValue">VN</s:String></wpf:ResourceDictionary>
+5 -2
View File
@@ -3,6 +3,7 @@ using EHR.Roles.Crewmate;
using EHR.Roles.Impostor;
using EHR.Roles.Neutral;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using UnityEngine;
@@ -148,6 +149,7 @@ internal static class CustomRolesHelper
CustomRoles.Express => CustomRoles.Crewmate,
CustomRoles.NiceEraser => CustomRoles.Crewmate,
CustomRoles.TaskManager => CustomRoles.Crewmate,
CustomRoles.Adventurer => CustomRoles.Engineer,
CustomRoles.Randomizer => CustomRoles.Crewmate,
CustomRoles.Beacon => CustomRoles.Crewmate,
CustomRoles.Rabbit => CustomRoles.Crewmate,
@@ -671,14 +673,15 @@ internal static class CustomRolesHelper
_ => false,
};
public static readonly CustomRoles[] OnlySpawnsWithPetsRoleList =
public static readonly List<CustomRoles> OnlySpawnsWithPetsRoleList =
[
CustomRoles.Tunneler,
CustomRoles.Tornado,
CustomRoles.Swiftclaw,
CustomRoles.Adventurer
];
public static bool OnlySpawnsWithPets(this CustomRoles role) => OnlySpawnsWithPetsRoleList.Any(x => x.ToString() == role.ToString());
public static bool OnlySpawnsWithPets(this CustomRoles role) => OnlySpawnsWithPetsRoleList.Contains(role);
public static bool NeedUpdateOnLights(this CustomRoles role) => (!role.UsesPetInsteadOfKill()) && (role.GetDYRole() != RoleTypes.GuardianAngel || role is
CustomRoles.Convict or
+13 -7
View File
@@ -323,15 +323,21 @@ internal class EAC
if (amount is not 64 and not 65) goto YesCheat;
break;
case SystemTypes.Comms:
if (amount == 0)
switch (amount)
{
if (Mapid is 1 or 5) goto YesCheat;
case 0:
{
if (Mapid is 1 or 5) goto YesCheat;
break;
}
case 64 or 65 or 32 or 33 or 16 or 17:
{
if (Mapid is not (1 or 5)) goto YesCheat;
break;
}
default:
goto YesCheat;
}
else if (amount is 64 or 65 or 32 or 33 or 16 or 17)
{
if (!(Mapid is 1 or 5)) goto YesCheat;
}
else goto YesCheat;
break;
case SystemTypes.Electrical:
@@ -16,41 +16,59 @@ public class PlayerGameOptionsSender(PlayerControl player) : GameOptionsSender
{
public static void SetDirty(byte playerId)
{
foreach (var sender in AllSenders.OfType<PlayerGameOptionsSender>().Where(sender => sender.player.PlayerId == playerId))
foreach (GameOptionsSender allSender in AllSenders)
{
sender.SetDirty();
if (allSender is PlayerGameOptionsSender sender && sender.player.PlayerId == playerId)
{
sender.SetDirty();
}
}
}
public static void SetDirtyToAll()
{
foreach (var sender in AllSenders.OfType<PlayerGameOptionsSender>())
foreach (GameOptionsSender allSender in AllSenders)
{
sender.SetDirty();
if (allSender is PlayerGameOptionsSender sender)
{
sender.SetDirty();
}
}
}
// For lights call/fix
public static void SetDirtyToAllV2()
{
foreach (var sender in AllSenders.OfType<PlayerGameOptionsSender>().Where(sender => !sender.IsDirty && sender.player.IsAlive() && (sender.player.GetCustomRole().NeedUpdateOnLights() || sender.player.Is(CustomRoles.Torch) || sender.player.Is(CustomRoles.Mare))))
foreach (GameOptionsSender allSender in AllSenders)
{
sender.SetDirty();
if (allSender is PlayerGameOptionsSender { IsDirty: false } sender && sender.player.IsAlive() && (sender.player.GetCustomRole().NeedUpdateOnLights() || sender.player.Is(CustomRoles.Torch) || sender.player.Is(CustomRoles.Mare)))
{
sender.SetDirty();
}
}
}
// For Grenadier blidning/restoring
public static void SetDirtyToAllV3()
{
foreach (var sender in AllSenders.OfType<PlayerGameOptionsSender>().Where(sender => !sender.IsDirty && sender.player.IsAlive() && ((Grenadier.GrenadierBlinding.Count > 0 && (sender.player.GetCustomRole().IsImpostor() || (sender.player.GetCustomRole().IsNeutral() && Options.GrenadierCanAffectNeutral.GetBool()))) || (Grenadier.MadGrenadierBlinding.Count > 0 && !sender.player.GetCustomRole().IsImpostorTeam() && !sender.player.Is(CustomRoles.Madmate)))))
foreach (GameOptionsSender allSender in AllSenders)
{
sender.SetDirty();
if (allSender is PlayerGameOptionsSender { IsDirty: false } sender && sender.player.IsAlive() && ((Grenadier.GrenadierBlinding.Count > 0 && (sender.player.GetCustomRole().IsImpostor() || (sender.player.GetCustomRole().IsNeutral() && Options.GrenadierCanAffectNeutral.GetBool()))) || (Grenadier.MadGrenadierBlinding.Count > 0 && !sender.player.GetCustomRole().IsImpostorTeam() && !sender.player.Is(CustomRoles.Madmate))))
{
sender.SetDirty();
}
}
}
// For players with kill buttons
public static void SetDirtyToAllV4()
{
foreach (var sender in AllSenders.OfType<PlayerGameOptionsSender>().Where(sender => !sender.IsDirty && sender.player.IsAlive() && sender.player.CanUseKillButton()).ToArray())
foreach (GameOptionsSender allSender in AllSenders)
{
sender.SetDirty();
if (allSender is PlayerGameOptionsSender { IsDirty: false } sender && sender.player.IsAlive() && sender.player.CanUseKillButton())
{
sender.SetDirty();
}
}
}
@@ -324,6 +342,13 @@ public class PlayerGameOptionsSender(PlayerControl player) : GameOptionsSender
opt.SetFloat(FloatOptionNames.ImpostorLightMod, 0);
}
if (player.IsCrewmate() && Main.PlayerStates.Values.Any(s => s.Role is Adventurer { IsEnable: true } av && av.ActiveWeapons.Contains(Adventurer.Weapon.Lantern)))
{
opt.SetVision(true);
opt.SetFloat(FloatOptionNames.CrewLightMod, 1.5f);
opt.SetFloat(FloatOptionNames.ImpostorLightMod, 1.5f);
}
if (Changeling.ChangedRole.TryGetValue(player.PlayerId, out var changed) && changed && player.GetRoleTypes() != RoleTypes.Shapeshifter)
{
AURoleOptions.ShapeshifterCooldown = 300f;
+13 -20
View File
@@ -106,24 +106,18 @@ public static class GuessManager
return true;
}
if (!pc.Is(CustomRoles.NiceGuesser))
if (!pc.Is(CustomRoles.NiceGuesser) && pc.IsCrewmate() && !Options.CrewmatesCanGuess.GetBool() && !pc.Is(CustomRoles.Guesser) && !pc.Is(CustomRoles.Judge) && !pc.Is(CustomRoles.NiceSwapper))
{
if (pc.IsCrewmate() && !Options.CrewmatesCanGuess.GetBool() && !pc.Is(CustomRoles.Guesser) && !pc.Is(CustomRoles.Judge) && !pc.Is(CustomRoles.NiceSwapper))
{
if (!isUI) Utils.SendMessage(GetString("GuessNotAllowed"), pc.PlayerId);
else pc.ShowPopUp(GetString("GuessNotAllowed"));
return true;
}
if (!isUI) Utils.SendMessage(GetString("GuessNotAllowed"), pc.PlayerId);
else pc.ShowPopUp(GetString("GuessNotAllowed"));
return true;
}
if (!pc.Is(CustomRoles.EvilGuesser))
if (!pc.Is(CustomRoles.EvilGuesser) && pc.GetCustomRole().IsImpostor() && !Options.ImpostorsCanGuess.GetBool() && !pc.Is(CustomRoles.Guesser) && !pc.Is(CustomRoles.Councillor))
{
if (pc.GetCustomRole().IsImpostor() && !Options.ImpostorsCanGuess.GetBool() && !pc.Is(CustomRoles.Guesser) && !pc.Is(CustomRoles.Councillor))
{
if (!isUI) Utils.SendMessage(GetString("GuessNotAllowed"), pc.PlayerId);
else pc.ShowPopUp(GetString("GuessNotAllowed"));
return true;
}
if (!isUI) Utils.SendMessage(GetString("GuessNotAllowed"), pc.PlayerId);
else pc.ShowPopUp(GetString("GuessNotAllowed"));
return true;
}
if (pc.IsNeutralKiller() && !Options.NeutralKillersCanGuess.GetBool() && !pc.Is(CustomRoles.Guesser))
@@ -147,12 +141,11 @@ public static class GuessManager
return true;
case 2:
{
if (
(pc.Is(CustomRoles.NiceGuesser) && Options.GGTryHideMsg.GetBool()) ||
if ((pc.Is(CustomRoles.NiceGuesser) && Options.GGTryHideMsg.GetBool()) ||
(pc.Is(CustomRoles.EvilGuesser) && Options.EGTryHideMsg.GetBool()) ||
(pc.Is(CustomRoles.Doomsayer) && Doomsayer.DoomsayerTryHideMsg.GetBool()) ||
(pc.Is(CustomRoles.Guesser) && Options.GTryHideMsg.GetBool()) || (Options.GuesserMode.GetBool() && Options.HideGuesserCommands.GetBool())
) /*TryHideMsg();*/ ChatManager.SendPreviousMessagesToAll();
(pc.Is(CustomRoles.Guesser) && Options.GTryHideMsg.GetBool()) || (Options.GuesserMode.GetBool() && Options.HideGuesserCommands.GetBool()))
ChatManager.SendPreviousMessagesToAll();
else if (pc.AmOwner && !isUI) Utils.SendMessage(originMsg, 255, pc.GetRealName());
if (!MsgToPlayerAndRole(msg, out byte targetId, out CustomRoles role, out string error))
@@ -960,7 +953,7 @@ public static class GuessManager
CustomRoleTypes.Impostor => new(255, 25, 25, byte.MaxValue),
CustomRoleTypes.Neutral => new(255, 171, 27, byte.MaxValue),
CustomRoleTypes.Addon => new Color32(255, 154, 206, byte.MaxValue),
_ => throw new NotImplementedException(),
_ => throw new NotImplementedException()
};
Logger.Info(Teamlabel.color.ToString(), ((CustomRoleTypes)index).ToString());
Teamlabel.text = GetString("Type" + ((CustomRoleTypes)index));
@@ -1026,7 +1019,7 @@ public static class GuessManager
Pagelabel.transform.localScale *= 1.6f;
Pagelabel.autoSizeTextContainer = true;
if (!IsNext && Page <= 1) Pagebutton.GetComponent<SpriteRenderer>().color = new(1, 1, 1, 0.1f);
Pagebutton.GetComponent<PassiveButton>().OnClick.AddListener((Action)(() => ClickEvent()));
Pagebutton.GetComponent<PassiveButton>().OnClick.AddListener((Action)(ClickEvent));
PageButtons.Add(Pagebutton.GetComponent<SpriteRenderer>());
return;
+1 -6
View File
@@ -83,12 +83,7 @@ static class LocateArrow
/// <returns></returns>
public static string GetArrows(PlayerControl seer)
{
var arrows = string.Empty;
foreach (var arrowInfo in LocateArrows.Keys.Where(ai => ai.From == seer.PlayerId))
{
arrows += LocateArrows[arrowInfo];
}
return arrows;
return LocateArrows.Keys.Where(ai => ai.From == seer.PlayerId).Aggregate(string.Empty, (current, arrowInfo) => current + LocateArrows[arrowInfo]);
}
/// <summary>
/// Check target arrow every FixedUpdate
+13 -14
View File
@@ -929,7 +929,6 @@ public static class Options
public static OptionItem MinWaitAutoStart;
public static OptionItem MaxWaitAutoStart;
public static OptionItem PlayerAutoStart;
//public static OptionItem SidekickCountMode;
public static OptionItem DumpLogAfterGameEnd;
@@ -1185,21 +1184,21 @@ public static class Options
var tab = roleClasses.Key.GetTabFromOptionType();
var categorySuffix = roleClasses.Key switch
{
RoleOptionType.Neutral_Killing => "NK",
RoleOptionType.Neutral_NonKilling => "NNK",
_ => string.Empty
};
TextOptionItem.Create(titleId, $"ROT.Basic{categorySuffix}", tab)
.SetGameMode(CustomGameMode.Standard)
.SetColor(Color.gray)
.SetHeader(true);
titleId += 10;
var key = roleClasses.Key.GetSimpleRoleOptionType();
if (simpleRoleClasses.TryGetValue(key, out ISettingHolder[] value))
if (simpleRoleClasses.TryGetValue(key, out ISettingHolder[] value) && value.Length > 0)
{
var categorySuffix = roleClasses.Key switch
{
RoleOptionType.Neutral_Killing => "NK",
RoleOptionType.Neutral_NonKilling => "NNK",
_ => string.Empty
};
TextOptionItem.Create(titleId, $"ROT.Basic{categorySuffix}", tab)
.SetGameMode(CustomGameMode.Standard)
.SetColor(Color.gray)
.SetHeader(true);
titleId += 10;
foreach (ISettingHolder holder in value)
{
holder.SetupCustomOption();
+28 -19
View File
@@ -42,9 +42,9 @@ other: ∟ ⌠ ⌡ ╬ ╨ ▓ ▒ ░ « » █ ▄ ▌▀▐│ ┤ ╡ ╢
public static class Utils
{
private static readonly DateTime timeStampStartTime = new(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public static long GetTimeStamp(DateTime? dateTime = null) => (long)((dateTime ?? DateTime.Now).ToUniversalTime() - timeStampStartTime).TotalSeconds;
public static long TimeStamp => GetTimeStamp();
private static readonly DateTime TimeStampStartTime = new(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public static long GetTimeStamp(DateTime? dateTime = null) => (long)((dateTime ?? DateTime.Now).ToUniversalTime() - TimeStampStartTime).TotalSeconds;
public static long TimeStamp => (long)(DateTime.Now.ToUniversalTime() - TimeStampStartTime).TotalSeconds;
public static void ErrorEnd(string text)
{
@@ -704,6 +704,7 @@ public static class Utils
__instance.Is(CustomRoleTypes.Impostor) && PlayerControl.LocalPlayer.Is(CustomRoleTypes.Impostor) && Options.ImpKnowAlliesRole.GetBool() ||
__instance.Is(CustomRoleTypes.Impostor) && PlayerControl.LocalPlayer.Is(CustomRoles.Madmate) && Options.MadmateKnowWhosImp.GetBool() ||
CustomTeamManager.AreInSameCustomTeam(__instance.PlayerId, PlayerControl.LocalPlayer.PlayerId) ||
Adventurer.KnowRole(PlayerControl.LocalPlayer, __instance) ||
Totocalcio.KnowRole(PlayerControl.LocalPlayer, __instance) ||
Romantic.KnowRole(PlayerControl.LocalPlayer, __instance) ||
Lawyer.KnowRole(PlayerControl.LocalPlayer, __instance) ||
@@ -716,7 +717,6 @@ public static class Utils
PlayerControl.LocalPlayer.IsRevealedPlayer(__instance) ||
PlayerControl.LocalPlayer.Is(CustomRoles.God) ||
PlayerControl.LocalPlayer.Is(CustomRoles.GM) ||
Totocalcio.KnowRole(PlayerControl.LocalPlayer, __instance) ||
Lawyer.KnowRole(PlayerControl.LocalPlayer, __instance) ||
EvilDiviner.IsShowTargetRole(PlayerControl.LocalPlayer, __instance) ||
Executioner.KnowRole(PlayerControl.LocalPlayer, __instance) ||
@@ -1786,6 +1786,8 @@ public static class Utils
if (Options.CurrentGameMode != CustomGameMode.Standard) goto GameMode;
SelfSuffix.Append(Adventurer.GetSuffixAndHUDText(seer, isForMeeting: isForMeeting));
if (!isForMeeting)
{
if (Options.UsePets.GetBool() && Main.AbilityCD.TryGetValue(seer.PlayerId, out var time) && !seer.IsModClient())
@@ -2138,6 +2140,7 @@ public static class Utils
(seer.Is(CustomRoleTypes.Crewmate) && target.Is(CustomRoles.Marshall) && target.GetTaskState().IsTaskFinished) ||
(Main.PlayerStates[target.PlayerId].deathReason == PlayerState.DeathReason.Vote && Options.SeeEjectedRolesInMeeting.GetBool()) ||
CustomTeamManager.AreInSameCustomTeam(seer.PlayerId, target.PlayerId) ||
Adventurer.KnowRole(seer, target) ||
Totocalcio.KnowRole(seer, target) ||
Romantic.KnowRole(seer, target) ||
Lawyer.KnowRole(seer, target) ||
@@ -2412,25 +2415,30 @@ public static class Utils
public static void AfterMeetingTasks()
{
foreach (var pc in Main.AllAlivePlayerControls)
foreach (var pc in Main.AllPlayerControls)
{
pc.AddKillTimerToDict();
if (pc.Is(CustomRoles.Truant))
if (pc.IsAlive())
{
float beforeSpeed = Main.AllPlayerSpeed[pc.PlayerId];
Main.AllPlayerSpeed[pc.PlayerId] = Main.MinSpeed;
pc.MarkDirtySettings();
_ = new LateTask(() =>
{
Main.AllPlayerSpeed[pc.PlayerId] = beforeSpeed;
pc.MarkDirtySettings();
}, Options.TruantWaitingTime.GetFloat(), $"Truant Waiting: {pc.GetNameWithRole()}");
pc.AddKillTimerToDict();
if (pc.Is(CustomRoles.Truant))
{
float beforeSpeed = Main.AllPlayerSpeed[pc.PlayerId];
Main.AllPlayerSpeed[pc.PlayerId] = Main.MinSpeed;
pc.MarkDirtySettings();
_ = new LateTask(() =>
{
Main.AllPlayerSpeed[pc.PlayerId] = beforeSpeed;
pc.MarkDirtySettings();
}, Options.TruantWaitingTime.GetFloat(), $"Truant Waiting: {pc.GetNameWithRole()}");
}
if (Options.UsePets.GetBool()) pc.AddAbilityCD(includeDuration: false);
Main.PlayerStates[pc.PlayerId].Role.AfterMeetingTasks();
}
if (Options.UsePets.GetBool()) pc.AddAbilityCD(includeDuration: false);
Main.PlayerStates[pc.PlayerId].Role.AfterMeetingTasks();
if (pc.Is(CustomRoles.Specter) || pc.Is(CustomRoles.Haunter)) pc.RpcResetAbilityCooldown();
}
CopyCat.ResetRole();
@@ -2555,6 +2563,7 @@ public static class Utils
Tracefinder.OnPlayerDead(target);
Vulture.OnPlayerDead(target);
Tracker.OnPlayerDeath(target);
Adventurer.OnAnyoneDead(target);
FixedUpdatePatch.LoversSuicide(target.PlayerId, onMeeting);
}
+4 -5
View File
@@ -353,7 +353,7 @@ internal class ChatCommands
settings.Append("</size>");
var txt = sb.ToString();
_ = sb.Clear().Append(txt.RemoveHtmlTags());
if (role.PetActivatedAbility()) sb.Append("<size=50%>" + GetString("SupportsPetMessage").RemoveHtmlTags() + "</size>");
if (role.PetActivatedAbility() && sb.Length < 1000) sb.Append("<size=50%>" + GetString("SupportsPetMessage").RemoveHtmlTags() + "</size>");
sb.Append("<size=70%>");
foreach (CustomRoles subRole in Main.PlayerStates[localPlayerId].SubRoles.ToArray())
{
@@ -939,7 +939,7 @@ internal class ChatCommands
_ = sb.Clear().Append(txt);
}
if (rl.PetActivatedAbility()) sb.Append($"<size=50%>{GetString("SupportsPetMessage")}</size>");
if (rl.PetActivatedAbility() && sb.Length < 1000) sb.Append($"<size=50%>{GetString("SupportsPetMessage")}</size>");
Utils.SendMessage(text: "\n", sendTo: playerId, title: settings.ToString());
Utils.SendMessage(text: sb.ToString(), sendTo: playerId, title: title);
return;
@@ -968,8 +968,7 @@ internal class ChatCommands
if (GuessManager.GuesserMsg(player, text))
{
if (GuessManager.GuesserMsg(player, text) ||
Judge.TrialMsg(player, text) ||
if (Judge.TrialMsg(player, text) ||
NiceSwapper.SwapMsg(player, text) ||
ParityCop.ParityCheckMsg(player, text) ||
Councillor.MurderMsg(player, text))
@@ -1045,7 +1044,7 @@ internal class ChatCommands
settings.Append("</size>");
var txt = sb.ToString();
_ = sb.Clear().Append(txt.RemoveHtmlTags());
if (role.PetActivatedAbility()) sb.Append("<size=50%>" + GetString("SupportsPetMessage").RemoveHtmlTags() + "</size>");
if (role.PetActivatedAbility() && sb.Length < 1000) sb.Append("<size=50%>" + GetString("SupportsPetMessage").RemoveHtmlTags() + "</size>");
sb.Append("<size=70%>");
foreach (CustomRoles subRole in Main.PlayerStates[player.PlayerId].SubRoles.ToArray())
{
+2 -1
View File
@@ -377,6 +377,7 @@ class HudManagerPatch
CustomRoles.Swooper or CustomRoles.Wraith or CustomRoles.Chameleon => Swooper.GetHudText(player),
CustomRoles.HeadHunter => HeadHunter.GetHudText(player),
CustomRoles.Alchemist => Alchemist.GetHudText(player),
CustomRoles.Adventurer => Adventurer.GetSuffixAndHUDText(player, hud: true),
CustomRoles.Werewolf => Werewolf.GetHudText(player),
CustomRoles.Glitch => Glitch.GetHudText(player),
CustomRoles.NiceHacker => NiceHacker.GetHudText(player),
@@ -773,7 +774,7 @@ class TaskPanelBehaviourPatch
List<(int, byte)> list3 = [];
foreach (var id in Main.PlayerStates.Keys) list3.Add((MoveAndStopManager.GetRankOfScore(id), id));
list3.Sort();
list3 = [.. list3.OrderBy(x => Utils.GetPlayerById(x.Item2).IsAlive())];
list3 = [.. list3.OrderBy(x => !Utils.GetPlayerById(x.Item2).IsAlive())];
foreach (var id in list3.Where(x => SummaryText3.ContainsKey(x.Item2)).ToArray())
{
bool alive = Utils.GetPlayerById(id.Item2).IsAlive();
+1
View File
@@ -182,6 +182,7 @@ class BeginCrewmatePatch
var team = CustomTeamManager.GetCustomTeam(PlayerControl.LocalPlayer.PlayerId);
if (team != null)
{
teamToDisplay = new();
foreach (var pc in Main.AllPlayerControls)
{
if (CustomTeamManager.AreInSameCustomTeam(pc.PlayerId, PlayerControl.LocalPlayer.PlayerId))
+25 -7
View File
@@ -121,7 +121,7 @@ class CheckForEndVotingPatch
}
}
if (__instance.playerStates.TakeWhile(_ => !shouldSkip).Any(ps => !(Main.PlayerStates[ps.TargetPlayerId].IsDead || ps.DidVote)))
if (!shouldSkip && !__instance.playerStates.All(ps => Main.PlayerStates[ps.TargetPlayerId].IsDead || ps.DidVote || Utils.GetPlayerById(ps.TargetPlayerId).Data.Disconnected))
{
return false;
}
@@ -132,7 +132,7 @@ class CheckForEndVotingPatch
foreach (var ps in __instance.playerStates)
{
if (ps == null) continue;
voteLog.Info($"{ps.TargetPlayerId,-2}{$"({Utils.GetVoteName(ps.TargetPlayerId)})".PadRightV2(40)}:{ps.VotedFor,-3}{$"({Utils.GetVoteName(ps.VotedFor)})"}");
voteLog.Info($"{ps.TargetPlayerId,-2}{$"({Utils.GetVoteName(ps.TargetPlayerId)})".PadRightV2(40)}:{ps.VotedFor,-3}({Utils.GetVoteName(ps.VotedFor)})");
var voter = Utils.GetPlayerById(ps.TargetPlayerId);
if (voter == null || voter.Data == null || voter.Data.Disconnected) continue;
if (Options.VoteMode.GetBool())
@@ -195,9 +195,6 @@ class CheckForEndVotingPatch
VotedForId = ps.VotedFor
});
Blackmailer.OnCheckForEndVoting();
NiceSwapper.OnCheckForEndVoting();
if (CheckRole(ps.TargetPlayerId, CustomRoles.Mayor) && !Mayor.MayorHideVote.GetBool()) //Mayorの投票数
{
for (var i2 = 0; i2 < Mayor.MayorAdditionalVote.GetFloat(); i2++)
@@ -221,8 +218,20 @@ class CheckForEndVotingPatch
});
}
}
if (Main.PlayerStates[ps.TargetPlayerId].Role is Adventurer { IsEnable: true } av && av.ActiveWeapons.Contains(Adventurer.Weapon.Proxy))
{
statesList.Add(new()
{
VoterId = ps.TargetPlayerId,
VotedForId = ps.VotedFor
});
}
}
Blackmailer.OnCheckForEndVoting();
NiceSwapper.OnCheckForEndVoting();
states = [.. statesList];
var VotingData = __instance.CustomCalculateVotes();
@@ -387,7 +396,10 @@ class CheckForEndVotingPatch
if (Options.ShowTeamNextToRoleNameOnEject.GetBool())
{
name += " (";
if (player.GetCustomRole().IsImpostor() || player.Is(CustomRoles.Madmate))
var team = CustomTeamManager.GetCustomTeam(player.PlayerId);
if (team != null)
name += Utils.ColorString(team.RoleRevealScreenBackgroundColor == "*" || !ColorUtility.TryParseHtmlString(team.RoleRevealScreenBackgroundColor, out var color) ? Color.yellow : color, team.RoleRevealScreenTitle == "*" ? team.TeamName : team.RoleRevealScreenTitle);
else if (player.GetCustomRole().IsImpostor() || player.Is(CustomRoles.Madmate))
name += Utils.ColorString(new(255, 25, 25, byte.MaxValue), GetString("TeamImpostor"));
else if (player.GetCustomRole().IsNeutral() || player.Is(CustomRoles.Charmed))
name += Utils.ColorString(new(255, 171, 27, byte.MaxValue), GetString("TeamNeutral"));
@@ -584,6 +596,11 @@ static class ExtendedMeetingHud
) VoteNum += VoteNum;
}
if (Main.PlayerStates[ps.TargetPlayerId].Role is Adventurer { IsEnable: true } av && av.ActiveWeapons.Contains(Adventurer.Weapon.Proxy))
{
VoteNum++;
}
if (CheckForEndVotingPatch.CheckRole(ps.TargetPlayerId, CustomRoles.TicketsStealer))
{
var ps1 = ps;
@@ -654,7 +671,7 @@ class MeetingHudStartPatch
AddMsg(string.Format(GetString("WorkaholicAdviceAlive"), string.Join(separator, workaholicAliveList)), 255, Utils.ColorString(Utils.GetRoleColor(CustomRoles.Workaholic), GetString("WorkaholicAliveTitle")));
}
//Bait Notify
// Bait Notify
if (MeetingStates.FirstMeeting && CustomRoles.Bait.RoleExist() && Options.BaitNotification.GetBool())
{
foreach (var pc in Main.AllAlivePlayerControls.Where(x => x.Is(CustomRoles.Bait)).ToArray())
@@ -780,6 +797,7 @@ class MeetingHudStartPatch
(pc.Is(CustomRoles.Marshall) && PlayerControl.LocalPlayer.Is(CustomRoleTypes.Crewmate) && pc.GetTaskState().IsTaskFinished) ||
(Main.PlayerStates[pc.PlayerId].deathReason == PlayerState.DeathReason.Vote && Options.SeeEjectedRolesInMeeting.GetBool()) ||
CustomTeamManager.AreInSameCustomTeam(pc.PlayerId, PlayerControl.LocalPlayer.PlayerId) ||
Adventurer.KnowRole(PlayerControl.LocalPlayer, pc) ||
Totocalcio.KnowRole(PlayerControl.LocalPlayer, pc) ||
Romantic.KnowRole(PlayerControl.LocalPlayer, pc) ||
EvilDiviner.IsShowTargetRole(PlayerControl.LocalPlayer, pc) ||
+11 -15
View File
@@ -330,6 +330,8 @@ class CheckMurderPatch
if (Penguin.IsVictim(killer)) return false;
if (!Adventurer.OnAnyoneCheckMurder(target)) return false;
if (killer.Is(CustomRoles.Refugee) && target.Is(CustomRoleTypes.Impostor)) return false;
if (SoulHunter.IsSoulHunterTarget(killer.PlayerId) && target.Is(CustomRoles.SoulHunter))
@@ -660,7 +662,7 @@ class ShapeshiftPatch
if (Main.CheckShapeshift.TryGetValue(shapeshifter.PlayerId, out var last) && last == shapeshifting)
{
// Dunno how you would get here but ok
// Don't know how you would get here but ok
return true;
}
@@ -720,6 +722,11 @@ class ShapeshiftPatch
{
pc.Notify(shapeshifting ? GetString("ShiftguardNotifySS") : "ShiftguardNotifyUnshift");
}
if (Main.PlayerStates[pc.PlayerId].Role is Adventurer { IsEnable: true } av)
{
Adventurer.OnAnyoneShapeshiftLoop(av, __instance);
}
}
}
}
@@ -1554,20 +1561,9 @@ class FixedUpdatePatch
offset += 0.15f;
}
if (!seer.IsAlive())
{
offset += 0.1f;
}
if (isProgressTextLong)
{
offset += 0.3f;
}
if (Options.CurrentGameMode == CustomGameMode.MoveAndStop)
{
offset += 0.2f;
}
if (!seer.IsAlive()) offset += 0.1f;
if (isProgressTextLong) offset += 0.3f;
if (Options.CurrentGameMode == CustomGameMode.MoveAndStop) offset += 0.2f;
RoleText.transform.SetLocalY(offset);
}
+12 -5
View File
@@ -71,7 +71,7 @@ class RepairSystemPatch
if (RepairSender.enabled && AmongUsClient.Instance.NetworkMode != NetworkModes.OnlineGame)
Logger.SendInGame("SystemType: " + systemType + ", PlayerName: " + player.GetNameWithRole().RemoveHtmlTags() + ", amount: " + amount);
if (!AmongUsClient.Instance.AmHost) return true; //Execute the following only on the host
if (!AmongUsClient.Instance.AmHost) return true; // Execute the following only on the host
IsComms = PlayerControl.LocalPlayer.myTasks.ToArray().Any(x => x.TaskType == TaskTypes.FixComms);
@@ -79,7 +79,7 @@ class RepairSystemPatch
if (Options.DisableSabotage.GetBool() && systemType == SystemTypes.Sabotage) return false;
//Note: "SystemTypes.Laboratory" сauses bugs in the Host, it is better not to use
// Note: "SystemTypes.Laboratory" сauses bugs in the Host, it is better not to use
if (player.Is(CustomRoles.Fool) &&
(systemType is
SystemTypes.Comms or
@@ -168,20 +168,27 @@ class RepairSystemPatch
var SwitchSystem = ShipStatus.Instance?.Systems?[SystemTypes.Electrical]?.Cast<SwitchSystem>();
if (SwitchSystem is { IsActive: true })
{
switch (player.GetCustomRole())
switch (Main.PlayerStates[player.PlayerId].Role)
{
case CustomRoles.SabotageMaster:
case SabotageMaster:
Logger.Info($"{player.GetNameWithRole().RemoveHtmlTags()} instant-fix-lights", "SwitchSystem");
SabotageMaster.SwitchSystemRepair(player.PlayerId, SwitchSystem, amount);
Utils.NotifyRoles(SpecifySeer: player, SpecifyTarget: player);
break;
case CustomRoles.Alchemist when Main.PlayerStates[player.PlayerId].Role is Alchemist { FixNextSabo: true } am:
case Alchemist { FixNextSabo: true } am:
Logger.Info($"{player.GetNameWithRole().RemoveHtmlTags()} instant-fix-lights", "SwitchSystem");
SwitchSystem.ActualSwitches = 0;
SwitchSystem.ExpectedSwitches = 0;
am.FixNextSabo = false;
Utils.NotifyRoles(SpecifySeer: player, SpecifyTarget: player);
break;
case Adventurer av:
Logger.Info($"{player.GetNameWithRole().RemoveHtmlTags()} instant-fix-lights", "SwitchSystem");
SwitchSystem.ActualSwitches = 0;
SwitchSystem.ExpectedSwitches = 0;
av.OnLightsFix();
Utils.NotifyRoles(SpecifySeer: player, SpecifyTarget: player);
break;
}
if (player.Is(CustomRoles.Damocles) && Damocles.countRepairSabotage) Damocles.OnRepairSabotage(player.PlayerId);
+26
View File
@@ -3106,6 +3106,32 @@
"CandleLighterEndVision": "End Vision (Smallest Vision)",
"CandleLighterTimeMoveMeeting": "Time Moves During Meetings",
"CandleLighterTasksFinishedVision": "Vision after completing all tasks",
"AprilFoolsMode": "April Fools Mode",
"SilenceMode": "Silencing Method",
"Adventurer": "Adventurer",
"AdventurerInfo": "Collect Resources to Perform Actions",
"AdventurerInfoLong": "(Crewmates):\\nAs the Adventurer, you can collect resources listed below and craft them into weapons if you have the required amount of materials for it.<size=70%>\\n\\n<u><b>Resources (and how to obtain them):</b></u>\\n- ❖ (Complete a Task)\\n- Θ (Players Leave This Behind<sup>*</sup>)\\n- ♳ (Dead Bodies<sup>*</sup>)\\n- ⁂ (Shapeshift Skins<sup>*</sup>)\\n- \u2600 (Fix Lights)\\n- ○ (Found in Groups<sup>*</sup>)\\n<size=50%><sup>*</sup> When this resource is available somewhere, you get an arrow pointing towards that location. (Except dead bodies.) Go there to collect it.</size>\\n\\n<u><b>Weapons (and their ingredients):</b></u>\\n- Gun (1 ♳ + 1 ❖) (Kill someone (pet near them))\\n- Shield (3 ❖) (Gives someone a 1-time shield)\\n- Lantern (1 \u2600 + 1 ❖) (Increases crewmates' vision for some time)\\n- Portal (2 Θ) (Swaps you with a random player)\\n- Wrench (1 \u2600 + 2 ❖) (Clears the current sabotage)\\n- Proxy (2 ○ + 1 ❖) (Gives you +1 vote in the next meeting)\\n- Prediction (1 ♳ + 2 ⁂ + 1 ❖) (Reveals the nearest player's role)\\n- RNG (2 Θ + 2 ❖) (Makes a random weapon)</size>",
"AdventurerWeaponDescription.Gun": "Kill the next player you go near",
"AdventurerWeaponDescription.Shield": "Gives someone a 1-time shield",
"AdventurerWeaponDescription.Lantern": "Increases crewmates' vision for some time",
"AdventurerWeaponDescription.Portal": "Swaps you with a random player",
"AdventurerWeaponDescription.Wrench": "Clears the current sabotage",
"AdventurerWeaponDescription.Proxy": "Gives you +1 vote in the next meeting",
"AdventurerWeaponDescription.Prediction": "Reveals the nearest player's role",
"AdventurerWeaponDescription.RNG": "Makes a random weapon",
"AdventurerIncreasedVisionDuration": "Increased Vision Duration",
"AdventurerWeaponEnabled.Gun": "Gun Enabled",
"AdventurerWeaponEnabled.Shield": "Healthy Dose Enabled",
"AdventurerWeaponEnabled.Lantern": "Lantern Enabled",
"AdventurerWeaponEnabled.Portal": "Portal Enabled",
"AdventurerWeaponEnabled.Wrench": "Wrench Enabled",
"AdventurerWeaponEnabled.Proxy": "Proxy Enabled",
"AdventurerWeaponEnabled.Prediction": "Prediction Enabled",
"AdventurerWeaponEnabled.RNG": "RNG Enabled",
"AdventurerVentToEnterCrafting": "Vent to Enter Crafting Menu",
"AdventurerIngredientsDisplay": "{0}: {1}\\nVent to craft this weapon / Pet to cycle to next weapon",
"AdventurerWeaponCrafted": "Crafted Weapon: {0}",
"AdventurerFound": "Found Resource: {0}",
"Imitator": "Imitator",
"ImitatorInfo": "Your kill cooldown shifts",
"ImitatorInfoLong": "(Neutral):\\nAs the Imitator, your kill cooldown is different after every even numbered kill and every odd numbered kill of yours. You have a separate cooldown after meetings. Your first kill after every meeting will set your cooldown to the Even-Numbered Kill Cooldown, your second kill will set it to the Odd-Numbered Kill Cooldown, and the process repeats until a meeting is called again.",
+1 -1
View File
@@ -27,7 +27,7 @@ namespace EHR.Roles.AddOns.GhostRoles
GameData.Instance.RpcSetTasks(pc.PlayerId, Array.Empty<byte>());
pc.SyncSettings();
pc.RpcResetAbilityCooldown();
_ = new LateTask(pc.RpcResetAbilityCooldown, 1f, log: false);
Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
}, 1f, "Specter Assign");
}
+366
View File
@@ -0,0 +1,366 @@
using EHR.Patches;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace EHR.Roles.Crewmate
{
internal class Adventurer : RoleBase
{
public static bool On;
public override bool IsEnable => On;
enum Resource
{
TaskCompletion,
Random,
DeadBody,
ShapeshiftSkin,
LightsFix,
Grouping
}
public enum Weapon
{
Gun,
Shield,
Lantern,
Portal,
Wrench,
Proxy,
Prediction,
RNG
}
private static readonly Dictionary<Resource, (char Icon, Color Color)> ResourceDisplayData = new()
{
{ Resource.TaskCompletion, ('\u2756', Color.blue) },
{ Resource.Random, ('Θ', Color.cyan) },
{ Resource.DeadBody, ('\u2673', Color.magenta) },
{ Resource.ShapeshiftSkin, ('⁂', Color.gray) },
{ Resource.LightsFix, ('\u2600', Color.yellow) },
{ Resource.Grouping, ('\u25cb', Color.green) }
};
private static readonly Dictionary<Weapon, List<(Resource Resource, int Count)>> Ingredients = new()
{
{ Weapon.Gun, [(Resource.DeadBody, 1), (Resource.TaskCompletion, 1)] },
{ Weapon.Shield, [(Resource.TaskCompletion, 3)] },
{ Weapon.Lantern, [(Resource.LightsFix, 1), (Resource.TaskCompletion, 1)] },
{ Weapon.Portal, [(Resource.Random, 2)] },
{ Weapon.Wrench, [(Resource.LightsFix, 1), (Resource.TaskCompletion, 2)] },
{ Weapon.Proxy, [(Resource.Grouping, 2), (Resource.TaskCompletion, 1)] },
{ Weapon.Prediction, [(Resource.DeadBody, 1), (Resource.ShapeshiftSkin, 2), (Resource.TaskCompletion, 1)] },
{ Weapon.RNG, [(Resource.Random, 2), (Resource.TaskCompletion, 2)] }
};
private static OptionItem IncreasedVisionDuration;
private static readonly Dictionary<Weapon, OptionItem> WeaponEnabledSettings = [];
private static List<Weapon> EnabledWeapons = [];
static OptionItem CreateWeaponEnabledSetting(int id, Weapon weapon) => BooleanOptionItem.Create(id, $"AdventurerWeaponEnabled.{weapon}", true, TabGroup.CrewmateRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Adventurer]);
public static void SetupCustomOption()
{
Options.SetupRoleOptions(11330, TabGroup.CrewmateRoles, CustomRoles.Adventurer);
IncreasedVisionDuration = IntegerOptionItem.Create(11332, "AdventurerIncreasedVisionDuration", new(1, 60, 1), 30, TabGroup.CrewmateRoles, false)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Adventurer])
.SetValueFormat(OptionFormat.Seconds);
foreach (var weapon in EnumHelper.GetAllValues<Weapon>())
{
WeaponEnabledSettings[weapon] = CreateWeaponEnabledSetting(11333 + (int)weapon, weapon);
}
}
private PlayerControl AdventurerPC;
private readonly Dictionary<Resource, int> ResourceCounts = [];
public bool InCraftingMode;
private Weapon SelectedWeaponToCraft;
public List<Weapon> OrderedWeapons;
public List<Weapon> ActiveWeapons;
public HashSet<byte> ShieldedPlayers;
public HashSet<byte> RevealedPlayers;
private long LastRandomResourceTimeStamp;
private long LastGroupingResourceTimeStamp;
private Dictionary<Resource, Vector2> ResourceLocations;
public override void Add(byte playerId)
{
On = true;
AdventurerPC = Utils.GetPlayerById(playerId);
InCraftingMode = false;
SelectedWeaponToCraft = new();
OrderedWeapons = [];
ActiveWeapons = [];
ShieldedPlayers = [];
RevealedPlayers = [];
LastRandomResourceTimeStamp = Utils.TimeStamp + 8;
LastGroupingResourceTimeStamp = Utils.TimeStamp + 20;
ResourceLocations = [];
foreach (var resource in EnumHelper.GetAllValues<Resource>())
{
ResourceCounts[resource] = 0;
}
}
public override void Init()
{
On = false;
EnabledWeapons = WeaponEnabledSettings
.Where(x => x.Value.GetBool())
.Select(x => x.Key)
.ToList();
}
public override void OnExitVent(PlayerControl pc, Vent vent)
{
InCraftingMode = !InCraftingMode;
switch (InCraftingMode)
{
case true:
OrderedWeapons = [.. EnabledWeapons.OrderBy(x => !Ingredients[x].All(r => r.Count <= ResourceCounts[r.Resource]))];
SelectedWeaponToCraft = OrderedWeapons.FirstOrDefault();
break;
case false when Ingredients[SelectedWeaponToCraft].All(x => x.Count <= ResourceCounts[x.Resource]):
var weapon = SelectedWeaponToCraft == Weapon.RNG ? EnabledWeapons[IRandom.Instance.Next(EnabledWeapons.Count)] : SelectedWeaponToCraft;
ActiveWeapons.Add(weapon);
pc.Notify(string.Format(Translator.GetString("AdventurerWeaponCrafted"), $"{weapon}"));
foreach ((Resource resource, int count) in Ingredients[weapon])
{
ResourceCounts[resource] -= count;
}
switch (weapon)
{
case Weapon.Lantern:
Utils.MarkEveryoneDirtySettings();
_ = new LateTask(() => { ActiveWeapons.Remove(Weapon.Lantern); }, IncreasedVisionDuration.GetInt(), log: false);
break;
case Weapon.Portal:
_ = new LateTask(() =>
{
var e = Main.AllAlivePlayerControls.Where(x => x.PlayerId != pc.PlayerId && !x.inVent && !x.inMovingPlat && !x.onLadder);
var filtered = e as PlayerControl[] ?? e.ToArray();
if (filtered.Length == 0) return;
var target = filtered[IRandom.Instance.Next(filtered.Length)];
target.TP(pc);
pc.TP(target);
ActiveWeapons.Remove(weapon);
}, 1f, log: false);
break;
case Weapon.Wrench:
if (Utils.IsActive(SystemTypes.Electrical))
{
var SwitchSystem = ShipStatus.Instance?.Systems?[SystemTypes.Electrical]?.TryCast<SwitchSystem>();
if (SwitchSystem != null)
{
SwitchSystem.ActualSwitches = 0;
SwitchSystem.ExpectedSwitches = 0;
}
}
else if (Utils.IsActive(SystemTypes.Reactor))
{
ShipStatus.Instance.RpcUpdateSystem(SystemTypes.Reactor, 16);
ShipStatus.Instance.RpcUpdateSystem(SystemTypes.Reactor, 17);
}
else if (Utils.IsActive(SystemTypes.Laboratory))
{
ShipStatus.Instance.RpcUpdateSystem(SystemTypes.Laboratory, 67);
ShipStatus.Instance.RpcUpdateSystem(SystemTypes.Laboratory, 66);
}
else if (Utils.IsActive(SystemTypes.LifeSupp))
{
ShipStatus.Instance.RpcUpdateSystem(SystemTypes.LifeSupp, 67);
ShipStatus.Instance.RpcUpdateSystem(SystemTypes.LifeSupp, 66);
}
else if (Utils.IsActive(SystemTypes.Comms))
{
ShipStatus.Instance.RpcUpdateSystem(SystemTypes.Comms, 16);
ShipStatus.Instance.RpcUpdateSystem(SystemTypes.Comms, 17);
}
ActiveWeapons.Remove(weapon);
break;
case Weapon.Prediction:
var closest = Main.AllAlivePlayerControls.Where(x => x.PlayerId != pc.PlayerId).MinBy(x => Vector2.Distance(pc.Pos(), x.Pos()));
RevealedPlayers.Add(closest.PlayerId);
ActiveWeapons.Remove(weapon);
break;
}
break;
}
Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
}
public override void OnPet(PlayerControl pc)
{
switch (InCraftingMode)
{
case true:
SelectedWeaponToCraft = OrderedWeapons[(OrderedWeapons.IndexOf(SelectedWeaponToCraft) + 1) % OrderedWeapons.Count];
Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
break;
case false when ActiveWeapons.Count > 0:
var target = ExternalRpcPetPatch.SelectKillButtonTarget(pc);
switch (ActiveWeapons[0])
{
case Weapon.Gun when target != null:
pc.RpcCheckAndMurder(target);
ActiveWeapons.RemoveAt(0);
Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
break;
case Weapon.Shield when target != null:
ShieldedPlayers.Add(target.PlayerId);
ActiveWeapons.RemoveAt(0);
Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
break;
}
break;
}
}
public override void OnTaskComplete(PlayerControl pc, int completedTaskCount, int totalTaskCount)
{
ResourceCounts[Resource.TaskCompletion]++;
}
public override void OnGlobalFixedUpdate(PlayerControl pc, bool lowLoad)
{
long now = Utils.TimeStamp;
if (lowLoad) return;
if (!GameStates.IsInTask)
{
LastGroupingResourceTimeStamp = now;
LastRandomResourceTimeStamp = now;
return;
}
if (LastRandomResourceTimeStamp + 20 <= now && pc.PlayerId != AdventurerPC.PlayerId && IRandom.Instance.Next(50) == 0)
{
var pos = pc.Pos();
LocateArrow.Add(AdventurerPC.PlayerId, pos);
ResourceLocations[Resource.Random] = pos;
LastRandomResourceTimeStamp = now;
Utils.NotifyRoles(SpecifySeer: AdventurerPC, SpecifyTarget: AdventurerPC);
}
if (LastGroupingResourceTimeStamp + 20 <= now && Main.AllAlivePlayerControls.Count(x => x.PlayerId != pc.PlayerId && Vector2.Distance(x.Pos(), pc.Pos()) < 2f) >= 2)
{
var pos = pc.Pos();
LocateArrow.Add(AdventurerPC.PlayerId, pos);
ResourceLocations[Resource.Grouping] = pos;
LastGroupingResourceTimeStamp = now;
Utils.NotifyRoles(SpecifySeer: AdventurerPC, SpecifyTarget: AdventurerPC);
}
}
public override void OnFixedUpdate(PlayerControl pc)
{
foreach ((Resource resource, Vector2 location) in ResourceLocations)
{
if (Vector2.Distance(pc.Pos(), location) < 2f)
{
ResourceCounts[resource]++;
ResourceLocations.Remove(resource);
LocateArrow.Remove(pc.PlayerId, location);
var displayData = ResourceDisplayData[resource];
pc.Notify(string.Format(Translator.GetString("AdventurerFound"), Utils.ColorString(displayData.Color, $"{displayData.Icon}")));
break;
}
}
}
public override void AfterMeetingTasks()
{
ActiveWeapons.Remove(Weapon.Proxy);
}
public void OnLightsFix()
{
ResourceCounts[Resource.LightsFix]++;
}
public static void OnAnyoneShapeshiftLoop(Adventurer av, PlayerControl shapeshifter)
{
av.ResourceLocations[Resource.ShapeshiftSkin] = shapeshifter.Pos();
}
public static void OnAnyoneDead(PlayerControl target)
{
foreach (var state in Main.PlayerStates.Values)
{
if (state.Role is Adventurer { IsEnable: true } av)
{
av.ResourceLocations[Resource.DeadBody] = target.Pos();
}
}
}
public static bool OnAnyoneCheckMurder(PlayerControl target)
{
bool any = false;
foreach (var s in Main.PlayerStates.Values)
{
if (s.Role is Adventurer { IsEnable: true } av && av.ShieldedPlayers.Contains(target.PlayerId))
{
any = true;
av.ShieldedPlayers.Remove(target.PlayerId);
break;
}
}
return !any;
}
public static bool KnowRole(PlayerControl seer, PlayerControl target)
{
return Main.PlayerStates[seer.PlayerId].Role is Adventurer { IsEnable: true } av && av.RevealedPlayers.Contains(target.PlayerId);
}
public static string GetSuffixAndHUDText(PlayerControl pc, bool hud = false, bool isForMeeting = false)
{
if (pc.IsModClient() && !hud) return string.Empty;
if (Main.PlayerStates[pc.PlayerId].Role is not Adventurer { IsEnable: true } av) return string.Empty;
IEnumerable<string> resources =
from resource in EnumHelper.GetAllValues<Resource>()
let displayData = ResourceDisplayData[resource]
select $"{Utils.ColorString(displayData.Color, $"{displayData.Icon}")}{av.ResourceCounts[resource]}";
string finalText = string.Join(' ', resources);
if (isForMeeting) return finalText;
finalText += $"\n{LocateArrow.GetArrows(pc)}\n";
finalText += "<size=80%>";
finalText += av.InCraftingMode
? string.Format(
Translator.GetString("AdventurerIngredientsDisplay"),
$"{av.SelectedWeaponToCraft}",
string.Join(' ', Ingredients[av.SelectedWeaponToCraft]
.Select(x => $"{Utils.ColorString(ResourceDisplayData[x.Resource].Color, $"{ResourceDisplayData[x.Resource].Icon}")}" +
$"{Utils.ColorString(x.Count > av.ResourceCounts[x.Resource] ? Color.red : Color.white, $"{x.Count}")}")))
: Translator.GetString("AdventurerVentToEnterCrafting");
finalText += "</size>";
return finalText;
}
}
}
+1 -1
View File
@@ -52,7 +52,7 @@ namespace EHR.Roles.Neutral
public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat();
public override void ApplyGameOptions(IGameOptions opt, byte id) => opt.SetVision(true);
public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool();
public override bool CanUseSabotage(PlayerControl pc) => true;
public override bool CanUseSabotage(PlayerControl pc) => pc.IsAlive();
public override void OnPet(PlayerControl pc)
{
+1 -1
View File
@@ -96,7 +96,7 @@ public class Glitch : RoleBase
public override bool IsEnable => playerIdList.Count > 0;
public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool();
public override bool CanUseSabotage(PlayerControl pc) => true;
public override bool CanUseSabotage(PlayerControl pc) => pc.IsAlive();
void SendRPCSyncTimers()
{
+1 -1
View File
@@ -52,7 +52,7 @@ namespace EHR.Roles.Neutral
public override bool IsEnable => HookshotId != byte.MaxValue;
public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat();
public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool();
public override bool CanUseSabotage(PlayerControl pc) => true;
public override bool CanUseSabotage(PlayerControl pc) => pc.IsAlive();
public override void ApplyGameOptions(IGameOptions opt, byte id) => opt.SetVision(HasImpostorVision.GetBool());
void SendRPC()
+1 -1
View File
@@ -88,7 +88,7 @@ public class Jackal : RoleBase
public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat();
public static bool CanRecruit(byte id) => id.GetAbilityUseLimit() > 0;
public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool();
public override bool CanUseSabotage(PlayerControl pc) => CanSabotage.GetBool();
public override bool CanUseSabotage(PlayerControl pc) => CanSabotage.GetBool() && pc.IsAlive();
public override void SetButtonTexts(HudManager hud, byte id)
{
+1 -1
View File
@@ -107,7 +107,7 @@ public class Magician : RoleBase
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) => CanVent.GetBool();
public override bool CanUseSabotage(PlayerControl pc) => true;
public override bool CanUseSabotage(PlayerControl pc) => pc.IsAlive();
public override void OnMurder(PlayerControl killer, PlayerControl target)
{
+1 -1
View File
@@ -139,6 +139,6 @@ namespace EHR.Roles.Neutral
public override bool OnCheckMurder(PlayerControl killer, PlayerControl target) => IsEnable && target != null && InfectedPlayers.Contains(target.PlayerId);
public override void AfterMeetingTasks() => Mycologist_.AddAbilityCD(CD.GetInt());
public override bool CanUseImpostorVentButton(PlayerControl pc) => true;
public override bool CanUseSabotage(PlayerControl pc) => SpreadAction.GetValue() == 1;
public override bool CanUseSabotage(PlayerControl pc) => SpreadAction.GetValue() == 1 && pc.IsAlive();
}
}
+1 -1
View File
@@ -26,5 +26,5 @@ public class Sidekick : RoleBase
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 void SetButtonTexts(HudManager __instance, byte id) => __instance.SabotageButton.ToggleVisible(Jackal.CanSabotageSK.GetBool());
public override bool CanUseSabotage(PlayerControl pc) => Jackal.CanSabotageSK.GetBool();
public override bool CanUseSabotage(PlayerControl pc) => Jackal.CanSabotageSK.GetBool() && pc.IsAlive();
}
+1 -1
View File
@@ -85,7 +85,7 @@ namespace EHR.Roles.Neutral
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) => CanVent.GetBool();
public override bool CanUseSabotage(PlayerControl pc) => true;
public override bool CanUseSabotage(PlayerControl pc) => pc.IsAlive();
public override bool OnSabotage(PlayerControl pc)
{
+1 -1
View File
@@ -60,7 +60,7 @@ namespace EHR.Roles.Neutral
public override bool CanUseSabotage(PlayerControl pc)
{
return true;
return pc.IsAlive();
}
public override bool OnSabotage(PlayerControl pc)
+1 -1
View File
@@ -43,5 +43,5 @@ public class Traitor : RoleBase
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) => CanVent.GetBool();
public override bool CanUseSabotage(PlayerControl pc) => CanSabotage.GetBool();
public override bool CanUseSabotage(PlayerControl pc) => CanSabotage.GetBool() && pc.IsAlive();
}
+1 -1
View File
@@ -88,7 +88,7 @@ public class WeaponMaster : RoleBase
public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat();
public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool();
public override bool CanUseSabotage(PlayerControl pc) => true;
public override bool CanUseSabotage(PlayerControl pc) => pc.IsAlive();
public override void ApplyGameOptions(IGameOptions opt, byte id)
{
+1 -1
View File
@@ -51,7 +51,7 @@ namespace EHR
public virtual bool CanUseSabotage(PlayerControl pc)
{
return pc.Is(Team.Impostor) || pc.Is(CustomRoles.Mischievous) || (pc.Is(CustomRoles.Bloodlust) && Bloodlust.HasImpVision.GetBool());
return pc.Is(Team.Impostor) || (pc.Is(CustomRoles.Mischievous) || (pc.Is(CustomRoles.Bloodlust) && Bloodlust.HasImpVision.GetBool()) && pc.IsAlive());
}
public virtual void ApplyGameOptions(IGameOptions opt, byte playerId)
+3 -2
View File
@@ -35,8 +35,8 @@ public class Main : BasePlugin
public const string DebugKeySalt = "59687b";
public static ConfigEntry<string> DebugKeyInput { get; private set; }
public const string PluginGuid = "com.gurge44.endlesshostroles";
public const string PluginVersion = "3.1.1";
public const string PluginDisplayVersion = "3.1.1";
public const string PluginVersion = "3.1.2";
public const string PluginDisplayVersion = "3.1.2";
public static readonly string SupportedAUVersion = "2024.3.5";
public Harmony Harmony { get; } = new(PluginGuid);
@@ -305,6 +305,7 @@ public class Main : BasePlugin
{ CustomRoles.Express, "#00ffff" },
{ CustomRoles.NiceEraser, "#00a5ff" },
{ CustomRoles.TaskManager, "#00ffa5" },
{ CustomRoles.Adventurer, "#fbbb04" },
{ CustomRoles.Randomizer, "#fcba03" },
{ CustomRoles.Beacon, "#a3fdff" },
{ CustomRoles.Rabbit, "#88d2ff" },