From: keronshb <54602815+keronshb@users.noreply.github.com> Date: Wed, 4 Dec 2024 16:49:54 +0000 (-0500) Subject: Adds Store on Collide and Wand of the Locker (#33710) X-Git-Url: https://git.smokeofanarchy.ru/gitweb.cgi?a=commitdiff_plain;h=82528dce377ed76399fedf570a96459288354c95;p=space-station-14.git Adds Store on Collide and Wand of the Locker (#33710) * Adds wand of locker and locker projectile * Adds IsOpen method to check if storage is open * Adds store on collide * Adds Store On Collide to Wizard Locker * Adds Lock API * Adds locking support * Adds resist override and custom visual layers * Fixes decursed states, adds comment for a future visualizer * adds locker wand visuals and descriptions * shrinks locker radius, moves TODO for throw support * Adds whitelist and moves storage and lock logic into their own methods * Adds support to disable store on collide after the first open. Fixes prediction issues with disabling. * Adds wand of locker to the grimoire * Adds wizard access prototype * Adds Wizard to universal access * Moves Lock on collide to on collide method * Comments * Changes layer order * Fixes prediction issues when locking. * Adds Wiz access to universal ID --- diff --git a/Content.Shared/Lock/LockSystem.cs b/Content.Shared/Lock/LockSystem.cs index 3349034f32..411766d8c1 100644 --- a/Content.Shared/Lock/LockSystem.cs +++ b/Content.Shared/Lock/LockSystem.cs @@ -131,8 +131,24 @@ public sealed class LockSystem : EntitySystem }); } - _sharedPopupSystem.PopupClient(Loc.GetString("lock-comp-do-lock-success", + Lock(uid, user, lockComp); + return true; + } + + /// + /// Forces a given entity to be locked, does not activate a do-after. + /// + public void Lock(EntityUid uid, EntityUid? user, LockComponent? lockComp = null) + { + if (!Resolve(uid, ref lockComp)) + return; + + if (user is { Valid: true }) + { + _sharedPopupSystem.PopupClient(Loc.GetString("lock-comp-do-lock-success", ("entityName", Identity.Name(uid, EntityManager))), uid, user); + } + _audio.PlayPredicted(lockComp.LockSound, uid, user); lockComp.Locked = true; @@ -141,7 +157,6 @@ public sealed class LockSystem : EntitySystem var ev = new LockToggledEvent(true); RaiseLocalEvent(uid, ref ev, true); - return true; } /// diff --git a/Content.Shared/Storage/Components/StoreOnCollideComponent.cs b/Content.Shared/Storage/Components/StoreOnCollideComponent.cs new file mode 100644 index 0000000000..d8fff31938 --- /dev/null +++ b/Content.Shared/Storage/Components/StoreOnCollideComponent.cs @@ -0,0 +1,34 @@ +using Content.Shared.Storage.EntitySystems; +using Content.Shared.Whitelist; +using Robust.Shared.GameStates; + +namespace Content.Shared.Storage.Components; + +// Use where you want an entity to store other entities on collide +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(StoreOnCollideSystem))] +public sealed partial class StoreOnCollideComponent : Component +{ + /// + /// Entities that are allowed in the storage on collide + /// + [DataField] + public EntityWhitelist? Whitelist; + + /// + /// Should this storage lock on collide, provided they have a lock component? + /// + [DataField] + public bool LockOnCollide; + + /// + /// Should the behavior be disabled when the storage is first opened? + /// + [DataField] + public bool DisableWhenFirstOpened; + + /// + /// If the behavior is disabled or not + /// + [DataField, AutoNetworkedField] + public bool Disabled; +} diff --git a/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs b/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs index 309ac0a2e0..829f574ad1 100644 --- a/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs +++ b/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs @@ -344,6 +344,14 @@ public abstract class SharedEntityStorageSystem : EntitySystem return true; } + public bool IsOpen(EntityUid target, SharedEntityStorageComponent? component = null) + { + if (!ResolveStorage(target, ref component)) + return false; + + return component.Open; + } + public bool CanOpen(EntityUid user, EntityUid target, bool silent = false, SharedEntityStorageComponent? component = null) { if (!ResolveStorage(target, ref component)) diff --git a/Content.Shared/Storage/EntitySystems/StoreOnCollideSystem.cs b/Content.Shared/Storage/EntitySystems/StoreOnCollideSystem.cs new file mode 100644 index 0000000000..000e19faf3 --- /dev/null +++ b/Content.Shared/Storage/EntitySystems/StoreOnCollideSystem.cs @@ -0,0 +1,71 @@ +using Content.Shared.Lock; +using Content.Shared.Storage.Components; +using Content.Shared.Whitelist; +using Robust.Shared.Network; +using Robust.Shared.Physics.Events; +using Robust.Shared.Timing; + +namespace Content.Shared.Storage.EntitySystems; + +internal sealed class StoreOnCollideSystem : EntitySystem +{ + [Dependency] private readonly SharedEntityStorageSystem _storage = default!; + [Dependency] private readonly LockSystem _lock = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelist = default!; + [Dependency] private readonly INetManager _netMan = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnCollide); + SubscribeLocalEvent(AfterOpen); + // TODO: Add support to stop colliding after throw, wands will need a WandComp + } + + // We use Collide instead of Projectile to support different types of interactions + private void OnCollide(Entity ent, ref StartCollideEvent args) + { + TryStoreTarget(ent, args.OtherEntity); + + TryLockStorage(ent); + } + + private void AfterOpen(Entity ent, ref StorageAfterOpenEvent args) + { + var comp = ent.Comp; + + if (comp is { DisableWhenFirstOpened: true, Disabled: false }) + comp.Disabled = true; + } + + private void TryStoreTarget(Entity ent, EntityUid target) + { + var storageEnt = ent.Owner; + var comp = ent.Comp; + + if (_netMan.IsClient || _gameTiming.ApplyingState) + return; + + if (ent.Comp.Disabled || storageEnt == target || Transform(target).Anchored || _storage.IsOpen(storageEnt) || _whitelist.IsWhitelistFail(comp.Whitelist, target)) + return; + + _storage.Insert(target, storageEnt); + + } + + private void TryLockStorage(Entity ent) + { + var storageEnt = ent.Owner; + var comp = ent.Comp; + + if (_netMan.IsClient || _gameTiming.ApplyingState) + return; + + if (ent.Comp.Disabled) + return; + + if (comp.LockOnCollide && !_lock.IsLocked(storageEnt)) + _lock.Lock(storageEnt, storageEnt); + } +} diff --git a/Resources/Locale/en-US/prototypes/access/accesses.ftl b/Resources/Locale/en-US/prototypes/access/accesses.ftl index 0e8b1d9ac7..5e54fcad22 100644 --- a/Resources/Locale/en-US/prototypes/access/accesses.ftl +++ b/Resources/Locale/en-US/prototypes/access/accesses.ftl @@ -42,3 +42,5 @@ id-card-access-level-nuclear-operative = Nuclear Operative id-card-access-level-syndicate-agent = Syndicate Agent id-card-access-level-central-command = Central Command + +id-card-access-level-wizard = Wizard diff --git a/Resources/Locale/en-US/store/spellbook-catalog.ftl b/Resources/Locale/en-US/store/spellbook-catalog.ftl index ed62c6fa82..dff918b0bc 100644 --- a/Resources/Locale/en-US/store/spellbook-catalog.ftl +++ b/Resources/Locale/en-US/store/spellbook-catalog.ftl @@ -28,6 +28,9 @@ spellbook-wand-polymorph-door-description = For when you need a get-away route. spellbook-wand-polymorph-carp-name = Wand of Carp Polymorph spellbook-wand-polymorph-carp-description = For when you need a carp filet quick and the clown is looking juicy. +spellbook-wand-locker-name = Wand of the Locker +spellbook-wand-locker-description = Shoot cursed lockers at your enemies and lock em away! + # Events spellbook-event-summon-ghosts-name = Summon Ghosts diff --git a/Resources/Prototypes/Access/wizard.yml b/Resources/Prototypes/Access/wizard.yml new file mode 100644 index 0000000000..cacb889936 --- /dev/null +++ b/Resources/Prototypes/Access/wizard.yml @@ -0,0 +1,3 @@ +- type: accessLevel + id: Wizard + name: id-card-access-level-wizard diff --git a/Resources/Prototypes/Catalog/spellbook_catalog.yml b/Resources/Prototypes/Catalog/spellbook_catalog.yml index 6e9bba87a6..57172dc665 100644 --- a/Resources/Prototypes/Catalog/spellbook_catalog.yml +++ b/Resources/Prototypes/Catalog/spellbook_catalog.yml @@ -118,6 +118,19 @@ - !type:ListingLimitedStockCondition stock: 1 +- type: listing + id: SpellbookWandLocker + name: spellbook-wand-locker-name + description: spellbook-wand-locker-description + productEntity: WeaponWandLocker + cost: + WizCoin: 3 + categories: + - SpellbookEquipment + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + # Event - type: listing id: SpellbookEventSummonGhosts diff --git a/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml b/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml index ccb83b6aaa..a0e144d0ac 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml @@ -810,3 +810,4 @@ - CentralCommand - NuclearOperative - SyndicateAgent + - Wizard diff --git a/Resources/Prototypes/Entities/Objects/Tools/access_configurator.yml b/Resources/Prototypes/Entities/Objects/Tools/access_configurator.yml index 66f4689099..d55437696a 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/access_configurator.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/access_configurator.yml @@ -119,6 +119,7 @@ - CentralCommand - NuclearOperative - SyndicateAgent + - Wizard privilegedIdSlot: name: id-card-console-privileged-id ejectSound: /Audio/Machines/id_swipe.ogg diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/wands.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/wands.yml index e723a1db5f..d3745288f6 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/wands.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/wands.yml @@ -57,6 +57,42 @@ capacity: 5 count: 5 +- type: entity + name: wand of the locker + description: Stuff nerds at a distance! + parent: WeaponWandBase + id: WeaponWandLocker + components: + - type: Sprite + layers: + - state: locker + map: ["base"] + - state: locker-effect + map: ["effect"] + - type: Gun + soundGunshot: + path: /Audio/Weapons/Guns/Gunshots/Magic/staff_animation.ogg + - type: BasicEntityAmmoProvider + proto: ProjectileLocker + capacity: 5 + count: 5 + - type: Item + size: Normal + inhandVisuals: + left: + - state: locker-inhand-left + right: + - state: locker-inhand-right + - type: GenericVisualizer + visuals: + enum.AmmoVisuals.HasAmmo: + effect: + True: { visible: False } + False: { visible: True } + base: + True: { visible: True } + False: { visible: False } + - type: entity name: magical wand of instant death parent: WeaponWandBase diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/magic.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/magic.yml index d11f96d875..cd736a33d0 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/magic.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/magic.yml @@ -79,6 +79,86 @@ totalIntensity: 0.3 maxTileBreak: 0 +- type: entity + id: ProjectileLocker + name: cursed locker + description: A cursed magical locker! Can you resist? + parent: ClosetSteelBase + categories: [ HideSpawnMenu ] + components: + - type: ResistLocker + resistTime: 30 + - type: StoreOnCollide + lockOnCollide: true + disableWhenFirstOpened: true + whitelist: + components: + - Body + - type: LockVisuals + stateLocked: cursed_door + stateUnlocked: decursed_door + - type: Lock + breakOnEmag: false + - type: AccessReader + access: [["Wizard"]] + breakOnEmag: false + - type: Projectile + deleteOnCollide: false + onlyCollideWhenShot: true + damage: + types: + Brute: 0 + - type: Sprite + noRot: true + sprite: Structures/Storage/closet.rsi + layers: + - state: cursed + map: [ "enum.StorageVisualLayers.Base" ] + - state: decursed_door + map: [ "enum.StorageVisualLayers.Door" ] + - state: paper + visible: false + sprite: Structures/Storage/closet_labels.rsi + map: [ "enum.PaperLabelVisuals.Layer" ] + - state: cursed_door + map: [ "enum.LockVisualLayers.Lock" ] + - state: welded + visible: false + map: [ "enum.WeldableLayers.BaseWelded" ] + #TODO: Will have to eventually make a custom visualizer for cursed lockers + - type: EntityStorageVisuals + stateBaseClosed: decursed + stateDoorOpen: decursed_open + stateDoorClosed: decursed_door + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeAabb + bounds: "-0.25,-0.48,0.25,0.48" + density: 75 + mask: + - MachineMask + layer: + - MachineLayer + projectile: + shape: + !type:PhysShapeAabb + bounds: "-0.15,-0.45,0.15,0.15" + hard: false + mask: + - Impassable + - BulletImpassable + fly-by: &flybyfixture + shape: !type:PhysShapeCircle + radius: 0.6 + layer: + - Impassable + - MidImpassable + - HighImpassable + - LowImpassable + hard: false + - type: entity id: ProjectilePolyboltBase parent: BaseBullet diff --git a/Resources/Textures/Objects/Weapons/Guns/Basic/wands.rsi/locker-effect.png b/Resources/Textures/Objects/Weapons/Guns/Basic/wands.rsi/locker-effect.png new file mode 100644 index 0000000000..77bcb4b364 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Basic/wands.rsi/locker-effect.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Basic/wands.rsi/locker-inhand-left.png b/Resources/Textures/Objects/Weapons/Guns/Basic/wands.rsi/locker-inhand-left.png new file mode 100644 index 0000000000..bcb330b9ed Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Basic/wands.rsi/locker-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Basic/wands.rsi/locker-inhand-right.png b/Resources/Textures/Objects/Weapons/Guns/Basic/wands.rsi/locker-inhand-right.png new file mode 100644 index 0000000000..4be7ef2059 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Basic/wands.rsi/locker-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Basic/wands.rsi/locker.png b/Resources/Textures/Objects/Weapons/Guns/Basic/wands.rsi/locker.png new file mode 100644 index 0000000000..f638769226 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Basic/wands.rsi/locker.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Basic/wands.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/Basic/wands.rsi/meta.json index 87b6f38677..59d423baac 100644 --- a/Resources/Textures/Objects/Weapons/Guns/Basic/wands.rsi/meta.json +++ b/Resources/Textures/Objects/Weapons/Guns/Basic/wands.rsi/meta.json @@ -63,6 +63,20 @@ { "name": "wand-inhand-right", "directions": 4 + }, + { + "name": "locker" + }, + { + "name": "locker-effect" + }, + { + "name": "locker-inhand-right", + "directions": 4 + }, + { + "name": "locker-inhand-left", + "directions": 4 } ] -} \ No newline at end of file +}