mirror of
https://github.com/space-syndicate/space-station-14.git
synced 2026-02-15 00:54:51 +01:00
Изменение экрана КПБ во время раунда (#3342)
This commit is contained in:
76
Content.Client/Corvax/Ipc/IpcFaceMenu.cs
Normal file
76
Content.Client/Corvax/Ipc/IpcFaceMenu.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using Content.Shared.Corvax.Ipc;
|
||||
using Content.Shared.Humanoid.Markings;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.Corvax.Ipc;
|
||||
|
||||
public sealed class IpcFaceMenu : FancyWindow
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||
private readonly SpriteSystem _sprite;
|
||||
|
||||
private readonly ItemList _list;
|
||||
public event Action<string>? FaceSelected;
|
||||
private bool _suppressSelection;
|
||||
|
||||
public IpcFaceMenu()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
_sprite = _entMan.System<SpriteSystem>();
|
||||
|
||||
Title = Loc.GetString("ipc-face-menu-title");
|
||||
|
||||
MinSize = new Vector2(300, 400);
|
||||
|
||||
_list = new ItemList
|
||||
{
|
||||
VerticalExpand = true,
|
||||
HorizontalExpand = true
|
||||
};
|
||||
|
||||
_list.OnItemSelected += args =>
|
||||
{
|
||||
if (_suppressSelection)
|
||||
return;
|
||||
|
||||
if (_list[args.ItemIndex].Metadata is string id)
|
||||
FaceSelected?.Invoke(id);
|
||||
};
|
||||
|
||||
ContentsContainer.AddChild(_list);
|
||||
}
|
||||
|
||||
public void Populate(string profileId, string selected)
|
||||
{
|
||||
_suppressSelection = true;
|
||||
_list.Clear();
|
||||
var profile = _prototype.Index<IpcFaceProfilePrototype>(profileId);
|
||||
foreach (var face in profile.Faces)
|
||||
{
|
||||
if (!_prototype.TryIndex(face, out MarkingPrototype? marking) || marking.Sprites.Count == 0)
|
||||
continue;
|
||||
|
||||
if (marking.Sprites[0] is not SpriteSpecifier.Rsi rsi)
|
||||
continue;
|
||||
|
||||
var texture = _sprite.Frame0(rsi);
|
||||
var item = _list.AddItem(Loc.GetString($"marking-{marking.ID}"), texture);
|
||||
item.Metadata = marking.ID;
|
||||
|
||||
if (marking.ID == selected)
|
||||
item.Selected = true;
|
||||
}
|
||||
_suppressSelection = false;
|
||||
}
|
||||
}
|
||||
46
Content.Client/Corvax/Ipc/IpcFaceUserInterface.cs
Normal file
46
Content.Client/Corvax/Ipc/IpcFaceUserInterface.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using Content.Shared.Corvax.Ipc;
|
||||
using Robust.Client.GameObjects;
|
||||
using Content.Shared.UserInterface;
|
||||
|
||||
namespace Content.Client.Corvax.Ipc;
|
||||
|
||||
public sealed class IpcFaceUserInterface : BoundUserInterface
|
||||
{
|
||||
private IpcFaceMenu? _menu;
|
||||
|
||||
public IpcFaceUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
_menu = new IpcFaceMenu();
|
||||
_menu.OnClose += Close;
|
||||
_menu.FaceSelected += state =>
|
||||
{
|
||||
SendPredictedMessage(new IpcFaceSelectMessage(state));
|
||||
Close();
|
||||
};
|
||||
_menu.OpenCentered();
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState? state)
|
||||
{
|
||||
if (state != null)
|
||||
base.UpdateState(state);
|
||||
if (_menu == null || state is not IpcFaceBuiState msg)
|
||||
return;
|
||||
_menu.Populate(msg.Profile, msg.Selected);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (!disposing)
|
||||
return;
|
||||
_menu?.Dispose();
|
||||
_menu = null;
|
||||
}
|
||||
}
|
||||
@@ -12,11 +12,19 @@ using Content.Shared.Movement.Systems;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.Sound.Components;
|
||||
using Content.Shared.UserInterface;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Server.Humanoid;
|
||||
using Content.Shared.Humanoid.Markings;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Server.Corvax.Ipc;
|
||||
|
||||
public sealed class IpcSystem : EntitySystem
|
||||
public sealed partial class IpcSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedActionsSystem _action = default!;
|
||||
[Dependency] private readonly AlertsSystem _alerts = default!;
|
||||
@@ -26,9 +34,10 @@ public sealed class IpcSystem : EntitySystem
|
||||
[Dependency] private readonly DamageableSystem _damageable = default!;
|
||||
[Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifier = default!;
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
|
||||
|
||||
|
||||
[Dependency] private readonly SharedUserInterfaceSystem _ui = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly HumanoidAppearanceSystem _humanoid = default!;
|
||||
[Dependency] private readonly MarkingManager _markingManager = default!;
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -40,18 +49,33 @@ public sealed class IpcSystem : EntitySystem
|
||||
SubscribeLocalEvent<IpcComponent, EmpPulseEvent>(OnEmpPulse);
|
||||
SubscribeLocalEvent<IpcComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovementSpeedModifiers);
|
||||
SubscribeLocalEvent<IpcComponent, MobStateChangedEvent>(OnMobStateChanged);
|
||||
SubscribeLocalEvent<IpcComponent, OpenIpcFaceActionEvent>(OnOpenFaceAction);
|
||||
Subs.BuiEvents<IpcComponent>(IpcFaceUiKey.Face, subs =>
|
||||
{
|
||||
subs.Event<IpcFaceSelectMessage>(OnFaceSelected);
|
||||
});
|
||||
}
|
||||
|
||||
private void OnMapInit(EntityUid uid, IpcComponent component, MapInitEvent args)
|
||||
{
|
||||
UpdateBatteryAlert((uid, component));
|
||||
_action.AddAction(uid, ref component.ActionEntity, component.DrainBatteryAction);
|
||||
_action.AddAction(uid, ref component.ChangeFaceActionEntity, component.ChangeFaceAction);
|
||||
_movementSpeedModifier.RefreshMovementSpeedModifiers(uid);
|
||||
|
||||
if (TryComp<HumanoidAppearanceComponent>(uid, out var appearance) &&
|
||||
appearance.MarkingSet.TryGetCategory(MarkingCategories.Snout, out var markings) &&
|
||||
markings.Count > 0)
|
||||
{
|
||||
component.SelectedFace = markings[0].MarkingId;
|
||||
Dirty(uid, component);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnComponentShutdown(EntityUid uid, IpcComponent component, ComponentShutdown args)
|
||||
{
|
||||
_action.RemoveAction(uid, component.ActionEntity);
|
||||
_action.RemoveAction(uid, component.ChangeFaceActionEntity);
|
||||
}
|
||||
|
||||
private void OnPowerCellChanged(EntityUid uid, IpcComponent component, PowerCellChangedEvent args)
|
||||
@@ -90,7 +114,7 @@ public sealed class IpcSystem : EntitySystem
|
||||
if (!_powerCell.TryGetBatteryFromSlot(ent, out var battery, slot) || battery.CurrentCharge / battery.MaxCharge < 0.01f)
|
||||
{
|
||||
_alerts.ClearAlert(ent, ent.Comp.BatteryAlert);
|
||||
_alerts.ShowAlert(ent, ent.Comp.NoBatteryAlert);
|
||||
_alerts.ShowAlert(ent, ent.Comp.NoBatteryAlert);
|
||||
|
||||
_movementSpeedModifier.RefreshMovementSpeedModifiers(ent.Owner);
|
||||
return;
|
||||
@@ -116,6 +140,40 @@ public sealed class IpcSystem : EntitySystem
|
||||
}
|
||||
}
|
||||
|
||||
private void OnOpenFaceAction(EntityUid uid, IpcComponent comp, OpenIpcFaceActionEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if (!TryComp<ActorComponent>(uid, out var actor))
|
||||
return;
|
||||
|
||||
_ui.SetUiState(uid, IpcFaceUiKey.Face, new IpcFaceBuiState(comp.FaceProfile, comp.SelectedFace));
|
||||
_ui.TryToggleUi(uid, IpcFaceUiKey.Face, actor.PlayerSession);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnFaceSelected(Entity<IpcComponent> ent, ref IpcFaceSelectMessage msg)
|
||||
{
|
||||
if (TryComp<HumanoidAppearanceComponent>(ent.Owner, out var appearance))
|
||||
{
|
||||
var category = MarkingCategories.Snout;
|
||||
if (appearance.MarkingSet.TryGetCategory(category, out var markings) && markings.Count > 0)
|
||||
{
|
||||
_humanoid.SetMarkingId(ent.Owner, category, 0, msg.State, appearance);
|
||||
}
|
||||
else if (_markingManager.Markings.TryGetValue(msg.State, out var proto))
|
||||
{
|
||||
appearance.MarkingSet.AddBack(category, proto.AsMarking());
|
||||
Dirty(ent.Owner, appearance);
|
||||
}
|
||||
}
|
||||
|
||||
ent.Comp.SelectedFace = msg.State;
|
||||
Dirty(ent);
|
||||
_ui.CloseUi(ent.Owner, IpcFaceUiKey.Face);
|
||||
}
|
||||
|
||||
private void OnEmpPulse(EntityUid uid, IpcComponent component, ref EmpPulseEvent args)
|
||||
{
|
||||
args.Affected = true;
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace Content.Shared.Corvax.Ipc;
|
||||
/// This is used for...
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
[AutoGenerateComponentState]
|
||||
public sealed partial class IpcComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
@@ -20,9 +21,21 @@ public sealed partial class IpcComponent : Component
|
||||
[DataField]
|
||||
public EntProtoId DrainBatteryAction = "ActionDrainBattery";
|
||||
|
||||
[DataField]
|
||||
public EntProtoId ChangeFaceAction = "ActionIpcChangeFace";
|
||||
|
||||
[DataField]
|
||||
public EntityUid? ActionEntity;
|
||||
|
||||
[DataField]
|
||||
public EntityUid? ChangeFaceActionEntity;
|
||||
|
||||
[DataField, AutoNetworkedField]
|
||||
public string SelectedFace = string.Empty;
|
||||
|
||||
[DataField, AutoNetworkedField]
|
||||
public ProtoId<IpcFaceProfilePrototype> FaceProfile = "DefaultIpcFaces";
|
||||
|
||||
public bool DrainActivated;
|
||||
}
|
||||
|
||||
@@ -30,3 +43,7 @@ public sealed partial class ToggleDrainActionEvent : InstantActionEvent
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public sealed partial class OpenIpcFaceActionEvent : InstantActionEvent
|
||||
{
|
||||
}
|
||||
|
||||
32
Content.Shared/Corvax/Ipc/IpcFaceMenuMessages.cs
Normal file
32
Content.Shared/Corvax/Ipc/IpcFaceMenuMessages.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using Content.Shared.UserInterface;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Corvax.Ipc;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class IpcFaceSelectMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public readonly string State;
|
||||
public IpcFaceSelectMessage(string state)
|
||||
{
|
||||
State = state;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class IpcFaceBuiState : BoundUserInterfaceState
|
||||
{
|
||||
public readonly string Profile;
|
||||
public readonly string Selected;
|
||||
public IpcFaceBuiState(string profile, string selected)
|
||||
{
|
||||
Profile = profile;
|
||||
Selected = selected;
|
||||
}
|
||||
}
|
||||
|
||||
[NetSerializable, Serializable]
|
||||
public enum IpcFaceUiKey : byte
|
||||
{
|
||||
Face
|
||||
}
|
||||
21
Content.Shared/Corvax/Ipc/IpcFaceProfilePrototype.cs
Normal file
21
Content.Shared/Corvax/Ipc/IpcFaceProfilePrototype.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
using Content.Shared.Humanoid.Markings;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Shared.Corvax.Ipc;
|
||||
|
||||
/// <summary>
|
||||
/// Prototype defining a collection of IPC face sprites.
|
||||
/// </summary>
|
||||
[Prototype("ipcFaceProfile")]
|
||||
public sealed partial class IpcFaceProfilePrototype : IPrototype
|
||||
{
|
||||
[IdDataField]
|
||||
public string ID { get; private set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Available face markings for this profile.
|
||||
/// </summary>
|
||||
[DataField("faces", required: true)]
|
||||
public List<ProtoId<MarkingPrototype>> Faces { get; private set; } = new();
|
||||
}
|
||||
3
Resources/Locale/en-US/corvax/ipc/ipc.ftl
Normal file
3
Resources/Locale/en-US/corvax/ipc/ipc.ftl
Normal file
@@ -0,0 +1,3 @@
|
||||
ipc-component-ready = Ready to drain
|
||||
ipc-component-disabled = Battery charging disabled.
|
||||
ipc-face-menu-title = IPC monitor
|
||||
32
Resources/Locale/en-US/corvax/markings/ipc.ftl
Normal file
32
Resources/Locale/en-US/corvax/markings/ipc.ftl
Normal file
@@ -0,0 +1,32 @@
|
||||
marking-BreakoutS = Breakout
|
||||
marking-NatureS = Nature
|
||||
marking-EightS = Eight
|
||||
marking-OrangeHespAltS = Orange (Hesp alt.)
|
||||
marking-PinkHespAltS = Pink (Hesp alt.)
|
||||
marking-SmokingS = Smoking
|
||||
marking-RainbowS = Rainbow
|
||||
marking-HeartS = Heart
|
||||
marking-ScrollS = Scroll
|
||||
marking-ScrollHespAltS = Scroll (Hesp alt.)
|
||||
marking-StaticS = Static
|
||||
marking-GreenS = Green
|
||||
marking-YellowS = Yellow
|
||||
marking-GolGliderS = Gold glider
|
||||
marking-RgbHespAltS = RGB (Hesp alt.)
|
||||
marking-GogglesHespAltS = Goggles (Hesp alt.)
|
||||
marking-OffHespAltS = Off (Hesp alt.)
|
||||
marking-PinkS = Pink
|
||||
marking-RedS = Red
|
||||
marking-ShowerS = Shower
|
||||
marking-RainbowHespAltS = Rainbow (Hesp alt.)
|
||||
marking-GogglesS = Goggles
|
||||
marking-MonoeyeS = Mono-eye
|
||||
marking-BlueS = Blue
|
||||
marking-TestS = Test
|
||||
marking-RgbS = RGB
|
||||
marking-MusicS = Music
|
||||
marking-ConsoleS = Console
|
||||
marking-PurpleS = Purple
|
||||
marking-OrangeS = Orange
|
||||
marking-WaitingS = Waiting
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
ent-ActionDrainBattery = Drain battery
|
||||
.desc = Drain battery
|
||||
ent-ActionIpcChangeFace = Change face
|
||||
.desc = Change the IPC monitor face
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
ipc-component-ready = Готов к разрядке
|
||||
ipc-component-disabled = Зарядка батареи отключена.
|
||||
ipc-face-menu-title = Выбор экрана
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
ent-ActionDrainBattery = Включить заряд
|
||||
.desc = Разрядить батарею
|
||||
ent-ActionIpcChangeFace = Сменить экран
|
||||
.desc = Изменить экран КПБ
|
||||
|
||||
@@ -9,3 +9,14 @@
|
||||
itemIconStyle: NoItem
|
||||
- type: InstantAction
|
||||
event: !type:ToggleDrainActionEvent
|
||||
|
||||
- type: entity
|
||||
id: ActionIpcChangeFace
|
||||
name: Change face
|
||||
description: Change the IPC monitor face
|
||||
components:
|
||||
- type: Action
|
||||
icon: { sprite: Interface/Actions/actions_ai.rsi, state: crew_monitor }
|
||||
itemIconStyle: NoItem
|
||||
- type: InstantAction
|
||||
event: !type:OpenIpcFaceActionEvent
|
||||
|
||||
@@ -337,6 +337,8 @@
|
||||
type: HumanoidMarkingModifierBoundUserInterface
|
||||
enum.StrippingUiKey.Key:
|
||||
type: StrippableBoundUserInterface
|
||||
enum.IpcFaceUiKey.Face:
|
||||
type: IpcFaceUserInterface
|
||||
- type: Puller
|
||||
- type: Speech
|
||||
speechSounds: Alto
|
||||
@@ -383,7 +385,6 @@
|
||||
normalBodyTemperature: 310.15
|
||||
thermalRegulationTemperatureThreshold: 2
|
||||
|
||||
|
||||
- type: entity
|
||||
save: false
|
||||
name: Urist McHands
|
||||
|
||||
35
Resources/Prototypes/Corvax/Ipc/ipc_face_profiles.yml
Normal file
35
Resources/Prototypes/Corvax/Ipc/ipc_face_profiles.yml
Normal file
@@ -0,0 +1,35 @@
|
||||
- type: ipcFaceProfile
|
||||
id: DefaultIpcFaces
|
||||
faces:
|
||||
- BreakoutS
|
||||
- NatureS
|
||||
- EightS
|
||||
- OrangeHespAltS
|
||||
- PinkHespAltS
|
||||
- SmokingS
|
||||
- RainbowS
|
||||
- HeartS
|
||||
- ScrollS
|
||||
- ScrollHespAltS
|
||||
- StaticS
|
||||
- GreenS
|
||||
- YellowS
|
||||
- GolGliderS
|
||||
- RgbHespAltS
|
||||
- GogglesHespAltS
|
||||
- OffHespAltS
|
||||
- PinkS
|
||||
- RedS
|
||||
- ShowerS
|
||||
- RainbowHespAltS
|
||||
- GogglesS
|
||||
- MonoeyeS
|
||||
- BlueS
|
||||
- TestS
|
||||
- RgbS
|
||||
- MusicS
|
||||
- ConsoleS
|
||||
- PurpleS
|
||||
- OrangeS
|
||||
- WaitingS
|
||||
|
||||
Reference in New Issue
Block a user