Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
45637dc
refactor-step-1
WardexOfficial Apr 26, 2026
8fa71ef
Merge branch 'master' into refactor-wrdx
WardexOfficial Apr 26, 2026
263c9e4
пхех
WardexOfficial Apr 26, 2026
8eb8c69
Merge branch 'refactor-wrdx' of https://github.com/WardexOfficial/fir…
WardexOfficial Apr 26, 2026
5f2985e
пупупу
WardexOfficial Apr 26, 2026
902f1e5
гребаные акшионы 939
WardexOfficial Apr 28, 2026
762fdf3
Доработки
WardexOfficial Apr 28, 2026
be49d4e
Merge branch 'master' into refactor-wrdx
WardexOfficial Apr 28, 2026
f39e0fb
пупупу
WardexOfficial Apr 28, 2026
6910232
Merge branch 'refactor-wrdx' of https://github.com/WardexOfficial/fir…
WardexOfficial Apr 28, 2026
638f5b2
bruuh
WardexOfficial Apr 30, 2026
ae7e2b3
Merge branch 'master' into refactor-wrdx
WardexOfficial Apr 30, 2026
7678d70
Merge branch 'refactor-wrdx' of https://github.com/WardexOfficial/fir…
WardexOfficial Apr 30, 2026
834c45c
ойе, остатки
WardexOfficial Apr 30, 2026
61a66bc
Вишинка на торте
WardexOfficial Apr 30, 2026
e0ea076
Merge branch 'master' into refactor-wrdx
WardexOfficial Apr 30, 2026
300c5c4
да ёп
WardexOfficial Apr 30, 2026
9bfeb32
Merge branch 'refactor-wrdx' of https://github.com/WardexOfficial/fir…
WardexOfficial Apr 30, 2026
1d450bc
брууум
WardexOfficial May 1, 2026
1392bcb
Merge branch 'master' into refactor-wrdx
WardexOfficial May 1, 2026
1b28542
пупупу
WardexOfficial May 2, 2026
c45219a
ой
WardexOfficial May 2, 2026
630b585
ой x2
WardexOfficial May 2, 2026
ef050d6
а ты прав
WardexOfficial May 2, 2026
ea9c550
ScpTriggerOnAction
WardexOfficial May 2, 2026
6530359
кхм
WardexOfficial May 7, 2026
cd03e51
пупупу
WardexOfficial May 7, 2026
dd1dd3f
Merge branch 'master' into refactor-wrdx
WardexOfficial May 15, 2026
2a6cb15
Merge branch 'master' into refactor-wrdx
WardexOfficial Jul 10, 2026
6eeef19
fixes
WardexOfficial Jul 15, 2026
2e0af41
Merge branch 'refactor-wrdx' of https://github.com/WardexOfficial/fir…
WardexOfficial Jul 15, 2026
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
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
using Content.Shared._Scp.Scp939;
using Content.Shared._Scp.Other.ScpOnSoundVisibility;
using Robust.Client.Graphics;
using Robust.Shared.Player;

namespace Content.Client._Scp.Scp939;
namespace Content.Client._Scp.Other.ScpOnSoundVisibility;

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

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

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

private void OnPlayerDetached(Entity<Scp939Component> ent, ref LocalPlayerDetachedEvent args)
private void OnPlayerDetached(Entity<ScpOnSoundVisibilityViewerComponent> ent, ref LocalPlayerDetachedEvent args)
{
_scp939Component = null;
_viewerComponent = null;
}
Comment thread
WardexOfficial marked this conversation as resolved.

private void AddOverlays()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,293 @@
using Content.Client.Overlays;
using Content.Client.SSDIndicator;
using Content.Shared._Scp.Other.ScpOnSoundVisibility;
using Content.Shared.Examine;
using Content.Shared.Inventory.Events;
using Content.Shared.Movement.Components;
using Content.Shared.Standing;
using Content.Shared.StatusIcon.Components;
using Content.Shared.Throwing;
using Content.Shared.Weapons.Melee.Events;
using Content.Shared.Whitelist;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Events;
using Robust.Shared.Random;

