diff --git a/Content.Client/Chemistry/Components/InjectorComponent.cs b/Content.Client/Chemistry/Components/InjectorComponent.cs index 46120c1b39..4d10517a11 100644 --- a/Content.Client/Chemistry/Components/InjectorComponent.cs +++ b/Content.Client/Chemistry/Components/InjectorComponent.cs @@ -1,15 +1,5 @@ -using Content.Client.Items.Components; -using Content.Client.Message; -using Content.Client.Stylesheets; using Content.Shared.Chemistry.Components; -using Content.Shared.Chemistry.Reagent; using Content.Shared.FixedPoint; -using Robust.Client.UserInterface; -using Robust.Client.UserInterface.Controls; -using Robust.Shared.GameObjects; -using Robust.Shared.Localization; -using Robust.Shared.Timing; -using Robust.Shared.ViewVariables; namespace Content.Client.Chemistry.Components { diff --git a/Content.Client/Items/Components/ItemStatusComponent.cs b/Content.Client/Items/Components/ItemStatusComponent.cs deleted file mode 100644 index 34ab3bc9a0..0000000000 --- a/Content.Client/Items/Components/ItemStatusComponent.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Robust.Shared.GameObjects; - -namespace Content.Client.Items.Components -{ - [RegisterComponent] - public sealed partial class ItemStatusComponent : Component - { - } -} diff --git a/Content.Client/Salvage/FultonSystem.cs b/Content.Client/Salvage/FultonSystem.cs new file mode 100644 index 0000000000..1ecebdfdf8 --- /dev/null +++ b/Content.Client/Salvage/FultonSystem.cs @@ -0,0 +1,118 @@ +using System.Numerics; +using Content.Shared.Salvage.Fulton; +using Content.Shared.Spawners.Components; +using JetBrains.Annotations; +using Robust.Client.Animations; +using Robust.Client.GameObjects; +using Robust.Client.Graphics; +using Robust.Shared.Animations; +using Robust.Shared.Serialization.Manager; +using Robust.Shared.Utility; + +namespace Content.Client.Salvage; + +public sealed class FultonSystem : SharedFultonSystem +{ + [Dependency] private readonly ISerializationManager _serManager = default!; + [Dependency] private readonly AnimationPlayerSystem _player = default!; + + private static readonly TimeSpan AnimationDuration = TimeSpan.FromSeconds(0.4); + + private static readonly Animation InitialAnimation = new() + { + Length = AnimationDuration, + AnimationTracks = + { + new AnimationTrackSpriteFlick + { + LayerKey = FultonVisualLayers.Base, + KeyFrames = + { + new AnimationTrackSpriteFlick.KeyFrame(new RSI.StateId("fulton_expand"), 0f), + new AnimationTrackSpriteFlick.KeyFrame(new RSI.StateId("fulton_balloon"), 0.4f), + } + } + } + }; + + private static readonly Animation FultonAnimation = new() + { + Length = TimeSpan.FromSeconds(0.8f), + AnimationTracks = + { + new AnimationTrackComponentProperty() + { + ComponentType = typeof(SpriteComponent), + Property = nameof(SpriteComponent.Offset), + KeyFrames = + { + new AnimationTrackProperty.KeyFrame(Vector2.Zero, 0f), + new AnimationTrackProperty.KeyFrame(new Vector2(0f, -0.3f), 0.3f), + new AnimationTrackProperty.KeyFrame(new Vector2(0f, 20f), 0.5f), + } + } + } + }; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnHandleState); + SubscribeNetworkEvent(OnFultonMessage); + } + + private void OnFultonMessage(FultonAnimationMessage ev) + { + if (Deleted(ev.Entity) || !TryComp(ev.Entity, out var entSprite)) + return; + + var animationEnt = Spawn(null, ev.Coordinates); + // TODO: Spawn fulton layer + var sprite = AddComp(animationEnt); + _serManager.CopyTo(entSprite, ref sprite, notNullableOverride: true); + + if (TryComp(ev.Entity, out var entAppearance)) + { + var appearance = AddComp(animationEnt); + _serManager.CopyTo(entAppearance, ref appearance, notNullableOverride: true); + } + + sprite.NoRotation = true; + var effectLayer = sprite.AddLayer(new SpriteSpecifier.Rsi(new ResPath("Objects/Tools/fulton_balloon.rsi"), "fulton_balloon")); + sprite.LayerSetOffset(effectLayer, EffectOffset + new Vector2(0f, 0.5f)); + + var despawn = AddComp(animationEnt); + despawn.Lifetime = 1.5f; + + _player.Play(animationEnt, FultonAnimation, "fulton-animation"); + } + + private void OnHandleState(EntityUid uid, FultonedComponent component, ref AfterAutoHandleStateEvent args) + { + UpdateAppearance(uid, component); + } + + protected override void UpdateAppearance(EntityUid uid, FultonedComponent component) + { + if (!component.Effect.IsValid()) + return; + + var startTime = component.NextFulton - component.FultonDuration; + var elapsed = Timing.CurTime - startTime; + + if (elapsed >= AnimationDuration) + { + return; + } + + _player.Play(component.Effect, InitialAnimation, "fulton"); + } + + [UsedImplicitly] + public enum FultonVisualLayers : byte + { + Base, + } + + +} diff --git a/Content.Client/Storage/UI/StorageWindow.cs b/Content.Client/Storage/UI/StorageWindow.cs index 521d1cf590..aee8b86c7a 100644 --- a/Content.Client/Storage/UI/StorageWindow.cs +++ b/Content.Client/Storage/UI/StorageWindow.cs @@ -3,7 +3,6 @@ using Robust.Client.GameObjects; using Robust.Client.Graphics; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; -using Content.Client.Items.Components; using Content.Client.Stylesheets; using Content.Client.UserInterface.Controls; using Content.Shared.IdentityManagement; diff --git a/Content.IntegrationTests/Tests/EntityTest.cs b/Content.IntegrationTests/Tests/EntityTest.cs index 67923f5e7c..0966e984bb 100644 --- a/Content.IntegrationTests/Tests/EntityTest.cs +++ b/Content.IntegrationTests/Tests/EntityTest.cs @@ -311,6 +311,7 @@ namespace Content.IntegrationTests.Tests "DebrisFeaturePlacerController", // Above. "LoadedChunk", // Worldgen chunk loading malding. "BiomeSelection", // Whaddya know, requires config. + "DeployableBarrier", }; await using var pair = await PoolManager.GetServerClient(); diff --git a/Content.Server/Entry/IgnoredComponents.cs b/Content.Server/Entry/IgnoredComponents.cs index 3294b43030..e1d744da2d 100644 --- a/Content.Server/Entry/IgnoredComponents.cs +++ b/Content.Server/Entry/IgnoredComponents.cs @@ -7,7 +7,6 @@ namespace Content.Server.Entry "ConstructionGhost", "IconSmooth", "InteractionOutline", - "ItemStatus", "Marker", "GuidebookControlsTest", "GuideHelp", diff --git a/Content.Server/Salvage/FultonSystem.cs b/Content.Server/Salvage/FultonSystem.cs new file mode 100644 index 0000000000..b16339e05a --- /dev/null +++ b/Content.Server/Salvage/FultonSystem.cs @@ -0,0 +1,70 @@ +using System.Numerics; +using Content.Shared.Salvage.Fulton; +using Robust.Shared.Map; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; + +namespace Content.Server.Salvage; + +public sealed class FultonSystem : SharedFultonSystem +{ + [Dependency] private readonly IRobustRandom _random = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnFultonedStartup); + SubscribeLocalEvent(OnFultonedShutdown); + } + + private void OnFultonedShutdown(EntityUid uid, FultonedComponent component, ComponentShutdown args) + { + Del(component.Effect); + component.Effect = EntityUid.Invalid; + } + + private void OnFultonedStartup(EntityUid uid, FultonedComponent component, ComponentStartup args) + { + if (Exists(component.Effect)) + return; + + component.Effect = Spawn(EffectProto, new EntityCoordinates(uid, EffectOffset)); + Dirty(uid, component); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + var query = EntityQueryEnumerator(); + var curTime = Timing.CurTime; + + while (query.MoveNext(out var uid, out var comp)) + { + if (comp.NextFulton > curTime) + continue; + + Fulton(uid, comp); + } + } + + private void Fulton(EntityUid uid, FultonedComponent component) + { + if (!Deleted(component.Beacon)) + { + var xform = Transform(uid); + var oldCoords = xform.Coordinates; + var offset = _random.NextVector2(1.5f); + TransformSystem.SetCoordinates(uid, new EntityCoordinates(component.Beacon.Value, offset)); + + RaiseNetworkEvent(new FultonAnimationMessage() + { + Entity = uid, + Coordinates = oldCoords, + }); + } + + Audio.PlayPvs(component.Sound, uid); + RemCompDeferred(uid); + } +} diff --git a/Content.Server/Salvage/SalvageSystem.Runner.cs b/Content.Server/Salvage/SalvageSystem.Runner.cs index f94d71bf67..ce65ead928 100644 --- a/Content.Server/Salvage/SalvageSystem.Runner.cs +++ b/Content.Server/Salvage/SalvageSystem.Runner.cs @@ -155,24 +155,24 @@ public sealed partial class SalvageSystem { var remaining = comp.EndTime - _timing.CurTime; - if (comp.Stage < ExpeditionStage.FinalCountdown && remaining < TimeSpan.FromSeconds(30)) + if (comp.Stage < ExpeditionStage.FinalCountdown && remaining < TimeSpan.FromSeconds(45)) { comp.Stage = ExpeditionStage.FinalCountdown; - Dirty(comp); - Announce(uid, Loc.GetString("salvage-expedition-announcement-countdown-seconds", ("duration", TimeSpan.FromSeconds(30).Seconds))); + Dirty(uid, comp); + Announce(uid, Loc.GetString("salvage-expedition-announcement-countdown-seconds", ("duration", TimeSpan.FromSeconds(45).Seconds))); } else if (comp.Stage < ExpeditionStage.MusicCountdown && remaining < TimeSpan.FromMinutes(2)) { // TODO: Some way to play audio attached to a map for players. comp.Stream = _audio.PlayGlobal(comp.Sound, Filter.BroadcastMap(Comp(uid).MapId), true); comp.Stage = ExpeditionStage.MusicCountdown; - Dirty(comp); + Dirty(uid, comp); Announce(uid, Loc.GetString("salvage-expedition-announcement-countdown-minutes", ("duration", TimeSpan.FromMinutes(2).Minutes))); } else if (comp.Stage < ExpeditionStage.Countdown && remaining < TimeSpan.FromMinutes(5)) { comp.Stage = ExpeditionStage.Countdown; - Dirty(comp); + Dirty(uid, comp); Announce(uid, Loc.GetString("salvage-expedition-announcement-countdown-minutes", ("duration", TimeSpan.FromMinutes(5).Minutes))); } // Auto-FTL out any shuttles diff --git a/Content.Shared/DoAfter/SharedDoAfterSystem.cs b/Content.Shared/DoAfter/SharedDoAfterSystem.cs index 350f6e4b27..4bb6005b1c 100644 --- a/Content.Shared/DoAfter/SharedDoAfterSystem.cs +++ b/Content.Shared/DoAfter/SharedDoAfterSystem.cs @@ -216,7 +216,7 @@ public abstract partial class SharedDoAfterSystem : EntitySystem doAfter.InitialItem = handsComponent.ActiveHandEntity; } - // Inital checks + // Initial checks if (ShouldCancel(doAfter, GetEntityQuery(), GetEntityQuery())) return false; diff --git a/Content.Shared/Foldable/SharedFoldableSystem.cs b/Content.Shared/Foldable/SharedFoldableSystem.cs index 2b2b6423d0..78e8d158db 100644 --- a/Content.Shared/Foldable/SharedFoldableSystem.cs +++ b/Content.Shared/Foldable/SharedFoldableSystem.cs @@ -59,6 +59,17 @@ public abstract class SharedFoldableSystem : EntitySystem args.Cancelled = true; } + /// + /// Returns false if the entity isn't foldable. + /// + public bool IsFolded(EntityUid uid, FoldableComponent? component = null) + { + if (!Resolve(uid, ref component)) + return false; + + return component.IsFolded; + } + /// /// Set the folded state of the given /// diff --git a/Content.Shared/Salvage/Fulton/FultonBeaconComponent.cs b/Content.Shared/Salvage/Fulton/FultonBeaconComponent.cs new file mode 100644 index 0000000000..94ddffb108 --- /dev/null +++ b/Content.Shared/Salvage/Fulton/FultonBeaconComponent.cs @@ -0,0 +1,14 @@ +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared.Salvage.Fulton; + +/// +/// Receives . +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class FultonBeaconComponent : Component +{ + [ViewVariables(VVAccess.ReadWrite), DataField("soundLink"), AutoNetworkedField] + public SoundSpecifier? LinkSound = new SoundPathSpecifier("/Audio/Items/beep.ogg"); +} diff --git a/Content.Shared/Salvage/Fulton/FultonComponent.cs b/Content.Shared/Salvage/Fulton/FultonComponent.cs new file mode 100644 index 0000000000..5493636776 --- /dev/null +++ b/Content.Shared/Salvage/Fulton/FultonComponent.cs @@ -0,0 +1,54 @@ +using Content.Shared.Whitelist; +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared.Salvage.Fulton; + +/// +/// Applies to the target so they teleport to after a time. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class FultonComponent : Component +{ + /// + /// How long it takes to apply the fulton to an entity. + /// + [ViewVariables(VVAccess.ReadWrite), DataField("applyDuration"), AutoNetworkedField] + public TimeSpan ApplyFultonDuration = TimeSpan.FromSeconds(3); + + /// + /// Linked fulton beacon. + /// + [ViewVariables(VVAccess.ReadWrite), DataField("beacon")] + public EntityUid? Beacon; + + /// + /// Applies Removeable to the . + /// + [ViewVariables(VVAccess.ReadWrite), DataField("removeable"), AutoNetworkedField] + public bool Removeable = true; + + /// + /// How long the fulton will remain before teleporting to the beacon. + /// + [ViewVariables(VVAccess.ReadWrite), DataField("duration")] + public TimeSpan FultonDuration = TimeSpan.FromSeconds(45); + + [ViewVariables(VVAccess.ReadWrite), DataField("whitelist"), AutoNetworkedField] + public EntityWhitelist? Whitelist = new() + { + Components = new[] + { + "EntityStorage", + "Item", + "ReagentTank", + } + }; + + /// + /// Sound that gets played when fulton is applied. + /// + /// + [ViewVariables(VVAccess.ReadWrite), DataField("soundFulton"), AutoNetworkedField] + public SoundSpecifier? FultonSound = new SoundPathSpecifier("/Audio/Items/Mining/fultext_deploy.ogg"); +} diff --git a/Content.Shared/Salvage/Fulton/FultonedComponent.cs b/Content.Shared/Salvage/Fulton/FultonedComponent.cs new file mode 100644 index 0000000000..3070249eee --- /dev/null +++ b/Content.Shared/Salvage/Fulton/FultonedComponent.cs @@ -0,0 +1,40 @@ +using Robust.Shared.Audio; +using Robust.Shared.GameStates; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; + +namespace Content.Shared.Salvage.Fulton; + +/// +/// Marks an entity as pending being fultoned. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] +public sealed partial class FultonedComponent : Component +{ + /// + /// Effect entity to delete upon removing the component. Only matters clientside. + /// + [ViewVariables, DataField("effect"), AutoNetworkedField] + public EntityUid Effect { get; set; } + + [ViewVariables(VVAccess.ReadWrite), DataField("beacon")] + public EntityUid? Beacon; + + [ViewVariables(VVAccess.ReadWrite), DataField("fultonDuration"), AutoNetworkedField] + public TimeSpan FultonDuration = TimeSpan.FromSeconds(45); + + /// + /// When the fulton is travelling to the beacon. + /// + [ViewVariables(VVAccess.ReadWrite), DataField("nextFulton", customTypeSerializer:typeof(TimeOffsetSerializer)), AutoNetworkedField] + public TimeSpan NextFulton; + + [ViewVariables(VVAccess.ReadWrite), DataField("sound"), AutoNetworkedField] + public SoundSpecifier? Sound = new SoundPathSpecifier("/Audio/Items/Mining/fultext_launch.ogg"); + + // Mainly for admemes. + /// + /// Can the fulton be removed. + /// + [ViewVariables(VVAccess.ReadWrite), DataField("removeable")] + public bool Removeable = true; +} diff --git a/Content.Shared/Salvage/Fulton/SharedFultonSystem.cs b/Content.Shared/Salvage/Fulton/SharedFultonSystem.cs new file mode 100644 index 0000000000..7efa782c51 --- /dev/null +++ b/Content.Shared/Salvage/Fulton/SharedFultonSystem.cs @@ -0,0 +1,194 @@ +using System.Numerics; +using Content.Shared.DoAfter; +using Content.Shared.Examine; +using Content.Shared.Foldable; +using Content.Shared.Interaction; +using Content.Shared.Popups; +using Content.Shared.Stacks; +using Content.Shared.Verbs; +using Robust.Shared.Containers; +using Robust.Shared.Map; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; +using Robust.Shared.Timing; + +namespace Content.Shared.Salvage.Fulton; + +/// +/// Provides extraction devices that teleports the attached entity after elapses to the linked beacon. +/// +public abstract partial class SharedFultonSystem : EntitySystem +{ + [Dependency] protected readonly IGameTiming Timing = default!; + [Dependency] private readonly MetaDataSystem _metadata = default!; + [Dependency] protected readonly SharedAudioSystem Audio = default!; + [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; + [Dependency] private readonly SharedFoldableSystem _foldable = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly SharedStackSystem _stack = default!; + [Dependency] protected readonly SharedTransformSystem TransformSystem = default!; + + [ValidatePrototypeId] public const string EffectProto = "FultonEffect"; + protected static readonly Vector2 EffectOffset = Vector2.Zero; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnFultonDoAfter); + + SubscribeLocalEvent(OnFultonUnpaused); + SubscribeLocalEvent>(OnFultonedGetVerbs); + SubscribeLocalEvent(OnFultonedExamine); + SubscribeLocalEvent(OnFultonContainerInserted); + + SubscribeLocalEvent(OnFultonInteract); + } + + private void OnFultonContainerInserted(EntityUid uid, FultonedComponent component, EntGotInsertedIntoContainerMessage args) + { + RemCompDeferred(uid); + } + + private void OnFultonedExamine(EntityUid uid, FultonedComponent component, ExaminedEvent args) + { + var remaining = component.NextFulton + _metadata.GetPauseTime(uid) - Timing.CurTime; + var message = Loc.GetString("fulton-examine", ("time", $"{remaining.TotalSeconds:0.00}")); + + args.PushText(message); + } + + private void OnFultonedGetVerbs(EntityUid uid, FultonedComponent component, GetVerbsEvent args) + { + args.Verbs.Add(new InteractionVerb() + { + Text = Loc.GetString("fulton-remove"), + Act = () => + { + Unfulton(uid); + } + }); + } + + private void Unfulton(EntityUid uid, FultonedComponent? component = null) + { + if (!Resolve(uid, ref component, false) || !component.Removeable) + return; + + RemCompDeferred(uid); + } + + private void OnFultonDoAfter(FultonedDoAfterEvent args) + { + if (args.Cancelled || args.Target == null || !TryComp(args.Used, out var fulton)) + return; + + if (!_stack.Use(args.Used.Value, 1)) + { + return; + } + + var fultoned = AddComp(args.Target.Value); + fultoned.Beacon = fulton.Beacon; + fultoned.NextFulton = Timing.CurTime + fulton.FultonDuration; + fultoned.FultonDuration = fulton.FultonDuration; + fultoned.Removeable = fulton.Removeable; + UpdateAppearance(args.Target.Value, fultoned); + Dirty(args.Target.Value, fultoned); + Audio.PlayPredicted(fulton.FultonSound, args.Target.Value, args.User); + } + + private void OnFultonUnpaused(EntityUid uid, FultonedComponent component, ref EntityUnpausedEvent args) + { + component.NextFulton += args.PausedTime; + } + + private void OnFultonInteract(EntityUid uid, FultonComponent component, AfterInteractEvent args) + { + if (args.Target == null || args.Handled) + return; + + if (TryComp(args.Target, out var beacon)) + { + if (!_foldable.IsFolded(args.Target.Value)) + { + component.Beacon = args.Target.Value; + Audio.PlayPredicted(beacon.LinkSound, uid, args.User); + _popup.PopupClient(Loc.GetString("fulton-linked"), uid, args.User); + } + else + { + component.Beacon = EntityUid.Invalid; + _popup.PopupClient(Loc.GetString("fulton-folded"), uid, args.User); + } + + return; + } + + if (Deleted(component.Beacon)) + { + _popup.PopupClient(Loc.GetString("fulton-not-found"), uid, args.User); + return; + } + + if (!CanFulton(args.Target.Value, uid, component)) + { + _popup.PopupClient(Loc.GetString("fulton-invalid"), uid, uid); + return; + } + + if (HasComp(args.Target)) + { + _popup.PopupClient(Loc.GetString("fulton-fultoned"), uid, uid); + return; + } + + args.Handled = true; + + var ev = new FultonedDoAfterEvent(); + _doAfter.TryStartDoAfter( + new DoAfterArgs(args.User, component.ApplyFultonDuration, ev, args.Target, args.Target, args.Used) + { + CancelDuplicate = true, + MovementThreshold = 0.5f, + BreakOnUserMove = true, + BreakOnTargetMove = true, + Broadcast = true, + NeedHand = true, + }); + } + + protected virtual void UpdateAppearance(EntityUid uid, FultonedComponent fultoned) + { + return; + } + + private bool CanFulton(EntityUid targetUid, EntityUid uid, FultonComponent component) + { + if (Transform(targetUid).Anchored) + return false; + + if (component.Whitelist?.IsValid(targetUid, EntityManager) != true) + { + return false; + } + + return true; + } + + [Serializable, NetSerializable] + private sealed partial class FultonedDoAfterEvent : SimpleDoAfterEvent + { + } + + // Animations aren't really good for networking hence this. + /// + /// Tells clients to play the fulton animation. + /// + [Serializable, NetSerializable] + protected sealed class FultonAnimationMessage : EntityEventArgs + { + public EntityUid Entity; + public EntityCoordinates Coordinates; + } +} diff --git a/Resources/Audio/Items/Mining/attributions.yml b/Resources/Audio/Items/Mining/attributions.yml new file mode 100644 index 0000000000..847dba4351 --- /dev/null +++ b/Resources/Audio/Items/Mining/attributions.yml @@ -0,0 +1,4 @@ +- files: ["fultext_deploy.ogg", "fultext_launch.ogg"] + license: "CC-BY-SA-3.0" + copyright: "Taken from tgstation" + source: "https://github.com/tgstation/tgstation/tree/893e5b0180f3fffe192d2e241325cfac937f5257/sound/items" diff --git a/Resources/Audio/Items/Mining/fultext_deploy.ogg b/Resources/Audio/Items/Mining/fultext_deploy.ogg new file mode 100644 index 0000000000..2433b9e0fe Binary files /dev/null and b/Resources/Audio/Items/Mining/fultext_deploy.ogg differ diff --git a/Resources/Audio/Items/Mining/fultext_launch.ogg b/Resources/Audio/Items/Mining/fultext_launch.ogg new file mode 100644 index 0000000000..2c87441992 Binary files /dev/null and b/Resources/Audio/Items/Mining/fultext_launch.ogg differ diff --git a/Resources/Locale/en-US/research/technologies.ftl b/Resources/Locale/en-US/research/technologies.ftl index 44677ef890..9cd75a91c4 100644 --- a/Resources/Locale/en-US/research/technologies.ftl +++ b/Resources/Locale/en-US/research/technologies.ftl @@ -5,6 +5,7 @@ research-discipline-arsenal = Arsenal research-discipline-experimental = Experimental research-discipline-civilian-services = Civilian Services +research-technology-fulton = Fultons research-technology-salvage-equipment = Salvage Equipment research-technology-advanced-powercells = Advanced Powercells research-technology-compact-power = Compact Power diff --git a/Resources/Locale/en-US/salvage/fulton-system.ftl b/Resources/Locale/en-US/salvage/fulton-system.ftl new file mode 100644 index 0000000000..3d8e9e98c0 --- /dev/null +++ b/Resources/Locale/en-US/salvage/fulton-system.ftl @@ -0,0 +1,7 @@ +fulton-folded = Beacon needs unfolding +fulton-examine = {$time} seconds until extraction +fulton-linked = Linked beacon +fulton-not-found = No beacon found +fulton-invalid = Can't fulton +fulton-fultoned = Already fultoned +fulton-remove = Remove fulton diff --git a/Resources/Prototypes/Entities/Objects/Materials/Sheets/glass.yml b/Resources/Prototypes/Entities/Objects/Materials/Sheets/glass.yml index f22eb93e86..2c1a8e628d 100644 --- a/Resources/Prototypes/Entities/Objects/Materials/Sheets/glass.yml +++ b/Resources/Prototypes/Entities/Objects/Materials/Sheets/glass.yml @@ -12,7 +12,6 @@ size: 30 - type: StaticPrice price: 0 - - type: ItemStatus - type: Tag tags: - Sheet diff --git a/Resources/Prototypes/Entities/Objects/Materials/Sheets/metal.yml b/Resources/Prototypes/Entities/Objects/Materials/Sheets/metal.yml index d38cfd5240..fb08f7ad9b 100644 --- a/Resources/Prototypes/Entities/Objects/Materials/Sheets/metal.yml +++ b/Resources/Prototypes/Entities/Objects/Materials/Sheets/metal.yml @@ -11,7 +11,6 @@ size: 30 - type: StaticPrice price: 0 - - type: ItemStatus - type: Tag tags: - Sheet diff --git a/Resources/Prototypes/Entities/Objects/Materials/Sheets/other.yml b/Resources/Prototypes/Entities/Objects/Materials/Sheets/other.yml index 85c659378a..3cb6f027a9 100644 --- a/Resources/Prototypes/Entities/Objects/Materials/Sheets/other.yml +++ b/Resources/Prototypes/Entities/Objects/Materials/Sheets/other.yml @@ -9,7 +9,6 @@ - type: Item sprite: Objects/Materials/Sheets/other.rsi size: 30 - - type: ItemStatus - type: Tag tags: - Sheet diff --git a/Resources/Prototypes/Entities/Objects/Materials/ingots.yml b/Resources/Prototypes/Entities/Objects/Materials/ingots.yml index 386d21beb9..61aefee332 100644 --- a/Resources/Prototypes/Entities/Objects/Materials/ingots.yml +++ b/Resources/Prototypes/Entities/Objects/Materials/ingots.yml @@ -11,7 +11,6 @@ size: 30 - type: StaticPrice price: 0 - - type: ItemStatus - type: Tag tags: - Ingot diff --git a/Resources/Prototypes/Entities/Objects/Materials/materials.yml b/Resources/Prototypes/Entities/Objects/Materials/materials.yml index 05961b355e..1a242db1af 100644 --- a/Resources/Prototypes/Entities/Objects/Materials/materials.yml +++ b/Resources/Prototypes/Entities/Objects/Materials/materials.yml @@ -9,7 +9,6 @@ - type: Item sprite: Objects/Materials/materials.rsi size: 30 - - type: ItemStatus - type: Tag tags: - DroneUsable diff --git a/Resources/Prototypes/Entities/Objects/Materials/ore.yml b/Resources/Prototypes/Entities/Objects/Materials/ore.yml index bd639fd51a..f27d1b770e 100644 --- a/Resources/Prototypes/Entities/Objects/Materials/ore.yml +++ b/Resources/Prototypes/Entities/Objects/Materials/ore.yml @@ -9,7 +9,6 @@ - type: Item sprite: Objects/Materials/ore.rsi size: 60 - - type: ItemStatus - type: Tag tags: - Ore diff --git a/Resources/Prototypes/Entities/Objects/Materials/parts.yml b/Resources/Prototypes/Entities/Objects/Materials/parts.yml index d07f511fdf..e75704c2a4 100644 --- a/Resources/Prototypes/Entities/Objects/Materials/parts.yml +++ b/Resources/Prototypes/Entities/Objects/Materials/parts.yml @@ -8,7 +8,6 @@ state: rods - type: Item sprite: Objects/Materials/parts.rsi - - type: ItemStatus - type: Tag tags: - DroneUsable diff --git a/Resources/Prototypes/Entities/Objects/Tools/fulton.yml b/Resources/Prototypes/Entities/Objects/Tools/fulton.yml new file mode 100644 index 0000000000..e22cae19cd --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Tools/fulton.yml @@ -0,0 +1,108 @@ +# Stack +- type: stack + id: Fulton + name: fulton + icon: + sprite: /Textures/Objects/Tools/fulton.rsi + state: extraction_pack + spawn: Fulton1 + maxCount: 10 + itemSize: 2 + +# Entities +- type: entity + id: FultonBeacon + parent: BaseFoldable + name: fulton beacon + description: Beacon to receive fulton extractions. + components: + - type: Physics + bodyType: Dynamic + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeAabb + bounds: "-0.25,-0.4,0.25,0.1" + density: 20 + mask: + - Impassable + - type: Item + size: 30 + - type: Foldable + - type: Clickable + - type: InteractionOutline + - type: FultonBeacon + - type: Appearance + - type: GenericVisualizer + visuals: + enum.FoldedVisuals.State: + foldedLayer: + True: { state: folded_extraction } + False: { state: extraction_point } + - type: Sprite + sprite: Objects/Tools/fulton.rsi + drawdepth: SmallObjects + noRot: true + layers: + - state: extraction_point + map: [ "foldedLayer" ] + +- type: entity + id: Fulton + parent: BaseItem + suffix: Full + name: fulton + description: Used to extract containers, items, or forcibly recruit people into your base of operations. + components: + - type: Fulton + - type: Item + size: 20 + - type: Stack + stackType: Fulton + count: 10 + - type: Sprite + drawdepth: SmallObjects + sprite: Objects/Tools/fulton.rsi + state: extraction_pack + - type: Damageable + damageContainer: Inorganic + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 100 + behaviors: + - !type:DoActsBehavior + acts: [ "Destruction" ] + +- type: entity + id: Fulton1 + parent: Fulton + name: fulton + suffix: One + components: + - type: Item + size: 2 + - type: Stack + count: 1 + +- type: entity + id: FultonEffect + noSpawn: true + name: fulton effect + components: + - type: TimedDespawn + lifetime: 60 + - type: Sprite + drawdepth: Effects + noRot: true + offset: 0,0.5 + layers: + - map: [ "enum.FultonVisualLayers.Base" ] + sprite: Objects/Tools/fulton_balloon.rsi + state: fulton_balloon + - type: Tag + tags: + - HideContextMenu + - type: AnimationPlayer diff --git a/Resources/Prototypes/Entities/Objects/Tools/lighters.yml b/Resources/Prototypes/Entities/Objects/Tools/lighters.yml index 8dd4fa0c6a..e3422f2a4a 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/lighters.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/lighters.yml @@ -44,7 +44,6 @@ sprite: Objects/Tools/lighters.rsi heldPrefix: off - type: ItemCooldown - - type: ItemStatus - type: RefillableSolution solution: Welder - type: SolutionContainerManager diff --git a/Resources/Prototypes/Entities/Objects/Tools/welders.yml b/Resources/Prototypes/Entities/Objects/Tools/welders.yml index 710e7d5be0..3a105a2994 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/welders.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/welders.yml @@ -33,7 +33,6 @@ damage: types: Blunt: 5 #i mean... i GUESS you could use it like that - - type: ItemStatus - type: RefillableSolution solution: Welder - type: SolutionContainerManager diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/chainsaw.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/chainsaw.yml index 1e108c2dd7..387913715c 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/chainsaw.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/chainsaw.yml @@ -34,7 +34,6 @@ size: 50 sprite: Objects/Weapons/Melee/chainsaw.rsi - type: DisarmMalus - - type: ItemStatus - type: RefillableSolution solution: Welder - type: SolutionContainerManager diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index 72b01b266c..7832999464 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -97,6 +97,8 @@ - TRayScanner - GasAnalyzer - UtilityBelt + - Fulton + - FultonBeacon - Pickaxe - ModularReceiver - AppraisalTool diff --git a/Resources/Prototypes/Recipes/Lathes/salvage.yml b/Resources/Prototypes/Recipes/Lathes/salvage.yml new file mode 100644 index 0000000000..9cec605b3e --- /dev/null +++ b/Resources/Prototypes/Recipes/Lathes/salvage.yml @@ -0,0 +1,15 @@ +- type: latheRecipe + id: Fulton + result: Fulton1 + completetime: 5 + materials: + Cloth: 200 + +- type: latheRecipe + id: FultonBeacon + result: FultonBeacon + completetime: 5 + materials: + Steel: 1000 + Glass: 500 + # If they get spammed make it cost silver. diff --git a/Resources/Textures/Objects/Tools/fulton.rsi/extraction_pack.png b/Resources/Textures/Objects/Tools/fulton.rsi/extraction_pack.png new file mode 100644 index 0000000000..bdaf682202 Binary files /dev/null and b/Resources/Textures/Objects/Tools/fulton.rsi/extraction_pack.png differ diff --git a/Resources/Textures/Objects/Tools/fulton.rsi/extraction_point.png b/Resources/Textures/Objects/Tools/fulton.rsi/extraction_point.png new file mode 100644 index 0000000000..7bdfd4ef70 Binary files /dev/null and b/Resources/Textures/Objects/Tools/fulton.rsi/extraction_point.png differ diff --git a/Resources/Textures/Objects/Tools/fulton.rsi/extraction_point_light.png b/Resources/Textures/Objects/Tools/fulton.rsi/extraction_point_light.png new file mode 100644 index 0000000000..6b797068b1 Binary files /dev/null and b/Resources/Textures/Objects/Tools/fulton.rsi/extraction_point_light.png differ diff --git a/Resources/Textures/Objects/Tools/fulton.rsi/folded_extraction.png b/Resources/Textures/Objects/Tools/fulton.rsi/folded_extraction.png new file mode 100644 index 0000000000..31f1f4ef14 Binary files /dev/null and b/Resources/Textures/Objects/Tools/fulton.rsi/folded_extraction.png differ diff --git a/Resources/Textures/Objects/Tools/fulton.rsi/meta.json b/Resources/Textures/Objects/Tools/fulton.rsi/meta.json new file mode 100644 index 0000000000..33490d3b1e --- /dev/null +++ b/Resources/Textures/Objects/Tools/fulton.rsi/meta.json @@ -0,0 +1,35 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "https://github.com/tgstation/tgstation/blob/a7a67c81afc99d77483c84878173822ee8cbeecd/icons/obj/fulton.dmi", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "folded_extraction" + }, + { + "name": "extraction_point", + "delays": [ + [ + 1, + 0.1 + ] + ] + }, + { + "name": "extraction_point_light", + "delays": [ + [ + 1, + 0.1 + ] + ] + }, + { + "name": "extraction_pack" + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Objects/Tools/fulton_balloon.rsi/fulton_balloon.png b/Resources/Textures/Objects/Tools/fulton_balloon.rsi/fulton_balloon.png new file mode 100644 index 0000000000..4e4eba700d Binary files /dev/null and b/Resources/Textures/Objects/Tools/fulton_balloon.rsi/fulton_balloon.png differ diff --git a/Resources/Textures/Objects/Tools/fulton_balloon.rsi/fulton_expand.png b/Resources/Textures/Objects/Tools/fulton_balloon.rsi/fulton_expand.png new file mode 100644 index 0000000000..6b7af2daef Binary files /dev/null and b/Resources/Textures/Objects/Tools/fulton_balloon.rsi/fulton_expand.png differ diff --git a/Resources/Textures/Objects/Tools/fulton_balloon.rsi/meta.json b/Resources/Textures/Objects/Tools/fulton_balloon.rsi/meta.json new file mode 100644 index 0000000000..36df097eb4 --- /dev/null +++ b/Resources/Textures/Objects/Tools/fulton_balloon.rsi/meta.json @@ -0,0 +1,25 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "https://github.com/tgstation/tgstation/blob/a7a67c81afc99d77483c84878173822ee8cbeecd/icons/obj/fulton.dmi", + "size": { + "x": 32, + "y": 41 + }, + "states": [ + { + "name": "fulton_balloon" + }, + { + "name": "fulton_expand", + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + } + ] +} \ No newline at end of file