diff --git a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs index cbbfc289cf5..4dbb8296f8c 100644 --- a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs +++ b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs @@ -1,6 +1,7 @@ using System.Linq; using System.Numerics; using Content.Server.Cargo.Systems; +using Content.Server.Explosion.EntitySystems; using Content.Server.Interaction; using Content.Server.Power.EntitySystems; using Content.Server.Stunnable; @@ -10,6 +11,7 @@ using Content.Shared.Damage.Systems; using Content.Shared.Database; using Content.Shared.Effects; +using Content.Shared.Explosion.Components; using Content.Shared.Interaction.Components; using Content.Shared.Projectiles; using Content.Shared.Weapons.Melee; @@ -39,6 +41,7 @@ public sealed partial class GunSystem : SharedGunSystem [Dependency] private readonly StaminaSystem _stamina = default!; [Dependency] private readonly StunSystem _stun = default!; [Dependency] private readonly ContestsSystem _contests = default!; + [Dependency] private readonly TriggerSystem _trigger = default!; private const float DamagePitchVariation = 0.05f; public const float GunClumsyChance = 0.5f; @@ -287,6 +290,16 @@ private void ShootOrThrow(EntityUid uid, Vector2 mapDirection, Vector2 gunVeloci Dirty(uid, targeted); } + if (TryComp(uid, out var triggerComponent) && triggerComponent.StartOnShoot) + { + _trigger.HandleTimerTrigger(uid, + user, + triggerComponent.Delay, + triggerComponent.BeepInterval, + triggerComponent.InitialBeepDelay, + triggerComponent.BeepSound); + } + // Do a throw if (!HasComp(uid)) { diff --git a/Content.Shared/Explosion/Components/OnUseTimerTriggerComponent.cs b/Content.Shared/Explosion/Components/OnUseTimerTriggerComponent.cs index 5e509cb10bb..a5512d487d4 100644 --- a/Content.Shared/Explosion/Components/OnUseTimerTriggerComponent.cs +++ b/Content.Shared/Explosion/Components/OnUseTimerTriggerComponent.cs @@ -36,6 +36,11 @@ public sealed partial class OnUseTimerTriggerComponent : Component /// [DataField] public bool StartOnStick; + /// + /// Should timer be started when it is shot from a gun. + /// + [DataField] public bool StartOnShoot = false; + /// /// Allows changing the start-on-stick quality. /// diff --git a/Content.Shared/Weapons/Ranged/Components/BallisticAmmoProviderComponent.cs b/Content.Shared/Weapons/Ranged/Components/BallisticAmmoProviderComponent.cs index eb04d3227db..0b6d6f52c21 100644 --- a/Content.Shared/Weapons/Ranged/Components/BallisticAmmoProviderComponent.cs +++ b/Content.Shared/Weapons/Ranged/Components/BallisticAmmoProviderComponent.cs @@ -50,6 +50,12 @@ public sealed partial class BallisticAmmoProviderComponent : Component [ViewVariables(VVAccess.ReadWrite), DataField] public bool MayTransfer; + /// + /// Does this entity load ammo it is used on directly? + /// + [ViewVariables(VVAccess.ReadWrite), DataField] + public bool LoadOnUse = false; + /// /// DoAfter delay for filling a bullet into another ballistic ammo provider. /// diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Ballistic.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Ballistic.cs index 91aad895821..5660fc6090a 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Ballistic.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Ballistic.cs @@ -5,6 +5,7 @@ using Content.Shared.Verbs; using Content.Shared.Weapons.Ranged.Components; using Content.Shared.Weapons.Ranged.Events; +using Content.Shared.Whitelist; using Robust.Shared.Containers; using Robust.Shared.Map; using Robust.Shared.Serialization; @@ -14,6 +15,7 @@ namespace Content.Shared.Weapons.Ranged.Systems; public abstract partial class SharedGunSystem { [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelist = default!; protected virtual void InitializeBallistic() { @@ -41,44 +43,62 @@ private void OnBallisticUse(EntityUid uid, BallisticAmmoProviderComponent compon private void OnBallisticInteractUsing(EntityUid uid, BallisticAmmoProviderComponent component, InteractUsingEvent args) { - if (args.Handled || component.Whitelist?.IsValid(args.Used, EntityManager) != true) - return; - - if (GetBallisticShots(component) >= component.Capacity) + if (args.Handled) return; - component.Entities.Add(args.Used); - Containers.Insert(args.Used, component.Container); - // Not predicted so - Audio.PlayPredicted(component.SoundInsert, uid, args.User); - args.Handled = true; - UpdateBallisticAppearance(uid, component); - Dirty(uid, component); + if (TryInsertAmmo(uid, component, args.Used)) + { + Audio.PlayPredicted(component.SoundInsert, uid, args.User); + args.Handled = true; + } } private void OnBallisticAfterInteract(EntityUid uid, BallisticAmmoProviderComponent component, AfterInteractEvent args) { if (args.Handled || - !component.MayTransfer || !Timing.IsFirstTimePredicted || args.Target == null || args.Used == args.Target || - Deleted(args.Target) || - !TryComp(args.Target, out var targetComponent) || - targetComponent.Whitelist == null) + Deleted(args.Target)) { return; } - args.Handled = true; + // Try to fill the target component with this. + if (component.MayTransfer && + TryComp(args.Target, out var targetComponent) && + targetComponent.Whitelist != null) + { + args.Handled = true; - _doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager, args.User, component.FillDelay, new AmmoFillDoAfterEvent(), used: uid, target: args.Target, eventTarget: uid) + _doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager, args.User, component.FillDelay, new AmmoFillDoAfterEvent(), used: uid, target: args.Target, eventTarget: uid) + { + BreakOnTargetMove = true, + BreakOnUserMove = true, + BreakOnDamage = false, + NeedHand = true + }); + } + else if (component.LoadOnUse && TryInsertAmmo(uid, component, (EntityUid) args.Target)) { - BreakOnTargetMove = true, - BreakOnUserMove = true, - BreakOnDamage = false, - NeedHand = true - }); + Audio.PlayPredicted(component.SoundInsert, uid, args.User); + args.Handled = true; + } + } + + private bool TryInsertAmmo(EntityUid uid, BallisticAmmoProviderComponent ammoProviderComponent, EntityUid ammo) + { + if (ammoProviderComponent.Whitelist != null && !_whitelist.IsValid(ammoProviderComponent.Whitelist, ammo) + || GetBallisticShots(ammoProviderComponent) >= ammoProviderComponent.Capacity) + return false; + + ammoProviderComponent.Entities.Add(ammo); + Containers.Insert(ammo, ammoProviderComponent.Container); + // Not predicted so + UpdateBallisticAppearance(uid, ammoProviderComponent); + Dirty(uid, ammoProviderComponent); + + return true; } private void OnBallisticAmmoFillDoAfter(EntityUid uid, BallisticAmmoProviderComponent component, AmmoFillDoAfterEvent args) diff --git a/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml b/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml index af141dc3ced..8356073fa82 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml @@ -345,7 +345,8 @@ items: - AdvMopItem - HoloprojectorBorg - - SprayBottleSpaceCleaner + - MegaSprayBottleSpaceCleaner + - WeaponLauncherCleanadeBorg - Dropper - TrashBag diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml index b39303d9ede..65602a197b8 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml @@ -16,6 +16,7 @@ - Belt - type: OnUseTimerTrigger delay: 3.5 + startOnShoot: true - type: Damageable damageContainer: Inorganic - type: Destructible @@ -404,6 +405,9 @@ reagents: - ReagentId: SpaceCleaner Quantity: 30 + - type: Tag + tags: + - Cleanade - type: entity parent: SmokeGrenade diff --git a/Resources/Prototypes/Floof/Entities/Objects/Specific/Janitorial/spray.yml b/Resources/Prototypes/Floof/Entities/Objects/Specific/Janitorial/spray.yml new file mode 100644 index 00000000000..069b025af30 --- /dev/null +++ b/Resources/Prototypes/Floof/Entities/Objects/Specific/Janitorial/spray.yml @@ -0,0 +1,12 @@ +- type: entity + id: MegaSprayBottleSpaceCleaner + parent: MegaSprayBottle + suffix: Space Cleaner + components: + - type: SolutionContainerManager + solutions: + spray: + maxVol: 250 + reagents: + - ReagentId: SpaceCleaner + Quantity: 250 diff --git a/Resources/Prototypes/Floof/Entities/Objects/Weapons/Guns/launchers.yml b/Resources/Prototypes/Floof/Entities/Objects/Weapons/Guns/launchers.yml new file mode 100644 index 00000000000..1ac7d28d9d8 --- /dev/null +++ b/Resources/Prototypes/Floof/Entities/Objects/Weapons/Guns/launchers.yml @@ -0,0 +1,49 @@ +- type: entity + name: cleanade launcher + parent: [BaseWeaponLauncher, BaseGunWieldable] + id: WeaponLauncherCleanade + description: Only compatible with officially licensed Cleanades. + components: + - type: Sprite + sprite: Floof/Objects/Weapons/Guns/Launchers/cleanade.rsi + layers: + - state: icon + map: ["enum.GunVisualLayers.Base"] + - type: Clothing + sprite: Objects/Weapons/Guns/Launchers/china_lake.rsi + slots: + - Back + - suitStorage + - type: AmmoCounter + - type: Gun + fireRate: 1 + projectileSpeed: 10 + selectedMode: SemiAuto + availableModes: + - SemiAuto + soundGunshot: + path: /Audio/Weapons/Guns/Gunshots/grenade_launcher.ogg + - type: BallisticAmmoProvider + whitelist: + tags: + - Cleanade + capacity: 2 + proto: CleanerGrenade + soundInsert: + path: /Audio/Weapons/Guns/MagIn/batrifle_magin.ogg + +- type: entity + parent: WeaponLauncherCleanade + suffix: Borg + id: WeaponLauncherCleanadeBorg + categories: [ HideSpawnMenu ] + components: + - type: BallisticAmmoProvider + loadOnUse: true + whitelist: + tags: + - Cleanade + capacity: 2 + proto: CleanerGrenade + soundInsert: + path: /Audio/Weapons/Guns/MagIn/batrifle_magin.ogg diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index a8ed7a91c13..819a09832d7 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -1379,10 +1379,13 @@ id: BrassKnuckles - type: Tag - id: WeaponDisabler + id: Cleanade + +- type: Tag + id: ClothingHeadHelmetBasic - type: Tag id: Stunbaton - type: Tag - id: ClothingHeadHelmetBasic + id: WeaponDisabler diff --git a/Resources/Textures/Floof/Objects/Weapons/Guns/Launchers/cleanade.rsi/bolt-open.png b/Resources/Textures/Floof/Objects/Weapons/Guns/Launchers/cleanade.rsi/bolt-open.png new file mode 100644 index 00000000000..9d9e2968901 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Weapons/Guns/Launchers/cleanade.rsi/bolt-open.png differ diff --git a/Resources/Textures/Floof/Objects/Weapons/Guns/Launchers/cleanade.rsi/equipped-BACKPACK.png b/Resources/Textures/Floof/Objects/Weapons/Guns/Launchers/cleanade.rsi/equipped-BACKPACK.png new file mode 100644 index 00000000000..91c1df4ee9f Binary files /dev/null and b/Resources/Textures/Floof/Objects/Weapons/Guns/Launchers/cleanade.rsi/equipped-BACKPACK.png differ diff --git a/Resources/Textures/Floof/Objects/Weapons/Guns/Launchers/cleanade.rsi/equipped-BELT.png b/Resources/Textures/Floof/Objects/Weapons/Guns/Launchers/cleanade.rsi/equipped-BELT.png new file mode 100644 index 00000000000..dc365ee8441 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Weapons/Guns/Launchers/cleanade.rsi/equipped-BELT.png differ diff --git a/Resources/Textures/Floof/Objects/Weapons/Guns/Launchers/cleanade.rsi/icon.png b/Resources/Textures/Floof/Objects/Weapons/Guns/Launchers/cleanade.rsi/icon.png new file mode 100644 index 00000000000..74a28a33b73 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Weapons/Guns/Launchers/cleanade.rsi/icon.png differ diff --git a/Resources/Textures/Floof/Objects/Weapons/Guns/Launchers/cleanade.rsi/inhand-left.png b/Resources/Textures/Floof/Objects/Weapons/Guns/Launchers/cleanade.rsi/inhand-left.png new file mode 100644 index 00000000000..ea928e121c5 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Weapons/Guns/Launchers/cleanade.rsi/inhand-left.png differ diff --git a/Resources/Textures/Floof/Objects/Weapons/Guns/Launchers/cleanade.rsi/inhand-right.png b/Resources/Textures/Floof/Objects/Weapons/Guns/Launchers/cleanade.rsi/inhand-right.png new file mode 100644 index 00000000000..43cc7e4102d Binary files /dev/null and b/Resources/Textures/Floof/Objects/Weapons/Guns/Launchers/cleanade.rsi/inhand-right.png differ diff --git a/Resources/Textures/Floof/Objects/Weapons/Guns/Launchers/cleanade.rsi/meta.json b/Resources/Textures/Floof/Objects/Weapons/Guns/Launchers/cleanade.rsi/meta.json new file mode 100644 index 00000000000..48aa6275ad5 --- /dev/null +++ b/Resources/Textures/Floof/Objects/Weapons/Guns/Launchers/cleanade.rsi/meta.json @@ -0,0 +1,33 @@ +{ + "version": 1, + "license": "CC-BY-SA-4.0", + "copyright": "Taken/modified from cev-eris at https://github.com/discordia-space/CEV-Eris/pull/6042/commits/64916c98f4847acc4adf3a2416bf78c005fd7dd7, https://github.com/discordia-space/CEV-Eris/blob/master/icons/obj/guns/launcher/grenadelauncher.dmi, backpack sprite by Peptide, resprited for mail gun by erhardsteinhauer (discord), then resprited for cleanade launcher by Eagle0600 (discord and GitHub)", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "bolt-open" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "equipped-BELT", + "directions": 4 + }, + { + "name": "equipped-BACKPACK", + "directions": 4 + } + ] +} \ No newline at end of file