Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Красивые циферки урона #993

Merged
merged 16 commits into from
Jan 5, 2025
Merged
Show file tree
Hide file tree
Changes from 13 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
1 change: 1 addition & 0 deletions Content.Client/Options/UI/Tabs/ExtraTab.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<Label Text="{Loc 'ui-options-sunrise-general-combat'}"
StyleClasses="LabelKeyText"/>
<CheckBox Name="DamageOverlayCheckBox" Text="{Loc 'ui-options-damage-overlay'}" />
<ui:OptionDropDown Name="DamageOverlayPreset" Title="{Loc 'ui-options-damage-overlay-preset'}" />

<!-- Audio -->
<Label Text="{Loc 'ui-options-sunrise-general-audio'}" StyleClasses="LabelKeyText"/>
Expand Down
11 changes: 11 additions & 0 deletions Content.Client/Options/UI/Tabs/ExtraTab.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Content.Client.Audio;
using Content.Server.GameTicking.Prototypes;
using Content.Shared._Sunrise.DamageOverlay;
using Content.Shared._Sunrise.Lobby;
using Content.Shared._Sunrise.SunriseCCVars;
using Content.Shared.GameTicking;
Expand Down Expand Up @@ -82,12 +83,22 @@ public ExtraTab()
var layoutLoc = Loc.GetString($"lobby-animation-{lobbyAnimation.ID}");
lobbyAnimations.Add(new OptionDropDownCVar<string>.ValueOption(lobbyAnimation.ID, layoutLoc));
}

ThereDrD0 marked this conversation as resolved.
Show resolved Hide resolved
var damageOverlayPresets = new List<OptionDropDownCVar<string>.ValueOption>();
var damageOverlayPresetPrototypes = _prototypeManager.EnumeratePrototypes<DamageOverlayPrototype>();
foreach (var preset in damageOverlayPresetPrototypes)
{
var loc = Loc.GetString($"damage-overlay-{preset.ID}");
damageOverlayPresets.Add(new OptionDropDownCVar<string>.ValueOption(preset.ID, loc));
}

Control.AddOptionDropDown(SunriseCCVars.LobbyBackgroundType, DropDownLobbyBackgroundType, lobbyBackgroundTypes);
Control.AddOptionDropDown(SunriseCCVars.LobbyArt, DropDownLobbyArt, lobbyArts);
Control.AddOptionDropDown(SunriseCCVars.LobbyAnimation, DropDownLobbyAnimation, lobbyAnimations);
Control.AddOptionDropDown(SunriseCCVars.LobbyParallax, DropDownLobbyParallax, lobbyParallaxes);
Control.AddOptionPercentSlider(SunriseCCVars.LobbyOpacity, LobbyOpacitySlider);
Control.AddOptionCheckBox(SunriseCCVars.DamageOverlay, DamageOverlayCheckBox);
Control.AddOptionDropDown(SunriseCCVars.DamageOverlayPreset, DamageOverlayPreset, damageOverlayPresets);

Control.Initialize();
}
Expand Down
12 changes: 11 additions & 1 deletion Content.Client/Popups/PopupOverlay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,18 @@ private void DrawWorld(DrawingHandleScreen worldHandle, OverlayDrawArgs args, fl
e => e == popup.InitialPos.EntityId || e == ourEntity, entMan: _entManager))
continue;

// Sunrise edit start
var horizontalDirection = 0f;
if (ourEntity.HasValue)
{
var moverCoords = _transform.GetMoverCoordinates(ourEntity.Value);
// float horizontalDirection = 0f -1 for left, 1 for right.
horizontalDirection = moverCoords.X <= popup.InitialPos.X ? 1f : -1f;
}
// Sunrise edit end

var pos = Vector2.Transform(mapPos.Position, matrix);
_controller.DrawPopup(popup, worldHandle, pos, scale);
_controller.DrawPopup(popup, worldHandle, pos, scale, horizontalDirection); // Sunrise edit
}
}
}
26 changes: 24 additions & 2 deletions Content.Client/Popups/PopupUIController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,24 @@ public void OnStateExited(GameplayState state)
_popupControl = null;
}

