Add ability to resist out of welded lockers and locked closets (#5958)

* Enable lighting of Cigars with IsHotEvent

Subscribed to IsHotEvent in ThrusterSystem, added AfterInteractEvent to SmokingSystem.Cigar which will set SmokableState to Lit if IsHotEvent returns true

This should mean that cigs/Cigars should light on anything hot

* Revert "Enable lighting of Cigars with IsHotEvent"

This reverts commit db896e1f80940892a87d34aa7182b9c605fa53bc.

* Add the ability to kick your way out of welded or locked closets

Added a ResistLocker component/system that hooks into OnRelayMove to begin resisting out of lockers so that players aren't stuck in lockers forever

Also added check to EntityStorageComponent to not print out welded shut message if the entity attempting to open the locker is inside of it.

* Changes based on review

minor formatting changes

make components passed into AttemptResist nullable and resolve them inside of the function

Remove incorrectly named .ftl file

* Changes based on review

Ditched async DoAfter
Used PopupSystem over User.PopupMessage

Added Cancel token to ResistLockerComponent

Subscribed to EntRemovedFromContainer event to cancel DoAfter if the player is removed from a container

* I am in formatting hell, apparently

* Changes based on review

Added TryComp for the EntityStorageComponent instead of the event passed one

* Changes based on review

* Apply suggestions from code review

Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com>

* Formatting changes based on review

* Shuffle functions around in LockSystem to properly trigger visualizer

Moved all the unlocking logic to a Lock method inside of LockSystem and TryUnlock calls this method if the user passes all of the access checks

* Formatting, replacing Resolve with TryComp and making AttemptResist arguments optional

Co-authored-by: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com>

* Check if the player is inside THE container not A container

me no read good

* ok ok I give my code is bad

Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com>
Co-authored-by: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com>
This commit is contained in:
JustinTime
2022-01-05 23:18:48 -07:00
committed by GitHub
parent 71ce1208e0
commit 7d0b06f551
7 changed files with 176 additions and 17 deletions

View File

@@ -323,7 +323,8 @@ namespace Content.Client.Entry
"Spreader",
"GrowingKudzu",
"MonkeyAccent",
"ReplacementAccent"
"ReplacementAccent",
"ResistLocker"
};
}
}

View File

@@ -98,6 +98,27 @@ namespace Content.Server.Lock
return true;
}
public void Unlock(EntityUid uid, EntityUid user, LockComponent? lockComp = null)
{
if (!Resolve(uid, ref lockComp))
return;
lockComp.Owner.PopupMessage(user, Loc.GetString("lock-comp-do-unlock-success", ("entityName", Name: EntityManager.GetComponent<MetaDataComponent>(lockComp.Owner).EntityName)));
lockComp.Locked = false;
if (lockComp.UnlockSound != null)
{
SoundSystem.Play(Filter.Pvs(lockComp.Owner), lockComp.UnlockSound.GetSound(), lockComp.Owner, AudioParams.Default.WithVolume(-5));
}
if (EntityManager.TryGetComponent(lockComp.Owner, out AppearanceComponent? appearanceComp))
{
appearanceComp.SetData(StorageVisuals.Locked, false);
}
RaiseLocalEvent(lockComp.Owner, new LockToggledEvent(false));
}
public bool TryUnlock(EntityUid uid, EntityUid user, LockComponent? lockComp = null)
{
if (!Resolve(uid, ref lockComp))
@@ -109,21 +130,7 @@ namespace Content.Server.Lock
if (!HasUserAccess(uid, user, quiet: false))
return false;
lockComp.Owner.PopupMessage(user, Loc.GetString("lock-comp-do-unlock-success", ("entityName", Name: EntityManager.GetComponent<MetaDataComponent>(lockComp.Owner).EntityName)));
lockComp.Locked = false;
if(lockComp.UnlockSound != null)
{
SoundSystem.Play(Filter.Pvs(lockComp.Owner), lockComp.UnlockSound.GetSound(), lockComp.Owner, AudioParams.Default.WithVolume(-5));
}
if (EntityManager.TryGetComponent(lockComp.Owner, out AppearanceComponent? appearanceComp))
{
appearanceComp.SetData(StorageVisuals.Locked, false);
}
RaiseLocalEvent(lockComp.Owner, new LockToggledEvent(false));
Unlock(uid, user, lockComp);
return true;
}

View File

@@ -0,0 +1,32 @@
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
using Robust.Shared.Analyzers;
using System.Threading;
namespace Content.Server.Resist;
[RegisterComponent]
[Friend(typeof(ResistLockerSystem))]
public class ResistLockerComponent : Component
{
public override string Name => "ResistLocker";
/// <summary>
/// How long will this locker take to kick open, defaults to 2 minutes
/// </summary>
[ViewVariables]
[DataField("resistTime")]
public float ResistTime = 120f;
/// <summary>
/// For quick exit if the player attempts to move while already resisting
/// </summary>
[ViewVariables]
public bool IsResisting = false;
/// <summary>
/// Cancellation token used to cancel the DoAfter if the container is opened before it's complete
/// </summary>
public CancellationTokenSource? CancelToken;
}

