Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 143 additions & 37 deletions Content.Client/CombatMode/CombatModeIndicatorsOverlay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@
using Robust.Client.Input;
using Robust.Client.UserInterface;
using Robust.Shared.Enums;
using Robust.Shared.Utility;

#region Starlight
using Content.Shared._Starlight.CombatMode;
using Robust.Shared.Prototypes;
using SixLabors.ImageSharp.PixelFormats;
using Robust.Shared.Graphics.RSI;
using Content.Client.Weapons.Ranged.Systems;
#endregion

namespace Content.Client.CombatMode;

Expand All @@ -23,42 +30,48 @@ public sealed class CombatModeIndicatorsOverlay : Overlay
private readonly IEyeManager _eye;
private readonly CombatModeSystem _combat;
private readonly HandsSystem _hands = default!;

private readonly Texture _gunSight;
private readonly Texture _gunBoltSight;
private readonly Texture _meleeSight;
private readonly IClyde _clyde = default!; // Starlight-edit

#region Starlight
private readonly SightPrototype? _gunSight;
private readonly SightPrototype? _gunBoltSight;
private readonly SightPrototype? _meleeSight;
private readonly float? _scale;
private readonly float? _offset;
private readonly Color? _main;
private readonly Color? _second;
private readonly bool _rotation = true;
#endregion

public override OverlaySpace Space => OverlaySpace.ScreenSpace;

public Color MainColor = Color.White.WithAlpha(0.3f);
public Color StrokeColor = Color.Black.WithAlpha(0.5f);
public float Scale = 0.6f; // 1 is a little big

public CombatModeIndicatorsOverlay(IInputManager input, IEntityManager entMan,
IEyeManager eye, CombatModeSystem combatSys, HandsSystem hands)
public CombatModeIndicatorsOverlay(IInputManager input, IEntityManager entMan, IPrototypeManager prototypes,
IEyeManager eye, CombatModeSystem combatSys, HandsSystem hands, IClyde clyde, SightPrototype gunSight, SightPrototype meleeSight, float scale, float offset, Color main, Color second, bool rotation = true) // Starlight-edit
{
_inputManager = input;
_entMan = entMan;
_eye = eye;
_combat = combatSys;
_hands = hands;

var spriteSys = _entMan.EntitySysManager.GetEntitySystem<SpriteSystem>();
_gunSight = spriteSys.Frame0(new SpriteSpecifier.Rsi(new ResPath("/Textures/Interface/Misc/crosshair_pointers.rsi"),
"gun_sight"));
_gunBoltSight = spriteSys.Frame0(new SpriteSpecifier.Rsi(new ResPath("/Textures/Interface/Misc/crosshair_pointers.rsi"),
"gun_bolt_sight"));
_meleeSight = spriteSys.Frame0(new SpriteSpecifier.Rsi(new ResPath("/Textures/Interface/Misc/crosshair_pointers.rsi"),
"melee_sight"));
// Starlight-start: replace Texture to Proto
_gunSight = gunSight;
_meleeSight = meleeSight;
_clyde = clyde;
_scale = scale;
_offset = offset;
_main = main;
_second = second;
_rotation = rotation;

if (_gunSight.BoltVariant != null)
prototypes.TryIndex(_gunSight.BoltVariant, out _gunBoltSight);
// Starlight-end
}

protected override bool BeforeDraw(in OverlayDrawArgs args)
{
if (!_combat.IsInCombatMode())
return false;

return base.BeforeDraw(in args);
}
// Starlight-start: Make it lambda
protected override bool BeforeDraw(in OverlayDrawArgs args)
=> !_combat.IsInCombatMode() ? false : base.BeforeDraw(in args);
// Starlight-end