namespace Content.Client._Scp.Other.ScpOnSoundVisibility;

public sealed partial class ScpOnSoundVisibilityHudSystem : EquipmentHudSystem<ScpOnSoundVisibilityViewerComponent>
{
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
[Dependency] private readonly IRobustRandom _random = default!;

Comment thread
WardexOfficial marked this conversation as resolved.
Outdated
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;

internal readonly List<(Entity<SpriteComponent> Ent, float BaseAlpha)> CachedBaseAlphas = new(64);
Comment thread
WardexOfficial marked this conversation as resolved.
Outdated

private EntityQuery<EyeComponent> _eyeQuery;
private EntityQuery<MovementSpeedModifierComponent> _movementSpeedQuery;
private EntityQuery<PhysicsComponent> _physicsQuery;

private ScpOnSoundVisibilitySetAlphaOverlay _setAlphaOverlay = default!;
private ScpOnSoundVisibilityResetAlphaOverlay _resetAlphaOverlay = default!;

private ScpOnSoundVisibilityViewerComponent? _viewerComponent;
Comment thread
WardexOfficial marked this conversation as resolved.
Outdated

private bool _overlaysPresented;
private float _lastUpdateTime;
private const float UpdateInterval = 0.05f;

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

InitializeOverlay();

SubscribeLocalEvent<ActiveScpOnSoundVisibilityComponent, GetStatusIconsEvent>(OnGetStatusIcons, after: [typeof(SSDIndicatorSystem)]);
SubscribeLocalEvent<ActiveScpOnSoundVisibilityComponent, ExamineAttemptEvent>(OnExamine);

SubscribeLocalEvent((Entity<ActiveScpOnSoundVisibilityComponent> ent, ref StartCollideEvent args)
=> OnCollide(ent, args.OtherEntity));
SubscribeLocalEvent((Entity<ActiveScpOnSoundVisibilityComponent> ent, ref EndCollideEvent args)
Comment thread
WardexOfficial marked this conversation as resolved.
Outdated
=> OnCollide(ent, args.OtherEntity));
SubscribeLocalEvent<ActiveScpOnSoundVisibilityComponent, AfterAutoHandleStateEvent>(OnVisibilityStateUpdated);

SubscribeLocalEvent<ActiveScpOnSoundVisibilityComponent, MoveEvent>(OnMove);

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

_eyeQuery = GetEntityQuery<EyeComponent>();
_movementSpeedQuery = GetEntityQuery<MovementSpeedModifierComponent>();
_physicsQuery = GetEntityQuery<PhysicsComponent>();

_setAlphaOverlay = new();
_resetAlphaOverlay = new();
}

public override void Shutdown()
{
RestoreCachedBaseAlphas();
RemoveOverlays();

_setAlphaOverlay.Dispose();
_resetAlphaOverlay.Dispose();

base.Shutdown();
}

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

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

private void OnExamine(Entity<ActiveScpOnSoundVisibilityComponent> ent, ref ExamineAttemptEvent args)
{
if (!IsActive)
return;

var visibility = GetVisibility(ent);

if (visibility < 0.2f)
args.Cancel();
}

private void OnGetStatusIcons(Entity<ActiveScpOnSoundVisibilityComponent> ent, ref GetStatusIconsEvent args)
{
if (!IsActive)
return;

var visibility = GetVisibility(ent);

if (visibility <= 0.5f)
Comment thread
WardexOfficial marked this conversation as resolved.
Outdated
args.StatusIcons.Clear();
}

protected override void UpdateInternal(RefreshEquipmentHudEvent<ScpOnSoundVisibilityViewerComponent> args)
{
base.UpdateInternal(args);

_viewerComponent = args.Components.Count > 0 ? args.Components[0] : null;
AddOverlays();
}

protected override void DeactivateInternal()
{
base.DeactivateInternal();

_viewerComponent = null;
_lastUpdateTime = 0f;

RestoreCachedBaseAlphas();
RemoveOverlays();
}

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

