6
2026-01-18 12:53:36 +03:00

317 lines
11 KiB
C#

using System.Diagnostics.CodeAnalysis;
using Content.Shared._Horizon.FlavorText;
using Content.Shared._Horizon.OutpostCapture.Components;
using Content.Shared.Access.Components;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.Storage;
using Robust.Shared.Containers;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Serialization;
namespace Content.Shared._Horizon.OutpostCapture;
public class SharedOutpostCaptureSystem : EntitySystem
{
[Dependency] protected readonly IRobustRandom Random = null!;
[Dependency] protected readonly ItemSlotsSystem ItemSlotsSystem = null!;
[Dependency] protected readonly IPrototypeManager PrototypeManager = null!;
[Dependency] protected readonly SharedUserInterfaceSystem UiSystem = null!;
[Dependency] protected readonly SharedContainerSystem ContainerSystem = null!;
[Dependency] protected readonly SharedTransformSystem TransformSystem = null!;
protected ISawmill Sawmill = null!;
public override void Initialize()
{
SawmillInit();
SubscribeLocalEvent<OutpostConsoleComponent, ComponentInit>(OnConsoleInit);
SubscribeLocalEvent<OutpostConsoleComponent, ComponentRemove>(OnConsoleRemove);
SubscribeLocalEvent<OutpostConsoleComponent, EntInsertedIntoContainerMessage>(OnGetInsertedAttempt);
SubscribeLocalEvent<OutpostConsoleComponent, EntRemovedFromContainerMessage>(OnGetRemovedAttempt);
SubscribeLocalEvent<OutpostCaptureComponent, ComponentInit>(OnOutpostInit);
SubscribeLocalEvent<OutpostCaptureComponent, ComponentRemove>(OnOutpostRemove);
Subs.BuiEvents<OutpostConsoleComponent>(CaptureUIKey.Key,
subs =>
{
subs.Event<OpenBoundInterfaceMessage>((uid, comp, _) => UpdateConsole((uid, comp)));
subs.Event<OutpostCaptureButtonPressed>((uid, comp, _) => OnButtonPressed((uid, comp)));
});
}
#region Init
private void SawmillInit()
{
Sawmill = LogManager.GetSawmill("OutpostCapture");
Sawmill.Info("_outpostCaptureSystem start his work!");
}
private void OnConsoleInit(Entity<OutpostConsoleComponent> console, ref ComponentInit args)
{
if (TryGetOutpost(console, out var outpost, out var outpostUid))
return;
if (console.Comp.CanUseAsSpawnPoint &&
TransformSystem.TryGetMapOrGridCoordinates(console, out var coords))
outpost.SpawnLocation = coords;
console.Comp.LinkedOutpost = GetNetEntity(outpostUid);
outpost.LinkedConsoles.Add(GetNetEntity(console));
ItemSlotsSystem.AddItemSlot(console, console.Comp.ContainerSlot, console.Comp.IdCardSlot);
}
private void OnConsoleRemove(Entity<OutpostConsoleComponent> console, ref ComponentRemove args)
{
if (TryGetOutpost(console, out var outpost, out _))
return;
console.Comp.LinkedOutpost = null;
outpost.LinkedConsoles.Remove(GetNetEntity(console));
outpost.CapturedConsoles.Remove(GetNetEntity(console));
ItemSlotsSystem.RemoveItemSlot(console, console.Comp.IdCardSlot);
}
private void OnGetInsertedAttempt(Entity<OutpostConsoleComponent> console, ref EntInsertedIntoContainerMessage args)
{
UpdateConsole(console);
}
private void OnGetRemovedAttempt(Entity<OutpostConsoleComponent> console, ref EntRemovedFromContainerMessage args)
{
UpdateConsole(console);
}
private void OnOutpostInit(Entity<OutpostCaptureComponent> outpost, ref ComponentInit args)
{
if (outpost.Comp.NeedCaptured <= 0)
{
RemComp<OutpostCaptureComponent>(outpost);
return;
}
outpost.Comp.NextSpawn = outpost.Comp.SpawnCooldown;
}
private void OnOutpostRemove(Entity<OutpostCaptureComponent> outpost, ref ComponentRemove args)
{
if (outpost.Comp.LinkedConsoles.Count <= 0 ||
outpost.Comp.CapturedConsoles.Count <= 0)
return;
UnlinkAllConsoles(outpost.Comp);
}
public void UnlinkAllConsoles(OutpostCaptureComponent outpost)
{
foreach (var console in outpost.LinkedConsoles)
{
if (TryGetEntity(console, out var actualConsole) ||
!TryComp<OutpostConsoleComponent>(actualConsole, out var consoleComp))
continue;
consoleComp.LinkedOutpost = null;
consoleComp.CapturedFaction = null;
consoleComp.CapturedFactionName = null;
consoleComp.CapturingTime = null;
Dirty(actualConsole.Value, consoleComp);
}
}
#endregion
#region Private methods
private bool TryGetOutpost(EntityUid uid,
[NotNullWhen(false)] out OutpostCaptureComponent? outpost,
[NotNullWhen(false)] out EntityUid? grid)
{
outpost = null;
grid = TransformSystem.GetGrid(Transform(uid).Coordinates);
return grid == null || !TryComp(grid, out outpost);
}
#region Messages
private void UpdateConsole(Entity<OutpostConsoleComponent> console)
{
var progress = UpdateProgressBar(console);
var buttonStateDisabled = !CanChangeCaptureState(console, out _);
var labelState = FormattedLabel(console);
var buttonState = FormattedButton(console);
var state = new OutpostUIState(progress, buttonStateDisabled, labelState, buttonState);
UiSystem.SetUiState(console.Owner, CaptureUIKey.Key, state);
}
private void OnButtonPressed(Entity<OutpostConsoleComponent> console)
{
ChangeCaptureState(console);
UpdateConsole(console); // Update console
}
#endregion
#region Formats
private string FormattedLabel(Entity<OutpostConsoleComponent> console)
{
switch (console.Comp.State)
{
case OutpostConsoleState.Uncaptured:
return $"{Loc.GetString("faction-uncaptured-state")}";
case OutpostConsoleState.Capturing:
return $"{Loc.GetString("faction-capturing-state-by")}, {Loc.GetString(console.Comp.CapturedFactionName ?? "faction-none")}!";
case OutpostConsoleState.Captured:
return $"{Loc.GetString("faction-captured-state-by")}, {Loc.GetString(console.Comp.CapturedFactionName ?? "faction-none")}!";
default:
Sawmill.Error($"Unknown {console.Comp.State} state!");
break;
}
return Loc.GetString("faction-default-string");
}
private string FormattedButton(Entity<OutpostConsoleComponent> console)
{
var faction = TryGetFactionInSlot(console, out var slot);
if (slot.ContainedEntity == null)
return $"{Loc.GetString("faction-insert-faction-id")}";
if (faction == null)
return $"{Loc.GetString("faction-id-card-not-belong-to-any-faction")}";
return faction.ID == console.Comp.CapturedFaction
? $"{Loc.GetString("faction-cant-capture-already-captured-outpost")}"
: $"{Loc.GetString("faction-start-capture-outpost")}";
}
#endregion
private void ChangeCaptureState(Entity<OutpostConsoleComponent> console)
{
if (!CanChangeCaptureState(console, out var faction))
return;
var oldFaction = console.Comp.CapturedFaction;
console.Comp.CapturedFaction = faction.ID;
console.Comp.CapturedFactionName = faction.Name;
switch (console.Comp.State)
{
case OutpostConsoleState.Uncaptured:
Sawmill.Info($"Faction {faction}, start capturing console id - {console.Owner}");
break;
case OutpostConsoleState.Capturing:
Sawmill.Info($"Faction {faction}, intercepts capturing console faction, {oldFaction} on id - {console.Owner}");
break;
case OutpostConsoleState.Captured:
Sawmill.Info($"Faction {faction}, start recapturing console of faction, {oldFaction} on id - {console.Owner}");
break;
default:
Sawmill.Error("Don't know how to change default capture state!");
return;
}
console.Comp.State = OutpostConsoleState.Capturing;
StartCapture(GetNetEntity(console), console.Comp);
Dirty(console);
}
private void StartCapture(NetEntity netConsole, OutpostConsoleComponent console)
{
if (!TryGetEntity(console.LinkedOutpost, out var outpost) ||
!TryComp<OutpostCaptureComponent>(outpost, out var outpostCapture))
return;
console.CapturingTime = console.CaptureTime;
if (outpostCapture.CapturedConsoles.Contains(netConsole))
outpostCapture.CapturedConsoles.Remove(netConsole);
if (outpostCapture.CapturingConsoles.Contains(netConsole))
return;
outpostCapture.CapturingConsoles.Add(netConsole);
}
private CharacterFactionPrototype? TryGetFactionInSlot(Entity<OutpostConsoleComponent> console, out ContainerSlot slot)
{
slot = ContainerSystem.EnsureContainer<ContainerSlot>(console,
console.Comp.ContainerSlot,
out var existed);
if (!existed || slot.ContainedEntity == null)
return null;
var id = slot.ContainedEntity.Value;
if (!TryComp<IdCardComponent>(id, out var card) || card.JobPrototype == null)
return null;
var prototype = card.JobPrototype.Value;
if (!PrototypeManager.TryIndex(prototype, out var index))
return null;
var faction = index.ForceFaction;
return !PrototypeManager.TryIndex(faction, out var factionIndex) ? null : factionIndex;
}
private bool CanChangeCaptureState(Entity<OutpostConsoleComponent> console,
[NotNullWhen(true)] out CharacterFactionPrototype? faction)
{
faction = TryGetFactionInSlot(console, out _);
if (faction == null)
return false;
if (console.Comp.LinkedOutpost == null)
return false;
return console.Comp.CapturedFaction != faction.ID;
}
#endregion
public float? UpdateProgressBar(Entity<OutpostConsoleComponent> console)
{
var progress = (float?) (1f - console.Comp.CapturingTime / console.Comp.CaptureTime) * 100f;
progress = progress != null ? float.Clamp(progress.Value, 0f, 100f) : null;
return progress;
}
}
[Prototype("outpostSpawn")]
// ReSharper disable once PartialTypeWithSinglePart Ридер глупи.
public sealed partial class OutpostSpawnPrototype : IPrototype
{
[IdDataField]
public string ID { get; } = null!;
[DataField("spawn")]
public List<EntitySpawnEntry> SpawnList = [];
}
#region Serializable
[Serializable, NetSerializable]
public sealed class OutpostUIState(float? progress, bool disabled, string labelState, string buttonState) : BoundUserInterfaceState
{
public float? Progress => progress;
public bool Disabled => disabled;
public string LabelState => labelState;
public string ButtonState => buttonState;
}
[Serializable, NetSerializable]
public sealed class OutpostCaptureButtonPressed : BoundUserInterfaceMessage;
[Serializable, NetSerializable]
public sealed class ProgressBarUpdate(float? value) : BoundUserInterfaceMessage
{
public float? Value = value;
}
[Serializable, NetSerializable]
public enum CaptureUIKey : byte
{
Key = 0,
}
#endregion