public void DrawPopup(PopupSystem.PopupLabel popup, DrawingHandleScreen handle, Vector2 position, float scale)
public void DrawPopup(PopupSystem.PopupLabel popup, DrawingHandleScreen handle, Vector2 position, float scale, float horizontalDirection = 0f)
{
var lifetime = PopupSystem.GetPopupLifetime(popup);

// Keep alpha at 1 until TotalTime passes half its lifetime, then gradually decrease to 0.
var alpha = MathF.Min(1f, 1f - MathF.Max(0f, popup.TotalTime - lifetime / 2) * 2 / lifetime);

var updatedPosition = position - new Vector2(0f, MathF.Min(8f, 12f * (popup.TotalTime * popup.TotalTime + popup.TotalTime)));
var font = _smallFont;
var color = Color.White.WithAlpha(alpha);
var useHorizontalDirection = false;

switch (popup.Type)
{
// Sunrise start
case PopupType.SmallFloating:
useHorizontalDirection = true;
break;
// Sunrise end
case PopupType.SmallCaution:
color = Color.Red;
break;
Expand All @@ -71,6 +76,13 @@ public void DrawPopup(PopupSystem.PopupLabel popup, DrawingHandleScreen handle,
font = _mediumFont;
color = Color.Red;
break;
// Sunrise start
case PopupType.MediumCautionFloating:
font = _mediumFont;
color = Color.Red;
useHorizontalDirection = true;
break;
// Sunrise end
case PopupType.Large:
font = _largeFont;
color = Color.LightGray;
Expand All @@ -87,6 +99,16 @@ public void DrawPopup(PopupSystem.PopupLabel popup, DrawingHandleScreen handle,
// Sunrise-End
}

// Sunrise edit start
if (!useHorizontalDirection)
horizontalDirection = 0f;

// Calculate horizontal offset based on direction.
var horizontalOffset = horizontalDirection * MathF.Min(8f, 12f * popup.TotalTime);
// Adjust position to move both vertically and horizontally.
var updatedPosition = position + new Vector2(horizontalOffset, -MathF.Min(8f, 12f * (popup.TotalTime * popup.TotalTime + popup.TotalTime)));
// Sunrise edit end

var dimensions = handle.GetDimensions(font, popup.Text, scale);
handle.DrawString(font, updatedPosition - dimensions / 2f, popup.Text, scale, color.WithAlpha(alpha));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Content.Shared._Sunrise.DamageOverlay;
using Content.Shared._Sunrise.SunriseCCVars;
using Robust.Shared.Configuration;
using Robust.Shared.Prototypes;

namespace Content.Client._Sunrise.DamageOverlay;

Expand All @@ -13,17 +14,24 @@ public override void Initialize()
base.Initialize();

_cfg.OnValueChanged(SunriseCCVars.DamageOverlay, OnDamageOverlayOptionChanged, true);
_cfg.OnValueChanged(SunriseCCVars.DamageOverlayPreset, OnDamageOverlayPresetChanged, true);
}

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

_cfg.UnsubValueChanged(SunriseCCVars.DamageOverlay, OnDamageOverlayOptionChanged);
_cfg.UnsubValueChanged(SunriseCCVars.DamageOverlayPreset, OnDamageOverlayPresetChanged);
}

private void OnDamageOverlayOptionChanged(bool option)
{
RaiseNetworkEvent(new DamageOverlayOptionEvent(option));
}

private void OnDamageOverlayPresetChanged(string preset)
{
RaiseNetworkEvent(new DamageOverlayPresetChangedEvent(preset));
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,29 @@
namespace Content.Server._Sunrise.DamageOverlay;
using Content.Shared.Popups;

namespace Content.Server._Sunrise.DamageOverlay;

[RegisterComponent, Access(typeof(DamageOverlaySystem))]
public sealed partial class DamageOverlayComponent : Component
{
[DataField]
public PopupType DamagePopupType = PopupType.MediumCautionFloating;

[DataField]
public PopupType HealPopupType = PopupType.LargeGreen;

[DataField]
public float Radius = 0.5f;

[DataField]
public HashSet<string> IgnoredDamageTypes = new ()
{

};

/// <summary>
/// Является ли ентити структурой
/// </summary>
/// TODO: Более адекватная реализация
[DataField]
public bool IsStructure;
}
102 changes: 85 additions & 17 deletions Content.Server/_Sunrise/DamageOverlay/DamageOverlaySystem.cs
Original file line number Diff line number Diff line change
@@ -1,25 +1,35 @@
using System.Linq;
using System.Numerics;
using Content.Server.Mind;
using Content.Server.Popups;
using Content.Shared._Sunrise.DamageOverlay;
using Content.Shared.Damage;
using Content.Shared.FixedPoint;
using Content.Shared.Popups;
using Robust.Shared.Map;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;

namespace Content.Server._Sunrise.DamageOverlay;

public sealed class DamageOverlaySystem : EntitySystem
{
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly MindSystem _mindSystem = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;

private readonly List<ICommonSession> _disabledSessions = new();
private readonly Dictionary<ICommonSession, DamageOverlayPrototype> _playerSettings = new ();

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

SubscribeLocalEvent<DamageOverlayComponent, DamageChangedEvent>(OnDamageChange);

SubscribeNetworkEvent<DamageOverlayOptionEvent>(OnDamageOverlayOption);
SubscribeNetworkEvent<DamageOverlayPresetChangedEvent>(OnDamageOverlayPresetChanged);
}

private async void OnDamageOverlayOption(DamageOverlayOptionEvent ev, EntitySessionEventArgs args)
Expand All @@ -30,43 +40,101 @@ private async void OnDamageOverlayOption(DamageOverlayOptionEvent ev, EntitySess
_disabledSessions.Add(args.SenderSession);
}

private void OnDamageChange(EntityUid uid, DamageOverlayComponent component, DamageChangedEvent args)
private async void OnDamageOverlayPresetChanged(DamageOverlayPresetChangedEvent ev, EntitySessionEventArgs args)
{
if (args.SenderSession.AttachedEntity == null)
return;

if (!_prototype.TryIndex(ev.Preset, out var presetPrototype))
return;

_playerSettings[args.SenderSession] = presetPrototype;
}

private void OnDamageChange(Entity<DamageOverlayComponent> ent, ref DamageChangedEvent args)
{
if (args.DamageDelta == null)
return;

var damageDelta = args.DamageDelta.GetTotal();
var coords = GenerateRandomCoordinates(Transform(ent).Coordinates, ent.Comp.Radius);

if (_mindSystem.TryGetMind(uid, out _, out var mindTarget) && mindTarget.Session != null)
// Проверка на игнорируемые типы урона
if (args.DamageDelta.DamageDict.Keys.Any(item => ent.Comp.IgnoredDamageTypes.Contains(item)))
return;

if (_mindSystem.TryGetMind(ent, out _, out var mindTarget) && mindTarget.Session != null)
{
if (_disabledSessions.Contains(mindTarget.Session))
if (IsDisabledByClient(mindTarget.Session, ent, args.DamageDelta))
return;

if (damageDelta > 0)
{
_popupSystem.PopupEntity($"-{damageDelta}", uid, mindTarget.Session, PopupType.LargeCaution);
_popupSystem.PopupCoordinates($"-{damageDelta}", coords, mindTarget.Session, ent.Comp.DamagePopupType);
}
}

if (args.Origin == null)
return;

if (_mindSystem.TryGetMind(args.Origin.Value, out _, out var mindOrigin) && mindOrigin.Session != null)
if (!_mindSystem.TryGetMind(args.Origin.Value, out _, out var mindOrigin) || mindOrigin.Session == null)
return;

if (IsDisabledByClient(mindOrigin.Session, ent, args.DamageDelta))
return;

if (damageDelta > 0)
{
if (_disabledSessions.Contains(mindOrigin.Session))
// Ударили себя
if (args.Origin == ent)
return;

if (damageDelta > 0)
{
if (args.Origin == uid)
return;
_popupSystem.PopupCoordinates($"-{damageDelta}", coords, mindOrigin.Session, ent.Comp.DamagePopupType);
}
else
{
_popupSystem.PopupCoordinates($"+{FixedPoint2.Abs(damageDelta)}", coords, mindOrigin.Session, ent.Comp.HealPopupType);
}
}

_popupSystem.PopupEntity($"-{damageDelta}", uid, mindOrigin.Session, PopupType.LargeCaution);
}
else
{
_popupSystem.PopupEntity($"+{FixedPoint2.Abs(damageDelta)}", uid, mindOrigin.Session, PopupType.LargeGreen);
}
private EntityCoordinates GenerateRandomCoordinates(EntityCoordinates center, float radius)
{
// Случайное направление в радианах.
var angle = _random.NextDouble() * 2 * Math.PI;

// Случайное расстояние от центра в пределах радиуса.
var distance = _random.NextDouble() * radius;

// Вычисление смещения.
var offsetX = (float)(Math.Cos(angle) * distance);
var offsetY = (float)(Math.Sin(angle) * distance);

// Создание новых координат с учетом смещения.
var newPosition = new Vector2(center.Position.X + offsetX, center.Position.Y + offsetY);

return new EntityCoordinates(center.EntityId, newPosition);
}

/// <summary>
/// Проверка на то, включен ли у игрока данный урон для отображения
/// </summary>
private bool IsDisabledByClient(ICommonSession session, Entity<DamageOverlayComponent> target, DamageSpecifier damageDelta)
{
if (_disabledSessions.Contains(session))
return true;

if (_playerSettings.TryGetValue(session, out var playerPreset))
{
if (damageDelta.DamageDict.Keys.Any(item => playerPreset.Types.Contains(item)))
return true;

if (target.Comp.IsStructure && !playerPreset.StructureDamageEnabled)
return true;

if (target == session.AttachedEntity && !playerPreset.ToPlayerDamageEnabled)
return true;
}

return false;
}
}
2 changes: 2 additions & 0 deletions Content.Shared/Popups/SharedPopupSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -186,11 +186,13 @@ public enum PopupType : byte
/// </summary>
Small,
SmallCaution,
SmallFloating, // Sunrise
/// <summary>
/// Medium popups should be used for actions which are not spammable but may not be particularly important.
/// </summary>
Medium,
MediumCaution,
MediumCautionFloating, // Sunrise
/// <summary>
/// Large popups should be used for actions which may be important or very important to one or more users,
/// but is not life-threatening.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;

namespace Content.Shared._Sunrise.DamageOverlay;
Expand All @@ -11,3 +12,13 @@ public DamageOverlayOptionEvent(bool enabled)
Enabled = enabled;
}
}