View File

@@ -0,0 +1,114 @@
using Content.Shared.Movement;
using Robust.Shared.GameObjects;
using Content.Server.Storage.Components;
using Content.Server.DoAfter;
using Content.Server.Lock;
using Robust.Shared.IoC;
using Robust.Shared.Player;
using Robust.Shared.Containers;
using Content.Server.Popups;
using Robust.Shared.Localization;
namespace Content.Server.Resist;
public class ResistLockerSystem : EntitySystem
{
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly LockSystem _lockSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ResistLockerComponent, RelayMovementEntityEvent>(OnRelayMovement);
SubscribeLocalEvent<ResistLockerComponent, ResistDoAfterComplete>(OnDoAfterComplete);
SubscribeLocalEvent<ResistLockerComponent, ResistDoAfterCancelled>(OnDoAfterCancelled);
SubscribeLocalEvent<ResistLockerComponent, EntRemovedFromContainerMessage>(OnRemovedFromContainer);
}
private void OnRelayMovement(EntityUid uid, ResistLockerComponent component, RelayMovementEntityEvent args)
{
if (component.IsResisting)
return;
if (!TryComp(uid, out EntityStorageComponent? storageComponent))
return;
if (TryComp<LockComponent>(uid, out var lockComponent) && lockComponent.Locked || storageComponent.IsWeldedShut)
{
AttemptResist(args.Entity, uid, storageComponent, component);
}
}
private void AttemptResist(EntityUid user, EntityUid target, EntityStorageComponent? storageComponent = null, ResistLockerComponent? resistLockerComponent = null)
{
if (!Resolve(target, ref storageComponent, ref resistLockerComponent))
return;
resistLockerComponent.CancelToken = new();
var doAfterEventArgs = new DoAfterEventArgs(user, resistLockerComponent.ResistTime, resistLockerComponent.CancelToken.Token, target)
{
BreakOnTargetMove = false,
BreakOnUserMove = true,
BreakOnDamage = true,
BreakOnStun = true,
NeedHand = false, //No hands 'cause we be kickin'
TargetFinishedEvent = new ResistDoAfterComplete(user, target),
TargetCancelledEvent = new ResistDoAfterCancelled(user)
};
resistLockerComponent.IsResisting = true;
_popupSystem.PopupEntity(Loc.GetString("resist-locker-component-start-resisting"), user, Filter.Entities(user));
_doAfterSystem.DoAfter(doAfterEventArgs);
}
private void OnDoAfterComplete(EntityUid uid, ResistLockerComponent component, ResistDoAfterComplete ev)
{
component.IsResisting = false;
if (TryComp<EntityStorageComponent>(uid, out var storageComponent))
{
if (storageComponent.IsWeldedShut)
storageComponent.IsWeldedShut = false;
if (TryComp<LockComponent>(ev.Target, out var lockComponent))
_lockSystem.Unlock(uid, ev.User, lockComponent);
component.CancelToken = null;
storageComponent.TryOpenStorage(ev.User);
}
}
private void OnDoAfterCancelled(EntityUid uid, ResistLockerComponent component, ResistDoAfterCancelled ev)
{
component.IsResisting = false;
component.CancelToken = null;
_popupSystem.PopupEntity(Loc.GetString("resist-locker-component-resist-interrupted"), ev.User, Filter.Entities(ev.User));
}
private void OnRemovedFromContainer(EntityUid uid, ResistLockerComponent component, EntRemovedFromContainerMessage message)
{
component.CancelToken?.Cancel();
}
private class ResistDoAfterComplete : EntityEventArgs
{
public readonly EntityUid User;
public readonly EntityUid Target;
public ResistDoAfterComplete(EntityUid userUid, EntityUid target)
{
User = userUid;
Target = target;
}
}
private class ResistDoAfterCancelled : EntityEventArgs
{
public readonly EntityUid User;
public ResistDoAfterCancelled(EntityUid userUid)
{
User = userUid;
}
}
}

View File

@@ -183,7 +183,9 @@ namespace Content.Server.Storage.Components
{
if (IsWeldedShut)
{
if (!silent) Owner.PopupMessage(user, Loc.GetString("entity-storage-component-welded-shut-message"));
if (!silent && !Contents.Contains(user))
Owner.PopupMessage(user, Loc.GetString("entity-storage-component-welded-shut-message"));
return false;
}

View File

@@ -0,0 +1,2 @@
resist-locker-component-start-resisting = You begin to kick at the door!
resist-locker-component-resist-interrupted = Your attempts to kick at the door were interrupted!

View File

@@ -4,6 +4,7 @@
name: closet
description: A standard-issue Nanotrasen storage unit.
components:
- type: ResistLocker
- type: Transform
noRot: true
- type: Sprite