Files
EndlessHostRoles/Modules/CustomSabotage.cs
T
TommyXL 7929a4b83e Optimization (Part 1?) (#589)
* Well lets try check this

* Some changes

* Change

* Well

* Change ControllerManager.Update

* Nothing

* Optimaze more?

* Fix error build

* Fix win check

* Change

* Fix

* Optimaze some roles in OnCheckPlayerPosition

* More optimaze

* Full optimaze roles in OnGlobalFixedUpdate

* Optimaze some add-ons

* ProgressText

* Change

* Optimaze NameNotifyManager

* Optimaze NotifyRoles and some roles

* Move the displayed version

* Some changes

* Optimaze OnFixedUpdate in some roles

* Fix bugs

* Optimaze IsActive & V4 version

* Optimaze MapRoom.DoorsUpdate

* Cache TryCatch in IsActive

* Change

* Fix

* More optimze TaskPanelBehaviour

* Cache GetRoleColor & ColorString & AllStringNames & Change RemoveHtmlTags

* Cache TryCast VentilationSystem & ICriticalSabotage & IUsable and more optimaze

* Fix CountAlivePlayers

* Fix exceptios

* Replace some CachedAllPlayerControls to EnumeratePlayerControls

* Replace some CachedAlivePlayerControls to EnumerateAlivePlayerControls

* Fixes

* Fix modded clients

* Fix errors

* Fix again

* Optimaze & add null check

* Fix crash in Starlight

* Use only Main.PluginVersion in LobbySharingAPI

* Optimaze code in FixedUpdate

* Fix

* Optimize GetProgressText for Roles

* Some changes in Translations

* Cache Enum.GetValues and StringBuilder

* Changes

* CustomRole.ColoredTextByRole()

* Optimaze Lobby & Meeting

* ColorStringPrefix => ColorPrefix

* Add null check

* Remove

* Fixes & optimaze

* Fixes

* Changes

* Fix

* Fix

* Fix

* Remove

* Fix

* Change

* Revert
2026-05-15 20:01:54 +02:00

191 lines
6.1 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using AmongUs.GameOptions;
using UnityEngine;
namespace EHR.Modules;
public abstract class CustomSabotage
{
public static readonly List<CustomSabotage> Instances = [];
public virtual void Deteriorate()
{
Instances.Add(this);
}
protected virtual void Update() { }
protected virtual void Fix()
{
Instances.Remove(this);
ShipStatus.Instance.Systems[SystemTypes.Sabotage].CastFast<SabotageSystemType>().IsDirty = true;
}
protected virtual string GetSuffix(PlayerControl seer, PlayerControl target, bool hud, bool meeting)
{
return string.Empty;
}
protected static int GetDefaultSabotageTimeLimit(MapNames map)
{
return map switch
{
MapNames.Skeld or MapNames.Dleks => 30,
MapNames.MiraHQ => 45,
MapNames.Polus => 60,
MapNames.Airship => 90,
MapNames.Fungle => 60,
_ => 75
};
}
protected static void AdjustTimeLimitBasedOnPlayerSpeed(ref int timeLimit)
{
float speed = Main.RealOptionsData.GetFloat(FloatOptionNames.PlayerSpeedMod);
timeLimit = (int)Math.Ceiling(timeLimit / speed);
}
private static long LastNotifyTS;
public static string GetAllSuffix(PlayerControl seer, PlayerControl target, bool hud, bool meeting)
{
if (!AmongUsClient.Instance.AmHost || Options.CurrentGameMode != CustomGameMode.Standard) return string.Empty;
StringBuilder suffix = new();
foreach (CustomSabotage sabotage in Instances)
{
string tempSuffix = sabotage.GetSuffix(seer, target, hud, meeting);
if (!string.IsNullOrWhiteSpace(tempSuffix))
suffix.Append($"{tempSuffix}\n");
}
var result = suffix.ToString();
if (seer.IsNonHostModdedClient() && suffix.Length > 0)
{
long now = Utils.TimeStamp;
if (LastNotifyTS != now)
{
seer.Notify(result, 3f, true, false);
LastNotifyTS = now;
}
return string.Empty;
}
return result.Trim();
}
public static void UpdateAll()
{
for (int index = Instances.Count - 1; index >= 0; index--)
{
try { Instances[index].Update(); }
catch (Exception e) { Utils.ThrowException(e); }
}
if (Instances.Count > 0)
{
SabotageSystemType sabotageSystemType = ShipStatus.Instance.Systems[SystemTypes.Sabotage].CastFast<SabotageSystemType>();
sabotageSystemType.Timer = SabotageSystemTypeUpdateSystemPatch.IsCooldownModificationEnabled
? SabotageSystemTypeUpdateSystemPatch.ModifiedCooldownSec
: 30f;
sabotageSystemType.IsDirty = true;
}
}
public static void Reset()
{
Instances.Clear();
}
}
public class GrabOxygenMaskSabotage : CustomSabotage
{
private long LastNotify;
private long LastReactorFlash;
private long DeteriorateTS;
private HashSet<byte> HasMask;
private SystemTypes TargetRoom;
private int TimeLimit;
private Vector2 RoomPosition;
public override void Deteriorate()
{
base.Deteriorate();
DeteriorateTS = Utils.TimeStamp;
HasMask = [];
MapNames map = Main.CurrentMap;
TargetRoom = map switch
{
MapNames.Skeld or MapNames.Dleks => SystemTypes.MedBay,
MapNames.MiraHQ => SystemTypes.Balcony,
MapNames.Polus => SystemTypes.Specimens,
MapNames.Airship => SystemTypes.Medical,
MapNames.Fungle => SystemTypes.Kitchen,
(MapNames)6 => (SystemTypes)SubmergedCompatibility.SubmergedSystemTypes.Filtration,
_ => ShipStatus.Instance.AllRooms.RandomElement().RoomId
};
TimeLimit = Math.Min(60, GetDefaultSabotageTimeLimit(map));
AdjustTimeLimitBasedOnPlayerSpeed(ref TimeLimit);
RoomPosition = Main.LIMap ? TargetRoom.GetRoomClass().transform.position : RandomSpawn.SpawnMap.GetSpawnMap().Positions.GetValueOrDefault(TargetRoom, TargetRoom.GetRoomClass().transform.position);
Main.EnumerateAlivePlayerControls().Do(x => LocateArrow.Add(x.PlayerId, RoomPosition));
}
protected override void Update()
{
var aapc = Main.CachedAlivePlayerControls();
byte[] playersInRoom = aapc.Where(x => x.IsInRoom(TargetRoom)).Select(x => x.PlayerId).ToArray();
playersInRoom.Except(HasMask).ToValidPlayers().NotifyPlayers(Translator.GetString("CustomSabotage.GrabOxygenMask.Done"));
playersInRoom.Except(HasMask).Do(x => LocateArrow.Remove(x, RoomPosition));
HasMask.UnionWith(playersInRoom);
if (HasMask.IsSupersetOf(aapc.Select(x => x.PlayerId)))
{
Main.EnumeratePlayerControls().Do(x => LocateArrow.Remove(x.PlayerId, RoomPosition));
Fix();
return;
}
long now = Utils.TimeStamp;
if (DeteriorateTS + TimeLimit <= now)
{
Main.EnumeratePlayerControls().Do(x => LocateArrow.Remove(x.PlayerId, RoomPosition));
aapc.ExceptBy(HasMask, x => x.PlayerId).Do(x => x.Suicide(PlayerState.DeathReason.OutOfOxygen));
Fix();
return;
}
if (LastReactorFlash + 3 <= now)
{
LastReactorFlash = now;
aapc.ExceptBy(HasMask, x => x.PlayerId).Do(x => x.ReactorFlash(flashDuration: 0.5f));
}
if (LastNotify != now)
{
LastNotify = now;
Utils.NotifyRoles();
}
}
protected override string GetSuffix(PlayerControl seer, PlayerControl target, bool hud, bool meeting)
{
if (seer.PlayerId != target.PlayerId || hud || meeting || HasMask.Contains(seer.PlayerId)) return string.Empty;
long now = Utils.TimeStamp;
return Utils.ColorString(now % 2 == 0 ? Color.yellow : Color.red, $"[{Translator.GetString(TargetRoom.ToString())}] {Translator.GetString("CustomSabotage.GrabOxygenMask")} {TimeLimit - (now - DeteriorateTS)} {LocateArrow.GetArrow(seer, RoomPosition)}");
}
}