[Serializable, NetSerializable]
public sealed class DamageOverlayPresetChangedEvent : EntityEventArgs
{
public ProtoId<DamageOverlayPrototype> Preset { get; }
public DamageOverlayPresetChangedEvent(ProtoId<DamageOverlayPrototype> preset)
{
Preset = preset;
}
}
18 changes: 18 additions & 0 deletions Content.Shared/_Sunrise/DamageOverlay/DamageOverlayPrototype.cs
ThereDrD0 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Robust.Shared.Prototypes;

namespace Content.Shared._Sunrise.DamageOverlay;

[Prototype]
public sealed partial class DamageOverlayPrototype : IPrototype
{
[IdDataField] public string ID { get; } = string.Empty;

[DataField]
public HashSet<string> Types = new();

[DataField]
public bool StructureDamageEnabled = true;

[DataField]
public bool ToPlayerDamageEnabled = true;
}
3 changes: 3 additions & 0 deletions Content.Shared/_Sunrise/SunriseCCVars/SunriseCCVars.cs
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,9 @@ public static readonly CVarDef<bool>
public static readonly CVarDef<bool> DamageOverlay =
CVarDef.Create("damage.overlay", true, CVar.CLIENTONLY | CVar.ARCHIVE);

public static readonly CVarDef<string> DamageOverlayPreset =
CVarDef.Create("damage.overlay_preset", "All", CVar.CLIENTONLY | CVar.ARCHIVE);

public static readonly CVarDef<float> DamageVariance =
CVarDef.Create("damage.variance", 0.15f, CVar.SERVER | CVar.REPLICATED);

Expand Down
Loading
Loading