Files
wwdpublic/Content.Client/Weapons/Ranged/Systems/GunSystem.AmmoCounter.cs
Spatison 462ecb429e [Tweak] Hud UI (#834)
* combat mode ui

* movement ui

* some fix

* fix

* more fix

* fix
2025-09-13 17:38:24 +03:00

443 lines
15 KiB
C#

using Content.Client._White.Guns;
using Content.Client._White.UserInterface.Controls;
using Content.Client.Cooldown;
using Content.Client.IoC;
using Content.Client.Items;
using Content.Client.Resources;
using Content.Client.Stylesheets;
using Content.Client.Weapons.Ranged.Components;
using Content.Client.Weapons.Ranged.ItemStatus;
using Content.Shared._White.Guns;
using Content.Shared.Weapons.Ranged.Components;
using Robust.Client.Animations;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using System.Numerics;
namespace Content.Client.Weapons.Ranged.Systems;
public sealed partial class GunSystem
{
private void OnAmmoCounterCollect(EntityUid uid, AmmoCounterComponent component, ItemStatusCollectMessage args)
{
RefreshControl(uid, component);
if (component.Control != null)
args.Controls.Add(component.Control);
}
/// <summary>
/// Refreshes the control being used to show ammo. Useful if you change the AmmoProvider.
/// </summary>
/// <param name="uid"></param>
/// <param name="component"></param>
private void RefreshControl(EntityUid uid, AmmoCounterComponent? component = null)
{
if (!Resolve(uid, ref component, false))
return;
component.Control?.Dispose();
component.Control = null;
var ev = new AmmoCounterControlEvent();
RaiseLocalEvent(uid, ev, false);
// Fallback to default if none specified
ev.Control ??= new DefaultStatusControl();
component.Control = ev.Control;
UpdateAmmoCount(uid, component);
}
private void UpdateAmmoCount(EntityUid uid, AmmoCounterComponent component)
{
if (component.Control == null)
return;
var ev = new UpdateAmmoCounterEvent()
{
Control = component.Control
};
RaiseLocalEvent(uid, ev, false);
}
protected override void UpdateAmmoCount(EntityUid uid, bool prediction = true)
{
// Don't use resolves because the method is shared and there's no compref and I'm trying to
// share as much code as possible
if (prediction && !Timing.IsFirstTimePredicted ||
!TryComp<AmmoCounterComponent>(uid, out var clientComp))
{
return;
}
UpdateAmmoCount(uid, clientComp);
}
/// <summary>
/// Raised when an ammocounter is requesting a control.
/// </summary>
public sealed class AmmoCounterControlEvent : EntityEventArgs
{
public Control? Control;
}
/// <summary>
/// Raised whenever the ammo count / magazine for a control needs updating.
/// </summary>
public sealed class UpdateAmmoCounterEvent : HandledEntityEventArgs
{
public Control Control = default!;
}
#region Controls
private sealed class DefaultStatusControl : Control
{
private readonly BulletRender _bulletRender;
public DefaultStatusControl()
{
MinHeight = 15;
HorizontalExpand = true;
VerticalAlignment = VAlignment.Center;
AddChild(_bulletRender = new()
{
HorizontalAlignment = HAlignment.Right,
VerticalAlignment = VAlignment.Bottom
});
}
public void Update(int count, int capacity)
{
_bulletRender.Count = count;
_bulletRender.Capacity = capacity;
_bulletRender.Type = capacity > 50 ? BulletRender.BulletType.Tiny : BulletRender.BulletType.Normal;
}
}
// WWDP - DEFUNCT - Left just in case for upstream compatibility
public sealed class BoxesStatusControl : Control
{
private readonly BatteryBulletRenderer _bullets;
private readonly Label _ammoCount;
public BoxesStatusControl()
{
MinHeight = 15;
HorizontalExpand = true;
VerticalAlignment = Control.VAlignment.Center;
AddChild(new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Horizontal,
Children =
{
(_bullets = new()
{
Margin = new(0, 0, 5, 0),
HorizontalExpand = true
}),
(_ammoCount = new()
{
StyleClasses = { StyleNano.StyleClassItemStatus },
HorizontalAlignment = HAlignment.Right,
VerticalAlignment = VAlignment.Bottom
}),
}
});
}
public void Update(int count, int max)
{
_ammoCount.Visible = true;
_ammoCount.Text = $"x{count:00}";
_bullets.Capacity = max;
_bullets.Count = count;
}
}
private sealed class ChamberMagazineStatusControl : Control
{
private readonly BulletRender _bulletRender;
private readonly TextureRect _chamberedBullet;
private readonly Label _noMagazineLabel;
private readonly Label _ammoCount;
public ChamberMagazineStatusControl()
{
MinHeight = 15;
HorizontalExpand = true;
VerticalAlignment = Control.VAlignment.Center;
AddChild(new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Horizontal,
HorizontalExpand = true,
Children =
{
new Control
{
HorizontalExpand = true,
Margin = new(0, 0, 5, 0),
Children =
{
(_bulletRender = new()
{
HorizontalAlignment = HAlignment.Right,
VerticalAlignment = VAlignment.Bottom
}),
(_noMagazineLabel = new()
{
Text = "No Magazine!",
StyleClasses = {StyleNano.StyleClassItemStatus}
})
}
},
new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Vertical,
VerticalAlignment = VAlignment.Bottom,
Margin = new(0, 0, 0, 2),
Children =
{
(_ammoCount = new()
{
StyleClasses = {StyleNano.StyleClassItemStatus},
HorizontalAlignment = HAlignment.Right,
}),
(_chamberedBullet = new()
{
Texture = StaticIoC.ResC.GetTexture("/Textures/Interface/ItemStatus/Bullets/chambered.png"),
HorizontalAlignment = HAlignment.Left,
}),
}
}
}
});
}
public void Update(bool chambered, bool magazine, int count, int capacity)
{
_chamberedBullet.ModulateSelfOverride =
chambered ? Color.FromHex("#d7df60") : Color.Black;
if (!magazine)
{
_bulletRender.Visible = false;
_noMagazineLabel.Visible = true;
_ammoCount.Visible = false;
return;
}
_bulletRender.Visible = true;
_noMagazineLabel.Visible = false;
_ammoCount.Visible = true;
_bulletRender.Count = count;
_bulletRender.Capacity = capacity;
_bulletRender.Type = capacity > 50 ? BulletRender.BulletType.Tiny : BulletRender.BulletType.Normal;
_ammoCount.Text = $"x{count:00}";
}
public void PlayAlarmAnimation(Animation animation)
{
_noMagazineLabel.PlayAnimation(animation, "alarm");
}
}
private sealed class RevolverStatusControl : Control
{
private readonly BoxContainer _bulletsList;
public RevolverStatusControl()
{
MinHeight = 15;
HorizontalExpand = true;
VerticalAlignment = Control.VAlignment.Center;
AddChild(_bulletsList = new()
{
Orientation = BoxContainer.LayoutOrientation.Horizontal,
HorizontalExpand = true,
VerticalAlignment = VAlignment.Center,
SeparationOverride = 0
});
}
public void Update(int currentIndex, bool?[] bullets)
{
_bulletsList.RemoveAllChildren();
var capacity = 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(currentIndex, bullets, _bulletsList, texture, spentTexture);
}
private void FillBulletRow(int currentIndex, bool?[] bullets, Control container, Texture texture, Texture emptyTexture)
{
var capacity = bullets.Length;
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 < capacity; i++)
{
var bulletFree = bullets[i];
// Add a outline
var box = new Control()
{
MinSize = texture.Size * scale,
};
if (i == currentIndex)
{
box.AddChild(new TextureRect
{
Texture = texture,
TextureScale = new(scale, scale),
ModulateSelfOverride = Color.LimeGreen,
});
}
Color color;
Texture bulletTexture = texture;
if (bulletFree.HasValue)
{
if (bulletFree.Value)
{
color = altColor ? colorA : colorB;
}
else
{
color = altColor ? colorSpentA : colorSpentB;
bulletTexture = emptyTexture;
}
}
else
{
color = altColor ? colorGoneA : colorGoneB;
}
box.AddChild(new TextureRect
{
Stretch = TextureRect.StretchMode.KeepCentered,
Texture = bulletTexture,
ModulateSelfOverride = color,
});
altColor ^= true;
container.AddChild(box);
}
}
}
// WWDP EDIT START
// here be shitcode
public sealed class EnergyGunBatteryStatusControl : Control
{
private readonly FluxBarControl _fluxBar;
private readonly BarControl _ammoBar;
private readonly Label _ammoLabel;
private readonly BatteryAmmoProviderComponent _ammoProvider;
private readonly GunFluxComponent? _overheatComp;
private readonly GunOverheatSystem _overheatSystem;
private int _ammoCount;
public EnergyGunBatteryStatusControl(EntityUid uid, BatteryAmmoProviderComponent comp)
{
var entMan = IoCManager.Resolve<IEntityManager>();
_overheatSystem = entMan.System<GunOverheatSystem>();
entMan.TryGetComponent(uid, out _overheatComp);
_ammoProvider = comp;
_ammoCount = comp.Shots;
MinHeight = 15;
HorizontalExpand = true;
VerticalAlignment = VAlignment.Center;
AddChild(new BoxContainer // outer box
{
Orientation = BoxContainer.LayoutOrientation.Horizontal,
Children =
{
new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Vertical,
MaxWidth = 72,
SetHeight = 15,
VerticalAlignment = VAlignment.Top,
SeparationOverride = 1,
Children =
{
(_fluxBar = new()
{
}),
(_ammoBar = new()
{
})
}
},
(_ammoLabel = new()
{
StyleClasses = { StyleNano.StyleClassItemStatus },
HorizontalExpand = true,
HorizontalAlignment = HAlignment.Right,
VerticalAlignment = VAlignment.Top,
Text = $"x{_ammoCount:00}"
}),
}
});
}
protected override void PreRenderChildren(ref ControlRenderArguments args)
{
_ammoBar.Fill = 0;
if (_ammoProvider.Capacity > 0)
_ammoBar.Fill = (float) _ammoProvider.Shots / _ammoProvider.Capacity;
if (_overheatComp is null || !_overheatSystem.GetFluxCore(_overheatComp, out var core))
{
_fluxBar.Visible = false;
}
else
{
_fluxBar.Visible = true;
var currentFlux = _overheatSystem.GetCurrentFlux(core);
_fluxBar.Fill = currentFlux / core.Capacity;
_fluxBar.Mark = MathHelper.Clamp(_overheatComp.HeatCost / core.Capacity, -1, 1);
_fluxBar.SafeLimit = core.SafeFlux > 0 ? core.SafeFlux / core.Capacity : null;
_fluxBar.SafeLimitColor = _overheatComp.SafetyEnabled ? Color.LightGreen : Color.Yellow;
}
_ammoLabel.Text = $"x{_ammoProvider.Shots:00}";
}
}
// WWDP EDIT END
#endregion
}