protected override void Draw(in OverlayDrawArgs args)
{
Expand All @@ -68,28 +81,121 @@ protected override void Draw(in OverlayDrawArgs args)
return;

var handEntity = _hands.GetActiveHandEntity();
var isHandGunItem = _entMan.HasComponent<GunComponent>(handEntity);
var isHandGunItem = _entMan.TryGetComponent<GunComponent>(handEntity, out var gun); // Starlight-edit
var isGunBolted = true;
if (_entMan.TryGetComponent(handEntity, out ChamberMagazineAmmoProviderComponent? chamber))
isGunBolted = chamber.BoltClosed ?? true;


var mousePos = mouseScreenPosition.Position;
var uiScale = (args.ViewportControl as Control)?.UIScale ?? 1f;
var limitedScale = uiScale > 1.25f ? 1.25f : uiScale;

var sight = isHandGunItem ? (isGunBolted ? _gunSight : _gunBoltSight) : _meleeSight;
DrawSight(sight, args.ScreenHandle, mousePos, limitedScale * Scale);
#region Starlight

var spriteSys = _entMan.EntitySysManager.GetEntitySystem<SpriteSystem>();

var sight = isHandGunItem ? (isGunBolted || _gunBoltSight == null ? _gunSight : _gunBoltSight) : _meleeSight;
if (sight != null)
{
if (!sight.ShowCursor)
_clyde.SetCursor(_clyde.CreateCursor(new SixLabors.ImageSharp.Image<Rgba32>(32, 32), Vector2i.Zero));
else
_clyde.SetCursor(null);

var scale = limitedScale * Math.Clamp(_scale ?? 0.6f, 0f, 1f);

var eyePos = _eye.CurrentEye.Position;
var eyeScreen = _eye.MapToScreen(eyePos);
var rot = MathF.Atan2(eyeScreen.Y - mousePos.Y, eyeScreen.X - mousePos.X);
rot -= MathF.PI / 2f;
var rsiState = spriteSys.RsiStateLike(sight.Sprite);
if (rsiState.IsAnimated && rsiState.AnimationFrameCount >= 3)
{

var currentAngle = 0f;
if (isHandGunItem && handEntity != null)
currentAngle = (float)_entMan.System<GunSystem>().GetCurrentAngle(handEntity.Value).Degrees;

var bracket1 = rsiState.GetFrame(RsiDirection.South, 0); // Left
var sightTexture = rsiState.GetFrame(RsiDirection.South, 1); // Center
var bracket2 = rsiState.GetFrame(RsiDirection.South, 2); // Right

Texture? bracket3 = null; // Down
Texture? bracket4 = null; // Up

if (rsiState.AnimationFrameCount >= 4)
bracket3 = rsiState.GetFrame(RsiDirection.South, 3);

if (rsiState.AnimationFrameCount >= 5)
bracket4 = rsiState.GetFrame(RsiDirection.South, 4);

var offset = CalculateOffset(currentAngle, (eyeScreen.Position - mousePos).Length(), scale);
DrawSightPartial(sightTexture, bracket1, bracket2, args.ScreenHandle, rot, mousePos, scale,_main ?? sight.MainColor,_second ?? sight.StrokeColor, offset, bracket3, bracket4);
}
else
{
var sightTexture = spriteSys.Frame0(sight.Sprite);
DrawOverlayPart(sightTexture, args.ScreenHandle, mousePos, scale, _main ?? sight.MainColor, _second ?? sight.StrokeColor);
}
}

#endregion
}

#region Starlight
private float CalculateOffset(float currentAngle, float distance, float scale)
{
var angleRad = currentAngle * MathF.PI / 180f;
var offset = MathF.Tan(angleRad) * distance;
offset *= scale;
// So if slider is in center: 0.5 + 0.5 = 1, meaning no change. If slider is at minimum: 0 + 0.5 = 0.5, meaning offset is halved. If slider is at maximum: 1 + 0.5 = 1.5, meaning offset is increased by 50%.
offset *= (_offset ?? 0.5f) + 0.5f;
return offset;
}