if (!IsActive)
return;

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

var delta = _lastUpdateTime;
_lastUpdateTime = 0f;
Comment thread
WardexOfficial marked this conversation as resolved.
Outdated

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

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

internal bool CanDraw(in OverlayDrawArgs args)
Comment thread
WardexOfficial marked this conversation as resolved.
Outdated
{
if (!IsActive)
return false;

if (_playerManager.LocalEntity is not { } player)
return false;

if (!_eyeQuery.TryComp(player, out var eye))
return false;

return args.Viewport.Eye == eye.Eye;
}

internal void RestoreCachedBaseAlphas()
{
foreach (var (ent, baseAlpha) in CachedBaseAlphas)
{
if (!EntityManager.EntityExists(ent))
continue;

_sprite.SetColor(ent.AsNullable(), ent.Comp.Color.WithAlpha(baseAlpha));
}

CachedBaseAlphas.Clear();
}

internal static float GetVisibility(Entity<ActiveScpOnSoundVisibilityComponent> ent)
{
var acc = ent.Comp.VisibilityAcc;

if (acc > ent.Comp.HideTime)
return 0;

return Math.Clamp(1f - (acc / ent.Comp.HideTime), 0f, 1f);
}

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

// В зависимости от наличие защит или проблем со зрением изменяется то, насколько хорошо мы видим жертву
if (ModifyAcc(ent.Comp, out var modifier)) // Если зрение затруднено
{
ent.Comp.VisibilityAcc *= modifier;
}
else if (!TryComp<ScpOnSoundVisibilityViewerComponent>(ent, out var viewerComp) ||
Comment thread
WardexOfficial marked this conversation as resolved.
Outdated
!_whitelist.IsWhitelistPass(viewerComp.Protections, ent)) // Если имеется защита(тихое хождение)
{
return;
}
else // Если со зрением все ок
{
ent.Comp.VisibilityAcc = 0;
}
Comment thread
WardexOfficial marked this conversation as resolved.

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<ActiveScpOnSoundVisibilityComponent> ent, EntityUid otherEntity)
{
if (!IsActive)
return;

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

MobDidSomething(ent);
}

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

MobDidSomething(ent);
}

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

MobDidSomething(ent);
}

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

MobDidSomething(ent);
}

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

MobDidSomething(ent);
}

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

// TODO: Переделать под статус эффект и добавить его в панель статус эффектов, а то непонятно игруну
Comment thread
WardexOfficial marked this conversation as resolved.
private bool ModifyAcc(ActiveScpOnSoundVisibilityComponent visibilityComponent, out int modifier)
{
// 1 = отсутствие модификатора
modifier = 1;

if (_viewerComponent == null)
return false;

if (!_viewerComponent.PoorEyesight)
return false;

modifier = _random.Next(visibilityComponent.MinValue, visibilityComponent.MaxValue);
Comment thread
WardexOfficial marked this conversation as resolved.
Outdated

return true;
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
using Robust.Client.Graphics;
using Robust.Shared.Enums;

namespace Content.Client._Scp.Scp939;
namespace Content.Client._Scp.Other.ScpOnSoundVisibility;

public sealed class Scp939ResetAlphaOverlay : Overlay
public sealed class ScpOnSoundVisibilityResetAlphaOverlay : Overlay
{
[Dependency] private readonly IEntityManager _ent = default!;

private readonly Scp939HudSystem _hud;
private readonly ScpOnSoundVisibilityHudSystem _hud;

public override OverlaySpace Space => OverlaySpace.WorldSpace;

public Scp939ResetAlphaOverlay()
public ScpOnSoundVisibilityResetAlphaOverlay()
{
IoCManager.InjectDependencies(this);

_hud = _ent.System<Scp939HudSystem>();
_hud = _ent.System<ScpOnSoundVisibilityHudSystem>();
}

protected override bool BeforeDraw(in OverlayDrawArgs args)
Expand Down
Loading
Loading