diff --git a/Content.Client/GameObjects/Components/HandheldLightComponent.cs b/Content.Client/GameObjects/Components/HandheldLightComponent.cs index 1c09818ae0..30c4edd40a 100644 --- a/Content.Client/GameObjects/Components/HandheldLightComponent.cs +++ b/Content.Client/GameObjects/Components/HandheldLightComponent.cs @@ -14,10 +14,9 @@ namespace Content.Client.GameObjects.Components [RegisterComponent] public sealed class HandheldLightComponent : SharedHandheldLightComponent, IItemStatus { - private bool _hasCell; + [ViewVariables] protected override bool HasCell => _level != null; - [ViewVariables] public float? Charge { get; private set; } - [ViewVariables] protected override bool HasCell => _hasCell; + private byte? _level; public Control MakeControl() { @@ -29,8 +28,7 @@ namespace Content.Client.GameObjects.Components if (!(curState is HandheldLightComponentState cast)) return; - Charge = cast.Charge; - _hasCell = cast.HasCell; + _level = cast.Charge; } private sealed class StatusControl : Control @@ -38,7 +36,7 @@ namespace Content.Client.GameObjects.Components private const float TimerCycle = 1; private readonly HandheldLightComponent _parent; - private readonly PanelContainer[] _sections = new PanelContainer[5]; + private readonly PanelContainer[] _sections = new PanelContainer[StatusLevels - 1]; private float _timer; @@ -76,40 +74,37 @@ namespace Content.Client.GameObjects.Components { base.Update(args); + if (!_parent.HasCell) + return; + _timer += args.DeltaSeconds; _timer %= TimerCycle; - var charge = _parent.Charge ?? 0; + var level = _parent._level; - int level; + for (var i = 0; i < _sections.Length; i++) + { + if (i == 0) + { + if (level == 0) + { + _sections[0].PanelOverride = _styleBoxUnlit; + } + else if (level == 1) + { + // Flash the last light. + _sections[0].PanelOverride = _timer > TimerCycle / 2 ? _styleBoxLit : _styleBoxUnlit; + } + else + { + _sections[0].PanelOverride = _styleBoxLit; + } - if (MathHelper.CloseTo(charge, 0)) - { - level = 0; - } - else - { - level = ContentHelpers.RoundToNearestLevels(charge, 1.0, 6) + 1; - } + continue; + } - if (level == 0) - { - _sections[0].PanelOverride = _styleBoxUnlit; + _sections[i].PanelOverride = level >= i + 2 ? _styleBoxLit : _styleBoxUnlit; } - else if (level == 1) - { - // Flash the last light. - _sections[0].PanelOverride = _timer > TimerCycle / 2 ? _styleBoxLit : _styleBoxUnlit; - } - else - { - _sections[0].PanelOverride = _styleBoxLit; - } - - _sections[1].PanelOverride = level >= 3 ? _styleBoxLit : _styleBoxUnlit; - _sections[2].PanelOverride = level >= 4 ? _styleBoxLit : _styleBoxUnlit; - _sections[3].PanelOverride = level >= 5 ? _styleBoxLit : _styleBoxUnlit; - _sections[4].PanelOverride = level >= 6 ? _styleBoxLit : _styleBoxUnlit; } } } diff --git a/Content.Client/GameObjects/Components/Power/PowerCellVisualizer.cs b/Content.Client/GameObjects/Components/Power/PowerCellVisualizer.cs index 408c09d7d6..0bd1ab8f2e 100644 --- a/Content.Client/GameObjects/Components/Power/PowerCellVisualizer.cs +++ b/Content.Client/GameObjects/Components/Power/PowerCellVisualizer.cs @@ -34,10 +34,10 @@ namespace Content.Client.GameObjects.Components.Power base.OnChangeData(component); var sprite = component.Owner.GetComponent(); - if (component.TryGetData(PowerCellVisuals.ChargeLevel, out float fraction)) + if (component.TryGetData(PowerCellVisuals.ChargeLevel, out byte level)) { - int level = ContentHelpers.RoundToNearestLevels(fraction, 1, 4) * 25; - sprite.LayerSetState(Layers.Charge, $"{_prefix}_{level}"); + var adjustedLevel = level * 25; + sprite.LayerSetState(Layers.Charge, $"{_prefix}_{adjustedLevel}"); } } diff --git a/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs b/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs index ea1492f14a..3774218410 100644 --- a/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs +++ b/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs @@ -7,12 +7,14 @@ using Content.Shared.GameObjects.Components; using Content.Shared.GameObjects.EntitySystems; using Content.Shared.Interfaces; using Content.Shared.Interfaces.GameObjects.Components; +using Content.Shared.Utility; using Robust.Server.GameObjects; using Robust.Server.GameObjects.EntitySystems; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Localization; +using Robust.Shared.Maths; using Robust.Shared.Serialization; using Robust.Shared.Utility; using Robust.Shared.ViewVariables; @@ -41,6 +43,11 @@ namespace Content.Server.GameObjects.Components.Interactable [ViewVariables(VVAccess.ReadWrite)] public string? TurnOnFailSound; [ViewVariables(VVAccess.ReadWrite)] public string? TurnOffSound; + /// + /// Client-side ItemStatus level + /// + private byte? _lastLevel; + public override void ExposeData(ObjectSerializer serializer) { base.ExposeData(serializer); @@ -190,24 +197,34 @@ namespace Content.Server.GameObjects.Components.Interactable } if (Activated && !Cell.TryUseCharge(Wattage * frameTime)) TurnOff(false); - Dirty(); + + var level = GetLevel(); + + if (level != _lastLevel) + { + _lastLevel = level; + Dirty(); + } + } + + // Curently every single flashlight has the same number of levels for status and that's all it uses the charge for + // Thus we'll just check if the level changes. + private byte? GetLevel() + { + if (Cell == null) + return null; + + var currentCharge = Cell.CurrentCharge; + + if (MathHelper.CloseTo(currentCharge, 0) || Wattage > currentCharge) + return 0; + + return (byte?) ContentHelpers.RoundToNearestLevels(currentCharge / Cell.MaxCharge * 255, 255, StatusLevels); } public override ComponentState GetComponentState() { - if (Cell == null) - { - return new HandheldLightComponentState(null, false); - } - - if (Wattage > Cell.CurrentCharge) - { - // Practically zero. - // This is so the item status works correctly. - return new HandheldLightComponentState(0, HasCell); - } - - return new HandheldLightComponentState(Cell.CurrentCharge / Cell.MaxCharge, HasCell); + return new HandheldLightComponentState(GetLevel()); } } } diff --git a/Content.Server/GameObjects/Components/Power/PowerCellComponent.cs b/Content.Server/GameObjects/Components/Power/PowerCellComponent.cs index 9241536250..8a16a7c7da 100644 --- a/Content.Server/GameObjects/Components/Power/PowerCellComponent.cs +++ b/Content.Server/GameObjects/Components/Power/PowerCellComponent.cs @@ -1,5 +1,6 @@ using Content.Shared.GameObjects.Components.Power; using Content.Shared.GameObjects.EntitySystems; +using Content.Shared.Utility; using Robust.Server.GameObjects; using Robust.Shared.GameObjects; using Robust.Shared.Localization; @@ -45,10 +46,15 @@ namespace Content.Server.GameObjects.Components.Power { if (Owner.TryGetComponent(out AppearanceComponent appearance)) { - appearance.SetData(PowerCellVisuals.ChargeLevel, CurrentCharge / MaxCharge); + appearance.SetData(PowerCellVisuals.ChargeLevel, GetLevel(CurrentCharge / MaxCharge)); } } + private byte GetLevel(float fraction) + { + return (byte) ContentHelpers.RoundToNearestLevels(fraction, 1, SharedPowerCell.PowerCellVisualsLevels); + } + void IExamine.Examine(FormattedMessage message, bool inDetailsRange) { if(inDetailsRange) diff --git a/Content.Shared/GameObjects/Components/Power/SharedPowerCell.cs b/Content.Shared/GameObjects/Components/Power/SharedPowerCell.cs index 22b932883a..d460a8dd3c 100644 --- a/Content.Shared/GameObjects/Components/Power/SharedPowerCell.cs +++ b/Content.Shared/GameObjects/Components/Power/SharedPowerCell.cs @@ -3,6 +3,11 @@ using Robust.Shared.Serialization; namespace Content.Shared.GameObjects.Components.Power { + public static class SharedPowerCell + { + public const int PowerCellVisualsLevels = 4; + } + [Serializable, NetSerializable] public enum PowerCellVisuals { diff --git a/Content.Shared/GameObjects/Components/SharedHandheldLightComponent.cs b/Content.Shared/GameObjects/Components/SharedHandheldLightComponent.cs index f6dd37fcef..085d6ca06c 100644 --- a/Content.Shared/GameObjects/Components/SharedHandheldLightComponent.cs +++ b/Content.Shared/GameObjects/Components/SharedHandheldLightComponent.cs @@ -11,18 +11,17 @@ namespace Content.Shared.GameObjects.Components protected abstract bool HasCell { get; } + protected const int StatusLevels = 6; + [Serializable, NetSerializable] protected sealed class HandheldLightComponentState : ComponentState { - public HandheldLightComponentState(float? charge, bool hasCell) : base(ContentNetIDs.HANDHELD_LIGHT) + public byte? Charge { get; } + + public HandheldLightComponentState(byte? charge) : base(ContentNetIDs.HANDHELD_LIGHT) { Charge = charge; - HasCell = hasCell; } - - public float? Charge { get; } - - public bool HasCell { get; } } }