Merge branch 'master' into 20-06-24-movement-prediction
This commit is contained in:
@@ -95,6 +95,9 @@ namespace Content.Client.GameObjects.Components.Doors
|
||||
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
if (component.Owner.Deleted)
|
||||
return;
|
||||
|
||||
var sprite = component.Owner.GetComponent<ISpriteComponent>();
|
||||
var animPlayer = component.Owner.GetComponent<AnimationPlayerComponent>();
|
||||
if (!component.TryGetData(DoorVisuals.VisualState, out DoorVisualState state))
|
||||
|
||||
@@ -203,31 +203,30 @@ namespace Content.Client.GameObjects
|
||||
buttonDict.Add(slot, button);
|
||||
}
|
||||
|
||||
const int size = ButtonSize;
|
||||
const int sep = ButtonSeparation;
|
||||
const int rSep = RightSeparation;
|
||||
const int sizep = (ButtonSize + ButtonSeparation);
|
||||
|
||||
// Left column.
|
||||
AddButton(Slots.EYES, "glasses", (0, size + sep));
|
||||
AddButton(Slots.INNERCLOTHING, "uniform", (0, 2 * (size + sep)));
|
||||
AddButton(Slots.EXOSUITSLOT1, "suit_storage", (0, 3 * (size + sep)));
|
||||
AddButton(Slots.EYES, "glasses", (0, 0));
|
||||
AddButton(Slots.NECK, "neck", (0, sizep));
|
||||
AddButton(Slots.INNERCLOTHING, "uniform", (0, 2 * sizep));
|
||||
|
||||
// Middle column.
|
||||
AddButton(Slots.HEAD, "head", (size + sep, 0));
|
||||
AddButton(Slots.MASK, "mask", (size + sep, size + sep));
|
||||
AddButton(Slots.OUTERCLOTHING, "suit", (size + sep, 2 * (size + sep)));
|
||||
AddButton(Slots.SHOES, "shoes", (size + sep, 3 * (size + sep)));
|
||||
AddButton(Slots.HEAD, "head", (sizep, 0));
|
||||
AddButton(Slots.MASK, "mask", (sizep, sizep));
|
||||
AddButton(Slots.OUTERCLOTHING, "suit", (sizep, 2 * sizep));
|
||||
AddButton(Slots.SHOES, "shoes", (sizep, 3 * sizep));
|
||||
|
||||
// Right column
|
||||
AddButton(Slots.EARS, "ears", (2 * (size + sep), 0));
|
||||
AddButton(Slots.IDCARD, "id", (2 * (size + sep), size + sep));
|
||||
AddButton(Slots.GLOVES, "gloves", (2 * (size + sep), 2 * (size + sep)));
|
||||
AddButton(Slots.EARS, "ears", (2 * sizep, 0));
|
||||
AddButton(Slots.IDCARD, "id", (2 * sizep, sizep));
|
||||
AddButton(Slots.EXOSUITSLOT1, "suit_storage", (2 * sizep, 2 * sizep));
|
||||
AddButton(Slots.POCKET1, "pocket", (2 * sizep, 3 * sizep));
|
||||
|
||||
// Far right column.
|
||||
AddButton(Slots.BACKPACK, "back", (rSep + 3 * (size + sep), 0));
|
||||
AddButton(Slots.BELT, "belt", (rSep + 3 * (size + sep), size + sep));
|
||||
AddButton(Slots.POCKET1, "pocket", (rSep + 3 * (size + sep), 2 * (size + sep)));
|
||||
AddButton(Slots.POCKET2, "pocket", (rSep + 3 * (size + sep), 3 * (size + sep)));
|
||||
AddButton(Slots.BACKPACK, "back", (3 * sizep, 0));
|
||||
AddButton(Slots.BELT, "belt", (3 * sizep, sizep));
|
||||
AddButton(Slots.GLOVES, "gloves", (3 * sizep, 2 * sizep));
|
||||
AddButton(Slots.POCKET2, "pocket", (3 * sizep, 3 * sizep));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace Content.Client.GameObjects
|
||||
|
||||
public IEntity GetEntity(string index)
|
||||
{
|
||||
if (_hands.TryGetValue(index, out var entity))
|
||||
if (!string.IsNullOrEmpty(index) && _hands.TryGetValue(index, out var entity))
|
||||
{
|
||||
return entity;
|
||||
}
|
||||
@@ -166,6 +166,8 @@ namespace Content.Client.GameObjects
|
||||
{
|
||||
_hands.Add(slot, null);
|
||||
}
|
||||
|
||||
serializer.DataField(this, x => ActiveIndex, "defaultHand", _hands.Keys.LastOrDefault());
|
||||
}
|
||||
|
||||
public override void HandleMessage(ComponentMessage message, IComponent component)
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using Content.Shared.GameObjects.Components.Weapons;
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
using Robust.Client.Graphics.Overlays;
|
||||
using Robust.Client.Interfaces.Graphics;
|
||||
using Robust.Client.Interfaces.Graphics.Overlays;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.Timing;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
using Timer = Robust.Shared.Timers.Timer;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Weapons
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed class ClientFlashableComponent : SharedFlashableComponent
|
||||
{
|
||||
private CancellationTokenSource _cancelToken;
|
||||
private TimeSpan _startTime;
|
||||
private double _duration;
|
||||
private FlashOverlay _overlay;
|
||||
|
||||
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
|
||||
{
|
||||
if (curState == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var playerManager = IoCManager.Resolve<IPlayerManager>();
|
||||
if (playerManager.LocalPlayer.ControlledEntity != Owner)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var newState = (FlashComponentState) curState;
|
||||
if (newState.Time == default)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Few things here:
|
||||
// 1. If a shorter duration flash is applied then don't do anything
|
||||
// 2. If the client-side time is later than when the flash should've ended don't do anything
|
||||
var currentTime = IoCManager.Resolve<IGameTiming>().CurTime.TotalSeconds;
|
||||
var newEndTime = newState.Time.TotalSeconds + newState.Duration;
|
||||
var currentEndTime = _startTime.TotalSeconds + _duration;
|
||||
|
||||
if (currentEndTime > newEndTime)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentTime > newEndTime)
|
||||
{
|
||||
DisableOverlay();
|
||||
return;
|
||||
}
|
||||
|
||||
_startTime = newState.Time;
|
||||
_duration = newState.Duration;
|
||||
|
||||
EnableOverlay(newEndTime - currentTime);
|
||||
}
|
||||
|
||||
private void EnableOverlay(double duration)
|
||||
{
|
||||
// If the timer gets reset
|
||||
if (_overlay != null)
|
||||
{
|
||||
_overlay.Duration = _duration;
|
||||
_overlay.StartTime = _startTime;
|
||||
_cancelToken.Cancel();
|
||||
}
|
||||
else
|
||||
{
|
||||
var overlayManager = IoCManager.Resolve<IOverlayManager>();
|
||||
_overlay = new FlashOverlay(_duration);
|
||||
overlayManager.AddOverlay(_overlay);
|
||||
}
|
||||
|
||||
_cancelToken = new CancellationTokenSource();
|
||||
Timer.Spawn((int) duration * 1000, DisableOverlay, _cancelToken.Token);
|
||||
}
|
||||
|
||||
private void DisableOverlay()
|
||||
{
|
||||
if (_overlay == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var overlayManager = IoCManager.Resolve<IOverlayManager>();
|
||||
overlayManager.RemoveOverlay(_overlay.ID);
|
||||
_overlay = null;
|
||||
_cancelToken.Cancel();
|
||||
_cancelToken = null;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class FlashOverlay : Overlay
|
||||
{
|
||||
public override OverlaySpace Space => OverlaySpace.ScreenSpace;
|
||||
private readonly IGameTiming _timer;
|
||||
private readonly IClyde _displayManager;
|
||||
public TimeSpan StartTime { get; set; }
|
||||
public double Duration { get; set; }
|
||||
public FlashOverlay(double duration) : base(nameof(FlashOverlay))
|
||||
{
|
||||
_timer = IoCManager.Resolve<IGameTiming>();
|
||||
_displayManager = IoCManager.Resolve<IClyde>();
|
||||
StartTime = _timer.CurTime;
|
||||
Duration = duration;
|
||||
}
|
||||
|
||||
protected override void Draw(DrawingHandleBase handle)
|
||||
{
|
||||
var elapsedTime = (_timer.CurTime - StartTime).TotalSeconds;
|
||||
if (elapsedTime > Duration)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var screenHandle = (DrawingHandleScreen) handle;
|
||||
|
||||
screenHandle.DrawRect(
|
||||
new UIBox2(0.0f, 0.0f, _displayManager.ScreenSize.X, _displayManager.ScreenSize.Y),
|
||||
Color.White.WithAlpha(GetAlpha(elapsedTime / Duration))
|
||||
);
|
||||
}
|
||||
|
||||
private float GetAlpha(double ratio)
|
||||
{
|
||||
// Ideally you just want a smooth slope to finish it so it's not jarring at the end
|
||||
// By all means put in a better curve
|
||||
const float slope = -9.0f;
|
||||
const float exponent = 0.1f;
|
||||
const float yOffset = 9.0f;
|
||||
const float xOffset = 0.0f;
|
||||
|
||||
// Overkill but easy to adjust if you want to mess around with the design
|
||||
var result = (float) Math.Clamp(slope * (float) Math.Pow(ratio - xOffset, exponent) + yOffset, 0.0, 1.0);
|
||||
DebugTools.Assert(!float.IsNaN(result));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
using Content.Shared.GameObjects.Components.Weapons.Ranged;
|
||||
using Content.Shared.Utility;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.Utility;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Weapons.Ranged
|
||||
{
|
||||
public sealed class BallisticMagazineVisualizer2D : AppearanceVisualizer
|
||||
{
|
||||
private string _baseState;
|
||||
private int _steps;
|
||||
|
||||
public override void LoadData(YamlMappingNode node)
|
||||
{
|
||||
base.LoadData(node);
|
||||
|
||||
_baseState = node.GetNode("base_state").AsString();
|
||||
_steps = node.GetNode("steps").AsInt();
|
||||
}
|
||||
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
var sprite = component.Owner.GetComponent<ISpriteComponent>();
|
||||
|
||||
if (!component.TryGetData(BallisticMagazineVisuals.AmmoCapacity, out int capacity))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!component.TryGetData(BallisticMagazineVisuals.AmmoLeft, out int current))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var step = ContentHelpers.RoundToLevels(current, capacity, _steps);
|
||||
|
||||
sprite.LayerSetState(0, $"{_baseState}-{step}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
using Content.Shared.GameObjects.Components.Weapons.Ranged;
|
||||
using Content.Shared.Utility;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.Utility;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Weapons.Ranged
|
||||
{
|
||||
public sealed class BallisticMagazineWeaponVisualizer2D : AppearanceVisualizer
|
||||
{
|
||||
private string _baseState;
|
||||
private int _steps;
|
||||
|
||||
public override void LoadData(YamlMappingNode node)
|
||||
{
|
||||
base.LoadData(node);
|
||||
|
||||
_baseState = node.GetNode("base_state").AsString();
|
||||
_steps = node.GetNode("steps").AsInt();
|
||||
}
|
||||
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
var sprite = component.Owner.GetComponent<ISpriteComponent>();
|
||||
|
||||
component.TryGetData(BallisticMagazineWeaponVisuals.MagazineLoaded, out bool loaded);
|
||||
|
||||
if (loaded)
|
||||
{
|
||||
if (!component.TryGetData(BallisticMagazineWeaponVisuals.AmmoCapacity, out int capacity))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!component.TryGetData(BallisticMagazineWeaponVisuals.AmmoLeft, out int current))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// capacity is - 1 as normally a bullet is chambered so max state is virtually never hit.
|
||||
var step = ContentHelpers.RoundToLevels(current, capacity - 1, _steps);
|
||||
sprite.LayerSetState(0, $"{_baseState}-{step}");
|
||||
}
|
||||
else
|
||||
{
|
||||
sprite.LayerSetState(0, _baseState);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,26 @@
|
||||
using System;
|
||||
using System;
|
||||
using Content.Client.Animations;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Client.UserInterface.Stylesheets;
|
||||
using Content.Client.Utility;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.GameObjects.Components.Weapons.Ranged;
|
||||
using Content.Shared.GameObjects.Components.Weapons.Ranged.Barrels;
|
||||
using Robust.Client.Animations;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Animations;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using static Content.Client.StaticIoC;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Weapons.Ranged
|
||||
namespace Content.Client.GameObjects.Components.Weapons.Ranged.Barrels
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class BallisticMagazineWeaponComponent : Component, IItemStatus
|
||||
public class ClientMagazineBarrelComponent : Component, IItemStatus
|
||||
{
|
||||
private static readonly Animation AlarmAnimationSmg = new Animation
|
||||
{
|
||||
@@ -70,8 +68,8 @@ namespace Content.Client.GameObjects.Components.Weapons.Ranged
|
||||
}
|
||||
};
|
||||
|
||||
public override string Name => "BallisticMagazineWeapon";
|
||||
public override uint? NetID => ContentNetIDs.BALLISTIC_MAGAZINE_WEAPON;
|
||||
public override string Name => "MagazineBarrel";
|
||||
public override uint? NetID => ContentNetIDs.MAGAZINE_BARREL;
|
||||
|
||||
private StatusControl _statusControl;
|
||||
|
||||
@@ -101,11 +99,11 @@ namespace Content.Client.GameObjects.Components.Weapons.Ranged
|
||||
|
||||
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
|
||||
{
|
||||
if (!(curState is BallisticMagazineWeaponComponentState cast))
|
||||
if (!(curState is MagazineBarrelComponentState cast))
|
||||
return;
|
||||
|
||||
Chambered = cast.Chambered;
|
||||
MagazineCount = cast.MagazineCount;
|
||||
MagazineCount = cast.Magazine;
|
||||
_statusControl?.Update();
|
||||
}
|
||||
|
||||
@@ -115,7 +113,8 @@ namespace Content.Client.GameObjects.Components.Weapons.Ranged
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case BmwComponentAutoEjectedMessage _:
|
||||
|
||||
case MagazineAutoEjectMessage _:
|
||||
_statusControl?.PlayAlarmAnimation();
|
||||
return;
|
||||
}
|
||||
@@ -138,13 +137,13 @@ namespace Content.Client.GameObjects.Components.Weapons.Ranged
|
||||
|
||||
private sealed class StatusControl : Control
|
||||
{
|
||||
private readonly BallisticMagazineWeaponComponent _parent;
|
||||
private readonly ClientMagazineBarrelComponent _parent;
|
||||
private readonly HBoxContainer _bulletsListTop;
|
||||
private readonly HBoxContainer _bulletsListBottom;
|
||||
private readonly TextureRect _chamberedBullet;
|
||||
private readonly Label _noMagazineLabel;
|
||||
|
||||
public StatusControl(BallisticMagazineWeaponComponent parent)
|
||||
public StatusControl(ClientMagazineBarrelComponent parent)
|
||||
{
|
||||
_parent = parent;
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand;
|
||||
@@ -181,7 +180,7 @@ namespace Content.Client.GameObjects.Components.Weapons.Ranged
|
||||
},
|
||||
(_chamberedBullet = new TextureRect
|
||||
{
|
||||
Texture = ResC.GetTexture("/Textures/UserInterface/status/bullets/chambered.png"),
|
||||
Texture = StaticIoC.ResC.GetTexture("/Textures/UserInterface/status/bullets/chambered.png"),
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter,
|
||||
SizeFlagsHorizontal = SizeFlags.ShrinkEnd | SizeFlags.Fill,
|
||||
})
|
||||
@@ -223,7 +222,7 @@ namespace Content.Client.GameObjects.Components.Weapons.Ranged
|
||||
texturePath = "/Textures/UserInterface/status/bullets/tiny.png";
|
||||
}
|
||||
|
||||
var texture = ResC.GetTexture(texturePath);
|
||||
var texture = StaticIoC.ResC.GetTexture(texturePath);
|
||||
|
||||
const int tinyMaxRow = 60;
|
||||
|
||||
@@ -282,4 +281,4 @@ namespace Content.Client.GameObjects.Components.Weapons.Ranged
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using Content.Shared.GameObjects.Components.Weapons.Ranged.Barrels;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Weapons.Ranged.Barrels.Visualizers
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed class BarrelBoltVisualizer2D : AppearanceVisualizer
|
||||
{
|
||||
public override void InitializeEntity(IEntity entity)
|
||||
{
|
||||
base.InitializeEntity(entity);
|
||||
var sprite = entity.GetComponent<ISpriteComponent>();
|
||||
sprite.LayerSetState(RangedBarrelVisualLayers.Bolt, $"bolt-open");
|
||||
}
|
||||
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
var sprite = component.Owner.GetComponent<ISpriteComponent>();
|
||||
|
||||
if (!component.TryGetData(BarrelBoltVisuals.BoltOpen, out bool boltOpen))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (boltOpen)
|
||||
{
|
||||
sprite.LayerSetState(RangedBarrelVisualLayers.Bolt, "bolt-open");
|
||||
}
|
||||
else
|
||||
{
|
||||
sprite.LayerSetState(RangedBarrelVisualLayers.Bolt, "bolt-closed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
using Content.Shared.GameObjects.Components.Weapons.Ranged.Barrels;
|
||||
using Content.Shared.Utility;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Utility;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Weapons.Ranged.Barrels.Visualizers
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed class MagVisualizer2D : AppearanceVisualizer
|
||||
{
|
||||
private bool _magLoaded;
|
||||
private string _magState;
|
||||
private int _magSteps;
|
||||
private bool _zeroVisible;
|
||||
|
||||
public override void LoadData(YamlMappingNode node)
|
||||
{
|
||||
base.LoadData(node);
|
||||
_magState = node.GetNode("magState").AsString();
|
||||
_magSteps = node.GetNode("steps").AsInt();
|
||||
_zeroVisible = node.GetNode("zeroVisible").AsBool();
|
||||
}
|
||||
|
||||
public override void InitializeEntity(IEntity entity)
|
||||
{
|
||||
base.InitializeEntity(entity);
|
||||
var sprite = entity.GetComponent<ISpriteComponent>();
|
||||
|
||||
if (sprite.LayerMapTryGet(RangedBarrelVisualLayers.Mag, out _))
|
||||
{
|
||||
sprite.LayerSetState(RangedBarrelVisualLayers.Mag, $"{_magState}-{_magSteps-1}");
|
||||
sprite.LayerSetVisible(RangedBarrelVisualLayers.Mag, false);
|
||||
}
|
||||
|
||||
if (sprite.LayerMapTryGet(RangedBarrelVisualLayers.MagUnshaded, out _))
|
||||
{
|
||||
sprite.LayerSetState(RangedBarrelVisualLayers.MagUnshaded, $"{_magState}-unshaded-{_magSteps-1}");
|
||||
sprite.LayerSetVisible(RangedBarrelVisualLayers.MagUnshaded, false);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
// tl;dr
|
||||
// 1.If no mag then hide it OR
|
||||
// 2. If step 0 isn't visible then hide it (mag or unshaded)
|
||||
// 3. Otherwise just do mag / unshaded as is
|
||||
var sprite = component.Owner.GetComponent<ISpriteComponent>();
|
||||
|
||||
component.TryGetData(MagazineBarrelVisuals.MagLoaded, out _magLoaded);
|
||||
|
||||
if (_magLoaded)
|
||||
{
|
||||
if (!component.TryGetData(AmmoVisuals.AmmoMax, out int capacity))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!component.TryGetData(AmmoVisuals.AmmoCount, out int current))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var step = ContentHelpers.RoundToLevels(current, capacity, _magSteps);
|
||||
|
||||
if (step == 0 && !_zeroVisible)
|
||||
{
|
||||
if (sprite.LayerMapTryGet(RangedBarrelVisualLayers.Mag, out _))
|
||||
{
|
||||
sprite.LayerSetVisible(RangedBarrelVisualLayers.Mag, false);
|
||||
}
|
||||
|
||||
if (sprite.LayerMapTryGet(RangedBarrelVisualLayers.MagUnshaded, out _))
|
||||
{
|
||||
sprite.LayerSetVisible(RangedBarrelVisualLayers.MagUnshaded, false);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (sprite.LayerMapTryGet(RangedBarrelVisualLayers.Mag, out _))
|
||||
{
|
||||
sprite.LayerSetVisible(RangedBarrelVisualLayers.Mag, true);
|
||||
sprite.LayerSetState(RangedBarrelVisualLayers.Mag, $"{_magState}-{step}");
|
||||
}
|
||||
|
||||
if (sprite.LayerMapTryGet(RangedBarrelVisualLayers.MagUnshaded, out _))
|
||||
{
|
||||
sprite.LayerSetVisible(RangedBarrelVisualLayers.MagUnshaded, true);
|
||||
sprite.LayerSetState(RangedBarrelVisualLayers.MagUnshaded, $"{_magState}-unshaded-{step}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sprite.LayerMapTryGet(RangedBarrelVisualLayers.Mag, out _))
|
||||
{
|
||||
sprite.LayerSetVisible(RangedBarrelVisualLayers.Mag, false);
|
||||
}
|
||||
|
||||
if (sprite.LayerMapTryGet(RangedBarrelVisualLayers.MagUnshaded, out _))
|
||||
{
|
||||
sprite.LayerSetVisible(RangedBarrelVisualLayers.MagUnshaded, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using Content.Shared.GameObjects.Components.Weapons.Ranged.Barrels;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Weapons.Ranged.Barrels.Visualizers
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed class SpentAmmoVisualizer2D : AppearanceVisualizer
|
||||
{
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
base.OnChangeData(component);
|
||||
var sprite = component.Owner.GetComponent<ISpriteComponent>();
|
||||
|
||||
if (!component.TryGetData(AmmoVisuals.Spent, out bool spent))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
sprite.LayerSetState(AmmoVisualLayers.Base, spent ? "spent" : "base");
|
||||
}
|
||||
}
|
||||
|
||||
public enum AmmoVisualLayers
|
||||
{
|
||||
Base,
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,35 @@ using Robust.Shared.Map;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Weapons.Ranged
|
||||
{
|
||||
// Yeah I put it all in the same enum, don't judge me
|
||||
public enum RangedBarrelVisualLayers
|
||||
{
|
||||
Base,
|
||||
BaseUnshaded,
|
||||
Bolt,
|
||||
Mag,
|
||||
MagUnshaded,
|
||||
}
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed class ClientRangedWeaponComponent : SharedRangedWeaponComponent
|
||||
{
|
||||
public FireRateSelector FireRateSelector { get; private set; } = FireRateSelector.Safety;
|
||||
|
||||
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
|
||||
{
|
||||
base.HandleComponentState(curState, nextState);
|
||||
if (!(curState is RangedWeaponComponentState rangedState))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FireRateSelector = rangedState.FireRateSelector;
|
||||
}
|
||||
|
||||
public void SyncFirePos(GridCoordinates worldPos)
|
||||
{
|
||||
SendNetworkMessage(new SyncFirePosMessage(worldPos));
|
||||
SendNetworkMessage(new FirePosComponentMessage(worldPos));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
using Content.Shared.GameObjects.Components.Power;
|
||||
using Content.Shared.Utility;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.Utility;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Power
|
||||
{
|
||||
public class HitscanWeaponVisualizer2D : AppearanceVisualizer
|
||||
{
|
||||
private string _prefix;
|
||||
|
||||
public override void LoadData(YamlMappingNode node)
|
||||
{
|
||||
base.LoadData(node);
|
||||
|
||||
_prefix = node.GetNode("prefix").AsString();
|
||||
}
|
||||
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
base.OnChangeData(component);
|
||||
|
||||
var sprite = component.Owner.GetComponent<ISpriteComponent>();
|
||||
if (component.TryGetData(PowerCellVisuals.ChargeLevel, out float fraction))
|
||||
{
|
||||
sprite.LayerSetState(0, $"{_prefix}_{ContentHelpers.RoundToLevels(fraction, 1, 5) * 25}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user