--- /dev/null
+using Robust.Client.GameObjects;
+using Content.Shared.Fax.Components;
+using Content.Shared.Fax;
+using Robust.Client.Animations;
+
+namespace Content.Client.Fax.System;
+
+/// <summary>
+/// Visualizer for the fax machine which displays the correct sprite based on the inserted entity.
+/// </summary>
+public sealed class FaxVisualsSystem : EntitySystem
+{
+ [Dependency] private readonly AnimationPlayerSystem _player = default!;
+ [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent<FaxMachineComponent, AppearanceChangeEvent>(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");
+ }
+ }
+}
SubscribeLocalEvent<TransformableContainerComponent, SolutionContainerChangedEvent>(OnSolutionChange);
}
- private void OnMapInit(Entity<TransformableContainerComponent> entity, ref MapInitEvent args)
+ private void OnMapInit(Entity<TransformableContainerComponent> entity, ref MapInitEvent args)
{
var meta = MetaData(entity.Owner);
if (string.IsNullOrEmpty(entity.Comp.InitialName))
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;
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;
[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";
private void OnCopyButtonPressed(EntityUid uid, FaxMachineComponent component, FaxCopyMessage args)
{
- Copy(uid, component, args);
+ if (HasComp<MobStateComponent>(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<MobStateComponent>(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)
if (!Resolve(uid, ref component))
return;
+ if (TryComp<FaxableObjectComponent>(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))
return;
if (!TryComp<MetaDataComponent>(sendEntity, out var metadata) ||
- !TryComp<PaperComponent>(sendEntity, out var paper))
+ !TryComp<PaperComponent>(sendEntity, out var paper))
return;
var payload = new NetworkPayload()
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;
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
{
/// <summary>
[DataField("name")]
public string FaxName { get; set; } = "Unknown";
+ /// <summary>
+ /// Sprite to use when inserting an object.
+ /// </summary>
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField, AutoNetworkedField]
+ public string InsertingState = "inserting";
+
/// <summary>
/// Device address of fax in network to which data will be send
/// </summary>
/// <summary>
/// Contains the item to be sent, assumes it's paper...
/// </summary>
- [DataField("paperSlot", required: true)]
+ [DataField(required: true)]
public ItemSlot PaperSlot = new();
/// <summary>
/// This will make it visible to others on the network
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
- [DataField("responsePings")]
+ [DataField]
public bool ResponsePings { get; set; } = true;
/// <summary>
/// Should admins be notified on message receive
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
- [DataField("notifyAdmins")]
+ [DataField]
public bool NotifyAdmins { get; set; } = false;
/// <summary>
/// Should that fax receive nuke codes send by admins. Probably should be captain fax only
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
- [DataField("receiveNukeCodes")]
+ [DataField]
public bool ReceiveNukeCodes { get; set; } = false;
/// <summary>
/// Sound to play when fax has been emagged
/// </summary>
- [DataField("emagSound")]
+ [DataField]
public SoundSpecifier EmagSound = new SoundCollectionSpecifier("sparks");
/// <summary>
/// Sound to play when fax printing new message
/// </summary>
- [DataField("printSound")]
+ [DataField]
public SoundSpecifier PrintSound = new SoundPathSpecifier("/Audio/Machines/printer.ogg");
/// <summary>
/// Sound to play when fax successfully send message
/// </summary>
- [DataField("sendSound")]
+ [DataField]
public SoundSpecifier SendSound = new SoundPathSpecifier("/Audio/Machines/high_tech_confirm.ogg");
/// <summary>
/// Print queue of the incoming message
/// </summary>
[ViewVariables]
- [DataField("printingQueue")]
+ [DataField]
public Queue<FaxPrintout> PrintingQueue { get; private set; } = new();
/// <summary>
/// Message sending timeout
/// </summary>
[ViewVariables]
- [DataField("sendTimeoutRemaining")]
+ [DataField]
public float SendTimeoutRemaining;
/// <summary>
/// Message sending timeout
/// </summary>
[ViewVariables]
- [DataField("sendTimeout")]
+ [DataField]
public float SendTimeout = 5f;
/// <summary>
/// Remaining time of inserting animation
/// </summary>
- [DataField("insertingTimeRemaining")]
+ [DataField]
public float InsertingTimeRemaining;
/// <summary>
/// <summary>
/// Remaining time of printing animation
/// </summary>
- [DataField("printingTimeRemaining")]
+ [DataField]
public float PrintingTimeRemaining;
/// <summary>
[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<EntityPrototype>), required: true)]
+ [DataField(customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>), required: true)]
public string PrototypeId { get; private set; } = default!;
[DataField("stampState")]
--- /dev/null
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Fax.Components;
+/// <summary>
+/// Entity with this component can be faxed.
+/// </summary>
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class FaxableObjectComponent : Component
+{
+ /// <summary>
+ /// Sprite to use when inserting an object.
+ /// </summary>
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField, AutoNetworkedField]
+ public string InsertingState = "inserting";
+}
--- /dev/null
+using Content.Shared.Damage;
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Fax.Components;
+
+/// <summary>
+/// A fax component which stores a damage specifier for attempting to fax a mob.
+/// </summary>
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class FaxecuteComponent : Component
+{
+
+ /// <summary>
+ /// Type of damage dealt when entity is faxecuted.
+ /// </summary>
+ [DataField(required: true), AutoNetworkedField]
+ public DamageSpecifier Damage = new();
+}
+
--- /dev/null
+
+namespace Content.Shared.Fax.Components;
+
+/// <summary>
+/// Event for killing any mob within the fax machine.
+/// </summary
+[ByRefEvent]
+public record struct DamageOnFaxecuteEvent(FaxMachineComponent? Action);
+
--- /dev/null
+using Content.Shared.Damage;
+using Content.Shared.Popups;
+using Content.Shared.Fax.Components;
+
+namespace Content.Shared.Fax.Systems;
+/// <summary>
+/// System for handling execution of a mob within fax when copy or send attempt is made.
+/// </summary>
+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<FaxecuteComponent>(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;
+
+ }
+}
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
- type: Speech
speechVerb: Moth
speechSounds: Squeak
+ - type: FaxableObject
+ insertingState: inserting_mothroach
- type: MothAccent
- type: Sprite
sprite: Mobs/Animals/mothroach.rsi
rootTask:
task: MouseCompound
- type: Physics
+ - type: FaxableObject
+ insertingState: inserting_mouse
- type: Fixtures
fixtures:
fix1:
- type: Item
size: Tiny
- type: Physics
+ - type: FaxableObject
+ insertingState: inserting_hamster
- type: Fixtures
fixtures:
fix1:
- Trash
- Paper
- type: Appearance
+ - type: FaxableObject
- type: PaperVisuals
- type: Flammable
fireSpread: true
-- type: entity
+- type: entity
parent: BaseMachinePowered
id: FaxMachineBase
name: long range fax machine
drawdepth: SmallObjects
layers:
- state: icon
- map: ["base"]
+ map: [ "enum.FaxMachineVisuals.VisualState" ]
- type: Icon
sprite: Structures/Machines/fax_machine.rsi
state: icon
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:
]
]
},
+ {
+ "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": [