private void DrawSightPartial(Texture sight, Texture bracket1, Texture bracket2, DrawingHandleScreen screen, float rotation, Vector2 centerPos, float scale, Color mainColor, Color strokeColor, float offset, Texture? bracket3 = null, Texture? bracket4 = null)
{
DrawOverlayPart(sight, screen, centerPos, scale, mainColor, strokeColor);

var bracketSize1 = bracket1.Size * scale;
var bracketSize2 = bracket2.Size * scale;

if (_rotation)
screen.SetTransform(Matrix3x2.CreateRotation(rotation, centerPos));

var bracket1Pos = centerPos + new Vector2(-offset - bracketSize1.X * 0.5f, 0f);
var bracket2Pos = centerPos + new Vector2(offset + bracketSize2.X * 0.5f, 0f);
DrawOverlayPart(bracket1, screen, bracket1Pos, scale, mainColor, strokeColor);
DrawOverlayPart(bracket2, screen, bracket2Pos, scale, mainColor, strokeColor);

if (bracket3 != null)
{
var bracket3Pos = centerPos + new Vector2(0f, offset + bracketSize1.Y * 0.5f);
DrawOverlayPart(bracket3, screen, bracket3Pos, scale, mainColor, strokeColor);
}

if (bracket4 != null)
{
var bracket4Pos = centerPos + new Vector2(0f, -offset - bracketSize2.Y * 0.5f);
DrawOverlayPart(bracket4, screen, bracket4Pos, scale, mainColor, strokeColor);
}
}

private void DrawSight(Texture sight, DrawingHandleScreen screen, Vector2 centerPos, float scale)
private static void DrawOverlayPart(Texture texture, DrawingHandleScreen screen, Vector2 position, float scale, Color mainColor, Color strokeColor)
{
var sightSize = sight.Size * scale;
var expandedSize = sightSize + new Vector2(7f, 7f);
var size = texture.Size * scale;
screen.DrawTextureRect(texture,
UIBox2.FromDimensions(position - size * 0.5f, size), strokeColor);
screen.DrawTextureRect(texture,
UIBox2.FromDimensions(position - size * 0.5f - new Vector2(3f, 3f), size + new Vector2(7f, 7f)), mainColor);
}

screen.DrawTextureRect(sight,
UIBox2.FromDimensions(centerPos - sightSize * 0.5f, sightSize), StrokeColor);
screen.DrawTextureRect(sight,
UIBox2.FromDimensions(centerPos - expandedSize * 0.5f, expandedSize), MainColor);
private sealed class DummyCursor : ICursor
{
public void Dispose()
{
}
}

#endregion
}
111 changes: 103 additions & 8 deletions Content.Client/CombatMode/CombatModeSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
using Robust.Client.Player;
using Robust.Shared.Configuration;

#region Starlight
using Content.Shared._Starlight.CombatMode;
using Content.Shared.Starlight.CCVar;
using Robust.Shared.Prototypes;
#endregion

namespace Content.Client.CombatMode;

public sealed class CombatModeSystem : SharedCombatModeSystem
Expand All @@ -16,19 +22,43 @@ public sealed class CombatModeSystem : SharedCombatModeSystem
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IInputManager _inputManager = default!;
[Dependency] private readonly IEyeManager _eye = default!;
#region Starlight
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IClyde _clyde = default!;
#endregion

/// <summary>
/// Raised whenever combat mode changes.
/// </summary>
public event Action<bool>? LocalPlayerCombatModeUpdated;

#region Starlight
private bool _lastState = false;
private string _rangedSight = "GunSight";
private string _meleeSight = "MeleeSight";
private float _scale = 0.6f;
private float _offset = 0.5f;
private bool _rotation = true;
private Color _main = Color.White.WithAlpha(0.3f);
private Color _second = Color.Black.WithAlpha(0.5f);
#endregion

public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<CombatModeComponent, AfterAutoHandleStateEvent>(OnHandleState);

Subs.CVar(_cfg, CCVars.CombatModeIndicatorsPointShow, OnShowCombatIndicatorsChanged, true);
// Starlight-start
Subs.CVar(_cfg, StarlightCCVars.RangedSight, OnRangedSightChanged, true);
Subs.CVar(_cfg, StarlightCCVars.RangedSightScale, OnRangedSightScaleChanged, true);
Subs.CVar(_cfg, StarlightCCVars.RangedSightOffset, OnRangedSightOffsetChanged, true);
Subs.CVar(_cfg, StarlightCCVars.SightMainColor, OnSightMainColorChanged, true);
Subs.CVar(_cfg, StarlightCCVars.SightSecondColor, OnSightSecondColorChanged, true);
Subs.CVar(_cfg, StarlightCCVars.MeleeSight, OnMeleeSightChanged, true);
Subs.CVar(_cfg, StarlightCCVars.SightRotation, OnRotationChanged, true);
// Starlight-end
}

