diff --git a/Content.Client/CartridgeLoader/CartridgeLoaderBoundUserInterface.cs b/Content.Client/CartridgeLoader/CartridgeLoaderBoundUserInterface.cs index aaa17b7976..b7c3b7e22d 100644 --- a/Content.Client/CartridgeLoader/CartridgeLoaderBoundUserInterface.cs +++ b/Content.Client/CartridgeLoader/CartridgeLoaderBoundUserInterface.cs @@ -131,7 +131,7 @@ public abstract class CartridgeLoaderBoundUserInterface : BoundUserInterface private UIFragment? RetrieveCartridgeUI(EntityUid? cartridgeUid) { var component = _entityManager?.GetComponentOrNull(cartridgeUid); - component?.Ui?.Setup(this); + component?.Ui?.Setup(this, cartridgeUid); return component?.Ui; } } diff --git a/Content.Client/CartridgeLoader/Cartridges/NetProbeUi.cs b/Content.Client/CartridgeLoader/Cartridges/NetProbeUi.cs index 7846b120f9..5112a61dc2 100644 --- a/Content.Client/CartridgeLoader/Cartridges/NetProbeUi.cs +++ b/Content.Client/CartridgeLoader/Cartridges/NetProbeUi.cs @@ -14,7 +14,7 @@ public sealed class NetProbeUi : UIFragment return _fragment!; } - public override void Setup(BoundUserInterface userInterface) + public override void Setup(BoundUserInterface userInterface, EntityUid? fragmentOwner) { _fragment = new NetProbeUiFragment(); } diff --git a/Content.Client/CartridgeLoader/Cartridges/NotekeeperUi.cs b/Content.Client/CartridgeLoader/Cartridges/NotekeeperUi.cs index 74ec1032b1..8f90cd45f7 100644 --- a/Content.Client/CartridgeLoader/Cartridges/NotekeeperUi.cs +++ b/Content.Client/CartridgeLoader/Cartridges/NotekeeperUi.cs @@ -15,7 +15,7 @@ public sealed class NotekeeperUi : UIFragment return _fragment!; } - public override void Setup(BoundUserInterface userInterface) + public override void Setup(BoundUserInterface userInterface, EntityUid? fragmentOwner) { _fragment = new NotekeeperUiFragment(); _fragment.OnNoteRemoved += note => SendNotekeeperMessage(NotekeeperUiAction.Remove, note, userInterface); diff --git a/Content.Client/Mech/MechAssemblyVisualizerSystem.cs b/Content.Client/Mech/MechAssemblyVisualizerSystem.cs new file mode 100644 index 0000000000..42a2b5f534 --- /dev/null +++ b/Content.Client/Mech/MechAssemblyVisualizerSystem.cs @@ -0,0 +1,24 @@ +using Content.Shared.Mech; +using Robust.Client.GameObjects; + +namespace Content.Client.Mech; + +/// +/// Handles the sprite state changes while +/// constructing mech assemblies. +/// +public sealed class MechAssemblyVisualizerSystem : VisualizerSystem +{ + protected override void OnAppearanceChange(EntityUid uid, MechAssemblyVisualsComponent component, + ref AppearanceChangeEvent args) + { + base.OnAppearanceChange(uid, component, ref args); + + if (!args.Component.TryGetData(MechAssemblyVisuals.State, out int stage)) + return; + + var state = component.StatePrefix + stage; + + args.Sprite?.LayerSetState(0, state); + } +} diff --git a/Content.Client/Mech/MechAssemblyVisualsComponent.cs b/Content.Client/Mech/MechAssemblyVisualsComponent.cs new file mode 100644 index 0000000000..6d22db0cb5 --- /dev/null +++ b/Content.Client/Mech/MechAssemblyVisualsComponent.cs @@ -0,0 +1,15 @@ +namespace Content.Client.Mech; + +/// +/// This is used for visualizing mech constructions +/// +[RegisterComponent] +public sealed class MechAssemblyVisualsComponent : Component +{ + /// + /// The prefix that is followed by the number which + /// denotes the current state to use. + /// + [DataField("statePrefix", required: true)] + public string StatePrefix = string.Empty; +} diff --git a/Content.Client/Mech/MechComponent.cs b/Content.Client/Mech/MechComponent.cs new file mode 100644 index 0000000000..7f67f9b5a3 --- /dev/null +++ b/Content.Client/Mech/MechComponent.cs @@ -0,0 +1,12 @@ +using Content.Shared.Mech.Components; +using Robust.Shared.GameStates; + +namespace Content.Client.Mech; + +/// +[RegisterComponent, NetworkedComponent] +[ComponentReference(typeof(SharedMechComponent))] +public sealed class MechComponent : SharedMechComponent +{ + +} diff --git a/Content.Client/Mech/MechSystem.cs b/Content.Client/Mech/MechSystem.cs new file mode 100644 index 0000000000..77a23bc26d --- /dev/null +++ b/Content.Client/Mech/MechSystem.cs @@ -0,0 +1,43 @@ +using Content.Shared.Mech; +using Content.Shared.Mech.EntitySystems; +using Robust.Client.GameObjects; +using DrawDepth = Content.Shared.DrawDepth.DrawDepth; + +namespace Content.Client.Mech; + +/// +public sealed class MechSystem : SharedMechSystem +{ + /// + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnAppearanceChanged); + } + + private void OnAppearanceChanged(EntityUid uid, MechComponent component, ref AppearanceChangeEvent args) + { + if (args.Sprite == null) + return; + + if (!args.Sprite.TryGetLayer((int) MechVisualLayers.Base, out var layer)) + return; + + var state = component.BaseState; + var drawDepth = DrawDepth.Mobs; + if (component.BrokenState != null && args.Component.TryGetData(MechVisuals.Broken, out bool broken) && broken) + { + state = component.BrokenState; + drawDepth = DrawDepth.SmallMobs; + } + else if (component.OpenState != null && args.Component.TryGetData(MechVisuals.Open, out bool open) && open) + { + state = component.OpenState; + drawDepth = DrawDepth.SmallMobs; + } + + layer.SetState(state); + args.Sprite.DrawDepth = (int) drawDepth; + } +} diff --git a/Content.Client/Mech/Ui/Equipment/MechGrabberUi.cs b/Content.Client/Mech/Ui/Equipment/MechGrabberUi.cs new file mode 100644 index 0000000000..6cffba5163 --- /dev/null +++ b/Content.Client/Mech/Ui/Equipment/MechGrabberUi.cs @@ -0,0 +1,36 @@ +using Content.Client.UserInterface.Fragments; +using Content.Shared.Mech; +using Robust.Client.GameObjects; +using Robust.Client.UserInterface; + +namespace Content.Client.Mech.Ui.Equipment; + +public sealed class MechGrabberUi : UIFragment +{ + private MechGrabberUiFragment? _fragment; + + public override Control GetUIFragmentRoot() + { + return _fragment!; + } + + public override void Setup(BoundUserInterface userInterface, EntityUid? fragmentOwner) + { + if (fragmentOwner == null) + return; + + _fragment = new MechGrabberUiFragment(); + _fragment.OnEjectAction += e => + { + userInterface.SendMessage(new MechGrabberEjectMessage(fragmentOwner.Value, e)); + }; + } + + public override void UpdateState(BoundUserInterfaceState state) + { + if (state is not MechGrabberUiState grabberState) + return; + + _fragment?.UpdateContents(grabberState); + } +} diff --git a/Content.Client/Mech/Ui/Equipment/MechGrabberUiFragment.xaml b/Content.Client/Mech/Ui/Equipment/MechGrabberUiFragment.xaml new file mode 100644 index 0000000000..569dec28c3 --- /dev/null +++ b/Content.Client/Mech/Ui/Equipment/MechGrabberUiFragment.xaml @@ -0,0 +1,15 @@ + + + + + + + diff --git a/Content.Client/Mech/Ui/Equipment/MechGrabberUiFragment.xaml.cs b/Content.Client/Mech/Ui/Equipment/MechGrabberUiFragment.xaml.cs new file mode 100644 index 0000000000..8fc04d6460 --- /dev/null +++ b/Content.Client/Mech/Ui/Equipment/MechGrabberUiFragment.xaml.cs @@ -0,0 +1,35 @@ +using Content.Shared.Mech; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client.Mech.Ui.Equipment; + +[GenerateTypedNameReferences] +public sealed partial class MechGrabberUiFragment : BoxContainer +{ + [Dependency] private readonly IEntityManager _entity = default!; + + public event Action? OnEjectAction; + + public MechGrabberUiFragment() + { + RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); + } + + public void UpdateContents(MechGrabberUiState state) + { + SpaceLabel.Text = $"{state.Contents.Count}/{state.MaxContents}"; + for (var i = 0; i < state.Contents.Count; i++) + { + var ent = state.Contents[i]; + + if (!_entity.TryGetComponent(ent, out var meta)) + continue; + + ItemList.AddItem(meta.EntityName); + ItemList[i].OnSelected += _ => OnEjectAction?.Invoke(ent); + } + } +} diff --git a/Content.Client/Mech/Ui/MechBoundUserInterface.cs b/Content.Client/Mech/Ui/MechBoundUserInterface.cs new file mode 100644 index 0000000000..a6331554a5 --- /dev/null +++ b/Content.Client/Mech/Ui/MechBoundUserInterface.cs @@ -0,0 +1,84 @@ +using Content.Client.UserInterface.Fragments; +using Content.Shared.Mech; +using JetBrains.Annotations; +using Robust.Client.GameObjects; + +namespace Content.Client.Mech.Ui; + +[UsedImplicitly] +public sealed class MechBoundUserInterface : BoundUserInterface +{ + [Dependency] private readonly IEntityManager _ent = default!; + + private readonly EntityUid _mech; + + private MechMenu? _menu; + + public MechBoundUserInterface(ClientUserInterfaceComponent owner, Enum uiKey) : base(owner, uiKey) + { + IoCManager.InjectDependencies(this); + _mech = owner.Owner; + } + + protected override void Open() + { + base.Open(); + + _menu = new(_mech); + + _menu.OnClose += Close; + _menu.OpenCenteredLeft(); + + _menu.OnRemoveButtonPressed += uid => + { + SendMessage(new MechEquipmentRemoveMessage(uid)); + }; + } + + protected override void UpdateState(BoundUserInterfaceState state) + { + base.UpdateState(state); + + if (state is not MechBoundUiState msg) + return; + UpdateEquipmentControls(msg); + _menu?.UpdateMechStats(); + _menu?.UpdateEquipmentView(); + } + + public void UpdateEquipmentControls(MechBoundUiState state) + { + if (!_ent.TryGetComponent(_mech, out var mechComp)) + return; + + foreach (var ent in mechComp.EquipmentContainer.ContainedEntities) + { + var ui = GetEquipmentUi(ent); + if (ui == null) + continue; + foreach (var (attached, estate) in state.EquipmentStates) + { + if (ent == attached) + ui.UpdateState(estate); + } + } + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + if (!disposing) + return; + + _menu?.Close(); + } + + public UIFragment? GetEquipmentUi(EntityUid? uid) + { + var component = _ent.GetComponentOrNull(uid); + component?.Ui?.Setup(this, uid); + return component?.Ui; + } +} + diff --git a/Content.Client/Mech/Ui/MechEquipmentControl.xaml b/Content.Client/Mech/Ui/MechEquipmentControl.xaml new file mode 100644 index 0000000000..19263dd3c9 --- /dev/null +++ b/Content.Client/Mech/Ui/MechEquipmentControl.xaml @@ -0,0 +1,26 @@ + + + diff --git a/Content.Client/Mech/Ui/MechEquipmentControl.xaml.cs b/Content.Client/Mech/Ui/MechEquipmentControl.xaml.cs new file mode 100644 index 0000000000..1253890473 --- /dev/null +++ b/Content.Client/Mech/Ui/MechEquipmentControl.xaml.cs @@ -0,0 +1,28 @@ +using Robust.Client.AutoGenerated; +using Robust.Client.GameObjects; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client.Mech.Ui; + +[GenerateTypedNameReferences] +public sealed partial class MechEquipmentControl : Control +{ + public event Action? OnRemoveButtonPressed; + + public MechEquipmentControl(string itemName, SpriteComponent? sprite, Control? fragment) + { + RobustXamlLoader.Load(this); + EquipmentName.SetMessage(itemName); + EquipmentView.Sprite = sprite; + RemoveButton.TexturePath = "/Textures/Interface/Nano/cross.svg.png"; + + if (fragment != null) + { + Separator.Visible = true; + CustomControlContainer.AddChild(fragment); + } + + RemoveButton.OnPressed += _ => OnRemoveButtonPressed?.Invoke(); + } +} diff --git a/Content.Client/Mech/Ui/MechMenu.xaml b/Content.Client/Mech/Ui/MechMenu.xaml new file mode 100644 index 0000000000..2ed82eba15 --- /dev/null +++ b/Content.Client/Mech/Ui/MechMenu.xaml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Content.Client/Mech/Ui/MechMenu.xaml.cs b/Content.Client/Mech/Ui/MechMenu.xaml.cs new file mode 100644 index 0000000000..7c757c57f3 --- /dev/null +++ b/Content.Client/Mech/Ui/MechMenu.xaml.cs @@ -0,0 +1,72 @@ +using Content.Client.UserInterface.Controls; +using Content.Client.UserInterface.Fragments; +using Content.Shared.Mech.Components; +using Robust.Client.AutoGenerated; +using Robust.Client.GameObjects; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client.Mech.Ui; + +[GenerateTypedNameReferences] +public sealed partial class MechMenu : FancyWindow +{ + [Dependency] private readonly IEntityManager _ent = default!; + + private readonly EntityUid _mech; + + public event Action? OnRemoveButtonPressed; + + public MechMenu(EntityUid mech) + { + RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); + + _mech = mech; + + if (!_ent.TryGetComponent(mech, out var sprite)) + return; + + MechView.Sprite = sprite; + } + + public void UpdateMechStats() + { + if (!_ent.TryGetComponent(_mech, out var mechComp)) + return; + + var integrityPercent = mechComp.Integrity / mechComp.MaxIntegrity; + IntegrityDisplayBar.Value = integrityPercent.Float(); + IntegrityDisplay.Text = Loc.GetString("mech-integrity-display", ("amount", (integrityPercent*100).Int())); + + var energyPercent = mechComp.Energy / mechComp.MaxEnergy; + EnergyDisplayBar.Value = energyPercent.Float(); + EnergyDisplay.Text = Loc.GetString("mech-energy-display", ("amount", (energyPercent*100).Int())); + + SlotDisplay.Text = Loc.GetString("mech-slot-display", + ("amount", mechComp.MaxEquipmentAmount - mechComp.EquipmentContainer.ContainedEntities.Count)); + } + + public void UpdateEquipmentView() + { + if (!_ent.TryGetComponent(_mech, out var mechComp)) + return; + + EquipmentControlContainer.Children.Clear(); + foreach (var ent in mechComp.EquipmentContainer.ContainedEntities) + { + if (!_ent.TryGetComponent(ent, out var sprite) || + !_ent.TryGetComponent(ent, out var metaData)) + continue; + + var uicomp = _ent.GetComponentOrNull(ent); + var ui = uicomp?.Ui?.GetUIFragmentRoot(); + + var control = new MechEquipmentControl(metaData.EntityName, sprite, ui); + + control.OnRemoveButtonPressed += () => OnRemoveButtonPressed?.Invoke(ent); + + EquipmentControlContainer.AddChild(control); + } + } +} + diff --git a/Content.Client/UserInterface/Fragments/UIFragment.cs b/Content.Client/UserInterface/Fragments/UIFragment.cs index 5d09754826..afdb105783 100644 --- a/Content.Client/UserInterface/Fragments/UIFragment.cs +++ b/Content.Client/UserInterface/Fragments/UIFragment.cs @@ -18,7 +18,7 @@ public abstract class UIFragment { public abstract Control GetUIFragmentRoot(); - public abstract void Setup(BoundUserInterface userInterface); + public abstract void Setup(BoundUserInterface userInterface, EntityUid? fragmentOwner); public abstract void UpdateState(BoundUserInterfaceState state); diff --git a/Content.Server/Construction/Completions/BuildMech.cs b/Content.Server/Construction/Completions/BuildMech.cs new file mode 100644 index 0000000000..ff100538aa --- /dev/null +++ b/Content.Server/Construction/Completions/BuildMech.cs @@ -0,0 +1,71 @@ +using Content.Server.Mech.Components; +using Content.Server.Mech.Systems; +using Content.Server.Power.Components; +using Content.Shared.Construction; +using JetBrains.Annotations; +using Robust.Server.Containers; +using Robust.Shared.Containers; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Server.Construction.Completions; + +/// +/// Creates the mech entity while transferring all relevant parts inside of it, +/// for right now, the cell that was used in construction. +/// +[UsedImplicitly, DataDefinition] +public sealed class BuildMech : IGraphAction +{ + [DataField("mechPrototype", required: true, customTypeSerializer: typeof(PrototypeIdSerializer))] + public string MechPrototype = string.Empty; + + [DataField("container")] + public string Container = "battery-container"; + + public void PerformAction(EntityUid uid, EntityUid? userUid, IEntityManager entityManager) + { + if (!entityManager.TryGetComponent(uid, out ContainerManagerComponent? containerManager)) + { + Logger.Warning($"Mech construct entity {uid} did not have a container manager! Aborting build mech action."); + return; + } + + var containerSystem = entityManager.EntitySysManager.GetEntitySystem(); + var mechSys = entityManager.System(); + + if (!containerSystem.TryGetContainer(uid, Container, out var container, containerManager)) + { + Logger.Warning($"Mech construct entity {uid} did not have the specified '{Container}' container! Aborting build mech action."); + return; + } + + if (container.ContainedEntities.Count != 1) + { + Logger.Warning($"Mech construct entity {uid} did not have exactly one item in the specified '{Container}' container! Aborting build mech action."); + } + + var cell = container.ContainedEntities[0]; + + if (!entityManager.TryGetComponent(cell, out var batteryComponent)) + { + Logger.Warning($"Mech construct entity {uid} had an invalid entity in container \"{Container}\"! Aborting build mech action."); + return; + } + + container.Remove(cell); + + var transform = entityManager.GetComponent(uid); + var mech = entityManager.SpawnEntity(MechPrototype, transform.Coordinates); + + if (entityManager.TryGetComponent(mech, out var mechComp) && mechComp.BatterySlot.ContainedEntity == null) + { + mechSys.InsertBattery(mech, cell, mechComp, batteryComponent); + mechComp.BatterySlot.Insert(cell); + } + + // Delete the original entity. + entityManager.DeleteEntity(uid); + } +} + diff --git a/Content.Server/Mech/Components/MechAssemblyComponent.cs b/Content.Server/Mech/Components/MechAssemblyComponent.cs new file mode 100644 index 0000000000..2d99957a31 --- /dev/null +++ b/Content.Server/Mech/Components/MechAssemblyComponent.cs @@ -0,0 +1,50 @@ +using Content.Shared.Storage.Components; +using Content.Shared.Tag; +using Content.Shared.Tools; +using Robust.Shared.Containers; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary; + +namespace Content.Server.Mech.Components; + +/// +/// A component used to create a mech chassis +/// after the correct parts have been placed inside +/// of it. +/// +/// +/// The actual visualization of the parts being inserted is +/// done via +/// +[RegisterComponent] +public sealed class MechAssemblyComponent : Component +{ + /// + /// The parts needed to be placed within the assembly, + /// stored as a tag and a bool tracking whether or not + /// they're present. + /// + [DataField("requiredParts", required: true, customTypeSerializer: typeof(PrototypeIdDictionarySerializer))] + public Dictionary RequiredParts = new(); + + /// + /// The prototype spawned when the assembly is finished + /// + [DataField("finishedPrototype", required: true, customTypeSerializer: typeof(PrototypeIdSerializer))] + public string FinishedPrototype = default!; + + /// + /// The container that stores all of the parts when + /// they're being assembled. + /// + [ViewVariables] + public Container PartsContainer = default!; + + /// + /// The quality of tool needed to remove all the parts + /// from the parts container. + /// + [DataField("qualityNeeded", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string QualityNeeded = "Prying"; +} diff --git a/Content.Server/Mech/Components/MechComponent.cs b/Content.Server/Mech/Components/MechComponent.cs new file mode 100644 index 0000000000..8a9f1c7c2c --- /dev/null +++ b/Content.Server/Mech/Components/MechComponent.cs @@ -0,0 +1,118 @@ +using System.Threading; +using Content.Server.Atmos; +using Content.Shared.Mech.Components; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; + +namespace Content.Server.Mech.Components; + +/// +[RegisterComponent, NetworkedComponent] +[ComponentReference(typeof(SharedMechComponent))] +public sealed class MechComponent : SharedMechComponent +{ + /// + /// How long it takes to enter the mech. + /// + [DataField("entryDelay")] + public float EntryDelay = 3; + + /// + /// How long it takes to pull *another person* + /// outside of the mech. You can exit instantly yourself. + /// + [DataField("exitDelay")] + public float ExitDelay = 3; + + /// + /// How long it takes to pull out the battery. + /// + [DataField("batteryRemovalDelay")] + public float BatteryRemovalDelay = 2; + + public CancellationTokenSource? EntryTokenSource; + + /// + /// Whether or not the mech is airtight. + /// + /// + /// This needs to be redone + /// when mech internals are added + /// + [DataField("airtight"), ViewVariables(VVAccess.ReadWrite)] + public bool Airtight; + + /// + /// The equipment that the mech initially has when it spawns. + /// Good for things like nukie mechs that start with guns. + /// + [DataField("startingEquipment", customTypeSerializer: typeof(PrototypeIdListSerializer))] + public List StartingEquipment = new(); + + /// + /// The battery the mech initially has when it spawns + /// Good for admemes and nukie mechs. + /// + [DataField("startingBattery", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string? StartingBattery; + + //TODO: this doesn't support a tank implant for mechs or anything like that + [ViewVariables(VVAccess.ReadWrite)] + public GasMixture Air = new (GasMixVolume); + public const float GasMixVolume = 70f; +} + +/// +/// Event raised when a person successfully enters a mech +/// +public sealed class MechEntryFinishedEvent : EntityEventArgs +{ + public EntityUid User; + + public MechEntryFinishedEvent(EntityUid user) + { + User = user; + } +} + +/// +/// Event raised when a person fails to enter a mech +/// +public sealed class MechEntryCanclledEvent : EntityEventArgs +{ + +} + +/// +/// Event raised when a person successfully removes someone from a mech +/// +public sealed class MechExitFinishedEvent : EntityEventArgs +{ + +} + +/// +/// Event raised when a person fails to remove someone from a mech +/// +public sealed class MechExitCanclledEvent : EntityEventArgs +{ + +} + +/// +/// Event raised when the battery is successfully removed from the mech +/// +public sealed class MechRemoveBatteryFinishedEvent : EntityEventArgs +{ + +} + +/// +/// Event raised when the battery fails to be removed from the mech +/// +public sealed class MechRemoveBatteryCancelledEvent : EntityEventArgs +{ + +} diff --git a/Content.Server/Mech/Equipment/Components/MechGrabberComponent.cs b/Content.Server/Mech/Equipment/Components/MechGrabberComponent.cs new file mode 100644 index 0000000000..77881de7cb --- /dev/null +++ b/Content.Server/Mech/Equipment/Components/MechGrabberComponent.cs @@ -0,0 +1,74 @@ +using System.Threading; +using Robust.Shared.Audio; +using Robust.Shared.Containers; + +namespace Content.Server.Mech.Equipment.Components; + +/// +/// A piece of mech equipment that grabs entities and stores them +/// inside of a container so large objects can be moved. +/// +[RegisterComponent] +public sealed class MechGrabberComponent : Component +{ + /// + /// The change in energy after each grab. + /// + [DataField("grabEnergyDelta")] + public float GrabEnergyDelta = -30; + + /// + /// How long does it take to grab something? + /// + [DataField("grabDelay")] + public float GrabDelay = 2.5f; + + /// + /// The offset from the mech when an item is dropped. + /// This is here for things like lockers and vendors + /// + [DataField("depositOffset")] + public Vector2 DepositOffset = new(0, -1); + + /// + /// The maximum amount of items that can be fit in this grabber + /// + [DataField("maxContents")] + public int MaxContents = 10; + + /// + /// The sound played when a mech is grabbing something + /// + [DataField("grabSound")] + public SoundSpecifier GrabSound = new SoundPathSpecifier("/Audio/Mecha/sound_mecha_hydraulic.ogg"); + + public IPlayingAudioStream? AudioStream; + + [ViewVariables(VVAccess.ReadWrite)] + public Container ItemContainer = default!; + public CancellationTokenSource? Token; +} + +/// +/// Event raised on the user when the grab is complete. +/// +public sealed class MechGrabberGrabFinishedEvent : EntityEventArgs +{ + /// + /// The thing that was grabbed. + /// + public EntityUid Grabbed; + + public MechGrabberGrabFinishedEvent(EntityUid grabbed) + { + Grabbed = grabbed; + } +} + +/// +/// Event raised on the user when the grab fails +/// +public sealed class MechGrabberGrabCancelledEvent : EntityEventArgs +{ + +} diff --git a/Content.Server/Mech/Equipment/EntitySystems/MechGrabberSystem.cs b/Content.Server/Mech/Equipment/EntitySystems/MechGrabberSystem.cs new file mode 100644 index 0000000000..2cffe2c41f --- /dev/null +++ b/Content.Server/Mech/Equipment/EntitySystems/MechGrabberSystem.cs @@ -0,0 +1,167 @@ +using System.Linq; +using Content.Server.DoAfter; +using Content.Server.Interaction; +using Content.Server.Mech.Components; +using Content.Server.Mech.Equipment.Components; +using Content.Server.Mech.Systems; +using Content.Shared.Interaction; +using Content.Shared.Mech; +using Content.Shared.Mech.Equipment.Components; +using Content.Shared.Wall; +using Robust.Shared.Containers; +using Robust.Shared.Map; + +namespace Content.Server.Mech.Equipment.EntitySystems; + +/// +/// Handles and all related UI logic +/// +public sealed class MechGrabberSystem : EntitySystem +{ + [Dependency] private readonly SharedContainerSystem _container = default!; + [Dependency] private readonly MechSystem _mech = default!; + [Dependency] private readonly DoAfterSystem _doAfter = default!; + [Dependency] private readonly InteractionSystem _interaction = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + + /// + public override void Initialize() + { + SubscribeLocalEvent(OnGrabberMessage); + SubscribeLocalEvent(OnStartup); + SubscribeLocalEvent(OnUiStateReady); + SubscribeLocalEvent(OnEquipmentRemoved); + SubscribeLocalEvent(OnAttemptRemove); + + SubscribeLocalEvent(OnInteract); + SubscribeLocalEvent(OnGrabFinished); + SubscribeLocalEvent(OnGrabCancelled); + } + + private void OnGrabberMessage(EntityUid uid, MechGrabberComponent component, MechEquipmentUiMessageRelayEvent args) + { + if (args.Message is not MechGrabberEjectMessage msg) + return; + + if (!TryComp(uid, out var equipmentComponent) || + equipmentComponent.EquipmentOwner == null) + return; + var mech = equipmentComponent.EquipmentOwner.Value; + + var targetCoords = new EntityCoordinates(mech, component.DepositOffset); + if (!_interaction.InRangeUnobstructed(mech, targetCoords)) + return; + + if (!component.ItemContainer.Contains(msg.Item)) + return; + + RemoveItem(uid, mech, msg.Item, component); + } + + /// + /// Removes an item from the grabber's container + /// + /// The mech grabber + /// The mech it belongs to + /// The item being removed + /// + public void RemoveItem(EntityUid uid, EntityUid mech, EntityUid toRemove, MechGrabberComponent? component = null) + { + if (!Resolve(uid, ref component)) + return; + + component.ItemContainer.Remove(toRemove); + var mechxform = Transform(mech); + var xform = Transform(toRemove); + xform.AttachToGridOrMap(); + xform.WorldPosition = mechxform.WorldPosition + mechxform.WorldRotation.RotateVec(component.DepositOffset); + xform.WorldRotation = Angle.Zero; + _mech.UpdateUserInterface(mech); + } + + private void OnEquipmentRemoved(EntityUid uid, MechGrabberComponent component, ref MechEquipmentRemovedEvent args) + { + if (!TryComp(uid, out var equipmentComponent) || + equipmentComponent.EquipmentOwner == null) + return; + var mech = equipmentComponent.EquipmentOwner.Value; + + var allItems = new List(component.ItemContainer.ContainedEntities); + foreach (var item in allItems) + { + RemoveItem(uid, mech, item, component); + } + } + + private void OnAttemptRemove(EntityUid uid, MechGrabberComponent component, ref AttemptRemoveMechEquipmentEvent args) + { + args.Cancelled = component.ItemContainer.ContainedEntities.Any(); + } + + private void OnStartup(EntityUid uid, MechGrabberComponent component, ComponentStartup args) + { + component.ItemContainer = _container.EnsureContainer(uid, "item-container"); + } + + private void OnUiStateReady(EntityUid uid, MechGrabberComponent component, MechEquipmentUiStateReadyEvent args) + { + var state = new MechGrabberUiState + { + Contents = component.ItemContainer.ContainedEntities.ToList(), + MaxContents = component.MaxContents + }; + args.States.Add(uid, state); + } + + private void OnInteract(EntityUid uid, MechGrabberComponent component, InteractNoHandEvent args) + { + if (args.Handled || args.Target == null) + return; + + var xform = Transform(args.Target.Value); + if (xform.Anchored || HasComp(args.Target.Value)) + return; + + if (component.ItemContainer.ContainedEntities.Count >= component.MaxContents) + return; + + if (!TryComp(args.User, out var mech)) + return; + + if (mech.Energy + component.GrabEnergyDelta < 0) + return; + + if (component.Token != null) + return; + + args.Handled = true; + component.Token = new(); + component.AudioStream = _audio.PlayPvs(component.GrabSound, uid); + _doAfter.DoAfter(new DoAfterEventArgs(args.User, component.GrabDelay, component.Token.Token, args.Target, uid) + { + BreakOnTargetMove = true, + BreakOnUserMove = true, + UsedFinishedEvent = new MechGrabberGrabFinishedEvent(args.Target.Value), + UserCancelledEvent = new MechGrabberGrabCancelledEvent() + }); + } + + private void OnGrabFinished(EntityUid uid, MechGrabberComponent component, MechGrabberGrabFinishedEvent args) + { + component.Token = null; + + if (!TryComp(uid, out var equipmentComponent) || equipmentComponent.EquipmentOwner == null) + return; + if (!_mech.TryChangeEnergy(equipmentComponent.EquipmentOwner.Value, component.GrabEnergyDelta)) + return; + + component.ItemContainer.Insert(args.Grabbed); + _mech.UpdateUserInterface(equipmentComponent.EquipmentOwner.Value); + } + + private void OnGrabCancelled(EntityUid uid, MechGrabberComponent component, MechGrabberGrabCancelledEvent args) + { + component.AudioStream?.Stop(); + component.Token = null; + } +} diff --git a/Content.Server/Mech/Systems/MechAssemblySystem.cs b/Content.Server/Mech/Systems/MechAssemblySystem.cs new file mode 100644 index 0000000000..d237324102 --- /dev/null +++ b/Content.Server/Mech/Systems/MechAssemblySystem.cs @@ -0,0 +1,64 @@ +using Content.Server.Mech.Components; +using Content.Shared.Interaction; +using Content.Shared.Tag; +using Content.Shared.Tools.Components; +using Robust.Server.Containers; +using Robust.Shared.Containers; + +namespace Content.Server.Mech.Systems; + +/// +/// Handles and the insertion +/// and removal of parts from the assembly. +/// +public sealed class MechAssemblySystem : EntitySystem +{ + [Dependency] private readonly ContainerSystem _container = default!; + + /// + public override void Initialize() + { + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnInteractUsing); + } + + private void OnInit(EntityUid uid, MechAssemblyComponent component, ComponentInit args) + { + component.PartsContainer = _container.EnsureContainer(uid, "mech-assembly-container"); + } + + private void OnInteractUsing(EntityUid uid, MechAssemblyComponent component, InteractUsingEvent args) + { + if (TryComp(args.Used, out var toolComp) && toolComp.Qualities.Contains(component.QualityNeeded)) + { + foreach (var tag in component.RequiredParts.Keys) + { + component.RequiredParts[tag] = false; + } + _container.EmptyContainer(component.PartsContainer); + return; + } + + if (!TryComp(args.Used, out var tagComp)) + return; + + foreach (var (tag, val) in component.RequiredParts) + { + if (!val && tagComp.Tags.Contains(tag)) + { + component.RequiredParts[tag] = true; + component.PartsContainer.Insert(args.Used); + break; + } + } + + //check to see if we have all the parts + foreach (var val in component.RequiredParts.Values) + { + if (!val) + return; + } + Spawn(component.FinishedPrototype, Transform(uid).Coordinates); + EntityManager.DeleteEntity(uid); + } +} diff --git a/Content.Server/Mech/Systems/MechEquipmentSystem.cs b/Content.Server/Mech/Systems/MechEquipmentSystem.cs new file mode 100644 index 0000000000..a30b740544 --- /dev/null +++ b/Content.Server/Mech/Systems/MechEquipmentSystem.cs @@ -0,0 +1,73 @@ +using Content.Server.DoAfter; +using Content.Server.Mech.Components; +using Content.Server.Popups; +using Content.Shared.Interaction; +using Content.Shared.Mech.Equipment.Components; +using Robust.Shared.Player; + +namespace Content.Server.Mech.Systems; + +/// +/// Handles the insertion of mech equipment into mechs. +/// +public sealed class MechEquipmentSystem : EntitySystem +{ + [Dependency] private readonly MechSystem _mech = default!; + [Dependency] private readonly DoAfterSystem _doAfter = default!; + [Dependency] private readonly PopupSystem _popup = default!; + + /// + public override void Initialize() + { + SubscribeLocalEvent(OnUsed); + SubscribeLocalEvent(OnFinished); + SubscribeLocalEvent(OnCancelled); + } + + private void OnUsed(EntityUid uid, MechEquipmentComponent component, AfterInteractEvent args) + { + if (component.TokenSource != null) + return; + + if (args.Handled || !args.CanReach || args.Target == null) + return; + + var mech = args.Target.Value; + if (!TryComp(mech, out var mechComp)) + return; + + if (args.User == mechComp.PilotSlot.ContainedEntity) + return; + + if (mechComp.EquipmentContainer.ContainedEntities.Count >= mechComp.MaxEquipmentAmount) + return; + + if (mechComp.EquipmentWhitelist != null && !mechComp.EquipmentWhitelist.IsValid(uid)) + return; + + _popup.PopupEntity(Loc.GetString("mech-equipment-begin-install", ("item", uid)), mech, Filter.Pvs(mech)); + + component.TokenSource = new(); + _doAfter.DoAfter(new DoAfterEventArgs(args.User, component.InstallDuration, component.TokenSource.Token, mech, uid) + { + BreakOnStun = true, + BreakOnTargetMove = true, + BreakOnUserMove = true, + UsedFinishedEvent = new MechEquipmentInstallFinished(mech), + UsedCancelledEvent = new MechEquipmentInstallCancelled() + }); + } + + private void OnFinished(EntityUid uid, MechEquipmentComponent component, MechEquipmentInstallFinished args) + { + component.TokenSource = null; + _popup.PopupEntity(Loc.GetString("mech-equipment-finish-install", ("item", uid)), args.Mech, Filter.Pvs(args.Mech)); + + _mech.InsertEquipment(args.Mech, uid); + } + + private void OnCancelled(EntityUid uid, MechEquipmentComponent component, MechEquipmentInstallCancelled args) + { + component.TokenSource = null; + } +} diff --git a/Content.Server/Mech/Systems/MechSystem.cs b/Content.Server/Mech/Systems/MechSystem.cs new file mode 100644 index 0000000000..b122e05b90 --- /dev/null +++ b/Content.Server/Mech/Systems/MechSystem.cs @@ -0,0 +1,428 @@ +using System.Linq; +using System.Threading; +using Content.Server.Atmos.EntitySystems; +using Content.Server.DoAfter; +using Content.Server.Mech.Components; +using Content.Server.Power.Components; +using Content.Server.Wires; +using Content.Shared.Damage; +using Content.Shared.FixedPoint; +using Content.Shared.Interaction; +using Content.Shared.Mech; +using Content.Shared.Mech.Components; +using Content.Shared.Mech.EntitySystems; +using Content.Shared.Tools.Components; +using Content.Shared.Verbs; +using Robust.Server.Containers; +using Robust.Server.GameObjects; +using Robust.Shared.Map; + +namespace Content.Server.Mech.Systems; + +/// +public sealed class MechSystem : SharedMechSystem +{ + [Dependency] private readonly AtmosphereSystem _atmosphere = default!; + [Dependency] private readonly ContainerSystem _container = default!; + [Dependency] private readonly DamageableSystem _damageable = default!; + [Dependency] private readonly DoAfterSystem _doAfter = default!; + [Dependency] private readonly IMapManager _map = default!; + [Dependency] private readonly UserInterfaceSystem _ui = default!; + + private ISawmill _sawmill = default!; + + /// + public override void Initialize() + { + base.Initialize(); + + _sawmill = Logger.GetSawmill("mech"); + + SubscribeLocalEvent(OnInteractUsing); + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent>(OnAlternativeVerb); + SubscribeLocalEvent(OnOpenUi); + SubscribeLocalEvent(OnEntryFinished); + SubscribeLocalEvent(OnEntryExitCancelled); + SubscribeLocalEvent(OnExitFinished); + SubscribeLocalEvent(OnEntryExitCancelled); + SubscribeLocalEvent(OnRemoveBatteryFinished); + SubscribeLocalEvent(OnRemoveBatteryCancelled); + + SubscribeLocalEvent(OnDamageChanged); + SubscribeLocalEvent(OnRemoveEquipmentMessage); + + SubscribeLocalEvent(OnInhale); + SubscribeLocalEvent(OnExhale); + SubscribeLocalEvent(OnExpose); + + #region Equipment UI message relays + SubscribeLocalEvent(RecieveEquipmentUiMesssages); + #endregion + } + + private void OnInteractUsing(EntityUid uid, MechComponent component, InteractUsingEvent args) + { + if (TryComp(uid, out var wires) && !wires.IsPanelOpen) + return; + + if (component.BatterySlot.ContainedEntity == null && TryComp(args.Used, out var battery)) + { + InsertBattery(uid, args.Used, component, battery); + return; + } + + if (component.EntryTokenSource == null && + TryComp(args.Used, out var tool) && + tool.Qualities.Contains("Prying") && + component.BatterySlot.ContainedEntity != null) + { + component.EntryTokenSource = new(); + _doAfter.DoAfter(new DoAfterEventArgs(args.User, component.BatteryRemovalDelay, component.EntryTokenSource.Token, uid, args.Target) + { + BreakOnTargetMove = true, + BreakOnUserMove = true, + TargetFinishedEvent = new MechRemoveBatteryFinishedEvent(), + TargetCancelledEvent = new MechRemoveBatteryCancelledEvent() + }); + } + } + + private void OnRemoveBatteryFinished(EntityUid uid, MechComponent component, MechRemoveBatteryFinishedEvent args) + { + component.EntryTokenSource = null; + + RemoveBattery(uid, component); + } + + private void OnRemoveBatteryCancelled(EntityUid uid, MechComponent component, MechRemoveBatteryCancelledEvent args) + { + component.EntryTokenSource = null; + } + + private void OnMapInit(EntityUid uid, MechComponent component, MapInitEvent args) + { + var xform = Transform(uid); + foreach (var ent in component.StartingEquipment.Select(equipment => Spawn(equipment, xform.Coordinates))) + { + InsertEquipment(uid, ent, component); + } + + component.Integrity = component.MaxIntegrity; + component.Energy = component.MaxEnergy; + + if (component.StartingBattery != null) + { + var battery = Spawn(component.StartingBattery, Transform(uid).Coordinates); + InsertBattery(uid, battery, component); + } + + Dirty(component); + } + + private void OnRemoveEquipmentMessage(EntityUid uid, SharedMechComponent component, MechEquipmentRemoveMessage args) + { + if (!Exists(args.Equipment) || Deleted(args.Equipment)) + return; + + if (!component.EquipmentContainer.ContainedEntities.Contains(args.Equipment)) + return; + + RemoveEquipment(uid, args.Equipment, component); + } + + private void OnOpenUi(EntityUid uid, MechComponent component, MechOpenUiEvent args) + { + args.Handled = true; + ToggleMechUi(uid, component); + } + + private void OnAlternativeVerb(EntityUid uid, MechComponent component, GetVerbsEvent args) + { + if (!args.CanAccess || !args.CanInteract || component.Broken) + return; + + if (CanInsert(uid, args.User, component)) + { + var enterVerb = new AlternativeVerb + { + Text = Loc.GetString("mech-verb-enter"), + Act = () => + { + if (component.EntryTokenSource != null) + return; + component.EntryTokenSource = new CancellationTokenSource(); + _doAfter.DoAfter(new DoAfterEventArgs(args.User, component.EntryDelay, component.EntryTokenSource.Token, uid) + { + BreakOnUserMove = true, + BreakOnStun = true, + TargetFinishedEvent = new MechEntryFinishedEvent(args.User), + TargetCancelledEvent = new MechEntryCanclledEvent() + }); + } + }; + var openUiVerb = new AlternativeVerb //can't hijack someone else's mech + { + Act = () => ToggleMechUi(uid, component, args.User), + Text = Loc.GetString("mech-ui-open-verb") + }; + args.Verbs.Add(enterVerb); + args.Verbs.Add(openUiVerb); + } + else if (!IsEmpty(component)) + { + var ejectVerb = new AlternativeVerb + { + Text = Loc.GetString("mech-verb-exit"), + Priority = 1, // Promote to top to make ejecting the ALT-click action + Act = () => + { + if (component.EntryTokenSource != null) + return; + if (args.User == component.PilotSlot.ContainedEntity) + { + TryEject(uid, component); + return; + } + + component.EntryTokenSource = new CancellationTokenSource(); + _doAfter.DoAfter(new DoAfterEventArgs(args.User, component.ExitDelay, component.EntryTokenSource.Token, uid) + { + BreakOnUserMove = true, + BreakOnTargetMove = true, + BreakOnStun = true, + TargetFinishedEvent = new MechExitFinishedEvent(), + TargetCancelledEvent = new MechExitCanclledEvent() + }); + } + }; + args.Verbs.Add(ejectVerb); + } + } + + private void OnEntryFinished(EntityUid uid, MechComponent component, MechEntryFinishedEvent args) + { + component.EntryTokenSource = null; + TryInsert(uid, args.User, component); + } + + private void OnExitFinished(EntityUid uid, MechComponent component, MechExitFinishedEvent args) + { + component.EntryTokenSource = null; + TryEject(uid, component); + } + + private void OnEntryExitCancelled(EntityUid uid, MechComponent component, EntityEventArgs args) + { + component.EntryTokenSource = null; + } + + private void OnDamageChanged(EntityUid uid, SharedMechComponent component, DamageChangedEvent args) + { + var integrity = component.MaxIntegrity - args.Damageable.TotalDamage; + SetIntegrity(uid, integrity, component); + + if (args.DamageIncreased && + args.DamageDelta != null && + component.PilotSlot.ContainedEntity != null) + { + var damage = args.DamageDelta * component.MechToPilotDamageMultiplier; + _damageable.TryChangeDamage(component.PilotSlot.ContainedEntity, damage); + } + } + + private void ToggleMechUi(EntityUid uid, MechComponent? component = null, EntityUid? user = null) + { + if (!Resolve(uid, ref component)) + return; + user ??= component.PilotSlot.ContainedEntity; + if (user == null) + return; + + if (!TryComp(user, out var actor)) + return; + + _ui.TryToggleUi(uid, MechUiKey.Key, actor.PlayerSession); + UpdateUserInterface(uid, component); + } + + private void RecieveEquipmentUiMesssages(EntityUid uid, MechComponent component, T args) where T : MechEquipmentUiMessage + { + var ev = new MechEquipmentUiMessageRelayEvent(args); + var allEquipment = new List(component.EquipmentContainer.ContainedEntities); + foreach (var equipment in allEquipment) + { + if (args.Equipment == equipment) + RaiseLocalEvent(equipment, ev); + } + } + + public override void UpdateUserInterface(EntityUid uid, SharedMechComponent? component = null) + { + if (!Resolve(uid, ref component)) + return; + + base.UpdateUserInterface(uid, component); + + var ev = new MechEquipmentUiStateReadyEvent(); + foreach (var ent in component.EquipmentContainer.ContainedEntities) + { + RaiseLocalEvent(ent, ev); + } + + var state = new MechBoundUiState + { + EquipmentStates = ev.States + }; + var ui = _ui.GetUi(uid, MechUiKey.Key); + _ui.SetUiState(ui, state); + } + + public override bool TryInsert(EntityUid uid, EntityUid? toInsert, SharedMechComponent? component = null) + { + if (!Resolve(uid, ref component)) + return false; + + if (!base.TryInsert(uid, toInsert, component)) + return false; + + var mech = (MechComponent) component; + + if (mech.Airtight) + { + var coordinates = Transform(uid).MapPosition; + if (_map.TryFindGridAt(coordinates, out var grid)) + { + var tile = grid.GetTileRef(coordinates); + + if (_atmosphere.GetTileMixture(tile.GridUid, null, tile.GridIndices, true) is {} environment) + { + _atmosphere.Merge(mech.Air, environment.RemoveVolume(MechComponent.GasMixVolume)); + } + } + } + return true; + } + + public override bool TryEject(EntityUid uid, SharedMechComponent? component = null) + { + if (!Resolve(uid, ref component)) + return false; + + if (!base.TryEject(uid, component)) + return false; + + var mech = (MechComponent) component; + + if (mech.Airtight) + { + var coordinates = Transform(uid).MapPosition; + if (_map.TryFindGridAt(coordinates, out var grid)) + { + var tile = grid.GetTileRef(coordinates); + + if (_atmosphere.GetTileMixture(tile.GridUid, null, tile.GridIndices, true) is {} environment) + { + _atmosphere.Merge(environment, mech.Air); + mech.Air.Clear(); + } + } + } + + return true; + } + + public override void BreakMech(EntityUid uid, SharedMechComponent? component = null) + { + base.BreakMech(uid, component); + + _ui.TryCloseAll(uid, MechUiKey.Key); + } + + public override bool TryChangeEnergy(EntityUid uid, FixedPoint2 delta, SharedMechComponent? component = null) + { + if (!Resolve(uid, ref component)) + return false; + + if (!base.TryChangeEnergy(uid, delta, component)) + return false; + + var battery = component.BatterySlot.ContainedEntity; + if (battery == null) + return false; + + if (!TryComp(battery, out var batteryComp)) + return false; + + batteryComp.CurrentCharge = batteryComp.CurrentCharge + delta.Float(); + if (batteryComp.CurrentCharge != component.Energy) //if there's a discrepency, we have to resync them + { + _sawmill.Debug($"Battery charge was not equal to mech charge. Battery {batteryComp.CurrentCharge}. Mech {component.Energy}"); + component.Energy = batteryComp.CurrentCharge; + Dirty(component); + } + return true; + } + + public void InsertBattery(EntityUid uid, EntityUid toInsert, MechComponent? component = null, BatteryComponent? battery = null) + { + if (!Resolve(uid, ref component, false)) + return; + + if (!Resolve(toInsert, ref battery, false)) + return; + + component.BatterySlot.Insert(toInsert); + component.Energy = battery.CurrentCharge; + component.MaxEnergy = battery.MaxCharge; + + Dirty(component); + UpdateUserInterface(uid, component); + } + + public void RemoveBattery(EntityUid uid, MechComponent? component = null) + { + if (!Resolve(uid, ref component)) + return; + + _container.EmptyContainer(component.BatterySlot); + component.Energy = 0; + component.MaxEnergy = 0; + + Dirty(component); + UpdateUserInterface(uid, component); + } + + #region Atmos Handling + private void OnInhale(EntityUid uid, MechPilotComponent component, InhaleLocationEvent args) + { + if (!TryComp(component.Mech, out var mech)) + return; + + if (mech.Airtight) + args.Gas = mech.Air; + } + + private void OnExhale(EntityUid uid, MechPilotComponent component, ExhaleLocationEvent args) + { + if (!TryComp(component.Mech, out var mech)) + return; + + if (mech.Airtight) + args.Gas = mech.Air; + } + + private void OnExpose(EntityUid uid, MechPilotComponent component, ref AtmosExposedGetAirEvent args) + { + if (args.Handled) + return; + + if (!TryComp(component.Mech, out var mech)) + return; + + args.Gas = mech.Airtight ? mech.Air : _atmosphere.GetContainingMixture(component.Mech); + + args.Handled = true; + } + #endregion +} diff --git a/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs b/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs index 65244663cb..92b2e17a57 100644 --- a/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs +++ b/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs @@ -59,9 +59,9 @@ public sealed partial class RevenantSystem private void OnInteract(EntityUid uid, RevenantComponent component, InteractNoHandEvent args) { - var target = args.Target; - if (target == args.User) + if (args.Target == args.User || args.Target == null) return; + var target = args.Target.Value; if (HasComp(target)) { @@ -72,9 +72,6 @@ public sealed partial class RevenantSystem if (!HasComp(target) || !HasComp(target) || HasComp(target)) return; - if (!_interact.InRangeUnobstructed(uid, target)) - return; - args.Handled = true; if (!TryComp(target, out var essence) || !essence.SearchComplete) { diff --git a/Content.Shared/ActionBlocker/ActionBlockerSystem.cs b/Content.Shared/ActionBlocker/ActionBlockerSystem.cs index de6eb0e5b2..352135be22 100644 --- a/Content.Shared/ActionBlocker/ActionBlockerSystem.cs +++ b/Content.Shared/ActionBlocker/ActionBlockerSystem.cs @@ -4,7 +4,6 @@ using Content.Shared.Emoting; using Content.Shared.Interaction; using Content.Shared.Interaction.Events; using Content.Shared.Item; -using Content.Shared.Movement; using Content.Shared.Movement.Components; using Content.Shared.Movement.Events; using Content.Shared.Speech; @@ -148,7 +147,11 @@ namespace Content.Shared.ActionBlocker public bool CanAttack(EntityUid uid, EntityUid? target = null) { if (_container.IsEntityInContainer(uid)) - return false; + { + var containerEv = new CanAttackFromContainerEvent(uid, target); + RaiseLocalEvent(uid, containerEv); + return containerEv.CanAttack; + } var ev = new AttackAttemptEvent(uid, target); RaiseLocalEvent(uid, ev); diff --git a/Content.Shared/Interaction/Components/InteractionRelayComponent.cs b/Content.Shared/Interaction/Components/InteractionRelayComponent.cs new file mode 100644 index 0000000000..bd8bdf3b88 --- /dev/null +++ b/Content.Shared/Interaction/Components/InteractionRelayComponent.cs @@ -0,0 +1,34 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Serialization; + +namespace Content.Shared.Interaction.Components; + +/// +/// Relays an entities interactions to another entity. +/// This doesn't raise the same events, but just relays +/// the clicks of the mouse. +/// +[RegisterComponent, NetworkedComponent] +[Access(typeof(SharedInteractionSystem))] +public sealed class InteractionRelayComponent : Component +{ + /// + /// The entity the interactions are being relayed to. + /// + [ViewVariables] + public EntityUid? RelayEntity; +} + +/// +/// Contains network state for +/// +[Serializable, NetSerializable] +public sealed class InteractionRelayComponentState : ComponentState +{ + public EntityUid? RelayEntity; + + public InteractionRelayComponentState(EntityUid? relayEntity) + { + RelayEntity = relayEntity; + } +} diff --git a/Content.Shared/Interaction/Events/AttackAttemptEvent.cs b/Content.Shared/Interaction/Events/AttackAttemptEvent.cs index 014d66d58a..8fd2f75d89 100644 --- a/Content.Shared/Interaction/Events/AttackAttemptEvent.cs +++ b/Content.Shared/Interaction/Events/AttackAttemptEvent.cs @@ -18,4 +18,20 @@ namespace Content.Shared.Interaction.Events Target = target; } } + + /// + /// Raised directed at an entity to check if they can attack while inside of a container. + /// + public sealed class CanAttackFromContainerEvent : EntityEventArgs + { + public EntityUid Uid; + public EntityUid? Target; + public bool CanAttack = false; + + public CanAttackFromContainerEvent(EntityUid uid, EntityUid? target = null) + { + Uid = uid; + Target = target; + } + } } diff --git a/Content.Shared/Interaction/InteractHand.cs b/Content.Shared/Interaction/InteractHand.cs index 00a16e2398..32e250b0f1 100644 --- a/Content.Shared/Interaction/InteractHand.cs +++ b/Content.Shared/Interaction/InteractHand.cs @@ -1,4 +1,5 @@ using JetBrains.Annotations; +using Robust.Shared.Map; namespace Content.Shared.Interaction { @@ -37,44 +38,57 @@ namespace Content.Shared.Interaction } } - public sealed class InteractNoHandEvent : HandledEntityEventArgs, ITargetedInteractEventArgs + /// + /// Low-level interaction event used for entities without hands. + /// + /// + /// SHIT IS CURSED. + /// + //TODO: KILLLLLLL + public sealed class InteractNoHandEvent : HandledEntityEventArgs { /// /// Entity that triggered the interaction. /// - public EntityUid User { get; } + public EntityUid User; /// /// Entity that was interacted on. /// - public EntityUid Target { get; } + public EntityUid? Target; - public InteractNoHandEvent(EntityUid user, EntityUid target) + public EntityCoordinates ClickLocation; + + public InteractNoHandEvent(EntityUid user, EntityUid? target, EntityCoordinates clickLocation) { User = user; Target = target; + ClickLocation = clickLocation; } } /// /// Reverse of the InteractNoHandEvent - raised on what was interacted on, rather than the other way around. /// - public sealed class InteractedNoHandEvent : HandledEntityEventArgs, ITargetedInteractEventArgs + public sealed class InteractedNoHandEvent : HandledEntityEventArgs { /// /// Entity that was interacted on /// - public EntityUid Target { get; } + public EntityUid Target; /// /// Entity that triggered this interaction /// - public EntityUid User { get; } + public EntityUid User; - public InteractedNoHandEvent(EntityUid target, EntityUid user) + public EntityCoordinates ClickLocation; + + public InteractedNoHandEvent(EntityUid target, EntityUid user, EntityCoordinates clickLocation) { Target = target; User = user; + ClickLocation = clickLocation; } } } diff --git a/Content.Shared/Interaction/SharedInteractionSystem.Relay.cs b/Content.Shared/Interaction/SharedInteractionSystem.Relay.cs new file mode 100644 index 0000000000..b8cf4c7b2f --- /dev/null +++ b/Content.Shared/Interaction/SharedInteractionSystem.Relay.cs @@ -0,0 +1,35 @@ +using Content.Shared.Interaction.Components; +using Robust.Shared.GameStates; + +namespace Content.Shared.Interaction; + +public abstract partial class SharedInteractionSystem +{ + public void InitializeRelay() + { + SubscribeLocalEvent(OnGetState); + SubscribeLocalEvent(OnHandleState); + } + + private void OnGetState(EntityUid uid, InteractionRelayComponent component, ref ComponentGetState args) + { + args.State = new InteractionRelayComponentState(component.RelayEntity); + } + + private void OnHandleState(EntityUid uid, InteractionRelayComponent component, ref ComponentHandleState args) + { + if (args.Current is not InteractionRelayComponentState state) + return; + + component.RelayEntity = state.RelayEntity; + } + + public void SetRelay(EntityUid uid, EntityUid? relayEntity, InteractionRelayComponent? component = null) + { + if (!Resolve(uid, ref component)) + return; + + component.RelayEntity = relayEntity; + Dirty(component); + } +} diff --git a/Content.Shared/Interaction/SharedInteractionSystem.cs b/Content.Shared/Interaction/SharedInteractionSystem.cs index 568fd6af47..764caaad53 100644 --- a/Content.Shared/Interaction/SharedInteractionSystem.cs +++ b/Content.Shared/Interaction/SharedInteractionSystem.cs @@ -40,7 +40,7 @@ namespace Content.Shared.Interaction /// Governs interactions during clicking on entities /// [UsedImplicitly] - public abstract class SharedInteractionSystem : EntitySystem + public abstract partial class SharedInteractionSystem : EntitySystem { [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IMapManager _mapManager = default!; @@ -81,6 +81,8 @@ namespace Content.Shared.Interaction .Bind(ContentKeyFunctions.TryPullObject, new PointerInputCmdHandler(HandleTryPullObject)) .Register(); + + InitializeRelay(); } public override void Shutdown() @@ -224,6 +226,11 @@ namespace Content.Shared.Interaction bool checkAccess = true, bool checkCanUse = true) { + if (TryComp(user, out var relay) && relay.RelayEntity is not null) + { + UserInteraction(relay.RelayEntity.Value, coordinates, target, altInteract, checkCanInteract, checkAccess, checkCanUse); + } + if (target != null && Deleted(target.Value)) return; @@ -255,25 +262,25 @@ namespace Content.Shared.Interaction && !CanAccessViaStorage(user, target.Value)) return; + var inRangeUnobstructed = target == null + ? !checkAccess || InRangeUnobstructed(user, coordinates) + : !checkAccess || InRangeUnobstructed(user, target.Value); // permits interactions with wall mounted entities + // Does the user have hands? if (!TryComp(user, out SharedHandsComponent? hands) || hands.ActiveHand == null) { + var ev = new InteractNoHandEvent(user, target, coordinates); + RaiseLocalEvent(user, ev); + if (target != null) { - var ev = new InteractNoHandEvent(user, target.Value); - RaiseLocalEvent(user, ev); - - var interactedEv = new InteractedNoHandEvent(target.Value, user); + var interactedEv = new InteractedNoHandEvent(target.Value, user, coordinates); RaiseLocalEvent(target.Value, interactedEv); DoContactInteraction(user, target.Value, ev); } return; } - var inRangeUnobstructed = target == null - ? !checkAccess || InRangeUnobstructed(user, coordinates) - : !checkAccess || InRangeUnobstructed(user, target.Value); // permits interactions with wall mounted entities - // empty-hand interactions if (hands.ActiveHandEntity is not { } held) { diff --git a/Content.Shared/Mech/Components/MechPilotComponent.cs b/Content.Shared/Mech/Components/MechPilotComponent.cs new file mode 100644 index 0000000000..6095b53f5f --- /dev/null +++ b/Content.Shared/Mech/Components/MechPilotComponent.cs @@ -0,0 +1,26 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Serialization; + +namespace Content.Shared.Mech.Components; + +/// +/// Attached to entities piloting a +/// +/// +/// Get in the robot, Shinji +/// +[RegisterComponent, NetworkedComponent] +public sealed class MechPilotComponent : Component +{ + /// + /// The mech being piloted + /// + [ViewVariables(VVAccess.ReadWrite)] + public EntityUid Mech; +} + +[Serializable, NetSerializable] +public sealed class MechPilotComponentState : ComponentState +{ + public EntityUid Mech; +} diff --git a/Content.Shared/Mech/Components/SharedMechComponent.cs b/Content.Shared/Mech/Components/SharedMechComponent.cs new file mode 100644 index 0000000000..09196a1ff3 --- /dev/null +++ b/Content.Shared/Mech/Components/SharedMechComponent.cs @@ -0,0 +1,132 @@ +using Content.Shared.Actions.ActionTypes; +using Content.Shared.FixedPoint; +using Content.Shared.Whitelist; +using Robust.Shared.Containers; +using Robust.Shared.Serialization; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Shared.Mech.Components; + +/// +/// A large, pilotable machine that has equipment that is +/// powered via an internal battery. +/// +public abstract class SharedMechComponent : Component +{ + /// + /// How much "health" the mech has left. + /// + [ViewVariables(VVAccess.ReadWrite)] + public FixedPoint2 Integrity; + + /// + /// The maximum amount of damage the mech can take. + /// + [DataField("maxIntegrity")] + public FixedPoint2 MaxIntegrity = 250; + + /// + /// How much energy the mech has. + /// Derived from the currently inserted battery. + /// + [ViewVariables(VVAccess.ReadWrite)] + public FixedPoint2 Energy = 0; + + /// + /// The maximum amount of energy the mech can have. + /// Derived from the currently inserted battery. + /// + [DataField("maxEnergy")] + public FixedPoint2 MaxEnergy = 0; + + /// + /// The slot the battery is stored in. + /// + [ViewVariables] + public ContainerSlot BatterySlot = default!; + + [ViewVariables] + public readonly string BatterySlotId = "mech-battery-slot"; + + /// + /// A multiplier used to calculate how much of the damage done to a mech + /// is transfered to the pilot + /// + [DataField("mechToPilotDamageMultiplier")] + public float MechToPilotDamageMultiplier; + + /// + /// Whether the mech has been destroyed and is no longer pilotable. + /// + [ViewVariables(VVAccess.ReadWrite)] + public bool Broken = false; + + /// + /// The slot the pilot is stored in. + /// + [ViewVariables(VVAccess.ReadWrite)] + public ContainerSlot PilotSlot = default!; + + [ViewVariables] + public readonly string PilotSlotId = "mech-pilot-slot"; + + /// + /// The current selected equipment of the mech. + /// If null, the mech is using just its fists. + /// + [ViewVariables] + public EntityUid? CurrentSelectedEquipment; + + /// + /// The maximum amount of equipment items that can be installed in the mech + /// + [DataField("maxEquipmentAmount")] + public int MaxEquipmentAmount = 3; + + /// + /// A whitelist for inserting equipment items. + /// + [DataField("equipmentWhitelist")] + public EntityWhitelist? EquipmentWhitelist; + + /// + /// A container for storing the equipment entities. + /// + [ViewVariables(VVAccess.ReadWrite)] + public Container EquipmentContainer = default!; + + [ViewVariables] + public readonly string EquipmentContainerId = "mech-equipment-container"; + + #region Action Prototypes + [DataField("mechCycleAction", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string MechCycleAction = "MechCycleEquipment"; + [DataField("mechUiAction", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string MechUiAction = "MechOpenUI"; + [DataField("mechEjectAction", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string MechEjectAction = "MechEject"; + #endregion + + #region Visualizer States + [DataField("baseState")] + public string? BaseState; + [DataField("openState")] + public string? OpenState; + [DataField("brokenState")] + public string? BrokenState; + #endregion +} + +/// +/// Contains network state for . +/// +[Serializable, NetSerializable] +public sealed class MechComponentState : ComponentState +{ + public FixedPoint2 Integrity; + public FixedPoint2 MaxIntegrity; + public FixedPoint2 Energy; + public FixedPoint2 MaxEnergy; + public EntityUid? CurrentSelectedEquipment; + public bool Broken; +} diff --git a/Content.Shared/Mech/EntitySystems/SharedMechSystem.cs b/Content.Shared/Mech/EntitySystems/SharedMechSystem.cs new file mode 100644 index 0000000000..0420e15b18 --- /dev/null +++ b/Content.Shared/Mech/EntitySystems/SharedMechSystem.cs @@ -0,0 +1,463 @@ +using System.Linq; +using Content.Shared.Access.Components; +using Content.Shared.Access.Systems; +using Content.Shared.ActionBlocker; +using Content.Shared.Actions; +using Content.Shared.Actions.ActionTypes; +using Content.Shared.Body.Components; +using Content.Shared.Destructible; +using Content.Shared.FixedPoint; +using Content.Shared.Interaction; +using Content.Shared.Interaction.Components; +using Content.Shared.Interaction.Events; +using Content.Shared.Mech.Components; +using Content.Shared.Mech.Equipment.Components; +using Content.Shared.Movement.Components; +using Content.Shared.Movement.Systems; +using Content.Shared.Popups; +using Content.Shared.Weapons.Melee; +using Robust.Shared.Containers; +using Robust.Shared.GameStates; +using Robust.Shared.Player; +using Robust.Shared.Prototypes; +using Robust.Shared.Timing; + +namespace Content.Shared.Mech.EntitySystems; + +/// +/// Handles all of the interactions, UI handling, and items shennanigans for +/// +public abstract class SharedMechSystem : EntitySystem +{ + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly IPrototypeManager _prototype = default!; + [Dependency] private readonly ActionBlockerSystem _actionBlocker = default!; + [Dependency] private readonly AccessReaderSystem _access = default!; + [Dependency] private readonly SharedActionsSystem _actions = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly SharedContainerSystem _container = default!; + [Dependency] private readonly SharedInteractionSystem _interaction = default!; + [Dependency] private readonly SharedMoverController _mover = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + + /// + public override void Initialize() + { + SubscribeLocalEvent(OnGetState); + SubscribeLocalEvent(OnHandleState); + SubscribeLocalEvent(OnPilotGetState); + SubscribeLocalEvent(OnPilotHandleState); + + SubscribeLocalEvent(OnToggleEquipmentAction); + SubscribeLocalEvent(OnEjectPilotEvent); + SubscribeLocalEvent(RelayInteractionEvent); + SubscribeLocalEvent(OnStartup); + SubscribeLocalEvent(OnDestruction); + SubscribeLocalEvent(OnGetAdditionalAccess); + + SubscribeLocalEvent(OnGetMeleeWeapon); + SubscribeLocalEvent(OnCanAttackFromContainer); + } + + #region State Handling + private void OnGetState(EntityUid uid, SharedMechComponent component, ref ComponentGetState args) + { + args.State = new MechComponentState + { + Integrity = component.Integrity, + MaxIntegrity = component.MaxIntegrity, + Energy = component.Energy, + MaxEnergy = component.MaxEnergy, + CurrentSelectedEquipment = component.CurrentSelectedEquipment, + Broken = component.Broken + }; + } + + private void OnHandleState(EntityUid uid, SharedMechComponent component, ref ComponentHandleState args) + { + if (args.Current is not MechComponentState state) + return; + + component.Integrity = state.Integrity; + component.MaxIntegrity = state.MaxIntegrity; + component.Energy = state.Energy; + component.MaxEnergy = state.MaxEnergy; + component.CurrentSelectedEquipment = state.CurrentSelectedEquipment; + component.Broken = state.Broken; + } + + private void OnPilotGetState(EntityUid uid, MechPilotComponent component, ref ComponentGetState args) + { + args.State = new MechPilotComponentState + { + Mech = component.Mech + }; + } + + private void OnPilotHandleState(EntityUid uid, MechPilotComponent component, ref ComponentHandleState args) + { + if (args.Current is not MechPilotComponentState state) + return; + + component.Mech = state.Mech; + } + #endregion + + private void OnToggleEquipmentAction(EntityUid uid, SharedMechComponent component, MechToggleEquipmentEvent args) + { + if (args.Handled) + return; + args.Handled = true; + CycleEquipment(uid); + } + + private void OnEjectPilotEvent(EntityUid uid, SharedMechComponent component, MechEjectPilotEvent args) + { + if (args.Handled) + return; + args.Handled = true; + TryEject(uid, component); + } + + private void RelayInteractionEvent(EntityUid uid, SharedMechComponent component, InteractNoHandEvent args) + { + var pilot = component.PilotSlot.ContainedEntity; + if (pilot == null) + return; + + if (!_timing.IsFirstTimePredicted) + return; + + if (component.CurrentSelectedEquipment != null) + { + RaiseLocalEvent(component.CurrentSelectedEquipment.Value, args); + } + } + + private void OnStartup(EntityUid uid, SharedMechComponent component, ComponentStartup args) + { + component.PilotSlot = _container.EnsureContainer(uid, component.PilotSlotId); + component.EquipmentContainer = _container.EnsureContainer(uid, component.EquipmentContainerId); + component.BatterySlot = _container.EnsureContainer(uid, component.BatterySlotId); + UpdateAppearance(uid, component); + } + + private void OnDestruction(EntityUid uid, SharedMechComponent component, DestructionEventArgs args) + { + BreakMech(uid, component); + } + + private void OnGetAdditionalAccess(EntityUid uid, SharedMechComponent component, ref GetAdditionalAccessEvent args) + { + var pilot = component.PilotSlot.ContainedEntity; + if (pilot == null) + return; + + args.Entities.Add(pilot.Value); + _access.FindAccessItemsInventory(pilot.Value, out var items); + args.Entities = args.Entities.Union(items).ToHashSet(); + } + + private void SetupUser(EntityUid mech, EntityUid pilot, SharedMechComponent? component = null) + { + if (!Resolve(mech, ref component)) + return; + + var rider = EnsureComp(pilot); + var relay = EnsureComp(pilot); + var irelay = EnsureComp(pilot); + + _mover.SetRelay(pilot, mech, relay); + _interaction.SetRelay(pilot, mech, irelay); + rider.Mech = mech; + Dirty(rider); + + _actions.AddAction(pilot, new InstantAction(_prototype.Index(component.MechCycleAction)), mech); + _actions.AddAction(pilot, new InstantAction(_prototype.Index(component.MechUiAction)), mech); + _actions.AddAction(pilot, new InstantAction(_prototype.Index(component.MechEjectAction)), mech); + } + + private void RemoveUser(EntityUid mech, EntityUid pilot) + { + if (!RemComp(pilot)) + return; + RemComp(pilot); + RemComp(pilot); + + _actions.RemoveProvidedActions(pilot, mech); + } + + /// + /// Destroys the mech, removing the user and ejecting all installed equipment. + /// + /// + /// + public virtual void BreakMech(EntityUid uid, SharedMechComponent? component = null) + { + if (!Resolve(uid, ref component)) + return; + + TryEject(uid, component); + var equipment = new List(component.EquipmentContainer.ContainedEntities); + foreach (var ent in equipment) + { + RemoveEquipment(uid, ent, component, forced: true); + } + + component.Broken = true; + UpdateAppearance(uid, component); + } + + /// + /// Cycles through the currently selected equipment. + /// + /// + /// + public void CycleEquipment(EntityUid uid, SharedMechComponent? component = null) + { + if (!Resolve(uid, ref component)) + return; + + var allEquipment = component.EquipmentContainer.ContainedEntities.ToList(); + + var equipmentIndex = -1; + if (component.CurrentSelectedEquipment != null) + { + bool StartIndex(EntityUid u) => u == component.CurrentSelectedEquipment; + equipmentIndex = allEquipment.FindIndex(StartIndex); + } + + equipmentIndex++; + component.CurrentSelectedEquipment = equipmentIndex >= allEquipment.Count + ? null + : allEquipment[equipmentIndex]; + + var popupString = component.CurrentSelectedEquipment != null + ? Loc.GetString("mech-equipment-select-popup", ("item", component.CurrentSelectedEquipment)) + : Loc.GetString("mech-equipment-select-none-popup"); + + if (_timing.IsFirstTimePredicted) + _popup.PopupEntity(popupString, uid, Filter.Pvs(uid)); + Dirty(component); + } + + /// + /// Inserts an equipment item into the mech. + /// + /// + /// + /// + /// + public void InsertEquipment(EntityUid uid, EntityUid toInsert, SharedMechComponent? component = null, MechEquipmentComponent? equipmentComponent = null) + { + if (!Resolve(uid, ref component)) + return; + + if (!Resolve(toInsert, ref equipmentComponent)) + return; + + if (component.EquipmentContainer.ContainedEntities.Count >= component.MaxEquipmentAmount) + return; + + if (component.EquipmentWhitelist != null && !component.EquipmentWhitelist.IsValid(uid)) + return; + + equipmentComponent.EquipmentOwner = uid; + component.EquipmentContainer.Insert(toInsert, EntityManager); + var ev = new MechEquipmentInsertedEvent(uid); + RaiseLocalEvent(toInsert, ref ev); + UpdateUserInterface(uid, component); + } + + /// + /// Removes an equipment item from a mech. + /// + /// + /// + /// + /// + /// Whether or not the removal can be cancelled + public void RemoveEquipment(EntityUid uid, EntityUid toRemove, SharedMechComponent? component = null, MechEquipmentComponent? equipmentComponent = null, bool forced = false) + { + if (!Resolve(uid, ref component)) + return; + + if (!Resolve(toRemove, ref equipmentComponent)) + return; + + if (!forced) + { + var attemptev = new AttemptRemoveMechEquipmentEvent(); + RaiseLocalEvent(toRemove, ref attemptev); + if (attemptev.Cancelled) + return; + } + + equipmentComponent.EquipmentOwner = null; + component.EquipmentContainer.Remove(toRemove, EntityManager); + var ev = new MechEquipmentRemovedEvent(uid); + RaiseLocalEvent(toRemove, ref ev); + + if (component.CurrentSelectedEquipment == toRemove) + CycleEquipment(uid, component); + + UpdateUserInterface(uid, component); + } + + /// + /// Attempts to change the amount of energy in the mech. + /// + /// The mech itself + /// The change in energy + /// + /// If the energy was successfully changed. + public virtual bool TryChangeEnergy(EntityUid uid, FixedPoint2 delta, SharedMechComponent? component = null) + { + if (!Resolve(uid, ref component)) + return false; + + if (component.Energy + delta < 0) + return false; + + component.Energy = FixedPoint2.Clamp(component.Energy + delta, 0, component.MaxEnergy); + Dirty(component); + UpdateUserInterface(uid, component); + return true; + } + + /// + /// Sets the integrity of the mech. + /// + /// The mech itself + /// The value the integrity will be set at + /// + public void SetIntegrity(EntityUid uid, FixedPoint2 value, SharedMechComponent? component = null) + { + if (!Resolve(uid, ref component)) + return; + + component.Integrity = FixedPoint2.Clamp(value, 0, component.MaxIntegrity); + + if (component.Integrity <= 0) + { + BreakMech(uid, component); + } + else if (component.Broken) + { + component.Broken = false; + UpdateAppearance(uid, component); + } + + Dirty(component); + UpdateUserInterface(uid, component); + } + + /// + /// Checks if the pilot is present + /// + /// + /// Whether or not the pilot is present + public bool IsEmpty(SharedMechComponent component) + { + return component.PilotSlot.ContainedEntity == null; + } + + /// + /// Checks if an entity can be inserted into the mech. + /// + /// + /// + /// + /// + public bool CanInsert(EntityUid uid, EntityUid toInsert, SharedMechComponent? component = null) + { + if (!Resolve(uid, ref component)) + return false; + + return IsEmpty(component) && _actionBlocker.CanMove(toInsert) && HasComp(toInsert); + } + + /// + /// Updates the user interface + /// + /// + /// This is defined here so that UI updates can be accessed from shared. + /// + public virtual void UpdateUserInterface(EntityUid uid, SharedMechComponent? component = null) + { + + } + + /// + /// Attempts to insert a pilot into the mech. + /// + /// + /// + /// + /// Whether or not the entity was inserted + public virtual bool TryInsert(EntityUid uid, EntityUid? toInsert, SharedMechComponent? component = null) + { + if (!Resolve(uid, ref component)) + return false; + + if (toInsert == null || component.PilotSlot.ContainedEntity == toInsert) + return false; + + if (!CanInsert(uid, toInsert.Value, component)) + return false; + + SetupUser(uid, toInsert.Value); + component.PilotSlot.Insert(toInsert.Value, EntityManager); + UpdateAppearance(uid, component); + return true; + } + + /// + /// Attempts to eject the current pilot from the mech + /// + /// + /// + /// Whether or not the pilot was ejected. + public virtual bool TryEject(EntityUid uid, SharedMechComponent? component = null) + { + if (!Resolve(uid, ref component)) + return false; + + if (component.PilotSlot.ContainedEntity == null) + return false; + + var pilot = component.PilotSlot.ContainedEntity.Value; + + RemoveUser(uid, pilot); + _container.RemoveEntity(uid, pilot); + UpdateAppearance(uid, component); + return true; + } + + private void OnGetMeleeWeapon(EntityUid uid, MechPilotComponent component, GetMeleeWeaponEvent args) + { + if (args.Handled) + return; + + if (!TryComp(component.Mech, out var mech)) + return; + + var weapon = mech.CurrentSelectedEquipment ?? component.Mech; + args.Weapon = weapon; + args.Handled = true; + } + + private void OnCanAttackFromContainer(EntityUid uid, MechPilotComponent component, CanAttackFromContainerEvent args) + { + args.CanAttack = true; + } + + private void UpdateAppearance(EntityUid uid, SharedMechComponent ? component = null, AppearanceComponent? appearance = null) + { + if (!Resolve(uid, ref component, ref appearance, false)) + return; + + _appearance.SetData(uid, MechVisuals.Open, IsEmpty(component), appearance); + _appearance.SetData(uid, MechVisuals.Broken, component.Broken, appearance); + } +} diff --git a/Content.Shared/Mech/Equipment/Components/MechEquipmentComponent.cs b/Content.Shared/Mech/Equipment/Components/MechEquipmentComponent.cs new file mode 100644 index 0000000000..a83f617e5e --- /dev/null +++ b/Content.Shared/Mech/Equipment/Components/MechEquipmentComponent.cs @@ -0,0 +1,45 @@ +using System.Threading; +using Content.Shared.Mech.Components; + +namespace Content.Shared.Mech.Equipment.Components; + +/// +/// A piece of equipment that can be installed into +/// +[RegisterComponent] +public sealed class MechEquipmentComponent : Component +{ + /// + /// How long does it take to install this piece of equipment + /// + [DataField("installDuration")] + public float InstallDuration = 5; + + /// + /// The mech that the equipment is inside of. + /// + [ViewVariables] + public EntityUid? EquipmentOwner; + + public CancellationTokenSource? TokenSource = null; +} + +/// +/// Raised on the equipment when the installation is finished successfully +/// +public sealed class MechEquipmentInstallFinished : EntityEventArgs +{ + public EntityUid Mech; + + public MechEquipmentInstallFinished(EntityUid mech) + { + Mech = mech; + } +} + +/// +/// Raised on the equipment when the installation fails. +/// +public sealed class MechEquipmentInstallCancelled : EntityEventArgs +{ +} diff --git a/Content.Shared/Mech/MechUI.cs b/Content.Shared/Mech/MechUI.cs new file mode 100644 index 0000000000..381760166b --- /dev/null +++ b/Content.Shared/Mech/MechUI.cs @@ -0,0 +1,102 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared.Mech; + +[Serializable, NetSerializable] +public enum MechUiKey : byte +{ + Key +} + +/// +/// Event raised to collect BUI states for each of the mech's equipment items +/// +public sealed class MechEquipmentUiStateReadyEvent : EntityEventArgs +{ + public Dictionary States = new(); +} + +/// +/// Event raised to relay an equipment ui message +/// +public sealed class MechEquipmentUiMessageRelayEvent : EntityEventArgs +{ + public MechEquipmentUiMessage Message; + + public MechEquipmentUiMessageRelayEvent(MechEquipmentUiMessage message) + { + Message = message; + } +} + +/// +/// UI event raised to remove a piece of equipment from a mech +/// +[Serializable, NetSerializable] +public sealed class MechEquipmentRemoveMessage : BoundUserInterfaceMessage +{ + public EntityUid Equipment; + + public MechEquipmentRemoveMessage(EntityUid equipment) + { + Equipment = equipment; + } +} + +/// +/// base for all mech ui messages +/// +[Serializable, NetSerializable] +public abstract class MechEquipmentUiMessage : BoundUserInterfaceMessage +{ + public EntityUid Equipment; +} + +/// +/// event raised for the grabber equipment to eject an item from it's storage +/// +[Serializable, NetSerializable] +public sealed class MechGrabberEjectMessage : MechEquipmentUiMessage +{ + public EntityUid Item; + + public MechGrabberEjectMessage(EntityUid equipment, EntityUid uid) + { + Equipment = equipment; + Item = uid; + } +} + +/// +/// BUI state for mechs that also contains all equipment ui states. +/// +/// +/// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠⢐⠤⢃⢰⠐⡄⣀⠀⠀ +/// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠔⣨⠀⢁⠁⠐⡐⠠⠜⠐⠀ +/// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠔⠐⢀⡁⣀⠔⡌⠡⢀⢐⠁⠀ +/// ⠀⠀⠀⠀⢀⠔⠀⡂⡄⠠⢀⡀⠀⣄⡀⠠⠤⠴⡋⠑⡠⠀⠔⠐⢂⠕⢀⡂⠀⠀ +/// ⠀⠀⠀⡔⠁⠠⡐⠁⠀⠀⠀⢘⠀⠀⠀⠀⠠⠀⠈⠪⠀⠑⠡⣃⠈⠤⡈⠀⠀⠀ +/// ⠀⠀⠨⠀⠄⡒⠀⡂⢈⠀⣀⢌⠀⠀⠁⡈⠀⢆⢀⠀⡀⠉⠒⢆⠑⠀⠀⠀⠀⠀ +/// ⠀⠀⠀⡁⠐⠠⠐⡀⠀⢀⣀⠣⡀⠢⡀⠀⢀⡃⠰⠀⠈⠠⢁⠎⠀⠀⠀⠀⠀⠀ +/// ⠀⠀⠀⠅⠒⣈⢣⠠⠈⠕⠁⠱⠄⢤⠈⠪⠡⠎⢘⠈⡁⢙⠈⠀⠀⠀⠀⠀⠀⠀ +/// ⠀⠀⠀⠃⠀⢡⠀⠧⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⢕⡈⠌⠀⠀⠀⠀⠀⠀⠀⠀ +/// ⠀⠀⠀⠀⠀⠀⠈⡀⡀⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⡰⠀⡐⠀⠀⠀⠀⠀⠀⠀⠀ +/// ⠀⠀⠀⠀⠀⠀⠀⢈⢂⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠀⡃⠀⠀⠀⠀⠀⠀⠀⠀ +/// ⠀⠀⠀⠀⠀⠀⠀⠎⠐⢅⠀⠀⠀⠀⠀⠀⠀⠀⠀⢐⠅⠚⠄⠀⠀⠀⠀⠀⠀⠀ +/// ⠀⠀⢈⠩⠈⠀⠐⠁⠀⢀⠀⠄⡂⠒⠐⠀⠆⠁⠰⠠⠀⢅⠈⠐⠄⢁⢡⠀⠀⠀ +/// ⠀⠀⢈⡀⠰⡁⠀⠁⠴⠁⠔⠀⠀⠄⠄⡁⠀⠂⠀⠢⠠⠁⠀⠠⠈⠂⠬⠀⠀⠀ +/// ⠀⠀⠠⡂⢄⠤⠒⣁⠐⢕⢀⡈⡐⡠⠄⢐⠀⠈⠠⠈⡀⠂⢀⣀⠰⠁⠠⠀⠀ +/// trojan horse bui state⠀ +/// +[Serializable, NetSerializable] +public sealed class MechBoundUiState : BoundUserInterfaceState +{ + public Dictionary EquipmentStates = new(); +} + +[Serializable, NetSerializable] +public sealed class MechGrabberUiState : BoundUserInterfaceState +{ + public List Contents = new(); + public int MaxContents; +} diff --git a/Content.Shared/Mech/SharedMech.cs b/Content.Shared/Mech/SharedMech.cs new file mode 100644 index 0000000000..19a0aa9313 --- /dev/null +++ b/Content.Shared/Mech/SharedMech.cs @@ -0,0 +1,62 @@ +using Content.Shared.Actions; +using Robust.Shared.Serialization; + +namespace Content.Shared.Mech; + +[Serializable, NetSerializable] +public enum MechVisuals : byte +{ + Open, //whether or not it's open and has a rider + Broken //if it broke and no longer works. +} + +[Serializable, NetSerializable] +public enum MechAssemblyVisuals : byte +{ + State +} + +[Serializable, NetSerializable] +public enum MechVisualLayers : byte +{ + Base +} + +/// +/// Event raised on equipment when it is inserted into a mech +/// +[ByRefEvent] +public readonly record struct MechEquipmentInsertedEvent(EntityUid Mech) +{ + public readonly EntityUid Mech = Mech; +} + +/// +/// Event raised on equipment when it is removed from a mech +/// +[ByRefEvent] +public readonly record struct MechEquipmentRemovedEvent(EntityUid Mech) +{ + public readonly EntityUid Mech = Mech; +} + +/// +/// Raised on the mech equipment before it is going to be removed. +/// +[ByRefEvent] +public record struct AttemptRemoveMechEquipmentEvent() +{ + public bool Cancelled = false; +} + +public sealed class MechToggleEquipmentEvent : InstantActionEvent +{ +} + +public sealed class MechOpenUiEvent : InstantActionEvent +{ +} + +public sealed class MechEjectPilotEvent : InstantActionEvent +{ +} diff --git a/Content.Shared/Movement/Systems/SharedMoverController.cs b/Content.Shared/Movement/Systems/SharedMoverController.cs index 6c965a8f27..328b2b5e0d 100644 --- a/Content.Shared/Movement/Systems/SharedMoverController.cs +++ b/Content.Shared/Movement/Systems/SharedMoverController.cs @@ -17,6 +17,7 @@ using Robust.Shared.Physics.Controllers; using Robust.Shared.Timing; using Robust.Shared.Utility; using System.Diagnostics.CodeAnalysis; +using Content.Shared.Mech.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Systems; @@ -414,6 +415,12 @@ namespace Content.Shared.Movement.Systems mobMover.StepSoundDistance -= distanceNeeded; + if (TryComp(mover.Owner, out var moverModifier)) + { + sound = moverModifier.Sound; + return true; + } + if (_inventory.TryGetSlotEntity(mover.Owner, "shoes", out var shoes) && EntityManager.TryGetComponent(shoes, out var modifier)) { diff --git a/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs b/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs index 82bcd1f77e..ffaa3246f3 100644 --- a/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs +++ b/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs @@ -130,6 +130,15 @@ public sealed class MeleeWeaponComponent : Component public SoundSpecifier NoDamageSound { get; set; } = new SoundPathSpecifier("/Audio/Weapons/tap.ogg"); } +/// +/// Event raised on entity in GetWeapon function to allow systems to manually +/// specify what the weapon should be. +/// +public sealed class GetMeleeWeaponEvent : HandledEntityEventArgs +{ + public EntityUid? Weapon; +} + [Serializable, NetSerializable] public sealed class MeleeWeaponComponentState : ComponentState { diff --git a/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs b/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs index b9ae509a1d..1e01b2a141 100644 --- a/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs +++ b/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs @@ -19,7 +19,6 @@ using Robust.Shared.GameStates; using Robust.Shared.Map; using Robust.Shared.Physics; using Robust.Shared.Physics.Systems; -using Robust.Shared.Player; using Robust.Shared.Players; using Robust.Shared.Prototypes; using Robust.Shared.Timing; @@ -227,6 +226,13 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem { MeleeWeaponComponent? melee; + var ev = new GetMeleeWeaponEvent(); + RaiseLocalEvent(entity, ev); + if (ev.Handled) + { + return EntityManager.GetComponentOrNull(ev.Weapon); + } + // Use inhands entity if we got one. if (EntityManager.TryGetComponent(entity, out SharedHandsComponent? hands) && hands.ActiveHandEntity is { } held) diff --git a/Resources/Audio/Mecha/attributions.yml b/Resources/Audio/Mecha/attributions.yml new file mode 100644 index 0000000000..2330e20ad9 --- /dev/null +++ b/Resources/Audio/Mecha/attributions.yml @@ -0,0 +1,12 @@ +- files: ["mechmove03.ogg"] + license: "CC-BY-NC-SA-3.0" + copyright: "Taken from TG station." + source: "https://github.com/tgstation/tgstation/commit/d4f678a1772007ff8d7eddd21cf7218c8e07bfc0" +- files: ["sound_mecha_hydraulic.ogg"] + license: "CC-BY-NC-SA-3.0" + copyright: "Taken from TG station." + source: "https://github.com/tgstation/tgstation/commit/45123dd06cb6dc7c56e8004c528230682ea559b2" +- files: ["sound_mecha_powerloader_step.ogg"] + license: "CC-BY-NC-SA-3.0" + copyright: "Taken from TG station." + source: "https://github.com/tgstation/tgstation/commit/45123dd06cb6dc7c56e8004c528230682ea559b2" \ No newline at end of file diff --git a/Resources/Audio/Mecha/license.txt b/Resources/Audio/Mecha/license.txt deleted file mode 100644 index 85e55229b4..0000000000 --- a/Resources/Audio/Mecha/license.txt +++ /dev/null @@ -1 +0,0 @@ -mechmove03.ogg taken from TG station at commit https://github.com/tgstation/tgstation/commit/d4f678a1772007ff8d7eddd21cf7218c8e07bfc0 \ No newline at end of file diff --git a/Resources/Audio/Mecha/sound_mecha_hydraulic.ogg b/Resources/Audio/Mecha/sound_mecha_hydraulic.ogg new file mode 100644 index 0000000000..3281ed2dc0 Binary files /dev/null and b/Resources/Audio/Mecha/sound_mecha_hydraulic.ogg differ diff --git a/Resources/Audio/Mecha/sound_mecha_powerloader_step.ogg b/Resources/Audio/Mecha/sound_mecha_powerloader_step.ogg new file mode 100644 index 0000000000..538ba1efed Binary files /dev/null and b/Resources/Audio/Mecha/sound_mecha_powerloader_step.ogg differ diff --git a/Resources/Locale/en-US/actions/actions/mech.ftl b/Resources/Locale/en-US/actions/actions/mech.ftl new file mode 100644 index 0000000000..7acef18358 --- /dev/null +++ b/Resources/Locale/en-US/actions/actions/mech.ftl @@ -0,0 +1,8 @@ +action-name-mech-cycle = Cycle +action-description-mech-cycle = Cycles currently selected equipment + +action-name-mech-control-panel = Control Panel +action-description-mech-control-panel = Opens the control panel for the mech + +action-name-mech-eject = Eject +action-description-mech-eject = Ejects the pilot from the mech \ No newline at end of file diff --git a/Resources/Locale/en-US/mech/mech.ftl b/Resources/Locale/en-US/mech/mech.ftl new file mode 100644 index 0000000000..faf3ef3661 --- /dev/null +++ b/Resources/Locale/en-US/mech/mech.ftl @@ -0,0 +1,16 @@ +mech-verb-enter = Enter +mech-verb-exit = Exit + +mech-equipment-begin-install = Installing the {THE($item)}... +mech-equipment-finish-install = Finished installing the {THE($item)} + +mech-equipment-select-popup = {$item} selected +mech-equipment-select-none-popup = Nothing selected + +mech-ui-open-verb = Open control panel + +mech-menu-title = mech control panel + +mech-integrity-display = Integrity: {$amount}% +mech-energy-display = Energy: {$amount}% +mech-slot-display = Open Slots: {$amount} \ No newline at end of file diff --git a/Resources/Locale/en-US/prototypes/catalog/research/technologies.ftl b/Resources/Locale/en-US/prototypes/catalog/research/technologies.ftl index 172003b480..aca0ea08ad 100644 --- a/Resources/Locale/en-US/prototypes/catalog/research/technologies.ftl +++ b/Resources/Locale/en-US/prototypes/catalog/research/technologies.ftl @@ -76,5 +76,8 @@ technologies-robotics-technology-description = Parts needed for constructing mec technologies-archaeology = Archeological equipment technologies-archaeology-description = Advanced equipment for uncovering the secrets of artifacts. -technologies-adv-parts-technology = Advanced parts technology -technologies-adv-parts-technology-description = Like the previous ones, but better! \ No newline at end of file +technologies-ripley-technology = Exosuit: Ripley +technologies-ripley-technology-description = The latest and greatest in mechanized cargo construction. + +technologies-adv-parts-technology-description = Like the previous ones, but better! +technologies-adv-parts-technology = Advanced parts technology \ No newline at end of file diff --git a/Resources/Prototypes/Actions/mech.yml b/Resources/Prototypes/Actions/mech.yml new file mode 100644 index 0000000000..f070f006d6 --- /dev/null +++ b/Resources/Prototypes/Actions/mech.yml @@ -0,0 +1,31 @@ +- type: instantAction + id: MechCycleEquipment + name: action-name-mech-cycle + description: action-description-mech-cycle + itemIconStyle: NoItem + icon: + sprite: Interface/Actions/actions_mecha.rsi + state: mech_cycle_equip_on + event: !type:MechToggleEquipmentEvent + useDelay: 0.5 + +- type: instantAction + id: MechOpenUI + name: action-name-mech-control-panel + description: action-description-mech-control-panel + itemIconStyle: NoItem + icon: + sprite: Interface/Actions/actions_mecha.rsi + state: mech_view_stats + event: !type:MechOpenUiEvent + useDelay: 1 + +- type: instantAction + id: MechEject + name: action-name-mech-eject + description: action-description-mech-eject + itemIconStyle: NoItem + icon: + sprite: Interface/Actions/actions_mecha.rsi + state: mech_eject + event: !type:MechEjectPilotEvent \ No newline at end of file diff --git a/Resources/Prototypes/Actions/types.yml b/Resources/Prototypes/Actions/types.yml index 6c37a9f899..244e5fb0af 100644 --- a/Resources/Prototypes/Actions/types.yml +++ b/Resources/Prototypes/Actions/types.yml @@ -125,4 +125,4 @@ description: action-desc-wake icon: { sprite: Objects/Consumable/Food/egg.rsi, state: icon } checkCanInteract: false - event: !type:WakeActionEvent + event: !type:WakeActionEvent \ No newline at end of file diff --git a/Resources/Prototypes/Catalog/Research/technologies.yml b/Resources/Prototypes/Catalog/Research/technologies.yml index 9c79bb6ef9..50453e5111 100644 --- a/Resources/Prototypes/Catalog/Research/technologies.yml +++ b/Resources/Prototypes/Catalog/Research/technologies.yml @@ -259,6 +259,26 @@ #TODO- Gyroscope #TODO- Thruster +- type: technology + name: technologies-ripley-technology + id: RipleyTechnology + description: technologies-ripley-technology-description + icon: + sprite: Objects/Specific/Mech/mecha.rsi + state: ripley + requiredPoints: 30000 + requiredTechnologies: + - SalvageEquipment + unlockedRecipes: + - RipleyCentralElectronics + - RipleyPeripheralsElectronics + - MechEquipmentGrabber + - RipleyHarness + - RipleyLArm + - RipleyRArm + - RipleyLLeg + - RipleyRLeg + # Industrial Engineering Technology Tree - type: technology diff --git a/Resources/Prototypes/Entities/Objects/Devices/Electronics/mech.yml b/Resources/Prototypes/Entities/Objects/Devices/Electronics/mech.yml new file mode 100644 index 0000000000..0ea4629adb --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Devices/Electronics/mech.yml @@ -0,0 +1,25 @@ +- type: entity + id: RipleyCentralElectronics + parent: BaseElectronics + name: ripley central control module + description: The electrical control center for the ripley mech. + components: + - type: Sprite + sprite: Objects/Misc/module.rsi + state: mainboard + - type: Tag + tags: + - RipleyCentralControlModule + +- type: entity + id: RipleyPeripheralsElectronics + parent: BaseElectronics + name: ripley peripherals control module + description: The electrical peripherals control for the ripley mech. + components: + - type: Sprite + sprite: Objects/Misc/module.rsi + state: id_mod + - type: Tag + tags: + - RipleyPeripheralsControlModule \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Objects/Specific/Mech/mech_construction.yml b/Resources/Prototypes/Entities/Objects/Specific/Mech/mech_construction.yml new file mode 100644 index 0000000000..27024cc3ae --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Specific/Mech/mech_construction.yml @@ -0,0 +1,150 @@ +- type: entity + id: BaseMechPart + abstract: true + components: + - type: Clickable + - type: InteractionOutline + - type: CollisionWake + - type: TileFrictionModifier + modifier: 0.5 + - type: Physics + bodyType: Dynamic + fixedRotation: false + - type: Fixtures + fixtures: + - shape: + !type:PhysShapeAabb + bounds: "-0.25,-0.25,0.25,0.25" + density: 100 + mask: + - ItemMask + restitution: 0.3 # fite me + friction: 0.2 + - type: Pullable + - type: Sprite + drawdepth: Items + noRot: false + netsync: false + sprite: Objects/Specific/Mech/ripley_construction.rsi + +- type: entity + id: BaseMechPartItem + parent: BaseMechPart + abstract: true + components: + - type: Item + size: 50 + +- type: entity + id: BaseMechConstruct + parent: BaseMechPart + abstract: true + components: + - type: Appearance + - type: ContainerContainer + containers: + battery-container: !type:Container + - type: MechAssemblyVisuals + statePrefix: ripley + +- type: entity + parent: BaseMechPart + id: RipleyHarness + name: ripley harness + description: The core of the ripley mech + components: + - type: Appearance + - type: ItemMapper + mapLayers: + ripley_l_arm+o: + whitelist: + tags: + - RipleyLArm + ripley_r_arm+o: + whitelist: + tags: + - RipleyRArm + ripley_l_leg+o: + whitelist: + tags: + - RipleyLLeg + ripley_r_leg+o: + whitelist: + tags: + - RipleyRLeg + sprite: Objects/Specific/Mech/ripley_construction.rsi + - type: ContainerContainer + containers: + mech-assembly-container: !type:Container + - type: MechAssembly + finishedPrototype: RipleyChassis + requiredParts: + RipleyLArm: false + RipleyRArm: false + RipleyLLeg: false + RipleyRLeg: false + - type: Sprite + state: ripley_harness+o + noRot: true + +- type: entity + parent: BaseMechPartItem + id: RipleyLArm + name: ripley left arm + description: Ripley mech left arm + components: + - type: Sprite + state: ripley_l_arm + - type: Tag + tags: + - RipleyLArm + +- type: entity + parent: BaseMechPartItem + id: RipleyLLeg + name: ripley left leg + description: Ripley mech left leg + components: + - type: Sprite + state: ripley_l_leg + - type: Tag + tags: + - RipleyLLeg + +- type: entity + parent: BaseMechPartItem + id: RipleyRLeg + name: ripley right leg + description: Ripley mech right leg + components: + - type: Sprite + state: ripley_r_leg + - type: Tag + tags: + - RipleyRLeg + +- type: entity + parent: BaseMechPartItem + id: RipleyRArm + name: ripley right arm + description: Ripley mech right arm + components: + - type: Sprite + state: ripley_r_arm + - type: Tag + tags: + - RipleyRArm + +- type: entity + id: RipleyChassis + parent: BaseMechConstruct + name: ripley chassis + description: An in-progress construction of a ripley mech. + components: + - type: Sprite + noRot: true + state: ripley0 + - type: Construction + graph: Ripley + node: start + defaultTarget: ripley \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Objects/Specific/Mech/mecha_equipment.yml b/Resources/Prototypes/Entities/Objects/Specific/Mech/mecha_equipment.yml new file mode 100644 index 0000000000..fbbc13ddfb --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Specific/Mech/mecha_equipment.yml @@ -0,0 +1,26 @@ +- type: entity + parent: BaseItem + id: BaseMechEquipment + abstract: true + components: + - type: Sprite + sprite: Objects/Specific/Mech/mecha_equipment.rsi + - type: Item + sprite: Objects/Specific/Mech/mecha_equipment.rsi + size: 50 + - type: MechEquipment + +- type: entity + id: MechEquipmentGrabber + parent: BaseMechEquipment + name: hydraulic clamp + description: Gives the mech the ability to grab things and drag them around. + components: + - type: Sprite + state: mecha_clamp + - type: MechGrabber + - type: UIFragment + ui: !type:MechGrabberUi + - type: ContainerContainer + containers: + item-container: !type:Container \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Objects/Specific/Mech/mechs.yml b/Resources/Prototypes/Entities/Objects/Specific/Mech/mechs.yml new file mode 100644 index 0000000000..370216e66d --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Specific/Mech/mechs.yml @@ -0,0 +1,100 @@ +- type: entity + id: BaseMech + save: false + abstract: true + components: + - type: Sprite + netsync: false + drawdepth: Mobs + noRot: true + sprite: Objects/Specific/Mech/mecha.rsi + layers: + - map: [ "enum.MechVisualLayers.Base" ] + state: ripley + - type: MobMover + - type: Mech + baseState: ripley + openState: ripley-open + brokenState: ripley-broken + - type: DoAfter + - type: Repairable + fuelCost: 25 + doAfterDelay: 10 + - type: UserInterface + interfaces: + - key: enum.MechUiKey.Key + type: MechBoundUserInterface + - type: MeleeWeapon + hidden: true + attackRate: 0.75 + damage: + types: + Blunt: 25 #thwack + Structural: 20 + - type: Puller + needsHands: false + - type: InputMover + - type: InteractionOutline + - type: MovementSpeedModifier + baseWalkSpeed: 1 + baseSprintSpeed: 2 + - type: Tag + tags: + - DoorBumpOpener + - FootstepSound + - type: Pullable + - type: Physics + bodyType: KinematicController + - type: Clickable + - type: Wires #we just want the panel + BoardName: Mech + LayoutId: Mech + - type: Fixtures + fixtures: + - shape: + !type:PhysShapeCircle + radius: 0.45 + density: 1000 + mask: + - MobMask + layer: + - MobLayer + - type: Appearance + - type: ContainerContainer + containers: + mech-pilot-slot: !type:ContainerSlot + mech-equipment-container: !type:Container + mech-battery-slot: !type:ContainerSlot + - type: Damageable + damageContainer: Inorganic + damageModifierSet: Metallic + - type: FootstepModifier + footstepSoundCollection: + path: /Audio/Mecha/mechmove03.ogg + +- type: entity + id: MechRipley + parent: BaseMech + name: ripley + description: Cargo's favorite robotic box hauling friend. + components: + - type: FootstepModifier + footstepSoundCollection: + path: /Audio/Mecha/sound_mecha_powerloader_step.ogg + - type: Mech + baseState: ripley + openState: ripley-open + brokenState: ripley-broken + mechToPilotDamageMultiplier: 0.5 + +- type: entity + id: MechRipleyBattery + parent: MechRipley + suffix: Battery + components: + - type: Mech + baseState: ripley + openState: ripley-open + brokenState: ripley-broken + startingBattery: PowerCellHigh + mechToPilotDamageMultiplier: 0.5 diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index 89921de674..885bd03f33 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -290,6 +290,8 @@ - CloningConsoleComputerCircuitboard - StasisBedMachineCircuitboard - OreProcessorMachineCircuitboard + - RipleyCentralElectronics + - RipleyPeripheralsElectronics - GeneratorPlasmaMachineCircuitboard - GeneratorUraniumMachineCircuitboard - WallmountGeneratorElectronics @@ -334,6 +336,12 @@ - ProximitySensor - LeftArmBorg - RightArmBorg + - RipleyHarness + - RipleyLArm + - RipleyRArm + - RipleyLLeg + - RipleyRLeg + - MechEquipmentGrabber - type: MaterialStorage whitelist: tags: diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/mechs/ripley_construction.yml b/Resources/Prototypes/Recipes/Construction/Graphs/mechs/ripley_construction.yml new file mode 100644 index 0000000000..659a0360ca --- /dev/null +++ b/Resources/Prototypes/Recipes/Construction/Graphs/mechs/ripley_construction.yml @@ -0,0 +1,125 @@ +- type: constructionGraph + id: Ripley + start: start + graph: + - node: start + edges: + - to: ripley + steps: + - tool: Anchoring + doAfter: 1 + completed: + - !type:VisualizerDataInt + key: "enum.MechAssemblyVisuals.State" + data: 1 + + - tool: Screwing + doAfter: 1 + completed: + - !type:VisualizerDataInt + key: "enum.MechAssemblyVisuals.State" + data: 2 + + - material: Cable + completed: + - !type:VisualizerDataInt + key: "enum.MechAssemblyVisuals.State" + data: 3 + + - tool: Cutting + doAfter: 1 + completed: + - !type:VisualizerDataInt + key: "enum.MechAssemblyVisuals.State" + data: 4 + + - tag: RipleyCentralControlModule + name: ripley central control module + icon: + sprite: "Objects/Misc/module.rsi" + state: "mainboard" + completed: + - !type:VisualizerDataInt + key: "enum.MechAssemblyVisuals.State" + data: 5 + + - tool: Screwing + doAfter: 1 + completed: + - !type:VisualizerDataInt + key: "enum.MechAssemblyVisuals.State" + data: 6 + + - tag: RipleyPeripheralsControlModule + name: ripley peripherals control module + icon: + sprite: "Objects/Misc/module.rsi" + state: id_mod + completed: + - !type:VisualizerDataInt + key: "enum.MechAssemblyVisuals.State" + data: 7 + + - tool: Screwing + doAfter: 1 + completed: + - !type:VisualizerDataInt + key: "enum.MechAssemblyVisuals.State" + data: 12 + +#i omitted the steps involving inserting machine parts because +#currently mechs don't support upgrading. add them back in once that's squared away. + + - component: PowerCell + name: power cell + store: battery-container + icon: + sprite: Objects/Power/power_cells.rsi + state: small + completed: + - !type:VisualizerDataInt + key: "enum.MechAssemblyVisuals.State" + data: 13 + + - tool: Screwing + doAfter: 1 + completed: + - !type:VisualizerDataInt + key: "enum.MechAssemblyVisuals.State" + data: 14 + + - material: Steel + amount: 5 + completed: + - !type:VisualizerDataInt + key: "enum.MechAssemblyVisuals.State" + data: 15 + + - tool: Anchoring + doAfter: 1 + completed: + - !type:VisualizerDataInt + key: "enum.MechAssemblyVisuals.State" + data: 16 + + - tool: Welding + doAfter: 1 + completed: + - !type:VisualizerDataInt + key: "enum.MechAssemblyVisuals.State" + data: 17 + + - material: MetalRod + amount: 10 + completed: + - !type:VisualizerDataInt + key: "enum.MechAssemblyVisuals.State" + data: 18 + + - tool: Welding + doAfter: 1 + + - node: ripley + actions: + - !type:BuildMech + mechPrototype: MechRipley \ No newline at end of file diff --git a/Resources/Prototypes/Recipes/Lathes/electronics.yml b/Resources/Prototypes/Recipes/Lathes/electronics.yml index d0520bffb9..2cef6729fe 100644 --- a/Resources/Prototypes/Recipes/Lathes/electronics.yml +++ b/Resources/Prototypes/Recipes/Lathes/electronics.yml @@ -280,6 +280,27 @@ Steel: 100 Glass: 900 Gold: 100 + +- type: latheRecipe + id: RipleyCentralElectronics + icon: Objects/Misc/module.rsi/mainboard.png + result: RipleyCentralElectronics + completetime: 4 + materials: + Steel: 100 + Glass: 900 + Gold: 100 + +- type: latheRecipe + id: RipleyPeripheralsElectronics + icon: Objects/Misc/module.rsi/id_mod.png + result: RipleyPeripheralsElectronics + completetime: 4 + materials: + Steel: 100 + Glass: 900 + Gold: 100 + # Power - type: latheRecipe id: APCElectronics diff --git a/Resources/Prototypes/Recipes/Lathes/mech_parts.yml b/Resources/Prototypes/Recipes/Lathes/mech_parts.yml new file mode 100644 index 0000000000..47a238f885 --- /dev/null +++ b/Resources/Prototypes/Recipes/Lathes/mech_parts.yml @@ -0,0 +1,65 @@ +- type: latheRecipe + id: RipleyHarness + icon: + sprite: Objects/Specific/Mech/ripley_construction.rsi + state: ripley_harness + result: RipleyHarness + completetime: 10 + materials: + Steel: 3000 + Glass: 1200 + +- type: latheRecipe + id: RipleyLArm + icon: + sprite: Objects/Specific/Mech/ripley_construction.rsi + state: ripley_l_arm + result: RipleyLArm + completetime: 10 + materials: + Steel: 3000 + Glass: 1200 + +- type: latheRecipe + id: RipleyLLeg + icon: + sprite: Objects/Specific/Mech/ripley_construction.rsi + state: ripley_l_leg + result: RipleyLLeg + completetime: 10 + materials: + Steel: 3000 + Glass: 1200 + +- type: latheRecipe + id: RipleyRLeg + icon: + sprite: Objects/Specific/Mech/ripley_construction.rsi + state: ripley_r_leg + result: RipleyRLeg + completetime: 10 + materials: + Steel: 3000 + Glass: 1200 + +- type: latheRecipe + id: RipleyRArm + icon: + sprite: Objects/Specific/Mech/ripley_construction.rsi + state: ripley_r_arm + result: RipleyRArm + completetime: 10 + materials: + Steel: 3000 + Glass: 1200 + +- type: latheRecipe + id: MechEquipmentGrabber + icon: + sprite: Objects/Specific/Mech/mecha_equipment.rsi + state: mecha_clamp + result: MechEquipmentGrabber + completetime: 10 + materials: + Steel: 500 + Plastic: 200 \ No newline at end of file diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index d07c878fca..5fda8238c0 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -458,12 +458,30 @@ - type: Tag id: RawMaterial +- type: Tag + id: RCDDeconstructWhitelist + # Give this to something that doesn't need any special recycler behavior and just needs deleting. - type: Tag id: Recyclable - type: Tag - id: RCDDeconstructWhitelist + id: RipleyCentralControlModule + +- type: Tag + id: RipleyPeripheralsControlModule + +- type: Tag + id: RipleyLArm + +- type: Tag + id: RipleyLLeg + +- type: Tag + id: RipleyRLeg + +- type: Tag + id: RipleyRArm - type: Tag id: RodMetal1 diff --git a/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_cycle_equip_off.png b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_cycle_equip_off.png new file mode 100644 index 0000000000..352479e87b Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_cycle_equip_off.png differ diff --git a/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_cycle_equip_on.png b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_cycle_equip_on.png new file mode 100644 index 0000000000..c042bf0a9f Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_cycle_equip_on.png differ diff --git a/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_damtype_brute.png b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_damtype_brute.png new file mode 100644 index 0000000000..de57f3e5d1 Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_damtype_brute.png differ diff --git a/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_damtype_burn.png b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_damtype_burn.png new file mode 100644 index 0000000000..6d6b43c412 Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_damtype_burn.png differ diff --git a/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_damtype_toxin.png b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_damtype_toxin.png new file mode 100644 index 0000000000..5b51d05d40 Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_damtype_toxin.png differ diff --git a/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_defense_mode_off.png b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_defense_mode_off.png new file mode 100644 index 0000000000..498e07931f Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_defense_mode_off.png differ diff --git a/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_defense_mode_on.png b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_defense_mode_on.png new file mode 100644 index 0000000000..d926cac8fc Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_defense_mode_on.png differ diff --git a/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_eject.png b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_eject.png new file mode 100644 index 0000000000..79babfb931 Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_eject.png differ diff --git a/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_internals_off.png b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_internals_off.png new file mode 100644 index 0000000000..a631511d9e Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_internals_off.png differ diff --git a/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_internals_on.png b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_internals_on.png new file mode 100644 index 0000000000..64c0346d39 Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_internals_on.png differ diff --git a/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_ivanov.png b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_ivanov.png new file mode 100644 index 0000000000..c098b6eec2 Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_ivanov.png differ diff --git a/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_ivanov_cooldown.png b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_ivanov_cooldown.png new file mode 100644 index 0000000000..70704d56da Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_ivanov_cooldown.png differ diff --git a/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_lights_off.png b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_lights_off.png new file mode 100644 index 0000000000..2a2c8709bc Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_lights_off.png differ diff --git a/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_lights_on.png b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_lights_on.png new file mode 100644 index 0000000000..90659a8dec Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_lights_on.png differ diff --git a/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_overload_off.png b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_overload_off.png new file mode 100644 index 0000000000..c9ff8066e5 Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_overload_off.png differ diff --git a/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_overload_on.png b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_overload_on.png new file mode 100644 index 0000000000..c702d958ef Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_overload_on.png differ diff --git a/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_phasing_off.png b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_phasing_off.png new file mode 100644 index 0000000000..3ce5a540bd Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_phasing_off.png differ diff --git a/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_phasing_on.png b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_phasing_on.png new file mode 100644 index 0000000000..b2496eddc2 Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_phasing_on.png differ diff --git a/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_savannah.png b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_savannah.png new file mode 100644 index 0000000000..ce105cc8ab Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_savannah.png differ diff --git a/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_savannah_cooldown.png b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_savannah_cooldown.png new file mode 100644 index 0000000000..67aaad7f6c Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_savannah_cooldown.png differ diff --git a/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_seat_swap.png b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_seat_swap.png new file mode 100644 index 0000000000..859eed3a50 Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_seat_swap.png differ diff --git a/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_smoke.png b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_smoke.png new file mode 100644 index 0000000000..232b2eec9b Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_smoke.png differ diff --git a/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_thrusters_off.png b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_thrusters_off.png new file mode 100644 index 0000000000..4d73a0f23c Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_thrusters_off.png differ diff --git a/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_thrusters_on.png b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_thrusters_on.png new file mode 100644 index 0000000000..814bb8b34c Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_thrusters_on.png differ diff --git a/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_view_stats.png b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_view_stats.png new file mode 100644 index 0000000000..81b51a9d52 Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_view_stats.png differ diff --git a/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_zoom_off.png b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_zoom_off.png new file mode 100644 index 0000000000..0e60719c0a Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_zoom_off.png differ diff --git a/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_zoom_on.png b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_zoom_on.png new file mode 100644 index 0000000000..e6d6aa8899 Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_mecha.rsi/mech_zoom_on.png differ diff --git a/Resources/Textures/Interface/Actions/actions_mecha.rsi/meson.png b/Resources/Textures/Interface/Actions/actions_mecha.rsi/meson.png new file mode 100644 index 0000000000..1c2088bf14 Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_mecha.rsi/meson.png differ diff --git a/Resources/Textures/Interface/Actions/actions_mecha.rsi/meta.json b/Resources/Textures/Interface/Actions/actions_mecha.rsi/meta.json new file mode 100644 index 0000000000..ea7bf434e9 --- /dev/null +++ b/Resources/Textures/Interface/Actions/actions_mecha.rsi/meta.json @@ -0,0 +1,112 @@ +{ + "copyright" : "Taken from https://github.com/tgstation/tgstation at at https://github.com/tgstation/tgstation/commit/40d89d11ea4a5cb81d61dc1018b46f4e7d32c62a", + "license" : "CC-BY-SA-3.0", + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "mech_lights_off" + }, + { + "name": "mech_lights_on" + }, + { + "name": "mech_view_stats" + }, + { + "name": "mech_eject" + }, + { + "name": "mech_seat_swap" + }, + { + "name": "mech_internals_off" + }, + { + "name": "mech_internals_on" + }, + { + "name": "mech_cycle_equip_off" + }, + { + "name": "mech_cycle_equip_on" + }, + { + "name": "mech_defense_mode_off" + }, + { + "name": "mech_defense_mode_on" + }, + { + "name": "mech_thrusters_off" + }, + { + "name": "mech_thrusters_on" + }, + { + "name": "mech_smoke" + }, + { + "name": "mech_zoom_off" + }, + { + "name": "mech_zoom_on" + }, + { + "name": "mech_phasing_off" + }, + { + "name": "mech_phasing_on" + }, + { + "name": "mech_damtype_brute" + }, + { + "name": "mech_damtype_burn" + }, + { + "name": "mech_damtype_toxin" + }, + { + "name": "mech_overload_off" + }, + { + "name": "mech_overload_on" + }, + { + "name": "strafe" + }, + { + "name": "meson" + }, + { + "name": "mech_ivanov" + }, + { + "name": "mech_ivanov_cooldown", + "delays": [ + [ + 0.2, + 0.2, + 0.2 + ] + ] + }, + { + "name": "mech_savannah" + }, + { + "name": "mech_savannah_cooldown", + "delays": [ + [ + 0.2, + 0.2, + 0.2 + ] + ] + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Interface/Actions/actions_mecha.rsi/strafe.png b/Resources/Textures/Interface/Actions/actions_mecha.rsi/strafe.png new file mode 100644 index 0000000000..5c7697b3cf Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_mecha.rsi/strafe.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/clarke-broken.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/clarke-broken.png new file mode 100644 index 0000000000..068697b3f8 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/clarke-broken.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/clarke-open.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/clarke-open.png new file mode 100644 index 0000000000..c6cd664ee1 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/clarke-open.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/clarke.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/clarke.png new file mode 100644 index 0000000000..f5fd8b1a22 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/clarke.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/darkgygax-broken.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/darkgygax-broken.png new file mode 100644 index 0000000000..9b39c48b3b Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/darkgygax-broken.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/darkgygax-open.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/darkgygax-open.png new file mode 100644 index 0000000000..eadf7ffd93 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/darkgygax-open.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/darkgygax.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/darkgygax.png new file mode 100644 index 0000000000..6a65735f3f Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/darkgygax.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/darkhonker-broken.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/darkhonker-broken.png new file mode 100644 index 0000000000..eef046a3c6 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/darkhonker-broken.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/darkhonker-open.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/darkhonker-open.png new file mode 100644 index 0000000000..87c1595029 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/darkhonker-open.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/darkhonker.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/darkhonker.png new file mode 100644 index 0000000000..bf1a52a193 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/darkhonker.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/deathripley-broken.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/deathripley-broken.png new file mode 100644 index 0000000000..879ceef9c4 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/deathripley-broken.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/deathripley-open.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/deathripley-open.png new file mode 100644 index 0000000000..7db78ab187 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/deathripley-open.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/deathripley.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/deathripley.png new file mode 100644 index 0000000000..f8f544ba22 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/deathripley.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/durand-broken.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/durand-broken.png new file mode 100644 index 0000000000..e65af10f1d Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/durand-broken.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/durand-open.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/durand-open.png new file mode 100644 index 0000000000..7a186b0651 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/durand-open.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/durand.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/durand.png new file mode 100644 index 0000000000..8f1424bb24 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/durand.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/firefighter-broken.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/firefighter-broken.png new file mode 100644 index 0000000000..c10bbc9657 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/firefighter-broken.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/firefighter-open.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/firefighter-open.png new file mode 100644 index 0000000000..a3c1ad5645 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/firefighter-open.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/firefighter.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/firefighter.png new file mode 100644 index 0000000000..2e45633ee2 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/firefighter.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/gygax-broken.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/gygax-broken.png new file mode 100644 index 0000000000..ab4f2ae316 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/gygax-broken.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/gygax-open.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/gygax-open.png new file mode 100644 index 0000000000..044eaa62df Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/gygax-open.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/gygax.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/gygax.png new file mode 100644 index 0000000000..ab355dada5 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/gygax.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/hauler-broken.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/hauler-broken.png new file mode 100644 index 0000000000..2496061ab4 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/hauler-broken.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/hauler-empty.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/hauler-empty.png new file mode 100644 index 0000000000..0562436f8b Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/hauler-empty.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/hauler-open.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/hauler-open.png new file mode 100644 index 0000000000..f2b08e5607 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/hauler-open.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/hauler.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/hauler.png new file mode 100644 index 0000000000..7e81fe2a3e Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/hauler.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/honker-broken.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/honker-broken.png new file mode 100644 index 0000000000..689f53123a Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/honker-broken.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/honker-open.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/honker-open.png new file mode 100644 index 0000000000..bb5bf3a2ce Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/honker-open.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/honker.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/honker.png new file mode 100644 index 0000000000..2b44d325ef Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/honker.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/marauder-broken.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/marauder-broken.png new file mode 100644 index 0000000000..b926a6b2da Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/marauder-broken.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/marauder-open.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/marauder-open.png new file mode 100644 index 0000000000..594eaa993e Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/marauder-open.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/marauder.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/marauder.png new file mode 100644 index 0000000000..8f51c76b20 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/marauder.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/mauler-broken.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/mauler-broken.png new file mode 100644 index 0000000000..b024f6d9b4 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/mauler-broken.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/mauler-open.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/mauler-open.png new file mode 100644 index 0000000000..70252e39ba Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/mauler-open.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/mauler.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/mauler.png new file mode 100644 index 0000000000..fe3c934016 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/mauler.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/meta.json b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/meta.json new file mode 100644 index 0000000000..8954670599 --- /dev/null +++ b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/meta.json @@ -0,0 +1,469 @@ +{ + "copyright" : "Taken from https://github.com/tgstation/tgstation at at https://github.com/tgstation/tgstation/commit/40d89d11ea4a5cb81d61dc1018b46f4e7d32c62a", + "license" : "CC-BY-SA-3.0", + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "honker", + "directions": 4, + "delays": [ + [ + 1, + 1 + ], + [ + 1, + 1 + ], + [ + 1, + 1 + ], + [ + 1, + 1 + ] + ] + }, + { + "name": "honker-open" + }, + { + "name": "honker-broken" + }, + { + "name": "reticence", + "directions": 4 + }, + { + "name": "reticence-open" + }, + { + "name": "reticence-broken" + }, + { + "name": "ripley", + "directions": 4 + }, + { + "name": "ripley-empty", + "directions": 4 + }, + { + "name": "ripley-open" + }, + { + "name": "ripley-broken" + }, + { + "name": "marauder", + "directions": 4 + }, + { + "name": "marauder-open", + "delays": [ + [ + 0.5, + 0.1, + 0.2 + ] + ] + }, + { + "name": "marauder-broken" + }, + { + "name": "seraph", + "directions": 4 + }, + { + "name": "seraph-open", + "delays": [ + [ + 0.5, + 0.1, + 0.2 + ] + ] + }, + { + "name": "seraph-broken" + }, + { + "name": "phazon", + "directions": 4 + }, + { + "name": "phazon-open" + }, + { + "name": "phazon-phase", + "directions": 4, + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + }, + { + "name": "phazon-broken" + }, + { + "name": "ripley-old", + "directions": 4 + }, + { + "name": "ripley-broken-old" + }, + { + "name": "mauler", + "directions": 4, + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + }, + { + "name": "mauler-open", + "delays": [ + [ + 0.5, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + }, + { + "name": "mauler-broken" + }, + { + "name": "odysseus", + "directions": 4 + }, + { + "name": "odysseus-open" + }, + { + "name": "odysseus-broken" + }, + { + "name": "firefighter", + "directions": 4 + }, + { + "name": "firefighter-open" + }, + { + "name": "firefighter-broken" + }, + { + "name": "deathripley", + "directions": 4 + }, + { + "name": "deathripley-open" + }, + { + "name": "deathripley-broken" + }, + { + "name": "darkgygax", + "directions": 4 + }, + { + "name": "darkgygax-open", + "delays": [ + [ + 0.1, + 0.05, + 0.05, + 0.05, + 0.1, + 0.05, + 0.05, + 0.05, + 0.1 + ] + ] + }, + { + "name": "darkgygax-broken", + "delays": [ + [ + 0.3, + 0.5, + 0.3, + 0.5, + 0.3, + 0.4, + 0.5, + 0.3 + ] + ] + }, + { + "name": "durand", + "directions": 4 + }, + { + "name": "durand-open", + "delays": [ + [ + 1, + 0.1, + 0.1, + 0.5, + 0.1, + 0.1 + ] + ] + }, + { + "name": "durand-broken", + "delays": [ + [ + 0.5, + 1, + 0.5, + 1 + ] + ] + }, + { + "name": "gygax", + "directions": 4 + }, + { + "name": "gygax-open", + "delays": [ + [ + 0.1, + 0.05, + 0.05, + 0.05, + 0.1, + 0.05, + 0.05, + 0.05, + 0.1 + ] + ] + }, + { + "name": "gygax-broken", + "delays": [ + [ + 5, + 0.05, + 0.05, + 0.05, + 0.1, + 0.1, + 0.5, + 0.1 + ] + ] + }, + { + "name": "ripley-g", + "directions": 4 + }, + { + "name": "ripley-g-open" + }, + { + "name": "ripley-g-full", + "directions": 4 + }, + { + "name": "ripley-g-full-open" + }, + { + "name": "darkhonker", + "directions": 4, + "delays": [ + [ + 1, + 1 + ], + [ + 1, + 1 + ], + [ + 1, + 1 + ], + [ + 1, + 1 + ] + ] + }, + { + "name": "darkhonker-open" + }, + { + "name": "darkhonker-broken" + }, + { + "name": "ripleymkii", + "directions": 4 + }, + { + "name": "ripleymkii-open" + }, + { + "name": "ripleymkii-broken" + }, + { + "name": "clarke", + "directions": 4, + "delays": [ + [ + 0.1, + 0.05, + 0.05 + ], + [ + 0.1, + 0.05, + 0.05 + ], + [ + 0.1, + 0.05, + 0.05 + ], + [ + 0.1, + 0.05, + 0.05 + ] + ] + }, + { + "name": "clarke-open" + }, + { + "name": "clarke-broken" + }, + { + "name": "hauler", + "directions": 4 + }, + { + "name": "hauler-empty", + "directions": 4 + }, + { + "name": "hauler-open" + }, + { + "name": "hauler-broken" + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/odysseus-broken.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/odysseus-broken.png new file mode 100644 index 0000000000..12a01c8a66 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/odysseus-broken.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/odysseus-open.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/odysseus-open.png new file mode 100644 index 0000000000..cdc13c60b9 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/odysseus-open.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/odysseus.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/odysseus.png new file mode 100644 index 0000000000..0daa691044 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/odysseus.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/phazon-broken.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/phazon-broken.png new file mode 100644 index 0000000000..cde4774f08 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/phazon-broken.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/phazon-open.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/phazon-open.png new file mode 100644 index 0000000000..804bd8a910 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/phazon-open.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/phazon-phase.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/phazon-phase.png new file mode 100644 index 0000000000..17c15ae1af Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/phazon-phase.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/phazon.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/phazon.png new file mode 100644 index 0000000000..558d23c224 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/phazon.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/reticence-broken.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/reticence-broken.png new file mode 100644 index 0000000000..b5ce0dc73f Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/reticence-broken.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/reticence-open.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/reticence-open.png new file mode 100644 index 0000000000..e72dc3f51a Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/reticence-open.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/reticence.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/reticence.png new file mode 100644 index 0000000000..d5fa5a8707 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/reticence.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley-broken-old.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley-broken-old.png new file mode 100644 index 0000000000..1e0357f677 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley-broken-old.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley-broken.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley-broken.png new file mode 100644 index 0000000000..1e0357f677 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley-broken.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley-empty.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley-empty.png new file mode 100644 index 0000000000..d66dd5b51c Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley-empty.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley-g-full-open.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley-g-full-open.png new file mode 100644 index 0000000000..ef0c66b44e Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley-g-full-open.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley-g-full.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley-g-full.png new file mode 100644 index 0000000000..41faa001a7 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley-g-full.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley-g-open.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley-g-open.png new file mode 100644 index 0000000000..fdb9c09458 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley-g-open.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley-g.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley-g.png new file mode 100644 index 0000000000..a01defab94 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley-g.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley-old.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley-old.png new file mode 100644 index 0000000000..dddcf1e729 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley-old.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley-open.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley-open.png new file mode 100644 index 0000000000..530553d413 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley-open.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley.png new file mode 100644 index 0000000000..221b21c44f Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripleymkii-broken.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripleymkii-broken.png new file mode 100644 index 0000000000..1e0357f677 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripleymkii-broken.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripleymkii-open.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripleymkii-open.png new file mode 100644 index 0000000000..85e7a8518f Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripleymkii-open.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripleymkii.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripleymkii.png new file mode 100644 index 0000000000..33e77e3a23 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripleymkii.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/seraph-broken.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/seraph-broken.png new file mode 100644 index 0000000000..4fc3f79776 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/seraph-broken.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/seraph-open.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/seraph-open.png new file mode 100644 index 0000000000..b5abfd86cb Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/seraph-open.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha.rsi/seraph.png b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/seraph.png new file mode 100644 index 0000000000..798e49c8df Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha.rsi/seraph.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_abooster_ccw.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_abooster_ccw.png new file mode 100644 index 0000000000..ce3f0984ff Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_abooster_ccw.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_abooster_proj.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_abooster_proj.png new file mode 100644 index 0000000000..fd877c05a5 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_abooster_proj.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_analyzer.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_analyzer.png new file mode 100644 index 0000000000..5a6a2194a1 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_analyzer.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_bananamrtr.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_bananamrtr.png new file mode 100644 index 0000000000..3ae7faff33 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_bananamrtr.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_carbine.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_carbine.png new file mode 100644 index 0000000000..1ff2c4c103 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_carbine.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_clamp.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_clamp.png new file mode 100644 index 0000000000..bf4fdc2f08 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_clamp.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_diamond_drill.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_diamond_drill.png new file mode 100644 index 0000000000..3daf22692e Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_diamond_drill.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_disabler.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_disabler.png new file mode 100644 index 0000000000..a2667dbcd7 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_disabler.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_drill.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_drill.png new file mode 100644 index 0000000000..3343ca8a4a Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_drill.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_exting.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_exting.png new file mode 100644 index 0000000000..78917605eb Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_exting.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_grenadelnchr.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_grenadelnchr.png new file mode 100644 index 0000000000..6148f6b1ad Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_grenadelnchr.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_honker.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_honker.png new file mode 100644 index 0000000000..ed489a07be Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_honker.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_ion.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_ion.png new file mode 100644 index 0000000000..a0f4bd05d6 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_ion.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_kineticgun.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_kineticgun.png new file mode 100644 index 0000000000..4118491385 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_kineticgun.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_laser.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_laser.png new file mode 100644 index 0000000000..f2fd7271b9 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_laser.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_medigun.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_medigun.png new file mode 100644 index 0000000000..42c03f13ca Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_medigun.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_mime.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_mime.png new file mode 100644 index 0000000000..d4278dfe7b Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_mime.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_missilerack.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_missilerack.png new file mode 100644 index 0000000000..d01da19be3 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_missilerack.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_missilerack_six.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_missilerack_six.png new file mode 100644 index 0000000000..d0f92bcaea Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_missilerack_six.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_mousetrapmrtr.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_mousetrapmrtr.png new file mode 100644 index 0000000000..c5dc07ac27 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_mousetrapmrtr.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_plasmacutter.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_plasmacutter.png new file mode 100644 index 0000000000..5b2947d14b Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_plasmacutter.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_pulse.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_pulse.png new file mode 100644 index 0000000000..0b7aed3c81 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_pulse.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_punching_glove.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_punching_glove.png new file mode 100644 index 0000000000..516e8ba3eb Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_punching_glove.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_rcd.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_rcd.png new file mode 100644 index 0000000000..b4709b7ed9 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_rcd.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_scatter.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_scatter.png new file mode 100644 index 0000000000..be45932fc3 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_scatter.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_taser.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_taser.png new file mode 100644 index 0000000000..374e5aa03f Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_taser.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_teleport.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_teleport.png new file mode 100644 index 0000000000..c2303b59c3 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_teleport.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_uac2.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_uac2.png new file mode 100644 index 0000000000..033126f12b Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_uac2.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_weapon_bay.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_weapon_bay.png new file mode 100644 index 0000000000..33262a970a Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_weapon_bay.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_wholegen.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_wholegen.png new file mode 100644 index 0000000000..2e68b9759c Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_wholegen.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_wire.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_wire.png new file mode 100644 index 0000000000..c6f3b140ab Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/mecha_wire.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/meta.json b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/meta.json new file mode 100644 index 0000000000..ecdce169b6 --- /dev/null +++ b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/meta.json @@ -0,0 +1,152 @@ +{ + "copyright" : "Taken from https://github.com/tgstation/tgstation at at https://github.com/tgstation/tgstation/commit/40d89d11ea4a5cb81d61dc1018b46f4e7d32c62a", + "license" : "CC-BY-SA-3.0", + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "mecha_mousetrapmrtr" + }, + { + "name": "mecha_bananamrtr" + }, + { + "name": "mecha_honker" + }, + { + "name": "mecha_mime" + }, + { + "name": "mecha_scatter" + }, + { + "name": "mecha_carbine" + }, + { + "name": "mecha_disabler" + }, + { + "name": "mecha_grenadelnchr" + }, + { + "name": "mecha_uac2" + }, + { + "name": "mecha_taser" + }, + { + "name": "mecha_pulse" + }, + { + "name": "mecha_laser" + }, + { + "name": "mecha_missilerack" + }, + { + "name": "mecha_teleport" + }, + { + "name": "mecha_exting" + }, + { + "name": "mecha_drill" + }, + { + "name": "mecha_diamond_drill" + }, + { + "name": "mecha_plasmacutter" + }, + { + "name": "mecha_clamp" + }, + { + "name": "mecha_wire" + }, + { + "name": "mecha_wholegen", + "delays": [ + [ + 0.2, + 0.2, + 0.2, + 0.2 + ] + ] + }, + { + "name": "mecha_rcd" + }, + { + "name": "repair_droid_a", + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + }, + { + "name": "repair_droid" + }, + { + "name": "mecha_abooster_ccw" + }, + { + "name": "mecha_abooster_proj" + }, + { + "name": "tesla" + }, + { + "name": "mecha_ion" + }, + { + "name": "mecha_analyzer" + }, + { + "name": "mecha_medigun" + }, + { + "name": "mecha_punching_glove" + }, + { + "name": "mecha_weapon_bay" + }, + { + "name": "ripleyupgrade" + }, + { + "name": "mecha_missilerack_six" + }, + { + "name": "thrusters" + }, + { + "name": "mecha_kineticgun" + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/repair_droid.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/repair_droid.png new file mode 100644 index 0000000000..da2cf5f1fb Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/repair_droid.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/repair_droid_a.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/repair_droid_a.png new file mode 100644 index 0000000000..b5ee463b59 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/repair_droid_a.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/ripleyupgrade.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/ripleyupgrade.png new file mode 100644 index 0000000000..7707402d78 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/ripleyupgrade.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/tesla.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/tesla.png new file mode 100644 index 0000000000..6fab61a534 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/tesla.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/thrusters.png b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/thrusters.png new file mode 100644 index 0000000000..2cc3486cad Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/mecha_equipment.rsi/thrusters.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/meta.json b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/meta.json new file mode 100644 index 0000000000..ec77ada562 --- /dev/null +++ b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/meta.json @@ -0,0 +1,98 @@ +{ + "copyright" : "Taken from https://github.com/tgstation/tgstation at at https://github.com/tgstation/tgstation/commit/40d89d11ea4a5cb81d61dc1018b46f4e7d32c62a", + "license" : "CC-BY-SA-3.0", + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "ripley_harness" + }, + { + "name": "ripley_harness+o" + }, + { + "name": "ripley_r_arm" + }, + { + "name": "ripley_r_arm+o" + }, + { + "name": "ripley_l_arm" + }, + { + "name": "ripley_l_arm+o" + }, + { + "name": "ripley_r_leg" + }, + { + "name": "ripley_r_leg+o" + }, + { + "name": "ripley_l_leg" + }, + { + "name": "ripley_l_leg+o" + }, + { + "name": "ripley0" + }, + { + "name": "ripley1" + }, + { + "name": "ripley2" + }, + { + "name": "ripley3" + }, + { + "name": "ripley4" + }, + { + "name": "ripley5" + }, + { + "name": "ripley6" + }, + { + "name": "ripley7" + }, + { + "name": "ripley8" + }, + { + "name": "ripley9" + }, + { + "name": "ripley10" + }, + { + "name": "ripley11" + }, + { + "name": "ripley12" + }, + { + "name": "ripley13" + }, + { + "name": "ripley14" + }, + { + "name": "ripley15" + }, + { + "name": "ripley16" + }, + { + "name": "ripley17" + }, + { + "name": "ripley18" + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley0.png b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley0.png new file mode 100644 index 0000000000..01601a288d Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley0.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley1.png b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley1.png new file mode 100644 index 0000000000..2a7ab1d762 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley1.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley10.png b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley10.png new file mode 100644 index 0000000000..2ffb27b9b1 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley10.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley11.png b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley11.png new file mode 100644 index 0000000000..883295d9ff Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley11.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley12.png b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley12.png new file mode 100644 index 0000000000..76ff6767f4 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley12.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley13.png b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley13.png new file mode 100644 index 0000000000..76ff6767f4 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley13.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley14.png b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley14.png new file mode 100644 index 0000000000..76ff6767f4 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley14.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley15.png b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley15.png new file mode 100644 index 0000000000..6260449569 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley15.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley16.png b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley16.png new file mode 100644 index 0000000000..76f6cfd264 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley16.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley17.png b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley17.png new file mode 100644 index 0000000000..a5bc876d84 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley17.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley18.png b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley18.png new file mode 100644 index 0000000000..c6ca3bddcd Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley18.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley2.png b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley2.png new file mode 100644 index 0000000000..ea4e806eb5 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley2.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley3.png b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley3.png new file mode 100644 index 0000000000..8507c83cbf Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley3.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley4.png b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley4.png new file mode 100644 index 0000000000..089e330fbf Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley4.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley5.png b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley5.png new file mode 100644 index 0000000000..3dd89c377b Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley5.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley6.png b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley6.png new file mode 100644 index 0000000000..857db6f803 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley6.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley7.png b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley7.png new file mode 100644 index 0000000000..ff13a670af Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley7.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley8.png b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley8.png new file mode 100644 index 0000000000..3dbd188439 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley8.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley9.png b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley9.png new file mode 100644 index 0000000000..0dfe4e1fc9 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley9.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_chassis.png b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_chassis.png new file mode 100644 index 0000000000..531ae1d850 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_chassis.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_harness+o.png b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_harness+o.png new file mode 100644 index 0000000000..9c2eb36cda Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_harness+o.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_harness.png b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_harness.png new file mode 100644 index 0000000000..de4a5f8a77 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_harness.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_l_arm+o.png b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_l_arm+o.png new file mode 100644 index 0000000000..a511f8f542 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_l_arm+o.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_l_arm.png b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_l_arm.png new file mode 100644 index 0000000000..41d2c83327 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_l_arm.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_l_leg+o.png b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_l_leg+o.png new file mode 100644 index 0000000000..c27a1ff245 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_l_leg+o.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_l_leg.png b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_l_leg.png new file mode 100644 index 0000000000..b030880c47 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_l_leg.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_r_arm+o.png b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_r_arm+o.png new file mode 100644 index 0000000000..0733c1cd5c Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_r_arm+o.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_r_arm.png b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_r_arm.png new file mode 100644 index 0000000000..b3897f0985 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_r_arm.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_r_leg+o.png b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_r_leg+o.png new file mode 100644 index 0000000000..0c75e70f83 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_r_leg+o.png differ diff --git a/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_r_leg.png b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_r_leg.png new file mode 100644 index 0000000000..0b0c3ff8e5 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_r_leg.png differ