diff --git a/Content.Server/ADT/NightVision/NightVisionSystem.cs b/Content.Server/ADT/NightVision/NightVisionSystem.cs new file mode 100644 index 00000000000..5f6a3602a1c --- /dev/null +++ b/Content.Server/ADT/NightVision/NightVisionSystem.cs @@ -0,0 +1,7 @@ +// taken and adapted from https://github.com/RMC-14/RMC-14?ysclid=lzx00zxd6e53093995 + +using Content.Shared.ADT.NightVision; + +namespace Content.Server.ADT.NightVision; + +public sealed class NightVisionSystem : SharedNightVisionSystem; diff --git a/Content.Shared/ADT/NightVision/ADTNightVisionVisibleComponent.cs b/Content.Shared/ADT/NightVision/ADTNightVisionVisibleComponent.cs new file mode 100644 index 00000000000..6c5a997453e --- /dev/null +++ b/Content.Shared/ADT/NightVision/ADTNightVisionVisibleComponent.cs @@ -0,0 +1,25 @@ +// taken and adapted from https://github.com/RMC-14/RMC-14?ysclid=lzx00zxd6e53093995 + +using Robust.Shared.GameStates; + +namespace Content.Shared.ADT.NightVision; + +/// +/// For rendering sprites on top of FOV when the user has a . +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class NightVisionVisibleComponent : Component +{ + /// + /// Priority for rendering order. + /// Rendered from lowest to highest, which means higher numbers will be rendered above lower numbers. + /// + [DataField, AutoNetworkedField] + public int Priority = 0; + + /// + /// Transparency of the rendered sprite. + /// + [DataField, AutoNetworkedField] + public float? Transparency = null; +} diff --git a/Content.Shared/ADT/NightVision/NightVisionComponent.cs b/Content.Shared/ADT/NightVision/NightVisionComponent.cs new file mode 100644 index 00000000000..b0033594900 --- /dev/null +++ b/Content.Shared/ADT/NightVision/NightVisionComponent.cs @@ -0,0 +1,38 @@ +// taken and adapted from https://github.com/RMC-14/RMC-14?ysclid=lzx00zxd6e53093995 + +using Content.Shared.Alert; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; + +namespace Content.Shared.ADT.NightVision; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] +[Access(typeof(SharedNightVisionSystem))] +public sealed partial class NightVisionComponent : Component +{ + [DataField] + public ProtoId? Alert; + + [DataField, AutoNetworkedField] + public NightVisionState State = NightVisionState.Full; + + [DataField, AutoNetworkedField] + public bool Overlay; + + [DataField, AutoNetworkedField] + public bool Innate; + + [DataField, AutoNetworkedField] + public bool SeeThroughContainers; +} + +[Serializable, NetSerializable] +public enum NightVisionState +{ + Off, + Half, + Full +} + +public sealed partial class ToggleNightVision : BaseAlertEvent; diff --git a/Content.Shared/ADT/NightVision/NightVisionItemComponent.cs b/Content.Shared/ADT/NightVision/NightVisionItemComponent.cs new file mode 100644 index 00000000000..887d94c0a5a --- /dev/null +++ b/Content.Shared/ADT/NightVision/NightVisionItemComponent.cs @@ -0,0 +1,28 @@ +// taken and adapted from https://github.com/RMC-14/RMC-14?ysclid=lzx00zxd6e53093995 + +using Content.Shared.Inventory; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared.ADT.NightVision; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(SharedNightVisionSystem))] +public sealed partial class NightVisionItemComponent : Component +{ + [DataField, AutoNetworkedField] + public EntProtoId ActionId = "ActionToggleNinjaNightVision"; + + [DataField, AutoNetworkedField] + public EntityUid? Action; + + [DataField, AutoNetworkedField] + public EntityUid? User; + + [DataField, AutoNetworkedField] + public bool Toggleable = true; + + // Only allows for a single slotflag right now because some code uses strings and some code uses enums to determine slots :( + [DataField, AutoNetworkedField] + public SlotFlags SlotFlags { get; set; } = SlotFlags.EYES; +} diff --git a/Content.Shared/ADT/NightVision/NightVisionItemVisuals.cs b/Content.Shared/ADT/NightVision/NightVisionItemVisuals.cs new file mode 100644 index 00000000000..a0602cd1910 --- /dev/null +++ b/Content.Shared/ADT/NightVision/NightVisionItemVisuals.cs @@ -0,0 +1,11 @@ +// taken and adapted from https://github.com/RMC-14/RMC-14?ysclid=lzx00zxd6e53093995 + +using Robust.Shared.Serialization; + +namespace Content.Shared.ADT.NightVision; + +[Serializable, NetSerializable] +public enum NightVisionItemVisuals +{ + Active, +} diff --git a/Content.Shared/ADT/NightVision/SharedNightVisionSystem.cs b/Content.Shared/ADT/NightVision/SharedNightVisionSystem.cs new file mode 100644 index 00000000000..85a7bff3663 --- /dev/null +++ b/Content.Shared/ADT/NightVision/SharedNightVisionSystem.cs @@ -0,0 +1,201 @@ +// taken and adapted from https://github.com/RMC-14/RMC-14?ysclid=lzx00zxd6e53093995 + +using Content.Shared.Actions; +using Content.Shared.Alert; +using Content.Shared.Inventory.Events; +using Content.Shared.Rounding; +using Content.Shared.Toggleable; +using Robust.Shared.Timing; + +namespace Content.Shared.ADT.NightVision; + +public abstract class SharedNightVisionSystem : EntitySystem +{ + [Dependency] private readonly SharedActionsSystem _actions = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly AlertsSystem _alerts = default!; + [Dependency] private readonly IGameTiming _timing = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnNightVisionStartup); + SubscribeLocalEvent(OnNightVisionMapInit); + SubscribeLocalEvent(OnNightVisionAfterHandle); + SubscribeLocalEvent(OnNightVisionRemove); + + SubscribeLocalEvent(OnNightVisionItemGetActions); + SubscribeLocalEvent(OnNightVisionItemToggle); + SubscribeLocalEvent(OnNightVisionItemGotEquipped); + SubscribeLocalEvent(OnNightVisionItemGotUnequipped); + SubscribeLocalEvent(OnNightVisionItemActionRemoved); + SubscribeLocalEvent(OnNightVisionItemRemove); + SubscribeLocalEvent(OnNightVisionItemTerminating); + } + + private void OnNightVisionStartup(Entity ent, ref ComponentStartup args) + { + NightVisionChanged(ent); + } + + private void OnNightVisionAfterHandle(Entity ent, ref AfterAutoHandleStateEvent args) + { + NightVisionChanged(ent); + } + + private void OnNightVisionMapInit(Entity ent, ref MapInitEvent args) + { + UpdateAlert(ent); + } + + private void OnNightVisionRemove(Entity ent, ref ComponentRemove args) + { + if (ent.Comp.Alert is { } alert) + _alerts.ClearAlert(ent, alert); + + NightVisionRemoved(ent); + } + + private void OnNightVisionItemGetActions(Entity ent, ref GetItemActionsEvent args) + { + if (args.InHands || !ent.Comp.Toggleable) + return; + + if (ent.Comp.SlotFlags != args.SlotFlags) + return; + + args.AddAction(ref ent.Comp.Action, ent.Comp.ActionId); + } + + private void OnNightVisionItemToggle(Entity ent, ref ToggleActionEvent args) + { + if (args.Handled) + return; + + args.Handled = true; + ToggleNightVisionItem(ent, args.Performer); + } + + private void OnNightVisionItemGotEquipped(Entity ent, ref GotEquippedEvent args) + { + if (ent.Comp.SlotFlags != args.SlotFlags) + return; + + EnableNightVisionItem(ent, args.Equipee); + } + + private void OnNightVisionItemGotUnequipped(Entity ent, ref GotUnequippedEvent args) + { + if (ent.Comp.SlotFlags != args.SlotFlags) + return; + + DisableNightVisionItem(ent, args.Equipee); + } + + private void OnNightVisionItemActionRemoved(Entity ent, ref ActionRemovedEvent args) + { + DisableNightVisionItem(ent, ent.Comp.User); + } + + private void OnNightVisionItemRemove(Entity ent, ref ComponentRemove args) + { + DisableNightVisionItem(ent, ent.Comp.User); + } + + private void OnNightVisionItemTerminating(Entity ent, ref EntityTerminatingEvent args) + { + DisableNightVisionItem(ent, ent.Comp.User); + } + + public void Toggle(Entity ent) + { + if (!Resolve(ent, ref ent.Comp)) + return; + + ent.Comp.State = ent.Comp.State switch + { + NightVisionState.Off => NightVisionState.Half, + NightVisionState.Half => NightVisionState.Full, + NightVisionState.Full => NightVisionState.Off, + _ => throw new ArgumentOutOfRangeException(), + }; + + Dirty(ent); + UpdateAlert((ent, ent.Comp)); + } + + private void UpdateAlert(Entity ent) + { + if (ent.Comp.Alert is { } alert) + { + var level = MathF.Max((int) NightVisionState.Off, (int) ent.Comp.State); + var max = _alerts.GetMaxSeverity(alert); + var severity = max - ContentHelpers.RoundToLevels(level, (int) NightVisionState.Full, max + 1); + _alerts.ShowAlert(ent, alert, (short) severity); + } + + NightVisionChanged(ent); + } + + private void ToggleNightVisionItem(Entity item, EntityUid user) + { + if (item.Comp.User == user && item.Comp.Toggleable) + { + DisableNightVisionItem(item, item.Comp.User); + return; + } + + EnableNightVisionItem(item, user); + } + + private void EnableNightVisionItem(Entity item, EntityUid user) + { + DisableNightVisionItem(item, item.Comp.User); + + item.Comp.User = user; + Dirty(item); + + _appearance.SetData(item, NightVisionItemVisuals.Active, true); + + if (!_timing.ApplyingState) + { + var nightVision = EnsureComp(user); + nightVision.State = NightVisionState.Full; + Dirty(user, nightVision); + } + + _actions.SetToggled(item.Comp.Action, true); + } + + protected virtual void NightVisionChanged(Entity ent) + { + } + + protected virtual void NightVisionRemoved(Entity ent) + { + } + + protected void DisableNightVisionItem(Entity item, EntityUid? user) + { + _actions.SetToggled(item.Comp.Action, false); + + item.Comp.User = null; + Dirty(item); + + _appearance.SetData(item, NightVisionItemVisuals.Active, false); + + if (TryComp(user, out NightVisionComponent? nightVision) && + !nightVision.Innate) + { + RemCompDeferred(user.Value); + } + } + + public void SetSeeThroughContainers(Entity ent, bool see) + { + if (!Resolve(ent, ref ent.Comp, false)) + return; + + ent.Comp.SeeThroughContainers = see; + Dirty(ent); + } +} diff --git a/Content.Shared/ADT/NightVision/ToggleNightVision.cs b/Content.Shared/ADT/NightVision/ToggleNightVision.cs new file mode 100644 index 00000000000..45c739d015a --- /dev/null +++ b/Content.Shared/ADT/NightVision/ToggleNightVision.cs @@ -0,0 +1,13 @@ +//using Content.Shared.Alert; + +//namespace Content.Shared.ADT.NightVision; + +//[DataDefinition] +//public sealed partial class ToggleNightVision : IAlertClick +//{ +// public void AlertClicked(EntityUid player) +// { +// var entities = IoCManager.Resolve(); +// entities.System().Toggle(player); +// } +//} diff --git a/Resources/Prototypes/_Silver/Surgery/implants.yml b/Resources/Prototypes/_Silver/Surgery/implants.yml new file mode 100644 index 00000000000..259161659e0 --- /dev/null +++ b/Resources/Prototypes/_Silver/Surgery/implants.yml @@ -0,0 +1,38 @@ +# - type: NightVisionItem # RMC Night vision +# - type: ItemToggle + +- type: entity + parent: BasicCyberneticEyes + id: NightVisionCyberneticEyes + name: cybernetic eyes + description: A pair of cybernetic eyes that enhance your vision, and protect you from eye damage. + components: + - type: Organ + onAdd: + - type: InstantAction + icon: + sprite: Clothing/Eyes/Glasses/ninjavisor.rsi + state: icon + iconOn: + sprite: Clothing/Eyes/Glasses/ninjavisor.rsi + state: icon + event: !type:ToggleActionEvent + useDelay: 0.25 + - NightVisionComponent + - NightVisionItemComponent + +- type: entity + id: ActionToggleNinjaNightVision + categories: [HideSpawnMenu] + name: Toggle ninja visor nightvision + description: Allows you to see even in complete darkness. + components: + - type: InstantAction + icon: + sprite: Clothing/Eyes/Glasses/ninjavisor.rsi + state: icon + iconOn: + sprite: Clothing/Eyes/Glasses/ninjavisor.rsi + state: icon + event: !type:ToggleActionEvent + useDelay: 0.25 \ No newline at end of file diff --git a/Resources/Prototypes/_Silver/supermatter.yml b/Resources/Prototypes/_Silver/supermatter.yml index 7718bfe6521..b3b4612e0d3 100644 --- a/Resources/Prototypes/_Silver/supermatter.yml +++ b/Resources/Prototypes/_Silver/supermatter.yml @@ -61,3 +61,90 @@ maxIntensity: 25000 intensitySlope: 5 totalIntensity: 25000 + +- type: entity + id: SupermaterGenerator + description: Бессконечный источник электричества + name: суперматерьевый генератор + placement: + mode: SnapgridCenter + components: + - type: AmbientSound + range: 5 + sound: + path: /Audio/Ambience/Objects/engine_hum.ogg + - type: Clickable + - type: InteractionOutline + - type: Physics + bodyType: Static + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeAabb + bounds: "-0.4,-0.5,0.4,0.3" + density: 190 + mask: + - MachineMask + layer: + - MachineLayer + - type: Transform + anchored: true + noRot: true + - type: Sprite + sprite: Structures/Power/power.rsi + state: generator + snapCardinals: true + - type: NodeContainer + examinable: true + nodes: + output: + !type:CableDeviceNode + nodeGroupID: HVPower + - type: PowerMonitoringDevice + group: Generator + loadNode: output + sprite: _Silver\supermattergen.rsi + state: supermatter + - type: PowerSupplier + supplyRate: 30000 + supplyRampRate: 500 + supplyRampTolerance: 500 + - type: Anchorable + - type: Pullable + - type: Damageable + damageContainer: StructuralInorganic + damageModifierSet: Metallic + - type: PacifismDangerousAttack + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 200 + behaviors: + - !type:DoActsBehavior + acts: [ "Destruction" ] + - trigger: + !type:DamageTrigger + damage: 100 + behaviors: + - !type:DoActsBehavior + acts: ["Destruction"] + - !type:PlaySoundBehavior + sound: + collection: MetalBreak + - !type:ExplodeBehavior + - type: Explosive + explosionType: Default + # Same as AME, but numbers still picked from a hat. + maxIntensity: 300 + intensitySlope: 2 + totalIntensity: 600 + - type: StaticPrice + price: 500 + - type: Electrified + onHandInteract: false + onInteractUsing: false + onBump: false + requirePower: true + highVoltageNode: output \ No newline at end of file diff --git a/Resources/Textures/_Silver/supermattergen.rsi/meta.json b/Resources/Textures/_Silver/supermattergen.rsi/meta.json new file mode 100644 index 00000000000..7d982d8b585 --- /dev/null +++ b/Resources/Textures/_Silver/supermattergen.rsi/meta.json @@ -0,0 +1,14 @@ +{ + "version": 1, + "copyright": "Taken from https://github.com/tgstation/tgstation/blob/master/icons/obj/supermatter.dmi", + "license": "CC-BY-SA-3.0", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "supermatter" + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/_Silver/supermattergen.rsi/supermatter.png b/Resources/Textures/_Silver/supermattergen.rsi/supermatter.png new file mode 100644 index 00000000000..8447503b6e8 Binary files /dev/null and b/Resources/Textures/_Silver/supermattergen.rsi/supermatter.png differ