private void OnHandleState(EntityUid uid, CombatModeComponent component, ref AfterAutoHandleStateEvent args)
Expand Down Expand Up @@ -72,23 +102,88 @@ private void UpdateHud(EntityUid entity)
}

var inCombatMode = IsInCombatMode();
// Starlight-start
if (!inCombatMode)
_clyde.SetCursor(null);
// Starlight-end
LocalPlayerCombatModeUpdated?.Invoke(inCombatMode);
}

private void OnShowCombatIndicatorsChanged(bool isShow)
private void OnShowCombatIndicatorsChanged(bool isShow) // Starlight-edit: moved into another method
=> UpdateCombatIndicators(isShow);

#region Starlight

private void OnRangedSightChanged(string sight)
{
_rangedSight = sight;
UpdateCombatIndicators();
}

private void OnRangedSightScaleChanged(int scale)
{
float fScale = scale * 0.01f;
_scale = fScale;
UpdateCombatIndicators();
}

private void OnRangedSightOffsetChanged(int offset)
{
float fOffset = offset * 0.01f;
_offset = fOffset;
UpdateCombatIndicators();
}

private void OnSightMainColorChanged(string color)
{
_main = Color.FromHex(color).WithAlpha(0.3f);
UpdateCombatIndicators();
}

private void OnSightSecondColorChanged(string color)
{
if (isShow)
_second = Color.FromHex(color).WithAlpha(0.5f);
UpdateCombatIndicators();
}

private void OnMeleeSightChanged(string sight)
{
_meleeSight = sight;
UpdateCombatIndicators();
}

private void OnRotationChanged(bool rotation)
{
_rotation = rotation;
UpdateCombatIndicators();
}

private void UpdateCombatIndicators(bool? isShow = null)
{
if (isShow != null && isShow != _lastState)
_lastState = isShow.Value;

if ((isShow == null || !_lastState) && _overlayManager.HasOverlay<CombatModeIndicatorsOverlay>())
_overlayManager.RemoveOverlay<CombatModeIndicatorsOverlay>();
if ((isShow == null || _lastState) && _prototypeManager.TryIndex<SightPrototype>(_rangedSight, out var ranged) && _prototypeManager.TryIndex<SightPrototype>(_meleeSight, out var melee))
{
_overlayManager.AddOverlay(new CombatModeIndicatorsOverlay(
_inputManager,
EntityManager,
_prototypeManager,
_eye,
this,
EntityManager.System<HandsSystem>()));
}
else
{
_overlayManager.RemoveOverlay<CombatModeIndicatorsOverlay>();
EntityManager.System<HandsSystem>(),
_clyde,
ranged,
melee,
_scale,
_offset,
_main,
_second,
_rotation));
}
}
}

#endregion
}
12 changes: 8 additions & 4 deletions Content.Client/Options/UI/OptionsMenu.xaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
<DefaultWindow xmlns="https://spacestation14.io"
xmlns:tabs="clr-namespace:Content.Client.Options.UI.Tabs"
Title="{Loc 'ui-options-title'}"
MinSize="800 450">
<DefaultWindow
xmlns="https://spacestation14.io"
xmlns:stabs="clr-namespace:Content.Client._Starlight.Options.UI.Tabs"
xmlns:tabs="clr-namespace:Content.Client.Options.UI.Tabs"
Title="{Loc 'ui-options-title'}"
MinSize="800 450">
<TabContainer Name="Tabs" Access="Public">
<tabs:MiscTab Name="MiscTab" />
<!-- Starlight-edit: UI Tab -->
<stabs:UITab Name="UITab" />
<tabs:GraphicsTab Name="GraphicsTab" />
<tabs:KeyRebindTab Name="KeyRebindTab" />
<tabs:AudioTab Name="AudioTab" />
Expand Down
Loading
Loading