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
This commit is contained in:
@@ -0,0 +1,206 @@
|
||||
using Content.Client.UserInterface.Stylesheets;
|
||||
using Content.Client.Utility;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.GameObjects.Components.Weapons.Ranged.Barrels;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using System;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Weapons.Ranged.Barrels
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class ClientBoltActionBarrelComponent : Component, IItemStatus
|
||||
{
|
||||
public override string Name => "BoltActionBarrel";
|
||||
public override uint? NetID => ContentNetIDs.BOLTACTION_BARREL;
|
||||
|
||||
private StatusControl _statusControl;
|
||||
|
||||
/// <summary>
|
||||
/// chambered is true when a bullet is chambered
|
||||
/// spent is true when the chambered bullet is spent
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public (bool chambered, bool spent) Chamber { 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; }
|
||||
|
||||
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
|
||||
{
|
||||
if (!(curState is BoltActionBarrelComponentState cast))
|
||||
return;
|
||||
|
||||
Chamber = cast.Chamber;
|
||||
MagazineCount = cast.Magazine;
|
||||
_statusControl?.Update();
|
||||
}
|
||||
|
||||
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 ClientBoltActionBarrelComponent _parent;
|
||||
private readonly HBoxContainer _bulletsListTop;
|
||||
private readonly HBoxContainer _bulletsListBottom;
|
||||
private readonly TextureRect _chamberedBullet;
|
||||
private readonly Label _noMagazineLabel;
|
||||
|
||||
public StatusControl(ClientBoltActionBarrelComponent parent)
|
||||
{
|
||||
_parent = parent;
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand;
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter;
|
||||
AddChild(new VBoxContainer
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter,
|
||||
SeparationOverride = 0,
|
||||
Children =
|
||||
{
|
||||
(_bulletsListTop = new HBoxContainer {SeparationOverride = 0}),
|
||||
new HBoxContainer
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
Children =
|
||||
{
|
||||
new Control
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
Children =
|
||||
{
|
||||
(_bulletsListBottom = new HBoxContainer
|
||||
{
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter,
|
||||
SeparationOverride = 0
|
||||
}),
|
||||
(_noMagazineLabel = new Label
|
||||
{
|
||||
Text = "No Magazine!",
|
||||
StyleClasses = {StyleNano.StyleClassItemStatus}
|
||||
})
|
||||
}
|
||||
},
|
||||
(_chamberedBullet = new TextureRect
|
||||
{
|
||||
Texture = StaticIoC.ResC.GetTexture("/Textures/Interface/ItemStatus/Bullets/chambered.png"),
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter,
|
||||
SizeFlagsHorizontal = SizeFlags.ShrinkEnd | SizeFlags.Fill,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
_chamberedBullet.ModulateSelfOverride =
|
||||
_parent.Chamber.chambered ?
|
||||
_parent.Chamber.spent ? Color.Red : Color.FromHex("#d7df60")
|
||||
: Color.Black;
|
||||
|
||||
_bulletsListTop.RemoveAllChildren();
|
||||
_bulletsListBottom.RemoveAllChildren();
|
||||
|
||||
if (_parent.MagazineCount == null)
|
||||
{
|
||||
_noMagazineLabel.Visible = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var (count, capacity) = _parent.MagazineCount.Value;
|
||||
|
||||
_noMagazineLabel.Visible = false;
|
||||
|
||||
string texturePath;
|
||||
if (capacity <= 20)
|
||||
{
|
||||
texturePath = "/Textures/Interface/ItemStatus/Bullets/normal.png";
|
||||
}
|
||||
else if (capacity <= 30)
|
||||
{
|
||||
texturePath = "/Textures/Interface/ItemStatus/Bullets/small.png";
|
||||
}
|
||||
else
|
||||
{
|
||||
texturePath = "/Textures/Interface/ItemStatus/Bullets/tiny.png";
|
||||
}
|
||||
|
||||
var texture = StaticIoC.ResC.GetTexture(texturePath);
|
||||
|
||||
const int tinyMaxRow = 60;
|
||||
|
||||
if (capacity > tinyMaxRow)
|
||||
{
|
||||
FillBulletRow(_bulletsListBottom, Math.Min(tinyMaxRow, count), tinyMaxRow, texture);
|
||||
FillBulletRow(_bulletsListTop, Math.Max(0, count - tinyMaxRow), capacity - tinyMaxRow, texture);
|
||||
}
|
||||
else
|
||||
{
|
||||
FillBulletRow(_bulletsListBottom, 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;
|
||||
|
||||
for (var i = count; i < capacity; i++)
|
||||
{
|
||||
container.AddChild(new TextureRect
|
||||
{
|
||||
Texture = texture,
|
||||
ModulateSelfOverride = altColor ? colorGoneA : colorGoneB
|
||||
});
|
||||
|
||||
altColor ^= true;
|
||||
}
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
container.AddChild(new TextureRect
|
||||
{
|
||||
Texture = texture,
|
||||
ModulateSelfOverride = altColor ? colorA : colorB
|
||||
});
|
||||
|
||||
altColor ^= true;
|
||||
}
|
||||
}
|
||||
|
||||
protected override Vector2 CalculateMinimumSize()
|
||||
{
|
||||
return Vector2.ComponentMax((0, 15), base.CalculateMinimumSize());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using Content.Client.Animations;
|
||||
using Content.Client.UserInterface.Stylesheets;
|
||||
using Content.Client.Utility;
|
||||
@@ -138,54 +138,52 @@ namespace Content.Client.GameObjects.Components.Weapons.Ranged.Barrels
|
||||
private sealed class StatusControl : Control
|
||||
{
|
||||
private readonly ClientMagazineBarrelComponent _parent;
|
||||
private readonly HBoxContainer _bulletsListTop;
|
||||
private readonly HBoxContainer _bulletsListBottom;
|
||||
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 VBoxContainer
|
||||
|
||||
AddChild(new HBoxContainer
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter,
|
||||
SeparationOverride = 0,
|
||||
Children =
|
||||
{
|
||||
(_bulletsListTop = new HBoxContainer {SeparationOverride = 0}),
|
||||
new HBoxContainer
|
||||
(_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 =
|
||||
{
|
||||
new Control
|
||||
(_bulletsList = new HBoxContainer
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
Children =
|
||||
{
|
||||
(_bulletsListBottom = new HBoxContainer
|
||||
{
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter,
|
||||
SeparationOverride = 0
|
||||
}),
|
||||
(_noMagazineLabel = new Label
|
||||
{
|
||||
Text = "No Magazine!",
|
||||
StyleClasses = {StyleNano.StyleClassItemStatus}
|
||||
})
|
||||
}
|
||||
},
|
||||
(_chamberedBullet = new TextureRect
|
||||
{
|
||||
Texture = StaticIoC.ResC.GetTexture("/Textures/Interface/ItemStatus/Bullets/chambered.png"),
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter,
|
||||
SizeFlagsHorizontal = SizeFlags.ShrinkEnd | SizeFlags.Fill,
|
||||
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,
|
||||
}),
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -195,46 +193,26 @@ namespace Content.Client.GameObjects.Components.Weapons.Ranged.Barrels
|
||||
_chamberedBullet.ModulateSelfOverride =
|
||||
_parent.Chambered ? Color.FromHex("#d7df60") : Color.Black;
|
||||
|
||||
_bulletsListTop.RemoveAllChildren();
|
||||
_bulletsListBottom.RemoveAllChildren();
|
||||
_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;
|
||||
|
||||
string texturePath;
|
||||
if (capacity <= 20)
|
||||
{
|
||||
texturePath = "/Textures/Interface/ItemStatus/Bullets/normal.png";
|
||||
}
|
||||
else if (capacity <= 30)
|
||||
{
|
||||
texturePath = "/Textures/Interface/ItemStatus/Bullets/small.png";
|
||||
}
|
||||
else
|
||||
{
|
||||
texturePath = "/Textures/Interface/ItemStatus/Bullets/tiny.png";
|
||||
}
|
||||
|
||||
var texturePath = "/Textures/Interface/ItemStatus/Bullets/normal.png";
|
||||
var texture = StaticIoC.ResC.GetTexture(texturePath);
|
||||
|
||||
const int tinyMaxRow = 60;
|
||||
|
||||
if (capacity > tinyMaxRow)
|
||||
{
|
||||
FillBulletRow(_bulletsListBottom, Math.Min(tinyMaxRow, count), tinyMaxRow, texture);
|
||||
FillBulletRow(_bulletsListTop, Math.Max(0, count - tinyMaxRow), capacity - tinyMaxRow, texture);
|
||||
}
|
||||
else
|
||||
{
|
||||
FillBulletRow(_bulletsListBottom, count, capacity, texture);
|
||||
}
|
||||
_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)
|
||||
@@ -246,23 +224,32 @@ namespace Content.Client.GameObjects.Components.Weapons.Ranged.Barrels
|
||||
|
||||
var altColor = false;
|
||||
|
||||
// Draw the empty ones
|
||||
for (var i = count; i < capacity; i++)
|
||||
{
|
||||
container.AddChild(new TextureRect
|
||||
{
|
||||
Texture = texture,
|
||||
ModulateSelfOverride = altColor ? colorGoneA : colorGoneB
|
||||
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
|
||||
ModulateSelfOverride = altColor ? colorA : colorB,
|
||||
SizeFlagsHorizontal = SizeFlags.Fill,
|
||||
SizeFlagsVertical = SizeFlags.Fill,
|
||||
Stretch = TextureRect.StretchMode.KeepCentered
|
||||
});
|
||||
|
||||
altColor ^= true;
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
using Content.Client.UserInterface.Stylesheets;
|
||||
using Content.Client.Utility;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.GameObjects.Components.Weapons.Ranged.Barrels;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Weapons.Ranged.Barrels
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class ClientPumpBarrelComponent : Component, IItemStatus
|
||||
{
|
||||
public override string Name => "PumpBarrel";
|
||||
public override uint? NetID => ContentNetIDs.PUMP_BARREL;
|
||||
|
||||
private StatusControl _statusControl;
|
||||
|
||||
/// <summary>
|
||||
/// chambered is true when a bullet is chambered
|
||||
/// spent is true when the chambered bullet is spent
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public (bool chambered, bool spent) Chamber { 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; }
|
||||
|
||||
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
|
||||
{
|
||||
if (!(curState is PumpBarrelComponentState cast))
|
||||
return;
|
||||
|
||||
Chamber = cast.Chamber;
|
||||
MagazineCount = cast.Magazine;
|
||||
_statusControl?.Update();
|
||||
}
|
||||
|
||||
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 ClientPumpBarrelComponent _parent;
|
||||
private readonly HBoxContainer _bulletsListTop;
|
||||
private readonly HBoxContainer _bulletsListBottom;
|
||||
private readonly TextureRect _chamberedBullet;
|
||||
private readonly Label _noMagazineLabel;
|
||||
|
||||
public StatusControl(ClientPumpBarrelComponent parent)
|
||||
{
|
||||
_parent = parent;
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand;
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter;
|
||||
AddChild(new VBoxContainer
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter,
|
||||
SeparationOverride = 0,
|
||||
Children =
|
||||
{
|
||||
(_bulletsListTop = new HBoxContainer {SeparationOverride = 0}),
|
||||
new HBoxContainer
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
Children =
|
||||
{
|
||||
new Control
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
Children =
|
||||
{
|
||||
(_bulletsListBottom = new HBoxContainer
|
||||
{
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter,
|
||||
SeparationOverride = 0
|
||||
}),
|
||||
(_noMagazineLabel = new Label
|
||||
{
|
||||
Text = "No Magazine!",
|
||||
StyleClasses = {StyleNano.StyleClassItemStatus}
|
||||
})
|
||||
}
|
||||
},
|
||||
(_chamberedBullet = new TextureRect
|
||||
{
|
||||
Texture = StaticIoC.ResC.GetTexture("/Textures/Interface/ItemStatus/Bullets/chambered.png"),
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter,
|
||||
SizeFlagsHorizontal = SizeFlags.ShrinkEnd | SizeFlags.Fill,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
_chamberedBullet.ModulateSelfOverride =
|
||||
_parent.Chamber.chambered ?
|
||||
_parent.Chamber.spent ? Color.Red : Color.FromHex("#d7df60")
|
||||
: Color.Black;
|
||||
|
||||
_bulletsListTop.RemoveAllChildren();
|
||||
_bulletsListBottom.RemoveAllChildren();
|
||||
|
||||
if (_parent.MagazineCount == null)
|
||||
{
|
||||
_noMagazineLabel.Visible = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var (count, capacity) = _parent.MagazineCount.Value;
|
||||
|
||||
_noMagazineLabel.Visible = false;
|
||||
|
||||
string texturePath;
|
||||
if (capacity <= 20)
|
||||
{
|
||||
texturePath = "/Textures/Interface/ItemStatus/Bullets/normal.png";
|
||||
}
|
||||
else if (capacity <= 30)
|
||||
{
|
||||
texturePath = "/Textures/Interface/ItemStatus/Bullets/small.png";
|
||||
}
|
||||
else
|
||||
{
|
||||
texturePath = "/Textures/Interface/ItemStatus/Bullets/tiny.png";
|
||||
}
|
||||
|
||||
var texture = StaticIoC.ResC.GetTexture(texturePath);
|
||||
|
||||
const int tinyMaxRow = 60;
|
||||
|
||||
if (capacity > tinyMaxRow)
|
||||
{
|
||||
FillBulletRow(_bulletsListBottom, Math.Min(tinyMaxRow, count), tinyMaxRow, texture);
|
||||
FillBulletRow(_bulletsListTop, Math.Max(0, count - tinyMaxRow), capacity - tinyMaxRow, texture);
|
||||
}
|
||||
else
|
||||
{
|
||||
FillBulletRow(_bulletsListBottom, 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;
|
||||
|
||||
for (var i = count; i < capacity; i++)
|
||||
{
|
||||
container.AddChild(new TextureRect
|
||||
{
|
||||
Texture = texture,
|
||||
ModulateSelfOverride = altColor ? colorGoneA : colorGoneB
|
||||
});
|
||||
|
||||
altColor ^= true;
|
||||
}
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
container.AddChild(new TextureRect
|
||||
{
|
||||
Texture = texture,
|
||||
ModulateSelfOverride = altColor ? colorA : colorB
|
||||
});
|
||||
|
||||
altColor ^= true;
|
||||
}
|
||||
}
|
||||
|
||||
protected override Vector2 CalculateMinimumSize()
|
||||
{
|
||||
return Vector2.ComponentMax((0, 15), base.CalculateMinimumSize());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
using Content.Client.UserInterface.Stylesheets;
|
||||
using Content.Client.Utility;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.GameObjects.Components.Weapons.Ranged.Barrels;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
using System.Text;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Weapons.Ranged.Barrels
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class ClientRevolverBarrelComponent : Component, IItemStatus
|
||||
{
|
||||
public override string Name => "RevolverBarrel";
|
||||
public override uint? NetID => ContentNetIDs.REVOLVER_BARREL;
|
||||
|
||||
private StatusControl _statusControl;
|
||||
|
||||
/// <summary>
|
||||
/// A array that lists the bullet states
|
||||
/// true means a spent bullet
|
||||
/// false means a "shootable" bullet
|
||||
/// null means no bullet
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public bool?[] Bullets { get; private set; }
|
||||
|
||||
[ViewVariables]
|
||||
public int CurrentSlot { get; private set; }
|
||||
|
||||
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
|
||||
{
|
||||
if (!(curState is RevolverBarrelComponentState cast))
|
||||
return;
|
||||
|
||||
CurrentSlot = cast.CurrentSlot;
|
||||
Bullets = cast.Bullets;
|
||||
_statusControl?.Update();
|
||||
}
|
||||
|
||||
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 ClientRevolverBarrelComponent _parent;
|
||||
private readonly HBoxContainer _bulletsList;
|
||||
|
||||
public StatusControl(ClientRevolverBarrelComponent parent)
|
||||
{
|
||||
_parent = parent;
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand;
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter;
|
||||
AddChild((_bulletsList = new HBoxContainer
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter,
|
||||
SeparationOverride = 0
|
||||
}));
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
_bulletsList.RemoveAllChildren();
|
||||
|
||||
var capacity = _parent.Bullets.Length;
|
||||
|
||||
string texturePath;
|
||||
if (capacity <= 20)
|
||||
{
|
||||
texturePath = "/Textures/Interface/ItemStatus/Bullets/normal.png";
|
||||
}
|
||||
else if (capacity <= 30)
|
||||
{
|
||||
texturePath = "/Textures/Interface/ItemStatus/Bullets/small.png";
|
||||
}
|
||||
else
|
||||
{
|
||||
texturePath = "/Textures/Interface/ItemStatus/Bullets/tiny.png";
|
||||
}
|
||||
|
||||
var texture = StaticIoC.ResC.GetTexture(texturePath);
|
||||
var spentTexture = StaticIoC.ResC.GetTexture("/Textures/Interface/ItemStatus/Bullets/empty.png");
|
||||
|
||||
FillBulletRow(_bulletsList, texture, spentTexture);
|
||||
}
|
||||
|
||||
private void FillBulletRow(Control container, Texture texture, Texture emptyTexture)
|
||||
{
|
||||
var colorA = Color.FromHex("#b68f0e");
|
||||
var colorB = Color.FromHex("#d7df60");
|
||||
var colorSpentA = Color.FromHex("#b50e25");
|
||||
var colorSpentB = Color.FromHex("#d3745f");
|
||||
var colorGoneA = Color.FromHex("#000000");
|
||||
var colorGoneB = Color.FromHex("#222222");
|
||||
|
||||
var altColor = false;
|
||||
var scale = 1.3f;
|
||||
|
||||
for (var i = 0; i < _parent.Bullets.Length; i++)
|
||||
{
|
||||
var bulletSpent = _parent.Bullets[i];
|
||||
// Add a outline
|
||||
var box = new Control()
|
||||
{
|
||||
CustomMinimumSize = texture.Size * scale,
|
||||
};
|
||||
if (i == _parent.CurrentSlot)
|
||||
{
|
||||
box.AddChild(new TextureRect
|
||||
{
|
||||
Texture = texture,
|
||||
TextureScale = (scale, scale),
|
||||
ModulateSelfOverride = Color.Green,
|
||||
});
|
||||
}
|
||||
Color color;
|
||||
Texture bulletTexture = texture;
|
||||
|
||||
if (bulletSpent.HasValue)
|
||||
{
|
||||
if (bulletSpent.Value)
|
||||
{
|
||||
color = altColor ? colorSpentA : colorSpentB;
|
||||
bulletTexture = emptyTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
color = altColor ? colorA : colorB;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
color = altColor ? colorGoneA : colorGoneB;
|
||||
}
|
||||
|
||||
box.AddChild(new TextureRect
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.Fill,
|
||||
SizeFlagsVertical = SizeFlags.Fill,
|
||||
Stretch = TextureRect.StretchMode.KeepCentered,
|
||||
Texture = bulletTexture,
|
||||
ModulateSelfOverride = color,
|
||||
});
|
||||
altColor ^= true;
|
||||
container.AddChild(box);
|
||||
}
|
||||
}
|
||||
|
||||
protected override Vector2 CalculateMinimumSize()
|
||||
{
|
||||
return Vector2.ComponentMax((0, 15), base.CalculateMinimumSize());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -86,9 +86,6 @@
|
||||
"CanSpill",
|
||||
"SpeedLoader",
|
||||
"Hitscan",
|
||||
"BoltActionBarrel",
|
||||
"PumpBarrel",
|
||||
"RevolverBarrel",
|
||||
"ExplosiveProjectile",
|
||||
"StunnableProjectile",
|
||||
"RandomPottedPlant",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.GameObjects.Components.Weapons.Ranged.Barrels;
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
using Content.Shared.GameObjects.Verbs;
|
||||
@@ -32,6 +33,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels
|
||||
// but it felt a lot messier to play around with, especially when adding verbs
|
||||
|
||||
public override string Name => "BoltActionBarrel";
|
||||
public override uint? NetID => ContentNetIDs.BOLTACTION_BARREL;
|
||||
|
||||
public override int ShotsLeft
|
||||
{
|
||||
@@ -123,6 +125,24 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels
|
||||
UpdateAppearance();
|
||||
}
|
||||
|
||||
public override ComponentState GetComponentState()
|
||||
{
|
||||
(int, int)? count = (ShotsLeft, Capacity);
|
||||
var chamberedExists = _chamberContainer.ContainedEntity != null;
|
||||
// (Is one chambered?, is the bullet spend)
|
||||
var chamber = (chamberedExists, false);
|
||||
if (chamberedExists && _chamberContainer.ContainedEntity.TryGetComponent<AmmoComponent>(out var ammo))
|
||||
{
|
||||
chamber.Item2 = ammo.Spent;
|
||||
}
|
||||
|
||||
return new BoltActionBarrelComponentState(
|
||||
chamber,
|
||||
FireRateSelector,
|
||||
count,
|
||||
SoundGunshot);
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
// TODO: Add existing ammo support on revolvers
|
||||
@@ -170,6 +190,11 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels
|
||||
{
|
||||
Cycle();
|
||||
}
|
||||
else
|
||||
{
|
||||
Dirty();
|
||||
}
|
||||
|
||||
return chamberEntity?.GetComponent<AmmoComponent>().TakeBullet(spawnAtGrid, spawnAtMap);
|
||||
}
|
||||
|
||||
@@ -256,7 +281,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels
|
||||
{
|
||||
EntitySystem.Get<AudioSystem>().PlayAtCoords(_soundInsert, Owner.Transform.GridPosition, AudioParams.Default.WithVolume(-2));
|
||||
}
|
||||
// Dirty();
|
||||
Dirty();
|
||||
UpdateAppearance();
|
||||
return true;
|
||||
}
|
||||
@@ -269,7 +294,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels
|
||||
{
|
||||
EntitySystem.Get<AudioSystem>().PlayAtCoords(_soundInsert, Owner.Transform.GridPosition, AudioParams.Default.WithVolume(-2));
|
||||
}
|
||||
// Dirty();
|
||||
Dirty();
|
||||
UpdateAppearance();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.GameObjects.Components.Weapons.Ranged.Barrels;
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
using Content.Shared.Interfaces;
|
||||
@@ -27,6 +28,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels
|
||||
public sealed class PumpBarrelComponent : ServerRangedBarrelComponent, IMapInit, IExamine
|
||||
{
|
||||
public override string Name => "PumpBarrel";
|
||||
public override uint? NetID => ContentNetIDs.PUMP_BARREL;
|
||||
|
||||
public override int ShotsLeft
|
||||
{
|
||||
@@ -81,6 +83,23 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels
|
||||
UpdateAppearance();
|
||||
}
|
||||
|
||||
public override ComponentState GetComponentState()
|
||||
{
|
||||
(int, int)? count = (ShotsLeft, Capacity);
|
||||
var chamberedExists = _chamberContainer.ContainedEntity != null;
|
||||
// (Is one chambered?, is the bullet spend)
|
||||
var chamber = (chamberedExists, false);
|
||||
if (chamberedExists && _chamberContainer.ContainedEntity.TryGetComponent<AmmoComponent>(out var ammo))
|
||||
{
|
||||
chamber.Item2 = ammo.Spent;
|
||||
}
|
||||
return new PumpBarrelComponentState(
|
||||
chamber,
|
||||
FireRateSelector,
|
||||
count,
|
||||
SoundGunshot);
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -110,6 +129,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels
|
||||
}
|
||||
|
||||
_appearanceComponent?.SetData(MagazineBarrelVisuals.MagLoaded, true);
|
||||
Dirty();
|
||||
UpdateAppearance();
|
||||
}
|
||||
|
||||
@@ -131,6 +151,11 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels
|
||||
{
|
||||
Cycle();
|
||||
}
|
||||
else
|
||||
{
|
||||
Dirty();
|
||||
}
|
||||
|
||||
return chamberEntity?.GetComponent<AmmoComponent>().TakeBullet(spawnAtGrid, spawnAtMap);
|
||||
}
|
||||
|
||||
@@ -168,7 +193,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels
|
||||
}
|
||||
}
|
||||
|
||||
// Dirty();
|
||||
Dirty();
|
||||
UpdateAppearance();
|
||||
}
|
||||
|
||||
@@ -189,7 +214,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels
|
||||
{
|
||||
_ammoContainer.Insert(eventArgs.Using);
|
||||
_spawnedAmmo.Push(eventArgs.Using);
|
||||
// Dirty();
|
||||
Dirty();
|
||||
UpdateAppearance();
|
||||
if (_soundInsert != null)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.GameObjects.Components.Weapons.Ranged.Barrels;
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
using Content.Shared.GameObjects.Verbs;
|
||||
@@ -25,6 +26,8 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels
|
||||
public sealed class RevolverBarrelComponent : ServerRangedBarrelComponent
|
||||
{
|
||||
public override string Name => "RevolverBarrel";
|
||||
public override uint? NetID => ContentNetIDs.REVOLVER_BARREL;
|
||||
|
||||
private BallisticCaliber _caliber;
|
||||
private Container _ammoContainer;
|
||||
private int _currentSlot = 0;
|
||||
@@ -60,6 +63,26 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels
|
||||
serializer.DataField(ref _soundSpin, "soundSpin", "/Audio/Weapons/Guns/Misc/revolver_spin.ogg");
|
||||
}
|
||||
|
||||
public override ComponentState GetComponentState()
|
||||
{
|
||||
var slotsSpent = new bool?[Capacity];
|
||||
for (var i = 0; i < Capacity; i++)
|
||||
{
|
||||
slotsSpent[i] = null;
|
||||
if (_ammoSlots[i] != null && _ammoSlots[i].TryGetComponent(out AmmoComponent ammo))
|
||||
{
|
||||
slotsSpent[i] = ammo.Spent;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: make yaml var to not sent currentSlot/UI? (for russian roulette)
|
||||
return new RevolverBarrelComponentState(
|
||||
_currentSlot,
|
||||
FireRateSelector,
|
||||
slotsSpent,
|
||||
SoundGunshot);
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -90,6 +113,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels
|
||||
}
|
||||
|
||||
_appearanceComponent?.SetData(MagazineBarrelVisuals.MagLoaded, true);
|
||||
Dirty();
|
||||
}
|
||||
|
||||
private void UpdateAppearance()
|
||||
@@ -129,7 +153,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels
|
||||
EntitySystem.Get<AudioSystem>().PlayAtCoords(_soundInsert, Owner.Transform.GridPosition, AudioParams.Default.WithVolume(-2));
|
||||
}
|
||||
|
||||
// Dirty();
|
||||
Dirty();
|
||||
UpdateAppearance();
|
||||
return true;
|
||||
}
|
||||
@@ -143,7 +167,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels
|
||||
{
|
||||
// Move up a slot
|
||||
_currentSlot = (_currentSlot + 1) % _ammoSlots.Length;
|
||||
// Dirty();
|
||||
Dirty();
|
||||
UpdateAppearance();
|
||||
}
|
||||
|
||||
@@ -158,6 +182,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels
|
||||
{
|
||||
EntitySystem.Get<AudioSystem>().PlayAtCoords(_soundSpin, Owner.Transform.GridPosition, AudioParams.Default.WithVolume(-2));
|
||||
}
|
||||
Dirty();
|
||||
}
|
||||
|
||||
public override IEntity PeekAmmo()
|
||||
@@ -227,7 +252,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels
|
||||
public override bool UseEntity(UseEntityEventArgs eventArgs)
|
||||
{
|
||||
EjectAllSlots();
|
||||
//Dirty();
|
||||
Dirty();
|
||||
UpdateAppearance();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Content.Shared.GameObjects.Components.Weapons.Ranged.Barrels
|
||||
{
|
||||
[Serializable, NetSerializable]
|
||||
public class BoltActionBarrelComponentState : ComponentState
|
||||
{
|
||||
public (bool chambered, bool spent) Chamber { get; }
|
||||
public FireRateSelector FireRateSelector { get; }
|
||||
public (int count, int max)? Magazine { get; }
|
||||
public string SoundGunshot { get; }
|
||||
|
||||
public BoltActionBarrelComponentState(
|
||||
(bool chambered, bool spent) chamber,
|
||||
FireRateSelector fireRateSelector,
|
||||
(int count, int max)? magazine,
|
||||
string soundGunshot) :
|
||||
base(ContentNetIDs.BOLTACTION_BARREL)
|
||||
{
|
||||
Chamber = chamber;
|
||||
FireRateSelector = fireRateSelector;
|
||||
Magazine = magazine;
|
||||
SoundGunshot = soundGunshot;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Content.Shared.GameObjects.Components.Weapons.Ranged.Barrels
|
||||
{
|
||||
[Serializable, NetSerializable]
|
||||
public class PumpBarrelComponentState : ComponentState
|
||||
{
|
||||
public (bool chambered, bool spent) Chamber { get; }
|
||||
public FireRateSelector FireRateSelector { get; }
|
||||
public (int count, int max)? Magazine { get; }
|
||||
public string SoundGunshot { get; }
|
||||
|
||||
public PumpBarrelComponentState(
|
||||
(bool chambered, bool spent) chamber,
|
||||
FireRateSelector fireRateSelector,
|
||||
(int count, int max)? magazine,
|
||||
string soundGunshot) :
|
||||
base(ContentNetIDs.PUMP_BARREL)
|
||||
{
|
||||
Chamber = chamber;
|
||||
FireRateSelector = fireRateSelector;
|
||||
Magazine = magazine;
|
||||
SoundGunshot = soundGunshot;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Content.Shared.GameObjects.Components.Weapons.Ranged.Barrels
|
||||
{
|
||||
[Serializable, NetSerializable]
|
||||
public class RevolverBarrelComponentState : ComponentState
|
||||
{
|
||||
public int CurrentSlot { get; }
|
||||
public FireRateSelector FireRateSelector { get; }
|
||||
public bool?[] Bullets { get; }
|
||||
public string SoundGunshot { get; }
|
||||
|
||||
public RevolverBarrelComponentState(
|
||||
int currentSlot,
|
||||
FireRateSelector fireRateSelector,
|
||||
bool?[] bullets,
|
||||
string soundGunshot) :
|
||||
base(ContentNetIDs.REVOLVER_BARREL)
|
||||
{
|
||||
CurrentSlot = currentSlot;
|
||||
FireRateSelector = fireRateSelector;
|
||||
Bullets = bullets;
|
||||
SoundGunshot = soundGunshot;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,6 +65,9 @@
|
||||
public const uint RADIATION_PULSE = 1059;
|
||||
public const uint BODY_MANAGER = 1060;
|
||||
public const uint CLIMBING = 1061;
|
||||
public const uint BOLTACTION_BARREL = 1062;
|
||||
public const uint PUMP_BARREL = 1063;
|
||||
public const uint REVOLVER_BARREL = 1064;
|
||||
|
||||
// Net IDs for integration tests.
|
||||
public const uint PREDICTION_TEST = 10001;
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 496 B |
BIN
Resources/Textures/Interface/ItemStatus/Bullets/empty.png
Normal file
BIN
Resources/Textures/Interface/ItemStatus/Bullets/empty.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 524 B |
Reference in New Issue
Block a user