* 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
292 lines
9.6 KiB
C#
292 lines
9.6 KiB
C#
using System.Collections.Generic;
|
|
using Content.Server.GameObjects.Components.Mobs;
|
|
using Content.Server.GameObjects.Components.Power;
|
|
using Content.Server.GameObjects.EntitySystems.Click;
|
|
using Content.Server.Interfaces.GameObjects.Components.Interaction;
|
|
using Content.Server.Interfaces.GameObjects;
|
|
using Content.Shared.Audio;
|
|
using Content.Shared.GameObjects;
|
|
using Content.Shared.GameObjects.EntitySystems;
|
|
using Content.Shared.Interfaces;
|
|
using Robust.Server.GameObjects;
|
|
using Robust.Server.GameObjects.Components.Container;
|
|
using Robust.Server.GameObjects.EntitySystems;
|
|
using Robust.Server.Interfaces.GameObjects;
|
|
using Robust.Shared.GameObjects;
|
|
using Robust.Shared.GameObjects.Systems;
|
|
using Robust.Shared.Interfaces.GameObjects;
|
|
using Robust.Shared.Interfaces.Random;
|
|
using Robust.Shared.IoC;
|
|
using Robust.Shared.Localization;
|
|
using Robust.Shared.Random;
|
|
using Robust.Shared.Serialization;
|
|
using Robust.Shared.Utility;
|
|
using Robust.Shared.ViewVariables;
|
|
|
|
namespace Content.Server.GameObjects.Components.Weapon.Melee
|
|
{
|
|
[RegisterComponent]
|
|
public class StunbatonComponent : MeleeWeaponComponent, IUse, IExamine, IMapInit, IInteractUsing
|
|
{
|
|
#pragma warning disable 649
|
|
[Dependency] private IRobustRandom _robustRandom;
|
|
[Dependency] private readonly ISharedNotifyManager _notifyManager;
|
|
[Dependency] private readonly ILocalizationManager _localizationManager;
|
|
#pragma warning restore 649
|
|
|
|
public override string Name => "Stunbaton";
|
|
|
|
private bool _activated = false;
|
|
|
|
[ViewVariables] private ContainerSlot _cellContainer;
|
|
|
|
[ViewVariables(VVAccess.ReadWrite)]
|
|
private float _paralyzeChanceNoSlowdown = 0.35f;
|
|
|
|
[ViewVariables(VVAccess.ReadWrite)]
|
|
private float _paralyzeChanceWithSlowdown = 0.85f;
|
|
|
|
[ViewVariables(VVAccess.ReadWrite)]
|
|
private float _paralyzeTime = 10f;
|
|
|
|
[ViewVariables(VVAccess.ReadWrite)]
|
|
private float _slowdownTime = 5f;
|
|
|
|
[ViewVariables(VVAccess.ReadWrite)] public float EnergyPerUse { get; set; } = 1000;
|
|
|
|
[ViewVariables]
|
|
public bool Activated => _activated;
|
|
|
|
[ViewVariables]
|
|
private BatteryComponent Cell
|
|
{
|
|
get
|
|
{
|
|
if (_cellContainer.ContainedEntity == null) return null;
|
|
|
|
_cellContainer.ContainedEntity.TryGetComponent(out BatteryComponent cell);
|
|
return cell;
|
|
}
|
|
}
|
|
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
_cellContainer =
|
|
ContainerManagerComponent.Ensure<ContainerSlot>("stunbaton_cell_container", Owner, out var existed);
|
|
}
|
|
|
|
public override void ExposeData(ObjectSerializer serializer)
|
|
{
|
|
base.ExposeData(serializer);
|
|
|
|
serializer.DataField(ref _paralyzeChanceNoSlowdown, "paralyzeChanceNoSlowdown", 0.35f);
|
|
serializer.DataField(ref _paralyzeChanceWithSlowdown, "paralyzeChanceWithSlowdown", 0.85f);
|
|
serializer.DataField(ref _paralyzeTime, "paralyzeTime", 10f);
|
|
serializer.DataField(ref _slowdownTime, "slowdownTime", 5f);
|
|
}
|
|
|
|
protected override bool OnHitEntities(IReadOnlyList<IEntity> entities, AttackEventArgs eventArgs)
|
|
{
|
|
var cell = Cell;
|
|
if (!Activated || entities.Count == 0 || cell == null)
|
|
return false;
|
|
if (!cell.TryUseCharge(EnergyPerUse))
|
|
{
|
|
return false;
|
|
}
|
|
EntitySystem.Get<AudioSystem>().PlayAtCoords("/Audio/weapons/egloves.ogg", Owner.Transform.GridPosition, AudioHelpers.WithVariation(0.25f));
|
|
|
|
foreach (var entity in entities)
|
|
{
|
|
if (!entity.TryGetComponent(out StunnableComponent stunnable)) continue;
|
|
|
|
if(!stunnable.SlowedDown)
|
|
if(_robustRandom.Prob(_paralyzeChanceNoSlowdown))
|
|
stunnable.Paralyze(_paralyzeTime);
|
|
else
|
|
stunnable.Slowdown(_slowdownTime);
|
|
else
|
|
if(_robustRandom.Prob(_paralyzeChanceWithSlowdown))
|
|
stunnable.Paralyze(_paralyzeTime);
|
|
else
|
|
stunnable.Slowdown(_slowdownTime);
|
|
}
|
|
if(cell.CurrentCharge < EnergyPerUse)
|
|
{
|
|
EntitySystem.Get<AudioSystem>().PlayAtCoords(AudioHelpers.GetRandomFileFromSoundCollection("sparks"), Owner.Transform.GridPosition, AudioHelpers.WithVariation(0.25f));
|
|
TurnOff();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private bool ToggleStatus(IEntity user)
|
|
{
|
|
if (Activated)
|
|
{
|
|
TurnOff();
|
|
}
|
|
else
|
|
{
|
|
TurnOn(user);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private void TurnOff()
|
|
{
|
|
if (!_activated)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var sprite = Owner.GetComponent<SpriteComponent>();
|
|
var item = Owner.GetComponent<ItemComponent>();
|
|
|
|
EntitySystem.Get<AudioSystem>().PlayAtCoords(AudioHelpers.GetRandomFileFromSoundCollection("sparks"), Owner.Transform.GridPosition, AudioHelpers.WithVariation(0.25f));
|
|
|
|
item.EquippedPrefix = "off";
|
|
sprite.LayerSetState(0, "stunbaton_off");
|
|
_activated = false;
|
|
}
|
|
|
|
private void TurnOn(IEntity user)
|
|
{
|
|
if (_activated)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var sprite = Owner.GetComponent<SpriteComponent>();
|
|
var item = Owner.GetComponent<ItemComponent>();
|
|
var cell = Cell;
|
|
|
|
if (cell == null)
|
|
{
|
|
EntitySystem.Get<AudioSystem>().PlayAtCoords("/Audio/machines/button.ogg", Owner.Transform.GridPosition, AudioHelpers.WithVariation(0.25f));
|
|
|
|
_notifyManager.PopupMessage(Owner, user, _localizationManager.GetString("Cell missing..."));
|
|
return;
|
|
}
|
|
|
|
if (cell.CurrentCharge < EnergyPerUse)
|
|
{
|
|
EntitySystem.Get<AudioSystem>().PlayAtCoords("/Audio/machines/button.ogg", Owner.Transform.GridPosition, AudioHelpers.WithVariation(0.25f));
|
|
_notifyManager.PopupMessage(Owner, user, _localizationManager.GetString("Dead cell..."));
|
|
return;
|
|
}
|
|
|
|
EntitySystem.Get<AudioSystem>().PlayAtCoords(AudioHelpers.GetRandomFileFromSoundCollection("sparks"), Owner.Transform.GridPosition, AudioHelpers.WithVariation(0.25f));
|
|
|
|
item.EquippedPrefix = "on";
|
|
sprite.LayerSetState(0, "stunbaton_on");
|
|
_activated = true;
|
|
}
|
|
|
|
public bool UseEntity(UseEntityEventArgs eventArgs)
|
|
{
|
|
ToggleStatus(eventArgs.User);
|
|
|
|
return true;
|
|
}
|
|
|
|
public bool InteractUsing(InteractUsingEventArgs eventArgs)
|
|
{
|
|
if (!eventArgs.Using.HasComponent<BatteryComponent>()) return false;
|
|
|
|
if (Cell != null) return false;
|
|
|
|
var handsComponent = eventArgs.User.GetComponent<IHandsComponent>();
|
|
|
|
if (!handsComponent.Drop(eventArgs.Using, _cellContainer))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
EntitySystem.Get<AudioSystem>().PlayFromEntity("/Audio/items/weapons/pistol_magin.ogg", Owner);
|
|
|
|
Dirty();
|
|
|
|
return true;
|
|
}
|
|
|
|
private void EjectCell(IEntity user)
|
|
{
|
|
if (Cell == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var cell = Cell;
|
|
|
|
if (!_cellContainer.Remove(cell.Owner))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!user.TryGetComponent(out HandsComponent hands))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!hands.PutInHand(cell.Owner.GetComponent<ItemComponent>()))
|
|
{
|
|
cell.Owner.Transform.GridPosition = user.Transform.GridPosition;
|
|
}
|
|
|
|
EntitySystem.Get<AudioSystem>().PlayAtCoords("/Audio/items/weapons/pistol_magout.ogg", Owner.Transform.GridPosition, AudioHelpers.WithVariation(0.25f));
|
|
}
|
|
|
|
public void Examine(FormattedMessage message, bool inDetailsRange)
|
|
{
|
|
var loc = IoCManager.Resolve<ILocalizationManager>();
|
|
|
|
if (Activated)
|
|
{
|
|
message.AddMarkup(loc.GetString("The light is currently [color=darkgreen]on[/color]."));
|
|
}
|
|
}
|
|
|
|
public void MapInit()
|
|
{
|
|
if (_cellContainer.ContainedEntity != null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var cell = Owner.EntityManager.SpawnEntity("PowerCellSmallHyper", Owner.Transform.GridPosition);
|
|
_cellContainer.Insert(cell);
|
|
}
|
|
|
|
[Verb]
|
|
public sealed class EjectCellVerb : Verb<StunbatonComponent>
|
|
{
|
|
protected override void GetData(IEntity user, StunbatonComponent component, VerbData data)
|
|
{
|
|
if (!ActionBlockerSystem.CanInteract(user))
|
|
{
|
|
data.Visibility = VerbVisibility.Invisible;
|
|
return;
|
|
}
|
|
|
|
if (component.Cell == null)
|
|
{
|
|
data.Text = "Eject cell (cell missing)";
|
|
data.Visibility = VerbVisibility.Disabled;
|
|
}
|
|
else
|
|
{
|
|
data.Text = "Eject cell";
|
|
}
|
|
}
|
|
|
|
protected override void Activate(IEntity user, StunbatonComponent component)
|
|
{
|
|
component.EjectCell(user);
|
|
}
|
|
}
|
|
}
|
|
}
|