Files
tbd-station-14/Content.Server/GameObjects/Components/Weapon/Melee/FlashComponent.cs
R. Neuser 88f49961d8 OverlayManager refactor and Flash (#1218)
* Flash component, overlay and shader
Add BeginDraw method to Overlay.cs

* Add flash icons, sounds

* Progress

* Multiple overlays without enums

* This is probably the worst way to do this IDK

* Remove nullable reference type

* Add AttackEventArgs as parameter to OnHitEntities
MeleeWeaponComponent.Attack now continues when OnHitEntities returns true (it hit something)
Add OverlayType enum so client and server can agree on overlay ids
Move IConfigurable to its own file
Add AoE flash with shorter duration
Flashing someone slows them down

* Add arc to flash
Set item size to something reasonable
Remove chat log message when flash burns out

* Remove unused interface
2020-07-06 23:37:39 +02:00

183 lines
6.0 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Content.Server.GameObjects.Components.Mobs;
using Content.Server.GameObjects.EntitySystems;
using Content.Server.Interfaces;
using Content.Shared.Chat;
using Content.Shared.GameObjects.Components.Mobs;
using Content.Shared.Interfaces;
using Robust.Server.GameObjects;
using Robust.Server.GameObjects.EntitySystems;
using Robust.Server.Interfaces.GameObjects;
using Robust.Server.Interfaces.Player;
using Robust.Shared.Audio;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.Interfaces.Random;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
using Timer = Robust.Shared.Timers.Timer;
namespace Content.Server.GameObjects.Components.Weapon.Melee
{
[RegisterComponent]
public class FlashComponent : MeleeWeaponComponent, IUse, IExamine
{
#pragma warning disable 649
[Dependency] private readonly ILocalizationManager _localizationManager;
[Dependency] private readonly IEntityManager _entityManager;
[Dependency] private readonly ISharedNotifyManager _notifyManager;
#pragma warning restore 649
public override string Name => "Flash";
[ViewVariables(VVAccess.ReadWrite)] private int _flashDuration = 5000;
[ViewVariables(VVAccess.ReadWrite)] private float _flashFalloffExp = 8f;
[ViewVariables(VVAccess.ReadWrite)] private int _uses = 5;
[ViewVariables(VVAccess.ReadWrite)] private float _range = 3f;
[ViewVariables(VVAccess.ReadWrite)] private int _aoeFlashDuration = 5000 / 3;
[ViewVariables(VVAccess.ReadWrite)] private float _slowTo = 0.75f;
private bool _flashing;
private int Uses
{
get => _uses;
set
{
_uses = value;
Dirty();
}
}
private bool HasUses => _uses > 0;
public override void ExposeData(ObjectSerializer serializer)
{
base.ExposeData(serializer);
serializer.DataField(ref _flashDuration, "duration", 5000);
serializer.DataField(ref _flashFalloffExp, "flashFalloffExp", 8f);
serializer.DataField(ref _uses, "uses", 5);
serializer.DataField(ref _range, "range", 3f);
serializer.DataField(ref _aoeFlashDuration, "aoeFlashDuration", _flashDuration / 3);
serializer.DataField(ref _slowTo, "slowTo", 0.75f);
}
protected override bool OnHitEntities(IReadOnlyList<IEntity> entities, AttackEventArgs eventArgs)
{
if (entities.Count == 0)
{
return false;
}
if (!Use(eventArgs.User))
{
return false;
}
foreach (var entity in entities)
{
Flash(entity, eventArgs.User);
}
return true;
}
public bool UseEntity(UseEntityEventArgs eventArgs)
{
if (!Use(eventArgs.User))
{
return false;
}
foreach (var entity in _entityManager.GetEntitiesInRange(Owner.Transform.GridPosition, _range))
{
Flash(entity, eventArgs.User, _aoeFlashDuration);
}
return true;
}
private bool Use(IEntity user)
{
if (HasUses)
{
var sprite = Owner.GetComponent<SpriteComponent>();
if (--Uses == 0)
{
sprite.LayerSetState(0, "burnt");
_notifyManager.PopupMessage(Owner, user, "The flash burns out!");
}
else if (!_flashing)
{
int animLayer = sprite.AddLayerWithState("flashing");
_flashing = true;
Timer.Spawn(400, () =>
{
sprite.RemoveLayer(animLayer);
_flashing = false;
});
}
EntitySystem.Get<AudioSystem>().PlayAtCoords("/Audio/weapons/flash.ogg", Owner.Transform.GridPosition,
AudioParams.Default);
return true;
}
return false;
}
private void Flash(IEntity entity, IEntity user)
{
Flash(entity, user, _flashDuration);
}
// TODO: Check if target can be flashed (e.g. things like sunglasses would block a flash)
private void Flash(IEntity entity, IEntity user, int flashDuration)
{
if (entity.TryGetComponent(out ServerOverlayEffectsComponent overlayEffectsComponent))
{
var container = new TimedOverlayContainer(nameof(OverlayType.FlashOverlay), flashDuration);
overlayEffectsComponent.AddOverlay(container);
container.StartTimer(() => overlayEffectsComponent.RemoveOverlay(container));
}
if (entity.TryGetComponent(out StunnableComponent stunnableComponent))
{
stunnableComponent.Slowdown(flashDuration / 1000f, _slowTo, _slowTo);
}
if (entity != user)
{
_notifyManager.PopupMessage(user, entity, $"{user.Name} blinds you with the {Owner.Name}");
}
}
public void Examine(FormattedMessage message, bool inDetailsRange)
{
if (!HasUses)
{
message.AddText("It's burnt out.");
return;
}
if (inDetailsRange)
{
message.AddMarkup(_localizationManager.GetString(
$"The flash has [color=green]{Uses}[/color] uses remaining."));
}
}
}
}