some fixes

This commit is contained in:
Gurge44 committed 2025-04-25 12:39:13 +02:00
1 parent 2d00117b84
commit 61f96ef388
14 files changed
+206 -167

No files matched your search

+1
View File
@@ -66,6 +66,7 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=TS/@EntryIndexedValue">TS</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>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=XOR/@EntryIndexedValue">XOR</s:String>
<s:String
x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=42a3efd9_002Dd16d_002D4959_002Daa84_002D6ab8f5f87659/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Private, Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="non_field_members_should_be_pascal_case"&gt;&lt;ElementKinds&gt;&lt;Kind Name="PROPERTY" /&gt;&lt;Kind Name="EVENT" /&gt;&lt;Kind Name="METHOD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="False" Prefix="Get" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String
+59 -22
View File
@@ -3,7 +3,6 @@ using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using AmongUs.GameOptions;
using EHR.Modules;
using HarmonyLib;
using Hazel;
@@ -83,17 +82,19 @@ public static class Quiz
private static int QuestionsAsked;
private static long FFAEndTS;
private static bool NoSuffix;
public static bool AllowKills;
private static OptionItem FFAEventLength;
private static readonly Dictionary<Difficulty, (OptionItem Rounds, OptionItem QuestionsAsked, OptionItem CorrectRequirement, OptionItem TimeLimit)> Settings = [];
private static OptionItem ChatDuringGame;
static Quiz()
{
UsedRooms[MapNames.Dleks] = UsedRooms[MapNames.Skeld];
}
public static bool Chat => ChatDuringGame.GetBool();
public static void SetupCustomOption()
{
var id = 69_220_001;
@@ -115,6 +116,7 @@ public static class Quiz
.SetGameMode(gameMode);
var questionsAsked = new IntegerOptionItem(id++, $"Quiz.Settings.QuestionsAsked.{difficulty}", new(1, 50, 1), 3, TabGroup.GameSettings)
.SetHeader(difficulty == Difficulty.Hard)
.SetColor(color)
.SetGameMode(gameMode);
@@ -129,6 +131,11 @@ public static class Quiz
Settings[difficulty] = (rounds, questionsAsked, correctRequirement, timeLimit);
}
ChatDuringGame = new BooleanOptionItem(id, "Quiz.Settings.ChatDuringGame", false, TabGroup.GameSettings)
.SetHeader(true)
.SetColor(color)
.SetGameMode(gameMode);
}
public static string GetStatistics(byte id)
@@ -150,7 +157,9 @@ public static class Quiz
{
if (NoSuffix) return string.Empty;
bool wasWrong = DyingPlayers.Contains(seer.PlayerId);
int requiredCorrect;
int gotCorrect;
bool failed;
if (FFAEndTS == 0)
{
@@ -188,17 +197,17 @@ public static class Quiz
string correctAnswer = CurrentQuestion.Answers[CurrentQuestion.CorrectAnswerIndex];
char correctAnswerLetter = (char)('A' + CurrentQuestion.CorrectAnswerIndex);
string correctRoom = GetString(UsedRooms[Main.CurrentMap][correctAnswerLetter].ToString());
string color = wasWrong ? "#FF0000" : "#00FF00";
string color = DyingPlayers.Contains(seer.PlayerId) ? "#FF0000" : "#00FF00";
string str = string.Format(GetString("Quiz.Notify.CorrectAnswer"), color, correctAnswerLetter, correctAnswer, correctRoom);
int numPlayers = Main.AllAlivePlayerControls.Length;
if (DyingPlayers.Count == numPlayers) str += "\n" + GetString("Quiz.Notify.AllWrong");
if (DyingPlayers.Count == numPlayers) str += "\n" + GetString(numPlayers <= 3 ? "Quiz.Notify.AllWrongShort" : "Quiz.Notify.AllWrong");
if (CurrentDifficulty > Difficulty.Test && Settings[CurrentDifficulty].QuestionsAsked.GetInt() <= QuestionsAsked)
{
int requiredCorrect = Settings[CurrentDifficulty].CorrectRequirement.GetInt();
int gotCorrect = NumCorrectAnswers[seer.PlayerId][CurrentDifficulty][Round];
bool failed = gotCorrect < requiredCorrect;
requiredCorrect = Settings[CurrentDifficulty].CorrectRequirement.GetInt();
gotCorrect = NumCorrectAnswers[seer.PlayerId][CurrentDifficulty][Round];
failed = gotCorrect < requiredCorrect;
if (seer.IsAlive()) str += "\n\n" + string.Format(Utils.ColorString(failed ? Color.red : Color.green, GetString("Quiz.Notify.CorrectAnswerNum")), gotCorrect, QuestionsAsked, requiredCorrect);
@@ -216,9 +225,13 @@ public static class Quiz
if (!AllowKills) return string.Empty;
requiredCorrect = Settings[CurrentDifficulty].CorrectRequirement.GetInt();
gotCorrect = NumCorrectAnswers[seer.PlayerId][CurrentDifficulty][Round];
failed = gotCorrect < requiredCorrect;
var ffaTimeLeft = FFAEndTS - Utils.TimeStamp;
var rndRoom = Main.AllAlivePlayerControls.Without(seer).Select(x => x.GetPlainShipRoom()).Where(x => x != null).Select(x => x.RoomId).Distinct().Without(SystemTypes.Hallway).RandomElement();
return string.Format(GetString(wasWrong ? "Quiz.Notify.FFAOngoing" : "Quiz.Notify.FFASpectating"), GetString(rndRoom.ToString()), ffaTimeLeft);
var rooms = Main.AllAlivePlayerControls.Without(seer).Select(x => x.GetPlainShipRoom()).Where(x => x != null).Select(x => x.RoomId).Distinct().Without(SystemTypes.Hallway).Select(x => GetString(x.ToString())).Join();
return string.Format(GetString(failed ? "Quiz.Notify.FFAOngoing" : "Quiz.Notify.FFASpectating"), rooms, ffaTimeLeft);
}
public static void Init()
@@ -247,6 +260,8 @@ public static class Quiz
public static IEnumerator OnGameStart()
{
if (Chat) yield return new WaitForSeconds(11f);
NoSuffix = true;
PlayerControl[] aapc = Main.AllAlivePlayerControls;
bool showTutorial = aapc.ExceptBy(HasPlayedFriendCodes, x => x.FriendCode).Count() > aapc.Length / 2;
@@ -285,9 +300,17 @@ public static class Quiz
aapc.NotifyPlayers(GetString("Quiz.Tutorial.OnCorrectAnswer"));
yield return new WaitForSeconds(2f);
if (GameStates.IsMeeting || ExileController.Instance || !GameStates.InGame || GameStates.IsLobby) yield break;
NameNotifyManager.Reset();
}
else
{
NoSuffix = true;
var settings = Settings[CurrentDifficulty];
Main.AllAlivePlayerControls.NotifyPlayers(string.Format(GetString("Quiz.Notify.NextStage"), (int)CurrentDifficulty, settings.Rounds.GetInt(), settings.QuestionsAsked.GetInt(), settings.CorrectRequirement.GetInt(), settings.QuestionsAsked.GetInt(), settings.TimeLimit.GetInt()), 8f);
yield return new WaitForSeconds(6f);
}
if (GameStates.IsMeeting || ExileController.Instance || !GameStates.InGame || GameStates.IsLobby) yield break;
NameNotifyManager.Reset();
yield return NewQuestion(increaseDifficulty: showTutorial, newRound: true);
}
@@ -301,7 +324,7 @@ public static class Quiz
NoSuffix = true;
var settings = Settings[CurrentDifficulty];
Main.AllAlivePlayerControls.NotifyPlayers(string.Format(GetString("Quiz.Notify.NextStage"), (int)CurrentDifficulty, settings.Rounds.GetInt(), settings.QuestionsAsked.GetInt(), settings.CorrectRequirement.GetInt(), settings.QuestionsAsked.GetInt(), settings.TimeLimit.GetInt()), 8f);
yield return new WaitForSeconds(7f);
yield return new WaitForSeconds(6f);
if (GameStates.IsMeeting || ExileController.Instance || !GameStates.InGame || GameStates.IsLobby) yield break;
NameNotifyManager.Reset();
}
@@ -371,14 +394,14 @@ public static class Quiz
SystemTypes correctRoom = UsedRooms[Main.CurrentMap][(char)('A' + CurrentQuestion.CorrectAnswerIndex)];
DyingPlayers = aapc.Select(x => (ID: x.PlayerId, Room: x.GetPlainShipRoom())).Where(x => correctRoom == SystemTypes.Outside ? x.Room != null : x.Room == null || x.Room.RoomId != correctRoom).Select(x => x.ID).ToList();
bool everyoneWasWrong = DyingPlayers.Count == aapc.Length;
if (!everyoneWasWrong) NumCorrectAnswers.DoIf(x => !DyingPlayers.Contains(x.Key), x => x.Value[CurrentDifficulty][Round]++);
if (!everyoneWasWrong) NumCorrectAnswers.IntersectBy(aapc.Select(x => x.PlayerId), x => x.Key).DoIf(x => !DyingPlayers.Contains(x.Key), x => x.Value[CurrentDifficulty][Round]++);
Logger.Info($"{(everyoneWasWrong ? "Everyone" : "Players who")} got the question wrong: {string.Join(", ", DyingPlayers.Select(x => Main.AllPlayerNames.GetValueOrDefault(x, $"Someone (ID {x})")))}", "Quiz");
Logger.Info($"Number of correct answers for everyone currently: {string.Join(", ", NumCorrectAnswers.Select(x => $"{Main.AllPlayerNames.GetValueOrDefault(x.Key, string.Empty)}: {x.Value[CurrentDifficulty][Round]}"))}", "Quiz");
if (everyoneWasWrong) QuestionsAsked--;
else Utils.NotifyRoles();
yield return new WaitForSeconds(everyoneWasWrong ? 11f : 7f);
yield return new WaitForSeconds(everyoneWasWrong ? aapc.Length <= 3 ? 4f : 8f : 5f);
if (GameStates.IsMeeting || ExileController.Instance || !GameStates.InGame || GameStates.IsLobby) yield break;
var settings = Settings[CurrentDifficulty];
@@ -389,7 +412,7 @@ public static class Quiz
yield break;
}
yield return new WaitForSeconds(3f);
yield return new WaitForSeconds(2f);
var correctRequirement = settings.CorrectRequirement.GetInt();
List<byte> dyingPlayers = NumCorrectAnswers.Where(x => x.Value[CurrentDifficulty][Round] < correctRequirement).Select(x => x.Key).ToList();
@@ -412,7 +435,7 @@ public static class Quiz
NumCorrectAnswers.Values.Do(d => d[CurrentDifficulty][Round] = 0);
goto case 0;
default:
yield return new WaitForSeconds(3f);
yield return new WaitForSeconds(2f);
AllowKills = true;
FFAEndTS = Utils.TimeStamp + FFAEventLength.GetInt();
var spectators = aapc.ExceptBy(dyingPlayers, x => x.PlayerId).ToArray();
@@ -439,8 +462,6 @@ public static class Quiz
var location = RandomSpawn.SpawnMap.GetSpawnMap().Positions.IntersectBy(UsedRooms[Main.CurrentMap].Values, x => x.Key).RandomElement().Value;
sender = CustomRpcSender.Create("Quiz.FFA-Event-TP", SendOption.Reliable);
spectators.Do(x => sender.TP(x, location));
sender.SendMessage();
switch (stillLiving.Count)
{
@@ -448,16 +469,26 @@ public static class Quiz
break;
case 1:
stillLiving[0].RpcChangeRoleBasis(CustomRoles.QuizPlayer);
if (!Chat) sender.TP(stillLiving[0], location);
break;
default:
stillLiving.ForEach(x => x.Suicide());
break;
}
Main.AllPlayerSpeed.SetAllValues(Main.RealOptionsData.GetFloat(FloatOptionNames.PlayerSpeedMod));
Utils.MarkEveryoneDirtySettings();
yield return new WaitForSeconds(1f);
yield return new WaitForSeconds(3f);
if (Chat)
{
Utils.SetChatVisibleForAll();
yield return new WaitForSeconds(11f);
sender.TP(stillLiving[0], location);
}
spectators.Do(x => sender.TP(x, location));
sender.SendMessage();
yield return new WaitForSeconds(2f);
if (GameStates.IsMeeting || ExileController.Instance || !GameStates.InGame || GameStates.IsLobby) yield break;
FFAEndTS = 0;
@@ -466,6 +497,12 @@ public static class Quiz
}
}
public static string GetTaskBarText()
{
var correctAnswers = string.Join('\n', NumCorrectAnswers.Select(x => $"{x.Key.ColoredPlayerName()}: {x.Value.Select(k => $"{k.Key.ToString()[0]}-{k.Value.Sum()}")}"));
return string.Format(GetString("Quiz.TaskBarText"), CurrentDifficulty, Round + 1, QuestionsAsked + 1, correctAnswers);
}
enum Difficulty
{
Test,
+1
View File
@@ -74,6 +74,7 @@ public class Main : BasePlugin
public static Dictionary<byte, List<CustomRoles>> SetAddOns = [];
public static readonly Dictionary<int, Dictionary<CustomRoles, List<CustomRoles>>> AlwaysSpawnTogetherCombos = [];
public static readonly Dictionary<int, Dictionary<CustomRoles, List<CustomRoles>>> NeverSpawnTogetherCombos = [];
public static readonly List<(CustomRoles, CustomRoles)> XORRoles = [];
public static Dictionary<byte, string> LastAddOns = [];
public static List<RoleBase> AllRoleClasses;
public static float RefixCooldownDelay;
+11 -1
View File
@@ -93,10 +93,20 @@ internal static class CustomRoleSelector
(bool Spawning, bool OneIsImp) LoversData = (Lovers.LegacyLovers.GetBool(), rd.Next(100) < Lovers.LovingImpostorSpawnChance.GetInt());
LoversData.Spawning &= rd.Next(100) < Options.CustomAdtRoleSpawnRate[CustomRoles.Lovers].GetInt();
HashSet<CustomRoles> xorBannedRoles = [];
foreach ((CustomRoles, CustomRoles) xor in Main.XORRoles)
{
bool first = rd.Next(2) == 0;
xorBannedRoles.Add(first ? xor.Item1 : xor.Item2);
}
if (Main.XORRoles.Count > 0) Logger.Info($"Roles banned by XOR combinations: {string.Join(", ", xorBannedRoles)}", "CustomRoleSelector");
foreach (CustomRoles role in Enum.GetValues<CustomRoles>())
{
int chance = role.GetMode();
if (role.IsVanilla() || chance == 0 || role.IsAdditionRole() || (role.OnlySpawnsWithPets() && !Options.UsePets.GetBool()) || (role != CustomRoles.Randomizer && role.IsCrewmate() && Options.AprilFoolsMode.GetBool()) || CustomHnS.AllHnSRoles.Contains(role)) continue;
if (role.IsVanilla() || chance == 0 || role.IsAdditionRole() || (role.OnlySpawnsWithPets() && !Options.UsePets.GetBool()) || (role != CustomRoles.Randomizer && role.IsCrewmate() && Options.AprilFoolsMode.GetBool()) || CustomHnS.AllHnSRoles.Contains(role) || xorBannedRoles.Contains(role)) continue;
switch (role)
{
+1 -1
View File
@@ -466,7 +466,7 @@ public static class CustomRpcSenderExtensions
if (!player.CanUseKillButton() && !AntiBlackout.SkipTasks) return false;
player.AddKillTimerToDict(CD: time);
player.AddKillTimerToDict(cd: time);
if (target == null) target = player;
if (time >= 0f)
+45 -137
View File
@@ -25,32 +25,6 @@ internal static class ExtendedPlayerControl
{
public const MurderResultFlags ResultFlags = MurderResultFlags.Succeeded;
/*
public static void ResetPlayerCam(this PlayerControl pc, float delay = 0f)
{
if (pc == null || !AmongUsClient.Instance.AmHost || pc.AmOwner) return;
SystemTypes systemtypes = (MapNames)Main.NormalOptions.MapId switch
{
MapNames.Polus => SystemTypes.Laboratory,
MapNames.Airship => SystemTypes.HeliSabotage,
_ => SystemTypes.Reactor
};
LateTask.New(() => pc.RpcDesyncRepairSystem(systemtypes, 128), 0f + delay, "Reactor Desync");
LateTask.New(() => pc.RpcSpecificMurderPlayer(), 0.2f + delay, "Murder To Reset Cam");
LateTask.New(() =>
{
pc.RpcDesyncRepairSystem(systemtypes, 16);
if (Main.NormalOptions.MapId == 4) // Airship only
pc.RpcDesyncRepairSystem(systemtypes, 17);
}, 0.4f + delay, "Fix Desync Reactor");
}
*/
private static readonly HashSet<byte> BlackScreenWaitingPlayers = [];
public static void SetRole(this PlayerControl player, RoleTypes role, bool canOverride = true)
@@ -79,12 +53,12 @@ internal static class ExtendedPlayerControl
}
}
public static void RpcSetCustomRole(byte PlayerId, CustomRoles role)
public static void RpcSetCustomRole(byte playerId, CustomRoles role)
{
if (AmongUsClient.Instance.AmHost)
{
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetCustomRole, SendOption.Reliable);
writer.Write(PlayerId);
writer.Write(playerId);
writer.WritePacked((int)role);
AmongUsClient.Instance.FinishRpcImmediately(writer);
}
@@ -109,7 +83,7 @@ internal static class ExtendedPlayerControl
return (player.inVent && player.GetClosestVent()?.Id == ventId) || ((player.CanUseImpostorVentButton() || player.GetRoleTypes() == RoleTypes.Engineer) && Main.PlayerStates.Values.All(x => x.Role.CanUseVent(player, ventId)));
}
// Next 3: https://github.com/Rabek009/MoreGamemodes/blob/master/Modules/ExtendedPlayerControl.cs
// Next 2: https://github.com/Rabek009/MoreGamemodes/blob/master/Modules/ExtendedPlayerControl.cs
public static Vent GetClosestVent(this PlayerControl player)
{
Vector2 pos = player.Pos();
@@ -133,13 +107,6 @@ internal static class ExtendedPlayerControl
return vents;
}
/*
public static void RpcSetVentInteraction(this PlayerControl player)
{
var ventilationSystem = ShipStatus.Instance.Systems[SystemTypes.Ventilation].CastFast<VentilationSystem>();
if (ventilationSystem != null) VentilationSystemDeterioratePatch.SerializeV2(ventilationSystem, player);
}
*/
// From: https://github.com/Rabek009/MoreGamemodes/blob/master/Modules/ExtendedPlayerControl.cs - coded by Rabek009
public static void SetChatVisible(this PlayerControl player, bool visible)
{
@@ -189,12 +156,6 @@ internal static class ExtendedPlayerControl
writer.Recycle();
}
/*
public static void RpcExile(this PlayerControl player)
{
RPC.ExileAsync(player);
}
*/
public static ClientData GetClient(this PlayerControl player)
{
try { return AmongUsClient.Instance.allClients.ToArray().FirstOrDefault(cd => cd.Character.PlayerId == player.PlayerId); }
@@ -227,7 +188,7 @@ internal static class ExtendedPlayerControl
return CustomRoles.Crewmate;
}
return Main.PlayerStates.TryGetValue(player.PlayerId, out PlayerState State) ? State.MainRole : CustomRoles.Crewmate;
return Main.PlayerStates.TryGetValue(player.PlayerId, out PlayerState state) ? state.MainRole : CustomRoles.Crewmate;
}
public static List<CustomRoles> GetCustomSubRoles(this PlayerControl player)
@@ -262,53 +223,6 @@ internal static class ExtendedPlayerControl
return state.countTypes;
}
/*
public static void RpcSetNameEx(this PlayerControl player, string name)
{
try
{
if (player == null)
{
Logger.Warn("The player is null", "RpcSetNameEx");
return;
}
foreach (PlayerControl seer in Main.AllPlayerControls)
{
try { Main.LastNotifyNames[(player.PlayerId, seer.PlayerId)] = name; }
catch { }
}
if (player.Data != null) Logger.Info($"Set: {player.Data.PlayerName} => {name} for Everyone", "RpcSetNameEx");
player.RpcSetName(name);
}
catch (Exception e) { ThrowException(e); }
}
public static void RpcSetNamePrivate(this PlayerControl player, string name, PlayerControl seer = null, bool force = false)
{
if (player == null || name == null || !AmongUsClient.Instance.AmHost) return;
if (seer == null) seer = player;
if (!force && Main.LastNotifyNames[(player.PlayerId, seer.PlayerId)] == name) return;
Main.LastNotifyNames[(player.PlayerId, seer.PlayerId)] = name;
Logger.Info($"Set: {player.Data?.PlayerName} => {name} for {seer.GetNameWithRole().RemoveHtmlTags()}", "RpcSetNamePrivate");
if (seer == null || player == null) return;
int clientId = seer.GetClientId();
if (clientId == -1) return;
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(player.NetId, (byte)RpcCalls.SetName, SendOption.Reliable, clientId);
writer.Write(seer.Data.NetId);
writer.Write(name);
AmongUsClient.Instance.FinishRpcImmediately(writer);
}
*/
// By TommyXL
public static void RpcSetPetDesync(this PlayerControl player, string petId, PlayerControl seer)
{
@@ -671,10 +585,10 @@ internal static class ExtendedPlayerControl
_ => SystemTypes.Reactor
};
bool ReactorCheck = IsActive(systemtypes); // Checking whether the reactor sabotage is active
bool reactorCheck = IsActive(systemtypes); // Checking whether the reactor sabotage is active
float Duration = Options.KillFlashDuration.GetFloat();
if (ReactorCheck) Duration += 0.2f; // Extend blackout during reactor
float duration = Options.KillFlashDuration.GetFloat();
if (reactorCheck) duration += 0.2f; // Extend blackout during reactor
// Execution
Main.PlayerStates[player.PlayerId].IsBlackOut = true; // Blackout
@@ -689,7 +603,7 @@ internal static class ExtendedPlayerControl
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.KillFlash, SendOption.Reliable, player.GetClientId());
AmongUsClient.Instance.FinishRpcImmediately(writer);
}
else if (!ReactorCheck) player.ReactorFlash(); // Reactor flash
else if (!reactorCheck) player.ReactorFlash(); // Reactor flash
player.MarkDirtySettings();
@@ -697,7 +611,7 @@ internal static class ExtendedPlayerControl
{
Main.PlayerStates[player.PlayerId].IsBlackOut = false; // Cancel blackout
player.MarkDirtySettings();
}, Duration, "RemoveKillFlash");
}, duration, "RemoveKillFlash");
}
public static void RpcGuardAndKill(this PlayerControl killer, PlayerControl target = null, bool forObserver = false, bool fromSetKCD = false)
@@ -739,7 +653,7 @@ internal static class ExtendedPlayerControl
public static void AddKCDAsAbilityCD(this PlayerControl pc)
{
AddAbilityCD(pc, (int)Math.Round(Main.AllPlayerKillCooldown.TryGetValue(pc.PlayerId, out float KCD) ? KCD : Options.DefaultKillCooldown));
AddAbilityCD(pc, (int)Math.Round(Main.AllPlayerKillCooldown.TryGetValue(pc.PlayerId, out float kcd) ? kcd : Options.DefaultKillCooldown));
}
public static void AddAbilityCD(this PlayerControl pc, bool includeDuration = true)
@@ -747,10 +661,10 @@ internal static class ExtendedPlayerControl
Utils.AddAbilityCD(pc.GetCustomRole(), pc.PlayerId, includeDuration);
}
public static void AddAbilityCD(this PlayerControl pc, int CD)
public static void AddAbilityCD(this PlayerControl pc, int cd)
{
Main.AbilityCD[pc.PlayerId] = (TimeStamp, CD);
SendRPC(CustomRPC.SyncAbilityCD, 1, pc.PlayerId, CD);
Main.AbilityCD[pc.PlayerId] = (TimeStamp, cd);
SendRPC(CustomRPC.SyncAbilityCD, 1, pc.PlayerId, cd);
}
public static void RemoveAbilityCD(this PlayerControl pc)
@@ -861,7 +775,7 @@ internal static class ExtendedPlayerControl
if (!player.CanUseKillButton() && !AntiBlackout.SkipTasks) return;
player.AddKillTimerToDict(CD: time);
player.AddKillTimerToDict(cd: time);
if (target == null) target = player;
if (time >= 0f)
@@ -877,7 +791,7 @@ internal static class ExtendedPlayerControl
else if (forceAnime || !player.IsModdedClient() || !Options.DisableShieldAnimations.GetBool())
{
player.SyncSettings();
player.RpcGuardAndKill(target, fromSetKCD: true);
LateTask.New(() => player.RpcGuardAndKill(target, fromSetKCD: true), 0.1f, log: false);
}
else
{
@@ -895,25 +809,10 @@ internal static class ExtendedPlayerControl
Main.AllPlayerControls.Where(x => x.Is(CustomRoles.Observer) && target.PlayerId != x.PlayerId).Do(x => x.RpcGuardAndKill(target, true, true));
}
if (player.GetCustomRole() is not CustomRoles.Inhibitor and not CustomRoles.Saboteur) player.ResetKillCooldown();
if (player.GetCustomRole() is not CustomRoles.Inhibitor and not CustomRoles.Saboteur)
LateTask.New(() => player.ResetKillCooldown(), 0.3f, log: false);
}
/*
public static void RpcSpecificMurderPlayer(this PlayerControl killer, PlayerControl target = null)
{
if (target == null) target = killer;
if (killer.AmOwner)
killer.MurderPlayer(target, ResultFlags);
else
{
MessageWriter messageWriter = AmongUsClient.Instance.StartRpcImmediately(killer.NetId, (byte)RpcCalls.MurderPlayer, SendOption.Reliable, killer.GetClientId());
messageWriter.WriteNetObject(target);
messageWriter.Write((byte)ResultFlags);
AmongUsClient.Instance.FinishRpcImmediately(messageWriter);
}
}
*/
public static void RpcResetAbilityCooldown(this PlayerControl target)
{
if (!AmongUsClient.Instance.AmHost) return;
@@ -985,12 +884,12 @@ internal static class ExtendedPlayerControl
public static string GetSubRoleNames(this PlayerControl player, bool forUser = false)
{
List<CustomRoles> SubRoles = Main.PlayerStates[player.PlayerId].SubRoles;
if (SubRoles.Count == 0) return string.Empty;
List<CustomRoles> subRoles = Main.PlayerStates[player.PlayerId].SubRoles;
if (subRoles.Count == 0) return string.Empty;
StringBuilder sb = new();
foreach (CustomRoles role in SubRoles)
foreach (CustomRoles role in subRoles)
{
if (role == CustomRoles.NotAssigned) continue;
@@ -1049,6 +948,15 @@ internal static class ExtendedPlayerControl
yield break;
}
yield return new WaitForSeconds(1f);
if (!GameStates.InGame || GameStates.IsEnded)
{
Logger.Msg($"During the waiting, the game ended, so the black screen fix will not be executed for {pc.GetNameWithRole()}", "FixBlackScreen");
BlackScreenWaitingPlayers.Remove(pc.PlayerId);
yield break;
}
Logger.Msg($"Now that the conditions are met, fixing black screen for {pc.GetNameWithRole()}", "FixBlackScreen");
BlackScreenWaitingPlayers.Remove(pc.PlayerId);
pc.FixBlackScreen();
@@ -1336,18 +1244,18 @@ internal static class ExtendedPlayerControl
return new(pc.transform.position.x, pc.transform.position.y);
}
public static void AddKillTimerToDict(this PlayerControl pc, bool half = false, float CD = -1f)
public static void AddKillTimerToDict(this PlayerControl pc, bool half = false, float cd = -1f)
{
float resultKCD;
if (Math.Abs(CD - -1f) < 0.5f)
if (Math.Abs(cd - -1f) < 0.5f)
{
resultKCD = Main.AllPlayerKillCooldown.GetValueOrDefault(pc.PlayerId, 0f);
if (half) resultKCD /= 2f;
}
else
resultKCD = CD;
resultKCD = cd;
if (pc.GetCustomRole().UsesPetInsteadOfKill() && resultKCD > 0f)
pc.AddAbilityCD((int)Math.Round(resultKCD));
@@ -1754,29 +1662,29 @@ internal static class ExtendedPlayerControl
&& target.Data.IsDead;
}
public static string GetRoleInfo(this PlayerControl player, bool InfoLong = false)
public static string GetRoleInfo(this PlayerControl player, bool infoLong = false)
{
CustomRoles role = player.GetCustomRole();
if (role is CustomRoles.Crewmate or CustomRoles.Impostor) InfoLong = false;
if (role is CustomRoles.Crewmate or CustomRoles.Impostor) infoLong = false;
var text = role.ToString();
var Prefix = string.Empty;
var prefix = string.Empty;
if (!InfoLong)
if (!infoLong)
{
Prefix = role switch
prefix = role switch
{
CustomRoles.Mafia => CanMafiaKill() ? "After" : "Before",
_ => Prefix
_ => prefix
};
}
string Info = (role.IsVanilla() ? "Blurb" : "Info") + (InfoLong ? "Long" : string.Empty);
return GetString($"{Prefix}{text}{Info}");
string info = (role.IsVanilla() ? "Blurb" : "Info") + (infoLong ? "Long" : string.Empty);
return GetString($"{prefix}{text}{info}");
}
public static void SetRealKiller(this PlayerControl target, PlayerControl killer, bool NotOverRide = false)
public static void SetRealKiller(this PlayerControl target, PlayerControl killer, bool notOverRide = false)
{
if (target == null)
{
@@ -1784,8 +1692,8 @@ internal static class ExtendedPlayerControl
return;
}
PlayerState State = Main.PlayerStates[target.PlayerId];
if (State.RealKiller.TimeStamp != DateTime.MinValue && NotOverRide) return; // Do not overwrite if value already exists
PlayerState state = Main.PlayerStates[target.PlayerId];
if (state.RealKiller.TimeStamp != DateTime.MinValue && notOverRide) return; // Do not overwrite if value already exists
byte killerId = killer == null ? byte.MaxValue : killer.PlayerId;
RPC.SetRealKiller(target.PlayerId, killerId);
@@ -1801,8 +1709,8 @@ internal static class ExtendedPlayerControl
{
if (!pc.IsAlive() || Pelican.IsEaten(pc.PlayerId)) return null;
Il2CppReferenceArray<PlainShipRoom> Rooms = ShipStatus.Instance.AllRooms;
return Rooms.Where(room => room.roomArea).FirstOrDefault(room => pc.Collider.IsTouching(room.roomArea));
Il2CppReferenceArray<PlainShipRoom> rooms = ShipStatus.Instance.AllRooms;
return rooms.Where(room => room.roomArea).FirstOrDefault(room => pc.Collider.IsTouching(room.roomArea));
}
public static bool IsImpostor(this PlayerControl pc)
+27
View File
@@ -198,6 +198,7 @@ internal static class ChatCommands
new(["deletetag", "удалитьтег", "删除标签"], "{id}", GetString("CommandDescription.DeleteTag"), Command.UsageLevels.Host, Command.UsageTimes.InLobby, DeleteTagCommand, true, false, [GetString("CommandArgs.DeleteTag.Id")]),
new(["daybreak", "db", "дейбрейк", "破晓"], "", GetString("CommandDescription.DayBreak"), Command.UsageLevels.Everyone, Command.UsageTimes.InMeeting, DayBreakCommand, true, true),
new(["fix", "blackscreenfix", "fixblackscreen", "ф", "исправить", "修复"], "{id}", GetString("CommandDescription.Fix"), Command.UsageLevels.HostOrModerator, Command.UsageTimes.InGame, FixCommand, true, false, [GetString("CommandArgs.Fix.Id")]),
new(["xor", "异或命令"], "{role} {role}", GetString("CommandDescription.XOR"), Command.UsageLevels.Host, Command.UsageTimes.InLobby, XORCommand, true, false, [GetString("CommandArgs.XOR.Role"), GetString("CommandArgs.XOR.Role")]),
// Commands with action handled elsewhere
new(["shoot", "guess", "bet", "bt", "st", "угадать", "бт", "猜测", "赌", "adivinhar"], "{id} {role}", GetString("CommandDescription.Guess"), Command.UsageLevels.Everyone, Command.UsageTimes.InMeeting, (_, _, _) => { }, true, false, [GetString("CommandArgs.Guess.Id"), GetString("CommandArgs.Guess.Role")]),
@@ -382,6 +383,32 @@ internal static class ChatCommands
// ---------------------------------------------------------------------------------------------------------------------------------------------
private static void XORCommand(PlayerControl player, string text, string[] args)
{
if (args.Length < 3 || !GetRoleByName(args[1], out CustomRoles role1) || !GetRoleByName(args[2], out CustomRoles role2)) return;
if (Main.XORRoles.Remove((role1, role2)) || Main.XORRoles.Remove((role2, role1)))
{
Utils.SendMessage("\n", player.PlayerId, string.Format(GetString("XORRemoved"), role1.ToColoredString(), role2.ToColoredString()));
return;
}
if (role1 == role2)
{
Utils.SendMessage("\n", player.PlayerId, GetString("XORSameRole"));
return;
}
if (role1.IsAdditionRole() || role2.IsAdditionRole())
{
Utils.SendMessage("\n", player.PlayerId, GetString("XORAdditionRole"));
return;
}
Main.XORRoles.Add((role1, role2));
Utils.SendMessage("\n", player.PlayerId, string.Format(GetString("XORAdded"), role1.ToColoredString(), role2.ToColoredString()));
}
private static void FixCommand(PlayerControl player, string text, string[] args)
{
if (!AmongUsClient.Instance.AmHost)
+3
View File
@@ -97,6 +97,9 @@ internal static class ControllerManagerUpdatePatch
GameEndChecker.Prefix();
}
if (KeysDown(KeyCode.Return, KeyCode.C, KeyCode.LeftShift, KeyCode.LeftControl) && GameStates.IsInGame)
Utils.SetChatVisibleForAll();
if (KeysDown(KeyCode.Return, KeyCode.M, KeyCode.LeftShift) && GameStates.IsInGame)
{
if (GameStates.IsMeeting)
+7
View File
@@ -835,6 +835,13 @@ internal static class TaskPanelBehaviourPatch
finalText += "</size>";
break;
case CustomGameMode.Quiz when AmongUsClient.Instance.AmHost:
finalText += "\r\n\r\n\r\n<size=70%>";
finalText += Quiz.GetTaskBarText();
finalText += "</size>";
break;
}
__instance.taskText.text = finalText;
+1
View File
@@ -893,6 +893,7 @@ internal static class IntroCutsceneDestroyPatch
switch (Options.CurrentGameMode)
{
case CustomGameMode.FFA when FreeForAll.FFAChatDuringGame.GetBool():
case CustomGameMode.Quiz when Quiz.Chat:
Utils.SetChatVisibleForAll();
break;
}
+2 -2
View File
@@ -217,7 +217,7 @@ internal static class TextBoxTMPSetTextPatch
{
"{id}" or "{id1}" or "{id2}" => byte.TryParse(arg, out byte id) && Main.AllPlayerControls.Any(x => x.PlayerId == id),
"{team}" => arg is "crew" or "imp",
"{role}" => ChatCommands.GetRoleByName(arg, out _),
"{role}" or "[role]" => ChatCommands.GetRoleByName(arg, out _),
"{addon}" => ChatCommands.GetRoleByName(arg, out CustomRoles role) && role.IsAdditionRole(),
"{chance}" => int.TryParse(arg, out int chance) && chance is >= 0 and <= 100 && chance % 5 == 0,
"{color}" => arg.Length == 6 && arg.All(x => char.IsDigit(x) || x is >= 'a' and <= 'f') && ColorUtility.TryParseHtmlString($"#{arg}", out _),
@@ -230,7 +230,7 @@ internal static class TextBoxTMPSetTextPatch
: argName switch
{
"{id}" or "{id1}" or "{id2}" => $" ({byte.Parse(arg).ColoredPlayerName()})",
"{role}" or "{addon}" when ChatCommands.GetRoleByName(arg, out CustomRoles role) => $" ({role.ToColoredString()})",
"{role}" or "{addon}" or "[role]" when ChatCommands.GetRoleByName(arg, out CustomRoles role) => $" ({role.ToColoredString()})",
"{color}" when ColorUtility.TryParseHtmlString($"#{arg}", out Color color) => $" ({Utils.ColorString(color, "COLOR")})",
_ => string.Empty
};
+9
View File
@@ -2431,6 +2431,7 @@
"CommandDescription.DayBreak": "Call daybreak for the current meeting as the Starspawn.",
"CommandDescription.DraftDescription": "View the description of one of the roles you got in the draft.",
"CommandDescription.Fix": "Fixes the black screen bug for a specific player.",
"CommandDescription.XOR": "Specify 2 roles that will never spawn in the same game.",
"CommandArgs.ChangeSetting.Name": "The setting's name to change (leave blank to view all settings)",
"CommandArgs.ChangeSetting.UnknownValue": "(leave blank to view what to put here)",
"CommandArgs.Rename.Name": "Your new name",
@@ -2508,6 +2509,7 @@
"CommandArgs.DeleteTag.Id": "The player's ID to delete the tag from",
"CommandArgs.DraftDescription.Index": "The number in the drafting message of the role to view the description of",
"CommandArgs.Fix.Id": "The player's ID to fix the black screen bug for",
"CommandArgs.XOR.Role": "A main role that will never spawn in the same game with the other role",
"Commands.ChangeSettingHelp": "<b><u>Arguments:</u></b><size=70%>\\n- map (theskeld/mirahq/polus/dlekseht/airship/thefungle/custom)\\n- impostors (number)\\n- players (number)\\n- recommended (on/off)\\n- confirmejects (on/off)\\n- emergencymeetings (number)\\n- anonymousvotes (on/off)\\n- emergencycooldown (number)\\n- discussiontime (number)\\n- votingtime (number)\\n- playerspeed (float)\\n- crewmatevision (float)\\n- impostorvision (float)\\n- killcooldown (float)\\n- killdistance (short/medium/long/custom)\\n- taskbarupdates (always/meetings/never)\\n- visualtasks (on/off)\\n- commontasks (number)\\n- longtasks (number)\\n- shorttasks (number)\\n- scientistcount (number)\\n- scientistchance (number)\\n- vitalsdisplaycooldown (float)\\n- batteryduration (float)\\n- engineercount (number)\\n- engineerchance (number)\\n- ventusecooldown (float)\\n- maxtimeinvents (float)\\n- guardianangelcount (number)\\n- guardianangelchance (number)\\n- protectcooldown (float)\\n- protectduration (float)\\n- protectvisibletoimpostors (on/off)\\n- shapeshiftercount (number)\\n- shapeshifterchance (number)\\n- shapeshiftduration (float)\\n- shapeshiftcooldown (float)\\n- leaveshapeshiftevidence (on/off)\\n- phantomcount (number)\\n- phantomchance (number)\\n- inviscooldown (float)\\n- invisduration (float)\\n- noisemakercount (number)\\n- noisemakerchance (number)\\n- noisemakerimpostoralert (on/off)\\n- noisemakeralertduration (number)\\n- trackercount (number)\\n- trackerchance (number)\\n- trackduration (float)\\n- trackcooldown (float)\\n- trackdelay (float)\\n- ghostdotasks (on/off)\\n\\n<u><b>Notes:</b></u>\\n1. Upper and lowercase matters\\n2. Where it says custom, you obviously put a number argument after it\\n3. A float is a single precision floating number, like 1.7\\n4. \"ghostdotasks\" causes issues if you set it\\n5. Example uses:\\n - \"/cs map polus\"\\n - \"/cs killdistance custom 4\"\\n - \"/cs trackdelay 1,7\"\\n - \"/cs confirmejects on\"",
"AddTagSuccess": "<#00ffa5>✓</color> Suceessfully created the tag {0} for {1}. If you want to change it, just use this command again and it will override the current tag. To delete it, simply type <#00a5ff>/deletetag {2}</color>!",
"DeleteTagSuccess": "<#00ffa5>✓</color> Successfully deleted {0}'s tag.",
@@ -2562,6 +2564,10 @@
"Anagram.CorrectGuess": "<#00ffa5>✓</color> {0} has guessed the anagram correctly (<b>{1}</b>)!",
"Anagram": "The scrambled word is <b>{0}</b>! Guess the original word! (Hint: It starts with the letter <b>{1}</b>!)",
"AnagramTitle": "<#888888>➡ ANAGRAM ⬅</color>",
"XORRemoved": "<#00ffa5>✓</color> XOR combination removed successfully.",
"XORSameRole": "<#ff0000>X</color> XOR combinations must have 2 different roles.",
"XORAdditionRole": "<#ff0000>X</color> XOR combinations don't support add-ons. Use <#ffff00>/combo</color> for that.",
"XORAdded": "<#00ffa5>✓</color> XOR combination added successfully.",
"ThankYouForUsingEHR": "Thank you for using EHR!",
"GMRoles": "<color=#ff5b70>【 ★ Roles ★ 】</color>",
"ImpostorRoles": "【 ★ Impostor Roles ★ 】",
@@ -4934,6 +4940,7 @@
"Quiz.Settings.QuestionsAsked.Hard": "Number of Questions Asked in Each Hard Round",
"Quiz.Settings.CorrectRequirement.Hard": "Number of Correct Answers Required in Each Hard Round to Survive",
"Quiz.Settings.TimeLimit.Hard": "Time Limit to Answer Each Question in Hard Rounds",
"Quiz.Settings.ChatDuringGame": "Allow Chat During Game",
"Quiz.Tutorial.Basics": "The current game mode is <#CF2472>Quiz</color>.\\n<size=90%>You'll get questions, each with 5 choices: A, B, C, D, E.\\nYou must answer the questions correctly within the time limit\\nby entering the room corresponding to the correct answer.\\nThe rooms on this map are:\\n{0}</size>",
"Quiz.Tutorial.TestRound": "<size=90%>We'll play a test round to show you how it works.</size>",
"Quiz.Tutorial.OnWrongAnswer": "<size=90%>If you answer <#ff0000>incorrectly</color>, you will most likely die.</size>",
@@ -4944,6 +4951,7 @@
"Quiz.Notify.AllCorrect": "<#00ffa5>Everyone found enough correct answers!</color>",
"Quiz.Notify.AllDie": "<#ffff00><u>Everyone</u> would die, so no one will die!\\nInstead, we'll redo this round.</color>",
"Quiz.Notify.AllWrong": "<#ffff00><u>Everyone</u> got this question wrong, so this won't\\ncount as an incorrect answer for anyone.\\nInstead, we'll redo this question.</color>",
"Quiz.Notify.AllWrongShort": "<#ffff00><u>Everyone</u> was wrong, doesn't count, redo.</color>",
"Quiz.Notify.OnlyYouWrong": "<#ff0000>Only you failed this round. You will die now.</color>",
"Quiz.Notify.OneWrong": "<#00a5ff>1 player failed this round. They will simply die.</color>",
"Quiz.Notify.IncorrectFFA": "<#ff4444>Luckily, you're not alone to failed this round!\\nYou will participate in a Free For All (FFA) event against the others who failed.\\nKill everyone else and be the last one alive to get a second chance!\\nBe sure to do this within the time limit, or all of you will die!</color>",
@@ -4951,6 +4959,7 @@
"Quiz.Notify.FFAOngoing": "<size=80%><#ffff00><u>Kill everyone</u> and survive</color>\\nHint: Someone is in {0}\\n<#ffa500>{1}</color></size>",
"Quiz.Notify.FFASpectating": "<size=80%><#00ffff>Spectate the chaos!</color>\\n<#00a5ff>{1}</color></size>",
"Quiz.Notify.CorrectAnswerNum": "<size=80%>You got {0}/{1} questions correct! The required amount was {2}.</size>",
"Quiz.TaskBarText": "---- GAME DATA ----\\n\\nDifficulty: {0}\\nRound: {1}\\nQuestion: {2}\\n\\nNumber of correct answers\\nfrom everyone so far:\\n\\n{3}",
"Quiz.EndResults.CorrectAnswerNum": "Correct Answers: ",
"Quiz.Questions.Test.0": "Which map are we on?",
"Quiz.Questions.Test.0.Answer.A": "The Skeld / dlekS ehT",
+34 -4
View File
@@ -103,20 +103,50 @@ public class PotionMaster : Coven
long now = Utils.TimeStamp;
List<byte> toRemove = ShieldedPlayers.Where(x => now >= x.Value).Select(x => x.Key).ToList();
var sender = CustomRpcSender.Create("PotionMaster.OnFixedUpdate", SendOption.Reliable);
var hasValue = false;
toRemove.ForEach(x =>
{
ShieldedPlayers.Remove(x);
PlayerControl player = x.GetPlayer();
Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: player);
Utils.NotifyRoles(SpecifySeer: player, SpecifyTarget: player);
sender.NotifyRolesSpecific(pc, player);
sender = RestartMessageIfTooLong();
sender.NotifyRolesSpecific(player, player);
hasValue = true;
sender = RestartMessageIfTooLong();
Utils.SendRPC(CustomRPC.SyncRoleData, PotionMasterId, 2, x);
});
foreach (byte shieldedId in ShieldedPlayers.Keys)
{
PlayerControl player = shieldedId.GetPlayer();
Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: player);
Utils.NotifyRoles(SpecifySeer: player, SpecifyTarget: player);
sender.NotifyRolesSpecific(pc, player);
hasValue = true;
sender = RestartMessageIfTooLong();
sender.NotifyRolesSpecific(player, player);
hasValue = true;
sender = RestartMessageIfTooLong();
}
sender.SendMessage(dispose: !hasValue);
return;
CustomRpcSender RestartMessageIfTooLong()
{
if (sender.stream.Length > 800)
{
sender.SendMessage();
sender = CustomRpcSender.Create("PotionMaster.OnFixedUpdate", SendOption.Reliable);
hasValue = false;
}
return sender;
}
}
+5
View File
@@ -318,4 +318,9 @@ public class SabotageMaster : RoleBase
sm.UsedSkillCount += UsesUsedWhenFixingLightsOrComms.GetFloat();
sm.SendRPC();
}
public override bool CanUseVent(PlayerControl pc, int ventId)
{
return !IsThisRole(pc) || pc.Is(CustomRoles.Nimble) || CanVent.GetBool();
}
}