diff --git a/Content.Server/Holosign/HolosignProjectorComponent.cs b/Content.Server/Holosign/HolosignProjectorComponent.cs new file mode 100644 index 0000000000..c85356e173 --- /dev/null +++ b/Content.Server/Holosign/HolosignProjectorComponent.cs @@ -0,0 +1,33 @@ +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Server.Holosign +{ + [RegisterComponent] + public sealed class HolosignProjectorComponent : Component + { + [ViewVariables] + [DataField("maxCharges")] + public int MaxCharges = 6; + + [ViewVariables(VVAccess.ReadWrite), DataField("charges")] + public int CurrentCharges = 6; + + [ViewVariables(VVAccess.ReadWrite)] + [DataField("signProto", customTypeSerializer:typeof(PrototypeIdSerializer))] + public string SignProto = "HolosignWetFloor"; + + /// + /// When the holosign was last used. + /// + [ViewVariables(VVAccess.ReadWrite), DataField("lastUse")] + public TimeSpan LastUsed = TimeSpan.Zero; + + /// + /// How long it takes for 1 charge to accumulate. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField("rechargeTime")] + public TimeSpan RechargeTime = TimeSpan.FromSeconds(30); + } +} diff --git a/Content.Server/Holosign/HolosignSystem.cs b/Content.Server/Holosign/HolosignSystem.cs new file mode 100644 index 0000000000..faa1deba4a --- /dev/null +++ b/Content.Server/Holosign/HolosignSystem.cs @@ -0,0 +1,57 @@ +using Content.Shared.Interaction.Events; +using Content.Shared.Examine; +using Content.Server.Coordinates.Helpers; +using Robust.Shared.Timing; + +namespace Content.Server.Holosign +{ + public sealed class HolosignSystem : EntitySystem + { + [Dependency] private readonly IGameTiming _timing = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnUse); + SubscribeLocalEvent(OnExamine); + } + + private int GetCharges(HolosignProjectorComponent component) + { + return component.CurrentCharges + (int) ((_timing.CurTime - component.LastUsed).TotalSeconds / component.RechargeTime.TotalSeconds); + } + + private void OnExamine(EntityUid uid, HolosignProjectorComponent component, ExaminedEvent args) + { + // TODO: This should probably be using an itemstatus + // TODO: I'm too lazy to do this rn but it's literally copy-paste from emag. + var timeRemaining = (component.LastUsed + component.RechargeTime * (component.MaxCharges - component.CurrentCharges) - _timing.CurTime).TotalSeconds % component.RechargeTime.TotalSeconds; + var charges = GetCharges(component); + + args.PushMarkup(Loc.GetString("emag-charges-remaining", ("charges", charges))); + if (charges == component.MaxCharges) + { + args.PushMarkup(Loc.GetString("emag-max-charges")); + return; + } + args.PushMarkup(Loc.GetString("emag-recharging", ("seconds", Math.Round(timeRemaining)))); + } + + private void OnUse(EntityUid uid, HolosignProjectorComponent component, UseInHandEvent args) + { + if (component.CurrentCharges == 0 || args.Handled) + return; + + // TODO: Too tired to deal + var holo = EntityManager.SpawnEntity(component.SignProto, Transform(args.User).Coordinates.SnapToGrid(EntityManager)); + Transform(holo).Anchored = true; + + // Don't reset last use time if it's already accumulating. + if (component.CurrentCharges == component.MaxCharges) + component.LastUsed = _timing.CurTime; + + component.CurrentCharges--; + args.Handled = true; + } + } +} diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/engineer.yml b/Resources/Prototypes/Catalog/Fills/Lockers/engineer.yml index b9d0f4a318..5360828ada 100644 --- a/Resources/Prototypes/Catalog/Fills/Lockers/engineer.yml +++ b/Resources/Prototypes/Catalog/Fills/Lockers/engineer.yml @@ -87,6 +87,7 @@ - id: ClothingHeadHelmetAtmosFire - id: GasAnalyzer - id: MedkitOxygenFilled + - id: HolofanProjector - type: entity id: LockerEngineerFilled diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/janidrobe.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/janidrobe.yml index 85fac386af..db5762ac54 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/janidrobe.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/janidrobe.yml @@ -15,5 +15,6 @@ ClothingBeltJanitor: 2 ClothingHeadsetService: 2 ClothingOuterWinterJani: 2 + Holoprojector: 1 emaggedInventory: ClothingUniformJumpskirtJanimaid: 2 diff --git a/Resources/Prototypes/Entities/Objects/Devices/holoprojectors.yml b/Resources/Prototypes/Entities/Objects/Devices/holoprojectors.yml new file mode 100644 index 0000000000..f939c1bfe0 --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Devices/holoprojectors.yml @@ -0,0 +1,23 @@ +- type: entity + parent: BaseItem + id: Holoprojector + name: holographic sign projector + description: A handy-dandy holographic projector that displays a janitorial sign. + components: + - type: HolosignProjector + - type: Sprite + sprite: Objects/Devices/Holoprojectors/custodial.rsi + state: icon + +- type: entity + parent: Holoprojector + id: HolofanProjector + name: holofan projector + description: Stop suicidal passengers from killing everyone during atmos emergencies. + components: + - type: HolosignProjector + signProto: HoloFan + rechargeTime: 120 + - type: Sprite + sprite: Objects/Devices/Holoprojectors/atmos.rsi + state: icon diff --git a/Resources/Prototypes/Entities/Structures/Holographic/projections.yml b/Resources/Prototypes/Entities/Structures/Holographic/projections.yml new file mode 100644 index 0000000000..3029ecf2c4 --- /dev/null +++ b/Resources/Prototypes/Entities/Structures/Holographic/projections.yml @@ -0,0 +1,33 @@ +- type: entity + id: HolosignWetFloor + name: wet floor sign + description: The words flicker as if they mean nothing. + components: + - type: Physics + bodyType: Static + - type: Sprite + sprite: Structures/Holo/wetfloor.rsi + state: icon + netsync: false + - type: TimedDespawn + lifetime: 30 + +- type: entity + id: HoloFan + parent: HolosignWetFloor + name: holofan + description: A barrier of hard light that blocks air, but nothing else. + components: + - type: Sprite + sprite: Structures/Holo/holofan.rsi + state: icon + netsync: false + - type: Fixtures + fixtures: + - shape: + !type:PhysShapeAabb + bounds: "-0.5,-0.5,0.5,0.5" + - type: TimedDespawn + lifetime: 180 + - type: Airtight + noAirWhenFullyAirBlocked: false diff --git a/Resources/Textures/Objects/Devices/Holoprojectors/atmos.rsi/icon.png b/Resources/Textures/Objects/Devices/Holoprojectors/atmos.rsi/icon.png new file mode 100644 index 0000000000..eda050ce88 Binary files /dev/null and b/Resources/Textures/Objects/Devices/Holoprojectors/atmos.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Devices/Holoprojectors/atmos.rsi/meta.json b/Resources/Textures/Objects/Devices/Holoprojectors/atmos.rsi/meta.json new file mode 100644 index 0000000000..e887fb6907 --- /dev/null +++ b/Resources/Textures/Objects/Devices/Holoprojectors/atmos.rsi/meta.json @@ -0,0 +1,22 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/40d89d11ea4a5cb81d61dc1018b46f4e7d32c62a", + "states": [ + { + "name": "icon", + "delays": [ + [ + 0.3, + 0.3, + 0.3, + 0.3 + ] + ] + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Objects/Devices/Holoprojectors/custodial.rsi/icon.png b/Resources/Textures/Objects/Devices/Holoprojectors/custodial.rsi/icon.png new file mode 100644 index 0000000000..38d6732bda Binary files /dev/null and b/Resources/Textures/Objects/Devices/Holoprojectors/custodial.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Devices/Holoprojectors/custodial.rsi/meta.json b/Resources/Textures/Objects/Devices/Holoprojectors/custodial.rsi/meta.json new file mode 100644 index 0000000000..e887fb6907 --- /dev/null +++ b/Resources/Textures/Objects/Devices/Holoprojectors/custodial.rsi/meta.json @@ -0,0 +1,22 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/40d89d11ea4a5cb81d61dc1018b46f4e7d32c62a", + "states": [ + { + "name": "icon", + "delays": [ + [ + 0.3, + 0.3, + 0.3, + 0.3 + ] + ] + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Structures/Holo/holofan.rsi/icon.png b/Resources/Textures/Structures/Holo/holofan.rsi/icon.png new file mode 100644 index 0000000000..5c8c069c37 Binary files /dev/null and b/Resources/Textures/Structures/Holo/holofan.rsi/icon.png differ diff --git a/Resources/Textures/Structures/Holo/holofan.rsi/meta.json b/Resources/Textures/Structures/Holo/holofan.rsi/meta.json new file mode 100644 index 0000000000..cea3bbf1a0 --- /dev/null +++ b/Resources/Textures/Structures/Holo/holofan.rsi/meta.json @@ -0,0 +1,30 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/40d89d11ea4a5cb81d61dc1018b46f4e7d32c62a", + "states": [ + { + "name": "icon", + "delays": [ + [ + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3 + ] + ] + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Structures/Holo/wetfloor.rsi/icon.png b/Resources/Textures/Structures/Holo/wetfloor.rsi/icon.png new file mode 100644 index 0000000000..57c6b72357 Binary files /dev/null and b/Resources/Textures/Structures/Holo/wetfloor.rsi/icon.png differ diff --git a/Resources/Textures/Structures/Holo/wetfloor.rsi/meta.json b/Resources/Textures/Structures/Holo/wetfloor.rsi/meta.json new file mode 100644 index 0000000000..cea3bbf1a0 --- /dev/null +++ b/Resources/Textures/Structures/Holo/wetfloor.rsi/meta.json @@ -0,0 +1,30 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/40d89d11ea4a5cb81d61dc1018b46f4e7d32c62a", + "states": [ + { + "name": "icon", + "delays": [ + [ + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3 + ] + ] + } + ] +} \ No newline at end of file