mirror of
https://github.com/Gurge44/EndlessHostRoles.git
synced 2026-10-19 15:51:58 +00:00
889 lines
39 KiB
C#
889 lines
39 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using AmongUs.GameOptions;
|
|
using EHR.Gamemodes;
|
|
using EHR.Roles;
|
|
using Hazel;
|
|
using InnerNet;
|
|
using Mathf = UnityEngine.Mathf;
|
|
|
|
// ReSharper disable ForCanBeConvertedToForeach
|
|
|
|
namespace EHR.Modules;
|
|
|
|
public sealed class PlayerGameOptionsSender(PlayerControl player) : GameOptionsSender
|
|
{
|
|
public PlayerControl player = player;
|
|
|
|
private static IGameOptions BasedGameOptions =>
|
|
#if IL2CPP
|
|
Main.RealOptionsData.Restore(new NormalGameOptionsV11(new UnityLogger().CastFast<ILogger>()).CastFast<IGameOptions>());
|
|
#else
|
|
Main.RealOptionsData.Restore(new NormalGameOptionsV11(new UnityLogger()));
|
|
#endif
|
|
|
|
protected override bool IsDirty { get; set; }
|
|
|
|
public static void SetDirty(byte playerId)
|
|
{
|
|
for (var index = 0; index < AllSenders.Count; index++)
|
|
{
|
|
GameOptionsSender allSender = AllSenders[index];
|
|
|
|
if (allSender is PlayerGameOptionsSender sender && sender.player.PlayerId == playerId)
|
|
{
|
|
sender.SetDirty();
|
|
break; // Only one sender can have the same player id
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void ForceSendImmediately(byte playerId)
|
|
{
|
|
for (var index = 0; index < AllSenders.Count; index++)
|
|
{
|
|
GameOptionsSender allSender = AllSenders[index];
|
|
|
|
if (allSender is PlayerGameOptionsSender sender && sender.player.PlayerId == playerId)
|
|
{
|
|
ForceWaitFrame = true;
|
|
sender.SendGameOptions();
|
|
sender.IsDirty = false;
|
|
break; // Only one sender can have the same player id
|
|
}
|
|
}
|
|
}
|
|
|
|
public static DataFlagRateLimiter.QueuedAction SendAllImmediately()
|
|
{
|
|
if (AntiBlackout.SkipTasks && !AntiBlackout.AllowSyncSettings) return null;
|
|
|
|
ForceWaitFrame = true;
|
|
|
|
if (PackedWriterMessages > 0 && PackedWriter != null)
|
|
{
|
|
PackedWriter.EndMessage();
|
|
var capturedWriter = PackedWriter;
|
|
DataFlagRateLimiter.Enqueue(() =>
|
|
{
|
|
AmongUsClient.Instance.SendOrDisconnect(capturedWriter);
|
|
capturedWriter.Recycle();
|
|
}, cleanup: capturedWriter.Recycle);
|
|
}
|
|
|
|
PackedWriter = MessageWriter.Get(SendOption.Reliable);
|
|
PackedWriter.StartMessage(26);
|
|
PackedWriter.WritePacked(AmongUsClient.Instance.GameId);
|
|
PackedWriterMessages = 0;
|
|
|
|
for (var index = 0; index < AllSenders.Count; index++)
|
|
{
|
|
GameOptionsSender allSender = AllSenders[index];
|
|
|
|
if (allSender is PlayerGameOptionsSender { IsDirty: true } sender)
|
|
{
|
|
sender.SendGameOptions();
|
|
sender.IsDirty = false;
|
|
}
|
|
}
|
|
|
|
DataFlagRateLimiter.QueuedAction qa = null;
|
|
|
|
if (PackedWriter != null)
|
|
{
|
|
if (PackedWriterMessages > 0)
|
|
{
|
|
PackedWriter.EndMessage();
|
|
Logger.Info($"PackedWriter flush queued - Length: {PackedWriter.Length}, Messages: {PackedWriterMessages}", "SendAllImmediately");
|
|
var capturedWriter = PackedWriter;
|
|
qa = DataFlagRateLimiter.Enqueue(() =>
|
|
{
|
|
AmongUsClient.Instance.SendOrDisconnect(capturedWriter);
|
|
capturedWriter.Recycle();
|
|
Logger.Info("PackedWriter flush queue finished and sent", "SendAllImmediately");
|
|
}, cleanup: capturedWriter.Recycle);
|
|
}
|
|
else
|
|
{
|
|
PackedWriter.Recycle();
|
|
}
|
|
}
|
|
|
|
PackedWriter = null;
|
|
PackedWriterMessages = 0;
|
|
|
|
return qa;
|
|
}
|
|
|
|
public static void SetDirtyToAll()
|
|
{
|
|
for (var index = 0; index < AllSenders.Count; index++)
|
|
{
|
|
GameOptionsSender allSender = AllSenders[index];
|
|
|
|
if (allSender is PlayerGameOptionsSender sender)
|
|
sender.SetDirty();
|
|
}
|
|
}
|
|
|
|
// For lights call/fix
|
|
public static void SetDirtyToAllV2()
|
|
{
|
|
for (var index = 0; index < AllSenders.Count; index++)
|
|
{
|
|
GameOptionsSender allSender = AllSenders[index];
|
|
|
|
if (allSender is PlayerGameOptionsSender { IsDirty: false } sender && sender.player.IsAlive() && (sender.player.HasDesyncRole() || sender.player.GetCustomRole() is CustomRoles.Transporter or CustomRoles.Lighter or CustomRoles.Doomsayer || sender.player.Is(CustomRoles.Torch) || sender.player.Is(CustomRoles.Mare) || sender.player.Is(CustomRoles.Sleep) || Beacon.IsAffectedPlayer(sender.player.PlayerId)))
|
|
sender.SetDirty();
|
|
}
|
|
}
|
|
|
|
// For Grenadier blidning/restoring
|
|
public static void SetDirtyToAllV3()
|
|
{
|
|
for (var index = 0; index < AllSenders.Count; index++)
|
|
{
|
|
GameOptionsSender allSender = AllSenders[index];
|
|
|
|
if (allSender is PlayerGameOptionsSender { IsDirty: false } sender && sender.player.IsAlive() && (Grenadier.GrenadierBlinding.Count > 0 && (sender.player.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()
|
|
{
|
|
for (var index = 0; index < AllSenders.Count; index++)
|
|
{
|
|
GameOptionsSender allSender = AllSenders[index];
|
|
|
|
if (allSender is PlayerGameOptionsSender { IsDirty: false } sender && sender.player.IsAlive() && sender.player.CanUseKillButton())
|
|
sender.SetDirty();
|
|
}
|
|
}
|
|
|
|
private void SetDirty()
|
|
{
|
|
IsDirty = true;
|
|
}
|
|
|
|
protected override void SendGameOptions()
|
|
{
|
|
if (player.AmOwner)
|
|
{
|
|
IGameOptions opt = BuildGameOptions();
|
|
|
|
if (GameManager.Instance?.LogicComponents != null)
|
|
{
|
|
foreach (GameLogicComponent com in GameManager.Instance.LogicComponents)
|
|
{
|
|
if (com is LogicOptions lo)
|
|
lo.SetGameOptions(opt);
|
|
}
|
|
}
|
|
|
|
GameOptionsManager.Instance.CurrentGameOptions = opt;
|
|
}
|
|
else
|
|
base.SendGameOptions();
|
|
}
|
|
|
|
protected override IEnumerator SendGameOptionsAsync()
|
|
{
|
|
if (player.AmOwner)
|
|
{
|
|
IGameOptions opt = BuildGameOptions();
|
|
|
|
if (GameManager.Instance?.LogicComponents != null)
|
|
{
|
|
foreach (GameLogicComponent com in GameManager.Instance.LogicComponents)
|
|
{
|
|
if (com is LogicOptions lo)
|
|
lo.SetGameOptions(opt);
|
|
|
|
yield return WaitFrameIfNecessary();
|
|
}
|
|
}
|
|
|
|
GameOptionsManager.Instance.CurrentGameOptions = opt;
|
|
}
|
|
else
|
|
yield return base.SendGameOptionsAsync();
|
|
}
|
|
|
|
protected override IEnumerator SendOptionsArrayAsync(byte[] optionArray, byte logicOptionsIndex)
|
|
{
|
|
if (PackedWriter == null) yield break;
|
|
|
|
if (PackedWriter.Length > 1000 || PackedWriterMessages >= AmongUsClient.Instance.GetMaxMessagePackingLimit())
|
|
{
|
|
PackedWriter.EndMessage();
|
|
var qa = DataFlagRateLimiter.Enqueue(() => AmongUsClient.Instance.SendOrDisconnect(PackedWriter));
|
|
yield return qa.Wait();
|
|
Logger.Info($"PackedWriter flush finished - Length: {PackedWriter.Length}, Messages: {PackedWriterMessages}", "SendOptionsArrayAsync");
|
|
PackedWriterMessages = 0;
|
|
|
|
if (qa.Dropped)
|
|
{
|
|
PackedWriter.Recycle();
|
|
PackedWriter = null;
|
|
Main.Instance.StopCoroutine(ActiveCoroutine);
|
|
ActiveCoroutine = null;
|
|
yield return null;
|
|
yield break;
|
|
}
|
|
|
|
PackedWriter.Clear(SendOption.Reliable);
|
|
PackedWriter.StartMessage(26);
|
|
PackedWriter.WritePacked(AmongUsClient.Instance.GameId);
|
|
}
|
|
|
|
yield return WaitFrameIfNecessary();
|
|
|
|
PackedWriterMessages++;
|
|
|
|
PackedWriter.StartMessage(6);
|
|
{
|
|
PackedWriter.Write(AmongUsClient.Instance.GameId);
|
|
PackedWriter.WritePacked(player.OwnerId);
|
|
|
|
PackedWriter.StartMessage(1);
|
|
{
|
|
PackedWriter.WritePacked(GameManager.Instance.NetId);
|
|
PackedWriter.StartMessage(logicOptionsIndex);
|
|
{
|
|
PackedWriter.WriteBytesAndSize(optionArray);
|
|
}
|
|
PackedWriter.EndMessage();
|
|
}
|
|
PackedWriter.EndMessage();
|
|
}
|
|
PackedWriter.EndMessage();
|
|
|
|
Logger.Info($"PackedWriter message write complete - Length: {PackedWriter.Length}, Messages: {PackedWriterMessages}", "SendOptionsArrayAsync");
|
|
}
|
|
|
|
protected override void SendOptionsArray(byte[] optionArray, byte logicOptionsIndex)
|
|
{
|
|
if (AntiBlackout.SkipTasks && !AntiBlackout.AllowSyncSettings) return;
|
|
|
|
if (PackedWriter == null) // Single write
|
|
{
|
|
Logger.Info("Enqueue complete for single write", "SendOptionsArray");
|
|
DataFlagRateLimiter.Enqueue(() =>
|
|
{
|
|
MessageWriter writer = MessageWriter.Get(SendOption.Reliable);
|
|
|
|
writer.StartMessage(6);
|
|
{
|
|
writer.Write(AmongUsClient.Instance.GameId);
|
|
writer.WritePacked(player.OwnerId);
|
|
|
|
writer.StartMessage(1);
|
|
{
|
|
writer.WritePacked(GameManager.Instance.NetId);
|
|
writer.StartMessage(logicOptionsIndex);
|
|
{
|
|
writer.WriteBytesAndSize(optionArray);
|
|
}
|
|
writer.EndMessage();
|
|
}
|
|
writer.EndMessage();
|
|
}
|
|
|
|
writer.EndMessage();
|
|
|
|
AmongUsClient.Instance.SendOrDisconnect(writer);
|
|
writer.Recycle();
|
|
Logger.Info("Queue finished and sent for single write", "SendOptionsArray");
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (PackedWriter.Length > 1000 || PackedWriterMessages >= AmongUsClient.Instance.GetMaxMessagePackingLimit())
|
|
{
|
|
PackedWriter.EndMessage();
|
|
Logger.Info($"PackedWriter flush queued - Length: {PackedWriter.Length}, Messages: {PackedWriterMessages}", "SendOptionsArray");
|
|
var capturedWriter = PackedWriter;
|
|
DataFlagRateLimiter.Enqueue(() =>
|
|
{
|
|
AmongUsClient.Instance.SendOrDisconnect(capturedWriter);
|
|
capturedWriter.Recycle();
|
|
Logger.Info("PackedWriter flush queue finished and sent", "SendOptionsArray");
|
|
}, cleanup: capturedWriter.Recycle);
|
|
PackedWriterMessages = 0;
|
|
PackedWriter = MessageWriter.Get(SendOption.Reliable);
|
|
PackedWriter.StartMessage(26);
|
|
PackedWriter.WritePacked(AmongUsClient.Instance.GameId);
|
|
}
|
|
|
|
PackedWriterMessages++;
|
|
|
|
PackedWriter.StartMessage(6);
|
|
{
|
|
PackedWriter.Write(AmongUsClient.Instance.GameId);
|
|
PackedWriter.WritePacked(player.OwnerId);
|
|
|
|
PackedWriter.StartMessage(1);
|
|
{
|
|
PackedWriter.WritePacked(GameManager.Instance.NetId);
|
|
PackedWriter.StartMessage(logicOptionsIndex);
|
|
{
|
|
PackedWriter.WriteBytesAndSize(optionArray);
|
|
}
|
|
PackedWriter.EndMessage();
|
|
}
|
|
PackedWriter.EndMessage();
|
|
}
|
|
PackedWriter.EndMessage();
|
|
|
|
Logger.Info($"PackedWriter message write complete - Length: {PackedWriter.Length}, Messages: {PackedWriterMessages}", "SendOptionsArray");
|
|
}
|
|
|
|
public static void RemoveSender(PlayerControl player)
|
|
{
|
|
PlayerGameOptionsSender sender = AllSenders.OfType<PlayerGameOptionsSender>()
|
|
.FirstOrDefault(sender => sender.player.PlayerId == player.PlayerId);
|
|
|
|
if (sender == null) return;
|
|
|
|
sender.player = null;
|
|
AllSenders.Remove(sender);
|
|
}
|
|
|
|
public override IGameOptions BuildGameOptions()
|
|
{
|
|
try
|
|
{
|
|
Main.RealOptionsData ??= new(GameOptionsManager.Instance.CurrentGameOptions);
|
|
|
|
IGameOptions opt = BasedGameOptions;
|
|
AURoleOptions.SetOpt(opt);
|
|
PlayerState state = Main.PlayerStates[player.PlayerId];
|
|
opt.BlackOut(state.IsBlackOut);
|
|
|
|
CustomRoles role = player.GetCustomRole();
|
|
RoleTypes roleTypes = player.GetRoleTypes();
|
|
|
|
if (player.inVent && Options.OverrideVisionInVents.GetBool() && Options.InVentVision.TryGetValue(player.GetTeam(), out var option))
|
|
{
|
|
var value = option.GetFloat();
|
|
opt.SetFloat(FloatOptionNames.CrewLightMod, value);
|
|
opt.SetFloat(FloatOptionNames.ImpostorLightMod, value);
|
|
}
|
|
|
|
switch (Options.CurrentGameMode)
|
|
{
|
|
case CustomGameMode.FFA:
|
|
{
|
|
if (FreeForAll.FFALowerVisionList.ContainsKey(player.PlayerId))
|
|
{
|
|
opt.SetVision(true);
|
|
opt.SetFloat(FloatOptionNames.CrewLightMod, FreeForAll.FFALowerVision.GetFloat());
|
|
opt.SetFloat(FloatOptionNames.ImpostorLightMod, FreeForAll.FFALowerVision.GetFloat());
|
|
}
|
|
else SetMaxVision();
|
|
|
|
break;
|
|
}
|
|
case CustomGameMode.CaptureTheFlag:
|
|
{
|
|
CaptureTheFlag.ApplyGameOptions();
|
|
goto case CustomGameMode.RoomRush;
|
|
}
|
|
case CustomGameMode.Snowdown:
|
|
{
|
|
Snowdown.ApplyGameOptions();
|
|
goto case CustomGameMode.RoomRush;
|
|
}
|
|
case CustomGameMode.DoomTag:
|
|
{
|
|
DoomTag.ApplyGameOptions(opt, player.PlayerId);
|
|
break;
|
|
}
|
|
case CustomGameMode.NaturalDisasters:
|
|
{
|
|
SetMaxVision();
|
|
NaturalDisasters.ApplyGameOptions(opt, player.PlayerId);
|
|
break;
|
|
}
|
|
case CustomGameMode.RoomRush when RoomRush.VentLimit.TryGetValue(player.PlayerId, out int vl) && vl > 0:
|
|
{
|
|
AURoleOptions.EngineerCooldown = 0.01f;
|
|
AURoleOptions.EngineerInVentMaxTime = 0f;
|
|
goto case CustomGameMode.RoomRush;
|
|
}
|
|
case CustomGameMode.Mingle:
|
|
case CustomGameMode.RoomRush:
|
|
case CustomGameMode.Speedrun:
|
|
case CustomGameMode.HotPotato:
|
|
{
|
|
SetMaxVision();
|
|
break;
|
|
}
|
|
case CustomGameMode.Deathrace:
|
|
case CustomGameMode.BedWars:
|
|
{
|
|
AURoleOptions.PhantomCooldown = 0.1f;
|
|
goto case CustomGameMode.RoomRush;
|
|
}
|
|
case CustomGameMode.Quiz:
|
|
{
|
|
try
|
|
{
|
|
AURoleOptions.GuardianAngelCooldown = 900f;
|
|
AURoleOptions.ProtectionDurationSeconds = 0.01f;
|
|
}
|
|
catch (Exception e) { Utils.ThrowException(e); }
|
|
|
|
goto case CustomGameMode.RoomRush;
|
|
}
|
|
case CustomGameMode.StopAndGo:
|
|
{
|
|
try
|
|
{
|
|
AURoleOptions.EngineerCooldown = 1f;
|
|
AURoleOptions.EngineerInVentMaxTime = 300f;
|
|
}
|
|
catch (Exception e) { Utils.ThrowException(e); }
|
|
|
|
goto case CustomGameMode.RoomRush;
|
|
}
|
|
case CustomGameMode.HideAndSeek:
|
|
{
|
|
CustomHnS.ApplyGameOptions(opt, player);
|
|
break;
|
|
}
|
|
case CustomGameMode.TheMindGame:
|
|
{
|
|
try { AURoleOptions.PhantomCooldown = 0.1f; }
|
|
catch (Exception e) { Utils.ThrowException(e); }
|
|
|
|
goto case CustomGameMode.RoomRush;
|
|
}
|
|
case CustomGameMode.KingOfTheZones:
|
|
case CustomGameMode.SoloPVP:
|
|
{
|
|
try { AURoleOptions.GuardianAngelCooldown = 900f; }
|
|
catch (Exception e) { Utils.ThrowException(e); }
|
|
|
|
goto case CustomGameMode.RoomRush;
|
|
}
|
|
case CustomGameMode.Standard:
|
|
{
|
|
President.OnAnyoneApplyGameOptions(opt);
|
|
|
|
AURoleOptions.ViperDissolveTime = ImpostorVanillaRoles.ViperDissolveTime.GetFloat(); // can't be desynced
|
|
|
|
float playerSpeed = Main.AllPlayerSpeed.GetValueOrDefault(player.PlayerId);
|
|
bool frozen = Mathf.Approximately(playerSpeed, Main.MinSpeed);
|
|
bool inverted = playerSpeed < 0f;
|
|
|
|
foreach (CustomRoles subRole in state.SubRoles)
|
|
{
|
|
if (subRole.IsGhostRole())
|
|
{
|
|
AURoleOptions.GuardianAngelCooldown = 5f;
|
|
continue;
|
|
}
|
|
|
|
switch (subRole)
|
|
{
|
|
case CustomRoles.Watcher:
|
|
{
|
|
opt.SetBool(BoolOptionNames.AnonymousVotes, false);
|
|
break;
|
|
}
|
|
case CustomRoles.Flash when !frozen:
|
|
{
|
|
Main.AllPlayerSpeed[player.PlayerId] = inverted ? -Options.FlashSpeed.GetFloat() : Options.FlashSpeed.GetFloat();
|
|
break;
|
|
}
|
|
case CustomRoles.Giant when !frozen:
|
|
{
|
|
Main.AllPlayerSpeed[player.PlayerId] = inverted ? -Options.GiantSpeed.GetFloat() : Options.GiantSpeed.GetFloat();
|
|
break;
|
|
}
|
|
case CustomRoles.Mare when !frozen && Options.MareHasIncreasedSpeed.GetBool():
|
|
{
|
|
Main.AllPlayerSpeed[player.PlayerId] = inverted ? -Options.MareSpeedDuringLightsOut.GetFloat() : Options.MareSpeedDuringLightsOut.GetFloat();
|
|
break;
|
|
}
|
|
case CustomRoles.Sleep when player.IsAlive() && Utils.IsActive(SystemTypes.Electrical):
|
|
{
|
|
SetBlind();
|
|
Main.AllPlayerSpeed[player.PlayerId] = Main.MinSpeed;
|
|
break;
|
|
}
|
|
case CustomRoles.Torch:
|
|
{
|
|
if (!Utils.IsActive(SystemTypes.Electrical))
|
|
{
|
|
opt.SetVision(true);
|
|
opt.SetFloat(FloatOptionNames.CrewLightMod, Options.TorchVision.GetFloat());
|
|
opt.SetFloat(FloatOptionNames.ImpostorLightMod, Options.TorchVision.GetFloat());
|
|
}
|
|
else if (!Options.TorchAffectedByLights.GetBool())
|
|
{
|
|
opt.SetVision(true);
|
|
opt.SetFloat(FloatOptionNames.CrewLightMod, Options.TorchVision.GetFloat() * 5);
|
|
opt.SetFloat(FloatOptionNames.ImpostorLightMod, Options.TorchVision.GetFloat() * 5);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case CustomRoles.Bewilder when !Utils.IsActive(SystemTypes.Electrical):
|
|
{
|
|
opt.SetVision(false);
|
|
opt.SetFloat(FloatOptionNames.CrewLightMod, Options.BewilderVision.GetFloat());
|
|
opt.SetFloat(FloatOptionNames.ImpostorLightMod, Options.BewilderVision.GetFloat());
|
|
break;
|
|
}
|
|
case CustomRoles.Sunglasses when !Utils.IsActive(SystemTypes.Electrical):
|
|
{
|
|
opt.SetVision(false);
|
|
opt.SetFloat(FloatOptionNames.CrewLightMod, Options.SunglassesVision.GetFloat());
|
|
opt.SetFloat(FloatOptionNames.ImpostorLightMod, Options.SunglassesVision.GetFloat());
|
|
break;
|
|
}
|
|
case CustomRoles.Reach:
|
|
{
|
|
opt.SetInt(Int32OptionNames.KillDistance, 2);
|
|
break;
|
|
}
|
|
case CustomRoles.Constricted:
|
|
{
|
|
opt.SetInt(Int32OptionNames.KillDistance, 0);
|
|
break;
|
|
}
|
|
case CustomRoles.Madmate:
|
|
{
|
|
opt.SetVision(Options.MadmateHasImpostorVision.GetBool());
|
|
break;
|
|
}
|
|
case CustomRoles.Lovers when Main.LoversPlayers.Count(x => x.IsAlive()) == 1 && Lovers.LoverDieConsequence.GetValue() == 2:
|
|
{
|
|
opt.SetFloat(FloatOptionNames.CrewLightMod, Main.DefaultCrewmateVision / 2f);
|
|
opt.SetFloat(FloatOptionNames.ImpostorFlashlightSize, Main.DefaultImpostorVision / 2f);
|
|
break;
|
|
}
|
|
case CustomRoles.Nimble when roleTypes == RoleTypes.Engineer:
|
|
{
|
|
AURoleOptions.EngineerCooldown = Nimble.NimbleCD.GetFloat();
|
|
AURoleOptions.EngineerInVentMaxTime = Nimble.NimbleInVentTime.GetFloat();
|
|
break;
|
|
}
|
|
case CustomRoles.Physicist when roleTypes == RoleTypes.Scientist:
|
|
{
|
|
AURoleOptions.ScientistCooldown = Physicist.PhysicistCD.GetFloat();
|
|
AURoleOptions.ScientistBatteryCharge = Physicist.PhysicistViewDuration.GetFloat();
|
|
break;
|
|
}
|
|
case CustomRoles.Finder when roleTypes == RoleTypes.Tracker:
|
|
{
|
|
AURoleOptions.TrackerCooldown = Finder.FinderCD.GetFloat();
|
|
AURoleOptions.TrackerDuration = Finder.FinderDuration.GetFloat();
|
|
AURoleOptions.TrackerDelay = Finder.FinderDelay.GetFloat();
|
|
break;
|
|
}
|
|
case CustomRoles.Noisy when roleTypes == RoleTypes.Noisemaker:
|
|
{
|
|
AURoleOptions.NoisemakerImpostorAlert = Noisy.NoisyImpostorAlert.GetBool();
|
|
AURoleOptions.NoisemakerAlertDuration = Noisy.NoisyAlertDuration.GetFloat();
|
|
break;
|
|
}
|
|
case CustomRoles.Examiner when roleTypes == RoleTypes.Detective:
|
|
{
|
|
AURoleOptions.DetectiveSuspectLimit = Examiner.ExaminerSuspectLimit.GetFloat();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch (player.GetCustomRoleTypes())
|
|
{
|
|
case CustomRoleTypes.Impostor:
|
|
AURoleOptions.ShapeshifterCooldown = Options.DefaultShapeshiftCooldown.GetFloat();
|
|
break;
|
|
}
|
|
|
|
switch (role)
|
|
{
|
|
case CustomRoles.PhantomEHR:
|
|
AURoleOptions.PhantomCooldown = ImpostorVanillaRoles.PhantomCooldown.GetFloat();
|
|
AURoleOptions.PhantomDuration = ImpostorVanillaRoles.PhantomDuration.GetFloat();
|
|
break;
|
|
case CustomRoles.ShapeshifterEHR:
|
|
AURoleOptions.ShapeshifterCooldown = ImpostorVanillaRoles.ShapeshiftCD.GetFloat();
|
|
AURoleOptions.ShapeshifterDuration = ImpostorVanillaRoles.ShapeshiftDur.GetFloat();
|
|
break;
|
|
case CustomRoles.EngineerEHR:
|
|
AURoleOptions.EngineerCooldown = CrewmateVanillaRoles.EngineerCD.GetFloat();
|
|
AURoleOptions.EngineerInVentMaxTime = CrewmateVanillaRoles.EngineerDur.GetFloat();
|
|
break;
|
|
case CustomRoles.NoisemakerEHR:
|
|
AURoleOptions.NoisemakerImpostorAlert = CrewmateVanillaRoles.NoiseMakerImpostorAlert.GetBool();
|
|
AURoleOptions.NoisemakerAlertDuration = CrewmateVanillaRoles.NoisemakerAlertDuration.GetFloat();
|
|
break;
|
|
case CustomRoles.ScientistEHR:
|
|
AURoleOptions.ScientistCooldown = CrewmateVanillaRoles.ScientistCD.GetFloat();
|
|
AURoleOptions.ScientistBatteryCharge = CrewmateVanillaRoles.ScientistDur.GetFloat();
|
|
break;
|
|
case CustomRoles.TrackerEHR:
|
|
AURoleOptions.TrackerCooldown = CrewmateVanillaRoles.TrackerCooldown.GetFloat();
|
|
AURoleOptions.TrackerDuration = CrewmateVanillaRoles.TrackerDuration.GetFloat();
|
|
AURoleOptions.TrackerDelay = CrewmateVanillaRoles.TrackerDelay.GetFloat();
|
|
break;
|
|
case CustomRoles.DetectiveEHR:
|
|
AURoleOptions.DetectiveSuspectLimit = CrewmateVanillaRoles.DetectiveSuspectLimit.GetFloat();
|
|
break;
|
|
case CustomRoles.JudgeEHR:
|
|
AURoleOptions.JudgeTaskRequirementPercentage = CrewmateVanillaRoles.JudgeTaskRequirementPercentage.GetFloat();
|
|
break;
|
|
}
|
|
|
|
if (player.UsesJudgeAbilityAsTrigger())
|
|
AURoleOptions.JudgeTaskRequirementPercentage = 0f;
|
|
|
|
// When impostor alert is off, and the player is a desync crewmate, set impostor alert as true
|
|
if (role.IsDesyncRole() && role.IsCrewmate() && !CrewmateVanillaRoles.NoiseMakerImpostorAlert.GetBool())
|
|
AURoleOptions.NoisemakerImpostorAlert = true;
|
|
else
|
|
AURoleOptions.NoisemakerImpostorAlert = CrewmateVanillaRoles.NoiseMakerImpostorAlert.GetBool();
|
|
|
|
try
|
|
{
|
|
if (Shifter.WasShifter.Contains(player.PlayerId) && role.IsImpostor()) opt.SetVision(true);
|
|
}
|
|
catch (Exception e) { Utils.ThrowException(e); }
|
|
|
|
try { state.Role.ApplyGameOptions(opt, player.PlayerId); }
|
|
catch (Exception e) { Utils.ThrowException(e); }
|
|
|
|
if (player.Is(CustomRoles.Bloodlust) && Bloodlust.HasImpVision.GetBool()) opt.SetVision(true);
|
|
|
|
if (!player.Is(CustomRoles.Focused) && Main.CachedAllPlayerControls().Exists(x => x.Is(CustomRoles.Bewilder) && !x.IsAlive() && x.GetRealKiller()?.PlayerId == player.PlayerId && !x.Is(CustomRoles.Hangman)))
|
|
{
|
|
opt.SetVision(false);
|
|
opt.SetFloat(FloatOptionNames.CrewLightMod, Options.BewilderVision.GetFloat());
|
|
opt.SetFloat(FloatOptionNames.ImpostorLightMod, Options.BewilderVision.GetFloat());
|
|
}
|
|
|
|
if (Grenadier.GrenadierBlinding.Count > 0 &&
|
|
(role.IsImpostor() ||
|
|
role.IsNeutral() && Options.GrenadierCanAffectNeutral.GetBool()) ||
|
|
Grenadier.MadGrenadierBlinding.Count > 0 && !role.IsImpostorTeam() && !player.Is(CustomRoles.Madmate))
|
|
{
|
|
opt.SetVision(false);
|
|
opt.SetFloat(FloatOptionNames.CrewLightMod, Options.GrenadierCauseVision.GetFloat());
|
|
opt.SetFloat(FloatOptionNames.ImpostorLightMod, Options.GrenadierCauseVision.GetFloat());
|
|
}
|
|
|
|
switch (role)
|
|
{
|
|
case CustomRoles.Alchemist when ((Alchemist)state.Role).VisionPotionActive:
|
|
opt.SetVision(false);
|
|
|
|
if (Utils.IsActive(SystemTypes.Electrical))
|
|
opt.SetFloat(FloatOptionNames.CrewLightMod, Alchemist.VisionOnLightsOut.GetFloat() * 5);
|
|
else
|
|
opt.SetFloat(FloatOptionNames.CrewLightMod, Alchemist.Vision.GetFloat());
|
|
|
|
break;
|
|
case CustomRoles.Mayor when Mayor.MayorSeesVoteColorsWhenDoneTasks.GetBool() && player.GetTaskState().IsTaskFinished:
|
|
opt.SetBool(BoolOptionNames.AnonymousVotes, false);
|
|
break;
|
|
}
|
|
|
|
Farmer.OnAnyoneApplyGameOptions(opt, player);
|
|
Siren.ApplyGameOptionsForOthers(opt, player.PlayerId);
|
|
Chef.ApplyGameOptionsForOthers(opt, player.PlayerId);
|
|
Negotiator.OnAnyoneApplyGameOptions(opt, player.PlayerId);
|
|
Wizard.OnAnyoneApplyGameOptions(opt, player.PlayerId);
|
|
Curser.OnAnyoneApplyGameOptions(opt, player.PlayerId);
|
|
Auditor.OnAnyoneApplyGameOptions(opt, player.PlayerId);
|
|
Clerk.OnAnyoneApplyGameOptions(opt, player.PlayerId);
|
|
Spider.OnAnyoneApplyGameOptions(opt, player.PlayerId);
|
|
|
|
if (Sprayer.LowerVisionList.Contains(player.PlayerId))
|
|
{
|
|
opt.SetVision(false);
|
|
opt.SetFloat(FloatOptionNames.CrewLightMod, Sprayer.LoweredVision.GetFloat());
|
|
opt.SetFloat(FloatOptionNames.ImpostorLightMod, Sprayer.LoweredVision.GetFloat());
|
|
}
|
|
|
|
if (Minion.BlindPlayers.Contains(player.PlayerId)) SetBlind();
|
|
if (Slenderman.IsBlinded(player.PlayerId)) SetBlind();
|
|
|
|
if (Sentinel.IsPatrolling(player.PlayerId))
|
|
{
|
|
opt.SetVision(false);
|
|
opt.SetFloat(FloatOptionNames.CrewLightMod, Sentinel.LoweredVision.GetFloat());
|
|
opt.SetFloat(FloatOptionNames.ImpostorLightMod, Sentinel.LoweredVision.GetFloat());
|
|
}
|
|
|
|
if (Beacon.IsAffectedPlayer(player.PlayerId))
|
|
{
|
|
opt.SetFloat(FloatOptionNames.CrewLightMod, Beacon.IncreasedVision);
|
|
opt.SetFloat(FloatOptionNames.ImpostorLightMod, Beacon.IncreasedVision);
|
|
}
|
|
|
|
Dazzler.SetDazzled(player, opt);
|
|
Deathpact.SetDeathpactVision(player, opt);
|
|
|
|
Spiritcaller.ReduceVision(opt, player);
|
|
|
|
if (Randomizer.HasSuperVision(player)) SetMaxVision();
|
|
else if (Randomizer.IsBlind(player)) SetBlind();
|
|
|
|
bool energeticIncreaseSpeed = false, energeticDecreaseCooldown = false;
|
|
|
|
if (state.SubRoles.Contains(CustomRoles.Energetic) || Empress.Encouraged != null && Empress.Encouraged.Contains(player.PlayerId))
|
|
{
|
|
if (player.CanUseKillButton())
|
|
energeticDecreaseCooldown = true;
|
|
else
|
|
switch (roleTypes)
|
|
{
|
|
case RoleTypes.Impostor:
|
|
energeticDecreaseCooldown = true;
|
|
break;
|
|
case RoleTypes.Scientist:
|
|
AURoleOptions.ScientistCooldown *= 0.75f;
|
|
break;
|
|
case RoleTypes.Engineer:
|
|
AURoleOptions.EngineerCooldown *= 0.75f;
|
|
break;
|
|
case RoleTypes.Shapeshifter:
|
|
AURoleOptions.ShapeshifterCooldown *= 0.75f;
|
|
break;
|
|
case RoleTypes.Phantom:
|
|
AURoleOptions.PhantomCooldown *= 0.75f;
|
|
break;
|
|
case RoleTypes.Tracker:
|
|
AURoleOptions.TrackerCooldown *= 0.75f;
|
|
break;
|
|
case RoleTypes.Detective:
|
|
AURoleOptions.DetectiveSuspectLimit *= 1.25f;
|
|
goto default;
|
|
case RoleTypes.CrewmateGhost:
|
|
case RoleTypes.ImpostorGhost:
|
|
break;
|
|
default:
|
|
energeticIncreaseSpeed = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Magician.BlindPpl.ContainsKey(player.PlayerId))
|
|
SetBlind();
|
|
|
|
if (player.IsCrewmate() && Main.PlayerStates.Values.Any(s => s.Role is Adventurer { IsEnable: true } av && av.ActiveWeapons.Contains(Adventurer.Weapon.Lantern)))
|
|
SetMaxVision();
|
|
|
|
if (Chemist.Instances.Any(x => x.IsBlinding && player.PlayerId != x.ChemistPC.PlayerId))
|
|
SetBlind();
|
|
|
|
if (Changeling.ChangedRole.TryGetValue(player.PlayerId, out bool changed) && changed && roleTypes != RoleTypes.Shapeshifter)
|
|
{
|
|
AURoleOptions.ShapeshifterCooldown = 300f;
|
|
AURoleOptions.ShapeshifterDuration = 1f;
|
|
}
|
|
|
|
if ((Options.UsePhantomBasis.GetBool() || role.AlwaysUsesPhantomBase()) && role.SimpleAbilityTrigger())
|
|
AURoleOptions.PhantomDuration = 0.1f;
|
|
|
|
// ===================================================================================================================
|
|
|
|
if (state.IsBlackOut)
|
|
SetBlind();
|
|
|
|
AURoleOptions.EngineerCooldown = Mathf.Max(0.01f, AURoleOptions.EngineerCooldown);
|
|
|
|
if (Main.AllPlayerKillCooldown.TryGetValue(player.PlayerId, out float killCooldown))
|
|
{
|
|
if (energeticDecreaseCooldown) killCooldown *= 0.75f;
|
|
AURoleOptions.KillCooldown = Mathf.Max(0.01f, killCooldown);
|
|
}
|
|
|
|
if (Main.AllPlayerSpeed.TryGetValue(player.PlayerId, out float speed))
|
|
{
|
|
const float limit = 3f;
|
|
if (energeticIncreaseSpeed) speed *= 1.25f;
|
|
if (Mathf.Approximately(speed, 0f)) speed = Main.MinSpeed;
|
|
|
|
if (Camouflage.IsCamouflage && Options.CommsCamouflageSetSameSpeed.GetBool())
|
|
speed = Main.RealOptionsData.GetFloat(FloatOptionNames.PlayerSpeedMod);
|
|
|
|
AURoleOptions.PlayerSpeedMod = Mathf.Clamp(speed, -limit, limit);
|
|
}
|
|
|
|
state.TaskState.HasTasks = Utils.HasTasks(player.Data, false);
|
|
if (Options.GhostCanSeeOtherVotes.GetBool() && !player.IsAlive()) opt.SetBool(BoolOptionNames.AnonymousVotes, false);
|
|
|
|
if (Options.AdditionalEmergencyCooldown.GetBool() &&
|
|
Options.AdditionalEmergencyCooldownThreshold.GetInt() <= Main.AllAlivePlayerControlsCount)
|
|
{
|
|
opt.SetInt(
|
|
Int32OptionNames.EmergencyCooldown,
|
|
Options.AdditionalEmergencyCooldownTime.GetInt());
|
|
}
|
|
|
|
if (CustomRoles.ClockBlocker.RoleExist(ClockBlocker.CountAddedTimeAfterDeath.GetBool()))
|
|
{
|
|
int originalTime = opt.GetInt(Int32OptionNames.EmergencyCooldown);
|
|
opt.SetInt(Int32OptionNames.EmergencyCooldown, ClockBlocker.GetTotalTime(originalTime));
|
|
}
|
|
|
|
if (MeetingStates.FirstMeeting)
|
|
{
|
|
int originalTime = opt.GetInt(Int32OptionNames.EmergencyCooldown);
|
|
opt.SetInt(Int32OptionNames.EmergencyCooldown, originalTime + 30);
|
|
}
|
|
|
|
if (Options.SyncButtonMode.GetBool() && Options.SyncedButtonCount.GetValue() <= Options.UsedButtonCount)
|
|
opt.SetInt(Int32OptionNames.EmergencyCooldown, 3600);
|
|
|
|
MeetingTimeManager.ApplyGameOptions(opt);
|
|
|
|
AURoleOptions.ShapeshifterCooldown = Mathf.Max(1f, AURoleOptions.ShapeshifterCooldown);
|
|
AURoleOptions.ProtectionDurationSeconds = 0f;
|
|
AURoleOptions.ImpostorsCanSeeProtect = false;
|
|
|
|
Logger.Info($"Updated settings for {player.GetNameWithRole()}: Crew Vision = {opt.GetFloat(FloatOptionNames.CrewLightMod):N2}, Impostor Vision = {opt.GetFloat(FloatOptionNames.ImpostorLightMod):N2}, Speed = {opt.GetFloat(FloatOptionNames.PlayerSpeedMod):N2}", "BuildGameOptions");
|
|
|
|
return opt;
|
|
|
|
void SetMaxVision()
|
|
{
|
|
opt.SetVision(true);
|
|
opt.SetFloat(FloatOptionNames.CrewLightMod, 1.3f);
|
|
opt.SetFloat(FloatOptionNames.ImpostorLightMod, 1.3f);
|
|
}
|
|
|
|
void SetBlind()
|
|
{
|
|
opt.SetVision(false);
|
|
opt.SetFloat(FloatOptionNames.CrewLightMod, 0f);
|
|
opt.SetFloat(FloatOptionNames.ImpostorLightMod, 0f);
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Logger.Error($"Error for {player.GetRealName()} ({player.GetCustomRole()}): {e}", "PlayerGameOptionsSender.BuildGameOptions");
|
|
return BasedGameOptions;
|
|
}
|
|
}
|
|
|
|
protected override bool AmValid()
|
|
{
|
|
return base.AmValid() && player && player.Data && !player.Data.Disconnected && Main.RealOptionsData != null;
|
|
}
|
|
}
|