diff --git a/Content.Shared/_Arcadis/Computer/ComputerDiskComponent.cs b/Content.Shared/_Arcadis/Computer/ComputerDiskComponent.cs new file mode 100644 index 00000000000..5813c0342a8 --- /dev/null +++ b/Content.Shared/_Arcadis/Computer/ComputerDiskComponent.cs @@ -0,0 +1,23 @@ +using Robust.Shared.Audio; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared._Arcadis.Computer; + +/// +/// Main component for the ComputerDisk system +/// +[RegisterComponent, NetworkedComponent] +//[Access(typeof(ComputerDiskSystem))] +public sealed partial class ComputerDiskComponent : Component +{ + /// + /// The prototype of the computer that will be used + /// + [DataField] + public EntProtoId ProgramPrototype; + public EntityUid? ProgramPrototypeEntity; + + [DataField] + public bool PersistState; +} diff --git a/Content.Shared/_Arcadis/Computer/ModularComputerComponent.cs b/Content.Shared/_Arcadis/Computer/ModularComputerComponent.cs new file mode 100644 index 00000000000..de4fe5f2d24 --- /dev/null +++ b/Content.Shared/_Arcadis/Computer/ModularComputerComponent.cs @@ -0,0 +1,20 @@ +using Content.Shared.Containers.ItemSlots; +using Robust.Shared.Audio; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared._Arcadis.Computer; + +/// +/// Main component for the ComputerDisk system +/// +[RegisterComponent, NetworkedComponent] +//[Access(typeof(ComputerDiskSystem))] +public sealed partial class ModularComputerComponent : Component +{ + [DataField] + public string DiskSlot = "modularComputerDiskSlot"; + + [DataField] + public SoundSpecifier? DiskInsertSound = new SoundPathSpecifier("/Audio/_Arcadis/computer_startup.ogg"); +} diff --git a/Content.Shared/_Arcadis/Computer/ModularComputerSystem.cs b/Content.Shared/_Arcadis/Computer/ModularComputerSystem.cs new file mode 100644 index 00000000000..7a6d7742d11 --- /dev/null +++ b/Content.Shared/_Arcadis/Computer/ModularComputerSystem.cs @@ -0,0 +1,131 @@ +using Content.Shared.Containers.ItemSlots; +using Content.Shared.Coordinates; +using Robust.Shared.Audio; +using Content.Shared.Audio; +using Robust.Shared.Network; +using Robust.Shared.Containers; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Robust.Shared.Audio.Systems; +using Content.Shared.Popups; +using Content.Shared.Examine; +using Content.Shared.Interaction; +using Robust.Shared.Timing; + +namespace Content.Shared._Arcadis.Computer; + +public sealed class ModularComputerSystem : EntitySystem +{ + [Dependency] private readonly ItemSlotsSystem _itemSlots = default!; + + [Dependency] private readonly SharedAudioSystem _audioSystem = default!; + + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + + [Dependency] private readonly INetManager _netMan = default!; + + [Dependency] private readonly SharedTransformSystem _transform = default!; + + [Dependency] private readonly IGameTiming _gameTiming = default!; + + public string BlankDiskPrototype = "UnburnedDiskPrototype"; + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(InsertDisk); + SubscribeLocalEvent(OnActivate); + SubscribeLocalEvent(OnExamined); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + } + + private void OnExamined(EntityUid uid, ModularComputerComponent component, ExaminedEvent args) + { + if (!TryComp(uid, out ItemSlotsComponent? slots) + || !_itemSlots.TryGetSlot(uid, component.DiskSlot, out var diskSlot, slots)) + return; + + if (diskSlot.Item == null || !TryComp(diskSlot.Item, out ComputerDiskComponent? diskComp)) + { + args.PushMarkup(Loc.GetString("modular-computer-examine-no-disk")); + return; + } + + if (diskComp.ProgramPrototypeEntity == null) + { + args.PushMarkup(Loc.GetString("modular-computer-examine-disk-error")); + return; + } + + args.PushMarkup(Loc.GetString("modular-computer-examine-has-program", ("program", EntityManager.GetComponent(diskComp.ProgramPrototypeEntity.Value).EntityName))); + } + private void OnActivate(EntityUid uid, ModularComputerComponent component, ActivateInWorldEvent args) + { + // go figure it out yourself + if (!TryComp(uid, out ItemSlotsComponent? slots) + || !_itemSlots.TryGetSlot(uid, component.DiskSlot, out var diskSlot, slots)) + return; + + if (diskSlot.Item == null || !TryComp(diskSlot.Item, out ComputerDiskComponent? diskComp)) + { + _popupSystem.PopupPredicted(Loc.GetString("modular-computer-no-program"), uid, args.User); + return; + } + + if (diskComp.ProgramPrototypeEntity == null) + { + _popupSystem.PopupPredicted(Loc.GetString("modular-computer-no-program-on-disk"), uid, args.User); + return; + } + + if (_gameTiming.IsFirstTimePredicted || _netMan.IsServer) { + var activateMsg = new ActivateInWorldEvent(args.User, diskComp.ProgramPrototypeEntity.Value, true); + RaiseLocalEvent(diskComp.ProgramPrototypeEntity.Value, activateMsg); + } + } + + private void InsertDisk(EntityUid uid, ModularComputerComponent component, EntInsertedIntoContainerMessage args) + { + if (args.Container.ID != component.DiskSlot + || !TryComp(uid, out ItemSlotsComponent? slots) + || !_itemSlots.TryGetSlot(uid, component.DiskSlot, out var diskSlot, slots) + || diskSlot.Item is null + || !TryComp(diskSlot.Item, out ComputerDiskComponent? diskComp)) + return; + + UpdateComputer((uid, component), diskComp, diskSlot); + + if (diskComp.ProgramPrototypeEntity is null + || _netMan.IsClient) + return; + + _audioSystem.PlayPvs(component.DiskInsertSound, uid, AudioParams.Default.WithVolume(+4f)); + } + + + private void UpdateComputer(Entity computer, ComputerDiskComponent diskComp, ItemSlot diskSlot) + { + if (diskSlot.Item is null + || diskComp.ProgramPrototype == BlankDiskPrototype) + return; + + EntityUid magicComputerEntity; + + if (diskComp.ProgramPrototypeEntity == null || diskComp.PersistState != true) + { + if (diskComp.ProgramPrototypeEntity != null) + QueueDel(diskComp.ProgramPrototypeEntity.Value); + + magicComputerEntity = Spawn(diskComp.ProgramPrototype, computer.Owner.ToCoordinates()); + diskComp.ProgramPrototypeEntity = magicComputerEntity; + } + else + magicComputerEntity = diskComp.ProgramPrototypeEntity.Value; + + _transform.SetParent(magicComputerEntity, diskSlot.Item.Value); + } +} diff --git a/Resources/Audio/_Arcadis/computer_startup.ogg b/Resources/Audio/_Arcadis/computer_startup.ogg new file mode 100644 index 00000000000..53cfb4c4e57 Binary files /dev/null and b/Resources/Audio/_Arcadis/computer_startup.ogg differ diff --git a/Resources/Locale/en-US/_Arcadis/modularComputer.ftl b/Resources/Locale/en-US/_Arcadis/modularComputer.ftl new file mode 100644 index 00000000000..c3c60f3bb84 --- /dev/null +++ b/Resources/Locale/en-US/_Arcadis/modularComputer.ftl @@ -0,0 +1,5 @@ +modular-computer-no-program = ERROR: No program loaded! +modular-computer-no-program-on-disk = ERROR: No program on disk! +modular-computer-examine-no-disk = This computer doesn't have a program loaded. +modular-computer-examine-disk-error = This computer doesn't have a program loaded. An error on the display reports that the loaded disk has no program. +modular-computer-examine-has-program = This computer has the {$program} program loaded. diff --git a/Resources/Prototypes/_Arcadis/Entities/Objects/Computers/baseComputerModular.yml b/Resources/Prototypes/_Arcadis/Entities/Objects/Computers/baseComputerModular.yml new file mode 100644 index 00000000000..24c2f57d128 --- /dev/null +++ b/Resources/Prototypes/_Arcadis/Entities/Objects/Computers/baseComputerModular.yml @@ -0,0 +1,19 @@ +- type: entity + parent: BaseComputer + id: BaseComputerModular + name: modular computer + description: Part of a recent initiative to make computers less static. Comes with a disk slot for various "program disks". + components: + - type: ModularComputer + # I plan to make modular itemslots a thing in the future for stuff like the fax machine. Coming Soon:tm: + - type: ItemSlots + slots: + modularComputerDiskSlot: + name: Disk + insertSound: + path: /Audio/Machines/terminal_insert_disc.ogg + ejectSound: + path: /Audio/Machines/terminal_insert_disc.ogg + + + diff --git a/Resources/Prototypes/_Arcadis/Entities/Objects/Computers/computerDiskPrototypes.yml b/Resources/Prototypes/_Arcadis/Entities/Objects/Computers/computerDiskPrototypes.yml new file mode 100644 index 00000000000..d6df15c1dc2 --- /dev/null +++ b/Resources/Prototypes/_Arcadis/Entities/Objects/Computers/computerDiskPrototypes.yml @@ -0,0 +1,40 @@ +- type: entity + id: UnburnedDiskPrototype + name: unburned disk dummy prototype + categories: [HideSpawnMenu] + +- type: entity + id: CrewMonitorDiskPrototype + name: Crew Monitor + categories: [HideSpawnMenu] + components: + - type: ActivatableUI + key: enum.CrewMonitoringUIKey.Key + - type: UserInterface + interfaces: + enum.CrewMonitoringUIKey.Key: + type: CrewMonitoringBoundUserInterface + - type: CrewMonitoringConsole + - type: DeviceNetwork + deviceNetId: Wireless + receiveFrequencyId: CrewMonitor + - type: WirelessNetworkConnection + range: 1200 + +- type: entity + id: CommunicationsConsoleDiskPrototype + name: Communications Console + categories: [HideSpawnMenu] + components: + - type: AccessReader + access: [["Command"]] + - type: CommunicationsConsole + title: comms-console-announcement-title-station + - type: DeviceNetwork + transmitFrequencyId: ShuttleTimer + - type: ActivatableUI + key: enum.CommunicationsConsoleUiKey.Key + - type: UserInterface + interfaces: + enum.CommunicationsConsoleUiKey.Key: + type: CommunicationsConsoleBoundUserInterface diff --git a/Resources/Prototypes/_Arcadis/Entities/Objects/Computers/computerDisks.yml b/Resources/Prototypes/_Arcadis/Entities/Objects/Computers/computerDisks.yml new file mode 100644 index 00000000000..f742f46dc99 --- /dev/null +++ b/Resources/Prototypes/_Arcadis/Entities/Objects/Computers/computerDisks.yml @@ -0,0 +1,40 @@ +- type: entity + parent: BaseItem + id: BaseProgramDisk + abstract: true + name: program disk + components: + - type: Sprite + sprite: Objects/Misc/cd.rsi + state: icon + - type: ComputerDisk + saveData: false + +- type: entity + parent: BaseProgramDisk + id: ProgramDiskCrewMonitor + name: program disk (crew monitor) + description: A diskette for usage in a computer. This one has the "Crew Monitor" program burnt to it. + components: + - type: ComputerDisk + programPrototype: CrewMonitorDiskPrototype + persistState: true + +- type: entity + parent: BaseProgramDisk + id: ProgramDiskCommunicationsConsole + name: program disk (communications console) + description: A diskette for usage in a computer. This one has the "Communications Console" program burnt to it. + components: + - type: ComputerDisk + programPrototype: CommunicationsConsoleDiskPrototype + persistState: true + +- type: entity + parent: BaseProgramDisk + id: ProgramDiskUnburnt + name: program disk + description: A diskette for usage in a computer. This one has no program burnt to it. + components: + - type: ComputerDisk + programPrototype: UnburnedDiskPrototype