Add fultons (#18958)
This commit is contained in:
@@ -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
|
||||
{
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Client.Items.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed partial class ItemStatusComponent : Component
|
||||
{
|
||||
}
|
||||
}
|
||||
118
Content.Client/Salvage/FultonSystem.cs
Normal file
118
Content.Client/Salvage/FultonSystem.cs
Normal file
@@ -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<FultonedComponent, AfterAutoHandleStateEvent>(OnHandleState);
|
||||
SubscribeNetworkEvent<FultonAnimationMessage>(OnFultonMessage);
|
||||
}
|
||||
|
||||
private void OnFultonMessage(FultonAnimationMessage ev)
|
||||
{
|
||||
if (Deleted(ev.Entity) || !TryComp<SpriteComponent>(ev.Entity, out var entSprite))
|
||||
return;
|
||||
|
||||
var animationEnt = Spawn(null, ev.Coordinates);
|
||||
// TODO: Spawn fulton layer
|
||||
var sprite = AddComp<SpriteComponent>(animationEnt);
|
||||
_serManager.CopyTo(entSprite, ref sprite, notNullableOverride: true);
|
||||
|
||||
if (TryComp<AppearanceComponent>(ev.Entity, out var entAppearance))
|
||||
{
|
||||
var appearance = AddComp<AppearanceComponent>(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<TimedDespawnComponent>(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,
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -7,7 +7,6 @@ namespace Content.Server.Entry
|
||||
"ConstructionGhost",
|
||||
"IconSmooth",
|
||||
"InteractionOutline",
|
||||
"ItemStatus",
|
||||
"Marker",
|
||||
"GuidebookControlsTest",
|
||||
"GuideHelp",
|
||||
|
||||
70
Content.Server/Salvage/FultonSystem.cs
Normal file
70
Content.Server/Salvage/FultonSystem.cs
Normal file
@@ -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<FultonedComponent, ComponentStartup>(OnFultonedStartup);
|
||||
SubscribeLocalEvent<FultonedComponent, ComponentShutdown>(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<FultonedComponent>();
|
||||
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<FultonedComponent>(uid);
|
||||
}
|
||||
}
|
||||
@@ -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<MapComponent>(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
|
||||
|
||||
@@ -216,7 +216,7 @@ public abstract partial class SharedDoAfterSystem : EntitySystem
|
||||
doAfter.InitialItem = handsComponent.ActiveHandEntity;
|
||||
}
|
||||
|
||||
// Inital checks
|
||||
// Initial checks
|
||||
if (ShouldCancel(doAfter, GetEntityQuery<TransformComponent>(), GetEntityQuery<HandsComponent>()))
|
||||
return false;
|
||||
|
||||
|
||||
@@ -59,6 +59,17 @@ public abstract class SharedFoldableSystem : EntitySystem
|
||||
args.Cancelled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns false if the entity isn't foldable.
|
||||
/// </summary>
|
||||
public bool IsFolded(EntityUid uid, FoldableComponent? component = null)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return false;
|
||||
|
||||
return component.IsFolded;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the folded state of the given <see cref="FoldableComponent"/>
|
||||
/// </summary>
|
||||
|
||||
14
Content.Shared/Salvage/Fulton/FultonBeaconComponent.cs
Normal file
14
Content.Shared/Salvage/Fulton/FultonBeaconComponent.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Salvage.Fulton;
|
||||
|
||||
/// <summary>
|
||||
/// Receives <see cref="FultonedComponent"/>.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
public sealed partial class FultonBeaconComponent : Component
|
||||
{
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("soundLink"), AutoNetworkedField]
|
||||
public SoundSpecifier? LinkSound = new SoundPathSpecifier("/Audio/Items/beep.ogg");
|
||||
}
|
||||
54
Content.Shared/Salvage/Fulton/FultonComponent.cs
Normal file
54
Content.Shared/Salvage/Fulton/FultonComponent.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using Content.Shared.Whitelist;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Salvage.Fulton;
|
||||
|
||||
/// <summary>
|
||||
/// Applies <see cref="FultonedComponent"/> to the target so they teleport to <see cref="FultonBeaconComponent"/> after a time.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
public sealed partial class FultonComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// How long it takes to apply the fulton to an entity.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("applyDuration"), AutoNetworkedField]
|
||||
public TimeSpan ApplyFultonDuration = TimeSpan.FromSeconds(3);
|
||||
|
||||
/// <summary>
|
||||
/// Linked fulton beacon.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("beacon")]
|
||||
public EntityUid? Beacon;
|
||||
|
||||
/// <summary>
|
||||
/// Applies Removeable to the <see cref="FultonedComponent"/>.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("removeable"), AutoNetworkedField]
|
||||
public bool Removeable = true;
|
||||
|
||||
/// <summary>
|
||||
/// How long the fulton will remain before teleporting to the beacon.
|
||||
/// </summary>
|
||||
[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",
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Sound that gets played when fulton is applied.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("soundFulton"), AutoNetworkedField]
|
||||
public SoundSpecifier? FultonSound = new SoundPathSpecifier("/Audio/Items/Mining/fultext_deploy.ogg");
|
||||
}
|
||||
40
Content.Shared/Salvage/Fulton/FultonedComponent.cs
Normal file
40
Content.Shared/Salvage/Fulton/FultonedComponent.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||
|
||||
namespace Content.Shared.Salvage.Fulton;
|
||||
|
||||
/// <summary>
|
||||
/// Marks an entity as pending being fultoned.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)]
|
||||
public sealed partial class FultonedComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Effect entity to delete upon removing the component. Only matters clientside.
|
||||
/// </summary>
|
||||
[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);
|
||||
|
||||
/// <summary>
|
||||
/// When the fulton is travelling to the beacon.
|
||||
/// </summary>
|
||||
[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.
|
||||
/// <summary>
|
||||
/// Can the fulton be removed.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("removeable")]
|
||||
public bool Removeable = true;
|
||||
}
|
||||
194
Content.Shared/Salvage/Fulton/SharedFultonSystem.cs
Normal file
194
Content.Shared/Salvage/Fulton/SharedFultonSystem.cs
Normal file
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extraction devices that teleports the attached entity after <see cref="FultonDuration"/> elapses to the linked beacon.
|
||||
/// </summary>
|
||||
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<EntityPrototype>] public const string EffectProto = "FultonEffect";
|
||||
protected static readonly Vector2 EffectOffset = Vector2.Zero;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<FultonedDoAfterEvent>(OnFultonDoAfter);
|
||||
|
||||
SubscribeLocalEvent<FultonedComponent, EntityUnpausedEvent>(OnFultonUnpaused);
|
||||
SubscribeLocalEvent<FultonedComponent, GetVerbsEvent<InteractionVerb>>(OnFultonedGetVerbs);
|
||||
SubscribeLocalEvent<FultonedComponent, ExaminedEvent>(OnFultonedExamine);
|
||||
SubscribeLocalEvent<FultonedComponent, EntGotInsertedIntoContainerMessage>(OnFultonContainerInserted);
|
||||
|
||||
SubscribeLocalEvent<FultonComponent, AfterInteractEvent>(OnFultonInteract);
|
||||
}
|
||||
|
||||
private void OnFultonContainerInserted(EntityUid uid, FultonedComponent component, EntGotInsertedIntoContainerMessage args)
|
||||
{
|
||||
RemCompDeferred<FultonedComponent>(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<InteractionVerb> 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<FultonedComponent>(uid);
|
||||
}
|
||||
|
||||
private void OnFultonDoAfter(FultonedDoAfterEvent args)
|
||||
{
|
||||
if (args.Cancelled || args.Target == null || !TryComp<FultonComponent>(args.Used, out var fulton))
|
||||
return;
|
||||
|
||||
if (!_stack.Use(args.Used.Value, 1))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var fultoned = AddComp<FultonedComponent>(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<FultonBeaconComponent>(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<FultonedComponent>(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.
|
||||
/// <summary>
|
||||
/// Tells clients to play the fulton animation.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
protected sealed class FultonAnimationMessage : EntityEventArgs
|
||||
{
|
||||
public EntityUid Entity;
|
||||
public EntityCoordinates Coordinates;
|
||||
}
|
||||
}
|
||||
4
Resources/Audio/Items/Mining/attributions.yml
Normal file
4
Resources/Audio/Items/Mining/attributions.yml
Normal file
@@ -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"
|
||||
BIN
Resources/Audio/Items/Mining/fultext_deploy.ogg
Normal file
BIN
Resources/Audio/Items/Mining/fultext_deploy.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Items/Mining/fultext_launch.ogg
Normal file
BIN
Resources/Audio/Items/Mining/fultext_launch.ogg
Normal file
Binary file not shown.
@@ -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
|
||||
|
||||
7
Resources/Locale/en-US/salvage/fulton-system.ftl
Normal file
7
Resources/Locale/en-US/salvage/fulton-system.ftl
Normal file
@@ -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
|
||||
@@ -12,7 +12,6 @@
|
||||
size: 30
|
||||
- type: StaticPrice
|
||||
price: 0
|
||||
- type: ItemStatus
|
||||
- type: Tag
|
||||
tags:
|
||||
- Sheet
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
size: 30
|
||||
- type: StaticPrice
|
||||
price: 0
|
||||
- type: ItemStatus
|
||||
- type: Tag
|
||||
tags:
|
||||
- Sheet
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
- type: Item
|
||||
sprite: Objects/Materials/Sheets/other.rsi
|
||||
size: 30
|
||||
- type: ItemStatus
|
||||
- type: Tag
|
||||
tags:
|
||||
- Sheet
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
size: 30
|
||||
- type: StaticPrice
|
||||
price: 0
|
||||
- type: ItemStatus
|
||||
- type: Tag
|
||||
tags:
|
||||
- Ingot
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
- type: Item
|
||||
sprite: Objects/Materials/materials.rsi
|
||||
size: 30
|
||||
- type: ItemStatus
|
||||
- type: Tag
|
||||
tags:
|
||||
- DroneUsable
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
- type: Item
|
||||
sprite: Objects/Materials/ore.rsi
|
||||
size: 60
|
||||
- type: ItemStatus
|
||||
- type: Tag
|
||||
tags:
|
||||
- Ore
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
state: rods
|
||||
- type: Item
|
||||
sprite: Objects/Materials/parts.rsi
|
||||
- type: ItemStatus
|
||||
- type: Tag
|
||||
tags:
|
||||
- DroneUsable
|
||||
|
||||
108
Resources/Prototypes/Entities/Objects/Tools/fulton.yml
Normal file
108
Resources/Prototypes/Entities/Objects/Tools/fulton.yml
Normal file
@@ -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
|
||||
@@ -44,7 +44,6 @@
|
||||
sprite: Objects/Tools/lighters.rsi
|
||||
heldPrefix: off
|
||||
- type: ItemCooldown
|
||||
- type: ItemStatus
|
||||
- type: RefillableSolution
|
||||
solution: Welder
|
||||
- type: SolutionContainerManager
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
size: 50
|
||||
sprite: Objects/Weapons/Melee/chainsaw.rsi
|
||||
- type: DisarmMalus
|
||||
- type: ItemStatus
|
||||
- type: RefillableSolution
|
||||
solution: Welder
|
||||
- type: SolutionContainerManager
|
||||
|
||||
@@ -97,6 +97,8 @@
|
||||
- TRayScanner
|
||||
- GasAnalyzer
|
||||
- UtilityBelt
|
||||
- Fulton
|
||||
- FultonBeacon
|
||||
- Pickaxe
|
||||
- ModularReceiver
|
||||
- AppraisalTool
|
||||
|
||||
15
Resources/Prototypes/Recipes/Lathes/salvage.yml
Normal file
15
Resources/Prototypes/Recipes/Lathes/salvage.yml
Normal file
@@ -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.
|
||||
BIN
Resources/Textures/Objects/Tools/fulton.rsi/extraction_pack.png
Normal file
BIN
Resources/Textures/Objects/Tools/fulton.rsi/extraction_pack.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
BIN
Resources/Textures/Objects/Tools/fulton.rsi/extraction_point.png
Normal file
BIN
Resources/Textures/Objects/Tools/fulton.rsi/extraction_point.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 724 B |
Binary file not shown.
|
After Width: | Height: | Size: 328 B |
Binary file not shown.
|
After Width: | Height: | Size: 303 B |
35
Resources/Textures/Objects/Tools/fulton.rsi/meta.json
Normal file
35
Resources/Textures/Objects/Tools/fulton.rsi/meta.json
Normal file
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.9 KiB |
@@ -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
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user