diff --git a/Content.Client/_Pirate/Weapons/Ranged/Upgrades/GunFlashlightAttachmentVisualizerSystem.cs b/Content.Client/_Pirate/Weapons/Ranged/Upgrades/GunFlashlightAttachmentVisualizerSystem.cs new file mode 100644 index 000000000000..e98a825ad304 --- /dev/null +++ b/Content.Client/_Pirate/Weapons/Ranged/Upgrades/GunFlashlightAttachmentVisualizerSystem.cs @@ -0,0 +1,78 @@ +// SPDX-FileCopyrightText: 2026 +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Content.Shared._Pirate.Weapons.Ranged.Upgrades; +using Content.Shared._Pirate.Weapons.Ranged.Upgrades.Components; +using Robust.Client.GameObjects; +using Robust.Shared.GameObjects; + +namespace Content.Client._Pirate.Weapons.Ranged.Upgrades; + +public sealed class GunFlashlightAttachmentVisualizerSystem : EntitySystem +{ + [Dependency] private readonly SpriteSystem _sprite = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + + private const string LayerKey = "gun_flashlight"; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnStartup); + SubscribeLocalEvent(OnAppearanceChange); + } + + private void OnStartup(EntityUid uid, GunFlashlightAttachmentComponent component, ComponentStartup args) + { + if (!TryComp(uid, out var sprite)) + return; + + EnsureLayer((uid, sprite), component); + UpdateLayer((uid, sprite), component, attached: false, lightOn: false); + } + + private void OnAppearanceChange(EntityUid uid, GunFlashlightAttachmentComponent component, ref AppearanceChangeEvent args) + { + if (!TryComp(uid, out var sprite)) + return; + + if (!_appearance.TryGetData(uid, GunFlashlightVisuals.Attached, out var attached, args.Component)) + attached = false; + + if (!_appearance.TryGetData(uid, GunFlashlightVisuals.LightOn, out var lightOn, args.Component)) + lightOn = false; + + EnsureLayer((uid, sprite), component); + UpdateLayer((uid, sprite), component, attached, lightOn); + } + + private void EnsureLayer(Entity ent, GunFlashlightAttachmentComponent component) + { + if (_sprite.LayerMapTryGet(ent, LayerKey, out _, false)) + return; + + var index = _sprite.LayerMapReserve(ent, LayerKey); + _sprite.LayerSetData(ent, index, new PrototypeLayerData + { + RsiPath = component.Sprite.ToString(), + State = component.StateOff, + Offset = component.Offset, + Visible = false + }); + } + + private void UpdateLayer(Entity ent, GunFlashlightAttachmentComponent component, bool attached, bool lightOn) + { + if (!_sprite.LayerMapTryGet(ent, LayerKey, out var index, false)) + return; + + _sprite.LayerSetData(ent, index, new PrototypeLayerData + { + RsiPath = component.Sprite.ToString(), + State = lightOn ? component.StateOn : component.StateOff, + Offset = component.Offset, + Visible = attached + }); + } +} diff --git a/Content.Server/_Lavaland/Weapons/Ranged/Upgrades/GunUpgradeSystem.cs b/Content.Server/_Lavaland/Weapons/Ranged/Upgrades/GunUpgradeSystem.cs index 24d43a579351..c9f0df10f177 100644 --- a/Content.Server/_Lavaland/Weapons/Ranged/Upgrades/GunUpgradeSystem.cs +++ b/Content.Server/_Lavaland/Weapons/Ranged/Upgrades/GunUpgradeSystem.cs @@ -31,6 +31,15 @@ using Content.Shared.Weapons.Melee.Events; using Content.Shared.Weapons.Ranged.Systems; using Robust.Shared.Containers; +#region DOWNSTREAM-TPirates: gun flashlights +using Content.Shared.Actions; +using Content.Shared.Actions.Components; +using Content.Shared.Hands.Components; +using Content.Shared.Light.Components; +using Content.Shared._Pirate.Weapons.Ranged.Upgrades; +using Content.Shared.Toggleable; +using Robust.Shared.GameObjects; +#endregion namespace Content.Server._Lavaland.Weapons.Ranged.Upgrades; @@ -38,6 +47,12 @@ public sealed class GunUpgradeSystem : SharedGunUpgradeSystem { [Dependency] private readonly PressureEfficiencyChangeSystem _pressure = default!; [Dependency] private readonly EntityEffectSystem _entityEffect = default!; + #region DOWNSTREAM-TPirates: gun flashlights + [Dependency] private readonly SharedActionsSystem _actions = default!; + [Dependency] private readonly ActionContainerSystem _actionContainer = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly SharedContainerSystem _containers = default!; + #endregion public override void Initialize() { @@ -47,6 +62,12 @@ public override void Initialize() SubscribeLocalEvent(OnProjectileShot); SubscribeLocalEvent(OnPressureUpgradeInserted); SubscribeLocalEvent(OnPressureUpgradeRemoved); + #region DOWNSTREAM-TPirates: gun flashlights + SubscribeLocalEvent(OnFlashlightInserted); + SubscribeLocalEvent(OnFlashlightRemoved); + SubscribeLocalEvent(OnFlashlightToggled, + after: new[] { typeof(Content.Server.Light.EntitySystems.HandheldLightSystem) }); + #endregion SubscribeLocalEvent(OnEffectsUpgradeHit); } @@ -131,4 +152,118 @@ private void OnEffectsUpgradeHit(Entity ent, ref } } } + + #region DOWNSTREAM-TPirates: gun flashlights + private void OnFlashlightInserted(Entity ent, ref EntGotInsertedIntoContainerMessage args) + { + if (args.Container.ID != "flashlight") + return; + + if (!TryComp(args.Container.Owner, out _)) + return; + + if (!TryComp(ent, out var handheld) + || handheld.ToggleActionEntity == null) + return; + + if (!TryComp(handheld.ToggleActionEntity.Value, out var action)) + return; + + ent.Comp.OriginalItemIconStyle = action.ItemIconStyle; + ent.Comp.OriginalUseDelay = action.UseDelay; + ent.Comp.HasSavedActionDefaults = true; + + _actions.SetEntityIcon((handheld.ToggleActionEntity.Value, action), args.Container.Owner); + _actions.SetItemIconStyle((handheld.ToggleActionEntity.Value, action), ItemActionIconStyle.BigItem); + _actions.SetUseDelay((handheld.ToggleActionEntity.Value, action), null); + SetGunFlashlightVisuals(args.Container.Owner, attached: true, on: handheld.Activated); + GrantUpgradeActionsIfHeld(args.Container.Owner); + } + + private void OnFlashlightRemoved(Entity ent, ref EntGotRemovedFromContainerMessage args) + { + if (args.Container.ID != "flashlight") + return; + + if (TryComp(ent, out var handheld) + && handheld.ToggleActionEntity is { } toggleAction + && TryComp(toggleAction, out var action)) + { + if (ent.Comp.HasSavedActionDefaults) + { + _actions.SetItemIconStyle((toggleAction, action), ent.Comp.OriginalItemIconStyle); + _actions.SetUseDelay((toggleAction, action), ent.Comp.OriginalUseDelay); + ent.Comp.HasSavedActionDefaults = false; + } + + if (action.EntIcon == args.Container.Owner) + _actions.SetEntityIcon((toggleAction, action), null); + + if (_containers.TryGetContainingContainer((args.Container.Owner, Transform(args.Container.Owner), MetaData(args.Container.Owner)), out var gunContainer) + && TryComp(gunContainer.Owner, out _) + && action.AttachedEntity == gunContainer.Owner) + { + _actions.RemoveAction((gunContainer.Owner, CompOrNull(gunContainer.Owner)), (toggleAction, action)); + } + } + + SetGunFlashlightVisuals(args.Container.Owner, attached: false, on: false); + } + + private void OnFlashlightToggled(Entity ent, ref ToggleActionEvent args) + { + if (!TryComp(ent, out var handheld)) + return; + + if (!TryGetContainingGun(ent.Owner, out var gun)) + return; + + SetGunFlashlightVisuals(gun, attached: true, on: handheld.Activated); + } + + private bool TryGetContainingGun(EntityUid flashlight, out EntityUid gun) + { + gun = default; + + if (!_containers.TryGetContainingContainer((flashlight, Transform(flashlight), MetaData(flashlight)), out var container)) + return false; + + if (container.ID != "flashlight") + return false; + + if (!TryComp(container.Owner, out _)) + return false; + + gun = container.Owner; + return true; + } + + private void SetGunFlashlightVisuals(EntityUid gun, bool attached, bool on) + { + if (!TryComp(gun, out var appearance)) + return; + + _appearance.SetData(gun, GunFlashlightVisuals.Attached, attached, appearance); + _appearance.SetData(gun, GunFlashlightVisuals.LightOn, on, appearance); + } + + private void GrantUpgradeActionsIfHeld(EntityUid gun) + { + if (!_containers.TryGetContainingContainer((gun, Transform(gun), MetaData(gun)), out var container)) + return; + + var holder = container.Owner; + if (!TryComp(holder, out _)) + return; + + var ev = new GetItemActionsEvent(_actionContainer, holder, gun); + RaiseLocalEvent(gun, ev); + if (ev.Actions.Count == 0) + return; + + EnsureComp(gun); + _actions.GrantActions((holder, CompOrNull(holder)), ev.Actions, gun); + _actions.LoadActions(holder); + } + #endregion } diff --git a/Content.Shared/Actions/SharedActionsSystem.cs b/Content.Shared/Actions/SharedActionsSystem.cs index 9eeac71bc089..75b032cacc03 100644 --- a/Content.Shared/Actions/SharedActionsSystem.cs +++ b/Content.Shared/Actions/SharedActionsSystem.cs @@ -1199,6 +1199,18 @@ public void SetIconColor(Entity ent, Color color) DirtyField(ent, ent.Comp, nameof(ActionComponent.IconColor)); } + + #region DOWNSTREAM-TPirates: gun flashlights + public void SetItemIconStyle(Entity ent, ItemActionIconStyle style) + { + if (!_actionQuery.Resolve(ent, ref ent.Comp) || ent.Comp.ItemIconStyle == style) + return; + + ent.Comp.ItemIconStyle = style; + DirtyField(ent, ent.Comp, nameof(ActionComponent.ItemIconStyle)); + } + #endregion + /// /// Set the event of an action. /// Since the event isn't required to be serializable this is not networked. diff --git a/Content.Shared/_Lavaland/Weapons/Ranged/Upgrades/Components/GunUpgradeFlashlightComponent.cs b/Content.Shared/_Lavaland/Weapons/Ranged/Upgrades/Components/GunUpgradeFlashlightComponent.cs index 4c6d7bc0b6d3..5594b5939e33 100644 --- a/Content.Shared/_Lavaland/Weapons/Ranged/Upgrades/Components/GunUpgradeFlashlightComponent.cs +++ b/Content.Shared/_Lavaland/Weapons/Ranged/Upgrades/Components/GunUpgradeFlashlightComponent.cs @@ -19,6 +19,8 @@ // // SPDX-License-Identifier: AGPL-3.0-or-later +using System; +using Content.Shared.Actions.Components; using Robust.Shared.GameStates; namespace Content.Shared._Lavaland.Weapons.Ranged.Upgrades.Components; @@ -27,4 +29,20 @@ namespace Content.Shared._Lavaland.Weapons.Ranged.Upgrades.Components; /// Component to indicate a valid flashlight for weapon attachment /// [RegisterComponent, NetworkedComponent] -public sealed partial class GunUpgradeFlashlightComponent : Component; +public sealed partial class GunUpgradeFlashlightComponent : Component +{ + /// + /// Original action icon style before this flashlight was attached to a gun. + /// + public ItemActionIconStyle OriginalItemIconStyle = ItemActionIconStyle.NoItem; + + /// + /// Original use delay before this flashlight was attached to a gun. + /// + public TimeSpan? OriginalUseDelay; + + /// + /// True after original action visual/use settings were captured on insert. + /// + public bool HasSavedActionDefaults; +} diff --git a/Content.Shared/_Pirate/Weapons/Ranged/Upgrades/Components/GunFlashlightAttachmentComponent.cs b/Content.Shared/_Pirate/Weapons/Ranged/Upgrades/Components/GunFlashlightAttachmentComponent.cs new file mode 100644 index 000000000000..9faf1f84a8ff --- /dev/null +++ b/Content.Shared/_Pirate/Weapons/Ranged/Upgrades/Components/GunFlashlightAttachmentComponent.cs @@ -0,0 +1,27 @@ +// SPDX-FileCopyrightText: 2026 +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System.Numerics; +using Robust.Shared.Utility; + +namespace Content.Shared._Pirate.Weapons.Ranged.Upgrades.Components; + +/// +/// Configures flashlight overlay visuals for a gun. +/// +[RegisterComponent] +public sealed partial class GunFlashlightAttachmentComponent : Component +{ + [DataField("sprite")] + public ResPath Sprite = new("/Textures/_Pirate/Objects/Weapons/Guns/Upgrades/gun_flashlight_attachment.rsi"); + + [DataField("stateOff")] + public string StateOff = "flight"; + + [DataField("stateOn")] + public string StateOn = "flight-on"; + + [DataField("offset")] + public Vector2 Offset = Vector2.Zero; +} diff --git a/Content.Shared/_Pirate/Weapons/Ranged/Upgrades/GunFlashlightVisuals.cs b/Content.Shared/_Pirate/Weapons/Ranged/Upgrades/GunFlashlightVisuals.cs new file mode 100644 index 000000000000..6b7ba0083521 --- /dev/null +++ b/Content.Shared/_Pirate/Weapons/Ranged/Upgrades/GunFlashlightVisuals.cs @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2026 +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Robust.Shared.Serialization; + +namespace Content.Shared._Pirate.Weapons.Ranged.Upgrades; + +[Serializable, NetSerializable] +public enum GunFlashlightVisuals : byte +{ + Attached, + LightOn +} diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml index de6620c624da..2ea32005a37b 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml @@ -403,6 +403,8 @@ - state: mag-unshaded-4 map: ["enum.GunVisualLayers.MagUnshaded"] shader: unshaded + - type: GunFlashlightAttachment # DOWNSTREAM-TPirates: gun flashlights + offset: "0.03125, 0.09375" - type: RestrictGunshotsByUserTag # Goobstation doesntContain: - Oni @@ -423,7 +425,20 @@ - type: Battery maxCharge: 500 startingCharge: 500 - + - type: UpgradeableWeapon # DOWNSTREAM-TPirates: gun flashlights + - type: ItemSlots # DOWNSTREAM-TPirates: gun flashlights + slots: + flashlight: + name: weapon-upgrade-slot-name-flashlight + priority: 5 + ejectOnBreak: true + occludesLight: false + whitelist: + components: + - GunUpgradeFlashlight + - type: ContainerContainer # DOWNSTREAM-TPirates: gun flashlights + containers: + flashlight: !type:ContainerSlot - type: entity name: tesla gun parent: [BaseWeaponBattery, BaseMajorContraband] @@ -538,6 +553,8 @@ - state: mag-unshaded-4 map: ["enum.GunVisualLayers.MagUnshaded"] shader: unshaded + - type: GunFlashlightAttachment # DOWNSTREAM-TPirates: gun flashlights + offset: "0, 0.09375" - type: MagazineVisuals magState: mag steps: 5 @@ -560,7 +577,20 @@ - type: BatterySelfRecharger # Goobstation - CentComm Job Revamp autoRecharge: true autoRechargeRate: 40 - + - type: UpgradeableWeapon # DOWNSTREAM-TPirates: gun flashlights + - type: ItemSlots # DOWNSTREAM-TPirates: gun flashlights + slots: + flashlight: + name: weapon-upgrade-slot-name-flashlight + priority: 5 + ejectOnBreak: true + occludesLight: false + whitelist: + components: + - GunUpgradeFlashlight + - type: ContainerContainer # DOWNSTREAM-TPirates: gun flashlights + containers: + flashlight: !type:ContainerSlot - type: entity name: pulse carbine parent: [BaseWeaponBattery, BaseGunWieldable, BaseCentcommContraband] @@ -805,6 +835,8 @@ - state: mag-unshaded-0 map: ["enum.GunVisualLayers.MagUnshaded"] shader: unshaded + - type: GunFlashlightAttachment # DOWNSTREAM-TPirates: gun flashlights + offset: "0.03125, 0.0625" - type: Clothing sprite: Objects/Weapons/Guns/Battery/practice_disabler.rsi quickEquip: false @@ -831,8 +863,20 @@ - Sidearm - type: PacifismAllowedGun - type: GunExecutionBlacklist # Goobstation - - + - type: UpgradeableWeapon # DOWNSTREAM-TPirates: gun flashlights + - type: ItemSlots # DOWNSTREAM-TPirates: gun flashlights + slots: + flashlight: + name: weapon-upgrade-slot-name-flashlight + priority: 5 + ejectOnBreak: true + occludesLight: false + whitelist: + components: + - GunUpgradeFlashlight + - type: ContainerContainer # DOWNSTREAM-TPirates: gun flashlights + containers: + flashlight: !type:ContainerSlot - type: entity name: disabler parent: [WeaponDisablerPractice, BaseSecurityCommandContraband] @@ -963,6 +1007,8 @@ - state: mag-unshaded-4 map: ["enum.GunVisualLayers.MagUnshaded"] shader: unshaded + - type: GunFlashlightAttachment # DOWNSTREAM-TPirates: gun flashlights + offset: "0.125, 0.03125" - type: Clothing sprite: Objects/Weapons/Guns/Battery/antiquelasergun.rsi - type: Gun @@ -992,7 +1038,20 @@ flavorKind: station-event-random-sentience-flavor-inanimate weight: 0.0002 # 5,000 times less likely than 1 regular animal # not putting a BlockMovement component here cause that's funny. - + - type: UpgradeableWeapon # DOWNSTREAM-TPirates: gun flashlights + - type: ItemSlots # DOWNSTREAM-TPirates: gun flashlights + slots: + flashlight: + name: weapon-upgrade-slot-name-flashlight + priority: 5 + ejectOnBreak: true + occludesLight: false + whitelist: + components: + - GunUpgradeFlashlight + - type: ContainerContainer # DOWNSTREAM-TPirates: gun flashlights + containers: + flashlight: !type:ContainerSlot - type: entity name: advanced laser pistol # Goobstation parent: [BaseWeaponBatterySmall, BaseSecurityContraband] diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Pistols/pistols.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Pistols/pistols.yml index 61982a1f2547..f8d863376eff 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Pistols/pistols.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Pistols/pistols.yml @@ -210,8 +210,18 @@ components: - type: Sprite sprite: Objects/Weapons/Guns/Pistols/viper.rsi - - type: ItemSlots + - type: GunFlashlightAttachment # DOWNSTREAM-TPirates: gun flashlights + offset: "0.03125, 0.15625" + - type: ItemSlots # DOWNSTREAM-TPirates: gun flashlights slots: + flashlight: + name: weapon-upgrade-slot-name-flashlight + priority: 5 + ejectOnBreak: true + occludesLight: false + whitelist: + components: + - GunUpgradeFlashlight gun_magazine: name: Magazine startingItem: MagazinePistol @@ -230,8 +240,10 @@ whitelist: tags: - CartridgePistol - - type: ContainerContainer + - type: UpgradeableWeapon # DOWNSTREAM-TPirates: gun flashlights + - type: ContainerContainer # DOWNSTREAM-TPirates: gun flashlights containers: + flashlight: !type:ContainerSlot gun_magazine: !type:ContainerSlot gun_chamber: !type:ContainerSlot - type: StaticPrice @@ -258,9 +270,24 @@ map: ["enum.GunVisualLayers.Base"] - state: mag-0 map: ["enum.GunVisualLayers.Mag"] - - type: ContainerContainer + - type: GunFlashlightAttachment # DOWNSTREAM-TPirates: gun flashlights + offset: "0.03125, 0.15625" + - type: Appearance + - type: ContainerContainer # DOWNSTREAM-TPirates: gun flashlights containers: + flashlight: !type:ContainerSlot ballistic-ammo: !type:Container + - type: ItemSlots # DOWNSTREAM-TPirates: gun flashlights + slots: + flashlight: + name: weapon-upgrade-slot-name-flashlight + priority: 5 + ejectOnBreak: true + occludesLight: false + whitelist: + components: + - GunUpgradeFlashlight + - type: UpgradeableWeapon # DOWNSTREAM-TPirates: gun flashlights - type: ProjectileBatteryAmmoProvider proto: BulletPistol fireCost: 100 @@ -285,6 +312,8 @@ map: ["enum.GunVisualLayers.Base"] - state: mag-0 map: ["enum.GunVisualLayers.Mag"] + - type: GunFlashlightAttachment # DOWNSTREAM-TPirates: gun flashlights + offset: "-0.03125, 0.1875" - type: Clothing sprite: Objects/Weapons/Guns/Pistols/cobra.rsi - type: ChamberMagazineAmmoProvider @@ -298,8 +327,16 @@ projectileSpeed: 35 # Goobstation availableModes: - SemiAuto - - type: ItemSlots + - type: ItemSlots # DOWNSTREAM-TPirates: gun flashlights slots: + flashlight: + name: weapon-upgrade-slot-name-flashlight + priority: 5 + ejectOnBreak: true + occludesLight: false + whitelist: + components: + - GunUpgradeFlashlight gun_magazine: name: Magazine startingItem: MagazinePistolCaselessRifle @@ -317,8 +354,10 @@ whitelist: tags: - CartridgeCaselessRifle - - type: ContainerContainer + - type: UpgradeableWeapon # DOWNSTREAM-TPirates: gun flashlights + - type: ContainerContainer # DOWNSTREAM-TPirates: gun flashlights containers: + flashlight: !type:ContainerSlot gun_magazine: !type:ContainerSlot gun_chamber: !type:ContainerSlot - type: StaticPrice @@ -337,6 +376,8 @@ map: ["enum.GunVisualLayers.Base"] - state: mag-0 map: ["enum.GunVisualLayers.Mag"] + - type: GunFlashlightAttachment # DOWNSTREAM-TPirates: gun flashlights + offset: "0, 0.15625" - type: Clothing sprite: Objects/Weapons/Guns/Pistols/mk58.rsi - type: Gun @@ -345,6 +386,39 @@ - SemiAuto soundGunshot: path: /Audio/Weapons/Guns/Gunshots/mk58.ogg + - type: UpgradeableWeapon # DOWNSTREAM-TPirates: gun flashlights + - type: ItemSlots # DOWNSTREAM-TPirates: gun flashlights + slots: + flashlight: + name: weapon-upgrade-slot-name-flashlight + priority: 5 + ejectOnBreak: true + occludesLight: false + whitelist: + components: + - GunUpgradeFlashlight + gun_magazine: + name: Magazine + startingItem: MagazinePistol + insertSound: /Audio/Weapons/Guns/MagIn/pistol_magin.ogg + ejectSound: /Audio/Weapons/Guns/MagOut/pistol_magout.ogg + priority: 2 + whitelist: + tags: + - MagazinePistol + whitelistFailPopup: gun-magazine-whitelist-fail + gun_chamber: + name: Chamber + startingItem: CartridgePistol + priority: 1 + whitelist: + tags: + - CartridgePistol + - type: ContainerContainer # DOWNSTREAM-TPirates: gun flashlights + containers: + flashlight: !type:ContainerSlot + gun_magazine: !type:ContainerSlot + gun_chamber: !type:ContainerSlot - type: entity name: N1984 @@ -359,6 +433,8 @@ map: ["enum.GunVisualLayers.Base"] - state: mag-0 map: ["enum.GunVisualLayers.Mag"] + - type: GunFlashlightAttachment # DOWNSTREAM-TPirates: gun flashlights + offset: "0, 0.1875" - type: Clothing sprite: Objects/Weapons/Guns/Pistols/N1984.rsi - type: Gun @@ -373,8 +449,16 @@ - SemiAuto soundGunshot: path: /Audio/Weapons/Guns/Gunshots/mateba.ogg # Goob edit - - type: ItemSlots + - type: ItemSlots # DOWNSTREAM-TPirates: gun flashlights slots: + flashlight: + name: weapon-upgrade-slot-name-flashlight + priority: 5 + ejectOnBreak: true + occludesLight: false + whitelist: + components: + - GunUpgradeFlashlight gun_magazine: name: Magazine startingItem: MagazineMagnum @@ -392,5 +476,11 @@ whitelist: tags: - CartridgeMagnum + - type: UpgradeableWeapon # DOWNSTREAM-TPirates: gun flashlights + - type: ContainerContainer # DOWNSTREAM-TPirates: gun flashlights + containers: + flashlight: !type:ContainerSlot + gun_magazine: !type:ContainerSlot + gun_chamber: !type:ContainerSlot - type: Multishot #Goob spreadMultiplier: 30 diff --git a/Resources/Prototypes/_Goobstation/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml b/Resources/Prototypes/_Goobstation/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml index 0b3dafdaeabe..12c6957c1c9b 100644 --- a/Resources/Prototypes/_Goobstation/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml +++ b/Resources/Prototypes/_Goobstation/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml @@ -269,6 +269,8 @@ - state: mag-unshaded-0 map: ["enum.GunVisualLayers.MagUnshaded"] shader: unshaded + - type: GunFlashlightAttachment # DOWNSTREAM-TPirates: gun flashlights + offset: "0.03125, 0.0625" - type: Clothing sprite: _EinsteinEngines/Objects/Weapons/Guns/Battery/ccdisabler.rsi quickEquip: false @@ -282,7 +284,20 @@ - type: BatterySelfRecharger autoRecharge: true autoRechargeRate: 40 - + - type: UpgradeableWeapon # DOWNSTREAM-TPirates: gun flashlights + - type: ItemSlots # DOWNSTREAM-TPirates: gun flashlights + slots: + flashlight: + name: weapon-upgrade-slot-name-flashlight + priority: 5 + ejectOnBreak: true + occludesLight: false + whitelist: + components: + - GunUpgradeFlashlight + - type: ContainerContainer # DOWNSTREAM-TPirates: gun flashlights + containers: + flashlight: !type:ContainerSlot - type: entity name: syndicate disabler parent: [ WeaponDisablerPractice, BaseSyndicateContraband ] @@ -396,6 +411,8 @@ layers: - state: icon map: ["enum.GunVisualLayers.Base"] + - type: GunFlashlightAttachment # DOWNSTREAM-TPirates: gun flashlights + offset: "0.125, -0.03125" - type: Clothing quickEquip: false slots: @@ -462,6 +479,20 @@ keyPhrase: "lawbringer-phrase" listenRange: 1 holderOnly: true + - type: UpgradeableWeapon # DOWNSTREAM-TPirates: gun flashlights + - type: ItemSlots # DOWNSTREAM-TPirates: gun flashlights + slots: + flashlight: + name: weapon-upgrade-slot-name-flashlight + priority: 5 + ejectOnBreak: true + occludesLight: false + whitelist: + components: + - GunUpgradeFlashlight + - type: ContainerContainer # DOWNSTREAM-TPirates: gun flashlights + containers: + flashlight: !type:ContainerSlot - type: AccessReader access: [['HeadOfSecurity']] - type: ActiveListener diff --git a/Resources/Prototypes/_Goobstation/Entities/Objects/Weapons/Guns/Pistols/pistol.yml b/Resources/Prototypes/_Goobstation/Entities/Objects/Weapons/Guns/Pistols/pistol.yml index be326fa05761..350db738163d 100644 --- a/Resources/Prototypes/_Goobstation/Entities/Objects/Weapons/Guns/Pistols/pistol.yml +++ b/Resources/Prototypes/_Goobstation/Entities/Objects/Weapons/Guns/Pistols/pistol.yml @@ -25,6 +25,8 @@ map: ["enum.GunVisualLayers.Base"] - state: mag-0 map: ["enum.GunVisualLayers.Mag"] + - type: GunFlashlightAttachment # DOWNSTREAM-TPirates: gun flashlights + offset: "-0.03125, 0.1875" - type: Clothing sprite: _Goobstation/Objects/Weapons/Guns/Pistols/Dualetta.rsi - type: Gun @@ -38,8 +40,16 @@ - FullAuto soundGunshot: path: /Audio/Weapons/Guns/Gunshots/mateba.ogg - - type: ItemSlots + - type: ItemSlots # DOWNSTREAM-TPirates: gun flashlights slots: + flashlight: + name: weapon-upgrade-slot-name-flashlight + priority: 5 + ejectOnBreak: true + occludesLight: false + whitelist: + components: + - GunUpgradeFlashlight gun_magazine: name: Magazine startingItem: MagazinePistolHighCapacity @@ -58,6 +68,12 @@ whitelist: tags: - CartridgePistol + - type: UpgradeableWeapon # DOWNSTREAM-TPirates: gun flashlights + - type: ContainerContainer # DOWNSTREAM-TPirates: gun flashlights + containers: + flashlight: !type:ContainerSlot + gun_magazine: !type:ContainerSlot + gun_chamber: !type:ContainerSlot - type: Tag tags: - WeaponPistolDualetta @@ -89,6 +105,9 @@ layers: - state: icon map: ["enum.GunVisualLayers.Base"] + - type: GunFlashlightAttachment # DOWNSTREAM-TPirates: gun flashlights + offset: "0.09375, 0.125" + - type: Appearance - type: Clothing sprite: _Goobstation/Objects/Weapons/Guns/Pistols/anaconda.rsi quickEquip: false @@ -117,8 +136,20 @@ - oni-cannot-shoot-guns-2 - oni-cannot-shoot-guns-3 - type: AmmoCounter - - type: ContainerContainer + - type: UpgradeableWeapon # DOWNSTREAM-TPirates: gun flashlights + - type: ItemSlots # DOWNSTREAM-TPirates: gun flashlights + slots: + flashlight: + name: weapon-upgrade-slot-name-flashlight + priority: 5 + ejectOnBreak: true + occludesLight: false + whitelist: + components: + - GunUpgradeFlashlight + - type: ContainerContainer # DOWNSTREAM-TPirates: gun flashlights containers: + flashlight: !type:ContainerSlot ballistic-ammo: !type:Container - type: entity diff --git a/Resources/Prototypes/_Pirate/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml b/Resources/Prototypes/_Pirate/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml index c118933d1fb9..767e146e47f1 100644 --- a/Resources/Prototypes/_Pirate/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml +++ b/Resources/Prototypes/_Pirate/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml @@ -174,6 +174,8 @@ - state: mag-unshaded-4 map: ["enum.GunVisualLayers.MagUnshaded"] shader: unshaded + - type: GunFlashlightAttachment + offset: "0.0625, 0.15625" - type: Clothing sprite: _Pirate/Objects/Weapons/Guns/Battery/mini_energygun.rsi - type: Gun @@ -219,7 +221,20 @@ - state: mode-inhand-right shader: unshaded - type: Multishot - + - type: UpgradeableWeapon + - type: ItemSlots + slots: + flashlight: + name: weapon-upgrade-slot-name-flashlight + priority: 5 + ejectOnBreak: true + occludesLight: false + whitelist: + components: + - GunUpgradeFlashlight + - type: ContainerContainer + containers: + flashlight: !type:ContainerSlot - type: entity name: IK-60 laser carbine parent: [BaseWeaponBattery, BaseSecurityContraband, BaseGunWieldable] @@ -298,6 +313,8 @@ - state: mag-unshaded-4 map: ["enum.GunVisualLayers.MagUnshaded"] shader: unshaded + - type: GunFlashlightAttachment + offset: "0.09375, 0.0625" - type: Clothing sprite: _Pirate/Objects/Weapons/Guns/Battery/energygun_pistol.rsi - type: Gun @@ -343,6 +360,20 @@ right: - state: mode-inhand-right shader: unshaded + - type: UpgradeableWeapon + - type: ItemSlots + slots: + flashlight: + name: weapon-upgrade-slot-name-flashlight + priority: 5 + ejectOnBreak: true + occludesLight: false + whitelist: + components: + - GunUpgradeFlashlight + - type: ContainerContainer + containers: + flashlight: !type:ContainerSlot - type: StaticPrice price: 750 - - type: Multishot \ No newline at end of file + - type: Multishot diff --git a/Resources/Prototypes/_Pirate/Entities/Objects/Weapons/Guns/Pistols/pistols.yml b/Resources/Prototypes/_Pirate/Entities/Objects/Weapons/Guns/Pistols/pistols.yml index da2489980abd..b9aa5d3e98eb 100644 --- a/Resources/Prototypes/_Pirate/Entities/Objects/Weapons/Guns/Pistols/pistols.yml +++ b/Resources/Prototypes/_Pirate/Entities/Objects/Weapons/Guns/Pistols/pistols.yml @@ -1,6 +1,6 @@ - type: entity name: mk 32 "Universal" - parent: BaseWeaponPistol + parent: [BaseWeaponPistol] id: WeaponPistolUniversal description: An expensive and robust pistol with decent offensive capabilities. Uses .45 magnum ammo. components: @@ -11,6 +11,8 @@ map: ["enum.GunVisualLayers.Base"] - state: mag-0 map: ["enum.GunVisualLayers.Mag"] + - type: GunFlashlightAttachment + offset: "0.125, 0.1875" - type: Clothing sprite: _Pirate/Objects/Weapons/Guns/Pistols/universal.rsi - type: Gun @@ -25,6 +27,14 @@ path: /Audio/_Pirate/Weapons/Guns/Gunshots/universal.ogg - type: ItemSlots slots: + flashlight: + name: weapon-upgrade-slot-name-flashlight + priority: 5 + ejectOnBreak: true + occludesLight: false + whitelist: + components: + - GunUpgradeFlashlight gun_magazine: name: Magazine startingItem: MagazineUniversalMagnum @@ -41,8 +51,10 @@ whitelist: tags: - CartridgeMagnum + - type: UpgradeableWeapon - type: ContainerContainer containers: + flashlight: !type:ContainerSlot gun_magazine: !type:ContainerSlot gun_chamber: !type:ContainerSlot @@ -87,8 +99,18 @@ components: - type: Sprite sprite: _Pirate/Objects/Weapons/Guns/Pistols/universalnl.rsi + - type: GunFlashlightAttachment + offset: "0.125, 0.1875" - type: ItemSlots slots: + flashlight: + name: weapon-upgrade-slot-name-flashlight + priority: 5 + ejectOnBreak: true + occludesLight: false + whitelist: + components: + - GunUpgradeFlashlight gun_magazine: name: Magazine startingItem: MagazineUniversalMagnumRubber @@ -128,6 +150,8 @@ map: ["enum.GunVisualLayers.Base"] - state: mag-0 map: ["enum.GunVisualLayers.Mag"] + - type: GunFlashlightAttachment + offset: "0.03125, 0.15625" - type: Clothing sprite: _Pirate/Objects/Weapons/Guns/Pistols/sol_pistol.rsi - type: Gun @@ -135,4 +159,37 @@ availableModes: - SemiAuto soundGunshot: - path: /Audio/_Pirate/Weapons/Guns/Gunshots/pistol.ogg \ No newline at end of file + path: /Audio/_Pirate/Weapons/Guns/Gunshots/pistol.ogg + - type: UpgradeableWeapon + - type: ItemSlots + slots: + flashlight: + name: weapon-upgrade-slot-name-flashlight + priority: 5 + ejectOnBreak: true + occludesLight: false + whitelist: + components: + - GunUpgradeFlashlight + gun_magazine: + name: Magazine + startingItem: MagazinePistol + insertSound: /Audio/Weapons/Guns/MagIn/pistol_magin.ogg + ejectSound: /Audio/Weapons/Guns/MagOut/pistol_magout.ogg + priority: 2 + whitelist: + tags: + - MagazinePistol + whitelistFailPopup: gun-magazine-whitelist-fail + gun_chamber: + name: Chamber + startingItem: CartridgePistol + priority: 1 + whitelist: + tags: + - CartridgePistol + - type: ContainerContainer + containers: + flashlight: !type:ContainerSlot + gun_magazine: !type:ContainerSlot + gun_chamber: !type:ContainerSlot diff --git a/Resources/Textures/_Pirate/Objects/Weapons/Guns/Upgrades/gun_flashlight_attachment.rsi/flight-on.png b/Resources/Textures/_Pirate/Objects/Weapons/Guns/Upgrades/gun_flashlight_attachment.rsi/flight-on.png new file mode 100644 index 000000000000..f13ebdec629e Binary files /dev/null and b/Resources/Textures/_Pirate/Objects/Weapons/Guns/Upgrades/gun_flashlight_attachment.rsi/flight-on.png differ diff --git a/Resources/Textures/_Pirate/Objects/Weapons/Guns/Upgrades/gun_flashlight_attachment.rsi/flight.png b/Resources/Textures/_Pirate/Objects/Weapons/Guns/Upgrades/gun_flashlight_attachment.rsi/flight.png new file mode 100644 index 000000000000..5cc31b7dec3f Binary files /dev/null and b/Resources/Textures/_Pirate/Objects/Weapons/Guns/Upgrades/gun_flashlight_attachment.rsi/flight.png differ diff --git a/Resources/Textures/_Pirate/Objects/Weapons/Guns/Upgrades/gun_flashlight_attachment.rsi/meta.json b/Resources/Textures/_Pirate/Objects/Weapons/Guns/Upgrades/gun_flashlight_attachment.rsi/meta.json new file mode 100644 index 000000000000..fc08e8bd17ca --- /dev/null +++ b/Resources/Textures/_Pirate/Objects/Weapons/Guns/Upgrades/gun_flashlight_attachment.rsi/meta.json @@ -0,0 +1,17 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "flashlight sprites copied from Resources/Textures/Objects/Weapons/Guns/Basic/kinetic_accelerator.rsi (Monkestation-derived, see source RSI metadata)", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "flight" + }, + { + "name": "flight-on" + } + ] +} \ No newline at end of file