Skip to content
Merged
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
53 changes: 52 additions & 1 deletion Content.Client/_Scp/Blinking/BlinkingSystem.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
using Content.Client._Scp.Shaders.Common;
using Content.Shared._Scp.Blinking;
using Content.Shared.Alert;
using Robust.Client.Audio;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Shared.Audio;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;

namespace Content.Client._Scp.Blinking;
Expand All @@ -13,6 +15,7 @@ public sealed class BlinkingSystem : SharedBlinkingSystem
{
[Dependency] private readonly AudioSystem _audio = default!;
[Dependency] private readonly CompatibilityModeActiveWarningSystem _compatibility = default!;
[Dependency] private readonly AlertsSystem _alerts = default!;
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IOverlayManager _overlayMan = default!;
[Dependency] private readonly IGameTiming _timing = default!;
Expand All @@ -25,6 +28,7 @@ public sealed class BlinkingSystem : SharedBlinkingSystem

private BlinkingOverlay _overlay = default!;
private const float DefaultAnimationDuration = 0.4f;
private ProtoId<AlertPrototype>? _localBlinkingAlert;

public override void Initialize()
{
Expand All @@ -42,6 +46,29 @@ public override void Initialize()
_overlay.OnAnimationFinished += SetDefaultAnimationDuration;
}

public override void Update(float frameTime)
{
base.Update(frameTime);

if (_player.LocalEntity is not { Valid: true } localEntity)
return;

if (!BlinkableQuery.TryComp(localEntity, out var blinkable))
{
if (_localBlinkingAlert.HasValue)
_alerts.ClearAlert(localEntity, _localBlinkingAlert.Value);

_localBlinkingAlert = null;
return;
}

if (_localBlinkingAlert.HasValue && _localBlinkingAlert.Value != blinkable.BlinkingAlert)
_alerts.ClearAlert(localEntity, _localBlinkingAlert.Value);

_localBlinkingAlert = blinkable.BlinkingAlert;
UpdateAlert((localEntity, blinkable));
}

protected override void OnOpenedEyes(Entity<BlinkableComponent> ent, ref EntityOpenedEyesEvent args)
{
base.OnOpenedEyes(ent, ref args);
Expand All @@ -66,6 +93,11 @@ private void OnAttached(Entity<BlinkableComponent> ent, ref LocalPlayerAttachedE

private void OnDetached(Entity<BlinkableComponent> ent, ref LocalPlayerDetachedEvent args)
{
if (_localBlinkingAlert.HasValue)
_alerts.ClearAlert(ent.Owner, _localBlinkingAlert.Value);

_localBlinkingAlert = null;

if (!_overlayMan.HasOverlay<BlinkingOverlay>())
return;

Expand All @@ -84,7 +116,7 @@ private void OnEyesStateChanged(EntityEyesStateChanged ev)

var ent = GetEntity(ev.NetEntity);

if (!TryComp<BlinkableComponent>(ent, out var blinkable))
if (!BlinkableQuery.TryComp(ent, out var blinkable))
return;

if (ev.NewState == EyesState.Closed)
Expand Down Expand Up @@ -195,4 +227,23 @@ private void SetDefaultAnimationDuration()
{
_overlay.AnimationDuration = _compatibility.ShouldUseShaders ? DefaultAnimationDuration : 0f;
}

/// <summary>
/// Актуализирует иконку моргания справа у панели чата игрока
/// </summary>
private void UpdateAlert(Entity<BlinkableComponent> ent)
{
// Если в данный момент глаза закрыты, то выставляем иконку с закрытым глазом
if (IsBlind(ent.AsNullable()))
{
_alerts.ShowAlert(ent.Owner, ent.Comp.BlinkingAlert, 4);
return;
}

var timeToNextBlink = ent.Comp.NextBlink - _timing.CurTime;
var denom = MathF.Max(0.001f, (float)(ent.Comp.BlinkingInterval.TotalSeconds - ent.Comp.BlinkingDuration.TotalSeconds));
var severity = (short) Math.Clamp(4 - (float) timeToNextBlink.TotalSeconds / denom * 4, 0, 4);

_alerts.ShowAlert(ent.Owner, ent.Comp.BlinkingAlert, severity);
}
}
3 changes: 1 addition & 2 deletions Content.Client/_Scp/Fear/FearSystem.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Content.Shared._Scp.Fear;
using Content.Shared._Scp.Fear.Components;
using Content.Shared._Scp.Fear.Components;
using Content.Shared._Scp.Fear.Systems;
using Content.Shared._Sunrise.Heartbeat;
using Robust.Client.Audio;
Expand Down
50 changes: 50 additions & 0 deletions Content.Client/_Scp/Scp939/Scp939HudSystem.Overlay.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using Content.Shared._Scp.Scp939;
using Robust.Client.Graphics;
using Robust.Shared.Player;

namespace Content.Client._Scp.Scp939;

public sealed partial class Scp939HudSystem
{
[Dependency] private readonly IOverlayManager _overlayManager = default!;

private void InitializeOverlay()
{
SubscribeLocalEvent<Scp939Component, LocalPlayerAttachedEvent>(OnPlayerAttached);
SubscribeLocalEvent<Scp939Component, LocalPlayerDetachedEvent>(OnPlayerDetached);
}

private void OnPlayerAttached(Entity<Scp939Component> ent, ref LocalPlayerAttachedEvent args)
{
_scp939Component = ent.Comp;
AddOverlays();
}

private void OnPlayerDetached(Entity<Scp939Component> ent, ref LocalPlayerDetachedEvent args)
{
_scp939Component = null;
}

private void AddOverlays()
{
if (_overlaysPresented)
return;

_overlayManager.AddOverlay(_setAlphaOverlay);
_overlayManager.AddOverlay(_resetAlphaOverlay);

_overlaysPresented = true;
}

private void RemoveOverlays()
{
if (!_overlaysPresented)
return;

_overlayManager.RemoveOverlay(_setAlphaOverlay);
_overlayManager.RemoveOverlay(_resetAlphaOverlay);

CachedBaseAlphas.Clear();
_overlaysPresented = false;
}
}
162 changes: 162 additions & 0 deletions Content.Client/_Scp/Scp939/Scp939HudSystem.Visibility.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
using Content.Shared._Scp.Scp939;
using Content.Shared.Standing;
using Content.Shared.Throwing;
using Content.Shared.Weapons.Melee.Events;
using Robust.Shared.Physics.Events;
using Robust.Shared.Random;

namespace Content.Client._Scp.Scp939;

public sealed partial class Scp939HudSystem
{
[Dependency] private readonly IRobustRandom _random = default!;

private void InitializeVisibility()
{
SubscribeLocalEvent((Entity<ActiveScp939VisibilityComponent> ent, ref StartCollideEvent args)
=> OnCollide(ent, args.OtherEntity));
SubscribeLocalEvent((Entity<ActiveScp939VisibilityComponent> ent, ref EndCollideEvent args)
=> OnCollide(ent, args.OtherEntity));
SubscribeLocalEvent<ActiveScp939VisibilityComponent, AfterAutoHandleStateEvent>(OnVisibilityStateUpdated);

SubscribeLocalEvent<ActiveScp939VisibilityComponent, MoveEvent>(OnMove);

SubscribeLocalEvent<ActiveScp939VisibilityComponent, ThrowEvent>(OnThrow);
SubscribeLocalEvent<ActiveScp939VisibilityComponent, StoodEvent>(OnStood);
SubscribeLocalEvent<ActiveScp939VisibilityComponent, MeleeAttackEvent>(OnMeleeAttack);
SubscribeLocalEvent<ActiveScp939VisibilityComponent, DownedEvent>(OnDown);
}

private void OnVisibilityStateUpdated(Entity<ActiveScp939VisibilityComponent> ent, ref AfterAutoHandleStateEvent args)
{
if (ent.Comp.LastHandledVisibilityResetCounter == ent.Comp.VisibilityResetCounter)
return;

ent.Comp.LastHandledVisibilityResetCounter = ent.Comp.VisibilityResetCounter;
ent.Comp.VisibilityAcc = Scp939VisibilityComponent.InitialVisibilityAcc;
}

public override void Update(float frameTime)
{
base.Update(frameTime);

if (!IsActive)
return;

_lastUpdateTime += frameTime;
if (_lastUpdateTime < UpdateInterval)
return;

var delta = _lastUpdateTime;
_lastUpdateTime = 0f;

var query = EntityQueryEnumerator<ActiveScp939VisibilityComponent>();
while (query.MoveNext(out _, out var visibilityComponent))
{
if (visibilityComponent.VisibilityAcc >= visibilityComponent.HideTime)
continue;

visibilityComponent.VisibilityAcc = MathF.Min(visibilityComponent.VisibilityAcc + delta, visibilityComponent.HideTime);
}
}

private void OnMove(Entity<ActiveScp939VisibilityComponent> ent, ref MoveEvent args)
{
if (!IsActive)
return;

// В зависимости от наличие защит или проблем со зрением у 939 изменяется то, насколько хорошо мы видим жертву
if (ModifyAcc(ent.Comp, out var modifier)) // Если зрение затруднено
{
ent.Comp.VisibilityAcc *= modifier;
}
else if (_scp939ProtectionQuery.HasComp(ent)) // Если имеется защита(тихое хождение)
{
return;
}
else // Если со зрением все ок
{
ent.Comp.VisibilityAcc = 0;
}

if (!_movementSpeedQuery.TryComp(ent, out var speedModifierComponent)
|| !_physicsQuery.TryComp(ent, out var physicsComponent))
{
return;
}

var currentVelocity = physicsComponent.LinearVelocity.Length();

if (speedModifierComponent.BaseWalkSpeed > currentVelocity)
ent.Comp.VisibilityAcc = ent.Comp.HideTime / 2f;
}


private void OnCollide(Entity<ActiveScp939VisibilityComponent> ent, EntityUid otherEntity)
{
if (!IsActive)
return;

if (!HasComp<Scp939Component>(otherEntity))
return;

MobDidSomething(ent);
}

private void OnThrow(Entity<ActiveScp939VisibilityComponent> ent, ref ThrowEvent args)
{
if (!IsActive)
return;

MobDidSomething(ent);
}

private void OnStood(Entity<ActiveScp939VisibilityComponent> ent, ref StoodEvent args)
{
if (!IsActive)
return;

MobDidSomething(ent);
}

private void OnMeleeAttack(Entity<ActiveScp939VisibilityComponent> ent, ref MeleeAttackEvent args)
{
if (!IsActive)
return;

MobDidSomething(ent);
}

private void OnDown(Entity<ActiveScp939VisibilityComponent> ent, ref DownedEvent args)
{
if (!IsActive)
return;

MobDidSomething(ent);
}

private void MobDidSomething(Entity<ActiveScp939VisibilityComponent> ent)
{
ent.Comp.VisibilityAcc = Scp939VisibilityComponent.InitialVisibilityAcc;
}

// TODO: Переделать под статус эффект и добавить его в панель статус эффектов, а то непонятно игруну
/// <summary>
/// Если вдруг собачка плохо видит
/// </summary>
private bool ModifyAcc(ActiveScp939VisibilityComponent visibilityComponent, out int modifier)
{
// 1 = отсутствие модификатора
modifier = 1;

if (_scp939Component == null)
return false;

if (!_scp939Component.PoorEyesight)
return false;

modifier = _random.Next(visibilityComponent.MinValue, visibilityComponent.MaxValue);

return true;
}
}
Loading
Loading