diff --git a/Content.Client/Fax/System/FaxVisualsSystem.cs b/Content.Client/Fax/System/FaxVisualsSystem.cs new file mode 100644 index 00000000000000..892aec1d95490c --- /dev/null +++ b/Content.Client/Fax/System/FaxVisualsSystem.cs @@ -0,0 +1,48 @@ +using Robust.Client.GameObjects; +using Content.Shared.Fax.Components; +using Content.Shared.Fax; +using Robust.Client.Animations; + +namespace Content.Client.Fax.System; + +/// +/// Visualizer for the fax machine which displays the correct sprite based on the inserted entity. +/// +public sealed class FaxVisualsSystem : EntitySystem +{ + [Dependency] private readonly AnimationPlayerSystem _player = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnAppearanceChanged); + } + + private void OnAppearanceChanged(EntityUid uid, FaxMachineComponent component, ref AppearanceChangeEvent args) + { + if (args.Sprite == null) + return; + + if (_appearance.TryGetData(uid, FaxMachineVisuals.VisualState, out FaxMachineVisualState visuals) && visuals == FaxMachineVisualState.Inserting) + { + _player.Play(uid, new Animation() + { + Length = TimeSpan.FromSeconds(2.4), + AnimationTracks = + { + new AnimationTrackSpriteFlick() + { + LayerKey = FaxMachineVisuals.VisualState, + KeyFrames = + { + new AnimationTrackSpriteFlick.KeyFrame(component.InsertingState, 0f), + new AnimationTrackSpriteFlick.KeyFrame("icon", 2.4f), + } + } + } + }, "faxecute"); + } + } +} diff --git a/Content.Server/Chemistry/EntitySystems/TransformableContainerSystem.cs b/Content.Server/Chemistry/EntitySystems/TransformableContainerSystem.cs index 94a3fe2186168a..c375d97b8c3f7e 100644 --- a/Content.Server/Chemistry/EntitySystems/TransformableContainerSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/TransformableContainerSystem.cs @@ -20,7 +20,7 @@ public override void Initialize() SubscribeLocalEvent(OnSolutionChange); } - private void OnMapInit(Entity entity, ref MapInitEvent args) + private void OnMapInit(Entity entity, ref MapInitEvent args) { var meta = MetaData(entity.Owner); if (string.IsNullOrEmpty(entity.Comp.InitialName)) diff --git a/Content.Server/Fax/AdminUI/AdminFaxEui.cs b/Content.Server/Fax/AdminUI/AdminFaxEui.cs index c8be6618e45eda..5153e6219565af 100644 --- a/Content.Server/Fax/AdminUI/AdminFaxEui.cs +++ b/Content.Server/Fax/AdminUI/AdminFaxEui.cs @@ -1,6 +1,7 @@ using Content.Server.DeviceNetwork.Components; using Content.Server.EUI; using Content.Shared.Eui; +using Content.Shared.Fax.Components; using Content.Shared.Fax; using Content.Shared.Follower; using Content.Shared.Ghost; diff --git a/Content.Server/Fax/FaxSystem.cs b/Content.Server/Fax/FaxSystem.cs index f492595444aae5..c21e0db20cc5cf 100644 --- a/Content.Server/Fax/FaxSystem.cs +++ b/Content.Server/Fax/FaxSystem.cs @@ -16,7 +16,10 @@ using Content.Shared.Emag.Components; using Content.Shared.Emag.Systems; using Content.Shared.Fax; +using Content.Shared.Fax.Systems; +using Content.Shared.Fax.Components; using Content.Shared.Interaction; +using Content.Shared.Mobs.Components; using Content.Shared.Paper; using Robust.Server.GameObjects; using Robust.Shared.Audio; @@ -42,6 +45,7 @@ public sealed class FaxSystem : EntitySystem [Dependency] private readonly UserInterfaceSystem _userInterface = default!; [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; [Dependency] private readonly MetaDataSystem _metaData = default!; + [Dependency] private readonly FaxecuteSystem _faxecute = default!; private const string PaperSlotId = "Paper"; @@ -313,12 +317,18 @@ private void OnFileButtonPressed(EntityUid uid, FaxMachineComponent component, F private void OnCopyButtonPressed(EntityUid uid, FaxMachineComponent component, FaxCopyMessage args) { - Copy(uid, component, args); + if (HasComp(component.PaperSlot.Item)) + _faxecute.Faxecute(uid, component); /// when button pressed it will hurt the mob. + else + Copy(uid, component, args); } private void OnSendButtonPressed(EntityUid uid, FaxMachineComponent component, FaxSendMessage args) { - Send(uid, component, args.Actor); + if (HasComp(component.PaperSlot.Item)) + _faxecute.Faxecute(uid, component); /// when button pressed it will hurt the mob. + else + Send(uid, component, args.Actor); } private void OnRefreshButtonPressed(EntityUid uid, FaxMachineComponent component, FaxRefreshMessage args) @@ -336,14 +346,20 @@ private void UpdateAppearance(EntityUid uid, FaxMachineComponent? component = nu if (!Resolve(uid, ref component)) return; + if (TryComp(component.PaperSlot.Item, out var faxable)) + component.InsertingState = faxable.InsertingState; + + if (component.InsertingTimeRemaining > 0) + { _appearanceSystem.SetData(uid, FaxMachineVisuals.VisualState, FaxMachineVisualState.Inserting); + Dirty(uid, component); + } else if (component.PrintingTimeRemaining > 0) _appearanceSystem.SetData(uid, FaxMachineVisuals.VisualState, FaxMachineVisualState.Printing); else _appearanceSystem.SetData(uid, FaxMachineVisuals.VisualState, FaxMachineVisualState.Normal); } - private void UpdateUserInterface(EntityUid uid, FaxMachineComponent? component = null) { if (!Resolve(uid, ref component)) @@ -477,7 +493,7 @@ public void Send(EntityUid uid, FaxMachineComponent? component = null, EntityUid return; if (!TryComp(sendEntity, out var metadata) || - !TryComp(sendEntity, out var paper)) + !TryComp(sendEntity, out var paper)) return; var payload = new NetworkPayload() diff --git a/Content.Server/Nuke/NukeCodePaperSystem.cs b/Content.Server/Nuke/NukeCodePaperSystem.cs index 8df25feebfabca..c1725536e7cea3 100644 --- a/Content.Server/Nuke/NukeCodePaperSystem.cs +++ b/Content.Server/Nuke/NukeCodePaperSystem.cs @@ -1,6 +1,7 @@ using System.Diagnostics.CodeAnalysis; using Content.Server.Chat.Systems; using Content.Server.Fax; +using Content.Shared.Fax.Components; using Content.Server.Paper; using Content.Server.Station.Components; using Content.Server.Station.Systems; diff --git a/Content.Server/Fax/FaxMachineComponent.cs b/Content.Shared/Fax/Components/FaxMachineComponent.cs similarity index 84% rename from Content.Server/Fax/FaxMachineComponent.cs rename to Content.Shared/Fax/Components/FaxMachineComponent.cs index d1f269dd37055b..ee9459f5084057 100644 --- a/Content.Server/Fax/FaxMachineComponent.cs +++ b/Content.Shared/Fax/Components/FaxMachineComponent.cs @@ -1,12 +1,13 @@ using Content.Shared.Containers.ItemSlots; using Content.Shared.Paper; using Robust.Shared.Audio; +using Robust.Shared.GameStates; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Server.Fax; +namespace Content.Shared.Fax.Components; -[RegisterComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class FaxMachineComponent : Component { /// @@ -16,6 +17,13 @@ public sealed partial class FaxMachineComponent : Component [DataField("name")] public string FaxName { get; set; } = "Unknown"; + /// + /// Sprite to use when inserting an object. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField, AutoNetworkedField] + public string InsertingState = "inserting"; + /// /// Device address of fax in network to which data will be send /// @@ -26,7 +34,7 @@ public sealed partial class FaxMachineComponent : Component /// /// Contains the item to be sent, assumes it's paper... /// - [DataField("paperSlot", required: true)] + [DataField(required: true)] public ItemSlot PaperSlot = new(); /// @@ -34,39 +42,39 @@ public sealed partial class FaxMachineComponent : Component /// This will make it visible to others on the network /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("responsePings")] + [DataField] public bool ResponsePings { get; set; } = true; /// /// Should admins be notified on message receive /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("notifyAdmins")] + [DataField] public bool NotifyAdmins { get; set; } = false; /// /// Should that fax receive nuke codes send by admins. Probably should be captain fax only /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("receiveNukeCodes")] + [DataField] public bool ReceiveNukeCodes { get; set; } = false; /// /// Sound to play when fax has been emagged /// - [DataField("emagSound")] + [DataField] public SoundSpecifier EmagSound = new SoundCollectionSpecifier("sparks"); /// /// Sound to play when fax printing new message /// - [DataField("printSound")] + [DataField] public SoundSpecifier PrintSound = new SoundPathSpecifier("/Audio/Machines/printer.ogg"); /// /// Sound to play when fax successfully send message /// - [DataField("sendSound")] + [DataField] public SoundSpecifier SendSound = new SoundPathSpecifier("/Audio/Machines/high_tech_confirm.ogg"); /// @@ -79,27 +87,27 @@ public sealed partial class FaxMachineComponent : Component /// Print queue of the incoming message /// [ViewVariables] - [DataField("printingQueue")] + [DataField] public Queue PrintingQueue { get; private set; } = new(); /// /// Message sending timeout /// [ViewVariables] - [DataField("sendTimeoutRemaining")] + [DataField] public float SendTimeoutRemaining; /// /// Message sending timeout /// [ViewVariables] - [DataField("sendTimeout")] + [DataField] public float SendTimeout = 5f; /// /// Remaining time of inserting animation /// - [DataField("insertingTimeRemaining")] + [DataField] public float InsertingTimeRemaining; /// @@ -111,7 +119,7 @@ public sealed partial class FaxMachineComponent : Component /// /// Remaining time of printing animation /// - [DataField("printingTimeRemaining")] + [DataField] public float PrintingTimeRemaining; /// @@ -124,13 +132,13 @@ public sealed partial class FaxMachineComponent : Component [DataDefinition] public sealed partial class FaxPrintout { - [DataField("name", required: true)] + [DataField(required: true)] public string Name { get; private set; } = default!; - [DataField("content", required: true)] + [DataField(required: true)] public string Content { get; private set; } = default!; - [DataField("prototypeId", customTypeSerializer: typeof(PrototypeIdSerializer), required: true)] + [DataField(customTypeSerializer: typeof(PrototypeIdSerializer), required: true)] public string PrototypeId { get; private set; } = default!; [DataField("stampState")] diff --git a/Content.Shared/Fax/Components/FaxableObjectComponent.cs b/Content.Shared/Fax/Components/FaxableObjectComponent.cs new file mode 100644 index 00000000000000..57b6e610a329d0 --- /dev/null +++ b/Content.Shared/Fax/Components/FaxableObjectComponent.cs @@ -0,0 +1,16 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Fax.Components; +/// +/// Entity with this component can be faxed. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class FaxableObjectComponent : Component +{ + /// + /// Sprite to use when inserting an object. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField, AutoNetworkedField] + public string InsertingState = "inserting"; +} diff --git a/Content.Shared/Fax/Components/FaxecuteComponent.cs b/Content.Shared/Fax/Components/FaxecuteComponent.cs new file mode 100644 index 00000000000000..9c9bd0302033c0 --- /dev/null +++ b/Content.Shared/Fax/Components/FaxecuteComponent.cs @@ -0,0 +1,19 @@ +using Content.Shared.Damage; +using Robust.Shared.GameStates; + +namespace Content.Shared.Fax.Components; + +/// +/// A fax component which stores a damage specifier for attempting to fax a mob. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class FaxecuteComponent : Component +{ + + /// + /// Type of damage dealt when entity is faxecuted. + /// + [DataField(required: true), AutoNetworkedField] + public DamageSpecifier Damage = new(); +} + diff --git a/Content.Shared/Fax/DamageOnFaxecuteEvent.cs b/Content.Shared/Fax/DamageOnFaxecuteEvent.cs new file mode 100644 index 00000000000000..b36f55ab5d2846 --- /dev/null +++ b/Content.Shared/Fax/DamageOnFaxecuteEvent.cs @@ -0,0 +1,9 @@ + +namespace Content.Shared.Fax.Components; + +/// +/// Event for killing any mob within the fax machine. +/// +/// System for handling execution of a mob within fax when copy or send attempt is made. +/// +public sealed class FaxecuteSystem : EntitySystem +{ + [Dependency] private readonly DamageableSystem _damageable = default!; + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + + public override void Initialize() + { + base.Initialize(); + } + + public void Faxecute(EntityUid uid, FaxMachineComponent component, DamageOnFaxecuteEvent? args = null) + { + var sendEntity = component.PaperSlot.Item; + if (sendEntity == null) + return; + + if (!TryComp(uid, out var faxecute)) + return; + + var damageSpec = faxecute.Damage; + _damageable.TryChangeDamage(sendEntity, damageSpec); + _popupSystem.PopupEntity(Loc.GetString("fax-machine-popup-error", ("target", uid)), uid, PopupType.LargeCaution); + return; + + } +} diff --git a/Resources/Locale/en-US/fax/fax.ftl b/Resources/Locale/en-US/fax/fax.ftl index 1f1881a05d6ee9..412f3d7f435304 100644 --- a/Resources/Locale/en-US/fax/fax.ftl +++ b/Resources/Locale/en-US/fax/fax.ftl @@ -3,6 +3,8 @@ fax-machine-popup-received = Received correspondence from { $from }. fax-machine-popup-name-long = Fax name is too long fax-machine-popup-name-exist = Fax with same name already exist in network fax-machine-popup-name-set = Fax name has been updated +fax-machine-popup-error = ERROR - jam in paper feed +fax-machine-popup-copy-error = ERROR - unable to copy! fax-machine-dialog-rename = Rename fax-machine-dialog-field-name = Name diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index ad5b51d998d1a4..1cf56c29c6aea6 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -432,6 +432,8 @@ - type: Speech speechVerb: Moth speechSounds: Squeak + - type: FaxableObject + insertingState: inserting_mothroach - type: MothAccent - type: Sprite sprite: Mobs/Animals/mothroach.rsi @@ -1535,6 +1537,8 @@ rootTask: task: MouseCompound - type: Physics + - type: FaxableObject + insertingState: inserting_mouse - type: Fixtures fixtures: fix1: @@ -3049,6 +3053,8 @@ - type: Item size: Tiny - type: Physics + - type: FaxableObject + insertingState: inserting_hamster - type: Fixtures fixtures: fix1: diff --git a/Resources/Prototypes/Entities/Objects/Misc/paper.yml b/Resources/Prototypes/Entities/Objects/Misc/paper.yml index 08e5e3caafd90a..0c87459164a545 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/paper.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/paper.yml @@ -32,6 +32,7 @@ - Trash - Paper - type: Appearance + - type: FaxableObject - type: PaperVisuals - type: Flammable fireSpread: true diff --git a/Resources/Prototypes/Entities/Structures/Machines/fax_machine.yml b/Resources/Prototypes/Entities/Structures/Machines/fax_machine.yml index 583b5e3548a182..36be6451d20947 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/fax_machine.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/fax_machine.yml @@ -1,4 +1,4 @@ -- type: entity +- type: entity parent: BaseMachinePowered id: FaxMachineBase name: long range fax machine @@ -9,7 +9,7 @@ drawdepth: SmallObjects layers: - state: icon - map: ["base"] + map: [ "enum.FaxMachineVisuals.VisualState" ] - type: Icon sprite: Structures/Machines/fax_machine.rsi state: icon @@ -36,23 +36,27 @@ type: FaxBoundUi - type: ApcPowerReceiver powerLoad: 250 + - type: Faxecute + damage: + types: + Blunt: 100 - type: FaxMachine paperSlot: insertSound: /Audio/Machines/scanning.ogg ejectSound: /Audio/Machines/tray_eject.ogg whitelist: components: - - Paper + - FaxableObject #used to be PaperComponent - brainfood1183 - type: GenericVisualizer visuals: enum.PowerDeviceVisuals.Powered: - base: + enum.FaxMachineVisuals.VisualState: True: { state: idle } False: { state: icon } enum.FaxMachineVisuals.VisualState: - base: - Inserting: { state: inserting } + enum.FaxMachineVisuals.VisualState: Printing: { state: printing } + Normal: {state: idle} - type: ItemSlots - type: ContainerContainer containers: diff --git a/Resources/Textures/Structures/Machines/fax_machine.rsi/inserting_hamster.png b/Resources/Textures/Structures/Machines/fax_machine.rsi/inserting_hamster.png new file mode 100644 index 00000000000000..5f14e3013fe27a Binary files /dev/null and b/Resources/Textures/Structures/Machines/fax_machine.rsi/inserting_hamster.png differ diff --git a/Resources/Textures/Structures/Machines/fax_machine.rsi/inserting_mothroach.png b/Resources/Textures/Structures/Machines/fax_machine.rsi/inserting_mothroach.png new file mode 100644 index 00000000000000..d034322697ed03 Binary files /dev/null and b/Resources/Textures/Structures/Machines/fax_machine.rsi/inserting_mothroach.png differ diff --git a/Resources/Textures/Structures/Machines/fax_machine.rsi/inserting_mouse.png b/Resources/Textures/Structures/Machines/fax_machine.rsi/inserting_mouse.png new file mode 100644 index 00000000000000..7fb87053f3f250 Binary files /dev/null and b/Resources/Textures/Structures/Machines/fax_machine.rsi/inserting_mouse.png differ diff --git a/Resources/Textures/Structures/Machines/fax_machine.rsi/meta.json b/Resources/Textures/Structures/Machines/fax_machine.rsi/meta.json index 1a8856301d52af..00681ca6da1de1 100644 --- a/Resources/Textures/Structures/Machines/fax_machine.rsi/meta.json +++ b/Resources/Textures/Structures/Machines/fax_machine.rsi/meta.json @@ -40,6 +40,63 @@ ] ] }, + { + "name": "inserting_hamster", + "delays": [ + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ] + ] + }, + { + "name": "inserting_mothroach", + "delays": [ + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ] + ] + }, + { + "name": "inserting_mouse", + "delays": [ + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ] + ] + }, { "name": "printing", "delays": [