C4 (#7486)
This commit is contained in:
76
Content.Server/Sticky/Components/StickyComponent.cs
Normal file
76
Content.Server/Sticky/Components/StickyComponent.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using Content.Shared.Whitelist;
|
||||
|
||||
namespace Content.Server.Sticky.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Items that can be stick to other structures or entities.
|
||||
/// For example paper stickers or C4 charges.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed class StickyComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// What target entities are valid to be surface for sticky entity.
|
||||
/// </summary>
|
||||
[DataField("whitelist")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public EntityWhitelist? Whitelist;
|
||||
|
||||
/// <summary>
|
||||
/// How much time does it take to stick entity to target.
|
||||
/// If zero will stick entity immediately.
|
||||
/// </summary>
|
||||
[DataField("stickDelay")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public TimeSpan StickDelay = TimeSpan.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// Whether users can unstick item when it was stuck to surface.
|
||||
/// </summary>
|
||||
[DataField("canUnstick")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool CanUnstick = true;
|
||||
|
||||
/// <summary>
|
||||
/// How much time does it take to unstick entity.
|
||||
/// If zero will unstick entity immediately.
|
||||
/// </summary>
|
||||
[DataField("unstickDelay")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public TimeSpan UnstickDelay = TimeSpan.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// Popup message shown when player started sticking entity to another entity.
|
||||
/// </summary>
|
||||
[DataField("stickPopupStart")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public string? StickPopupStart;
|
||||
|
||||
/// <summary>
|
||||
/// Popup message shown when player successfully stuck entity.
|
||||
/// </summary>
|
||||
[DataField("stickPopupSuccess")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public string? StickPopupSuccess;
|
||||
|
||||
/// <summary>
|
||||
/// Popup message shown when player started unsticking entity from another entity.
|
||||
/// </summary>
|
||||
[DataField("unstickPopupStart")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public string? UnstickPopupStart;
|
||||
|
||||
/// <summary>
|
||||
/// Popup message shown when player successfully unstuck entity.
|
||||
/// </summary>
|
||||
[DataField("unstickPopupSuccess")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public string? UnstickPopupSuccess;
|
||||
|
||||
/// <summary>
|
||||
/// Entity that is used as surface for sticky entity.
|
||||
/// Null if entity doesn't stuck to anything.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public EntityUid? StuckTo;
|
||||
}
|
||||
45
Content.Server/Sticky/Events/EntityStuckEvent.cs
Normal file
45
Content.Server/Sticky/Events/EntityStuckEvent.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
namespace Content.Server.Sticky.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Risen on sticky entity when it was stuck to other entity.
|
||||
/// </summary>
|
||||
public sealed class EntityStuckEvent : EntityEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Entity that was used as a surface for sticky object.
|
||||
/// </summary>
|
||||
public readonly EntityUid Target;
|
||||
|
||||
/// <summary>
|
||||
/// Entity that stuck sticky object on target.
|
||||
/// </summary>
|
||||
public readonly EntityUid User;
|
||||
|
||||
public EntityStuckEvent(EntityUid target, EntityUid user)
|
||||
{
|
||||
Target = target;
|
||||
User = user;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Risen on sticky entity when it was unstuck from other entity.
|
||||
/// </summary>
|
||||
public sealed class EntityUnstuckEvent : EntityEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Entity that was used as a surface for sticky object.
|
||||
/// </summary>
|
||||
public readonly EntityUid Target;
|
||||
|
||||
/// <summary>
|
||||
/// Entity that unstuck sticky object on target.
|
||||
/// </summary>
|
||||
public readonly EntityUid User;
|
||||
|
||||
public EntityUnstuckEvent(EntityUid target, EntityUid user)
|
||||
{
|
||||
Target = target;
|
||||
User = user;
|
||||
}
|
||||
}
|
||||
231
Content.Server/Sticky/Systems/StickySystem.cs
Normal file
231
Content.Server/Sticky/Systems/StickySystem.cs
Normal file
@@ -0,0 +1,231 @@
|
||||
using Content.Server.DoAfter;
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.Sticky.Components;
|
||||
using Content.Server.Sticky.Events;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Sticky.Components;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Server.Sticky.Systems;
|
||||
|
||||
public sealed class StickySystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
|
||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
|
||||
private const string StickerSlotId = "stickers_container";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<StickSuccessfulEvent>(OnStickSuccessful);
|
||||
SubscribeLocalEvent<UnstickSuccessfulEvent>(OnUnstickSuccessful);
|
||||
SubscribeLocalEvent<StickyComponent, AfterInteractEvent>(OnAfterInteract);
|
||||
SubscribeLocalEvent<StickyComponent, GetVerbsEvent<Verb>>(AddUnstickVerb);
|
||||
}
|
||||
|
||||
private void OnAfterInteract(EntityUid uid, StickyComponent component, AfterInteractEvent args)
|
||||
{
|
||||
if (args.Handled || !args.CanReach || args.Target == null)
|
||||
return;
|
||||
|
||||
// try stick object to a clicked target entity
|
||||
args.Handled = StartSticking(uid, args.User, args.Target.Value, component);
|
||||
}
|
||||
|
||||
private void AddUnstickVerb(EntityUid uid, StickyComponent component, GetVerbsEvent<Verb> args)
|
||||
{
|
||||
if (component.StuckTo == null || !component.CanUnstick)
|
||||
return;
|
||||
|
||||
args.Verbs.Add(new Verb
|
||||
{
|
||||
Text = Loc.GetString("comp-sticky-unstick-verb-text"),
|
||||
IconTexture = "/Textures/Interface/VerbIcons/eject.svg.192dpi.png",
|
||||
Act = () => StartUnsticking(uid, args.User, component)
|
||||
});
|
||||
}
|
||||
|
||||
private bool StartSticking(EntityUid uid, EntityUid user, EntityUid target, StickyComponent? component = null)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return false;
|
||||
if (component.Whitelist != null && !component.Whitelist.IsValid(target))
|
||||
return false;
|
||||
|
||||
// check if delay is not zero to start do after
|
||||
var delay = (float) component.StickDelay.TotalSeconds;
|
||||
if (delay > 0)
|
||||
{
|
||||
// show message to user
|
||||
if (component.StickPopupStart != null)
|
||||
{
|
||||
var msg = Loc.GetString(component.StickPopupStart);
|
||||
_popupSystem.PopupEntity(msg, user, Filter.Entities(user));
|
||||
}
|
||||
|
||||
// start sticking object to target
|
||||
_doAfterSystem.DoAfter(new DoAfterEventArgs(user, delay, target: target)
|
||||
{
|
||||
BroadcastFinishedEvent = new StickSuccessfulEvent(uid, user, target),
|
||||
BreakOnStun = true,
|
||||
BreakOnTargetMove = true,
|
||||
BreakOnUserMove = true,
|
||||
NeedHand = true
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// if delay is zero - stick entity immediately
|
||||
StickToEntity(uid, target, user, component);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void OnStickSuccessful(StickSuccessfulEvent ev)
|
||||
{
|
||||
// check if entity still has sticky component
|
||||
if (!TryComp(ev.Uid, out StickyComponent? component))
|
||||
return;
|
||||
|
||||
StickToEntity(ev.Uid, ev.Target, ev.User, component);
|
||||
}
|
||||
|
||||
private void StartUnsticking(EntityUid uid, EntityUid user, StickyComponent? component = null)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return;
|
||||
|
||||
var delay = (float) component.UnstickDelay.TotalSeconds;
|
||||
if (delay > 0)
|
||||
{
|
||||
// show message to user
|
||||
if (component.UnstickPopupStart != null)
|
||||
{
|
||||
var msg = Loc.GetString(component.UnstickPopupStart);
|
||||
_popupSystem.PopupEntity(msg, user, Filter.Entities(user));
|
||||
}
|
||||
|
||||
// start unsticking object
|
||||
_doAfterSystem.DoAfter(new DoAfterEventArgs(user, delay, target: uid)
|
||||
{
|
||||
BroadcastFinishedEvent = new UnstickSuccessfulEvent(uid, user),
|
||||
BreakOnStun = true,
|
||||
BreakOnTargetMove = true,
|
||||
BreakOnUserMove = true,
|
||||
NeedHand = true
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// if delay is zero - unstick entity immediately
|
||||
UnstickFromEntity(uid, user, component);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
private void OnUnstickSuccessful(UnstickSuccessfulEvent ev)
|
||||
{
|
||||
// check if entity still has sticky component
|
||||
if (!TryComp(ev.Uid, out StickyComponent? component))
|
||||
return;
|
||||
|
||||
UnstickFromEntity(ev.Uid, ev.User, component);
|
||||
}
|
||||
|
||||
public void StickToEntity(EntityUid uid, EntityUid target, EntityUid user, StickyComponent? component = null)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return;
|
||||
|
||||
// add container to entity and insert sticker into it
|
||||
var container = _containerSystem.EnsureContainer<Container>(target, StickerSlotId);
|
||||
container.ShowContents = true;
|
||||
if (!container.Insert(uid))
|
||||
return;
|
||||
|
||||
// show message to user
|
||||
if (component.StickPopupSuccess != null)
|
||||
{
|
||||
var msg = Loc.GetString(component.StickPopupSuccess);
|
||||
_popupSystem.PopupEntity(msg, user, Filter.Entities(user));
|
||||
}
|
||||
|
||||
// send information to appearance that entity is stuck
|
||||
if (TryComp(uid, out AppearanceComponent? appearance))
|
||||
{
|
||||
appearance.SetData(StickyVisuals.IsStuck, true);
|
||||
}
|
||||
|
||||
component.StuckTo = target;
|
||||
RaiseLocalEvent(uid, new EntityStuckEvent(target, user));
|
||||
}
|
||||
|
||||
public void UnstickFromEntity(EntityUid uid, EntityUid user, StickyComponent? component = null)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return;
|
||||
if (component.StuckTo == null)
|
||||
return;
|
||||
|
||||
// try to remove sticky item from target container
|
||||
var target = component.StuckTo.Value;
|
||||
if (!_containerSystem.TryGetContainer(target, StickerSlotId, out var container) || !container.Remove(uid))
|
||||
return;
|
||||
// delete container if it's now empty
|
||||
if (container.ContainedEntities.Count == 0)
|
||||
container.Shutdown();
|
||||
|
||||
// try place dropped entity into user hands
|
||||
_handsSystem.PickupOrDrop(user, uid);
|
||||
|
||||
// send information to appearance that entity isn't stuck
|
||||
if (TryComp(uid, out AppearanceComponent? appearance))
|
||||
{
|
||||
appearance.SetData(StickyVisuals.IsStuck, false);
|
||||
}
|
||||
|
||||
// show message to user
|
||||
if (component.UnstickPopupSuccess != null)
|
||||
{
|
||||
var msg = Loc.GetString(component.UnstickPopupSuccess);
|
||||
_popupSystem.PopupEntity(msg, user, Filter.Entities(user));
|
||||
}
|
||||
|
||||
component.StuckTo = null;
|
||||
RaiseLocalEvent(uid, new EntityUnstuckEvent(target, user));
|
||||
}
|
||||
|
||||
private sealed class StickSuccessfulEvent : EntityEventArgs
|
||||
{
|
||||
public readonly EntityUid Uid;
|
||||
public readonly EntityUid User;
|
||||
public readonly EntityUid Target;
|
||||
|
||||
public StickSuccessfulEvent(EntityUid uid, EntityUid user, EntityUid target)
|
||||
{
|
||||
Uid = uid;
|
||||
User = user;
|
||||
Target = target;
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class UnstickSuccessfulEvent : EntityEventArgs
|
||||
{
|
||||
public readonly EntityUid Uid;
|
||||
public readonly EntityUid User;
|
||||
|
||||
public UnstickSuccessfulEvent(EntityUid uid, EntityUid user)
|
||||
{
|
||||
Uid = uid;
|
||||
User = user;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user