Files
tbd-station-14/Content.Client/GameObjects/Components/Weapons/Ranged/Barrels/ClientMagazineBarrelComponent.cs
Exp 56ebde7f45 Add IItemStatus to some weapon types (#1879)
* Bolt Action

* Shotguns

* Revolver + Outline

* In Magazines: show bullets as numbers plus the usual bullet stuff

* Empty bullets have another texture
2020-08-24 13:13:26 +02:00

272 lines
10 KiB
C#

using System;
using Content.Client.Animations;
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.Network;
using Robust.Shared.Maths;
using Robust.Shared.Players;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
namespace Content.Client.GameObjects.Components.Weapons.Ranged.Barrels
{
[RegisterComponent]
public class ClientMagazineBarrelComponent : Component, IItemStatus
{
private static readonly Animation AlarmAnimationSmg = new Animation
{
Length = TimeSpan.FromSeconds(1.4),
AnimationTracks =
{
new AnimationTrackControlProperty
{
// These timings match the SMG audio file.
Property = nameof(Label.FontColorOverride),
InterpolationMode = AnimationInterpolationMode.Previous,
KeyFrames =
{
new AnimationTrackProperty.KeyFrame(Color.Red, 0.1f),
new AnimationTrackProperty.KeyFrame(null, 0.3f),
new AnimationTrackProperty.KeyFrame(Color.Red, 0.2f),
new AnimationTrackProperty.KeyFrame(null, 0.3f),
new AnimationTrackProperty.KeyFrame(Color.Red, 0.2f),
new AnimationTrackProperty.KeyFrame(null, 0.3f),
}
}
}
};
private static readonly Animation AlarmAnimationLmg = new Animation
{
Length = TimeSpan.FromSeconds(0.75),
AnimationTracks =
{
new AnimationTrackControlProperty
{
// These timings match the SMG audio file.
Property = nameof(Label.FontColorOverride),
InterpolationMode = AnimationInterpolationMode.Previous,
KeyFrames =
{
new AnimationTrackProperty.KeyFrame(Color.Red, 0.0f),
new AnimationTrackProperty.KeyFrame(null, 0.15f),
new AnimationTrackProperty.KeyFrame(Color.Red, 0.15f),
new AnimationTrackProperty.KeyFrame(null, 0.15f),
new AnimationTrackProperty.KeyFrame(Color.Red, 0.15f),
new AnimationTrackProperty.KeyFrame(null, 0.15f),
}
}
}
};
public override string Name => "MagazineBarrel";
public override uint? NetID => ContentNetIDs.MAGAZINE_BARREL;
private StatusControl _statusControl;
/// <summary>
/// True if a bullet is chambered.
/// </summary>
[ViewVariables]
public bool Chambered { get; private set; }
/// <summary>
/// Count of bullets in the magazine.
/// </summary>
/// <remarks>
/// Null if no magazine is inserted.
/// </remarks>
[ViewVariables]
public (int count, int max)? MagazineCount { get; private set; }
[ViewVariables(VVAccess.ReadWrite)] private bool _isLmgAlarmAnimation;
public override void ExposeData(ObjectSerializer serializer)
{
base.ExposeData(serializer);
serializer.DataField(ref _isLmgAlarmAnimation, "lmg_alarm_animation", false);
}
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
{
if (!(curState is MagazineBarrelComponentState cast))
return;
Chambered = cast.Chambered;
MagazineCount = cast.Magazine;
_statusControl?.Update();
}
public override void HandleNetworkMessage(ComponentMessage message, INetChannel channel, ICommonSession session = null)
{
base.HandleNetworkMessage(message, channel, session);
switch (message)
{
case MagazineAutoEjectMessage _:
_statusControl?.PlayAlarmAnimation();
return;
}
}
public Control MakeControl()
{
_statusControl = new StatusControl(this);
_statusControl.Update();
return _statusControl;
}
public void DestroyControl(Control control)
{
if (_statusControl == control)
{
_statusControl = null;
}
}
private sealed class StatusControl : Control
{
private readonly ClientMagazineBarrelComponent _parent;
private readonly HBoxContainer _bulletsList;
private readonly TextureRect _chamberedBullet;
private readonly Label _noMagazineLabel;
private readonly Label _ammoCount;
public StatusControl(ClientMagazineBarrelComponent parent)
{
_parent = parent;
SizeFlagsHorizontal = SizeFlags.FillExpand;
SizeFlagsVertical = SizeFlags.ShrinkCenter;
AddChild(new HBoxContainer
{
SizeFlagsHorizontal = SizeFlags.FillExpand,
Children =
{
(_chamberedBullet = new TextureRect
{
Texture = StaticIoC.ResC.GetTexture("/Textures/Interface/ItemStatus/Bullets/chambered_rotated.png"),
SizeFlagsVertical = SizeFlags.ShrinkCenter,
SizeFlagsHorizontal = SizeFlags.ShrinkEnd | SizeFlags.Fill,
}),
new Control() { CustomMinimumSize = (5,0) },
new Control
{
SizeFlagsHorizontal = SizeFlags.FillExpand,
Children =
{
(_bulletsList = new HBoxContainer
{
SizeFlagsVertical = SizeFlags.ShrinkCenter,
SeparationOverride = 0
}),
(_noMagazineLabel = new Label
{
Text = "No Magazine!",
StyleClasses = {StyleNano.StyleClassItemStatus}
})
}
},
new Control() { CustomMinimumSize = (5,0) },
(_ammoCount = new Label
{
StyleClasses = {StyleNano.StyleClassItemStatus},
SizeFlagsHorizontal = SizeFlags.ShrinkEnd,
}),
}
});
}
public void Update()
{
_chamberedBullet.ModulateSelfOverride =
_parent.Chambered ? Color.FromHex("#d7df60") : Color.Black;
_bulletsList.RemoveAllChildren();
if (_parent.MagazineCount == null)
{
_noMagazineLabel.Visible = true;
_ammoCount.Visible = false;
return;
}
var (count, capacity) = _parent.MagazineCount.Value;
_noMagazineLabel.Visible = false;
_ammoCount.Visible = true;
var texturePath = "/Textures/Interface/ItemStatus/Bullets/normal.png";
var texture = StaticIoC.ResC.GetTexture(texturePath);
_ammoCount.Text = $"x{count:00}";
capacity = Math.Min(capacity, 20);
FillBulletRow(_bulletsList, count, capacity, texture);
}
private static void FillBulletRow(Control container, int count, int capacity, Texture texture)
{
var colorA = Color.FromHex("#b68f0e");
var colorB = Color.FromHex("#d7df60");
var colorGoneA = Color.FromHex("#000000");
var colorGoneB = Color.FromHex("#222222");
var altColor = false;
// Draw the empty ones
for (var i = count; i < capacity; i++)
{
container.AddChild(new TextureRect
{
Texture = texture,
ModulateSelfOverride = altColor ? colorGoneA : colorGoneB,
SizeFlagsHorizontal = SizeFlags.Fill,
SizeFlagsVertical = SizeFlags.Fill,
Stretch = TextureRect.StretchMode.KeepCentered
});
altColor ^= true;
}
// Draw the full ones, but limit the count to the capacity
count = Math.Min(count, capacity);
for (var i = 0; i < count; i++)
{
container.AddChild(new TextureRect
{
Texture = texture,
ModulateSelfOverride = altColor ? colorA : colorB,
SizeFlagsHorizontal = SizeFlags.Fill,
SizeFlagsVertical = SizeFlags.Fill,
Stretch = TextureRect.StretchMode.KeepCentered
});
altColor ^= true;
}
}
protected override Vector2 CalculateMinimumSize()
{
return Vector2.ComponentMax((0, 15), base.CalculateMinimumSize());
}
public void PlayAlarmAnimation()
{
var animation = _parent._isLmgAlarmAnimation ? AlarmAnimationLmg : AlarmAnimationSmg;
_noMagazineLabel.PlayAnimation(animation, "alarm");
}
}
}
}