From 0974f9bb6384bba65487d948f6a54112466b7996 Mon Sep 17 00:00:00 2001 From: Inconnu1337 Date: Wed, 13 Nov 2024 22:42:02 +0200 Subject: [PATCH 01/46] attachments --- Content.Client/Input/ContentContexts.cs | 20 +- .../Options/UI/Tabs/KeyRebindTab.xaml.cs | 13 + .../Projectiles/ProjectileSystem.cs | 2 +- .../Weapons/Melee/MeleeWeaponSystem.cs | 106 ++- .../AttachableHolderVisualsComponent.cs | 17 + .../Components/AttachableVisualsComponent.cs | 66 ++ .../Systems/AttachableHolderVisualsSystem.cs | 155 ++++ .../Ui/AttachableHolderChooseSlotMenu.xaml | 9 + .../Ui/AttachableHolderChooseSlotMenu.xaml.cs | 58 ++ .../Ui/AttachableHolderStripMenu.xaml | 9 + .../Ui/AttachableHolderStripMenu.xaml.cs | 95 +++ .../Attachable/Ui/AttachmentChooseSlotBui.cs | 45 + .../Attachable/Ui/AttachmentStripBui.cs | 45 + .../_RMC14/Actions/ActionCooldownComponent.cs | 11 + .../Actions/ActionReducedUseDelayComponent.cs | 18 + .../Actions/ActionReducedUseDelayEvent.cs | 7 + .../Actions/ActionSharedCooldownComponent.cs | 21 + .../Actions/RMCActionUseAttemptEvent.cs | 4 + .../ADT/_RMC14/Actions/RMCActionUseEvent.cs | 4 + .../ADT/_RMC14/Actions/RMCActionsSystem.cs | 126 +++ .../Magnetic/RMCMagneticArmorComponent.cs | 12 + .../Magnetic/RMCMagneticItemComponent.cs | 12 + .../Armor/Magnetic/RMCMagneticSystem.cs | 135 +++ .../Armor/Magnetic/RMCMagnetizeItemEvent.cs | 11 + .../Magnetic/RMCReturnToInventoryComponent.cs | 17 + .../ADT/_RMC14/Attachable/AttachableData.cs | 78 ++ .../ADT/_RMC14/Attachable/AttachableUI.cs | 35 + .../Components/AttachableComponent.cs | 19 + .../AttachableDirectionLockedComponent.cs | 16 + .../AttachableGunPreventShootComponent.cs | 15 + .../Components/AttachableHolderComponent.cs | 32 + .../Components/AttachableIFFComponent.cs | 8 + .../Components/AttachableMagneticComponent.cs | 13 + .../AttachableMovementLockedComponent.cs | 13 + ...ttachablePreventDropToggleableComponent.cs | 8 + .../Components/AttachablePryingComponent.cs | 8 + .../AttachableSideLockedComponent.cs | 18 + .../Components/AttachableSilencerComponent.cs | 13 + .../Components/AttachableSizeModsComponent.cs | 12 + .../AttachableSpeedModsComponent.cs | 13 + .../AttachableTemporarySpeedModsComponent.cs | 19 + .../AttachableToggleableComponent.cs | 148 ++++ ...tachableToggleablePreventShootComponent.cs | 15 + ...chableToggleableSimpleActivateComponent.cs | 8 + .../AttachableWeaponMeleeModsComponent.cs | 12 + .../AttachableWeaponRangedModsComponent.cs | 15 + .../AttachableWieldDelayModsComponent.cs | 13 + .../Components/GunAttachableIFFComponent.cs | 8 + .../Events/AttachableAlteredEvent.cs | 21 + .../Events/AttachableAttachDoAfterEvent.cs | 15 + .../Events/AttachableDetachDoAfterEvent.cs | 7 + .../Events/AttachableGetExamineDataEvent.cs | 4 + .../Events/AttachableGrantIFFEvent.cs | 4 + ...AttachableHolderAttachablesAlteredEvent.cs | 8 + .../Events/AttachableRelayedEvent.cs | 16 + .../Events/AttachableToggleDoAfterEvent.cs | 17 + .../Events/AttachableToggleStartedEvent.cs | 10 + .../AttachableToggleableInterruptEvent.cs | 8 + .../Events/GrantAttachableActionsEvent.cs | 4 + .../Events/RemoveAttachableActionsEvent.cs | 4 + .../Systems/AttachableHolderSystem.cs | 739 ++++++++++++++++ .../Attachable/Systems/AttachableIFFSystem.cs | 72 ++ .../Systems/AttachableMagneticSystem.cs | 30 + .../AttachableModifiersSystem.Melee.cs | 90 ++ .../AttachableModifiersSystem.Ranged.cs | 165 ++++ .../Systems/AttachableModifiersSystem.Size.cs | 71 ++ .../AttachableModifiersSystem.Speed.cs | 78 ++ .../AttachableModifiersSystem.WieldDelay.cs | 77 ++ .../Systems/AttachableModifiersSystem.cs | 215 +++++ .../Systems/AttachablePreventDropSystem.cs | 33 + .../Systems/AttachablePryingSystem.cs | 46 + .../Systems/AttachableSilencerSystem.cs | 24 + .../AttachableTemporarySpeedModsSystem.cs | 24 + .../Systems/AttachableToggleableSystem.cs | 789 ++++++++++++++++++ Content.Shared/ADT/_RMC14/CCVar/RMCCVars.cs | 243 ++++++ .../_RMC14/Input/ActiveInputMoverComponent.cs | 7 + .../ADT/_RMC14/Input/CMKeyFunctions.cs | 19 + .../ADT/_RMC14/Input/RMCInputSystem.cs | 53 ++ .../ADT/_RMC14/Inventory/CMHolsterChoose.cs | 10 + .../_RMC14/Inventory/CMHolsterComponent.cs | 47 ++ .../ADT/_RMC14/Inventory/CMHolsterLayers.cs | 9 + .../ADT/_RMC14/Inventory/CMHolsterVisuals.cs | 10 + .../_RMC14/Inventory/CMInventoryExtensions.cs | 39 + .../_RMC14/Inventory/CMItemSlotsComponent.cs | 29 + .../ADT/_RMC14/Inventory/CMItemSlotsLayers.cs | 9 + .../_RMC14/Inventory/CMItemSlotsVisuals.cs | 13 + .../Inventory/CMVirtualItemComponent.cs | 7 + .../_RMC14/Inventory/IsUnholsterableEvent.cs | 4 + .../ADT/_RMC14/Inventory/RMCDroppedEvent.cs | 4 + .../Inventory/SharedCMInventorySystem.cs | 661 +++++++++++++++ .../Item/FixedItemSizeStorageComponent.cs | 16 + .../_RMC14/Item/GetItemSizeModifiersEvent.cs | 4 + .../_RMC14/Item/ItemSizeChangeComponent.cs | 11 + .../ADT/_RMC14/Item/ItemSizeChangeSystem.cs | 100 +++ .../RMCItemToggleClothingVisualsComponent.cs | 11 + .../Item/ItemToggle/RMCItemToggleSystem.cs | 29 + .../_RMC14/Item/MultiHandedHolderComponent.cs | 11 + .../_RMC14/Item/MultiHandedHolderSystem.cs | 81 ++ .../ADT/_RMC14/Item/MultiHandedItem.cs | 8 + .../TemporarySpeedModifiersComponent.cs | 19 + .../Movement/TemporarySpeedModifiersSystem.cs | 73 ++ .../Projectiles/DeleteOnCollideComponent.cs | 7 + .../Projectiles/ModifyTargetOnHitComponent.cs | 16 + .../PreventCollideWithDeadComponent.cs | 7 + .../ProjectileMaxRangeComponent.cs | 18 + .../RMCProjectileDamageFalloffComponent.cs | 59 ++ .../_RMC14/Projectiles/RMCProjectileSystem.cs | 181 ++++ .../Projectiles/SpawnOnTerminateComponent.cs | 26 + .../ADT/_RMC14/Random/SplitMix64.cs | 39 + .../ADT/_RMC14/Random/Xoroshiro64S.cs | 65 ++ .../ADT/_RMC14/Scoping/GunScopingComponent.cs | 11 + .../ADT/_RMC14/Scoping/ScopeComponent.cs | 84 ++ .../Scoping/ScopeCycleZoomLevelEvent.cs | 5 + .../ADT/_RMC14/Scoping/ScopeDoAfterEvent.cs | 16 + .../ADT/_RMC14/Scoping/ScopingComponent.cs | 18 + .../_RMC14/Scoping/SharedScopeSystem.User.cs | 102 +++ .../ADT/_RMC14/Scoping/SharedScopeSystem.cs | 402 +++++++++ .../ADT/_RMC14/Sound/CMSoundSystem.cs | 75 ++ .../Sound/EmitSoundOnActionComponent.cs | 23 + .../ADT/_RMC14/Sound/RandomSoundComponent.cs | 21 + .../ADT/_RMC14/Sound/SoundActionEvent.cs | 5 + .../ADT/_RMC14/Sound/SoundOnDeathComponent.cs | 12 + .../ADT/_RMC14/Tackle/CMDisarmEvent.cs | 4 + .../ADT/_RMC14/Tackle/TackleComponent.cs | 20 + .../ADT/_RMC14/Tackle/TackleSystem.cs | 112 +++ .../ADT/_RMC14/Tackle/TackleableComponent.cs | 10 + .../_RMC14/Tackle/TackledRecentlyComponent.cs | 17 + .../Weapons/Common/UniqueActionComponent.cs | 7 + .../Weapons/Common/UniqueActionEvent.cs | 6 + .../Weapons/Common/UniqueActionSystem.cs | 68 ++ .../Weapons/Melee/ImmuneToMeleeComponent.cs | 12 + .../Weapons/Melee/ImmuneToUnarmedComponent.cs | 11 + .../Melee/MeleeDamageMultiplierComponent.cs | 21 + .../Melee/MeleeReceivedMultiplierComponent.cs | 13 + .../Weapons/Melee/MeleeResetComponent.cs | 11 + .../Melee/SharedRMCMeleeWeaponSystem.cs | 159 ++++ .../Weapons/Melee/StunOnHitComponent.cs | 15 + .../Ranged/Ammo/GunToggleAmmoActionEvent.cs | 5 + .../Ranged/Ammo/GunToggleableAmmoComponent.cs | 32 + .../Ranged/Ammo/GunToggleableAmmoSystem.cs | 95 +++ .../Weapons/Ranged/BreechLoadedComponent.cs | 37 + .../Weapons/Ranged/BreechLoadedSystem.cs | 95 +++ .../ADT/_RMC14/Weapons/Ranged/CMGunSystem.cs | 107 +++ .../Weapons/Ranged/GetDamageFalloffEvent.cs | 8 + .../Weapons/Ranged/GetFireModeValuesEvent.cs | 5 + .../Weapons/Ranged/GetFireModesEvent.cs | 6 + .../Ranged/GetGunDamageModifierEvent.cs | 6 + .../Weapons/Ranged/GunGetFireRateEvent.cs | 5 + .../Weapons/Ranged/PumpActionComponent.cs | 30 + .../Weapons/Ranged/RMCAmmoEjectComponent.cs | 23 + .../Weapons/Ranged/RMCFireGroupComponent.cs | 30 + .../Weapons/Ranged/RMCFireModeChangedEvent.cs | 6 + .../Ranged/RMCSelectiveFireComponent.cs | 130 +++ .../Weapons/Ranged/RMCSelectiveFireSystem.cs | 231 +++++ .../Weapons/Ranged/RMCTryAmmoEjectEvent.cs | 8 + .../Recoil/GunToggleRecoilActionEvent.cs | 5 + .../Recoil/GunToggleableRecoilComponent.cs | 25 + .../Recoil/GunToggleableRecoilSystem.cs | 63 ++ .../Weapons/Ranged/SharedFireGroupSystem.cs | 55 ++ .../Weapons/Ranged/SharedPumpActionSystem.cs | 79 ++ .../Weapons/Ranged/ShootUseDelayComponent.cs | 6 + .../Weapons/Ranged/ShootUseDelaySystem.cs | 27 + .../Ranged/Stacks/GunStacksComponent.cs | 31 + .../Stacks/GunStacksProjectileComponent.cs | 11 + .../Weapons/Ranged/Stacks/GunStacksSystem.cs | 97 +++ .../Components/WieldDelayComponent.cs | 18 + .../WieldSlowdownCompensationComponent.cs | 26 + .../WieldSlowdownCompensationUserComponent.cs | 14 + .../WieldableSpeedModifiersComponent.cs | 30 + .../Wieldable/Events/GetWieldDelayEvent.cs | 7 + .../Events/GetWieldableSpeedModifiersEvent.cs | 8 + .../RefreshWieldSlowdownCompensationEvent.cs | 10 + .../_RMC14/Wieldable/RMCWieldableSystem.cs | 234 ++++++ .../Actions/AttachableToggleActionEvent.cs | 3 + .../Containers/ItemSlot/ItemSlotsSystem.cs | 2 +- .../Damage/Systems/DamageableSystem.cs | 9 +- .../Projectiles/ProjectileComponent.cs | 8 + Content.Shared/Sound/SharedEmitSoundSystem.cs | 5 + .../Melee/Components/AltFireMeleeComponent.cs | 22 + .../Weapons/Ranged/Components/GunComponent.cs | 3 +- .../Systems/SharedGunSystem.Interactions.cs | 7 +- .../Weapons/Ranged/Systems/SharedGunSystem.cs | 4 +- .../Actions/Marines/marine_action_base.yml | 4 + .../Actions/Marines/marine_action_items.yml | 73 ++ Resources/Prototypes/ADT/_RMC14/test.yml | 366 ++++++++ .../Melee/kitchen_knife.rsi/icon_a.png | Bin 0 -> 544 bytes .../Weapons/Melee/kitchen_knife.rsi/meta.json | 3 + runclient.bat | 1 + 188 files changed, 9397 insertions(+), 51 deletions(-) create mode 100644 Content.Client/_RMC14/Attachable/Components/AttachableHolderVisualsComponent.cs create mode 100644 Content.Client/_RMC14/Attachable/Components/AttachableVisualsComponent.cs create mode 100644 Content.Client/_RMC14/Attachable/Systems/AttachableHolderVisualsSystem.cs create mode 100644 Content.Client/_RMC14/Attachable/Ui/AttachableHolderChooseSlotMenu.xaml create mode 100644 Content.Client/_RMC14/Attachable/Ui/AttachableHolderChooseSlotMenu.xaml.cs create mode 100644 Content.Client/_RMC14/Attachable/Ui/AttachableHolderStripMenu.xaml create mode 100644 Content.Client/_RMC14/Attachable/Ui/AttachableHolderStripMenu.xaml.cs create mode 100644 Content.Client/_RMC14/Attachable/Ui/AttachmentChooseSlotBui.cs create mode 100644 Content.Client/_RMC14/Attachable/Ui/AttachmentStripBui.cs create mode 100644 Content.Shared/ADT/_RMC14/Actions/ActionCooldownComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Actions/ActionReducedUseDelayComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Actions/ActionReducedUseDelayEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Actions/ActionSharedCooldownComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Actions/RMCActionUseAttemptEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Actions/RMCActionUseEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Actions/RMCActionsSystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticArmorComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticItemComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticSystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagnetizeItemEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCReturnToInventoryComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/AttachableData.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/AttachableUI.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Components/AttachableComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Components/AttachableDirectionLockedComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Components/AttachableGunPreventShootComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Components/AttachableHolderComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Components/AttachableIFFComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Components/AttachableMagneticComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Components/AttachableMovementLockedComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Components/AttachablePreventDropToggleableComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Components/AttachablePryingComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Components/AttachableSideLockedComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Components/AttachableSilencerComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Components/AttachableSizeModsComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Components/AttachableSpeedModsComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Components/AttachableTemporarySpeedModsComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Components/AttachableToggleableComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Components/AttachableToggleablePreventShootComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Components/AttachableToggleableSimpleActivateComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Components/AttachableWeaponMeleeModsComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Components/AttachableWeaponRangedModsComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Components/AttachableWieldDelayModsComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Components/GunAttachableIFFComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Events/AttachableAlteredEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Events/AttachableAttachDoAfterEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Events/AttachableDetachDoAfterEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Events/AttachableGetExamineDataEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Events/AttachableGrantIFFEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Events/AttachableHolderAttachablesAlteredEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Events/AttachableRelayedEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Events/AttachableToggleDoAfterEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Events/AttachableToggleStartedEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Events/AttachableToggleableInterruptEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Events/GrantAttachableActionsEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Events/RemoveAttachableActionsEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableHolderSystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableIFFSystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableMagneticSystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableModifiersSystem.Melee.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableModifiersSystem.Ranged.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableModifiersSystem.Size.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableModifiersSystem.Speed.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableModifiersSystem.WieldDelay.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableModifiersSystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Systems/AttachablePreventDropSystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Systems/AttachablePryingSystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableSilencerSystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableTemporarySpeedModsSystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableToggleableSystem.cs create mode 100644 Content.Shared/ADT/_RMC14/CCVar/RMCCVars.cs create mode 100644 Content.Shared/ADT/_RMC14/Input/ActiveInputMoverComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Input/CMKeyFunctions.cs create mode 100644 Content.Shared/ADT/_RMC14/Input/RMCInputSystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Inventory/CMHolsterChoose.cs create mode 100644 Content.Shared/ADT/_RMC14/Inventory/CMHolsterComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Inventory/CMHolsterLayers.cs create mode 100644 Content.Shared/ADT/_RMC14/Inventory/CMHolsterVisuals.cs create mode 100644 Content.Shared/ADT/_RMC14/Inventory/CMInventoryExtensions.cs create mode 100644 Content.Shared/ADT/_RMC14/Inventory/CMItemSlotsComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Inventory/CMItemSlotsLayers.cs create mode 100644 Content.Shared/ADT/_RMC14/Inventory/CMItemSlotsVisuals.cs create mode 100644 Content.Shared/ADT/_RMC14/Inventory/CMVirtualItemComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Inventory/IsUnholsterableEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Inventory/RMCDroppedEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Inventory/SharedCMInventorySystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Item/FixedItemSizeStorageComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Item/GetItemSizeModifiersEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Item/ItemSizeChangeComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Item/ItemSizeChangeSystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Item/ItemToggle/RMCItemToggleClothingVisualsComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Item/ItemToggle/RMCItemToggleSystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Item/MultiHandedHolderComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Item/MultiHandedHolderSystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Item/MultiHandedItem.cs create mode 100644 Content.Shared/ADT/_RMC14/Movement/TemporarySpeedModifiersComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Movement/TemporarySpeedModifiersSystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Projectiles/DeleteOnCollideComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Projectiles/ModifyTargetOnHitComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Projectiles/PreventCollideWithDeadComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Projectiles/ProjectileMaxRangeComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Projectiles/RMCProjectileDamageFalloffComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Projectiles/RMCProjectileSystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Projectiles/SpawnOnTerminateComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Random/SplitMix64.cs create mode 100644 Content.Shared/ADT/_RMC14/Random/Xoroshiro64S.cs create mode 100644 Content.Shared/ADT/_RMC14/Scoping/GunScopingComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Scoping/ScopeComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Scoping/ScopeCycleZoomLevelEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Scoping/ScopeDoAfterEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Scoping/ScopingComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Scoping/SharedScopeSystem.User.cs create mode 100644 Content.Shared/ADT/_RMC14/Scoping/SharedScopeSystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Sound/CMSoundSystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Sound/EmitSoundOnActionComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Sound/RandomSoundComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Sound/SoundActionEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Sound/SoundOnDeathComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Tackle/CMDisarmEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Tackle/TackleComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Tackle/TackleSystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Tackle/TackleableComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Tackle/TackledRecentlyComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Common/UniqueActionComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Common/UniqueActionEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Common/UniqueActionSystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Melee/ImmuneToMeleeComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Melee/ImmuneToUnarmedComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Melee/MeleeDamageMultiplierComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Melee/MeleeReceivedMultiplierComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Melee/MeleeResetComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Melee/SharedRMCMeleeWeaponSystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Melee/StunOnHitComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/Ammo/GunToggleAmmoActionEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/Ammo/GunToggleableAmmoComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/Ammo/GunToggleableAmmoSystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/BreechLoadedComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/BreechLoadedSystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/CMGunSystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/GetDamageFalloffEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/GetFireModeValuesEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/GetFireModesEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/GetGunDamageModifierEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/GunGetFireRateEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/PumpActionComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/RMCAmmoEjectComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/RMCFireGroupComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/RMCFireModeChangedEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/RMCSelectiveFireComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/RMCSelectiveFireSystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/RMCTryAmmoEjectEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/Recoil/GunToggleRecoilActionEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/Recoil/GunToggleableRecoilComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/Recoil/GunToggleableRecoilSystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/SharedFireGroupSystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/SharedPumpActionSystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/ShootUseDelayComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/ShootUseDelaySystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/Stacks/GunStacksComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/Stacks/GunStacksProjectileComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/Stacks/GunStacksSystem.cs create mode 100644 Content.Shared/ADT/_RMC14/Wieldable/Components/WieldDelayComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Wieldable/Components/WieldSlowdownCompensationComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Wieldable/Components/WieldSlowdownCompensationUserComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Wieldable/Components/WieldableSpeedModifiersComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Wieldable/Events/GetWieldDelayEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Wieldable/Events/GetWieldableSpeedModifiersEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Wieldable/Events/RefreshWieldSlowdownCompensationEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Wieldable/RMCWieldableSystem.cs create mode 100644 Content.Shared/Actions/AttachableToggleActionEvent.cs create mode 100644 Content.Shared/Weapons/Melee/Components/AltFireMeleeComponent.cs create mode 100644 Resources/Prototypes/ADT/_RMC14/Actions/Marines/marine_action_base.yml create mode 100644 Resources/Prototypes/ADT/_RMC14/Actions/Marines/marine_action_items.yml create mode 100644 Resources/Prototypes/ADT/_RMC14/test.yml create mode 100644 Resources/Textures/Objects/Weapons/Melee/kitchen_knife.rsi/icon_a.png diff --git a/Content.Client/Input/ContentContexts.cs b/Content.Client/Input/ContentContexts.cs index 4ae0ee62efa..e26ce672367 100644 --- a/Content.Client/Input/ContentContexts.cs +++ b/Content.Client/Input/ContentContexts.cs @@ -1,5 +1,6 @@ using Content.Shared.Input; using Robust.Shared.Input; +using Content.Shared._RMC14.Input; namespace Content.Client.Input { @@ -124,6 +125,23 @@ public static void SetupContexts(IInputContextContainer contexts) common.AddFunction(ContentKeyFunctions.OpenDecalSpawnWindow); common.AddFunction(ContentKeyFunctions.OpenAdminMenu); common.AddFunction(ContentKeyFunctions.OpenGuidebook); + + CMFunctions(contexts); + } + + private static void CMFunctions(IInputContextContainer contexts) + { + var human = contexts.GetContext("human"); + human.AddFunction(CMKeyFunctions.RMCActivateAttachableBarrel); + human.AddFunction(CMKeyFunctions.RMCActivateAttachableRail); + human.AddFunction(CMKeyFunctions.RMCActivateAttachableStock); + human.AddFunction(CMKeyFunctions.RMCActivateAttachableUnderbarrel); + human.AddFunction(CMKeyFunctions.RMCFieldStripHeldItem); + human.AddFunction(CMKeyFunctions.CMUniqueAction); + human.AddFunction(CMKeyFunctions.CMHolsterPrimary); + human.AddFunction(CMKeyFunctions.CMHolsterSecondary); + human.AddFunction(CMKeyFunctions.CMHolsterTertiary); + human.AddFunction(CMKeyFunctions.CMHolsterQuaternary); } } -} +} \ No newline at end of file diff --git a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs index 20b4330e985..60685694ce5 100644 --- a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs +++ b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs @@ -13,6 +13,7 @@ using Robust.Shared.Timing; using Robust.Shared.Utility; using static Robust.Client.UserInterface.Controls.BoxContainer; +using Content.Shared._RMC14.Input; namespace Content.Client.Options.UI.Tabs { @@ -151,6 +152,18 @@ void AddCheckBox(string checkBoxName, bool currentState, Action(OnProjectileImpact); + SubscribeAllEvent(OnProjectileImpact); } private void OnProjectileImpact(ImpactEffectEvent ev) diff --git a/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs b/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs index 7604d5f8808..609ea7c509e 100644 --- a/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs +++ b/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs @@ -1,11 +1,13 @@ using System.Linq; using Content.Client.Gameplay; +using Content.Shared._RMC14.Tackle; using Content.Shared.CombatMode; using Content.Shared.Effects; using Content.Shared.Hands.Components; using Content.Shared.Mobs.Components; using Content.Shared.StatusEffect; using Content.Shared.Weapons.Melee; +using Content.Shared.Weapons.Melee.Components; using Content.Shared.Weapons.Melee.Events; using Content.Shared.Weapons.Ranged.Components; using Robust.Client.GameObjects; @@ -88,16 +90,6 @@ public override void Update(float frameTime) // TODO using targeted actions while combat mode is enabled should NOT trigger attacks. - // TODO: Need to make alt-fire melee its own component I guess? - // Melee and guns share a lot in the middle but share virtually nothing at the start and end so - // it's kinda tricky. - // I think as long as we make secondaries their own component it's probably fine - // as long as guncomp has an alt-use key then it shouldn't be too much of a PITA to deal with. - if (TryComp(weaponUid, out var gun) && gun.UseKey) - { - return; - } - var mousePos = _eyeManager.PixelToMap(_inputManager.MouseScreenPosition); if (mousePos.MapId == MapId.Nullspace) @@ -116,51 +108,47 @@ public override void Update(float frameTime) coordinates = EntityCoordinates.FromMap(MapManager.GetMapEntityId(mousePos.MapId), mousePos, TransformSystem, EntityManager); } - // Heavy attack. - if (altDown == BoundKeyState.Down) + // If the gun has AltFireMeleeComponent, it can be used to attack. + if (TryComp(weaponUid, out var gun) && gun.UseKey) { - // If it's an unarmed attack then do a disarm - if (weapon.AltDisarm && weaponUid == entity) + if (!TryComp(weaponUid, out var altFireComponent) || altDown != BoundKeyState.Down) + return; + + switch(altFireComponent.AttackType) { - EntityUid? target = null; + case AltFireAttackType.Light: + ClientLightAttack(entity, mousePos, coordinates, weaponUid, weapon); + break; - if (_stateManager.CurrentState is GameplayStateBase screen) - { - target = screen.GetClickedEntity(mousePos); - } + case AltFireAttackType.Heavy: + ClientHeavyAttack(entity, coordinates, weaponUid, weapon); + break; - EntityManager.RaisePredictiveEvent(new DisarmAttackEvent(GetNetEntity(target), GetNetCoordinates(coordinates))); - return; + case AltFireAttackType.Disarm: + ClientDisarm(entity, mousePos, coordinates); + break; } - ClientHeavyAttack(entity, coordinates, weaponUid, weapon); return; } - // Light attack - if (useDown == BoundKeyState.Down) + // Heavy attack. + if (altDown == BoundKeyState.Down) { - var attackerPos = TransformSystem.GetMapCoordinates(entity); - - if (mousePos.MapId != attackerPos.MapId || - (attackerPos.Position - mousePos.Position).Length() > weapon.Range) + // If it's an unarmed attack then do a disarm + if (weapon.AltDisarm && weaponUid == entity) { + ClientDisarm(entity, mousePos, coordinates); return; } - EntityUid? target = null; - - if (_stateManager.CurrentState is GameplayStateBase screen) - { - target = screen.GetClickedEntity(mousePos); - } - - // Don't light-attack if interaction will be handling this instead - if (Interaction.CombatModeCanHandInteract(entity, target)) - return; - - RaisePredictiveEvent(new LightAttackEvent(GetNetEntity(target), GetNetEntity(weaponUid), GetNetCoordinates(coordinates))); + ClientHeavyAttack(entity, coordinates, weaponUid, weapon); + return; } + + // Light attack + if (useDown == BoundKeyState.Down) + ClientLightAttack(entity, mousePos, coordinates, weaponUid, weapon); } protected override bool InRange(EntityUid user, EntityUid target, float range, ICommonSession? session) @@ -190,6 +178,13 @@ protected override bool DoDisarm(EntityUid user, DisarmAttackEvent ev, EntityUid } var target = GetEntity(ev.Target); + if (target != null && InRange(user, target.Value, component.Range, session)) + { + var cmDisarmEvent = new CMDisarmEvent(user); + RaiseLocalEvent(target.Value, ref cmDisarmEvent); + if (cmDisarmEvent.Handled) + return true; + } // They need to either have hands... if (!HasComp(target!.Value)) @@ -211,7 +206,7 @@ protected override bool DoDisarm(EntityUid user, DisarmAttackEvent ev, EntityUid /// Raises a heavy attack event with the relevant attacked entities. /// This is to avoid lag effecting the client's perspective too much. /// - private void ClientHeavyAttack(EntityUid user, EntityCoordinates coordinates, EntityUid meleeUid, MeleeWeaponComponent component) + public void ClientHeavyAttack(EntityUid user, EntityCoordinates coordinates, EntityUid meleeUid, MeleeWeaponComponent component) { // Only run on first prediction to avoid the potential raycast entities changing. if (!_xformQuery.TryGetComponent(user, out var userXform) || @@ -235,6 +230,35 @@ private void ClientHeavyAttack(EntityUid user, EntityCoordinates coordinates, En RaisePredictiveEvent(new HeavyAttackEvent(GetNetEntity(meleeUid), entities.GetRange(0, Math.Min(MaxTargets, entities.Count)), GetNetCoordinates(coordinates))); } + private void ClientDisarm(EntityUid attacker, MapCoordinates mousePos, EntityCoordinates coordinates) + { + EntityUid? target = null; + + if (_stateManager.CurrentState is GameplayStateBase screen) + target = screen.GetClickedEntity(mousePos); + + RaisePredictiveEvent(new DisarmAttackEvent(GetNetEntity(target), GetNetCoordinates(coordinates))); + } + + private void ClientLightAttack(EntityUid attacker, MapCoordinates mousePos, EntityCoordinates coordinates, EntityUid weaponUid, MeleeWeaponComponent meleeComponent) + { + var attackerPos = TransformSystem.GetMapCoordinates(attacker); + + if (mousePos.MapId != attackerPos.MapId || (attackerPos.Position - mousePos.Position).Length() > meleeComponent.Range) + return; + + EntityUid? target = null; + + if (_stateManager.CurrentState is GameplayStateBase screen) + target = screen.GetClickedEntity(mousePos); + + // Don't light-attack if interaction will be handling this instead + if (Interaction.CombatModeCanHandInteract(attacker, target)) + return; + + RaisePredictiveEvent(new LightAttackEvent(GetNetEntity(target), GetNetEntity(weaponUid), GetNetCoordinates(coordinates))); + } + private void OnMeleeLunge(MeleeLungeEvent ev) { var ent = GetEntity(ev.Entity); diff --git a/Content.Client/_RMC14/Attachable/Components/AttachableHolderVisualsComponent.cs b/Content.Client/_RMC14/Attachable/Components/AttachableHolderVisualsComponent.cs new file mode 100644 index 00000000000..d1a1351691d --- /dev/null +++ b/Content.Client/_RMC14/Attachable/Components/AttachableHolderVisualsComponent.cs @@ -0,0 +1,17 @@ +using Content.Client._RMC14.Attachable.Systems; +using System.Numerics; + +namespace Content.Client._RMC14.Attachable.Components; + +[RegisterComponent, AutoGenerateComponentState] +[Access(typeof(AttachableHolderVisualsSystem))] +public sealed partial class AttachableHolderVisualsComponent : Component +{ + /// + /// This dictionary contains a list of offsets for every slot that should display the attachable placed into it. + /// If a slot is not in this dictionary, the attachable inside will not be displayed. + /// The list of valid slot names can be found in AttachableHolderComponent.cs + /// + [DataField(required: true), AutoNetworkedField] + public Dictionary Offsets = new(); +} diff --git a/Content.Client/_RMC14/Attachable/Components/AttachableVisualsComponent.cs b/Content.Client/_RMC14/Attachable/Components/AttachableVisualsComponent.cs new file mode 100644 index 00000000000..51100e8a74c --- /dev/null +++ b/Content.Client/_RMC14/Attachable/Components/AttachableVisualsComponent.cs @@ -0,0 +1,66 @@ +using Content.Client._RMC14.Attachable.Systems; +using System.Numerics; +using Robust.Shared.Utility; + +namespace Content.Client._RMC14.Attachable.Components; + +[RegisterComponent, AutoGenerateComponentState] +[Access(typeof(AttachableHolderVisualsSystem))] +public sealed partial class AttachableVisualsComponent : Component +{ + /// + /// Optional, only used if the item's own state should not be used. + /// The path to the RSI file that contains all the attached states. + /// + [DataField, AutoNetworkedField] + public ResPath? Rsi; + + /// + /// Optional, only used if the item's own state should not be used. + /// This prefix is added to the name of the slot the attachable is installed in. + /// The prefix must be in kebab-case and end with a dash, like so: example-prefix- + /// The RSI must contain a state for every slot the attachable fits into. + /// If the attachment only fits into one slot, it should be named as follows: normal-state_suffix. + /// The slot names can be found in AttachableHolderComponent.cs + /// + [DataField, AutoNetworkedField] + public string? Prefix; + + /// + /// Optional, only used if the item's own state should not be used. + /// This suffix is added to the name of the slot the attachable is installed in. + /// The RSI must contain a state for every slot the attachable fits into. + /// If the attachment only fits into one slot, it should be named as follows: normal-state_suffix. + /// The slot names can be found in AttachableHolderComponent.cs + /// + [DataField, AutoNetworkedField] + public string? Suffix = "_a"; + + /// + /// If true, will include the holder's slot name to find this attachment's state + /// in its RSI. + /// In this case, there must be a separate state for each slot the attachment fits into. + /// The states should be named as follows: prefix-slot-name-suffix. + /// + [DataField, AutoNetworkedField] + public bool IncludeSlotName; + + /// + /// If this is toggled on and the item has an AttachableToggleableComponent, then the visualisation system will try to show a different sprite when it's active. + /// Each active state must have "-on" appended to the end of its name. + /// + [DataField, AutoNetworkedField] + public bool ShowActive; + + /// + /// If this is set to true, the attachment will be redrawn on its holder every time it receives an AppearanceChangeEvent. Useful for things like the UGL. + /// + [DataField, AutoNetworkedField] + public bool RedrawOnAppearanceChange; + + [DataField, AutoNetworkedField] + public int Layer; + + [DataField, AutoNetworkedField] + public Vector2 Offset; +} diff --git a/Content.Client/_RMC14/Attachable/Systems/AttachableHolderVisualsSystem.cs b/Content.Client/_RMC14/Attachable/Systems/AttachableHolderVisualsSystem.cs new file mode 100644 index 00000000000..b083f1ca2b6 --- /dev/null +++ b/Content.Client/_RMC14/Attachable/Systems/AttachableHolderVisualsSystem.cs @@ -0,0 +1,155 @@ +using Content.Client._RMC14.Attachable.Components; +using Content.Shared._RMC14.Attachable; +using Content.Shared._RMC14.Attachable.Components; +using Content.Shared._RMC14.Attachable.Events; +using Content.Shared._RMC14.Attachable.Systems; +using Robust.Client.GameObjects; +using Robust.Shared.Containers; + +namespace Content.Client._RMC14.Attachable.Systems; + +public sealed class AttachableHolderVisualsSystem : EntitySystem +{ + [Dependency] private readonly AttachableHolderSystem _attachableHolderSystem = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnDetached); + SubscribeLocalEvent(OnAttachablesAltered); + + SubscribeLocalEvent(OnAttachableAppearanceChange); + } + + private void OnDetached(Entity holder, ref EntRemovedFromContainerMessage args) + { + if (!HasComp(args.Entity) || !_attachableHolderSystem.HasSlot(holder.Owner, args.Container.ID)) + return; + + var holderEv = new AttachableHolderAttachablesAlteredEvent(args.Entity, args.Container.ID, AttachableAlteredType.Detached); + RaiseLocalEvent(holder, ref holderEv); + } + + private void OnAttachablesAltered(Entity holder, + ref AttachableHolderAttachablesAlteredEvent args) + { + if (!TryComp(args.Attachable, out AttachableVisualsComponent? attachableComponent)) + return; + + string suffix = ""; + if (attachableComponent.ShowActive && TryComp(args.Attachable, out AttachableToggleableComponent? toggleableComponent) && toggleableComponent.Active) + suffix = "-on"; + + var attachable = new Entity(args.Attachable, attachableComponent); + switch (args.Alteration) + { + case AttachableAlteredType.Attached: + SetAttachableOverlay(holder, attachable, args.SlotId, suffix); + break; + + case AttachableAlteredType.Detached: + RemoveAttachableOverlay(holder, args.SlotId); + break; + + case AttachableAlteredType.Activated: + if (!attachableComponent.ShowActive) + break; + + SetAttachableOverlay(holder, attachable, args.SlotId, suffix); + break; + + case AttachableAlteredType.Deactivated: + if (!attachableComponent.ShowActive) + break; + + SetAttachableOverlay(holder, attachable, args.SlotId, suffix); + break; + + case AttachableAlteredType.Interrupted: + if (!attachableComponent.ShowActive) + break; + + SetAttachableOverlay(holder, attachable, args.SlotId); + break; + + case AttachableAlteredType.AppearanceChanged: + SetAttachableOverlay(holder, attachable, args.SlotId, suffix); + break; + } + } + + private void RemoveAttachableOverlay(Entity holder, string slotId) + { + if (!holder.Comp.Offsets.ContainsKey(slotId) || !TryComp(holder, out SpriteComponent? spriteComponent)) + return; + + if (!spriteComponent.LayerMapTryGet(slotId, out var index)) + return; + + spriteComponent.LayerMapRemove(slotId); + spriteComponent.RemoveLayer(index); + } + + private void SetAttachableOverlay(Entity holder, + Entity attachable, + string slotId, + string suffix = "") + { + if (!holder.Comp.Offsets.ContainsKey(slotId) || + !TryComp(holder, out SpriteComponent? holderSprite)) + { + return; + } + + if (!TryComp(attachable, out SpriteComponent? attachableSprite)) + return; + + var rsi = attachableSprite.LayerGetActualRSI(attachable.Comp.Layer)?.Path; + var state = attachableSprite.LayerGetState(attachable.Comp.Layer).ToString(); + if (attachable.Comp.Rsi is { } rsiPath) + { + rsi = rsiPath; + } + + if (!string.IsNullOrWhiteSpace(attachable.Comp.Prefix)) + state = attachable.Comp.Prefix; + + if (attachable.Comp.IncludeSlotName) + state += slotId; + + if (!string.IsNullOrWhiteSpace(attachable.Comp.Suffix)) + state += attachable.Comp.Suffix; + + state += suffix; + + var layerData = new PrototypeLayerData() + { + RsiPath = rsi.ToString(), + State = state, + Offset = holder.Comp.Offsets[slotId] + attachable.Comp.Offset, + Visible = true, + }; + + if (holderSprite.LayerMapTryGet(slotId, out var index)) + { + holderSprite.LayerSetData(index, layerData); + return; + } + + holderSprite.LayerMapSet(slotId, holderSprite.AddLayer(layerData)); + } + + private void OnAttachableAppearanceChange(Entity attachable, ref AppearanceChangeEvent args) + { + if (!attachable.Comp.RedrawOnAppearanceChange || + !_attachableHolderSystem.TryGetHolder(attachable.Owner, out var holderUid) || + !_attachableHolderSystem.TryGetSlotId(holderUid.Value, attachable.Owner, out var slotId)) + { + return; + } + + var holderEvent = new AttachableHolderAttachablesAlteredEvent(attachable.Owner, slotId, AttachableAlteredType.AppearanceChanged); + RaiseLocalEvent(holderUid.Value, ref holderEvent); + } +} diff --git a/Content.Client/_RMC14/Attachable/Ui/AttachableHolderChooseSlotMenu.xaml b/Content.Client/_RMC14/Attachable/Ui/AttachableHolderChooseSlotMenu.xaml new file mode 100644 index 00000000000..c2ff1b5b704 --- /dev/null +++ b/Content.Client/_RMC14/Attachable/Ui/AttachableHolderChooseSlotMenu.xaml @@ -0,0 +1,9 @@ + + + diff --git a/Content.Client/_RMC14/Attachable/Ui/AttachableHolderChooseSlotMenu.xaml.cs b/Content.Client/_RMC14/Attachable/Ui/AttachableHolderChooseSlotMenu.xaml.cs new file mode 100644 index 00000000000..704d2eb1aa1 --- /dev/null +++ b/Content.Client/_RMC14/Attachable/Ui/AttachableHolderChooseSlotMenu.xaml.cs @@ -0,0 +1,58 @@ +using Content.Client.UserInterface.Controls; +using Content.Shared._RMC14.Attachable; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client._RMC14.Attachable.Ui; + +[GenerateTypedNameReferences] +public sealed partial class AttachableHolderChooseSlotMenu : FancyWindow +{ + private readonly AttachmentChooseSlotBui _boundUI; + private readonly Dictionary _attachableSlotControls; + + public AttachableHolderChooseSlotMenu(AttachmentChooseSlotBui boundUI) + { + RobustXamlLoader.Load(this); + + _boundUI = boundUI; + _attachableSlotControls = new Dictionary(); + OnClose += boundUI.Close; + } + + public void UpdateMenu(List attachableSlots) + { + foreach (var slotId in attachableSlots) + { + if (!_attachableSlotControls.ContainsKey(slotId)) + AddSlotControl(slotId); + } + } + + private void AddSlotControl(string slotId) + { + var slotControl = new AttachableSlotControl(this, _boundUI, slotId); + SlotsContainer.AddChild(slotControl); + _attachableSlotControls.Add(slotId, slotControl); + } + + private sealed class AttachableSlotControl : Control + { + public AttachableSlotControl(AttachableHolderChooseSlotMenu slotMenu, + AttachmentChooseSlotBui boundUI, + string slotId) + { + var button = new Button { Text = Loc.GetString(slotId) }; + + button.OnPressed += _ => + { + boundUI.SendMessage(new AttachableHolderAttachToSlotMessage(slotId)); + slotMenu.Close(); + }; + + AddChild(button); + } + } +} diff --git a/Content.Client/_RMC14/Attachable/Ui/AttachableHolderStripMenu.xaml b/Content.Client/_RMC14/Attachable/Ui/AttachableHolderStripMenu.xaml new file mode 100644 index 00000000000..a21514abeda --- /dev/null +++ b/Content.Client/_RMC14/Attachable/Ui/AttachableHolderStripMenu.xaml @@ -0,0 +1,9 @@ + + + diff --git a/Content.Client/_RMC14/Attachable/Ui/AttachableHolderStripMenu.xaml.cs b/Content.Client/_RMC14/Attachable/Ui/AttachableHolderStripMenu.xaml.cs new file mode 100644 index 00000000000..ce1fe4be914 --- /dev/null +++ b/Content.Client/_RMC14/Attachable/Ui/AttachableHolderStripMenu.xaml.cs @@ -0,0 +1,95 @@ +using System.Numerics; +using Content.Client.Stylesheets; +using Content.Client.UserInterface.Controls; +using Content.Shared._RMC14.Attachable; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; +using static Robust.Client.UserInterface.Controls.BoxContainer; + +namespace Content.Client._RMC14.Attachable.Ui; + +[GenerateTypedNameReferences] +public sealed partial class AttachableHolderStripMenu : FancyWindow +{ + private readonly AttachmentStripBui _boundUI; + private readonly Dictionary _attachableSlotControls; + + public AttachableHolderStripMenu(AttachmentStripBui boundUI) + { + RobustXamlLoader.Load(this); + + _boundUI = boundUI; + _attachableSlotControls = new Dictionary(); + OnClose += boundUI.Close; + } + + public void UpdateMenu(Dictionary attachableSlots) + { + foreach (var slotId in attachableSlots.Keys) + { + if (!_attachableSlotControls.ContainsKey(slotId)) + AddSlotControl(slotId); + + _attachableSlotControls[slotId].Update(attachableSlots[slotId].attachableName, attachableSlots[slotId].locked); + } + } + + private void AddSlotControl(string slotId, string? attachableName = null) + { + var slotControl = new AttachableSlotControl(_boundUI, slotId); + AttachablesContainer.AddChild(slotControl); + _attachableSlotControls.Add(slotId, slotControl); + } + + private sealed class AttachableSlotControl : Control + { + private readonly Button AttachableButton; + + public AttachableSlotControl(AttachmentStripBui boundUI, string slotId) + { + var slotLabel = new Label + { + Text = Loc.GetString(slotId) + ':', + HorizontalAlignment = HAlignment.Left + }; + + AttachableButton = new Button + { + Text = Loc.GetString("rmc-attachable-holder-strip-ui-empty-slot"), + HorizontalExpand = true, + HorizontalAlignment = HAlignment.Right, + StyleClasses = { StyleBase.ButtonOpenRight } + }; + + var hBox = new BoxContainer + { + Orientation = LayoutOrientation.Horizontal, + Children = + { + new Control { MinSize = new Vector2(5, 0) }, + slotLabel, + new Control { MinSize = new Vector2(5, 0) }, + AttachableButton, + }, + }; + + AttachableButton.OnPressed += _ => boundUI.SendMessage(new AttachableHolderDetachMessage(slotId)); + AddChild(hBox); + } + + public void Update(string? attachableName, bool slotLocked) + { + if (attachableName == null) + { + AttachableButton.Text = Loc.GetString("rmc-attachable-holder-strip-ui-empty-slot"); + AttachableButton.Disabled = true; + return; + } + + AttachableButton.Text = attachableName; + AttachableButton.Disabled = slotLocked; + } + } +} diff --git a/Content.Client/_RMC14/Attachable/Ui/AttachmentChooseSlotBui.cs b/Content.Client/_RMC14/Attachable/Ui/AttachmentChooseSlotBui.cs new file mode 100644 index 00000000000..cdc48adb9a1 --- /dev/null +++ b/Content.Client/_RMC14/Attachable/Ui/AttachmentChooseSlotBui.cs @@ -0,0 +1,45 @@ +using Content.Shared._RMC14.Attachable; + +namespace Content.Client._RMC14.Attachable.Ui; + +public sealed class AttachmentChooseSlotBui : BoundUserInterface +{ + [ViewVariables] + private AttachableHolderChooseSlotMenu? _menu; + + public AttachmentChooseSlotBui(EntityUid owner, Enum uiKey) : base(owner, uiKey) { } + + protected override void Open() + { + base.Open(); + + _menu = new AttachableHolderChooseSlotMenu(this); + var metaQuery = EntMan.GetEntityQuery(); + if (metaQuery.TryGetComponent(Owner, out var metadata)) + _menu.Title = metadata.EntityName; + + _menu.OpenCentered(); + } + + protected override void UpdateState(BoundUserInterfaceState state) + { + base.UpdateState(state); + + if (state is not AttachableHolderChooseSlotUserInterfaceState msg) + return; + + if (_menu == null) + return; + + _menu.UpdateMenu(msg.AttachableSlots); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + return; + + _menu?.Dispose(); + } +} diff --git a/Content.Client/_RMC14/Attachable/Ui/AttachmentStripBui.cs b/Content.Client/_RMC14/Attachable/Ui/AttachmentStripBui.cs new file mode 100644 index 00000000000..69fdbdc55bc --- /dev/null +++ b/Content.Client/_RMC14/Attachable/Ui/AttachmentStripBui.cs @@ -0,0 +1,45 @@ +using Content.Shared._RMC14.Attachable; + +namespace Content.Client._RMC14.Attachable.Ui; + +public sealed class AttachmentStripBui : BoundUserInterface +{ + private AttachableHolderStripMenu? _menu; + + public AttachmentStripBui(EntityUid owner, Enum uiKey) : base(owner, uiKey) { } + + protected override void Open() + { + base.Open(); + + _menu = new AttachableHolderStripMenu(this); + + var metaQuery = EntMan.GetEntityQuery(); + if (metaQuery.TryGetComponent(Owner, out var metadata)) + _menu.Title = metadata.EntityName; + + _menu.OpenCentered(); + } + + protected override void UpdateState(BoundUserInterfaceState state) + { + base.UpdateState(state); + + if (state is not AttachableHolderStripUserInterfaceState msg) + return; + + if (_menu == null) + return; + + _menu.UpdateMenu(msg.AttachableSlots); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + return; + + _menu?.Dispose(); + } +} diff --git a/Content.Shared/ADT/_RMC14/Actions/ActionCooldownComponent.cs b/Content.Shared/ADT/_RMC14/Actions/ActionCooldownComponent.cs new file mode 100644 index 00000000000..0b9637ea10c --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Actions/ActionCooldownComponent.cs @@ -0,0 +1,11 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Actions; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(RMCActionsSystem))] +public sealed partial class ActionCooldownComponent : Component +{ + [DataField, AutoNetworkedField] + public TimeSpan Cooldown; +} diff --git a/Content.Shared/ADT/_RMC14/Actions/ActionReducedUseDelayComponent.cs b/Content.Shared/ADT/_RMC14/Actions/ActionReducedUseDelayComponent.cs new file mode 100644 index 00000000000..381b3db3d4b --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Actions/ActionReducedUseDelayComponent.cs @@ -0,0 +1,18 @@ +using Content.Shared.FixedPoint; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared._RMC14.Actions; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(RMCActionsSystem))] +public sealed partial class ActionReducedUseDelayComponent : Component +{ + // Default cooldown without reductions + [DataField, AutoNetworkedField] + public TimeSpan? UseDelayBase = default!; + + // Cooldown reduction percentage + [DataField, AutoNetworkedField] + public FixedPoint2 UseDelayReduction = default!; +} diff --git a/Content.Shared/ADT/_RMC14/Actions/ActionReducedUseDelayEvent.cs b/Content.Shared/ADT/_RMC14/Actions/ActionReducedUseDelayEvent.cs new file mode 100644 index 00000000000..b4a1ceab71f --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Actions/ActionReducedUseDelayEvent.cs @@ -0,0 +1,7 @@ +using Content.Shared.FixedPoint; + +namespace Content.Shared._RMC14.Actions; + +// If amount is 0, will reset usedelay to default value +// If amount is between 0 and 1, will reduce usedelay +public record struct ActionReducedUseDelayEvent(FixedPoint2 Amount); diff --git a/Content.Shared/ADT/_RMC14/Actions/ActionSharedCooldownComponent.cs b/Content.Shared/ADT/_RMC14/Actions/ActionSharedCooldownComponent.cs new file mode 100644 index 00000000000..1db4e0888bc --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Actions/ActionSharedCooldownComponent.cs @@ -0,0 +1,21 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared._RMC14.Actions; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(RMCActionsSystem))] +public sealed partial class ActionSharedCooldownComponent : Component +{ + [DataField, AutoNetworkedField] + public EntProtoId? Id; + + [DataField, AutoNetworkedField] + public HashSet Ids = new(); + + [DataField, AutoNetworkedField] + public TimeSpan Cooldown; + + [DataField, AutoNetworkedField] + public bool OnPerform = true; +} diff --git a/Content.Shared/ADT/_RMC14/Actions/RMCActionUseAttemptEvent.cs b/Content.Shared/ADT/_RMC14/Actions/RMCActionUseAttemptEvent.cs new file mode 100644 index 00000000000..cea0989c2b4 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Actions/RMCActionUseAttemptEvent.cs @@ -0,0 +1,4 @@ +namespace Content.Shared._RMC14.Actions; + +[ByRefEvent] +public record struct RMCActionUseAttemptEvent(EntityUid User, bool Cancelled = false); diff --git a/Content.Shared/ADT/_RMC14/Actions/RMCActionUseEvent.cs b/Content.Shared/ADT/_RMC14/Actions/RMCActionUseEvent.cs new file mode 100644 index 00000000000..cb3490f8e3c --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Actions/RMCActionUseEvent.cs @@ -0,0 +1,4 @@ +namespace Content.Shared._RMC14.Actions; + +[ByRefEvent] +public readonly record struct RMCActionUseEvent(EntityUid User); diff --git a/Content.Shared/ADT/_RMC14/Actions/RMCActionsSystem.cs b/Content.Shared/ADT/_RMC14/Actions/RMCActionsSystem.cs new file mode 100644 index 00000000000..a5f77834033 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Actions/RMCActionsSystem.cs @@ -0,0 +1,126 @@ +using Content.Shared.Actions; +using Content.Shared.Actions.Events; +using Content.Shared.FixedPoint; + +namespace Content.Shared._RMC14.Actions; + +public sealed class RMCActionsSystem : EntitySystem +{ + [Dependency] private readonly SharedActionsSystem _actions = default!; + + private EntityQuery _actionSharedCooldownQuery; + + public override void Initialize() + { + _actionSharedCooldownQuery = GetEntityQuery(); + + SubscribeLocalEvent(OnSharedCooldownPerformed); + + SubscribeLocalEvent(OnCooldownUse); + + SubscribeLocalEvent(OnReducedUseDelayEvent); + SubscribeLocalEvent(OnReducedUseDelayEvent); + SubscribeLocalEvent(OnReducedUseDelayEvent); + SubscribeLocalEvent(OnReducedUseDelayEvent); + } + + private void OnSharedCooldownPerformed(Entity ent, ref ActionPerformedEvent args) + { + if (ent.Comp.OnPerform) + ActivateSharedCooldown((ent, ent), args.Performer); + } + + public void ActivateSharedCooldown(Entity action, EntityUid performer) + { + if (!Resolve(action, ref action.Comp, false)) + return; + + if (action.Comp.Cooldown == TimeSpan.Zero) + return; + + foreach (var (actionId, _) in _actions.GetActions(performer)) + { + if (!_actionSharedCooldownQuery.TryComp(actionId, out var shared)) + continue; + + // Same ID or primary ID found in subset of other action's ids + if ((shared.Id != null && shared.Id == action.Comp.Id) || (action.Comp.Id != null && shared.Ids.Contains(action.Comp.Id.Value))) + _actions.SetIfBiggerCooldown(actionId, action.Comp.Cooldown); + } + } + + private void OnReducedUseDelayEvent(EntityUid uid, T component, ActionReducedUseDelayEvent args) where T : BaseActionComponent + { + if (!TryComp(uid, out ActionReducedUseDelayComponent? comp)) + return; + + if (args.Amount < 0 || args.Amount > 1) + return; + + comp.UseDelayReduction = args.Amount; + + if (TryComp(uid, out ActionSharedCooldownComponent? shared)) + { + if (comp.UseDelayBase == null) + comp.UseDelayBase = shared.Cooldown; + + RefreshSharedUseDelay((uid, comp), shared); + return; + } + + // Should be fine to only set this once as the base use delay should remain constant + if (comp.UseDelayBase == null) + comp.UseDelayBase = component.UseDelay; + + RefreshUseDelay((uid, comp)); + } + + private void RefreshUseDelay(Entity ent) + { + if (ent.Comp.UseDelayBase is not { } delayBase) + return; + + var reduction = ent.Comp.UseDelayReduction.Double(); + var delayNew = delayBase.Multiply(1 - reduction); + + _actions.SetUseDelay(ent.Owner, delayNew); + } + + private void RefreshSharedUseDelay(Entity ent, ActionSharedCooldownComponent shared) + { + if (ent.Comp.UseDelayBase is not { } delayBase) + return; + + var reduction = ent.Comp.UseDelayReduction.Double(); + var delayNew = delayBase.Multiply(1 - reduction); + + shared.Cooldown = delayNew; + } + + private void OnCooldownUse(Entity ent, ref RMCActionUseEvent args) + { + _actions.SetIfBiggerCooldown(ent, ent.Comp.Cooldown); + } + + public bool CanUseActionPopup(EntityUid user, EntityUid action) + { + var ev = new RMCActionUseAttemptEvent(user); + RaiseLocalEvent(action, ref ev); + return !ev.Cancelled; + } + + public void ActionUsed(EntityUid user, EntityUid action) + { + var ev = new RMCActionUseEvent(user); + RaiseLocalEvent(action, ref ev); + } + + public bool TryUseAction(EntityUid user, EntityUid action) + { + if (!CanUseActionPopup(user, action)) + return false; + + ActionUsed(user, action); + return true; + } +} diff --git a/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticArmorComponent.cs b/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticArmorComponent.cs new file mode 100644 index 00000000000..a043d1cfe49 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticArmorComponent.cs @@ -0,0 +1,12 @@ +using Content.Shared.Inventory; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Armor.Magnetic; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(RMCMagneticSystem))] +public sealed partial class RMCMagneticArmorComponent : Component +{ + [DataField, AutoNetworkedField] + public SlotFlags AllowMagnetizeToSlots = SlotFlags.SUITSTORAGE; +} diff --git a/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticItemComponent.cs b/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticItemComponent.cs new file mode 100644 index 00000000000..dc3bf644f13 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticItemComponent.cs @@ -0,0 +1,12 @@ +using Content.Shared.Inventory; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Armor.Magnetic; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(RMCMagneticSystem))] +public sealed partial class RMCMagneticItemComponent : Component +{ + [DataField, AutoNetworkedField] + public SlotFlags MagnetizeToSlots = SlotFlags.SUITSTORAGE; +} diff --git a/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticSystem.cs b/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticSystem.cs new file mode 100644 index 00000000000..9c5e909e06e --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticSystem.cs @@ -0,0 +1,135 @@ +using Content.Shared._RMC14.Inventory; +using Content.Shared.Hands; +using Content.Shared.Interaction.Events; +using Content.Shared.Inventory; +using Content.Shared.Popups; +using Content.Shared.Throwing; + +namespace Content.Shared._RMC14.Armor.Magnetic; + +public sealed class RMCMagneticSystem : EntitySystem +{ + [Dependency] private readonly InventorySystem _inventory = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly ThrownItemSystem _thrownItem = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnMagneticItemDropped); + SubscribeLocalEvent(OnMagneticItemRMCDropped); + SubscribeLocalEvent(OnMagneticItemThrown); + SubscribeLocalEvent(OnMagneticItemDropAttempt); + + SubscribeLocalEvent>(OnMagnetizeItem); + + SubscribeLocalEvent(_inventory.RelayEvent); + } + + private void OnMagneticItemDropped(Entity ent, ref DroppedEvent args) + { + TryReturn(ent, args.User); + } + + private void OnMagneticItemRMCDropped(Entity ent, ref RMCDroppedEvent args) + { + TryReturn(ent, args.User); + } + + private void OnMagneticItemThrown(Entity ent, ref ThrownEvent args) + { + if (args.User is not { } user) + return; + + if (!TryReturn(ent, user)) + return; + + if (TryComp(ent, out ThrownItemComponent? thrown)) + _thrownItem.StopThrow(ent, thrown); + } + + private void OnMagneticItemDropAttempt(Entity ent, ref DropAttemptEvent args) + { + if (!CanReturn(ent, args.Uid, out _)) + return; + + args.Cancel(); + } + + private void OnMagnetizeItem(Entity ent, ref InventoryRelayedEvent args) + { + if ((ent.Comp.AllowMagnetizeToSlots & args.Args.MagnetizeToSlots) == SlotFlags.NONE) + return; + + var slotEnumerator = _inventory.GetSlotEnumerator(args.Args.User, ent.Comp.AllowMagnetizeToSlots & args.Args.MagnetizeToSlots); + + while (slotEnumerator.MoveNext(out var container)) + { + if (container.Count > 0) + continue; + + args.Args.Magnetizer = ent; + break; + } + } + + private bool CanReturn(Entity ent, EntityUid user, out EntityUid magnetizer) + { + var ev = new RMCMagnetizeItemEvent(user, ent.Comp.MagnetizeToSlots, SlotFlags.OUTERCLOTHING); + RaiseLocalEvent(user, ref ev); + + magnetizer = ev.Magnetizer ?? default; + return magnetizer != default; + } + + private bool TryReturn(Entity ent, EntityUid user) + { + if (!CanReturn(ent, user, out var magnetizer)) + return false; + + var returnComp = EnsureComp(ent); + returnComp.User = user; + returnComp.Magnetizer = magnetizer; + + Dirty(ent, returnComp); + return true; + } + + public void SetMagnetizeToSlots(Entity ent, SlotFlags slots) + { + ent.Comp.MagnetizeToSlots = slots; + Dirty(ent); + } + + public override void Update(float frameTime) + { + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var comp)) + { + if (comp.Returned) + continue; + + var user = comp.User; + var magnetizer = comp.Magnetizer; + if (!TerminatingOrDeleted(user) && !TerminatingOrDeleted(magnetizer)) + { + var slots = _inventory.GetSlotEnumerator(user, SlotFlags.SUITSTORAGE); + while (slots.MoveNext(out var slot)) + { + if (_inventory.TryEquip(user, uid, slot.ID, force: true)) + { + var popup = Loc.GetString("rmc-magnetize-return", + ("item", uid), + ("magnetizer", magnetizer)); + _popup.PopupClient(popup, user, user, PopupType.Medium); + + comp.Returned = true; + Dirty(uid, comp); + break; + } + } + } + + RemCompDeferred(uid); + } + } +} diff --git a/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagnetizeItemEvent.cs b/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagnetizeItemEvent.cs new file mode 100644 index 00000000000..c922aa48992 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagnetizeItemEvent.cs @@ -0,0 +1,11 @@ +using Content.Shared.Inventory; + +namespace Content.Shared._RMC14.Armor.Magnetic; + +[ByRefEvent] +public record struct RMCMagnetizeItemEvent( + EntityUid User, + SlotFlags MagnetizeToSlots, + SlotFlags TargetSlots, + EntityUid? Magnetizer = null +) : IInventoryRelayEvent; diff --git a/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCReturnToInventoryComponent.cs b/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCReturnToInventoryComponent.cs new file mode 100644 index 00000000000..5d85fa47e1e --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCReturnToInventoryComponent.cs @@ -0,0 +1,17 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Armor.Magnetic; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(RMCMagneticSystem))] +public sealed partial class RMCReturnToInventoryComponent : Component +{ + [DataField, AutoNetworkedField] + public EntityUid User; + + [DataField, AutoNetworkedField] + public EntityUid Magnetizer; + + [DataField, AutoNetworkedField] + public bool Returned; +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/AttachableData.cs b/Content.Shared/ADT/_RMC14/Attachable/AttachableData.cs new file mode 100644 index 00000000000..cccd1c2bb49 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/AttachableData.cs @@ -0,0 +1,78 @@ +using Content.Shared.Damage; +using Content.Shared.FixedPoint; +using Content.Shared.Weapons.Ranged.Components; +using Content.Shared.Whitelist; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; + +namespace Content.Shared._RMC14.Attachable; + +[DataRecord, Serializable, NetSerializable] +public record struct AttachableSlot( + bool Locked, + EntityWhitelist Whitelist, + ProtoId? StartingAttachable +); + +[DataRecord, Serializable, NetSerializable] +public record struct AttachableModifierConditions( + bool UnwieldedOnly, + bool WieldedOnly, + bool ActiveOnly, + bool InactiveOnly, + EntityWhitelist? Whitelist, + EntityWhitelist? Blacklist +); + +[DataRecord, Serializable, NetSerializable] +public record struct AttachableWeaponMeleeModifierSet( + AttachableModifierConditions? Conditions, + DamageSpecifier? BonusDamage +); + +[DataRecord, Serializable, NetSerializable] +public record struct AttachableWeaponRangedModifierSet( + AttachableModifierConditions? Conditions, + FixedPoint2 AccuracyAddMult, // Not implemented yet. Added to have all the values already on our attachments, so whoever implements this doesn't need to dig through CM13. Remove this comment once implemented. + FixedPoint2 AccuracyMovementPenaltyAddMult, // As above. + FixedPoint2 DamageFalloffAddMult, // This affects the damage falloff of all shots fired by the weapon. Conversion to RMC: damage_falloff_mod + double BurstScatterAddMult, // This affects scatter during burst and full-auto fire. Conversion to RMC: burst_scatter_mod + int ShotsPerBurstFlat, // Modifies the maximum number of shots in a burst. + FixedPoint2 DamageAddMult, // Additive multiplier to damage. + float RecoilFlat, // How much the camera shakes when you shoot. + double ScatterFlat, // Scatter in degrees. This is how far bullets go from where you aim. Conversion to RMC: CM_SCATTER * 2 + float FireDelayFlat, // The delay between each shot. Conversion to RMC: CM_FIRE_DELAY / 10 + float ProjectileSpeedFlat // How fast the projectiles move. Conversion to RMC: CM_PROJECTILE_SPEED * 10 +); + +[DataRecord, Serializable, NetSerializable] +public record struct AttachableWeaponFireModesModifierSet( + AttachableModifierConditions? Conditions, + SelectiveFire ExtraFireModes, + SelectiveFire SetFireMode +); + +// SS13 has move delay instead of speed. Move delay isn't implemented here, and approximating it through maths like fire delay is scuffed because of how the events used to change speed work. +// So instead we take the default speed values and use them to convert it to a multiplier beforehand. +// Converting from move delay to additive multiplier: 1 / (1 / SS14_SPEED + SS13_MOVE_DELAY / 10) / SS14_SPEED - 1 +// Speed and move delay are inversely proportional. So 1 divided by speed is move delay and vice versa. +// We then add the ss13 move delay, and divide 1 by the result to convert it back into speed. +// Then we divide it by the original speed and subtract 1 from the result to get the additive multiplier. +[DataRecord, Serializable, NetSerializable] +public record struct AttachableSpeedModifierSet( + AttachableModifierConditions? Conditions, + float Walk, // Default human walk speed: 2.5f + float Sprint // Default human sprint speed: 4.5f +); + +[DataRecord, Serializable, NetSerializable] +public record struct AttachableSizeModifierSet( + AttachableModifierConditions? Conditions, + int Size +); + +[DataRecord, Serializable, NetSerializable] +public record struct AttachableWieldDelayModifierSet( + AttachableModifierConditions? Conditions, + TimeSpan Delay +); diff --git a/Content.Shared/ADT/_RMC14/Attachable/AttachableUI.cs b/Content.Shared/ADT/_RMC14/Attachable/AttachableUI.cs new file mode 100644 index 00000000000..4bab6dbb2b8 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/AttachableUI.cs @@ -0,0 +1,35 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared._RMC14.Attachable; + +[Serializable, NetSerializable] +public sealed class AttachableHolderStripUserInterfaceState(Dictionary attachableSlots) + : BoundUserInterfaceState +{ + public Dictionary AttachableSlots = attachableSlots; +} + +[Serializable, NetSerializable] +public sealed class AttachableHolderChooseSlotUserInterfaceState(List attachableSlots) : BoundUserInterfaceState +{ + public List AttachableSlots = attachableSlots; +} + +[Serializable, NetSerializable] +public sealed class AttachableHolderDetachMessage(string slot) : BoundUserInterfaceMessage +{ + public readonly string Slot = slot; +} + +[Serializable, NetSerializable] +public sealed class AttachableHolderAttachToSlotMessage(string slot) : BoundUserInterfaceMessage +{ + public readonly string Slot = slot; +} + +[Serializable, NetSerializable] +public enum AttachmentUI : byte +{ + StripKey, + ChooseSlotKey, +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableComponent.cs b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableComponent.cs new file mode 100644 index 00000000000..dd55d2bf9eb --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableComponent.cs @@ -0,0 +1,19 @@ +using Content.Shared._RMC14.Attachable.Systems; +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Attachable.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(AttachableHolderSystem))] +public sealed partial class AttachableComponent : Component +{ + [DataField, AutoNetworkedField] + public float AttachDoAfter = 1.5f; + + [DataField, AutoNetworkedField] + public SoundSpecifier? AttachSound = new SoundPathSpecifier("/Audio/Items/beep.ogg", AudioParams.Default.WithVolume(-6.5f)); + + [DataField, AutoNetworkedField] + public SoundSpecifier? DetachSound = new SoundPathSpecifier("/Audio/Items/beep.ogg", AudioParams.Default.WithVolume(-5.5f)); +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableDirectionLockedComponent.cs b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableDirectionLockedComponent.cs new file mode 100644 index 00000000000..24c59fbc609 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableDirectionLockedComponent.cs @@ -0,0 +1,16 @@ +using Content.Shared._RMC14.Attachable.Systems; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Attachable.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(AttachableToggleableSystem))] +public sealed partial class AttachableDirectionLockedComponent : Component +{ + [DataField, AutoNetworkedField] + public List AttachableList = new(); + + [DataField, AutoNetworkedField] + public Direction? LockedDirection; +} + diff --git a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableGunPreventShootComponent.cs b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableGunPreventShootComponent.cs new file mode 100644 index 00000000000..b706b01b7aa --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableGunPreventShootComponent.cs @@ -0,0 +1,15 @@ +using Content.Shared._RMC14.Attachable.Systems; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Attachable.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(AttachableToggleableSystem))] +public sealed partial class AttachableGunPreventShootComponent : Component +{ + [DataField, AutoNetworkedField] + public bool PreventShoot; + + [DataField, AutoNetworkedField] + public string Message = ""; +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableHolderComponent.cs b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableHolderComponent.cs new file mode 100644 index 00000000000..d57a17f1503 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableHolderComponent.cs @@ -0,0 +1,32 @@ +using Content.Shared._RMC14.Attachable.Systems; +using Content.Shared.Whitelist; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Attachable.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(AttachableHolderSystem))] +public sealed partial class AttachableHolderComponent : Component +{ + [DataField, AutoNetworkedField] + public EntityUid? SupercedingAttachable; + + /// + /// The key is one of the slot IDs at the bottom of this file. + /// Each key is followed by the description of the slot. + /// + [DataField, AutoNetworkedField] + public Dictionary Slots = new(); +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Slot IDs should be named as follows: rmc-aslot-SLOTNAME, for example: rmc-aslot-barrel. * + * Each slot ID must have a name attached to it in \Resources\Locale\en-US\_RMC14\attachable\attachable.ftl * + * The slot list is below. If you add more, list them here so others can use the comment for reference. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * GUN SLOTS: + * rmc-aslot-barrel + * rmc-aslot-rail + * rmc-aslot-stock + * rmc-aslot-underbarrel + */ diff --git a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableIFFComponent.cs b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableIFFComponent.cs new file mode 100644 index 00000000000..d003e631d05 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableIFFComponent.cs @@ -0,0 +1,8 @@ +// using Content.Shared._RMC14.Attachable.Systems; +// using Robust.Shared.GameStates; + +// namespace Content.Shared._RMC14.Attachable.Components; + +// [RegisterComponent, NetworkedComponent] +// [Access(typeof(AttachableIFFSystem))] +// public sealed partial class AttachableIFFComponent : Component; diff --git a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableMagneticComponent.cs b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableMagneticComponent.cs new file mode 100644 index 00000000000..575fa3dbeb8 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableMagneticComponent.cs @@ -0,0 +1,13 @@ +using Content.Shared._RMC14.Attachable.Systems; +using Content.Shared.Inventory; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Attachable.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(AttachableMagneticSystem))] +public sealed partial class AttachableMagneticComponent : Component +{ + [DataField, AutoNetworkedField] + public SlotFlags MagnetizeToSlots = SlotFlags.SUITSTORAGE; +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableMovementLockedComponent.cs b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableMovementLockedComponent.cs new file mode 100644 index 00000000000..84350a654f2 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableMovementLockedComponent.cs @@ -0,0 +1,13 @@ +using Content.Shared._RMC14.Attachable.Systems; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Attachable.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(AttachableToggleableSystem))] +public sealed partial class AttachableMovementLockedComponent : Component +{ + [DataField, AutoNetworkedField] + public List AttachableList = new(); +} + diff --git a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachablePreventDropToggleableComponent.cs b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachablePreventDropToggleableComponent.cs new file mode 100644 index 00000000000..747ba3d7f64 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachablePreventDropToggleableComponent.cs @@ -0,0 +1,8 @@ +using Content.Shared._RMC14.Attachable.Systems; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Attachable.Components; + +[RegisterComponent, NetworkedComponent] +[Access(typeof(AttachablePreventDropSystem))] +public sealed partial class AttachablePreventDropToggleableComponent : Component; diff --git a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachablePryingComponent.cs b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachablePryingComponent.cs new file mode 100644 index 00000000000..42ce4afedb4 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachablePryingComponent.cs @@ -0,0 +1,8 @@ +using Content.Shared._RMC14.Attachable.Systems; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Attachable.Components; + +[RegisterComponent, NetworkedComponent] +[Access(typeof(AttachablePryingSystem))] +public sealed partial class AttachablePryingComponent : Component; diff --git a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableSideLockedComponent.cs b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableSideLockedComponent.cs new file mode 100644 index 00000000000..a2cfcaf2776 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableSideLockedComponent.cs @@ -0,0 +1,18 @@ +using Content.Shared._RMC14.Attachable.Systems; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Attachable.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(AttachableToggleableSystem))] +public sealed partial class AttachableSideLockedComponent : Component +{ + [DataField, AutoNetworkedField] + public List AttachableList = new(); + + /// + /// The cardinal direction the attachments are locked into. In this case, direction is counted as a full 180 degrees, rather than 90. + /// + [DataField, AutoNetworkedField] + public Direction? LockedDirection; +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableSilencerComponent.cs b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableSilencerComponent.cs new file mode 100644 index 00000000000..2d53feee9e4 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableSilencerComponent.cs @@ -0,0 +1,13 @@ +using Content.Shared._RMC14.Attachable.Systems; +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Attachable.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(AttachableSilencerSystem))] +public sealed partial class AttachableSilencerComponent : Component +{ + [DataField, AutoNetworkedField] + public SoundSpecifier Sound = new SoundCollectionSpecifier("CMSilencedShoot"); +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableSizeModsComponent.cs b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableSizeModsComponent.cs new file mode 100644 index 00000000000..ad86fe9a910 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableSizeModsComponent.cs @@ -0,0 +1,12 @@ +using Content.Shared._RMC14.Attachable.Systems; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Attachable.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(AttachableModifiersSystem))] +public sealed partial class AttachableSizeModsComponent : Component +{ + [DataField, AutoNetworkedField] + public List Modifiers = new(); +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableSpeedModsComponent.cs b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableSpeedModsComponent.cs new file mode 100644 index 00000000000..7af2a4b6cf5 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableSpeedModsComponent.cs @@ -0,0 +1,13 @@ +using Content.Shared._RMC14.Attachable.Systems; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Attachable.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(AttachableModifiersSystem))] +public sealed partial class AttachableSpeedModsComponent : Component +{ + [DataField, AutoNetworkedField] + public List Modifiers = new(); +} + diff --git a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableTemporarySpeedModsComponent.cs b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableTemporarySpeedModsComponent.cs new file mode 100644 index 00000000000..aa898116ac3 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableTemporarySpeedModsComponent.cs @@ -0,0 +1,19 @@ +using Content.Shared._RMC14.Attachable.Events; +using Content.Shared._RMC14.Attachable.Systems; +using Content.Shared._RMC14.Movement; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Attachable.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(AttachableTemporarySpeedModsSystem))] +public sealed partial class AttachableTemporarySpeedModsComponent : Component +{ + [DataField, AutoNetworkedField] + public AttachableAlteredType Alteration = AttachableAlteredType.Interrupted; + + [DataField, AutoNetworkedField] + public List Modifiers = new(); +} + + diff --git a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableToggleableComponent.cs b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableToggleableComponent.cs new file mode 100644 index 00000000000..28ea58fa290 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableToggleableComponent.cs @@ -0,0 +1,148 @@ +using Content.Shared._RMC14.Attachable.Systems; +using Content.Shared.Whitelist; +using Robust.Shared.Audio; +using Robust.Shared.GameStates; +using Robust.Shared.Utility; + +namespace Content.Shared._RMC14.Attachable.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(AttachableToggleableSystem))] +public sealed partial class AttachableToggleableComponent : Component +{ + /// + /// Whether the attachment is currently active. + /// + [DataField, AutoNetworkedField] + public bool Active = false; + + /// + /// If set to true, the attachment will deactivate upon switching hands. + /// + [DataField, AutoNetworkedField] + public bool NeedHand = false; + + /// + /// If set to true, the attachment will not toggle itself when its action is interrupted. Used in cases where the item toggles itself separately, like scopes. + /// + [DataField, AutoNetworkedField] + public bool DoInterrupt = false; + + /// + /// If set to true, the attachment will deactivate upon moving. + /// + [DataField, AutoNetworkedField] + public bool BreakOnMove = false; + + /// + /// If set to true, the attachment will deactivate upon rotating to any direction other than the one it was activated in. + /// + [DataField, AutoNetworkedField] + public bool BreakOnRotate = false; + + /// + /// If set to true, the attachment will deactivate upon rotating 90 degrees away from the one it was activated in. + /// + [DataField, AutoNetworkedField] + public bool BreakOnFullRotate = false; + + /// + /// If set to true, the attachment can only be toggled when the holder is wielded. + /// + [DataField, AutoNetworkedField] + public bool WieldedOnly = false; + + /// + /// If set to true, the attachment can only be used when the holder is wielded. + /// + [DataField, AutoNetworkedField] + public bool WieldedUseOnly = false; + + /// + /// If set to true, the attachment can only be activated when someone is holding it. + /// + [DataField, AutoNetworkedField] + public bool HeldOnlyActivate = false; + + /// + /// Only the person holding or wearing the holder can activate this attachment. + /// + [DataField, AutoNetworkedField] + public bool UserOnly = false; + + [DataField, AutoNetworkedField] + public TimeSpan UseDelay = TimeSpan.FromSeconds(0f); + + [DataField, AutoNetworkedField] + public float DoAfter; + + [DataField, AutoNetworkedField] + public float? DeactivateDoAfter; + + [DataField, AutoNetworkedField] + public bool DoAfterNeedHand = true; + + [DataField, AutoNetworkedField] + public bool DoAfterBreakOnMove = true; + + [DataField, AutoNetworkedField] + public AttachableInstantToggleConditions InstantToggle = AttachableInstantToggleConditions.None; + + /// + /// If set to true, this attachment will block some of the holder's functionality when active and perform it instead. + /// Used for attached weapons, like the UGL. + /// + [DataField, AutoNetworkedField] + public bool SupercedeHolder = false; + + /// + /// If set to true, this attachment's functions only work when it's attached to a holder. + /// + [DataField, AutoNetworkedField] + public bool AttachedOnly = false; + + [DataField, AutoNetworkedField] + public SoundSpecifier? ActivateSound = new SoundPathSpecifier("/Audio/Items/beep.ogg"); + + [DataField, AutoNetworkedField] + public SoundSpecifier? DeactivateSound = new SoundPathSpecifier("/Audio/Items/beep.ogg"); + + [DataField, AutoNetworkedField] + public bool ShowTogglePopup = true; + + [DataField, AutoNetworkedField] + public LocId ActivatePopupText = new LocId("attachable-popup-activate-generic"); + + [DataField, AutoNetworkedField] + public LocId DeactivatePopupText = new LocId("attachable-popup-deactivate-generic"); + + [DataField, AutoNetworkedField] + public EntityUid? Action; + + [DataField, AutoNetworkedField] + public string ActionId = "CMActionToggleAttachable"; + + [DataField, AutoNetworkedField] + public string ActionName = "Toggle Attachable"; + + [DataField, AutoNetworkedField] + public string ActionDesc = "Toggle an attachable. If you're seeing this, someone forgot to set the description properly."; + + [DataField, AutoNetworkedField] + public EntityWhitelist? ActionsToRelayWhitelist; + + [DataField, AutoNetworkedField] + public SpriteSpecifier Icon = new SpriteSpecifier.Rsi(new ResPath("_RMC14/Objects/Weapons/Guns/Attachments/rail.rsi"), "flashlight"); + + [DataField, AutoNetworkedField] + public SpriteSpecifier? IconActive; + + [DataField, AutoNetworkedField] + public bool Attached = false; +} + +public enum AttachableInstantToggleConditions : byte +{ + None = 0, + Brace = 1 << 0 +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableToggleablePreventShootComponent.cs b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableToggleablePreventShootComponent.cs new file mode 100644 index 00000000000..82dd1ed5c36 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableToggleablePreventShootComponent.cs @@ -0,0 +1,15 @@ +using Content.Shared._RMC14.Attachable.Systems; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Attachable.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(AttachableToggleableSystem))] +public sealed partial class AttachableToggleablePreventShootComponent : Component +{ + [DataField, AutoNetworkedField] + public bool ShootWhenActive = true; + + [DataField, AutoNetworkedField] + public string Message = "You can't shoot this right now!"; +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableToggleableSimpleActivateComponent.cs b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableToggleableSimpleActivateComponent.cs new file mode 100644 index 00000000000..16b531a14bf --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableToggleableSimpleActivateComponent.cs @@ -0,0 +1,8 @@ +using Content.Shared._RMC14.Attachable.Systems; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Attachable.Components; + +[RegisterComponent, NetworkedComponent] +[Access(typeof(AttachableToggleableSystem))] +public sealed partial class AttachableToggleableSimpleActivateComponent : Component; diff --git a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableWeaponMeleeModsComponent.cs b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableWeaponMeleeModsComponent.cs new file mode 100644 index 00000000000..3f20d62f373 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableWeaponMeleeModsComponent.cs @@ -0,0 +1,12 @@ +using Content.Shared._RMC14.Attachable.Systems; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Attachable.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(AttachableModifiersSystem))] +public sealed partial class AttachableWeaponMeleeModsComponent : Component +{ + [DataField, AutoNetworkedField] + public List Modifiers = new(); +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableWeaponRangedModsComponent.cs b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableWeaponRangedModsComponent.cs new file mode 100644 index 00000000000..f4ba342fd31 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableWeaponRangedModsComponent.cs @@ -0,0 +1,15 @@ +using Content.Shared._RMC14.Attachable.Systems; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Attachable.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(AttachableModifiersSystem))] +public sealed partial class AttachableWeaponRangedModsComponent : Component +{ + [DataField, AutoNetworkedField] + public List Modifiers = new(); + + [DataField, AutoNetworkedField] + public List? FireModeMods; +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableWieldDelayModsComponent.cs b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableWieldDelayModsComponent.cs new file mode 100644 index 00000000000..de609b9e813 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableWieldDelayModsComponent.cs @@ -0,0 +1,13 @@ +using Content.Shared._RMC14.Attachable.Systems; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Attachable.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(AttachableModifiersSystem))] +public sealed partial class AttachableWieldDelayModsComponent : Component +{ + [DataField, AutoNetworkedField] + public List Modifiers = new(); +} + diff --git a/Content.Shared/ADT/_RMC14/Attachable/Components/GunAttachableIFFComponent.cs b/Content.Shared/ADT/_RMC14/Attachable/Components/GunAttachableIFFComponent.cs new file mode 100644 index 00000000000..cbe45806dc0 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Components/GunAttachableIFFComponent.cs @@ -0,0 +1,8 @@ +// using Content.Shared._RMC14.Attachable.Systems; +// using Robust.Shared.GameStates; + +// namespace Content.Shared._RMC14.Attachable.Components; + +// [RegisterComponent, NetworkedComponent] +// [Access(typeof(AttachableIFFSystem))] +// public sealed partial class GunAttachableIFFComponent : Component; diff --git a/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableAlteredEvent.cs b/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableAlteredEvent.cs new file mode 100644 index 00000000000..838ca6cc4cf --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableAlteredEvent.cs @@ -0,0 +1,21 @@ +namespace Content.Shared._RMC14.Attachable.Events; + +[ByRefEvent] +public readonly record struct AttachableAlteredEvent( + EntityUid Holder, + AttachableAlteredType Alteration, + EntityUid? User = null +); + +public enum AttachableAlteredType : byte +{ + Attached = 1 << 0, + Detached = 1 << 1, + Wielded = 1 << 2, + Unwielded = 1 << 3, + Activated = 1 << 4, + Deactivated = 1 << 5, + Interrupted = 1 << 6, // This is used when a toggleable attachment is deactivated by something other than its hotkey or action. + AppearanceChanged = 1 << 7, + DetachedDeactivated = Detached | Deactivated, +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableAttachDoAfterEvent.cs b/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableAttachDoAfterEvent.cs new file mode 100644 index 00000000000..124ac4ba79d --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableAttachDoAfterEvent.cs @@ -0,0 +1,15 @@ +using Content.Shared.DoAfter; +using Robust.Shared.Serialization; + +namespace Content.Shared._RMC14.Attachable.Events; + +[Serializable, NetSerializable] +public sealed partial class AttachableAttachDoAfterEvent : SimpleDoAfterEvent +{ + public readonly string SlotId; + + public AttachableAttachDoAfterEvent(string slotId) + { + SlotId = slotId; + } +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableDetachDoAfterEvent.cs b/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableDetachDoAfterEvent.cs new file mode 100644 index 00000000000..bbe430752b4 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableDetachDoAfterEvent.cs @@ -0,0 +1,7 @@ +using Content.Shared.DoAfter; +using Robust.Shared.Serialization; + +namespace Content.Shared._RMC14.Attachable.Events; + +[Serializable, NetSerializable] +public sealed partial class AttachableDetachDoAfterEvent : SimpleDoAfterEvent; diff --git a/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableGetExamineDataEvent.cs b/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableGetExamineDataEvent.cs new file mode 100644 index 00000000000..6becd4e87fc --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableGetExamineDataEvent.cs @@ -0,0 +1,4 @@ +namespace Content.Shared._RMC14.Attachable.Events; + +[ByRefEvent] +public readonly record struct AttachableGetExamineDataEvent(Dictionary effectStrings)> Data); diff --git a/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableGrantIFFEvent.cs b/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableGrantIFFEvent.cs new file mode 100644 index 00000000000..05603e6330c --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableGrantIFFEvent.cs @@ -0,0 +1,4 @@ +// namespace Content.Shared._RMC14.Attachable.Events; + +// [ByRefEvent] +// public record struct AttachableGrantIFFEvent(bool Grants); diff --git a/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableHolderAttachablesAlteredEvent.cs b/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableHolderAttachablesAlteredEvent.cs new file mode 100644 index 00000000000..0d60bfd8da9 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableHolderAttachablesAlteredEvent.cs @@ -0,0 +1,8 @@ +namespace Content.Shared._RMC14.Attachable.Events; + +[ByRefEvent] +public readonly record struct AttachableHolderAttachablesAlteredEvent( + EntityUid Attachable, + string SlotId, + AttachableAlteredType Alteration +); diff --git a/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableRelayedEvent.cs b/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableRelayedEvent.cs new file mode 100644 index 00000000000..d2842104ee4 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableRelayedEvent.cs @@ -0,0 +1,16 @@ +namespace Content.Shared._RMC14.Attachable.Events; + +/// +/// Wrapper for events relayed to attachables by their holder. +/// +public sealed class AttachableRelayedEvent : EntityEventArgs +{ + public TEvent Args; + public EntityUid Holder; + + public AttachableRelayedEvent(TEvent args, EntityUid holder) + { + Args = args; + Holder = holder; + } +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableToggleDoAfterEvent.cs b/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableToggleDoAfterEvent.cs new file mode 100644 index 00000000000..1fb9f1e1318 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableToggleDoAfterEvent.cs @@ -0,0 +1,17 @@ +using Content.Shared.DoAfter; +using Robust.Shared.Serialization; + +namespace Content.Shared._RMC14.Attachable.Events; + +[Serializable, NetSerializable] +public sealed partial class AttachableToggleDoAfterEvent : SimpleDoAfterEvent +{ + public readonly string SlotId; + public readonly string PopupText; + + public AttachableToggleDoAfterEvent(string slotId, string popupText) + { + SlotId = slotId; + PopupText = popupText; + } +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableToggleStartedEvent.cs b/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableToggleStartedEvent.cs new file mode 100644 index 00000000000..0ec1cba3cd3 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableToggleStartedEvent.cs @@ -0,0 +1,10 @@ +using Content.Shared._RMC14.Attachable.Components; + +namespace Content.Shared._RMC14.Attachable.Events; + +[ByRefEvent] +public readonly record struct AttachableToggleStartedEvent( + EntityUid Holder, + EntityUid User, + string SlotId +); diff --git a/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableToggleableInterruptEvent.cs b/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableToggleableInterruptEvent.cs new file mode 100644 index 00000000000..2f4bbbbcedd --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableToggleableInterruptEvent.cs @@ -0,0 +1,8 @@ +using Content.Shared._RMC14.Attachable.Components; + +namespace Content.Shared._RMC14.Attachable.Events; + +[ByRefEvent] +public readonly record struct AttachableToggleableInterruptEvent( + EntityUid User +); diff --git a/Content.Shared/ADT/_RMC14/Attachable/Events/GrantAttachableActionsEvent.cs b/Content.Shared/ADT/_RMC14/Attachable/Events/GrantAttachableActionsEvent.cs new file mode 100644 index 00000000000..2a7357c61c8 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Events/GrantAttachableActionsEvent.cs @@ -0,0 +1,4 @@ +namespace Content.Shared._RMC14.Attachable.Events; + +[ByRefEvent] +public readonly record struct GrantAttachableActionsEvent(EntityUid User); diff --git a/Content.Shared/ADT/_RMC14/Attachable/Events/RemoveAttachableActionsEvent.cs b/Content.Shared/ADT/_RMC14/Attachable/Events/RemoveAttachableActionsEvent.cs new file mode 100644 index 00000000000..231dbfe5bba --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Events/RemoveAttachableActionsEvent.cs @@ -0,0 +1,4 @@ +namespace Content.Shared._RMC14.Attachable.Events; + +[ByRefEvent] +public readonly record struct RemoveAttachableActionsEvent(EntityUid User); diff --git a/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableHolderSystem.cs b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableHolderSystem.cs new file mode 100644 index 00000000000..ef0d19e6864 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableHolderSystem.cs @@ -0,0 +1,739 @@ +using System.Diagnostics.CodeAnalysis; +using System.Numerics; +using Content.Shared._RMC14.Attachable.Components; +using Content.Shared._RMC14.Attachable.Events; +using Content.Shared._RMC14.Input; +using Content.Shared._RMC14.Item; +using Content.Shared._RMC14.Weapons.Common; +using Content.Shared._RMC14.Weapons.Ranged; +using Content.Shared._RMC14.Wieldable.Events; +using Content.Shared.ActionBlocker; +using Content.Shared.Containers; +using Content.Shared.DoAfter; +using Content.Shared.Hands; +using Content.Shared.Hands.Components; +using Content.Shared.Hands.EntitySystems; +using Content.Shared.Interaction; +using Content.Shared.Verbs; +using Content.Shared.Weapons.Melee.Events; +using Content.Shared.Weapons.Ranged.Components; +using Content.Shared.Weapons.Ranged.Events; +using Content.Shared.Weapons.Ranged.Systems; +using Content.Shared.Whitelist; +using Content.Shared.Wieldable; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Containers; +using Robust.Shared.Input.Binding; +using Robust.Shared.Map; + +namespace Content.Shared._RMC14.Attachable.Systems; + +public sealed class AttachableHolderSystem : EntitySystem +{ + [Dependency] private readonly ActionBlockerSystem _actionBlocker = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelist = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedContainerSystem _container = default!; + [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; + [Dependency] private readonly SharedGunSystem _gun = default!; + [Dependency] private readonly SharedHandsSystem _hands = default!; + [Dependency] private readonly SharedUserInterfaceSystem _ui = default!; + [Dependency] private readonly SharedVerbSystem _verbSystem = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnAttachDoAfter); + SubscribeLocalEvent(OnDetachDoAfter); + SubscribeLocalEvent(OnAttachableHolderAttachToSlotMessage); + SubscribeLocalEvent(OnAttachableHolderDetachMessage); + SubscribeLocalEvent(OnAttachableHolderAttemptShoot); + SubscribeLocalEvent(RelayEvent); + SubscribeLocalEvent(OnAttachableHolderUiOpened); + SubscribeLocalEvent(OnAttached); + SubscribeLocalEvent(OnHolderMapInit, + after: new[] { typeof(ContainerFillSystem) }); + SubscribeLocalEvent>(OnAttachableHolderGetVerbs); + SubscribeLocalEvent(RelayEvent); + SubscribeLocalEvent(RelayEvent); + SubscribeLocalEvent(RelayEvent, + after: new[] { typeof(WieldableSystem) }); + SubscribeLocalEvent(OnAttachableHolderInteractUsing); + SubscribeLocalEvent(OnAttachableHolderInteractInWorld); + SubscribeLocalEvent(OnHolderWielded); + SubscribeLocalEvent(OnHolderUnwielded); + SubscribeLocalEvent(OnAttachableHolderUniqueAction); + SubscribeLocalEvent(RelayEvent); + SubscribeLocalEvent(RelayEvent); + SubscribeLocalEvent(RelayEvent); + SubscribeLocalEvent(RelayEvent); + SubscribeLocalEvent(RelayEvent); + SubscribeLocalEvent(RelayEvent); + SubscribeLocalEvent(RelayEvent); + SubscribeLocalEvent(RelayEvent); + SubscribeLocalEvent(RelayEvent); + SubscribeLocalEvent(RelayEvent); + SubscribeLocalEvent(RelayEvent); + SubscribeLocalEvent(RelayEvent); + SubscribeLocalEvent(RelayEvent); + + + CommandBinds.Builder + .Bind(CMKeyFunctions.RMCActivateAttachableBarrel, + InputCmdHandler.FromDelegate(session => + { + if (session?.AttachedEntity is { } userUid) + ToggleAttachable(userUid, "rmc-aslot-barrel"); + }, + handle: false)) + .Bind(CMKeyFunctions.RMCActivateAttachableRail, + InputCmdHandler.FromDelegate(session => + { + if (session?.AttachedEntity is { } userUid) + ToggleAttachable(userUid, "rmc-aslot-rail"); + }, + handle: false)) + .Bind(CMKeyFunctions.RMCActivateAttachableStock, + InputCmdHandler.FromDelegate(session => + { + if (session?.AttachedEntity is { } userUid) + ToggleAttachable(userUid, "rmc-aslot-stock"); + }, + handle: false)) + .Bind(CMKeyFunctions.RMCActivateAttachableUnderbarrel, + InputCmdHandler.FromDelegate(session => + { + if (session?.AttachedEntity is { } userUid) + ToggleAttachable(userUid, "rmc-aslot-underbarrel"); + }, + handle: false)) + .Bind(CMKeyFunctions.RMCFieldStripHeldItem, + InputCmdHandler.FromDelegate(session => + { + if (session?.AttachedEntity is { } userUid) + FieldStripHeldItem(userUid); + }, + handle: false)) + .Register(); + } + + public override void Shutdown() + { + CommandBinds.Unregister(); + } + + private void OnHolderMapInit(Entity holder, ref MapInitEvent args) + { + var xform = Transform(holder.Owner); + var coords = new EntityCoordinates(holder.Owner, Vector2.Zero); + + foreach (var slotId in holder.Comp.Slots.Keys) + { + if (holder.Comp.Slots[slotId].StartingAttachable == null) + continue; + + var container = _container.EnsureContainer(holder, slotId); + container.OccludesLight = false; + + var attachableUid = Spawn(holder.Comp.Slots[slotId].StartingAttachable, coords); + if (!_container.Insert(attachableUid, container, containerXform: xform)) + continue; + } + + Dirty(holder); + } + + private void OnAttachableHolderInteractUsing(Entity holder, ref InteractUsingEvent args) + { + if (CanAttach(holder, args.Used)) + { + StartAttach(holder, args.Used, args.User); + args.Handled = true; + } + + if (holder.Comp.SupercedingAttachable == null) + return; + + var interactUsingEvent = new InteractUsingEvent(args.User, + args.Used, + holder.Comp.SupercedingAttachable.Value, + args.ClickLocation); + RaiseLocalEvent(holder.Comp.SupercedingAttachable.Value, interactUsingEvent); + + if (interactUsingEvent.Handled) + { + args.Handled = true; + return; + } + + var afterInteractEvent = new AfterInteractEvent(args.User, + args.Used, + holder.Comp.SupercedingAttachable.Value, + args.ClickLocation, + true); + RaiseLocalEvent(args.Used, afterInteractEvent); + + if (afterInteractEvent.Handled) + args.Handled = true; + } + + private void OnAttachableHolderInteractInWorld(Entity holder, ref ActivateInWorldEvent args) + { + if (args.Handled || holder.Comp.SupercedingAttachable == null) + return; + + var activateInWorldEvent = new ActivateInWorldEvent(args.User, holder.Comp.SupercedingAttachable.Value, args.Complex); + RaiseLocalEvent(holder.Comp.SupercedingAttachable.Value, activateInWorldEvent); + + args.Handled = activateInWorldEvent.Handled; + } + + private void OnAttachableHolderAttemptShoot(Entity holder, ref AttemptShootEvent args) + { + if (args.Cancelled) + return; + + if (holder.Comp.SupercedingAttachable == null) + return; + + args.Cancelled = true; + + if (!TryComp(holder.Owner, out var holderGunComponent) || + holderGunComponent.ShootCoordinates == null || + !TryComp(holder.Comp.SupercedingAttachable, + out var attachableGunComponent)) + { + return; + } + + _gun.AttemptShoot(args.User, + holder.Comp.SupercedingAttachable.Value, + attachableGunComponent, + holderGunComponent.ShootCoordinates.Value); + } + + private void OnAttachableHolderUniqueAction(Entity holder, ref UniqueActionEvent args) + { + if (holder.Comp.SupercedingAttachable == null || args.Handled) + return; + + RaiseLocalEvent(holder.Comp.SupercedingAttachable.Value, new UniqueActionEvent(args.UserUid)); + args.Handled = true; + } + + private void OnHolderWielded(Entity holder, ref ItemWieldedEvent args) + { + AlterAllAttachables(holder, AttachableAlteredType.Wielded); + } + + private void OnHolderUnwielded(Entity holder, ref ItemUnwieldedEvent args) + { + AlterAllAttachables(holder, AttachableAlteredType.Unwielded); + } + + private void OnAttachableHolderDetachMessage(EntityUid holderUid, + AttachableHolderComponent holderComponent, + AttachableHolderDetachMessage args) + { + StartDetach((holderUid, holderComponent), args.Slot, args.Actor); + } + + private void OnAttachableHolderGetVerbs(Entity holder, ref GetVerbsEvent args) + { + + EnsureSlots(holder); + var userUid = args.User; + + foreach (var slotId in holder.Comp.Slots.Keys) + { + if (_container.TryGetContainer(holder.Owner, slotId, out var container)) + { + foreach (var contained in container.ContainedEntities) + { + if (!TryComp(contained, out AttachableToggleableComponent? toggleableComponent)) + continue; + + if (toggleableComponent.UserOnly && + (!TryComp(holder.Owner, out TransformComponent? transformComponent) || !transformComponent.ParentUid.Valid || transformComponent.ParentUid != userUid)) + { + continue; + } + + var verb = new EquipmentVerb() + { + Text = toggleableComponent.ActionName, + IconEntity = GetNetEntity(contained), + Act = () => + { + var ev = new AttachableToggleStartedEvent(holder.Owner, userUid, slotId); + RaiseLocalEvent(contained, ref ev); + } + }; + + args.Verbs.Add(verb); + } + } + } + } + + private void OnAttachableHolderAttachToSlotMessage(EntityUid holderUid, + AttachableHolderComponent holderComponent, + AttachableHolderAttachToSlotMessage args) + { + TryComp(args.Actor, out var handsComponent); + + if (handsComponent == null) + return; + + _hands.TryGetActiveItem((args.Actor, handsComponent), out var attachableUid); + + if (attachableUid == null) + return; + + StartAttach((holderUid, holderComponent), attachableUid.Value, args.Actor, args.Slot); + } + + private void OnAttachableHolderUiOpened(EntityUid holderUid, + AttachableHolderComponent holderComponent, + BoundUIOpenedEvent args) + { + UpdateStripUi(holderUid); + } + + public void StartAttach(Entity holder, + EntityUid attachableUid, + EntityUid userUid, + string slotId = "") + { + + var validSlots = GetValidSlots(holder, attachableUid); + + if (validSlots.Count == 0) + return; + + if (string.IsNullOrEmpty(slotId)) + { + if (validSlots.Count > 1) + { + TryComp(holder.Owner, + out var userInterfaceComponent); + _ui.OpenUi((holder.Owner, userInterfaceComponent), AttachmentUI.ChooseSlotKey, userUid); + + var state = + new AttachableHolderChooseSlotUserInterfaceState(validSlots); + _ui.SetUiState(holder.Owner, AttachmentUI.ChooseSlotKey, state); + return; + } + + slotId = validSlots[0]; + } + + _doAfter.TryStartDoAfter(new DoAfterArgs( + EntityManager, + userUid, + Comp(attachableUid).AttachDoAfter, + new AttachableAttachDoAfterEvent(slotId), + holder, + target: holder.Owner, + used: attachableUid) + { + NeedHand = true, + BreakOnMove = true, + }); + } + + private void OnAttachDoAfter(EntityUid uid, AttachableHolderComponent component, AttachableAttachDoAfterEvent args) + { + if (args.Cancelled || args.Handled) + return; + + if (args.Target is not { } target || args.Used is not { } used) + return; + + if (!TryComp(args.Target, out AttachableHolderComponent? holder) || + !HasComp(args.Used)) + return; + + if (Attach((target, holder), used, args.User, args.SlotId)) + args.Handled = true; + } + + public bool Attach(Entity holder, + EntityUid attachableUid, + EntityUid userUid, + string slotId = "") + { + if (!CanAttach(holder, attachableUid, ref slotId)) + return false; + + var container = _container.EnsureContainer(holder, slotId); + container.OccludesLight = false; + + if (container.Count > 0 && !Detach(holder, container.ContainedEntities[0], userUid, slotId)) + return false; + + if (!_container.Insert(attachableUid, container)) + return false; + + if (_hands.IsHolding(userUid, holder.Owner)) + { + var addEv = new GrantAttachableActionsEvent(userUid); + RaiseLocalEvent(attachableUid, ref addEv); + } + + Dirty(holder); + + _audio.PlayPredicted(Comp(attachableUid).AttachSound, + holder, + userUid); + + return true; + } + + private void OnAttached(Entity holder, ref EntInsertedIntoContainerMessage args) + { + if (!TryComp(args.Entity, out AttachableComponent? attachableComponent) || !holder.Comp.Slots.ContainsKey(args.Container.ID)) + return; + + UpdateStripUi(holder.Owner, holder.Comp); + + var ev = new AttachableAlteredEvent(holder.Owner, AttachableAlteredType.Attached); + RaiseLocalEvent(args.Entity, ref ev); + + var holderEv = new AttachableHolderAttachablesAlteredEvent(args.Entity, args.Container.ID, AttachableAlteredType.Attached); + RaiseLocalEvent(holder, ref holderEv); + } + + //Detaching + public void StartDetach(Entity holder, string slotId, EntityUid userUid) + { + if (TryGetAttachable(holder, slotId, out var attachable) && holder.Comp.Slots.ContainsKey(slotId) && !holder.Comp.Slots[slotId].Locked) + StartDetach(holder, attachable.Owner, userUid); + } + + public void StartDetach(Entity holder, EntityUid attachableUid, EntityUid userUid) + { + + var delay = Comp(attachableUid).AttachDoAfter; + var args = new DoAfterArgs( + EntityManager, + userUid, + delay, + new AttachableDetachDoAfterEvent(), + holder, + holder.Owner, + attachableUid) + { + NeedHand = true, + BreakOnMove = true, + }; + + _doAfter.TryStartDoAfter(args); + } + + private void OnDetachDoAfter(EntityUid uid, AttachableHolderComponent component, AttachableDetachDoAfterEvent args) + { + if (args.Cancelled || args.Handled || args.Target == null || args.Used == null) + return; + + if (!TryComp(args.Target, out AttachableHolderComponent? holderComponent) || !HasComp(args.Used)) + return; + + if (!Detach((args.Target.Value, holderComponent), args.Used.Value, args.User)) + return; + + args.Handled = true; + } + + public bool Detach(Entity holder, + EntityUid attachableUid, + EntityUid userUid, + string? slotId = null) + { + if (TerminatingOrDeleted(holder) || !holder.Comp.Running) + return false; + + if (string.IsNullOrEmpty(slotId) && !TryGetSlotId(holder.Owner, attachableUid, out slotId)) + return false; + + if (!_container.TryGetContainer(holder, slotId, out var container) || container.Count <= 0) + return false; + + if (!TryGetAttachable(holder, slotId, out var attachable)) + return false; + + if (!_container.Remove(attachable.Owner, container, force: true)) + return false; + + UpdateStripUi(holder.Owner, holder.Comp); + + var ev = new AttachableAlteredEvent(holder.Owner, AttachableAlteredType.Detached, userUid); + RaiseLocalEvent(attachableUid, ref ev); + + var holderEv = new AttachableHolderAttachablesAlteredEvent(attachableUid, slotId, AttachableAlteredType.Detached); + RaiseLocalEvent(holder.Owner, ref holderEv); + + var removeEv = new RemoveAttachableActionsEvent(userUid); + RaiseLocalEvent(attachableUid, ref removeEv); + + _audio.PlayPredicted(Comp(attachableUid).DetachSound, + holder, + userUid); + + Dirty(holder); + _hands.TryPickupAnyHand(userUid, attachable); + return true; + } + + private bool CanAttach(Entity holder, EntityUid attachableUid) + { + var slotId = ""; + return CanAttach(holder, attachableUid, ref slotId); + } + + private bool CanAttach(Entity holder, EntityUid attachableUid, ref string slotId) + { + if (!HasComp(attachableUid)) + return false; + + if (!string.IsNullOrWhiteSpace(slotId)) + return _whitelist.IsWhitelistPass(holder.Comp.Slots[slotId].Whitelist, attachableUid); + + foreach (var key in holder.Comp.Slots.Keys) + { + if (_whitelist.IsWhitelistPass(holder.Comp.Slots[key].Whitelist, attachableUid)) + { + slotId = key; + return true; + } + } + + return false; + } + + private Dictionary GetSlotsForStripUi(Entity holder) + { + var result = new Dictionary(); + var metaQuery = GetEntityQuery(); + + foreach (var slotId in holder.Comp.Slots.Keys) + { + if (TryGetAttachable(holder, slotId, out var attachable) && + metaQuery.TryGetComponent(attachable.Owner, out var metadata)) + { + result.Add(slotId, (metadata.EntityName, holder.Comp.Slots[slotId].Locked)); + } + else + { + result.Add(slotId, (null, holder.Comp.Slots[slotId].Locked)); + } + } + + return result; + } + + public bool TryGetAttachable(Entity holder, + string slotId, + out Entity attachable) + { + attachable = default; + + if (!_container.TryGetContainer(holder, slotId, out var container) || container.Count <= 0) + return false; + + var ent = container.ContainedEntities[0]; + if (!TryComp(ent, out AttachableComponent? attachableComp)) + return false; + + attachable = (ent, attachableComp); + return true; + } + + private void UpdateStripUi(EntityUid holderUid, AttachableHolderComponent? holderComponent = null) + { + if (!Resolve(holderUid, ref holderComponent)) + return; + + var state = + new AttachableHolderStripUserInterfaceState(GetSlotsForStripUi((holderUid, holderComponent))); + _ui.SetUiState(holderUid, AttachmentUI.StripKey, state); + } + + private void EnsureSlots(Entity holder) + { + foreach (var slotId in holder.Comp.Slots.Keys) + { + var container = _container.EnsureContainer(holder, slotId); + container.OccludesLight = false; + } + } + + private List GetValidSlots(Entity holder, EntityUid attachableUid, bool ignoreLock = false) + { + var list = new List(); + + if (!HasComp(attachableUid)) + return list; + + foreach (var slotId in holder.Comp.Slots.Keys) + { + if (_whitelist.IsWhitelistPass(holder.Comp.Slots[slotId].Whitelist, attachableUid) && (!ignoreLock || !holder.Comp.Slots[slotId].Locked)) + list.Add(slotId); + } + + return list; + } + + private void ToggleAttachable(EntityUid userUid, string slotId) + { + if (!TryComp(userUid, out var handsComponent) || + !TryComp(handsComponent.ActiveHandEntity, out var holderComponent)) + { + return; + } + + var active = handsComponent.ActiveHandEntity; + if (!holderComponent.Running || !_actionBlocker.CanInteract(userUid, active)) + return; + + if (!_container.TryGetContainer(active.Value, + slotId, + out var container) || container.Count <= 0) + return; + + var attachableUid = container.ContainedEntities[0]; + + if (!HasComp(attachableUid)) + return; + + if (!TryComp(attachableUid, out var toggleableComponent)) + return; + + var ev = new AttachableToggleStartedEvent(active.Value, userUid, slotId); + RaiseLocalEvent(attachableUid, ref ev); + } + + private void FieldStripHeldItem(EntityUid userUid) + { + if (!TryComp(userUid, out var handsComponent) || + !TryComp(handsComponent.ActiveHandEntity, out var holderComponent)) + { + return; + } + + EntityUid holderUid = handsComponent.ActiveHandEntity.Value; + + if (!holderComponent.Running || !_actionBlocker.CanInteract(userUid, holderUid)) + return; + + foreach (var verb in _verbSystem.GetLocalVerbs(holderUid, userUid, typeof(Verb))) + { + if (!verb.Text.Equals(Loc.GetString("rmc-verb-strip-attachables"))) + continue; + + _verbSystem.ExecuteVerb(verb, userUid, holderUid); + break; + } + } + + public void SetSupercedingAttachable(Entity holder, EntityUid? supercedingAttachable) + { + holder.Comp.SupercedingAttachable = supercedingAttachable; + Dirty(holder); + } + + public bool TryGetSlotId(EntityUid holderUid, EntityUid attachableUid, [NotNullWhen(true)] out string? slotId) + { + slotId = null; + + if (!TryComp(holderUid, out var holderComponent) || + !TryComp(attachableUid, out _)) + { + return false; + } + + foreach (var id in holderComponent.Slots.Keys) + { + if (!_container.TryGetContainer(holderUid, id, out var container) || container.Count <= 0) + continue; + + if (container.ContainedEntities[0] != attachableUid) + continue; + + slotId = id; + return true; + } + + return false; + } + + public bool HasSlot(Entity holder, string slotId) + { + if (holder.Comp == null) + { + if (!TryComp(holder.Owner, out AttachableHolderComponent? holderComponent)) + return false; + + holder.Comp = holderComponent; + } + + return holder.Comp.Slots.ContainsKey(slotId); + } + + public bool TryGetHolder(EntityUid attachable, [NotNullWhen(true)] out EntityUid? holderUid) + { + if (!TryComp(attachable, out TransformComponent? transformComponent) || + !transformComponent.ParentUid.Valid || + !HasComp(transformComponent.ParentUid)) + { + holderUid = null; + return false; + } + + holderUid = transformComponent.ParentUid; + return true; + } + + public bool TryGetUser(EntityUid attachable, [NotNullWhen(true)] out EntityUid? userUid) + { + userUid = null; + + if (!TryGetHolder(attachable, out var holderUid)) + return false; + + if (!TryComp(holderUid, out TransformComponent? transformComponent) || !transformComponent.ParentUid.Valid) + return false; + + userUid = transformComponent.ParentUid; + return true; + } + + public void RelayEvent(Entity holder, ref T args) where T : notnull + { + var ev = new AttachableRelayedEvent(args, holder.Owner); + + foreach (var slot in holder.Comp.Slots.Keys) + { + if (_container.TryGetContainer(holder, slot, out var container)) + { + foreach (var contained in container.ContainedEntities) + { + RaiseLocalEvent(contained, ev); + } + } + } + + args = ev.Args; + } + + private void AlterAllAttachables(Entity holder, AttachableAlteredType alteration) + { + foreach (var slotId in holder.Comp.Slots.Keys) + { + if (!_container.TryGetContainer(holder, slotId, out var container) || container.Count <= 0) + continue; + + var ev = new AttachableAlteredEvent(holder.Owner, alteration); + RaiseLocalEvent(container.ContainedEntities[0], ref ev); + } + } +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableIFFSystem.cs b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableIFFSystem.cs new file mode 100644 index 00000000000..9b021878821 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableIFFSystem.cs @@ -0,0 +1,72 @@ +// using Content.Shared._RMC14.Attachable.Components; +// using Content.Shared._RMC14.Attachable.Events; +// using Content.Shared._RMC14.Weapons.Ranged.IFF; +// using Content.Shared.Examine; +// using Content.Shared.Weapons.Ranged.Events; +// using Robust.Shared.Timing; + +// namespace Content.Shared._RMC14.Attachable.Systems; + +// public sealed class AttachableIFFSystem : EntitySystem +// { +// [Dependency] private readonly AttachableHolderSystem _holder = default!; +// [Dependency] private readonly GunIFFSystem _gunIFF = default!; +// [Dependency] private readonly IGameTiming _timing = default!; + +// public override void Initialize() +// { +// SubscribeLocalEvent(OnAttachableIFFAltered); +// SubscribeLocalEvent>(OnAttachableIFFGrant); + +// SubscribeLocalEvent(OnGunAttachableIFFAmmoShot); +// SubscribeLocalEvent(OnGunAttachableIFFExamined); +// } + +// private void OnAttachableIFFAltered(Entity ent, ref AttachableAlteredEvent args) +// { +// switch (args.Alteration) +// { +// case AttachableAlteredType.Attached: +// UpdateGunIFF(args.Holder); +// break; +// case AttachableAlteredType.Detached: +// UpdateGunIFF(args.Holder); +// break; +// } +// } + +// private void OnAttachableIFFGrant(Entity ent, ref AttachableRelayedEvent args) +// { +// args.Args.Grants = true; +// } + +// private void OnGunAttachableIFFAmmoShot(Entity ent, ref AmmoShotEvent args) +// { +// _gunIFF.GiveAmmoIFF(ent, ref args, false, true); +// } + +// private void OnGunAttachableIFFExamined(Entity ent, ref ExaminedEvent args) +// { +// using (args.PushGroup(nameof(GunAttachableIFFComponent))) +// { +// args.PushMarkup(Loc.GetString("rmc-examine-text-iff")); +// } +// } + +// private void UpdateGunIFF(EntityUid gun) +// { +// if (!TryComp(gun, out AttachableHolderComponent? holder)) +// return; + +// var ev = new AttachableGrantIFFEvent(); +// _holder.RelayEvent((gun, holder), ref ev); + +// if (_timing.ApplyingState) +// return; + +// if (ev.Grants) +// EnsureComp(gun); +// else +// RemCompDeferred(gun); +// } +// } diff --git a/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableMagneticSystem.cs b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableMagneticSystem.cs new file mode 100644 index 00000000000..4ec3042de9a --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableMagneticSystem.cs @@ -0,0 +1,30 @@ +using Content.Shared._RMC14.Armor.Magnetic; +using Content.Shared._RMC14.Attachable.Components; +using Content.Shared._RMC14.Attachable.Events; + +namespace Content.Shared._RMC14.Attachable.Systems; + +public sealed class AttachableMagneticSystem : EntitySystem +{ + [Dependency] private readonly RMCMagneticSystem _magneticSystem = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnAttachableAltered); + } + + private void OnAttachableAltered(Entity attachable, ref AttachableAlteredEvent args) + { + switch (args.Alteration) + { + case AttachableAlteredType.Attached: + var comp = EnsureComp(args.Holder); + _magneticSystem.SetMagnetizeToSlots((args.Holder, comp), attachable.Comp.MagnetizeToSlots); + break; + + case AttachableAlteredType.Detached: + RemCompDeferred(args.Holder); + break; + } + } +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableModifiersSystem.Melee.cs b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableModifiersSystem.Melee.cs new file mode 100644 index 00000000000..02220c942a8 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableModifiersSystem.Melee.cs @@ -0,0 +1,90 @@ +using Content.Shared._RMC14.Attachable.Components; +using Content.Shared._RMC14.Attachable.Events; +using Content.Shared.FixedPoint; +using Content.Shared.Weapons.Melee.Events; + +namespace Content.Shared._RMC14.Attachable.Systems; + +public sealed partial class AttachableModifiersSystem : EntitySystem +{ + private readonly Dictionary _damage = new(); + + private void InitializeMelee() + { + SubscribeLocalEvent(OnMeleeModsGetExamineData); + SubscribeLocalEvent>(OnMeleeModsHitEvent); + } + + private void OnMeleeModsGetExamineData(Entity attachable, ref AttachableGetExamineDataEvent args) + { + foreach (var modSet in attachable.Comp.Modifiers) + { + var key = GetExamineKey(modSet.Conditions); + + if (!args.Data.ContainsKey(key)) + args.Data[key] = new (modSet.Conditions, GetEffectStrings(modSet)); + else + args.Data[key].effectStrings.AddRange(GetEffectStrings(modSet)); + } + } + + private List GetEffectStrings(AttachableWeaponMeleeModifierSet modSet) + { + var result = new List(); + + + if (modSet.BonusDamage != null) + { + var bonusDamage = modSet.BonusDamage.GetTotal(); + if (bonusDamage != 0) + result.Add(Loc.GetString("rmc-attachable-examine-melee-damage", + ("colour", modifierExamineColour), ("sign", bonusDamage > 0 ? '+' : ""), ("damage", bonusDamage))); + } + + return result; + } + + private void OnMeleeModsHitEvent(Entity attachable, ref AttachableRelayedEvent args) + { + foreach(var modSet in attachable.Comp.Modifiers) + { + ApplyModifierSet(attachable, modSet, ref args.Args); + } + } + + private void ApplyModifierSet(Entity attachable, AttachableWeaponMeleeModifierSet modSet, ref MeleeHitEvent args) + { + if (!_attachableHolderSystem.TryGetHolder(attachable, out _) || + !CanApplyModifiers(attachable.Owner, modSet.Conditions)) + { + return; + } + + if (modSet.BonusDamage != null) + args.BonusDamage += modSet.BonusDamage; + + if (args.BonusDamage.GetTotal() < FixedPoint2.Zero) + { + _damage.Clear(); + foreach (var (bonusId, bonusDmg) in args.BonusDamage.DamageDict) + { + if (bonusDmg > FixedPoint2.Zero) + continue; + + if (!args.BaseDamage.DamageDict.TryGetValue(bonusId, out var baseDamage)) + { + _damage[bonusId] = -bonusDmg; + continue; + } + + if (-bonusDmg > baseDamage) + _damage[bonusId] = -bonusDmg - baseDamage; + } + + foreach (var (bonusId, bonusDmg) in _damage) + { + args.BonusDamage.DamageDict[bonusId] = -bonusDmg; + } + } + } +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableModifiersSystem.Ranged.cs b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableModifiersSystem.Ranged.cs new file mode 100644 index 00000000000..4652539d339 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableModifiersSystem.Ranged.cs @@ -0,0 +1,165 @@ +using Content.Shared._RMC14.Attachable.Components; +using Content.Shared._RMC14.Attachable.Events; +using Content.Shared._RMC14.Weapons.Ranged; +using Content.Shared.Weapons.Ranged.Components; +using Content.Shared.Weapons.Ranged.Events; + +namespace Content.Shared._RMC14.Attachable.Systems; + +public sealed partial class AttachableModifiersSystem : EntitySystem +{ + private void InitializeRanged() + { + SubscribeLocalEvent(OnRangedModsAltered); + SubscribeLocalEvent(OnRangedModsGetExamineData); + SubscribeLocalEvent>(OnRangedGetFireModes); + SubscribeLocalEvent>(OnRangedModsGetFireModeValues); + SubscribeLocalEvent>(OnRangedModsGetDamageFalloff); + SubscribeLocalEvent>(OnRangedModsGetGunDamage); + SubscribeLocalEvent>(OnRangedModsRefreshModifiers); + } + + private void OnRangedModsGetExamineData(Entity attachable, ref AttachableGetExamineDataEvent args) + { + foreach (var modSet in attachable.Comp.Modifiers) + { + var key = GetExamineKey(modSet.Conditions); + + if (!args.Data.ContainsKey(key)) + args.Data[key] = new (modSet.Conditions, GetEffectStrings(modSet)); + else + args.Data[key].effectStrings.AddRange(GetEffectStrings(modSet)); + } + } + + private List GetEffectStrings(AttachableWeaponRangedModifierSet modSet) + { + var result = new List(); + + if (modSet.ScatterFlat != 0) + result.Add(Loc.GetString("rmc-attachable-examine-ranged-scatter", + ("colour", modifierExamineColour), ("sign", modSet.ScatterFlat > 0 ? '+' : ""), ("scatter", modSet.ScatterFlat))); + + if (modSet.BurstScatterAddMult != 0) + result.Add(Loc.GetString("rmc-attachable-examine-ranged-burst-scatter", + ("colour", modifierExamineColour), ("sign", modSet.BurstScatterAddMult > 0 ? '+' : ""), ("burstScatterMult", modSet.BurstScatterAddMult))); + + if (modSet.ShotsPerBurstFlat != 0) + result.Add(Loc.GetString("rmc-attachable-examine-ranged-shots-per-burst", + ("colour", modifierExamineColour), ("sign", modSet.ShotsPerBurstFlat > 0 ? '+' : ""), ("shots", modSet.ShotsPerBurstFlat))); + + if (modSet.FireDelayFlat != 0) + result.Add(Loc.GetString("rmc-attachable-examine-ranged-fire-delay", + ("colour", modifierExamineColour), ("sign", modSet.FireDelayFlat > 0 ? '+' : ""), ("fireDelay", modSet.FireDelayFlat))); + + if (modSet.RecoilFlat != 0) + result.Add(Loc.GetString("rmc-attachable-examine-ranged-recoil", + ("colour", modifierExamineColour), ("sign", modSet.RecoilFlat > 0 ? '+' : ""), ("recoil", modSet.RecoilFlat))); + + if (modSet.DamageAddMult != 0) + result.Add(Loc.GetString("rmc-attachable-examine-ranged-damage", + ("colour", modifierExamineColour), ("sign", modSet.DamageAddMult > 0 ? '+' : ""), ("damage", modSet.DamageAddMult))); + + if (modSet.ProjectileSpeedFlat != 0) + result.Add(Loc.GetString("rmc-attachable-examine-ranged-projectile-speed", + ("colour", modifierExamineColour), ("sign", modSet.ProjectileSpeedFlat > 0 ? '+' : ""), ("projectileSpeed", modSet.ProjectileSpeedFlat))); + + if (modSet.DamageFalloffAddMult != 0) + result.Add(Loc.GetString("rmc-attachable-examine-ranged-damage-falloff", + ("colour", modifierExamineColour), ("sign", modSet.DamageFalloffAddMult > 0 ? '+' : ""), ("falloff", modSet.DamageFalloffAddMult))); + + return result; + } + + private void OnRangedModsAltered(Entity attachable, ref AttachableAlteredEvent args) + { + switch(args.Alteration) + { + case AttachableAlteredType.AppearanceChanged: + break; + + case AttachableAlteredType.DetachedDeactivated: + break; + + default: + + if (attachable.Comp.FireModeMods != null) + { + _rmcSelectiveFireSystem.RefreshFireModes(args.Holder, true); + break; + } + + _rmcSelectiveFireSystem.RefreshModifiableFireModeValues(args.Holder); + break; + } + } + + private void OnRangedModsRefreshModifiers(Entity attachable, ref AttachableRelayedEvent args) + { + foreach(var modSet in attachable.Comp.Modifiers) + { + if (!CanApplyModifiers(attachable.Owner, modSet.Conditions)) + continue; + + args.Args.ShotsPerBurst = Math.Max(args.Args.ShotsPerBurst + modSet.ShotsPerBurstFlat, 1); + args.Args.CameraRecoilScalar = Math.Max(args.Args.CameraRecoilScalar + modSet.RecoilFlat, 0); + args.Args.MinAngle = Angle.FromDegrees(Math.Max(args.Args.MinAngle.Degrees + modSet.ScatterFlat, 0.0)); + args.Args.MaxAngle = Angle.FromDegrees(Math.Max(args.Args.MaxAngle.Degrees + modSet.ScatterFlat, args.Args.MinAngle)); + args.Args.ProjectileSpeed += modSet.ProjectileSpeedFlat; + + // Fire delay doesn't work quite like SS14 fire rate, so we're having to do maths: + // Fire rate is shots per second. Fire delay is the interval between shots. They are inversely proportionate to each other. + // First we divide 1 second by the fire rate to get our current fire delay, then we add the delay modifier, then we divide 1 by the result again to get the modified fire rate. + var fireDelayMod = args.Args.Gun.Comp.SelectedMode == SelectiveFire.Burst ? modSet.FireDelayFlat / 2f : modSet.FireDelayFlat; + args.Args.FireRate = 1f / (1f / args.Args.FireRate + fireDelayMod); + } + } + + private void OnRangedGetFireModes(Entity attachable, ref AttachableRelayedEvent args) + { + if (attachable.Comp.FireModeMods == null) + return; + + foreach (var modSet in attachable.Comp.FireModeMods) + { + if (!CanApplyModifiers(attachable.Owner, modSet.Conditions)) + continue; + + args.Args.Modes |= modSet.ExtraFireModes; + args.Args.Set = modSet.SetFireMode; + } + } + + private void OnRangedModsGetDamageFalloff(Entity attachable, ref AttachableRelayedEvent args) + { + foreach (var modSet in attachable.Comp.Modifiers) + { + if (!CanApplyModifiers(attachable.Owner, modSet.Conditions)) + continue; + + args.Args.FalloffMultiplier += modSet.DamageFalloffAddMult; + } + } + + private void OnRangedModsGetGunDamage(Entity attachable, ref AttachableRelayedEvent args) + { + foreach (var modSet in attachable.Comp.Modifiers) + { + if (!CanApplyModifiers(attachable.Owner, modSet.Conditions)) + continue; + + args.Args.Multiplier += modSet.DamageAddMult; + } + } + + private void OnRangedModsGetFireModeValues(Entity attachable, ref AttachableRelayedEvent args) + { + foreach (var modSet in attachable.Comp.Modifiers) + { + if (!CanApplyModifiers(attachable.Owner, modSet.Conditions)) + continue; + + args.Args.BurstScatterMult += modSet.BurstScatterAddMult; + } + } +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableModifiersSystem.Size.cs b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableModifiersSystem.Size.cs new file mode 100644 index 00000000000..a5ddbfdac4b --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableModifiersSystem.Size.cs @@ -0,0 +1,71 @@ +using Content.Shared._RMC14.Attachable.Components; +using Content.Shared._RMC14.Attachable.Events; +using Content.Shared._RMC14.Item; + +namespace Content.Shared._RMC14.Attachable.Systems; + +public sealed partial class AttachableModifiersSystem : EntitySystem +{ + [Dependency] private readonly ItemSizeChangeSystem _itemSizeChangeSystem = default!; + + private void InitializeSize() + { + SubscribeLocalEvent(OnSizeModsGetExamineData); + SubscribeLocalEvent(OnAttachableAltered); + SubscribeLocalEvent>(OnGetItemSizeModifiers); + } + + private void OnSizeModsGetExamineData(Entity attachable, ref AttachableGetExamineDataEvent args) + { + foreach (var modSet in attachable.Comp.Modifiers) + { + var key = GetExamineKey(modSet.Conditions); + + if (!args.Data.ContainsKey(key)) + args.Data[key] = new (modSet.Conditions, GetEffectStrings(modSet)); + else + args.Data[key].effectStrings.AddRange(GetEffectStrings(modSet)); + } + } + + private List GetEffectStrings(AttachableSizeModifierSet modSet) + { + var result = new List(); + + if (modSet.Size != 0) + result.Add(Loc.GetString("rmc-attachable-examine-size", + ("colour", modifierExamineColour), ("sign", modSet.Size > 0 ? '+' : ""), ("size", modSet.Size))); + + return result; + } + + private void OnAttachableAltered(Entity attachable, ref AttachableAlteredEvent args) + { + if (attachable.Comp.Modifiers.Count == 0) + return; + + switch (args.Alteration) + { + case AttachableAlteredType.AppearanceChanged: + break; + + case AttachableAlteredType.DetachedDeactivated: + break; + + default: + _itemSizeChangeSystem.RefreshItemSizeModifiers(args.Holder); + break; + } + } + + private void OnGetItemSizeModifiers(Entity attachable, ref AttachableRelayedEvent args) + { + foreach(var modSet in attachable.Comp.Modifiers) + { + if (!CanApplyModifiers(attachable.Owner, modSet.Conditions)) + return; + + args.Args.Size += modSet.Size; + } + } +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableModifiersSystem.Speed.cs b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableModifiersSystem.Speed.cs new file mode 100644 index 00000000000..3bfd981f66c --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableModifiersSystem.Speed.cs @@ -0,0 +1,78 @@ +using Content.Shared._RMC14.Attachable.Components; +using Content.Shared._RMC14.Attachable.Events; +using Content.Shared._RMC14.Wieldable; +using Content.Shared._RMC14.Wieldable.Events; +using Content.Shared.Wieldable.Components; + +namespace Content.Shared._RMC14.Attachable.Systems; + +public sealed partial class AttachableModifiersSystem : EntitySystem +{ + private void InitializeSpeed() + { + SubscribeLocalEvent(OnSpeedModsGetExamineData); + SubscribeLocalEvent(OnAttachableAltered); + SubscribeLocalEvent>(OnGetSpeedModifiers); + } + + private void OnSpeedModsGetExamineData(Entity attachable, ref AttachableGetExamineDataEvent args) + { + foreach (var modSet in attachable.Comp.Modifiers) + { + var key = GetExamineKey(modSet.Conditions); + + if (!args.Data.ContainsKey(key)) + args.Data[key] = new (modSet.Conditions, GetEffectStrings(modSet)); + else + args.Data[key].effectStrings.AddRange(GetEffectStrings(modSet)); + } + } + + private List GetEffectStrings(AttachableSpeedModifierSet modSet) + { + var result = new List(); + + if (modSet.Walk != 0) + result.Add(Loc.GetString("rmc-attachable-examine-speed-walk", + ("colour", modifierExamineColour), ("sign", modSet.Walk > 0 ? '+' : ""), ("speed", modSet.Walk))); + + if (modSet.Sprint != 0) + result.Add(Loc.GetString("rmc-attachable-examine-speed-sprint", + ("colour", modifierExamineColour), ("sign", modSet.Sprint > 0 ? '+' : ""), ("speed", modSet.Sprint))); + + return result; + } + + private void OnAttachableAltered(Entity attachable, ref AttachableAlteredEvent args) + { + switch(args.Alteration) + { + case AttachableAlteredType.AppearanceChanged: + break; + + case AttachableAlteredType.DetachedDeactivated: + break; + + default: + _wieldableSystem.RefreshSpeedModifiers(args.Holder); + break; + } + } + + private void OnGetSpeedModifiers(Entity attachable, ref AttachableRelayedEvent args) + { + foreach(var modSet in attachable.Comp.Modifiers) + { + ApplyModifierSet(attachable, modSet, ref args.Args); + } + } + + private void ApplyModifierSet(Entity attachable, AttachableSpeedModifierSet modSet, ref GetWieldableSpeedModifiersEvent args) + { + if (!CanApplyModifiers(attachable.Owner, modSet.Conditions)) + return; + + args.Walk += modSet.Walk; + args.Sprint += modSet.Sprint; + } +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableModifiersSystem.WieldDelay.cs b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableModifiersSystem.WieldDelay.cs new file mode 100644 index 00000000000..bfa3d627e3b --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableModifiersSystem.WieldDelay.cs @@ -0,0 +1,77 @@ +using Content.Shared._RMC14.Attachable.Components; +using Content.Shared._RMC14.Attachable.Events; +using Content.Shared._RMC14.Wieldable.Events; + +namespace Content.Shared._RMC14.Attachable.Systems; + +public sealed partial class AttachableModifiersSystem : EntitySystem +{ + private void InitializeWieldDelay() + { + SubscribeLocalEvent(OnWieldDelayModsGetExamineData); + SubscribeLocalEvent(OnAttachableAltered); + SubscribeLocalEvent>(OnGetWieldDelay); + } + + private void OnWieldDelayModsGetExamineData(Entity attachable, ref AttachableGetExamineDataEvent args) + { + foreach (var modSet in attachable.Comp.Modifiers) + { + var key = GetExamineKey(modSet.Conditions); + + if (!args.Data.ContainsKey(key)) + args.Data[key] = new (modSet.Conditions, GetEffectStrings(modSet)); + else + args.Data[key].effectStrings.AddRange(GetEffectStrings(modSet)); + } + } + + private List GetEffectStrings(AttachableWieldDelayModifierSet modSet) + { + var result = new List(); + + if (modSet.Delay != TimeSpan.Zero) + result.Add(Loc.GetString("rmc-attachable-examine-wield-delay", + ("colour", modifierExamineColour), ("sign", modSet.Delay.TotalSeconds > 0 ? '+' : ""), ("delay", modSet.Delay.TotalSeconds))); + + return result; + } + + private void OnAttachableAltered(Entity attachable, ref AttachableAlteredEvent args) + { + switch(args.Alteration) + { + case AttachableAlteredType.AppearanceChanged: + break; + + case AttachableAlteredType.DetachedDeactivated: + break; + + case AttachableAlteredType.Wielded: + break; + + case AttachableAlteredType.Unwielded: + break; + + default: + _wieldableSystem.RefreshWieldDelay(args.Holder); + break; + } + } + + private void OnGetWieldDelay(Entity attachable, ref AttachableRelayedEvent args) + { + foreach(var modSet in attachable.Comp.Modifiers) + { + ApplyModifierSet(attachable, modSet, ref args.Args); + } + } + + private void ApplyModifierSet(Entity attachable, AttachableWieldDelayModifierSet modSet, ref GetWieldDelayEvent args) + { + if (!CanApplyModifiers(attachable.Owner, modSet.Conditions)) + return; + + args.Delay += modSet.Delay; + } +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableModifiersSystem.cs b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableModifiersSystem.cs new file mode 100644 index 00000000000..605c146d740 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableModifiersSystem.cs @@ -0,0 +1,215 @@ +using Content.Shared._RMC14.Attachable.Components; +using Content.Shared._RMC14.Attachable.Events; +using Content.Shared._RMC14.Weapons.Ranged; +using Content.Shared._RMC14.Wieldable; +using Content.Shared.Examine; +using Content.Shared.Verbs; +using Content.Shared.Weapons.Ranged.Systems; +using Content.Shared.Whitelist; +using Content.Shared.Wieldable.Components; +using Robust.Shared.Utility; + +namespace Content.Shared._RMC14.Attachable.Systems; + +public sealed partial class AttachableModifiersSystem : EntitySystem +{ + [Dependency] private readonly AttachableHolderSystem _attachableHolderSystem = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; + [Dependency] private readonly ExamineSystemShared _examineSystem = default!; + [Dependency] private readonly RMCSelectiveFireSystem _rmcSelectiveFireSystem = default!; + [Dependency] private readonly RMCWieldableSystem _wieldableSystem = default!; + [Dependency] private readonly SharedGunSystem _gunSystem = default!; + + private const string modifierExamineColour = "yellow"; + + public override void Initialize() + { + SubscribeLocalEvent>(OnAttachableGetExamineVerbs); + + InitializeMelee(); + InitializeRanged(); + InitializeSize(); + InitializeSpeed(); + InitializeWieldDelay(); + } + + private void OnAttachableGetExamineVerbs(Entity attachable, ref GetVerbsEvent args) + { + if (!args.CanInteract || !args.CanAccess) + return; + + var ev = new AttachableGetExamineDataEvent(new Dictionary effectStrings)>()); + RaiseLocalEvent(attachable.Owner, ref ev); + + var message = new FormattedMessage(); + foreach (var key in ev.Data.Keys) + { + message.TryAddMarkup(GetExamineConditionText(attachable, ev.Data[key].conditions), out _); + message.PushNewline(); + + foreach (var effectText in ev.Data[key].effectStrings) + { + message.TryAddMarkup(" " + effectText, out _); + message.PushNewline(); + } + } + + if (!message.IsEmpty) + { + _examineSystem.AddDetailedExamineVerb(args, attachable.Comp, message, + Loc.GetString("rmc-attachable-examinable-verb-text"), + "/Textures/Interface/VerbIcons/information.svg.192dpi.png", + Loc.GetString("rmc-attachable-examinable-verb-message") + ); + } + } + + private string GetExamineConditionText(Entity attachable, AttachableModifierConditions? conditions) + { + string conditionText = Loc.GetString("rmc-attachable-examine-condition-always"); + + if (conditions == null) + return conditionText; + + AttachableModifierConditions cond = conditions.Value; + + bool conditionPlaced = false; + conditionText = Loc.GetString("rmc-attachable-examine-condition-when") + ' '; + + ExamineConditionAddEntry(cond.WieldedOnly, Loc.GetString("rmc-attachable-examine-condition-wielded"), ref conditionText, ref conditionPlaced); + ExamineConditionAddEntry(cond.UnwieldedOnly, Loc.GetString("rmc-attachable-examine-condition-unwielded"), ref conditionText, ref conditionPlaced); + + ExamineConditionAddEntry( + cond.ActiveOnly, + Loc.GetString("rmc-attachable-examine-condition-active", ("attachable", attachable.Owner)), + ref conditionText, + ref conditionPlaced); + + ExamineConditionAddEntry( + cond.InactiveOnly, + Loc.GetString("rmc-attachable-examine-condition-inactive", ("attachable", attachable.Owner)), + ref conditionText, + ref conditionPlaced); + + if (cond.Whitelist != null) + { + EntityWhitelist whitelist = cond.Whitelist; + + if (whitelist.Registrations != null) + ExamineConditionAddEntry( + cond.Whitelist != null, + Loc.GetString("rmc-attachable-examine-condition-whitelist-comps", ("compNumber", whitelist.RequireAll ? "all" : "one"), ("comps", String.Join(", ", whitelist.Registrations))), + ref conditionText, + ref conditionPlaced); + + if (whitelist.Sizes != null) + ExamineConditionAddEntry( + cond.Whitelist != null, + Loc.GetString("rmc-attachable-examine-condition-whitelist-sizes", ("sizes", String.Join(", ", whitelist.Sizes))), + ref conditionText, + ref conditionPlaced); + + if (whitelist.Tags != null) + ExamineConditionAddEntry( + cond.Whitelist != null, + Loc.GetString("rmc-attachable-examine-condition-whitelist-tags", ("tagNumber", whitelist.RequireAll ? "all" : "one"), ("tags", String.Join(", ", whitelist.Tags))), + ref conditionText, + ref conditionPlaced); + } + + if (cond.Blacklist != null && cond.Blacklist.Tags != null) + { + EntityWhitelist blacklist = cond.Blacklist; + + if (blacklist.Registrations != null) + ExamineConditionAddEntry( + cond.Blacklist != null, + Loc.GetString("rmc-attachable-examine-condition-blacklist-comps", ("compNumber", blacklist.RequireAll ? "one" : "all"), ("comps", String.Join(", ", blacklist.Registrations))), + ref conditionText, + ref conditionPlaced); + + if (blacklist.Sizes != null) + ExamineConditionAddEntry( + cond.Blacklist != null, + Loc.GetString("rmc-attachable-examine-condition-blacklist-sizes", ("sizes", String.Join(", ", blacklist.Sizes))), + ref conditionText, + ref conditionPlaced); + + if (blacklist.Tags != null) + ExamineConditionAddEntry( + cond.Blacklist != null, + Loc.GetString("rmc-attachable-examine-condition-blacklist-tags", ("tagNumber", blacklist.RequireAll ? "one" : "all"), ("tags", String.Join(", ", blacklist.Tags))), + ref conditionText, + ref conditionPlaced); + } + + conditionText += ':'; + + return conditionText; + } + + private void ExamineConditionAddEntry(bool condition, string text, ref string conditionText, ref bool conditionPlaced) + { + if (!condition) + return; + + if (conditionPlaced) + conditionText += "; "; + conditionText += text; + conditionPlaced = true; + } + + private byte GetExamineKey(AttachableModifierConditions? conditions) + { + byte key = 0; + + if (conditions == null) + return key; + + key |= conditions.Value.WieldedOnly ? (byte)(1 << 0) : (byte)0; + key |= conditions.Value.UnwieldedOnly ? (byte)(1 << 1) : (byte)0; + key |= conditions.Value.ActiveOnly ? (byte)(1 << 2) : (byte)0; + key |= conditions.Value.InactiveOnly ? (byte)(1 << 3) : (byte)0; + key |= conditions.Value.Whitelist != null ? (byte)(1 << 4) : (byte)0; + key |= conditions.Value.Blacklist != null ? (byte)(1 << 5) : (byte)0; + + return key; + } + + private bool CanApplyModifiers(EntityUid attachableUid, AttachableModifierConditions? conditions) + { + if (conditions == null) + return true; + + _attachableHolderSystem.TryGetHolder(attachableUid, out var holderUid); + + if (holderUid != null) + { + TryComp(holderUid, out WieldableComponent? wieldableComponent); + + if (conditions.Value.UnwieldedOnly && wieldableComponent != null && wieldableComponent.Wielded) + return false; + else if (conditions.Value.WieldedOnly && (wieldableComponent == null || !wieldableComponent.Wielded)) + return false; + } + + TryComp(attachableUid, out AttachableToggleableComponent? toggleableComponent); + + if (conditions.Value.InactiveOnly && toggleableComponent != null && toggleableComponent.Active) + return false; + else if (conditions.Value.ActiveOnly && (toggleableComponent == null || !toggleableComponent.Active)) + return false; + + + if (holderUid != null) + { + if (conditions.Value.Whitelist != null && _whitelistSystem.IsWhitelistFail(conditions.Value.Whitelist, holderUid.Value)) + return false; + + if (conditions.Value.Blacklist != null && _whitelistSystem.IsWhitelistPass(conditions.Value.Blacklist, holderUid.Value)) + return false; + } + + return true; + } +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachablePreventDropSystem.cs b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachablePreventDropSystem.cs new file mode 100644 index 00000000000..488eae5db06 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachablePreventDropSystem.cs @@ -0,0 +1,33 @@ +using Content.Shared._RMC14.Attachable.Components; +using Content.Shared._RMC14.Attachable.Events; +using Content.Shared.Interaction.Components; + +namespace Content.Shared._RMC14.Attachable.Systems; + +public sealed class AttachablePreventDropSystem : EntitySystem +{ + public override void Initialize() + { + SubscribeLocalEvent(OnAttachableAltered); + } + + private void OnAttachableAltered(Entity attachable, ref AttachableAlteredEvent args) + { + switch (args.Alteration) + { + case AttachableAlteredType.Activated: + var comp = EnsureComp(args.Holder); + comp.DeleteOnDrop = false; + Dirty(args.Holder, comp); + break; + + case AttachableAlteredType.Deactivated: + RemCompDeferred(args.Holder); + break; + + case AttachableAlteredType.DetachedDeactivated: + RemCompDeferred(args.Holder); + break; + } + } +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachablePryingSystem.cs b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachablePryingSystem.cs new file mode 100644 index 00000000000..398e85b2daa --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachablePryingSystem.cs @@ -0,0 +1,46 @@ +using Content.Shared._RMC14.Attachable.Components; +using Content.Shared._RMC14.Attachable.Events; +using Content.Shared.Prying.Components; +using Content.Shared.Tools.Components; +using Robust.Shared.Audio; +using Robust.Shared.Prototypes; +using Robust.Shared.Timing; + +namespace Content.Shared._RMC14.Attachable.Systems; + +public sealed class AttachablePryingSystem : EntitySystem +{ + [Dependency] private readonly IPrototypeManager _prototype = default!; + [Dependency] private readonly IGameTiming _timing = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnAttachableAltered); + } + + private void OnAttachableAltered(Entity ent, ref AttachableAlteredEvent args) + { + if (_timing.ApplyingState) + return; + + switch (args.Alteration) + { + case AttachableAlteredType.Attached: + var prying = EnsureComp(args.Holder); + var tool = EnsureComp(args.Holder); +#pragma warning disable RA0002 + prying.SpeedModifier = 0.5f; + tool.Qualities.Add("Prying", _prototype); + tool.UseSound = new SoundPathSpecifier("/Audio/Items/crowbar.ogg"); +#pragma warning restore RA0002 + + Dirty(args.Holder, prying); + Dirty(args.Holder, tool); + break; + case AttachableAlteredType.Detached: + RemCompDeferred(args.Holder); + RemCompDeferred(args.Holder); + break; + } + } +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableSilencerSystem.cs b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableSilencerSystem.cs new file mode 100644 index 00000000000..5c4a7d19a8c --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableSilencerSystem.cs @@ -0,0 +1,24 @@ +using Content.Shared._RMC14.Attachable.Components; +using Content.Shared._RMC14.Attachable.Events; +using Content.Shared.Weapons.Ranged.Events; + +namespace Content.Shared._RMC14.Attachable.Systems; + +public sealed class AttachableSilencerSystem : EntitySystem +{ + public override void Initialize() + { + SubscribeLocalEvent>(OnSilencerRefreshModifiers); + SubscribeLocalEvent>(OnSilencerMuzzleFlash); + } + + private void OnSilencerRefreshModifiers(Entity ent, ref AttachableRelayedEvent args) + { + args.Args.SoundGunshot = ent.Comp.Sound; + } + + private void OnSilencerMuzzleFlash(Entity ent, ref AttachableRelayedEvent args) + { + args.Args.Cancelled = true; + } +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableTemporarySpeedModsSystem.cs b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableTemporarySpeedModsSystem.cs new file mode 100644 index 00000000000..23288ac8e3b --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableTemporarySpeedModsSystem.cs @@ -0,0 +1,24 @@ +using Content.Shared._RMC14.Attachable.Components; +using Content.Shared._RMC14.Attachable.Events; +using Content.Shared._RMC14.Movement; + +namespace Content.Shared._RMC14.Attachable.Systems; + +public sealed class AttachableTemporarySpeedModsSystem : EntitySystem +{ + [Dependency] private readonly TemporarySpeedModifiersSystem _temporarySpeedModifiersSystem = default!; + [Dependency] private readonly AttachableHolderSystem _attachableHolderSystem = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnAttachableAltered); + } + + private void OnAttachableAltered(Entity attachable, ref AttachableAlteredEvent args) + { + if ((attachable.Comp.Alteration & args.Alteration) != attachable.Comp.Alteration || !_attachableHolderSystem.TryGetUser(attachable.Owner, out var userUid)) + return; + + _temporarySpeedModifiersSystem.ModifySpeed(userUid.Value, attachable.Comp.Modifiers); + } +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableToggleableSystem.cs b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableToggleableSystem.cs new file mode 100644 index 00000000000..65e5f3a5f49 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableToggleableSystem.cs @@ -0,0 +1,789 @@ +using System.Numerics; +using Content.Shared._RMC14.Attachable.Components; +using Content.Shared._RMC14.Attachable.Events; +using Content.Shared._RMC14.Weapons.Ranged; +using Content.Shared.Actions; +using Content.Shared.Actions.Events; +using Content.Shared.DoAfter; +using Content.Shared.Hands; +using Content.Shared.Hands.EntitySystems; +using Content.Shared.Interaction; +using Content.Shared.Light; +using Content.Shared.Movement.Events; +using Content.Shared.Physics; +using Content.Shared.Popups; +using Content.Shared.Timing; +using Content.Shared.Toggleable; +using Content.Shared.Weapons.Ranged.Systems; +using Content.Shared.Whitelist; +using Content.Shared.Wieldable.Components; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Map; +using Robust.Shared.Physics; +using Robust.Shared.Timing; + +namespace Content.Shared._RMC14.Attachable.Systems; + +public sealed class AttachableToggleableSystem : EntitySystem +{ + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly ActionContainerSystem _actionContainerSystem = default!; + [Dependency] private readonly EntityLookupSystem _entityLookupSystem = default!; + [Dependency] private readonly EntityWhitelistSystem _entityWhitelistSystem = default!; + [Dependency] private readonly MetaDataSystem _metaDataSystem = default!; + [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; + [Dependency] private readonly AttachableHolderSystem _attachableHolderSystem = default!; + [Dependency] private readonly SharedAudioSystem _audioSystem = default!; + [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; + [Dependency] private readonly SharedHandsSystem _handsSystem = default!; + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + [Dependency] private readonly SharedTransformSystem _transformSystem = default!; + [Dependency] private readonly UseDelaySystem _useDelaySystem = default!; + + private const string attachableToggleUseDelayID = "RMCAttachableToggle"; + + private const int bracingInvalidCollisionGroup = (int)CollisionGroup.ThrownItem; + private const int bracingRequiredCollisionGroup = (int)CollisionGroup.MidImpassable; + + public override void Initialize() + { + SubscribeLocalEvent(OnActivateInWorld); + SubscribeLocalEvent(OnAttachableAltered, + after: new[] { typeof(AttachableModifiersSystem) }); + SubscribeLocalEvent(OnAttachableToggleableInterrupt); + SubscribeLocalEvent(OnAttachableToggleAction); + SubscribeLocalEvent(OnAttachableToggleDoAfter); + SubscribeLocalEvent(OnAttachableToggleStarted); + SubscribeLocalEvent(OnAttemptShoot); + SubscribeLocalEvent>(OnGunShot); + SubscribeLocalEvent(OnGunShot); + SubscribeLocalEvent(OnToggleAction, + before: new[] { typeof(SharedHandheldLightSystem) }); + //SubscribeLocalEvent(OnUniqueAction); + SubscribeLocalEvent(OnGrantAttachableActions); + SubscribeLocalEvent(OnRemoveAttachableActions); + SubscribeLocalEvent>(OnHandDeselected); + SubscribeLocalEvent>(OnGotEquippedHand); + SubscribeLocalEvent>(OnGotUnequippedHand); + + SubscribeLocalEvent(OnAttachableMovementLockedMoveInput); + + SubscribeLocalEvent(OnAttachableAltered, + after: new[] { typeof(AttachableModifiersSystem) }); + + SubscribeLocalEvent(OnAttachableAltered, + after: new[] { typeof(AttachableModifiersSystem) }); + + SubscribeLocalEvent(OnAttemptShoot); + } + +#region AttachableAlteredEvent handling + private void OnAttachableAltered(Entity attachable, ref AttachableAlteredEvent args) + { + switch (args.Alteration) + { + case AttachableAlteredType.Detached: + if (attachable.Comp.SupercedeHolder && + TryComp(args.Holder, out AttachableHolderComponent? holderComponent) && + holderComponent.SupercedingAttachable == attachable.Owner) + { + _attachableHolderSystem.SetSupercedingAttachable((args.Holder, holderComponent), null); + } + + if (attachable.Comp.Active) + { + var ev = args with { Alteration = AttachableAlteredType.DetachedDeactivated }; + RaiseLocalEvent(attachable.Owner, ref ev); + } + + attachable.Comp.Attached = false; + attachable.Comp.Active = false; + Dirty(attachable); + break; + + case AttachableAlteredType.Attached: + attachable.Comp.Attached = true; + break; + + case AttachableAlteredType.Unwielded: + if (!attachable.Comp.WieldedOnly || !attachable.Comp.Active) + break; + + Toggle(attachable, args.User, attachable.Comp.DoInterrupt); + break; + } + + if (attachable.Comp.Action == null || + !TryComp(attachable.Comp.Action, out InstantActionComponent? actionComponent)) + { + return; + } + + _actionsSystem.SetToggled(attachable.Comp.Action, attachable.Comp.Active); + actionComponent.Enabled = attachable.Comp.Attached; + } + + private void OnAttachableAltered(Entity attachable, ref AttachableAlteredEvent args) + { + if (args.User == null) + return; + + switch (args.Alteration) + { + case AttachableAlteredType.Activated: + RaiseLocalEvent(attachable.Owner, new ActivateInWorldEvent(args.User.Value, args.Holder, true)); + break; + + case AttachableAlteredType.Deactivated: + RaiseLocalEvent(attachable.Owner, new ActivateInWorldEvent(args.User.Value, args.Holder, true)); + break; + + case AttachableAlteredType.DetachedDeactivated: + RaiseLocalEvent(attachable.Owner, new ActivateInWorldEvent(args.User.Value, args.Holder, true)); + break; + } + } + + private void OnAttachableAltered(Entity attachable, ref AttachableAlteredEvent args) + { + if (!TryComp(attachable.Owner, out AttachableToggleableComponent? toggleableComponent)) + return; + + EnsureComp(args.Holder, out AttachableGunPreventShootComponent preventShootComponent); + + switch (args.Alteration) + { + case AttachableAlteredType.Attached: + preventShootComponent.Message = attachable.Comp.Message; + preventShootComponent.PreventShoot = attachable.Comp.ShootWhenActive && !toggleableComponent.Active || !attachable.Comp.ShootWhenActive && toggleableComponent.Active; + break; + + case AttachableAlteredType.Detached: + preventShootComponent.Message = ""; + preventShootComponent.PreventShoot = false; + break; + + case AttachableAlteredType.Activated: + preventShootComponent.PreventShoot = !attachable.Comp.ShootWhenActive; + break; + + case AttachableAlteredType.Deactivated: + preventShootComponent.PreventShoot = attachable.Comp.ShootWhenActive; + break; + + case AttachableAlteredType.DetachedDeactivated: + preventShootComponent.PreventShoot = false; + break; + } + + Dirty(args.Holder, preventShootComponent); + } +#endregion + + private void OnGotEquippedHand(Entity attachable, ref AttachableRelayedEvent args) + { + if (!attachable.Comp.Attached) + return; + + args.Args.Handled = true; + + var addEv = new GrantAttachableActionsEvent(args.Args.User); + RaiseLocalEvent(attachable, ref addEv); + } + +#region Lockouts and interrupts + private void OnActivateInWorld(Entity attachable, ref ActivateInWorldEvent args) + { + if (attachable.Comp.AttachedOnly && !attachable.Comp.Attached) + args.Handled = true; + } + + private void OnAttemptShoot(Entity attachable, ref AttemptShootEvent args) + { + if (args.Cancelled) + return; + + if (attachable.Comp.AttachedOnly && !attachable.Comp.Attached) + { + args.Cancelled = true; + return; + } + + if (attachable.Comp.WieldedUseOnly && + (!_attachableHolderSystem.TryGetHolder(attachable.Owner, out EntityUid? holderUid) || + !TryComp(holderUid, out WieldableComponent? wieldableComponent) || + !wieldableComponent.Wielded)) + { + args.Cancelled = true; + + if (holderUid == null) + return; + + _popupSystem.PopupClient( + Loc.GetString("rmc-attachable-shoot-fail-not-wielded", ("holder", holderUid), ("attachable", attachable)), + args.User, + args.User); + return; + } + } + + private void OnGunShot(Entity attachable, ref AttachableRelayedEvent args) + { + CheckUserBreakOnRotate(args.Args.User); + CheckUserBreakOnFullRotate(args.Args.User, args.Args.FromCoordinates, args.Args.ToCoordinates); + } + + private void OnGunShot(Entity attachable, ref GunShotEvent args) + { + CheckUserBreakOnRotate(args.User); + CheckUserBreakOnFullRotate(args.User, args.FromCoordinates, args.ToCoordinates); + } + + private void OnAttemptShoot(Entity gun, ref AttemptShootEvent args) + { + if (args.Cancelled || !gun.Comp.PreventShoot) + return; + + args.Cancelled = true; + + _popupSystem.PopupClient(gun.Comp.Message, args.User, args.User); + } + +/* private void OnUniqueAction(Entity attachable, ref UniqueActionEvent args) + { + if (attachable.Comp.AttachedOnly && !attachable.Comp.Attached) + args.Handled = true; + }*/ + + private void OnHandDeselected(Entity attachable, ref AttachableRelayedEvent args) + { + if (!attachable.Comp.Attached) + return; + + args.Args.Handled = true; + + if (!attachable.Comp.NeedHand || !attachable.Comp.Active) + return; + + Toggle(attachable, args.Args.User, attachable.Comp.DoInterrupt); + } + + private void OnAttachableToggleableInterrupt(Entity attachable, ref AttachableToggleableInterruptEvent args) + { + if (!attachable.Comp.Active) + return; + + Toggle(attachable, args.User, attachable.Comp.DoInterrupt); + } + + private void OnGotUnequippedHand(Entity attachable, ref AttachableRelayedEvent args) + { + if (!attachable.Comp.Attached) + return; + + args.Args.Handled = true; + + if (attachable.Comp.NeedHand && attachable.Comp.Active) + Toggle(attachable, args.Args.User, attachable.Comp.DoInterrupt); + + + var removeEv = new RemoveAttachableActionsEvent(args.Args.User); + RaiseLocalEvent(attachable, ref removeEv); + } + + private void OnAttachableMovementLockedMoveInput(Entity user, ref MoveInputEvent args) + { + if (!args.HasDirectionalMovement) + return; + + foreach (var attachableUid in user.Comp.AttachableList) + { + if (!TryComp(attachableUid, out AttachableToggleableComponent? toggleableComponent) || + !toggleableComponent.Active || + !toggleableComponent.BreakOnMove) + { + continue; + } + + Toggle((attachableUid, toggleableComponent), user.Owner, toggleableComponent.DoInterrupt); + } + + RemCompDeferred(user); + } + + private void CheckUserBreakOnRotate(Entity user) + { + if (user.Comp == null) + { + if (!TryComp(user.Owner, out AttachableDirectionLockedComponent? lockedComponent)) + return; + + user.Comp = lockedComponent; + } + + if (Transform(user.Owner).LocalRotation.GetCardinalDir() == user.Comp.LockedDirection) + return; + + foreach (EntityUid attachableUid in user.Comp.AttachableList) + { + if (!TryComp(attachableUid, out AttachableToggleableComponent? toggleableComponent) || + !toggleableComponent.Active || + !toggleableComponent.BreakOnRotate) + { + continue; + } + + Toggle((attachableUid, toggleableComponent), user.Owner, toggleableComponent.DoInterrupt); + } + + RemCompDeferred(user); + } + + private void CheckUserBreakOnFullRotate(Entity user, EntityCoordinates playerPos, EntityCoordinates targetPos) + { + if (user.Comp == null) + { + if (!TryComp(user.Owner, out AttachableSideLockedComponent? lockedComponent)) + return; + + user.Comp = lockedComponent; + } + + if (user.Comp.LockedDirection == null) + return; + + var initialAngle = user.Comp.LockedDirection.Value.ToAngle(); + var playerMapPos = _transformSystem.ToMapCoordinates(playerPos); + var targetMapPos = _transformSystem.ToMapCoordinates(targetPos); + var currentAngle = (targetMapPos.Position - playerMapPos.Position).ToWorldAngle(); + + var differenceFromLockedAngle = (currentAngle.Degrees - initialAngle.Degrees + 180 + 360) % 360 - 180; + + if (differenceFromLockedAngle > -90 && differenceFromLockedAngle < 90) + return; + + foreach (EntityUid attachableUid in user.Comp.AttachableList) + { + if (!TryComp(attachableUid, out AttachableToggleableComponent? toggleableComponent) || + !toggleableComponent.Active || + !toggleableComponent.BreakOnFullRotate) + { + continue; + } + + Toggle((attachableUid, toggleableComponent), user.Owner, toggleableComponent.DoInterrupt); + } + + RemCompDeferred(user); + } +#endregion + +#region Toggling + private void OnAttachableToggleStarted(Entity attachable, ref AttachableToggleStartedEvent args) + { + + if (!CanStartToggleDoAfter(attachable, ref args)) + return; + + var popupText = Loc.GetString(attachable.Comp.Active ? attachable.Comp.DeactivatePopupText : attachable.Comp.ActivatePopupText, ("attachable", attachable.Owner)); + + _doAfterSystem.TryStartDoAfter(new DoAfterArgs( + EntityManager, + args.User, + GetToggleDoAfter(attachable, args.Holder, args.User, ref popupText), + new AttachableToggleDoAfterEvent(args.SlotId, popupText), + attachable, + target: attachable.Owner, + used: args.Holder) + { + NeedHand = attachable.Comp.DoAfterNeedHand, + BreakOnMove = attachable.Comp.DoAfterBreakOnMove + }); + + Dirty(attachable); + } + + private bool CanStartToggleDoAfter(Entity attachable, ref AttachableToggleStartedEvent args, bool silent = false) + { + if (TryComp(attachable.Owner, out UseDelayComponent? useDelayComponent) && + _useDelaySystem.IsDelayed((attachable.Owner, useDelayComponent), attachableToggleUseDelayID)) + { + return false; + } + + _attachableHolderSystem.TryGetUser(attachable.Owner, out var userUid); + + if (attachable.Comp.HeldOnlyActivate && !attachable.Comp.Active && (userUid == null || !_handsSystem.IsHolding(userUid.Value, args.Holder, out _))) + { + if (!silent) + _popupSystem.PopupClient( + Loc.GetString("rmc-attachable-activation-fail-not-held", ("holder", args.Holder), ("attachable", attachable)), + args.User, + args.User); + return false; + } + + if (attachable.Comp.UserOnly && userUid != args.User) + { + if (!silent) + _popupSystem.PopupClient( + Loc.GetString("rmc-attachable-activation-fail-not-owned", ("holder", args.Holder), ("attachable", attachable)), + args.User, + args.User); + return false; + } + + if (!attachable.Comp.Active && attachable.Comp.WieldedOnly && (!TryComp(args.Holder, out WieldableComponent? wieldableComponent) || !wieldableComponent.Wielded)) + { + if (!silent) + _popupSystem.PopupClient( + Loc.GetString("rmc-attachable-activation-fail-not-wielded", ("holder", args.Holder), ("attachable", attachable)), + args.User, + args.User); + return false; + } + + return true; + } + + private TimeSpan GetToggleDoAfter(Entity attachable, EntityUid holderUid, EntityUid userUid, ref string popupText) + { + if (!TryComp(holderUid, out TransformComponent? transformComponent) || !transformComponent.ParentUid.Valid) + return TimeSpan.FromSeconds(0f); + + var extraDoAfter = transformComponent.ParentUid == userUid ? 0f : 0.5f; + + switch (attachable.Comp.InstantToggle) + { + case AttachableInstantToggleConditions.Brace: + if (attachable.Comp.Active || transformComponent.ParentUid != userUid || !TryComp(userUid, out TransformComponent? userTransform)) + break; + + TimeSpan? doAfter; + + var coords = userTransform.Coordinates; + + Func comparer = (EntityCoordinates userCoords, EntityCoordinates entCoords) => { return false; }; + var coordsShift = new Vector2(0f, 0f); + + Func, EntityUid?> GetBracingSurface = (HashSet ents) => + { + foreach (var entity in ents) + { + if (!TryComp(entity, out FixturesComponent? fixturesComponent)) + continue; + + foreach (var fixture in fixturesComponent.Fixtures.Values) + { + if ((fixture.CollisionLayer & bracingInvalidCollisionGroup) != 0 || (fixture.CollisionLayer & bracingRequiredCollisionGroup) == 0) + continue; + + if (!comparer(coords, Transform(entity).Coordinates)) + continue; + + return entity; + } + } + + return null; + }; + + switch (userTransform.LocalRotation.GetCardinalDir()) + { + case Direction.South: + comparer = (EntityCoordinates userCoords, EntityCoordinates entCoords) => { return entCoords.Y < userCoords.Y; }; + coordsShift = new Vector2(0f, -0.7f); + break; + + case Direction.North: + comparer = (EntityCoordinates userCoords, EntityCoordinates entCoords) => { return entCoords.Y > userCoords.Y; }; + coordsShift = new Vector2(0f, 0.7f); + break; + + case Direction.East: + comparer = (EntityCoordinates userCoords, EntityCoordinates entCoords) => { return entCoords.X > userCoords.X; }; + coordsShift = new Vector2(0.7f, 0f); + break; + + case Direction.West: + comparer = (EntityCoordinates userCoords, EntityCoordinates entCoords) => { return entCoords.X < userCoords.X; }; + coordsShift = new Vector2(-0.7f, 0f); + break; + + default: + break; + } + + var surface = GetBracingSurface(_entityLookupSystem.GetEntitiesInRange(coords, 0.5f, LookupFlags.Dynamic | LookupFlags.Static)); + if (surface != null) + { + popupText = Loc.GetString("attachable-popup-activate-deploy-on-generic", ("attachable", attachable.Owner), ("surface", surface)); + return TimeSpan.FromSeconds(0f); + } + + coords = new EntityCoordinates(coords.EntityId, coords.Position + coordsShift); + surface = GetBracingSurface(_entityLookupSystem.GetEntitiesInRange(coords, 0.5f, LookupFlags.Dynamic | LookupFlags.Static)); + if (surface != null) + { + popupText = Loc.GetString("attachable-popup-activate-deploy-on-generic", ("attachable", attachable.Owner), ("surface", surface)); + return TimeSpan.FromSeconds(0f); + } + + popupText = Loc.GetString("attachable-popup-activate-deploy-on-ground", ("attachable", attachable.Owner)); + break; + + default: + break; + } + + return TimeSpan.FromSeconds(Math.Max( + (attachable.Comp.DeactivateDoAfter != null && attachable.Comp.Active + ? attachable.Comp.DeactivateDoAfter.Value + : attachable.Comp.DoAfter + ) + extraDoAfter, + 0)); + } + + private void OnAttachableToggleDoAfter(Entity attachable, + ref AttachableToggleDoAfterEvent args) + { + if (args.Cancelled || args.Handled) + return; + + if (args.Target is not { } target || args.Used is not { } used) + return; + + if (!HasComp(target)) + return; + + if (!TryComp(args.Used, out AttachableHolderComponent? holderComponent)) + return; + + FinishToggle(attachable, (used, holderComponent), args.SlotId, args.User, args.PopupText); + args.Handled = true; + Dirty(attachable); + } + + private void FinishToggle( + Entity attachable, + Entity holder, + string slotId, + EntityUid? userUid, + string popupText, + bool interrupted = false) + { + attachable.Comp.Active = !attachable.Comp.Active; + + var mode = attachable.Comp.Active + ? AttachableAlteredType.Activated + : interrupted ? AttachableAlteredType.Interrupted : AttachableAlteredType.Deactivated; + var ev = new AttachableAlteredEvent(holder.Owner, mode, userUid); + RaiseLocalEvent(attachable.Owner, ref ev); + + var holderEv = new AttachableHolderAttachablesAlteredEvent(attachable.Owner, slotId, mode); + RaiseLocalEvent(holder.Owner, ref holderEv); + + _useDelaySystem.SetLength(attachable.Owner, attachable.Comp.UseDelay, attachableToggleUseDelayID); + _useDelaySystem.TryResetDelay(attachable.Owner, id: attachableToggleUseDelayID); + _actionsSystem.StartUseDelay(attachable.Comp.Action); + + if (attachable.Comp.ShowTogglePopup && userUid != null) + _popupSystem.PopupClient(popupText, userUid.Value, userUid.Value); + + _audioSystem.PlayPredicted( + attachable.Comp.Active ? attachable.Comp.ActivateSound : attachable.Comp.DeactivateSound, + attachable, + userUid); + + if (!attachable.Comp.Active) + { + if (attachable.Comp.SupercedeHolder && holder.Comp.SupercedingAttachable == attachable.Owner) + _attachableHolderSystem.SetSupercedingAttachable(holder, null); + return; + } + + if (attachable.Comp.BreakOnMove && userUid != null) + { + var movementLockedComponent = EnsureComp(userUid.Value); + movementLockedComponent.AttachableList.Add(attachable.Owner); + } + + if (attachable.Comp.BreakOnRotate && userUid != null) + { + var directionLockedComponent = EnsureComp(userUid.Value); + directionLockedComponent.AttachableList.Add(attachable.Owner); + + if (directionLockedComponent.LockedDirection == null) + directionLockedComponent.LockedDirection = Transform(userUid.Value).LocalRotation.GetCardinalDir(); + } + + if (attachable.Comp.BreakOnFullRotate && userUid != null) + { + var sideLockedComponent = EnsureComp(userUid.Value); + sideLockedComponent.AttachableList.Add(attachable.Owner); + + if (sideLockedComponent.LockedDirection == null) + sideLockedComponent.LockedDirection = Transform(userUid.Value).LocalRotation.GetCardinalDir(); + } + + if (!attachable.Comp.SupercedeHolder) + return; + + if (holder.Comp.SupercedingAttachable != null && + TryComp(holder.Comp.SupercedingAttachable, out AttachableToggleableComponent? toggleableComponent)) + { + toggleableComponent.Active = false; + ev = new AttachableAlteredEvent(holder.Owner, AttachableAlteredType.Deactivated); + RaiseLocalEvent(holder.Comp.SupercedingAttachable.Value, ref ev); + + if (_attachableHolderSystem.TryGetSlotId(holder.Owner, attachable.Owner, out var deactivatedSlot)) + { + holderEv = new AttachableHolderAttachablesAlteredEvent(holder.Comp.SupercedingAttachable.Value, + deactivatedSlot, + AttachableAlteredType.Deactivated); + RaiseLocalEvent(holder.Owner, ref holderEv); + } + } + + _attachableHolderSystem.SetSupercedingAttachable(holder, attachable.Owner); + } + + private void Toggle(Entity attachable, EntityUid? user, bool interrupted = false) + { + if (!_attachableHolderSystem.TryGetHolder(attachable.Owner, out var holderUid) || + !TryComp(holderUid, out AttachableHolderComponent? holderComponent) || + !_attachableHolderSystem.TryGetSlotId(holderUid.Value, attachable.Owner, out var slotId)) + { + return; + } + + FinishToggle( + attachable, + (holderUid.Value, holderComponent), + slotId, + user, + Loc.GetString(attachable.Comp.Active ? attachable.Comp.DeactivatePopupText : attachable.Comp.ActivatePopupText, ("attachable", attachable.Owner)), + interrupted); + Dirty(attachable); + } +#endregion + +#region Actions + private void OnGrantAttachableActions(Entity ent, ref GrantAttachableActionsEvent args) + { + GrantAttachableActions(ent, args.User); + RelayAttachableActions(ent, args.User); + } + + private void GrantAttachableActions(Entity ent, EntityUid user, bool doSecondTry = true) + { + // This is to prevent ActionContainerSystem from shitting itself if the attachment has actions other than its attachment toggle. + if (!TryComp(ent.Owner, out ActionsContainerComponent? actionsContainerComponent) || actionsContainerComponent.Container == null) + { + EnsureComp(ent.Owner); + + if (doSecondTry) + GrantAttachableActions(ent, user, false); + + return; + } + + var exists = ent.Comp.Action != null; + _actionContainerSystem.EnsureAction(ent, ref ent.Comp.Action, ent.Comp.ActionId, actionsContainerComponent); + + if (ent.Comp.Action is not { } actionId) + return; + + _actionsSystem.GrantContainedAction(user, ent.Owner, actionId); + + if (exists) + return; + + _metaDataSystem.SetEntityName(actionId, ent.Comp.ActionName); + _metaDataSystem.SetEntityDescription(actionId, ent.Comp.ActionDesc); + + if (_actionsSystem.TryGetActionData(actionId, out var action)) + { + action.Icon = ent.Comp.Icon; + action.IconOn = ent.Comp.IconActive; + action.Enabled = ent.Comp.Attached; + action.UseDelay = ent.Comp.UseDelay; + Dirty(actionId, action); + } + + Dirty(ent); + } + + private void RelayAttachableActions(Entity attachable, EntityUid user) + { + if (attachable.Comp.ActionsToRelayWhitelist == null || !TryComp(attachable.Owner, out ActionsContainerComponent? actionsContainerComponent)) + return; + + foreach (var actionUid in actionsContainerComponent.Container.ContainedEntities) + { + if (!_entityWhitelistSystem.IsWhitelistPass(attachable.Comp.ActionsToRelayWhitelist, actionUid)) + continue; + + _actionsSystem.GrantContainedAction(user, (attachable.Owner, actionsContainerComponent), actionUid); + } + } + + private void OnRemoveAttachableActions(Entity ent, ref RemoveAttachableActionsEvent args) + { + RemoveAttachableActions(ent, args.User); + RemoveRelayedActions(ent, args.User); + } + + private void RemoveAttachableActions(Entity ent, EntityUid user) + { + if (ent.Comp.Action is not { } action) + return; + + if (!TryComp(action, out InstantActionComponent? actionComponent) || actionComponent.AttachedEntity != user) + return; + + _actionsSystem.RemoveProvidedAction(user, ent, action); + } + + private void RemoveRelayedActions(Entity attachable, EntityUid user) + { + if (attachable.Comp.ActionsToRelayWhitelist == null || !TryComp(attachable.Owner, out ActionsContainerComponent? actionsContainerComponent)) + return; + + foreach (var actionUid in actionsContainerComponent.Container.ContainedEntities) + { + if (!_entityWhitelistSystem.IsWhitelistPass(attachable.Comp.ActionsToRelayWhitelist, actionUid)) + continue; + + _actionsSystem.RemoveProvidedAction(user, attachable.Owner, actionUid); + } + } + + private void OnAttachableToggleAction(Entity attachable, + ref AttachableToggleActionEvent args) + { + args.Handled = true; + + if (!attachable.Comp.Attached) + return; + + if (!_attachableHolderSystem.TryGetHolder(attachable.Owner, out var holderUid) || + !TryComp(holderUid, out AttachableHolderComponent? holderComponent) || + !_attachableHolderSystem.TryGetSlotId(holderUid.Value, attachable.Owner, out var slotId)) + { + return; + } + + var ev = new AttachableToggleStartedEvent(holderUid.Value, + args.Performer, + slotId); + RaiseLocalEvent(attachable.Owner, ref ev); + } + + private void OnToggleAction(Entity attachable, ref ToggleActionEvent args) + { + if (attachable.Comp.AttachedOnly && !attachable.Comp.Attached) + args.Handled = true; + } +#endregion +} diff --git a/Content.Shared/ADT/_RMC14/CCVar/RMCCVars.cs b/Content.Shared/ADT/_RMC14/CCVar/RMCCVars.cs new file mode 100644 index 00000000000..e81d261dca7 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/CCVar/RMCCVars.cs @@ -0,0 +1,243 @@ +using Robust.Shared; +using Robust.Shared.Configuration; + +namespace Content.Shared._RMC14.CCVar; + +[CVarDefs] +public sealed class RMCCVars : CVars +{ + public static readonly CVarDef CMXenoDamageDealtMultiplier = + CVarDef.Create("rmc.xeno_damage_dealt_multiplier", 1f, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef CMXenoDamageReceivedMultiplier = + CVarDef.Create("rmc.xeno_damage_received_multiplier", 1f, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef CMXenoSpeedMultiplier = + CVarDef.Create("rmc.xeno_speed_multiplier", 1f, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef CMPlayVoicelinesArachnid = + CVarDef.Create("rmc.play_voicelines_arachnid", true, CVar.REPLICATED | CVar.CLIENT | CVar.ARCHIVE); + + public static readonly CVarDef CMPlayVoicelinesDiona = + CVarDef.Create("rmc.play_voicelines_diona", true, CVar.REPLICATED | CVar.CLIENT | CVar.ARCHIVE); + + public static readonly CVarDef CMPlayVoicelinesDwarf = + CVarDef.Create("rmc.play_voicelines_dwarf", true, CVar.REPLICATED | CVar.CLIENT | CVar.ARCHIVE); + + public static readonly CVarDef CMPlayVoicelinesFelinid = + CVarDef.Create("rmc.play_voicelines_felinid", true, CVar.REPLICATED | CVar.CLIENT | CVar.ARCHIVE); + + public static readonly CVarDef CMPlayVoicelinesHuman = + CVarDef.Create("rmc.play_voicelines_human", true, CVar.REPLICATED | CVar.CLIENT | CVar.ARCHIVE); + + public static readonly CVarDef CMPlayVoicelinesMoth = + CVarDef.Create("rmc.play_voicelines_moth", true, CVar.REPLICATED | CVar.CLIENT | CVar.ARCHIVE); + + public static readonly CVarDef CMPlayVoicelinesReptilian = + CVarDef.Create("rmc.play_voicelines_reptilian", true, CVar.REPLICATED | CVar.CLIENT | CVar.ARCHIVE); + + public static readonly CVarDef CMPlayVoicelinesSlime = + CVarDef.Create("rmc.play_voicelines_slime", true, CVar.REPLICATED | CVar.CLIENT | CVar.ARCHIVE); + + public static readonly CVarDef CMOocWebhook = + CVarDef.Create("rmc.ooc_webhook", "", CVar.SERVERONLY | CVar.CONFIDENTIAL); + + public static readonly CVarDef CMMaxHeavyAttackTargets = + CVarDef.Create("rmc.max_heavy_attack_targets", 3, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef CMBloodlossMultiplier = + CVarDef.Create("rmc.bloodloss_multiplier", 1.5f, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef CMBleedTimeMultiplier = + CVarDef.Create("rmc.bleed_time_multiplier", 1f, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef CMMarinesPerXeno = + CVarDef.Create("rmc.marines_per_xeno", 6f, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCPatronLobbyMessageTimeSeconds = + CVarDef.Create("rmc.patron_lobby_message_time_seconds", 30, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCPatronLobbyMessageInitialDelaySeconds = + CVarDef.Create("rmc.patron_lobby_message_initial_delay_seconds", 5, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCDiscordAccountLinkingMessageLink = + CVarDef.Create("rmc.discord_account_linking_message_link", "", CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCRequisitionsStartingBalance = + CVarDef.Create("rmc.requisitions_starting_balance", 0, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCRequisitionsBalanceGain = + CVarDef.Create("rmc.requisitions_balance_gain", 750, CVar.REPLICATED | CVar.SERVER); + + // TODO RMC14 400 + public static readonly CVarDef RMCRequisitionsStartingDollarsPerMarine = + CVarDef.Create("rmc.requisitions_starting_dollars_per_marine", 1750, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCDiscordToken = + CVarDef.Create("rmc.discord_token", "", CVar.SERVER | CVar.SERVERONLY | CVar.CONFIDENTIAL); + + public static readonly CVarDef RMCDiscordAdminChatChannel = + CVarDef.Create("rmc.discord_admin_chat_channel", 0UL, CVar.SERVER | CVar.SERVERONLY | CVar.CONFIDENTIAL); + + /// + /// Comma-separated list of maps to load as the planet in the distress signal gamemode. + /// + public static readonly CVarDef RMCPlanetMaps = + CVarDef.Create("rmc.planet_maps", "/Maps/_RMC14/lv624.yml,/Maps/_RMC14/solaris.yml,/Maps/_RMC14/prison.yml,/Maps/_RMC14/shiva.yml,/Maps/_RMC14/trijent.yml,/Maps/_RMC14/varadero.yml", CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCPlanetCoordinateVariance = + CVarDef.Create("rmc.planet_coordinate_variance", 500, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCDrawStorageIconLabels = + CVarDef.Create("rmc.draw_storage_icon_labels", true, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCFTLCrashLand = + CVarDef.Create("rmc.ftl_crash_land", true, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCDropshipInitialDelayMinutes = + CVarDef.Create("rmc.dropship_initial_delay_minutes", 15f, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCLandingZonePrimaryAutoMinutes = + CVarDef.Create("rmc.landing_zone_primary_auto_minutes", 25f, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCCorrosiveAcidTickDelaySeconds = + CVarDef.Create("rmc.corrosive_acid_tick_delay_seconds", 10, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCCorrosiveAcidDamageType = + CVarDef.Create("rmc.corrosive_acid_damage_type", "Heat", CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCCorrosiveAcidDamageTimeSeconds = + CVarDef.Create("rmc.corrosive_acid_damage_time_seconds", 45, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCTailStabMaxTargets = + CVarDef.Create("rmc.tail_stab_max_targets", 1, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCEvolutionPointsRequireOvipositorMinutes = + CVarDef.Create("rmc.evolution_points_require_ovipositor_minutes", 5, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCEvolutionPointsAccumulateBeforeMinutes = + CVarDef.Create("rmc.evolution_points_accumulate_before_minutes", 15, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCAtmosTileEqualize = + CVarDef.Create("rmc.atmos_tile_equalize", false, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCGasTileOverlayUpdate = + CVarDef.Create("rmc.gas_tile_overlay_update", false, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCActiveInputMoverEnabled = + CVarDef.Create("rmc.active_input_mover_enabled", true, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCAdminFaxAreaMap = + CVarDef.Create("rmc.admin_fax_area_map", "Maps/_RMC14/admin_fax.yml", CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCBioscanInitialDelaySeconds = + CVarDef.Create("rmc.bioscan_initial_delay_seconds", 300, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCBioscanCheckDelaySeconds = + CVarDef.Create("rmc.bioscan_check_delay_seconds", 60, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCBioscanMinimumCooldownSeconds = + CVarDef.Create("rmc.bioscan_minimum_cooldown_seconds", 300, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCBioscanBaseCooldownSeconds = + CVarDef.Create("rmc.bioscan_base_cooldown_seconds", 1800, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCBioscanVariance = + CVarDef.Create("rmc.bioscan_variance", 2, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCDropshipFabricatorStartingPoints = + CVarDef.Create("rmc.dropship_fabricator_starting_points", 20000, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCDropshipFabricatorGainEverySeconds = + CVarDef.Create("rmc.dropship_fabricator_gain_every_seconds", 3.33333f, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCDropshipCASDebug = + CVarDef.Create("rmc.dropship_cas_debug", false, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCDropshipFlyByTimeSeconds = + CVarDef.Create("rmc.dropship_fly_by_time_seconds", 100, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCDropshipHijackTravelTimeSeconds = + CVarDef.Create("rmc.dropship_hijack_travel_time_seconds", 180, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCEntitiesLogDelete = + CVarDef.Create("rmc.entities_log_delete", false, CVar.SERVER | CVar.SERVERONLY); + + public static readonly CVarDef RMCPlanetMapVote = + CVarDef.Create("rmc.planet_map_vote", true, CVar.SERVER | CVar.SERVERONLY); + + public static readonly CVarDef RMCPlanetMapVoteExcludeLast = + CVarDef.Create("rmc.planet_map_vote_exclude_last", 2, CVar.SERVER | CVar.SERVERONLY); + + public static readonly CVarDef RMCTacticalMapAnnounceCooldownSeconds = + CVarDef.Create("rmc.tactical_map_announce_cooldown_seconds", 240, CVar.SERVER | CVar.SERVERONLY); + + public static readonly CVarDef RMCTacticalMapLineLimit = + CVarDef.Create("rmc.tactical_map_line_limit", 1000, CVar.SERVER | CVar.REPLICATED); + + public static readonly CVarDef RMCTacticalMapAdminHistorySize = + CVarDef.Create("rmc.tactical_map_admin_history_size", 100, CVar.SERVER | CVar.REPLICATED); + + public static readonly CVarDef RMCTacticalMapUpdateEverySeconds = + CVarDef.Create("rmc.tactical_map_update_every_seconds", 1f, CVar.SERVER | CVar.REPLICATED); + + public static readonly CVarDef RMCGunPrediction = + CVarDef.Create("rmc.gun_prediction", true, CVar.SERVER | CVar.REPLICATED); + + public static readonly CVarDef RMCGunPredictionPreventCollision = + CVarDef.Create("rmc.gun_prediction_prevent_collision", false, CVar.SERVER | CVar.REPLICATED); + + public static readonly CVarDef RMCGunPredictionLogHits = + CVarDef.Create("rmc.gun_prediction_log_hits", false, CVar.SERVER | CVar.REPLICATED); + + public static readonly CVarDef RMCGunPredictionCoordinateDeviation = + CVarDef.Create("rmc.gun_prediction_coordinate_deviation", 1f, CVar.SERVER | CVar.REPLICATED); + + public static readonly CVarDef RMCGunPredictionLowestCoordinateDeviation = + CVarDef.Create("rmc.gun_prediction_lowest_coordinate_deviation", 1f, CVar.SERVER | CVar.REPLICATED); + + public static readonly CVarDef RMCGunPredictionAabbEnlargement = + CVarDef.Create("rmc.gun_prediction_aabb_enlargement", 0.3f, CVar.SERVER | CVar.REPLICATED); + + public static readonly CVarDef RMCJobSlotScaling = + CVarDef.Create("rmc.job_slot_scaling", true, CVar.SERVER | CVar.REPLICATED); + + public static readonly CVarDef RMCEmoteCooldownSeconds = + CVarDef.Create("rmc.emote_cooldown_seconds", 20f, CVar.SERVER | CVar.REPLICATED); + + public static readonly CVarDef RMCPowerUpdateEverySeconds = + CVarDef.Create("rmc.power_update_every_seconds", 1f, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCPowerLoadMultiplier = + CVarDef.Create("rmc.power_load_multiplier", 0.01f, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCMarinesPerSurvivor = + CVarDef.Create("rmc.marines_per_survivor", 20, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCSurvivorsMinimum = + CVarDef.Create("rmc.survivors_minimum", 2, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCSurvivorsMaximum = + CVarDef.Create("rmc.survivors_maximum", 6, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCSpawnerMaxCorpses = + CVarDef.Create("rmc.spawner_max_corpses", 25, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCHiveSpreadEarlyMinutes = + CVarDef.Create("rmc.hive_spread_early_minutes", 40, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCNewPlayerTimeTotalHours = + CVarDef.Create("rmc.new_player_time_total_hours", 25, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCNewPlayerTimeJobHours = + CVarDef.Create("rmc.new_player_time_job_hours", 10, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCLateJoinsPerBurrowedLarvaEarlyThresholdMinutes = + CVarDef.Create("rmc.late_joins_per_burrowed_larva_early_threshold_minutes", 15f, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCLateJoinsPerBurrowedLarvaEarly = + CVarDef.Create("rmc.late_joins_per_burrowed_larva_early", 5.5f, CVar.REPLICATED | CVar.SERVER); + + public static readonly CVarDef RMCLateJoinsPerBurrowedLarva = + CVarDef.Create("rmc.late_joins_per_burrowed_larva", 4f, CVar.REPLICATED | CVar.SERVER); +} diff --git a/Content.Shared/ADT/_RMC14/Input/ActiveInputMoverComponent.cs b/Content.Shared/ADT/_RMC14/Input/ActiveInputMoverComponent.cs new file mode 100644 index 00000000000..0c98fa7b5e8 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Input/ActiveInputMoverComponent.cs @@ -0,0 +1,7 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Input; + +[RegisterComponent, NetworkedComponent] +[Access(typeof(RMCInputSystem))] +public sealed partial class ActiveInputMoverComponent : Component; diff --git a/Content.Shared/ADT/_RMC14/Input/CMKeyFunctions.cs b/Content.Shared/ADT/_RMC14/Input/CMKeyFunctions.cs new file mode 100644 index 00000000000..cf25188c598 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Input/CMKeyFunctions.cs @@ -0,0 +1,19 @@ +using Robust.Shared.Input; + +namespace Content.Shared._RMC14.Input; + +[KeyFunctions] +public sealed class CMKeyFunctions +{ + public static readonly BoundKeyFunction RMCActivateAttachableBarrel = "RMCActivateAttachableBarrel"; + public static readonly BoundKeyFunction RMCActivateAttachableRail = "RMCActivateAttachableRail"; + public static readonly BoundKeyFunction RMCActivateAttachableStock = "RMCActivateAttachableStock"; + public static readonly BoundKeyFunction RMCActivateAttachableUnderbarrel = "RMCActivateAttachableUnderbarrel"; + public static readonly BoundKeyFunction RMCFieldStripHeldItem = "RMCFieldStripHeldItem"; + public static readonly BoundKeyFunction RMCCycleFireMode = "RMCCycleFireMode"; + public static readonly BoundKeyFunction CMUniqueAction = "CMUniqueAction"; + public static readonly BoundKeyFunction CMHolsterPrimary = "CMHolsterPrimary"; + public static readonly BoundKeyFunction CMHolsterSecondary = "CMHolsterSecondary"; + public static readonly BoundKeyFunction CMHolsterTertiary = "CMHolsterTertiary"; + public static readonly BoundKeyFunction CMHolsterQuaternary = "CMHolsterQuaternary"; +} diff --git a/Content.Shared/ADT/_RMC14/Input/RMCInputSystem.cs b/Content.Shared/ADT/_RMC14/Input/RMCInputSystem.cs new file mode 100644 index 00000000000..c1da449df21 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Input/RMCInputSystem.cs @@ -0,0 +1,53 @@ +using Content.Shared._RMC14.CCVar; +using Content.Shared.Movement.Components; +using Robust.Shared.Configuration; +using Robust.Shared.Player; + +namespace Content.Shared._RMC14.Input; + +public sealed class RMCInputSystem : EntitySystem +{ + [Dependency] private readonly IConfigurationManager _config = default!; + + private bool _activeInputMoverEnabled; + + private EntityQuery _actorQuery; + + public override void Initialize() + { + _actorQuery = GetEntityQuery(); + + SubscribeLocalEvent(OnActiveMapInit); + SubscribeLocalEvent(OnActiveAttached); + SubscribeLocalEvent(OnActiveDetached); + + Subs.CVar(_config, RMCCVars.RMCActiveInputMoverEnabled, v => _activeInputMoverEnabled = v, true); + } + + private void OnActiveMapInit(Entity ent, ref MapInitEvent args) + { + if (!_activeInputMoverEnabled) + return; + + if (_actorQuery.HasComp(ent)) + EnsureComp(ent); + else + RemCompDeferred(ent); + } + + private void OnActiveAttached(Entity ent, ref PlayerAttachedEvent args) + { + if (!_activeInputMoverEnabled) + return; + + EnsureComp(ent); + } + + private void OnActiveDetached(Entity ent, ref PlayerDetachedEvent args) + { + if (!_activeInputMoverEnabled) + return; + + RemCompDeferred(ent); + } +} diff --git a/Content.Shared/ADT/_RMC14/Inventory/CMHolsterChoose.cs b/Content.Shared/ADT/_RMC14/Inventory/CMHolsterChoose.cs new file mode 100644 index 00000000000..47a75483dac --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Inventory/CMHolsterChoose.cs @@ -0,0 +1,10 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared._RMC14.Inventory; + +[Serializable, NetSerializable] +public enum CMHolsterChoose +{ + First, + Last +} diff --git a/Content.Shared/ADT/_RMC14/Inventory/CMHolsterComponent.cs b/Content.Shared/ADT/_RMC14/Inventory/CMHolsterComponent.cs new file mode 100644 index 00000000000..19bf140620b --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Inventory/CMHolsterComponent.cs @@ -0,0 +1,47 @@ +using Robust.Shared.Audio; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; +using Content.Shared.Whitelist; + +namespace Content.Shared._RMC14.Inventory; + +// TODO RMC14 add to rifle holster +// TODO RMC14 add to machete scabbard pouch +// TODO RMC14 add to all large scabbards (machete scabbard, katana scabbard, m63 holster rig) +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true), AutoGenerateComponentPause] +[Access(typeof(SharedCMInventorySystem))] +public sealed partial class CMHolsterComponent : Component +{ + // List of entities "inside" the holster + [DataField] + public List Contents = new(); + + // Whitelist for entities that can be (un)holstered + // Note: this does not block them from being inserted (use other whitelists for that), + // this is here to prevent "unholstering" non-weapons (e.g. tools from the combat toolbelt) + [DataField] + public EntityWhitelist? Whitelist; + + // Variables to mitigate holster spamming + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField, AutoPausedField] + public TimeSpan LastEjectAt; + + [DataField, AutoNetworkedField] + public TimeSpan? Cooldown; + + [DataField, AutoNetworkedField] + public string? CooldownPopup; + + /// + /// Sound played whenever an entity is inserted into holster. + /// + [DataField] + public SoundSpecifier? InsertSound = new SoundPathSpecifier("/Audio/_RMC14/Weapons/Guns/gun_pistol_sheathe.ogg"); + + /// + /// Sound played whenever an entity is removed from holster. + /// + [DataField] + public SoundSpecifier? EjectSound = new SoundPathSpecifier("/Audio/_RMC14/Weapons/Guns/gun_pistol_draw.ogg"); +} diff --git a/Content.Shared/ADT/_RMC14/Inventory/CMHolsterLayers.cs b/Content.Shared/ADT/_RMC14/Inventory/CMHolsterLayers.cs new file mode 100644 index 00000000000..b1129ce9361 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Inventory/CMHolsterLayers.cs @@ -0,0 +1,9 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared._RMC14.Inventory; + +[Serializable, NetSerializable] +public enum CMHolsterLayers +{ + Fill, // For displaying the weapon underlay +} diff --git a/Content.Shared/ADT/_RMC14/Inventory/CMHolsterVisuals.cs b/Content.Shared/ADT/_RMC14/Inventory/CMHolsterVisuals.cs new file mode 100644 index 00000000000..fc9b37dd906 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Inventory/CMHolsterVisuals.cs @@ -0,0 +1,10 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared._RMC14.Inventory; + +[Serializable, NetSerializable] +public enum CMHolsterVisuals +{ + Empty, // TODO: account for the gunslinger belt + Full, +} diff --git a/Content.Shared/ADT/_RMC14/Inventory/CMInventoryExtensions.cs b/Content.Shared/ADT/_RMC14/Inventory/CMInventoryExtensions.cs new file mode 100644 index 00000000000..977ac2ad16e --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Inventory/CMInventoryExtensions.cs @@ -0,0 +1,39 @@ +using Content.Shared.Item; +using Content.Shared.Storage; +using Content.Shared.Storage.EntitySystems; + +namespace Content.Shared._RMC14.Inventory; + +public static class CMInventoryExtensions +{ + public static bool TryGetFirst(EntityUid storageId, EntityUid itemId, out ItemStorageLocation location) + { + location = default; + + var entities = IoCManager.Resolve(); + var storageSystem = entities.System(); + + if (!entities.TryGetComponent(storageId, out StorageComponent? storage) || + !entities.TryGetComponent(itemId, out ItemComponent? item)) + { + return false; + } + + var storageBounding = storage.Grid.GetBoundingBox(); + + for (var y = storageBounding.Bottom; y <= storageBounding.Top; y++) + { + for (var x = storageBounding.Left; x <= storageBounding.Right; x++) + { + location = new ItemStorageLocation(0, (x, y)); + if (storageSystem.ItemFitsInGridLocation(itemId, storageId, location)) + { + return true; + } + } + } + + location = default; + return false; + } +} diff --git a/Content.Shared/ADT/_RMC14/Inventory/CMItemSlotsComponent.cs b/Content.Shared/ADT/_RMC14/Inventory/CMItemSlotsComponent.cs new file mode 100644 index 00000000000..aad4ad69387 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Inventory/CMItemSlotsComponent.cs @@ -0,0 +1,29 @@ +using Content.Shared.Containers.ItemSlots; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; + +namespace Content.Shared._RMC14.Inventory; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true), AutoGenerateComponentPause] +[Access(typeof(SharedCMInventorySystem))] +public sealed partial class CMItemSlotsComponent : Component +{ + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField, AutoPausedField] + public TimeSpan LastEjectAt; + + [DataField, AutoNetworkedField] + public TimeSpan? Cooldown; + + [DataField, AutoNetworkedField] + public string? CooldownPopup; + + [DataField, AutoNetworkedField] + public int? Count; + + [DataField, AutoNetworkedField] + public ItemSlot? Slot; + + [DataField, AutoNetworkedField] + public EntProtoId? StartingItem; +} diff --git a/Content.Shared/ADT/_RMC14/Inventory/CMItemSlotsLayers.cs b/Content.Shared/ADT/_RMC14/Inventory/CMItemSlotsLayers.cs new file mode 100644 index 00000000000..606faaea066 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Inventory/CMItemSlotsLayers.cs @@ -0,0 +1,9 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared._RMC14.Inventory; + +[Serializable, NetSerializable] +public enum CMItemSlotsLayers +{ + Fill, +} diff --git a/Content.Shared/ADT/_RMC14/Inventory/CMItemSlotsVisuals.cs b/Content.Shared/ADT/_RMC14/Inventory/CMItemSlotsVisuals.cs new file mode 100644 index 00000000000..fd4568312ad --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Inventory/CMItemSlotsVisuals.cs @@ -0,0 +1,13 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared._RMC14.Inventory; + +[Serializable, NetSerializable] +public enum CMItemSlotsVisuals +{ + Empty, + Low, + Medium, + High, + Full, +} diff --git a/Content.Shared/ADT/_RMC14/Inventory/CMVirtualItemComponent.cs b/Content.Shared/ADT/_RMC14/Inventory/CMVirtualItemComponent.cs new file mode 100644 index 00000000000..f0f1ef6d22a --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Inventory/CMVirtualItemComponent.cs @@ -0,0 +1,7 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Inventory; + +[RegisterComponent, NetworkedComponent] +[Access(typeof(SharedCMInventorySystem))] +public sealed partial class CMVirtualItemComponent : Component; diff --git a/Content.Shared/ADT/_RMC14/Inventory/IsUnholsterableEvent.cs b/Content.Shared/ADT/_RMC14/Inventory/IsUnholsterableEvent.cs new file mode 100644 index 00000000000..51956c76452 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Inventory/IsUnholsterableEvent.cs @@ -0,0 +1,4 @@ +namespace Content.Shared._RMC14.Inventory; + +[ByRefEvent] +public record struct IsUnholsterableEvent(bool Unholsterable); diff --git a/Content.Shared/ADT/_RMC14/Inventory/RMCDroppedEvent.cs b/Content.Shared/ADT/_RMC14/Inventory/RMCDroppedEvent.cs new file mode 100644 index 00000000000..08c1cbaec67 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Inventory/RMCDroppedEvent.cs @@ -0,0 +1,4 @@ +namespace Content.Shared._RMC14.Inventory; + +[ByRefEvent] +public readonly record struct RMCDroppedEvent(EntityUid User); diff --git a/Content.Shared/ADT/_RMC14/Inventory/SharedCMInventorySystem.cs b/Content.Shared/ADT/_RMC14/Inventory/SharedCMInventorySystem.cs new file mode 100644 index 00000000000..bd9720a644b --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Inventory/SharedCMInventorySystem.cs @@ -0,0 +1,661 @@ +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Content.Shared._RMC14.Input; +using Content.Shared.Administration.Logs; +using Content.Shared.Clothing.Components; +using Content.Shared.Containers.ItemSlots; +using Content.Shared.Database; +using Content.Shared.Hands.Components; +using Content.Shared.Hands.EntitySystems; +using Content.Shared.Interaction; +using Content.Shared.Inventory; +using Content.Shared.Item; +using Content.Shared.Popups; +using Content.Shared.Storage; +using Content.Shared.Storage.EntitySystems; +using Content.Shared.Verbs; +using Content.Shared.Weapons.Melee; +using Content.Shared.Weapons.Ranged.Components; +using Content.Shared.Whitelist; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Containers; +using Robust.Shared.Input.Binding; +using Robust.Shared.Timing; +using Robust.Shared.Utility; + +namespace Content.Shared._RMC14.Inventory; + +public abstract class SharedCMInventorySystem : EntitySystem +{ + [Dependency] private readonly ISharedAdminLogManager _adminLog = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedContainerSystem _container = default!; + [Dependency] private readonly SharedHandsSystem _hands = default!; + [Dependency] private readonly InventorySystem _inventory = default!; + [Dependency] private readonly ItemSlotsSystem _itemSlots = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly SharedStorageSystem _storage = default!; + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelist = default!; + [Dependency] private readonly SharedItemSystem _item = default!; + + private readonly SlotFlags[] _order = + [ + SlotFlags.SUITSTORAGE, SlotFlags.BELT, SlotFlags.BACK, + SlotFlags.POCKET, SlotFlags.INNERCLOTHING, SlotFlags.FEET + ]; + + private readonly SlotFlags[] _quickEquipOrder = + [ + SlotFlags.BACK, + SlotFlags.IDCARD, + SlotFlags.INNERCLOTHING, + SlotFlags.OUTERCLOTHING, + SlotFlags.HEAD, + SlotFlags.FEET, + SlotFlags.MASK, + SlotFlags.GLOVES, + SlotFlags.EARS, + SlotFlags.EYES, + SlotFlags.BELT, + SlotFlags.SUITSTORAGE, + SlotFlags.NECK, + SlotFlags.POCKET, + SlotFlags.LEGS + ]; + + public override void Initialize() + { + SubscribeLocalEvent(AllowUnholster); + SubscribeLocalEvent(AllowUnholster); + + SubscribeLocalEvent(OnSlotsFillMapInit); + SubscribeLocalEvent(OnSlotsComponentHandleState); + SubscribeLocalEvent(OnSlotsActivateInWorld); + SubscribeLocalEvent(OnSlotsEjectAttempt); + SubscribeLocalEvent(OnSlotsEntInsertedIntoContainer); + SubscribeLocalEvent(OnSlotsEntRemovedFromContainer); + + SubscribeLocalEvent>(OnHolsterGetAltVerbs); + SubscribeLocalEvent(OnHolsterComponentHandleState); + SubscribeLocalEvent(OnHolsterEntInsertedIntoContainer); + SubscribeLocalEvent(OnHolsterEntRemovedFromContainer); + + CommandBinds.Builder + .Bind(CMKeyFunctions.CMHolsterPrimary, + InputCmdHandler.FromDelegate(session => + { + if (session?.AttachedEntity is { } entity) + OnHolster(entity, 0); + }, handle: false)) + .Bind(CMKeyFunctions.CMHolsterSecondary, + InputCmdHandler.FromDelegate(session => + { + if (session?.AttachedEntity is { } entity) + OnHolster(entity, 1); + }, handle: false)) + .Bind(CMKeyFunctions.CMHolsterTertiary, + InputCmdHandler.FromDelegate(session => + { + if (session?.AttachedEntity is { } entity) + OnHolster(entity, 2); + }, handle: false)) + .Bind(CMKeyFunctions.CMHolsterQuaternary, + InputCmdHandler.FromDelegate(session => + { + if (session?.AttachedEntity is { } entity) + OnHolster(entity, 3, CMHolsterChoose.Last); + }, handle: false)) + .Register(); + } + + private void OnHolsterGetAltVerbs(EntityUid holster, CMHolsterComponent comp, GetVerbsEvent args) + { + if (!args.CanAccess || !args.CanInteract) + return; + + if (comp.Contents.Count == 0) + return; + + // CMItemSlots-based holsters have their own eject verb, no need to add a duplicate + if (HasComp(holster)) + return; + + AlternativeVerb holsterVerb = new() + { + Act = () => Unholster(args.User, holster, out _), + Text = Loc.GetString("rmc-storage-holster-eject-verb"), + IconEntity = GetNetEntity(comp.Contents[0]), + Priority = 5 // Higher priority to appear above folding verbs (for webbing-based holsters) + }; + args.Verbs.Add(holsterVerb); + } + + public override void Shutdown() + { + base.Shutdown(); + CommandBinds.Unregister(); + } + + private void AllowUnholster(Entity ent, ref IsUnholsterableEvent args) where T : IComponent? + { + args.Unholsterable = true; + } + + private void OnSlotsFillMapInit(Entity ent, ref MapInitEvent args) + { + if (ent.Comp.Slot is not { } slot || ent.Comp.Count is not { } count) + return; + + var itemId = ent.Comp.StartingItem; + var slots = EnsureComp(ent); + var coordinates = Transform(ent).Coordinates; + for (var i = 0; i < count; i++) + { + var n = i + 1; + var copy = new ItemSlot(slot); + copy.Name = $"{copy.Name} {n}"; + + _itemSlots.AddItemSlot(ent, $"{slot.Name}{n}", copy); + + if (itemId != null) + { + if (copy.ContainerSlot is { } containerSlot) + { + var item = Spawn(itemId, coordinates); + _container.Insert(item, containerSlot); + } + else + { + copy.StartingItem = itemId; + } + } + } + + ContentsUpdated(ent); + Dirty(ent, slots); + } + + private void OnSlotsComponentHandleState(Entity ent, ref AfterAutoHandleStateEvent args) + { + ContentsUpdated(ent); + } + + private void OnHolsterComponentHandleState(Entity ent, ref AfterAutoHandleStateEvent args) + { + ContentsUpdated(ent); + } + + private void OnSlotsActivateInWorld(Entity ent, ref ActivateInWorldEvent args) + { + // If holster belongs to storage item, open it instead of unholstering + if (HasComp(ent)) + return; + + PickupSlot(args.User, ent); + } + + private void OnSlotsEjectAttempt(Entity ent, ref ItemSlotEjectAttemptEvent args) + { + if (args.Cancelled) + return; + + if (ent.Comp.Cooldown is { } cooldown && + _timing.CurTime < ent.Comp.LastEjectAt + cooldown) + { + args.Cancelled = true; + } + } + + protected void OnSlotsEntInsertedIntoContainer(Entity ent, ref EntInsertedIntoContainerMessage args) + { + ContentsUpdated(ent); + } + + protected void OnSlotsEntRemovedFromContainer(Entity ent, ref EntRemovedFromContainerMessage args) + { + if (!_timing.ApplyingState) + { + ent.Comp.LastEjectAt = _timing.CurTime; + Dirty(ent); + } + + ContentsUpdated(ent); + } + + protected void OnHolsterEntInsertedIntoContainer(Entity ent, ref EntInsertedIntoContainerMessage args) + { + var item = args.Entity; + var ev = new IsUnholsterableEvent(); + RaiseLocalEvent(item, ref ev); + + if (ev.Unholsterable && // Check if unholsterable + !ent.Comp.Contents.Contains(item) && // Here to prevent holster from counting one item twice + (ent.Comp.Whitelist is not { } whitelist || // Check if no whitelist + _whitelist.IsWhitelistPass(whitelist, item))) // or if item matches whitelist + ent.Comp.Contents.Add(item); + + ContentsUpdated(ent); + } + + protected void OnHolsterEntRemovedFromContainer(Entity ent, ref EntRemovedFromContainerMessage args) + { + if (!_timing.ApplyingState) + { + ent.Comp.LastEjectAt = _timing.CurTime; + Dirty(ent); + } + + var item = args.Entity; + ent.Comp.Contents.Remove(item); + + ContentsUpdated(ent); + } + + protected virtual void ContentsUpdated(Entity ent) + { + var (filled, total) = GetItemSlotsFilled(ent.Owner); + CMItemSlotsVisuals visuals; + if (total == 0) + visuals = CMItemSlotsVisuals.Empty; + else if (filled >= total) + visuals = CMItemSlotsVisuals.Full; + else if (filled >= total * 0.666f) + visuals = CMItemSlotsVisuals.High; + else if (filled >= total * 0.333f) + visuals = CMItemSlotsVisuals.Medium; + else if (filled > 0) + visuals = CMItemSlotsVisuals.Low; + else + visuals = CMItemSlotsVisuals.Empty; + + _appearance.SetData(ent, CMItemSlotsLayers.Fill, visuals); + } + + protected virtual void ContentsUpdated(Entity ent) + { + CMHolsterVisuals visuals = CMHolsterVisuals.Empty; + var size = 0; + + // TODO: account for the gunslinger belt + if (ent.Comp.Contents.Count != 0) + { + // Display weapon underlay + visuals = CMHolsterVisuals.Full; + // Get weapons size to accurately display storage visuals + foreach (var item in ent.Comp.Contents) + { + if (TryComp(item, out ItemComponent? itemComp)) + size += _item.GetItemShape(itemComp).GetArea(); + } + } + + _appearance.SetData(ent, CMHolsterLayers.Fill, visuals); + } + + private bool SlotCanInteract(EntityUid user, EntityUid holster, [NotNullWhen(true)] out ItemSlotsComponent? itemSlots) + { + if (!TryComp(holster, out itemSlots)) + return false; + + // no quick unholstering other's holsters + if (_container.TryGetContainingContainer((holster, null), out var container) && + container.Owner != user && + _inventory.HasSlot(container.Owner, container.ID)) + { + itemSlots = default; + return false; + } + + return true; + } + + private bool PickupSlot(EntityUid user, EntityUid holster) + { + if (!SlotCanInteract(user, holster, out var itemSlots)) + return false; + + foreach (var slot in itemSlots.Slots.Values.OrderBy(s => s.Priority)) + { + var item = slot.ContainerSlot?.ContainedEntity; + if (_itemSlots.TryEjectToHands(holster, slot, user, true)) + { + if (item != null) + //_adminLog.Add(LogType.RMCHolster, $"{ToPrettyString(user)} unholstered {ToPrettyString(item)}"); + + return true; + } + } + + return false; + } + + private void OnHolster(EntityUid user, int startIndex, CMHolsterChoose choose = CMHolsterChoose.First) + { + if (_hands.TryGetActiveItem(user, out var active)) + { + Holster(user, active.Value); + return; + } + + Unholster(user, startIndex, choose); + } + + private void Holster(EntityUid user, EntityUid item) + { + // TODO RMC14 try uniform-attached weapon and ammo holsters first + var validSlots = new List(); + + var priority = 0; + foreach (var flag in _quickEquipOrder) + { + var slots = _inventory.GetSlotEnumerator(user, flag); + while (slots.MoveNext(out var slot)) + { + if (slot.ContainedEntity is not { } clothing) + { + // If slot is empty and can equip + if (_inventory.CanEquip(user, item, slot.ID, out _)) + { + validSlots.Add(new HolsterSlot(priority, false, slot, user, null)); + } + + continue; + } + + // Check if the slot item has a CMHolsterComponent + if (!TryComp(clothing, out CMHolsterComponent? holster)) + continue; + + // Check if item matches holster whitelist (if it has one) + // This is to prevent e.g. tools from being "holstered" + if (holster.Whitelist is { } whitelist && + !_whitelist.IsWhitelistPass(whitelist, item)) + continue; + + // If holster has ItemSlotsComponent + // Check if can be inserted into item slot + if (HasComp(clothing) && + SlotCanInteract(user, clothing, out var slotComp) && + TryGetAvailableSlot((clothing, slotComp), + item, + user, + out var itemSlot, + emptyOnly: true) && + itemSlot.ContainerSlot != null) + { + validSlots.Add(new HolsterSlot(priority, true, null, clothing, ItemSlot: itemSlot)); + continue; + } + + // If holster has StorageComponent + // And item can be inserted + if (HasComp(clothing) && + _storage.CanInsert(clothing, item, out _)) + { + validSlots.Add(new HolsterSlot(priority, true, null, clothing, null)); + } + } + priority++; + } + + validSlots.Sort(); + + foreach (var slot in validSlots) + { + // Try equip to inventory slot + if (!slot.IsHolster && + slot.Slot != null && + _inventory.TryEquip(user, item, slot.Slot.ID, true, checkDoafter: true)) + return; + + // Try insert into ItemSlot-based holster + if (slot.ItemSlot != null && + _itemSlots.TryInsert(slot.Ent, slot.ItemSlot, item, user, excludeUserAudio: true)) + { + //_adminLog.Add(LogType.RMCHolster, $"{ToPrettyString(user)} holstered {ToPrettyString(item)}"); + return; + } + + // Try insert into Storage-based holster + if (slot.ItemSlot == null && + TryComp(slot.Ent, out StorageComponent? storage) && + TryComp(slot.Ent, out CMHolsterComponent? holster) && + !holster.Contents.Contains(item)) + { + holster.Contents.Add(item); + _hands.TryDrop(user, item); + _storage.Insert(slot.Ent, item, out _, user, storage, playSound: false); + _audio.PlayPredicted(holster.InsertSound, item, user); + //_adminLog.Add(LogType.RMCHolster, $"{ToPrettyString(user)} holstered {ToPrettyString(item)}"); + return; + } + } + + _popup.PopupClient(Loc.GetString("cm-inventory-unable-equip"), user, user, PopupType.SmallCaution); + } + + private readonly record struct HolsterSlot( + int Priority, + bool IsHolster, + ContainerSlot? Slot, + EntityUid Ent, + ItemSlot? ItemSlot) : IComparable + { + public int CompareTo(HolsterSlot other) + { + // Sort holsters first + // Then sort by priority between each holster and non-holster + + // If holster and holster + // Sort by priority higher first + if (IsHolster && other.IsHolster) + return Priority.CompareTo(other.Priority); + + // If only first is holster, then sort it higher + if (IsHolster) + return -1; + return 1; + } + } + + /// + /// Tries to get any slot that the can be inserted into. + /// + /// Entity that is being inserted into. + /// Entity being inserted into . + /// Entity inserting into . + /// The ItemSlot on to insert into. + /// True only returns slots that are empty. + /// False returns any slot that is able to receive . + /// True when a slot is found. Otherwise, false. + private bool TryGetAvailableSlot(Entity ent, + EntityUid item, + Entity? userEnt, + [NotNullWhen(true)] out ItemSlot? itemSlot, + bool emptyOnly = false) + { + // TODO Replace with ItemSlotsSystem version when upstream is merged + itemSlot = null; + + if (userEnt is { } user && Resolve(user, ref user.Comp) && _hands.IsHolding(user, item)) + { + if (!_hands.CanDrop(user, item, user.Comp)) + return false; + } + + if (!Resolve(ent, ref ent.Comp, false)) + return false; + + var slots = new List(); + foreach (var slot in ent.Comp.Slots.Values) + { + if (emptyOnly && slot.ContainerSlot?.ContainedEntity != null) + continue; + + if (_itemSlots.CanInsert(ent, item, userEnt, slot)) + slots.Add(slot); + } + + if (slots.Count == 0) + return false; + + slots.Sort(ItemSlotsSystem.SortEmpty); + + itemSlot = slots[0]; + return true; + } + + // Get last item inserted into holster (can also be used to check if holster is empty) + private bool TryGetLastInserted(Entity holster, out EntityUid item) + { + item = default; + + if (!Resolve(holster, ref holster.Comp)) + return false; + + var contents = holster.Comp.Contents; + + if (contents.Count == 0) + return false; + + item = contents[contents.Count - 1]; + return true; + } + + private void Unholster(EntityUid user, int startIndex, CMHolsterChoose choose) + { + if (_order.Length == 0) + return; + + if (startIndex >= _order.Length) + startIndex = _order.Length - 1; + + for (var i = startIndex; i < _order.Length; i++) + { + if (Unholster(user, _order[i], choose, out var stop) || stop) + return; + } + + for (var i = 0; i < startIndex; i++) + { + if (Unholster(user, _order[i], choose, out var stop) || stop) + return; + } + } + + private bool Unholster(EntityUid user, SlotFlags flag, CMHolsterChoose choose, out bool stop) + { + stop = false; + var enumerator = _inventory.GetSlotEnumerator(user, flag); + + if (choose == CMHolsterChoose.Last) + { + var items = new List(); + while (enumerator.NextItem(out var next)) + { + items.Add(next); + } + + items.Reverse(); + + foreach (var item in items) + { + if (Unholster(user, item, out stop)) + return true; + } + } + while (enumerator.NextItem(out var item)) + { + if (Unholster(user, item, out stop)) + return true; + } + + return false; + } + + private bool Unholster(EntityUid user, EntityUid item, out bool stop) + { + stop = false; + if (TryComp(item, out CMHolsterComponent? holster)) + { + if (holster.Cooldown is { } cooldown && + _timing.CurTime < holster.LastEjectAt + cooldown) + { + stop = true; + _popup.PopupPredicted(holster.CooldownPopup, user, user, PopupType.SmallCaution); + return false; + } + + if (TryComp(item, out StorageComponent? storage) && + TryGetLastInserted((item, holster), out var weapon)) + { + if (!_hands.TryPickup(user, weapon)) + return false; + + holster.Contents.Remove(weapon); + _audio.PlayPredicted(holster.EjectSound, item, user); + stop = true; + return true; + } + + if (PickupSlot(user, item)) + { + //_adminLog.Add(LogType.RMCHolster, $"{ToPrettyString(user)} unholstered {ToPrettyString(item)}"); + return true; + } + } + + var ev = new IsUnholsterableEvent(); + RaiseLocalEvent(item, ref ev); + + if (!ev.Unholsterable) + return false; + + //_adminLog.Add(LogType.RMCHolster, $"{ToPrettyString(user)} unholstered {ToPrettyString(item)}"); + return _hands.TryPickup(user, item); + } + + public bool TryEquipClothing(EntityUid user, Entity clothing) + { + foreach (var order in _quickEquipOrder) + { + if ((clothing.Comp.Slots & order) == 0) + continue; + + if (!_inventory.TryGetContainerSlotEnumerator(user, out var slots, clothing.Comp.Slots)) + continue; + + while (slots.MoveNext(out var slot)) + { + if (_inventory.TryEquip(user, clothing, slot.ID)) + return true; + } + } + + return false; + } + + public (int Filled, int Total) GetItemSlotsFilled(Entity slots) + { + if (!Resolve(slots, ref slots.Comp, false)) + return (0, 0); + + var total = slots.Comp.Slots.Count; + if (total == 0) + return (0, 0); + + var filled = 0; + foreach (var (_, slot) in slots.Comp.Slots) + { + if (slot.ContainerSlot?.ContainedEntity is { } contained && + !TerminatingOrDeleted(contained)) + { + filled++; + } + } + + return (filled, slots.Comp.Slots.Count); + } +} diff --git a/Content.Shared/ADT/_RMC14/Item/FixedItemSizeStorageComponent.cs b/Content.Shared/ADT/_RMC14/Item/FixedItemSizeStorageComponent.cs new file mode 100644 index 00000000000..b02eb9880ac --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Item/FixedItemSizeStorageComponent.cs @@ -0,0 +1,16 @@ +using Content.Shared.Item; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Item; + +// TODO RMC14 rename to slot storage +// TODO RMC14 upstream this +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(SharedItemSystem))] +public sealed partial class FixedItemSizeStorageComponent : Component +{ + [DataField, AutoNetworkedField] + public Vector2i Size = new(2, 2); + + public Box2i[]? CachedSize; +} diff --git a/Content.Shared/ADT/_RMC14/Item/GetItemSizeModifiersEvent.cs b/Content.Shared/ADT/_RMC14/Item/GetItemSizeModifiersEvent.cs new file mode 100644 index 00000000000..d02f9569b75 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Item/GetItemSizeModifiersEvent.cs @@ -0,0 +1,4 @@ +namespace Content.Shared._RMC14.Item; + +[ByRefEvent] +public record struct GetItemSizeModifiersEvent(int Size); diff --git a/Content.Shared/ADT/_RMC14/Item/ItemSizeChangeComponent.cs b/Content.Shared/ADT/_RMC14/Item/ItemSizeChangeComponent.cs new file mode 100644 index 00000000000..a2282c898d7 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Item/ItemSizeChangeComponent.cs @@ -0,0 +1,11 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Item; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(ItemSizeChangeSystem))] +public sealed partial class ItemSizeChangeComponent : Component +{ + [DataField, AutoNetworkedField] + public int? BaseSize; +} diff --git a/Content.Shared/ADT/_RMC14/Item/ItemSizeChangeSystem.cs b/Content.Shared/ADT/_RMC14/Item/ItemSizeChangeSystem.cs new file mode 100644 index 00000000000..0e86bd598e6 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Item/ItemSizeChangeSystem.cs @@ -0,0 +1,100 @@ +using Content.Shared._RMC14.Attachable.Systems; +using Content.Shared.Item; +using Robust.Shared.Prototypes; + +namespace Content.Shared._RMC14.Item; + +public sealed partial class ItemSizeChangeSystem : EntitySystem +{ + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly SharedItemSystem _itemSystem = default!; + + private readonly List _sortedSizes = new(); + + public override void Initialize() + { + SubscribeLocalEvent(OnPrototypesReloaded); + + SubscribeLocalEvent(OnMapInit, + before: new[] { typeof(AttachableHolderSystem) }); + + InitItemSizes(); + } + + private void OnPrototypesReloaded(PrototypesReloadedEventArgs args) + { + if (!args.ByType.ContainsKey(typeof(ItemSizePrototype)) && args.Removed?.ContainsKey(typeof(ItemSizePrototype)) != true) + return; + + InitItemSizes(); + } + + private void InitItemSizes() + { + _sortedSizes.Clear(); + + foreach (var prototype in _prototypeManager.EnumeratePrototypes()) + { + if (prototype.ID.Equals("Invalid")) + continue; + + _sortedSizes.Add(prototype); + } + + _sortedSizes.Sort(); + } + + private void OnMapInit(Entity item, ref MapInitEvent args) + { + InitItem(item); + RefreshItemSizeModifiers((item.Owner, item.Comp)); + } + + public void RefreshItemSizeModifiers(Entity item) + { + if (item.Comp == null) + item.Comp = EnsureComp(item.Owner); + else if (!InitItem((item.Owner, item.Comp))) + return; + + if (item.Comp == null || item.Comp.BaseSize == null) + return; + + var ev = new GetItemSizeModifiersEvent(item.Comp.BaseSize.Value); + RaiseLocalEvent(item.Owner, ref ev); + + ev.Size = Math.Clamp(ev.Size, 0, _sortedSizes.Count > 0 ? _sortedSizes.Count - 1 : 0); + + if (_sortedSizes.Count <= ev.Size) + return; + + _itemSystem.SetSize(item, _sortedSizes[ev.Size]); + } + + private bool InitItem(Entity item, bool onlyNull = false) + { + if (!onlyNull && item.Comp.BaseSize != null) + return true; + + if (_sortedSizes.Count <= 0) + { + InitItemSizes(); + + if (_sortedSizes.Count <= 0) + return false; + } + + if (!TryComp(item.Owner, out ItemComponent? itemComponent) || !_prototypeManager.TryIndex(itemComponent.Size, out ItemSizePrototype? prototype)) + return false; + + var size = _sortedSizes.IndexOf(prototype); + + if (size < 0) + return false; + + item.Comp.BaseSize = size; + Dirty(item); + + return true; + } +} diff --git a/Content.Shared/ADT/_RMC14/Item/ItemToggle/RMCItemToggleClothingVisualsComponent.cs b/Content.Shared/ADT/_RMC14/Item/ItemToggle/RMCItemToggleClothingVisualsComponent.cs new file mode 100644 index 00000000000..96d036e4132 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Item/ItemToggle/RMCItemToggleClothingVisualsComponent.cs @@ -0,0 +1,11 @@ +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Item.ItemToggle; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class RMCItemToggleClothingVisualsComponent : Component +{ + [DataField, AutoNetworkedField] + public string Prefix = "on"; +} diff --git a/Content.Shared/ADT/_RMC14/Item/ItemToggle/RMCItemToggleSystem.cs b/Content.Shared/ADT/_RMC14/Item/ItemToggle/RMCItemToggleSystem.cs new file mode 100644 index 00000000000..a9172ab4b0a --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Item/ItemToggle/RMCItemToggleSystem.cs @@ -0,0 +1,29 @@ +using Content.Shared.Clothing.EntitySystems; +using Content.Shared.Item; +using Content.Shared.Item.ItemToggle.Components; + +namespace Content.Shared._RMC14.Item.ItemToggle; + +public sealed class RMCItemToggleSystem : EntitySystem +{ + [Dependency] private readonly ClothingSystem _clothing = default!; + [Dependency] private readonly SharedItemSystem _item = default!; + + private EntityQuery _query; + + public override void Initialize() + { + base.Initialize(); + + _query = GetEntityQuery(); + + SubscribeLocalEvent(OnToggled); + } + + private void OnToggled(Entity ent, ref ItemToggledEvent args) + { + var prefix = args.Activated ? ent.Comp.Prefix : null; + _item.SetHeldPrefix(ent, prefix); + _clothing.SetEquippedPrefix(ent, prefix); + } +} diff --git a/Content.Shared/ADT/_RMC14/Item/MultiHandedHolderComponent.cs b/Content.Shared/ADT/_RMC14/Item/MultiHandedHolderComponent.cs new file mode 100644 index 00000000000..59266223886 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Item/MultiHandedHolderComponent.cs @@ -0,0 +1,11 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Item; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(MultiHandedHolderSystem))] +public sealed partial class MultiHandedHolderComponent : Component +{ + [DataField, AutoNetworkedField] + public List Items = new(); +} diff --git a/Content.Shared/ADT/_RMC14/Item/MultiHandedHolderSystem.cs b/Content.Shared/ADT/_RMC14/Item/MultiHandedHolderSystem.cs new file mode 100644 index 00000000000..063702205e8 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Item/MultiHandedHolderSystem.cs @@ -0,0 +1,81 @@ +using Content.Shared.Hands; +using Content.Shared.Hands.Components; +using Content.Shared.Hands.EntitySystems; +using Content.Shared.Inventory.VirtualItem; +using Content.Shared.Item; +using Content.Shared.Popups; +using Content.Shared.Whitelist; +using Robust.Shared.Timing; + +namespace Content.Shared._RMC14.Item; + +public sealed class MultiHandedHolderSystem : EntitySystem +{ + [Dependency] private readonly SharedHandsSystem _hands = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly SharedVirtualItemSystem _virtualItem = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelist = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnPickupAttempt); + SubscribeLocalEvent(OnVirtualItemDeleted); + SubscribeLocalEvent(OnEquipped); + SubscribeLocalEvent(OnUnequipped); + } + + private void OnPickupAttempt(Entity holder, ref PickupAttemptEvent args) + { + if (GetHandsNeeded(holder, args.Item) is not { } needed) + return; + + if (TryComp(args.User, out var hands) && + hands.CountFreeHands() >= needed) + { + return; + } + + args.Cancel(); + if (_timing.IsFirstTimePredicted) + { + _popup.PopupCursor(Loc.GetString("multi-handed-item-pick-up-fail", + ("number", needed - 1), ("item", args.Item)), args.User); + } + } + + private void OnVirtualItemDeleted(Entity ent, ref VirtualItemDeletedEvent args) + { + if (args.User != ent.Owner) + return; + + _hands.TryDrop(args.User, args.BlockingEntity); + } + + private void OnEquipped(Entity holder, ref DidEquipHandEvent args) + { + if (GetHandsNeeded(holder, args.Equipped) is not { } hands) + return; + + for (var i = 0; i < hands - 1; i++) + { + _virtualItem.TrySpawnVirtualItemInHand(args.Equipped, args.User); + } + } + + private void OnUnequipped(Entity holder, ref DidUnequipHandEvent args) + { + _virtualItem.DeleteInHandsMatching(args.User, args.Unequipped); + } + + private int? GetHandsNeeded(Entity holder, EntityUid item) + { + foreach (var (hands, whitelist) in holder.Comp.Items) + { + if (_whitelist.IsValid(whitelist, item)) + return hands; + } + + return null; + } +} diff --git a/Content.Shared/ADT/_RMC14/Item/MultiHandedItem.cs b/Content.Shared/ADT/_RMC14/Item/MultiHandedItem.cs new file mode 100644 index 00000000000..765ac0c4a37 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Item/MultiHandedItem.cs @@ -0,0 +1,8 @@ +using Content.Shared.Whitelist; +using Robust.Shared.Serialization; + +namespace Content.Shared._RMC14.Item; + +[DataRecord] +[Serializable, NetSerializable] +public record MultiHandedItem(int Hands, EntityWhitelist Whitelist); diff --git a/Content.Shared/ADT/_RMC14/Movement/TemporarySpeedModifiersComponent.cs b/Content.Shared/ADT/_RMC14/Movement/TemporarySpeedModifiersComponent.cs new file mode 100644 index 00000000000..2ab2b876770 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Movement/TemporarySpeedModifiersComponent.cs @@ -0,0 +1,19 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Serialization; + +namespace Content.Shared._RMC14.Movement; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(TemporarySpeedModifiersSystem))] +public sealed partial class TemporarySpeedModifiersComponent : Component +{ + [DataField, AutoNetworkedField] + public List<(TimeSpan ExpiresAt, float Walk, float Sprint)> Modifiers = new(); +} + +[DataRecord, Serializable, NetSerializable] +public record struct TemporarySpeedModifierSet( + TimeSpan Duration, + float Walk, + float Sprint +); diff --git a/Content.Shared/ADT/_RMC14/Movement/TemporarySpeedModifiersSystem.cs b/Content.Shared/ADT/_RMC14/Movement/TemporarySpeedModifiersSystem.cs new file mode 100644 index 00000000000..0a008f53f89 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Movement/TemporarySpeedModifiersSystem.cs @@ -0,0 +1,73 @@ +using Content.Shared.Movement.Systems; +using Robust.Shared.Network; +using Robust.Shared.Timing; + +namespace Content.Shared._RMC14.Movement; + +public sealed class TemporarySpeedModifiersSystem : EntitySystem +{ + [Dependency] private readonly MovementSpeedModifierSystem _movementSpeedSystem = default!; + [Dependency] private readonly INetManager _netManager = default!; + [Dependency] private readonly IGameTiming _timing = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnRefreshMovement); + } + + private void OnRefreshMovement(Entity ent, ref RefreshMovementSpeedModifiersEvent args) + { + foreach (var modifier in ent.Comp.Modifiers) + { + if (modifier.ExpiresAt <= _timing.CurTime) + continue; + + args.ModifySpeed(modifier.Walk, modifier.Sprint); + } + } + + public override void Update(float frameTime) + { + var time = _timing.CurTime; + var speedModsQuery = EntityQueryEnumerator(); + + while (speedModsQuery.MoveNext(out var uid, out var speedModsComponent)) + { + var toRemove = new List<(TimeSpan ExpiresAt, float Walk, float Sprint)>(); + + foreach (var modifier in speedModsComponent.Modifiers) + { + if (modifier.ExpiresAt > time) + continue; + + toRemove.Add(modifier); + } + + foreach (var modifier in toRemove) + { + speedModsComponent.Modifiers.Remove(modifier); + } + + if (toRemove.Count > 0) + Dirty(uid, speedModsComponent); + + if (speedModsComponent.Modifiers.Count <= 0) + RemCompDeferred(uid); + + _movementSpeedSystem.RefreshMovementSpeedModifiers(uid); + } + } + + public void ModifySpeed(EntityUid entUid, List modifiers) + { + if (_netManager.IsClient) + return; + + var comp = EnsureComp(entUid); + + foreach (var modifier in modifiers) + { + comp.Modifiers.Add((_timing.CurTime + modifier.Duration, modifier.Walk, modifier.Sprint)); + } + } +} diff --git a/Content.Shared/ADT/_RMC14/Projectiles/DeleteOnCollideComponent.cs b/Content.Shared/ADT/_RMC14/Projectiles/DeleteOnCollideComponent.cs new file mode 100644 index 00000000000..233bee9e56f --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Projectiles/DeleteOnCollideComponent.cs @@ -0,0 +1,7 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Projectiles; + +[RegisterComponent, NetworkedComponent] +[Access(typeof(RMCProjectileSystem))] +public sealed partial class DeleteOnCollideComponent : Component; diff --git a/Content.Shared/ADT/_RMC14/Projectiles/ModifyTargetOnHitComponent.cs b/Content.Shared/ADT/_RMC14/Projectiles/ModifyTargetOnHitComponent.cs new file mode 100644 index 00000000000..88f6a3bffbc --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Projectiles/ModifyTargetOnHitComponent.cs @@ -0,0 +1,16 @@ +using Content.Shared.Whitelist; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared._RMC14.Projectiles; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(RMCProjectileSystem))] +public sealed partial class ModifyTargetOnHitComponent : Component +{ + [DataField] + public ComponentRegistry? Add; + + [DataField, AutoNetworkedField] + public EntityWhitelist? Whitelist; +} diff --git a/Content.Shared/ADT/_RMC14/Projectiles/PreventCollideWithDeadComponent.cs b/Content.Shared/ADT/_RMC14/Projectiles/PreventCollideWithDeadComponent.cs new file mode 100644 index 00000000000..7b07130a568 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Projectiles/PreventCollideWithDeadComponent.cs @@ -0,0 +1,7 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Projectiles; + +[RegisterComponent, NetworkedComponent] +[Access(typeof(RMCProjectileSystem))] +public sealed partial class PreventCollideWithDeadComponent : Component; diff --git a/Content.Shared/ADT/_RMC14/Projectiles/ProjectileMaxRangeComponent.cs b/Content.Shared/ADT/_RMC14/Projectiles/ProjectileMaxRangeComponent.cs new file mode 100644 index 00000000000..903a38a378a --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Projectiles/ProjectileMaxRangeComponent.cs @@ -0,0 +1,18 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Map; + +namespace Content.Shared._RMC14.Projectiles; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(RMCProjectileSystem))] +public sealed partial class ProjectileMaxRangeComponent : Component +{ + [DataField, AutoNetworkedField] + public EntityCoordinates? Origin; + + [DataField(required: true), AutoNetworkedField] + public float Max; + + [DataField, AutoNetworkedField] + public bool Delete = true; +} diff --git a/Content.Shared/ADT/_RMC14/Projectiles/RMCProjectileDamageFalloffComponent.cs b/Content.Shared/ADT/_RMC14/Projectiles/RMCProjectileDamageFalloffComponent.cs new file mode 100644 index 00000000000..4153d44acd0 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Projectiles/RMCProjectileDamageFalloffComponent.cs @@ -0,0 +1,59 @@ +using Content.Shared.FixedPoint; +using Robust.Shared.GameStates; +using Robust.Shared.Map; +using Robust.Shared.Serialization; + +namespace Content.Shared._RMC14.Projectiles; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(RMCProjectileSystem))] +public sealed partial class RMCProjectileDamageFalloffComponent : Component +{ + /// + /// This lists all the thresholds and their falloff values. + /// + [DataField, AutoNetworkedField] + public List Thresholds = new() + { + new DamageFalloffThreshold(0f, 1, false), + new DamageFalloffThreshold(22f, 9999, true) + }; + + /// + /// This determines the minimum fraction of the projectile's original damage that must remain after falloff is applied. + /// + [DataField, AutoNetworkedField] + public FixedPoint2 MinRemainingDamageMult = 0.05f; + + /// + /// This is the additional falloff multiplier applied by the firing weapon. + /// + [DataField, AutoNetworkedField] + public FixedPoint2 WeaponMult = 1; + + /// + /// These are the coordinates from which the projectile was shot. Used to determine the distance travelled. + /// + [DataField, AutoNetworkedField] + public EntityCoordinates? ShotFrom; +} + +[DataRecord, Serializable, NetSerializable] +public record struct DamageFalloffThreshold( + /// + /// The range at which falloff starts to take effect. + /// Conversion from 13: effective_range_max + /// + float Range, + + /// + /// This is the number by which the projectile's damage is decreased for each tile travelled beyond its effective range. + /// Conversion from 13: damage_falloff + /// + FixedPoint2 Falloff, + + /// + /// This makes this falloff value ignore the firing weapon's falloff multiplier. Used primarily to simulate having a capped maximum range. Should generally be false. + /// + bool IgnoreModifiers +); diff --git a/Content.Shared/ADT/_RMC14/Projectiles/RMCProjectileSystem.cs b/Content.Shared/ADT/_RMC14/Projectiles/RMCProjectileSystem.cs new file mode 100644 index 00000000000..a10b3ca51fc --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Projectiles/RMCProjectileSystem.cs @@ -0,0 +1,181 @@ +using System.Numerics; +using Content.Shared.FixedPoint; +using Content.Shared.Mobs.Systems; +using Content.Shared.Popups; +using Content.Shared.Projectiles; +using Content.Shared.Whitelist; +using Robust.Shared.Network; +using Robust.Shared.Physics.Events; +using Robust.Shared.Physics.Systems; + +namespace Content.Shared._RMC14.Projectiles; + +public sealed class RMCProjectileSystem : EntitySystem +{ + [Dependency] private readonly MobStateSystem _mobState = default!; + [Dependency] private readonly INetManager _net = default!; + [Dependency] private readonly SharedPhysicsSystem _physics = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelist = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnDeleteOnCollideStartCollide); + SubscribeLocalEvent(OnModifyTargetOnHit); + SubscribeLocalEvent(OnProjectileMaxRangeMapInit); + + SubscribeLocalEvent(OnFalloffProjectileMapInit); + SubscribeLocalEvent(OnFalloffProjectileHit); + + SubscribeLocalEvent(OnSpawnOnTerminatingMapInit); + SubscribeLocalEvent(OnSpawnOnTerminatingTerminate); + + SubscribeLocalEvent(OnPreventCollideWithDead); + } + + private void OnDeleteOnCollideStartCollide(Entity ent, ref StartCollideEvent args) + { + if (_net.IsServer) + QueueDel(ent); + } + + private void OnModifyTargetOnHit(Entity ent, ref ProjectileHitEvent args) + { + if (!_whitelist.IsWhitelistPassOrNull(ent.Comp.Whitelist, args.Target)) + return; + + if (ent.Comp.Add is { } add) + EntityManager.AddComponents(args.Target, add); + } + + private void OnProjectileMaxRangeMapInit(Entity ent, ref MapInitEvent args) + { + ent.Comp.Origin = _transform.GetMoverCoordinates(ent); + Dirty(ent); + } + + private void OnFalloffProjectileMapInit(Entity projectile, ref MapInitEvent args) + { + projectile.Comp.ShotFrom = _transform.GetMoverCoordinates(projectile.Owner); + Dirty(projectile); + } + + private void OnFalloffProjectileHit(Entity projectile, ref ProjectileHitEvent args) + { + if (projectile.Comp.ShotFrom == null || projectile.Comp.MinRemainingDamageMult < 0) + return; + + var distance = (_transform.GetMoverCoordinates(args.Target).Position - projectile.Comp.ShotFrom.Value.Position).Length(); + var minDamage = args.Damage.GetTotal() * projectile.Comp.MinRemainingDamageMult; + + foreach (var threshold in projectile.Comp.Thresholds) + { + var pastEffectiveRange = distance - threshold.Range; + + if (pastEffectiveRange <= 0) + continue; + + var totalDamage = args.Damage.GetTotal(); + + if (totalDamage <= minDamage) + break; + + var extraMult = threshold.IgnoreModifiers ? 1 : projectile.Comp.WeaponMult; + var minMult = FixedPoint2.Min(minDamage / totalDamage, 1); + + args.Damage *= FixedPoint2.Clamp((totalDamage - pastEffectiveRange * threshold.Falloff * extraMult) / totalDamage, minMult, 1); + + } + } + + public void SetProjectileFalloffWeaponMult(Entity projectile, FixedPoint2 mult) + { + projectile.Comp.WeaponMult = mult; + Dirty(projectile); + } + + private void OnSpawnOnTerminatingMapInit(Entity ent, ref MapInitEvent args) + { + ent.Comp.Origin = _transform.GetMoverCoordinates(ent); + Dirty(ent); + } + + private void OnSpawnOnTerminatingTerminate(Entity ent, ref EntityTerminatingEvent args) + { + if (_net.IsClient) + return; + + if (!TryComp(ent, out TransformComponent? transform)) + return; + + if (TerminatingOrDeleted(transform.ParentUid)) + return; + + var coordinates = transform.Coordinates; + if (ent.Comp.ProjectileAdjust && + ent.Comp.Origin is { } origin && + coordinates.TryDelta(EntityManager, _transform, origin, out var delta) && + delta.Length() > 0) + { + coordinates = coordinates.Offset(delta.Normalized() / -2); + } + + SpawnAtPosition(ent.Comp.Spawn, coordinates); + + if (ent.Comp.Popup is { } popup) + _popup.PopupCoordinates(Loc.GetString(popup), coordinates, ent.Comp.PopupType ?? PopupType.Small); + } + + private void OnPreventCollideWithDead(Entity ent, ref PreventCollideEvent args) + { + if (args.Cancelled) + return; + + if (_mobState.IsDead(args.OtherEntity)) + args.Cancelled = true; + } + + public void SetMaxRange(Entity ent, float max) + { + ent.Comp.Max = max; + Dirty(ent); + } + + private void StopProjectile(Entity ent) + { + if (ent.Comp.Delete) + { + if (_net.IsServer) + QueueDel(ent); + } + else + { + _physics.SetLinearVelocity(ent, Vector2.Zero); + RemCompDeferred(ent); + } + } + + public override void Update(float frameTime) + { + if (_net.IsClient) + return; + + var maxQuery = EntityQueryEnumerator(); + while (maxQuery.MoveNext(out var uid, out var comp)) + { + var coordinates = _transform.GetMoverCoordinates(uid); + if (comp.Origin is not { } origin || + !coordinates.TryDistance(EntityManager, _transform, origin, out var distance)) + { + StopProjectile((uid, comp)); + continue; + } + + if (distance < comp.Max && Math.Abs(distance - comp.Max) > 0.1f) + continue; + + StopProjectile((uid, comp)); + } + } +} diff --git a/Content.Shared/ADT/_RMC14/Projectiles/SpawnOnTerminateComponent.cs b/Content.Shared/ADT/_RMC14/Projectiles/SpawnOnTerminateComponent.cs new file mode 100644 index 00000000000..8ee0c41fcdd --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Projectiles/SpawnOnTerminateComponent.cs @@ -0,0 +1,26 @@ +using Content.Shared.Popups; +using Robust.Shared.GameStates; +using Robust.Shared.Map; +using Robust.Shared.Prototypes; + +namespace Content.Shared._RMC14.Projectiles; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(RMCProjectileSystem))] +public sealed partial class SpawnOnTerminateComponent : Component +{ + [DataField, AutoNetworkedField] + public EntityCoordinates? Origin; + + [DataField(required: true), AutoNetworkedField] + public EntProtoId Spawn; + + [DataField, AutoNetworkedField] + public LocId? Popup; + + [DataField, AutoNetworkedField] + public PopupType? PopupType; + + [DataField, AutoNetworkedField] + public bool ProjectileAdjust = true; +} diff --git a/Content.Shared/ADT/_RMC14/Random/SplitMix64.cs b/Content.Shared/ADT/_RMC14/Random/SplitMix64.cs new file mode 100644 index 00000000000..8f427f057c0 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Random/SplitMix64.cs @@ -0,0 +1,39 @@ +namespace Content.Shared._RMC14.Random; + +/// +/// Seed initializer PRNG (splitmix64). +/// +/// http://prng.di.unimi.it/splitmix64.c +public record struct SplitMix64 +{ + /// + /// Creates a new instance. + /// + public SplitMix64() + : this(DateTime.UtcNow.Ticks) + { + } + + /// + /// Creates a new instance. + /// + /// Seed value. + public SplitMix64(long seed) + { + x = (UInt64) seed; + } + + + private UInt64 x; + + /// + /// Returns the next 64-bit pseudo-random number. + /// + public long Next() + { + UInt64 z = unchecked(x += 0x9e3779b97f4a7c15); + z = unchecked((z ^ (z >> 30)) * 0xbf58476d1ce4e5b9); + z = unchecked((z ^ (z >> 27)) * 0x94d049bb133111eb); + return unchecked((Int64) (z ^ (z >> 31))); + } +} diff --git a/Content.Shared/ADT/_RMC14/Random/Xoroshiro64S.cs b/Content.Shared/ADT/_RMC14/Random/Xoroshiro64S.cs new file mode 100644 index 00000000000..68d525e31b2 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Random/Xoroshiro64S.cs @@ -0,0 +1,65 @@ +using System.Runtime.CompilerServices; + +namespace Content.Shared._RMC14.Random; + +// https://github.com/medo64/Medo.ScrambledLinear/blob/main/src/Xoroshiro/Xoroshiro64S.cs +/// +/// 32-bit random number generator intended for floating point numbers with 64-bit state (xoroshiro64*). +/// +/// http://prng.di.unimi.it/xoroshiro64star.c +public record struct Xoroshiro64S +{ + /// + /// Creates a new instance. + /// + public Xoroshiro64S() + : this(DateTime.UtcNow.Ticks) + { + } + + /// + /// Creates a new instance. + /// + /// Seed value. + public Xoroshiro64S(long seed) + { + var sm64 = new SplitMix64(seed); + _s0 = unchecked((UInt32) sm64.Next()); + _s1 = unchecked((UInt32) sm64.Next()); + } + + + private UInt32 _s0; + private UInt32 _s1; + + /// + /// Returns the next 32-bit pseudo-random number. + /// + public int Next() + { + UInt32 s0 = _s0; + UInt32 s1 = _s1; + UInt32 result = unchecked(s0 * (UInt32) 0x9E3779BB); + + s1 ^= s0; + _s0 = RotateLeft(s0, 26) ^ s1 ^ (s1 << 9); + _s1 = RotateLeft(s1, 13); + + return Math.Abs((int) result); + } + + public float NextFloat() + { + return Next() * 4.6566128752458E-10f; + } + + public float NextFloat(float min, float max) + { + return NextFloat() * (max - min) + min; + } + + private static UInt32 RotateLeft(UInt32 x, int k) + { + return (x << k) | (x >> (32 - k)); + } +} diff --git a/Content.Shared/ADT/_RMC14/Scoping/GunScopingComponent.cs b/Content.Shared/ADT/_RMC14/Scoping/GunScopingComponent.cs new file mode 100644 index 00000000000..c1a3b9a8215 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Scoping/GunScopingComponent.cs @@ -0,0 +1,11 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Scoping; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(SharedScopeSystem))] +public sealed partial class GunScopingComponent : Component +{ + [DataField, AutoNetworkedField] + public EntityUid? Scope; +} diff --git a/Content.Shared/ADT/_RMC14/Scoping/ScopeComponent.cs b/Content.Shared/ADT/_RMC14/Scoping/ScopeComponent.cs new file mode 100644 index 00000000000..0074295f4ba --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Scoping/ScopeComponent.cs @@ -0,0 +1,84 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; + +namespace Content.Shared._RMC14.Scoping; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(SharedScopeSystem))] +public sealed partial class ScopeComponent : Component +{ + [DataField, AutoNetworkedField] + public int CurrentZoomLevel = 0; + + [DataField, AutoNetworkedField] + public List ZoomLevels = new() + { + new ScopeZoomLevel(null, 1f, 15, false, TimeSpan.FromSeconds(1)) + }; + + /// + /// The entity that's scoping + /// + [ViewVariables, AutoNetworkedField] + public EntityUid? User; + + [DataField, AutoNetworkedField] + public EntProtoId ScopingToggleAction = "CMActionToggleScope"; + + [DataField, AutoNetworkedField] + public EntityUid? ScopingToggleActionEntity; + + [DataField, AutoNetworkedField] + public EntProtoId CycleZoomLevelAction = "RMCActionCycleZoomLevel"; + + [DataField, AutoNetworkedField] + public EntityUid? CycleZoomLevelActionEntity; + + [DataField, AutoNetworkedField] + public bool RequireWielding; + + [DataField, AutoNetworkedField] + public bool UseInHand; + + [DataField, AutoNetworkedField] + public Direction? ScopingDirection; + + [DataField, AutoNetworkedField] + public EntityUid? RelayEntity; + + [DataField, AutoNetworkedField] + public bool Attachment; +} + +[DataRecord, Serializable, NetSerializable] +public record struct ScopeZoomLevel( + /// + /// This is used in the popup when cycling through zoom levels. + /// + string? Name, + + /// + /// Value to which zoom will be set when scoped in. + /// + float Zoom, + + // TODO RMC14 scoping making this too high causes pop-in + // wait until https://github.com/space-wizards/RobustToolbox/pull/5228 is fixed to increase it + // cm13 values: 11 tile offset, 24x24 view in 4x | 6 tile offset, normal view in 2x. + // right now we are doing a mix of both and only one setting. + /// + /// How much to offset the user's view by when scoping. + /// + float Offset, + + /// + /// If set to true, the user's movement won't interrupt the scoping action. + /// + bool AllowMovement, + + /// + /// The length of the doafter to zoom in. + /// + TimeSpan DoAfter +); diff --git a/Content.Shared/ADT/_RMC14/Scoping/ScopeCycleZoomLevelEvent.cs b/Content.Shared/ADT/_RMC14/Scoping/ScopeCycleZoomLevelEvent.cs new file mode 100644 index 00000000000..c41d1bd670e --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Scoping/ScopeCycleZoomLevelEvent.cs @@ -0,0 +1,5 @@ +using Content.Shared.Actions; + +namespace Content.Shared._RMC14.Scoping; + +public sealed partial class ScopeCycleZoomLevelEvent : InstantActionEvent; diff --git a/Content.Shared/ADT/_RMC14/Scoping/ScopeDoAfterEvent.cs b/Content.Shared/ADT/_RMC14/Scoping/ScopeDoAfterEvent.cs new file mode 100644 index 00000000000..7b74523d321 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Scoping/ScopeDoAfterEvent.cs @@ -0,0 +1,16 @@ +using Content.Shared.DoAfter; +using Robust.Shared.Serialization; + +namespace Content.Shared._RMC14.Scoping; + +[Serializable, NetSerializable] +public sealed partial class ScopeDoAfterEvent : SimpleDoAfterEvent +{ + [DataField] + public Direction Direction; + + public ScopeDoAfterEvent(Direction direction) + { + Direction = direction; + } +} diff --git a/Content.Shared/ADT/_RMC14/Scoping/ScopingComponent.cs b/Content.Shared/ADT/_RMC14/Scoping/ScopingComponent.cs new file mode 100644 index 00000000000..bdeea75630f --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Scoping/ScopingComponent.cs @@ -0,0 +1,18 @@ +using System.Numerics; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Scoping; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(SharedScopeSystem))] +public sealed partial class ScopingComponent : Component +{ + [ViewVariables, AutoNetworkedField] + public EntityUid? Scope; + + [ViewVariables, AutoNetworkedField] + public Vector2 EyeOffset; + + [ViewVariables, AutoNetworkedField] + public bool AllowMovement; +} diff --git a/Content.Shared/ADT/_RMC14/Scoping/SharedScopeSystem.User.cs b/Content.Shared/ADT/_RMC14/Scoping/SharedScopeSystem.User.cs new file mode 100644 index 00000000000..6ad64e48054 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Scoping/SharedScopeSystem.User.cs @@ -0,0 +1,102 @@ +using Content.Shared.Camera; +using Content.Shared.Mobs; +using Content.Shared.Movement.Events; +using Content.Shared.Movement.Pulling.Events; +using Content.Shared.Stunnable; +using Robust.Shared.Containers; +using Robust.Shared.Player; + +namespace Content.Shared._RMC14.Scoping; + +public partial class SharedScopeSystem +{ + private void InitializeUser() + { + SubscribeLocalEvent(OnRemove); + SubscribeLocalEvent(OnMoveInput); + SubscribeLocalEvent(OnPullStarted); + SubscribeLocalEvent(OnParentChanged); + SubscribeLocalEvent(OnInsertAttempt); + SubscribeLocalEvent(OnEntityTerminating); + SubscribeLocalEvent(OnGetEyeOffset); + SubscribeLocalEvent(OnPlayerDetached); + SubscribeLocalEvent(OnKnockedDown); + SubscribeLocalEvent(OnStunned); + SubscribeLocalEvent(OnMobStateChanged); + } + + private void OnRemove(Entity user, ref ComponentRemove args) + { + if (!TerminatingOrDeleted(user)) + UpdateOffset(user); + } + + private void OnMoveInput(Entity ent, ref MoveInputEvent args) + { + if (!args.HasDirectionalMovement) + return; + + if (!ent.Comp.AllowMovement) + UserStopScoping(ent); + } + + private void OnPullStarted(Entity ent, ref PullStartedMessage args) + { + if (args.PulledUid != ent.Owner) + return; + + UserStopScoping(ent); + } + + private void OnParentChanged(Entity ent, ref EntParentChangedMessage args) + { + UserStopScoping(ent); + } + + private void OnInsertAttempt(Entity ent, ref ContainerGettingInsertedAttemptEvent args) + { + UserStopScoping(ent); + } + + private void OnEntityTerminating(Entity ent, ref EntityTerminatingEvent args) + { + UserStopScoping(ent); + } + + private void OnGetEyeOffset(Entity ent, ref GetEyeOffsetEvent args) + { + args.Offset += ent.Comp.EyeOffset; + } + + private void OnPlayerDetached(Entity ent, ref PlayerDetachedEvent args) + { + UserStopScoping(ent); + } + + private void OnKnockedDown(Entity ent, ref KnockedDownEvent args) + { + UserStopScoping(ent); + } + + private void OnStunned(Entity ent, ref StunnedEvent args) + { + UserStopScoping(ent); + } + + private void OnMobStateChanged(Entity ent, ref MobStateChangedEvent args) + { + if (args.NewMobState == MobState.Alive) + return; + + UserStopScoping(ent); + } + + private void UserStopScoping(Entity ent) + { + var scope = ent.Comp.Scope; + RemCompDeferred(ent); + + if (TryComp(scope, out ScopeComponent? scopeComponent) && scopeComponent.User == ent) + Unscope((scope.Value, scopeComponent)); + } +} diff --git a/Content.Shared/ADT/_RMC14/Scoping/SharedScopeSystem.cs b/Content.Shared/ADT/_RMC14/Scoping/SharedScopeSystem.cs new file mode 100644 index 00000000000..25bc98b1046 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Scoping/SharedScopeSystem.cs @@ -0,0 +1,402 @@ +using System.Numerics; +using Content.Shared._RMC14.Attachable.Events; +using Content.Shared.Actions; +using Content.Shared.Camera; +using Content.Shared.DoAfter; +using Content.Shared.Hands; +using Content.Shared.Hands.EntitySystems; +using Content.Shared.Interaction; +using Content.Shared.Movement.Pulling.Systems; +using Content.Shared.Movement.Systems; +using Content.Shared.Popups; +using Content.Shared.Toggleable; +using Content.Shared.Weapons.Ranged.Components; +using Content.Shared.Weapons.Ranged.Systems; +using Content.Shared.Wieldable; +using Content.Shared.Wieldable.Components; +using Robust.Shared.Containers; + +namespace Content.Shared._RMC14.Scoping; + +public abstract partial class SharedScopeSystem : EntitySystem +{ + [Dependency] private readonly ActionContainerSystem _actionContainer = default!; + [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; + [Dependency] private readonly SharedContainerSystem _container = default!; + [Dependency] private readonly SharedContentEyeSystem _contentEye = default!; + [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; + [Dependency] private readonly SharedEyeSystem _eye = default!; + [Dependency] private readonly SharedHandsSystem _hands = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly PullingSystem _pulling = default!; + + public override void Initialize() + { + InitializeUser(); + + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnShutdown); + SubscribeLocalEvent(OnScopeEntityTerminating); + SubscribeLocalEvent(OnUnequip); + SubscribeLocalEvent(OnDeselectHand); + SubscribeLocalEvent(OnUnwielded); + SubscribeLocalEvent(OnGetActions); + SubscribeLocalEvent(OnToggleAction); + SubscribeLocalEvent(OnCycleZoomLevel); + SubscribeLocalEvent(OnActivateInWorld); + SubscribeLocalEvent(OnGunShot); + SubscribeLocalEvent(OnScopeDoAfter); + + SubscribeLocalEvent(OnGunUnequip); + SubscribeLocalEvent(OnGunDeselectHand); + SubscribeLocalEvent(OnGunUnwielded); + SubscribeLocalEvent(OnGunGunShot); + } + + private void OnMapInit(Entity ent, ref MapInitEvent args) + { + _actionContainer.EnsureAction(ent.Owner, ref ent.Comp.ScopingToggleActionEntity, ent.Comp.ScopingToggleAction); + + if (ent.Comp.ZoomLevels.Count > 1) + _actionContainer.EnsureAction(ent.Owner, ref ent.Comp.CycleZoomLevelActionEntity, ent.Comp.CycleZoomLevelAction); + + Dirty(ent.Owner, ent.Comp); + } + + private void OnShutdown(Entity ent, ref ComponentRemove args) + { + if (ent.Comp.User is not { } user) + return; + + Unscope(ent); + _actionsSystem.RemoveProvidedActions(user, ent.Owner); + } + + private void OnScopeEntityTerminating(Entity ent, ref EntityTerminatingEvent args) + { + Unscope(ent); + } + + private void OnUnequip(Entity ent, ref GotUnequippedHandEvent args) + { + Unscope(ent); + } + + private void OnDeselectHand(Entity ent, ref HandDeselectedEvent args) + { + Unscope(ent); + } + + private void OnUnwielded(Entity ent, ref ItemUnwieldedEvent args) + { + if (ent.Comp.RequireWielding) + Unscope(ent); + } + + private void OnGetActions(Entity ent, ref GetItemActionsEvent args) + { + args.AddAction(ref ent.Comp.ScopingToggleActionEntity, ent.Comp.ScopingToggleAction); + + if (ent.Comp.ZoomLevels.Count > 1) + args.AddAction(ref ent.Comp.CycleZoomLevelActionEntity, ent.Comp.CycleZoomLevelAction); + } + + private void OnToggleAction(Entity ent, ref ToggleActionEvent args) + { + if (args.Handled) + return; + + args.Handled = true; + ToggleScoping(ent, args.Performer); + } + + private void OnCycleZoomLevel(Entity scope, ref ScopeCycleZoomLevelEvent args) + { + if (args.Handled) + return; + + args.Handled = true; + + if (scope.Comp.CurrentZoomLevel >= scope.Comp.ZoomLevels.Count - 1) + scope.Comp.CurrentZoomLevel = 0; + else + ++scope.Comp.CurrentZoomLevel; + + var zoomLevel = GetCurrentZoomLevel(scope); + if (zoomLevel.Name != null) + _popup.PopupClient(Loc.GetString("rcm-action-popup-scope-cycle-zoom", ("zoom", zoomLevel.Name)), args.Performer, args.Performer); + + Dirty(scope); + } + + private void OnActivateInWorld(Entity ent, ref ActivateInWorldEvent args) + { + if (args.Handled || !args.Complex || !ent.Comp.UseInHand) + return; + + args.Handled = true; + ToggleScoping(ent, args.User); + } + + private void OnGunShot(Entity ent, ref GunShotEvent args) + { + var dir = Transform(args.User).LocalRotation.GetCardinalDir(); + if (ent.Comp.ScopingDirection != dir) + Unscope(ent); + } + + private void OnScopeDoAfter(Entity ent, ref ScopeDoAfterEvent args) + { + if (args.Handled) + return; + + args.Handled = true; + + if (args.Cancelled) + { + DeleteRelay(ent, args.User); + return; + } + + var user = args.User; + if (!CanScopePopup(ent, user)) + { + DeleteRelay(ent, args.User); + return; + } + + Scope(ent, user, args.Direction); + } + + private void OnGunUnequip(Entity ent, ref GotUnequippedHandEvent args) + { + UnscopeGun(ent); + } + + private void OnGunDeselectHand(Entity ent, ref HandDeselectedEvent args) + { + UnscopeGun(ent); + } + + private void OnGunUnwielded(Entity ent, ref ItemUnwieldedEvent args) + { + UnscopeGun(ent); + } + + private void OnGunGunShot(Entity ent, ref GunShotEvent args) + { + var dir = Transform(args.User).LocalRotation.GetCardinalDir(); + if (TryComp(ent.Comp.Scope, out ScopeComponent? scope) && scope.ScopingDirection != dir) + UnscopeGun(ent); + } + + private bool CanScopePopup(Entity scope, EntityUid user) + { + var ent = scope.Owner; + if (scope.Comp.Attachment && !TryGetActiveEntity(scope, out ent)) + { + var msgError = Loc.GetString("cm-action-popup-scoping-must-attach", ("scope", ent)); + _popup.PopupClient(msgError, user, user); + return false; + } + + if (!_hands.TryGetActiveItem(user, out var heldItem) || !scope.Comp.Attachment && heldItem != scope.Owner) + { + var msgError = Loc.GetString("cm-action-popup-scoping-user-must-hold", ("scope", ent)); + _popup.PopupClient(msgError, user, user); + return false; + } + + if (_pulling.IsPulled(user)) + { + var msgError = Loc.GetString("cm-action-popup-scoping-user-must-not-pulled", ("scope", ent)); + _popup.PopupClient(msgError, user, user); + return false; + } + + if (_container.IsEntityInContainer(user)) + { + var msgError = Loc.GetString("cm-action-popup-scoping-user-must-not-contained", ("scope", ent)); + _popup.PopupClient(msgError, user, user); + return false; + } + + if (scope.Comp.RequireWielding && + TryComp(ent, out WieldableComponent? wieldable) && + !wieldable.Wielded) + { + var msgError = Loc.GetString("cm-action-popup-scoping-user-must-wield", ("scope", ent)); + _popup.PopupClient(msgError, user, user); + return false; + } + + return true; + } + + protected virtual Direction? StartScoping(Entity scope, EntityUid user) + { + if (!CanScopePopup(scope, user)) + return null; + + // TODO RMC14 make this work properly with rotations + var xform = Transform(user); + var cardinalDir = xform.LocalRotation.GetCardinalDir(); + var ev = new ScopeDoAfterEvent(cardinalDir); + var zoomLevel = GetCurrentZoomLevel(scope); + var doAfter = new DoAfterArgs(EntityManager, user, zoomLevel.DoAfter, ev, scope, null, scope) + { + BreakOnMove = !zoomLevel.AllowMovement + }; + + if (_doAfter.TryStartDoAfter(doAfter)) + return cardinalDir; + + return null; + } + + private void Scope(Entity scope, EntityUid user, Direction direction) + { + if (TryComp(user, out ScopingComponent? scoping)) + UserStopScoping((user, scoping)); + + var zoomLevel = GetCurrentZoomLevel(scope); + + scope.Comp.User = user; + scope.Comp.ScopingDirection = direction; + + Dirty(scope); + + scoping = EnsureComp(user); + scoping.Scope = scope; + scoping.AllowMovement = zoomLevel.AllowMovement; + Dirty(user, scoping); + + if (scope.Comp.Attachment && TryGetActiveEntity(scope, out var active)) + { + var gunScoping = EnsureComp(active); + gunScoping.Scope = scope; + Dirty(active, gunScoping); + } + + var targetOffset = GetScopeOffset(scope, direction); + scoping.EyeOffset = targetOffset; + + var msgUser = Loc.GetString("cm-action-popup-scoping-user", ("scope", scope.Owner)); + _popup.PopupClient(msgUser, user, user); + + _actionsSystem.SetToggled(scope.Comp.ScopingToggleActionEntity, true); + _contentEye.SetZoom(user, Vector2.One * zoomLevel.Zoom, true); + UpdateOffset(user); + } + + protected virtual bool Unscope(Entity scope) + { + if (scope.Comp.User is not { } user) + return false; + + RemCompDeferred(user); + + if (scope.Comp.Attachment && TryGetActiveEntity(scope, out var active)) + RemCompDeferred(active); + + if (scope.Comp.Attachment && scope.Comp.User != null) + { + var interruptEvent = new AttachableToggleableInterruptEvent(scope.Comp.User.Value); + RaiseLocalEvent(scope.Owner, ref interruptEvent); + } + + scope.Comp.User = null; + scope.Comp.ScopingDirection = null; + Dirty(scope); + + var msgUser = Loc.GetString("cm-action-popup-scoping-stopping-user", ("scope", scope.Owner)); + _popup.PopupClient(msgUser, user, user); + + _actionsSystem.SetToggled(scope.Comp.ScopingToggleActionEntity, false); + _contentEye.ResetZoom(user); + return true; + } + + private void UnscopeGun(Entity gun) + { + if (TryComp(gun.Comp.Scope, out ScopeComponent? scope)) + Unscope((gun.Comp.Scope.Value, scope)); + } + + private void ToggleScoping(Entity scope, EntityUid user) + { + if (HasComp(user)) + { + Unscope(scope); + + if (TryComp(user, out ScopingComponent? scoping)) + UserStopScoping((user, scoping)); + + return; + } + + StartScoping(scope, user); + } + + private bool TryGetActiveEntity(Entity scope, out EntityUid active) + { + if (!scope.Comp.Attachment) + { + active = scope; + return true; + } + + if (!_container.TryGetContainingContainer((scope, null), out var container) || + !HasComp(container.Owner)) + { + active = default; + return false; + } + + active = container.Owner; + return true; + } + + protected Vector2 GetScopeOffset(Entity scope, Direction direction) + { + var zoomLevel = GetCurrentZoomLevel(scope); + return direction.ToVec() * ((zoomLevel.Offset * zoomLevel.Zoom - 1) / 2); + } + + protected virtual void DeleteRelay(Entity scope, EntityUid? user) + { + } + + private ScopeZoomLevel GetCurrentZoomLevel(Entity scope) + { + ValidateCurrentZoomLevel(scope); + return scope.Comp.ZoomLevels[scope.Comp.CurrentZoomLevel]; + } + + private void ValidateCurrentZoomLevel(Entity scope) + { + bool dirty = false; + + if (scope.Comp.ZoomLevels == null || scope.Comp.ZoomLevels.Count <= 0) + { + scope.Comp.ZoomLevels = new List(){ new ScopeZoomLevel(null, 1f, 15, false, TimeSpan.FromSeconds(1)) }; + dirty = true; + } + + if (scope.Comp.CurrentZoomLevel >= scope.Comp.ZoomLevels.Count) + { + scope.Comp.CurrentZoomLevel = 0; + dirty = true; + } + + if (dirty) + Dirty(scope); + } + + private void UpdateOffset(EntityUid user) + { + var ev = new GetEyeOffsetEvent(); + RaiseLocalEvent(user, ref ev); + _eye.SetOffset(user, ev.Offset); + } +} diff --git a/Content.Shared/ADT/_RMC14/Sound/CMSoundSystem.cs b/Content.Shared/ADT/_RMC14/Sound/CMSoundSystem.cs new file mode 100644 index 00000000000..91a63d4edb2 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Sound/CMSoundSystem.cs @@ -0,0 +1,75 @@ +using Content.Shared.Mobs; +using Content.Shared.Mobs.Systems; +using Content.Shared.Sound; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Network; +using Robust.Shared.Random; +using Robust.Shared.Timing; + +namespace Content.Shared._RMC14.Sound; + +public sealed class CMSoundSystem : EntitySystem +{ + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedEmitSoundSystem _emitSound = default!; + [Dependency] private readonly MobStateSystem _mobState = default!; + [Dependency] private readonly INetManager _net = default!; + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly IGameTiming _timing = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnRandomMapInit); + + SubscribeLocalEvent(OnDeathMobStateChanged); + + SubscribeLocalEvent(OnEmitSoundOnAction); + } + + private void OnRandomMapInit(Entity ent, ref MapInitEvent args) + { + var min = ent.Comp.Min; + var max = ent.Comp.Max; + if (max <= min) + max = min.Add(TimeSpan.FromTicks(1)); + + ent.Comp.PlayAt = _timing.CurTime + _random.Next(min, max); + Dirty(ent); + } + + private void OnDeathMobStateChanged(Entity ent, ref MobStateChangedEvent args) + { + if (args.NewMobState != MobState.Dead) + return; + + if (_net.IsServer) + _audio.PlayPvs(ent.Comp.Sound, ent); + } + + private void OnEmitSoundOnAction(Entity ent, ref SoundActionEvent args) + { + _emitSound.EmitSound(ent, ent, args.Performer); + + if (ent.Comp.Handle) + args.Handled = true; + } + + public override void Update(float frameTime) + { + if (_net.IsClient) + return; + + var time = _timing.CurTime; + var random = EntityQueryEnumerator(); + while (random.MoveNext(out var uid, out var comp)) + { + if (_mobState.IsDead(uid) || time <= comp.PlayAt) + continue; + + comp.PlayAt = time + _random.Next(comp.Min, comp.Max); + Dirty(uid, comp); + + _audio.PlayPvs(comp.Sound, uid); + } + } +} diff --git a/Content.Shared/ADT/_RMC14/Sound/EmitSoundOnActionComponent.cs b/Content.Shared/ADT/_RMC14/Sound/EmitSoundOnActionComponent.cs new file mode 100644 index 00000000000..38126704dca --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Sound/EmitSoundOnActionComponent.cs @@ -0,0 +1,23 @@ +using Robust.Shared.GameStates; +using Content.Shared.Sound.Components; + +namespace Content.Shared._RMC14.Sound; + +/// +/// Simple sound emitter that emits sound on InstantAction +/// +[RegisterComponent] +public sealed partial class EmitSoundOnActionComponent : BaseEmitSoundComponent +{ + /// + /// Whether or not to mark an interaction as handled after playing the sound. Useful if this component is + /// used to play sound for some other component with on-use functionality + /// + /// + /// If false, you should be confident that the interaction will also be handled by some other system, as + /// otherwise this might enable sound spamming, as use-delays are only initiated if the interaction was + /// handled. + /// + [DataField] + public bool Handle = true; +} diff --git a/Content.Shared/ADT/_RMC14/Sound/RandomSoundComponent.cs b/Content.Shared/ADT/_RMC14/Sound/RandomSoundComponent.cs new file mode 100644 index 00000000000..3112f521a13 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Sound/RandomSoundComponent.cs @@ -0,0 +1,21 @@ +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Sound; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause] +[Access(typeof(CMSoundSystem))] +public sealed partial class RandomSoundComponent : Component +{ + [DataField(required: true), AutoNetworkedField] + public SoundSpecifier? Sound; + + [DataField(required: true), AutoNetworkedField] + public TimeSpan Min; + + [DataField(required: true), AutoNetworkedField] + public TimeSpan Max; + + [DataField, AutoNetworkedField, AutoPausedField] + public TimeSpan? PlayAt; +} diff --git a/Content.Shared/ADT/_RMC14/Sound/SoundActionEvent.cs b/Content.Shared/ADT/_RMC14/Sound/SoundActionEvent.cs new file mode 100644 index 00000000000..9b8469f3c97 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Sound/SoundActionEvent.cs @@ -0,0 +1,5 @@ +using Content.Shared.Actions; + +namespace Content.Shared._RMC14.Sound; + +public sealed partial class SoundActionEvent : InstantActionEvent; diff --git a/Content.Shared/ADT/_RMC14/Sound/SoundOnDeathComponent.cs b/Content.Shared/ADT/_RMC14/Sound/SoundOnDeathComponent.cs new file mode 100644 index 00000000000..c48525c9ab8 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Sound/SoundOnDeathComponent.cs @@ -0,0 +1,12 @@ +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Sound; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(CMSoundSystem))] +public sealed partial class SoundOnDeathComponent : Component +{ + [DataField(required: true), AutoNetworkedField] + public SoundSpecifier? Sound; +} diff --git a/Content.Shared/ADT/_RMC14/Tackle/CMDisarmEvent.cs b/Content.Shared/ADT/_RMC14/Tackle/CMDisarmEvent.cs new file mode 100644 index 00000000000..0847cab7c35 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Tackle/CMDisarmEvent.cs @@ -0,0 +1,4 @@ +namespace Content.Shared._RMC14.Tackle; + +[ByRefEvent] +public record struct CMDisarmEvent(EntityUid User, bool Handled = false); diff --git a/Content.Shared/ADT/_RMC14/Tackle/TackleComponent.cs b/Content.Shared/ADT/_RMC14/Tackle/TackleComponent.cs new file mode 100644 index 00000000000..dd70dc85f46 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Tackle/TackleComponent.cs @@ -0,0 +1,20 @@ +using Content.Shared.FixedPoint; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Tackle; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class TackleComponent : Component +{ + [DataField, AutoNetworkedField] + public FixedPoint2 Strength = 1; + + [DataField, AutoNetworkedField] + public FixedPoint2 Threshold = 4; + + [DataField, AutoNetworkedField] + public TimeSpan Stun = TimeSpan.FromSeconds(5); + + [DataField, AutoNetworkedField] + public float Chance = 0.35f; +} diff --git a/Content.Shared/ADT/_RMC14/Tackle/TackleSystem.cs b/Content.Shared/ADT/_RMC14/Tackle/TackleSystem.cs new file mode 100644 index 00000000000..1f11d39a777 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Tackle/TackleSystem.cs @@ -0,0 +1,112 @@ +using Content.Shared.Administration.Logs; +using Content.Shared.CombatMode; +using Content.Shared.Damage.Systems; +using Content.Shared.Database; +using Content.Shared.Effects; +using Content.Shared.Hands.EntitySystems; +using Content.Shared.Popups; +using Content.Shared.Stunnable; +using Robust.Shared.Audio; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Network; +using Robust.Shared.Player; +using Robust.Shared.Random; +using Robust.Shared.Timing; + +namespace Content.Shared._RMC14.Tackle; + +public sealed class TackleSystem : EntitySystem +{ + [Dependency] private readonly ISharedAdminLogManager _adminLog = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedColorFlashEffectSystem _colorFlash = default!; + [Dependency] private readonly INetManager _net = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly SharedStunSystem _stun = default!; + [Dependency] private readonly IGameTiming _timing = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnDisarmed, before: [typeof(SharedHandsSystem), typeof(StaminaSystem)]); + } + + private void OnDisarmed(Entity target, ref CMDisarmEvent args) + { + var user = args.User; + if (!TryComp(user, out TackleComponent? tackle)) + return; + + args.Handled = true; + + _colorFlash.RaiseEffect(Color.Aqua, new List { target.Owner }, Filter.PvsExcept(user)); + + var time = _timing.CurTime; + var recently = EnsureComp(target); + recently.LastTackled = time; + recently.LastTackledDuration = target.Comp.ExpireAfter; + recently.Current += tackle.Strength; + + Dirty(target, recently); + + if (recently.Current < tackle.Threshold) + { + //_adminLog.Add(LogType.RMCTackle, $"{ToPrettyString(user)} tried to tackle {ToPrettyString(target)}."); + + if (_net.IsServer) + _popup.PopupEntity(Loc.GetString("cm-tackle-try-self", ("target", target.Owner)), user, user); + + foreach (var session in Filter.PvsExcept(user).Recipients) + { + if (session.AttachedEntity is not { } recipient) + continue; + + if (recipient == target.Owner) + _popup.PopupEntity(Loc.GetString("cm-tackle-try-target", ("user", user)), user, recipient, PopupType.MediumCaution); + else + _popup.PopupEntity(Loc.GetString("cm-tackle-try-observer", ("user", user), ("target", target.Owner)), user, recipient); + } + + return; + } + else + { + //_adminLog.Add(LogType.RMCTackle, $"{ToPrettyString(user)} tackled down {ToPrettyString(target)}."); + _popup.PopupClient(Loc.GetString("cm-tackle-success-self", ("target", target.Owner)), user, user); + + foreach (var session in Filter.PvsExcept(user).Recipients) + { + if (session.AttachedEntity is not { } recipient) + continue; + + if (recipient == target.Owner) + _popup.PopupEntity(Loc.GetString("cm-tackle-success-target", ("user", user)), user, recipient, PopupType.MediumCaution); + else + _popup.PopupEntity(Loc.GetString("cm-tackle-success-observer", ("user", user), ("target", target.Owner)), user, recipient); + } + } + + if (_net.IsClient) + return; + + if (TryComp(user, out CombatModeComponent? combatMode)) + { + var audioParams = AudioParams.Default.WithVariation(0.025f).WithVolume(5f); + _audio.PlayPredicted(combatMode.DisarmSuccessSound, target, user, audioParams); + } + + _stun.TryParalyze(target, tackle.Stun, true); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + var time = _timing.CurTime; + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var recently, out _)) + { + if (time > recently.LastTackled + recently.LastTackledDuration) + RemCompDeferred(uid); + } + } +} diff --git a/Content.Shared/ADT/_RMC14/Tackle/TackleableComponent.cs b/Content.Shared/ADT/_RMC14/Tackle/TackleableComponent.cs new file mode 100644 index 00000000000..446a5320554 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Tackle/TackleableComponent.cs @@ -0,0 +1,10 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Tackle; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class TackleableComponent : Component +{ + [DataField, AutoNetworkedField] + public TimeSpan ExpireAfter = TimeSpan.FromSeconds(4); +} diff --git a/Content.Shared/ADT/_RMC14/Tackle/TackledRecentlyComponent.cs b/Content.Shared/ADT/_RMC14/Tackle/TackledRecentlyComponent.cs new file mode 100644 index 00000000000..82349489fde --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Tackle/TackledRecentlyComponent.cs @@ -0,0 +1,17 @@ +using Content.Shared.FixedPoint; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Tackle; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class TackledRecentlyComponent : Component +{ + [DataField, AutoNetworkedField] + public FixedPoint2 Current; + + [DataField, AutoNetworkedField] + public TimeSpan LastTackled; + + [DataField, AutoNetworkedField] + public TimeSpan LastTackledDuration; +} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Common/UniqueActionComponent.cs b/Content.Shared/ADT/_RMC14/Weapons/Common/UniqueActionComponent.cs new file mode 100644 index 00000000000..83765aa250d --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Common/UniqueActionComponent.cs @@ -0,0 +1,7 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Weapons.Common; + +[RegisterComponent, NetworkedComponent] +[Access(typeof(UniqueActionSystem))] +public sealed partial class UniqueActionComponent : Component; diff --git a/Content.Shared/ADT/_RMC14/Weapons/Common/UniqueActionEvent.cs b/Content.Shared/ADT/_RMC14/Weapons/Common/UniqueActionEvent.cs new file mode 100644 index 00000000000..3ea6d572a44 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Common/UniqueActionEvent.cs @@ -0,0 +1,6 @@ +namespace Content.Shared._RMC14.Weapons.Common; + +public sealed class UniqueActionEvent(EntityUid userUid) : HandledEntityEventArgs +{ + public readonly EntityUid UserUid = userUid; +} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Common/UniqueActionSystem.cs b/Content.Shared/ADT/_RMC14/Weapons/Common/UniqueActionSystem.cs new file mode 100644 index 00000000000..390409a15ed --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Common/UniqueActionSystem.cs @@ -0,0 +1,68 @@ +using Content.Shared._RMC14.Input; +using Content.Shared.ActionBlocker; +using Content.Shared.Hands.Components; +using Content.Shared.Verbs; +using Robust.Shared.Input.Binding; + +namespace Content.Shared._RMC14.Weapons.Common; + +public sealed class UniqueActionSystem : EntitySystem +{ + [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!; + [Dependency] private readonly IEntityManager _entityManager = default!; + + + public override void Initialize() + { + SubscribeLocalEvent>(OnGetVerbs); + + CommandBinds.Builder + .Bind(CMKeyFunctions.CMUniqueAction, + InputCmdHandler.FromDelegate(session => + { + if (session?.AttachedEntity is { } userUid) + TryUniqueAction(userUid); + }, + handle: false)) + .Register(); + } + + public override void Shutdown() + { + base.Shutdown(); + CommandBinds.Unregister(); + } + + private void OnGetVerbs(Entity ent, ref GetVerbsEvent args) + { + if (!args.CanAccess || !args.CanInteract) + return; + + if (!_actionBlockerSystem.CanInteract(args.User, args.Target)) + return; + + var user = args.User; + args.Verbs.Add(new InteractionVerb + { + Act = () => TryUniqueAction(user, ent.Owner), + Text = "Unique action", + }); + } + + private void TryUniqueAction(EntityUid userUid) + { + if (!_entityManager.TryGetComponent(userUid, out HandsComponent? handsComponent) || + handsComponent.ActiveHandEntity == null) + return; + + TryUniqueAction(userUid, handsComponent.ActiveHandEntity.Value); + } + + private void TryUniqueAction(EntityUid userUid, EntityUid targetUid) + { + if (!_actionBlockerSystem.CanInteract(userUid, targetUid)) + return; + + RaiseLocalEvent(targetUid, new UniqueActionEvent(userUid)); + } +} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Melee/ImmuneToMeleeComponent.cs b/Content.Shared/ADT/_RMC14/Weapons/Melee/ImmuneToMeleeComponent.cs new file mode 100644 index 00000000000..4a877aa907d --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Melee/ImmuneToMeleeComponent.cs @@ -0,0 +1,12 @@ +using Content.Shared.Whitelist; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Weapons.Melee; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(SharedRMCMeleeWeaponSystem))] +public sealed partial class ImmuneToMeleeComponent : Component +{ + [DataField(required: true), AutoNetworkedField] + public EntityWhitelist? Whitelist; +} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Melee/ImmuneToUnarmedComponent.cs b/Content.Shared/ADT/_RMC14/Weapons/Melee/ImmuneToUnarmedComponent.cs new file mode 100644 index 00000000000..72d0338f528 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Melee/ImmuneToUnarmedComponent.cs @@ -0,0 +1,11 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Weapons.Melee; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(SharedRMCMeleeWeaponSystem))] +public sealed partial class ImmuneToUnarmedComponent : Component +{ + [DataField, AutoNetworkedField] + public bool ApplyToXenos; +} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Melee/MeleeDamageMultiplierComponent.cs b/Content.Shared/ADT/_RMC14/Weapons/Melee/MeleeDamageMultiplierComponent.cs new file mode 100644 index 00000000000..9c58c834a9b --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Melee/MeleeDamageMultiplierComponent.cs @@ -0,0 +1,21 @@ +using Content.Shared.Whitelist; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Weapons.Melee; + +/// +/// For melee weapons to apply extra damage to certain entities with certain component(s). +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(SharedRMCMeleeWeaponSystem))] +public sealed partial class MeleeDamageMultiplierComponent : Component +{ + /// + /// The amount the bonus damage is multipled by. For example, 0.5 would be x1.5 the weapon's base damage. + /// + [DataField, AutoNetworkedField] + public float Multiplier = 0.5f; // x1.5 extra damage + + [DataField, AutoNetworkedField] + public EntityWhitelist Whitelist = new(); +} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Melee/MeleeReceivedMultiplierComponent.cs b/Content.Shared/ADT/_RMC14/Weapons/Melee/MeleeReceivedMultiplierComponent.cs new file mode 100644 index 00000000000..985478c0a9d --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Melee/MeleeReceivedMultiplierComponent.cs @@ -0,0 +1,13 @@ +using Content.Shared.Damage; +using Content.Shared.FixedPoint; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Weapons.Melee; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(SharedRMCMeleeWeaponSystem))] +public sealed partial class MeleeReceivedMultiplierComponent : Component +{ + [DataField(required: true), AutoNetworkedField] + public FixedPoint2 OtherMultiplier; +} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Melee/MeleeResetComponent.cs b/Content.Shared/ADT/_RMC14/Weapons/Melee/MeleeResetComponent.cs new file mode 100644 index 00000000000..b9bfc232746 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Melee/MeleeResetComponent.cs @@ -0,0 +1,11 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Weapons.Melee; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(SharedRMCMeleeWeaponSystem))] +public sealed partial class MeleeResetComponent : Component +{ + [DataField, AutoNetworkedField] + public TimeSpan OriginalTime; +} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Melee/SharedRMCMeleeWeaponSystem.cs b/Content.Shared/ADT/_RMC14/Weapons/Melee/SharedRMCMeleeWeaponSystem.cs new file mode 100644 index 00000000000..3bd1b366bad --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Melee/SharedRMCMeleeWeaponSystem.cs @@ -0,0 +1,159 @@ +using Content.Shared.Damage; +using Content.Shared.Interaction.Events; +using Content.Shared.Stunnable; +using Content.Shared.Weapons.Melee; +using Content.Shared.Weapons.Melee.Events; +using Content.Shared.Whitelist; +using Robust.Shared.Timing; + +namespace Content.Shared._RMC14.Weapons.Melee; + +public abstract class SharedRMCMeleeWeaponSystem : EntitySystem +{ + [Dependency] private readonly SharedStunSystem _stun = default!; + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelist = default!; + [Dependency] private readonly SharedMeleeWeaponSystem _melee = default!; + + private EntityQuery _meleeWeaponQuery; + + public override void Initialize() + { + _meleeWeaponQuery = GetEntityQuery(); + + SubscribeLocalEvent(OnImmuneToUnarmedGettingAttacked); + + SubscribeLocalEvent(OnImmuneToMeleeGettingAttacked); + + SubscribeLocalEvent(OnMeleeReceivedMultiplierDamageModify); + + SubscribeLocalEvent(OnStunOnHitMeleeHit); + + SubscribeLocalEvent(OnMultiplierOnHitMeleeHit); + + SubscribeAllEvent(OnLightAttack, before: new[] { typeof(SharedMeleeWeaponSystem) }); + + SubscribeAllEvent(OnHeavyAttack, before: new[] { typeof(SharedMeleeWeaponSystem) }); + + SubscribeAllEvent(OnDisarmAttack, before: new[] { typeof(SharedMeleeWeaponSystem) }); + } + + //Call this whenever you add MeleeResetComponent to anything + public void MeleeResetInit(Entity ent) + { + if (!TryComp(ent, out var weapon)) + { + RemComp(ent); + return; + } + + ent.Comp.OriginalTime = weapon.NextAttack; + weapon.NextAttack = _timing.CurTime; + Dirty(ent, weapon); + Dirty(ent, ent.Comp); + } + + private void OnStunOnHitMeleeHit(Entity ent, ref MeleeHitEvent args) + { + if (!args.IsHit) + return; + + foreach (var hit in args.HitEntities) + { + if (_whitelist.IsValid(ent.Comp.Whitelist, hit)) + _stun.TryParalyze(hit, ent.Comp.Duration, true); + } + } + + private void OnMultiplierOnHitMeleeHit(Entity ent, ref MeleeHitEvent args) + { + if (!args.IsHit) + return; + + var comp = ent.Comp; + + foreach (var hit in args.HitEntities) + { + if (_whitelist.IsValid(comp.Whitelist, hit)) + { + var damage = args.BaseDamage * comp.Multiplier; + args.BonusDamage += damage; + break; + } + } + } + + private void OnImmuneToUnarmedGettingAttacked(Entity ent, ref GettingAttackedAttemptEvent args) + { + + if (args.Attacker == args.Weapon) + args.Cancelled = true; + } + + private void OnImmuneToMeleeGettingAttacked(Entity ent, ref GettingAttackedAttemptEvent args) + { + if (_whitelist.IsWhitelistPassOrNull(ent.Comp.Whitelist, args.Attacker)) + args.Cancelled = true; + } + + private void OnMeleeReceivedMultiplierDamageModify(Entity ent, ref DamageModifyEvent args) + { + if (!_meleeWeaponQuery.HasComp(args.Tool)) + return; + + args.Damage = args.Damage * ent.Comp.OtherMultiplier; + } + + private void OnLightAttack(LightAttackEvent msg, EntitySessionEventArgs args) + { + if (args.SenderSession.AttachedEntity is not {} user) + return; + + if (!_melee.TryGetWeapon(user, out var weaponUid, out var weapon) || + weaponUid != GetEntity(msg.Weapon)) + { + return; + } + + TryMeleeReset(weaponUid, weapon, false); + } + + private void OnHeavyAttack(HeavyAttackEvent msg, EntitySessionEventArgs args) + { + if (args.SenderSession.AttachedEntity is not {} user) + return; + + if (!_melee.TryGetWeapon(user, out var weaponUid, out var weapon) || + weaponUid != GetEntity(msg.Weapon)) + { + return; + } + + TryMeleeReset(weaponUid, weapon, false); + } + + private void OnDisarmAttack(DisarmAttackEvent msg, EntitySessionEventArgs args) + { + if (args.SenderSession.AttachedEntity is not {} user) + return; + + if (!_melee.TryGetWeapon(user, out var weaponUid, out var weapon)) + { + return; + } + + TryMeleeReset(weaponUid, weapon, true); + } + + + private void TryMeleeReset(EntityUid weaponUid, MeleeWeaponComponent weapon, bool disarm){ + if (!TryComp(weaponUid, out var reset)) + return; + + if (disarm) + weapon.NextAttack = reset.OriginalTime; + + RemComp(weaponUid); + Dirty(weaponUid, weapon); + } +} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Melee/StunOnHitComponent.cs b/Content.Shared/ADT/_RMC14/Weapons/Melee/StunOnHitComponent.cs new file mode 100644 index 00000000000..5e02a697afd --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Melee/StunOnHitComponent.cs @@ -0,0 +1,15 @@ +using Content.Shared.Whitelist; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Weapons.Melee; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(SharedRMCMeleeWeaponSystem))] +public sealed partial class StunOnHitComponent : Component +{ + [DataField, AutoNetworkedField] + public TimeSpan Duration = TimeSpan.FromSeconds(12); + + [DataField(required: true), AutoNetworkedField] + public EntityWhitelist Whitelist = new(); +} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/Ammo/GunToggleAmmoActionEvent.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/Ammo/GunToggleAmmoActionEvent.cs new file mode 100644 index 00000000000..f4ad89a5009 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/Ammo/GunToggleAmmoActionEvent.cs @@ -0,0 +1,5 @@ +using Content.Shared.Actions; + +namespace Content.Shared._RMC14.Weapons.Ranged.Ammo; + +public sealed partial class GunToggleAmmoActionEvent : InstantActionEvent; diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/Ammo/GunToggleableAmmoComponent.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/Ammo/GunToggleableAmmoComponent.cs new file mode 100644 index 00000000000..b1f14ea9776 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/Ammo/GunToggleableAmmoComponent.cs @@ -0,0 +1,32 @@ +using Content.Shared.Damage; +using Robust.Shared.Audio; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; +using Robust.Shared.Utility; + +namespace Content.Shared._RMC14.Weapons.Ranged.Ammo; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(GunToggleableAmmoSystem))] +public sealed partial class GunToggleableAmmoComponent : Component +{ + [DataField(required: true), AutoNetworkedField] + public List Settings = new(); + + [DataField, AutoNetworkedField] + public int Setting; + + [DataField, AutoNetworkedField] + public EntProtoId ActionId = "RMCActionToggleAmmo"; + + [DataField, AutoNetworkedField] + public EntityUid? Action; + + [DataField, AutoNetworkedField] + public SoundSpecifier ToggleSound = new SoundPathSpecifier("/Audio/Items/beep.ogg"); +} + +[DataRecord] +[Serializable, NetSerializable] +public readonly record struct GunToggleableAmmoSetting(DamageSpecifier Damage, int ArmorPiercing, LocId Name, SpriteSpecifier.Rsi Icon); diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/Ammo/GunToggleableAmmoSystem.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/Ammo/GunToggleableAmmoSystem.cs new file mode 100644 index 00000000000..9f01a294b25 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/Ammo/GunToggleableAmmoSystem.cs @@ -0,0 +1,95 @@ +using System.Runtime.InteropServices; +using Content.Shared._RMC14.Armor; +using Content.Shared._RMC14.Weapons.Common; +using Content.Shared.Actions; +using Content.Shared.Damage; +using Content.Shared.Popups; +using Content.Shared.Projectiles; +using Content.Shared.Weapons.Ranged.Events; +using Robust.Shared.Audio.Systems; + +namespace Content.Shared._RMC14.Weapons.Ranged.Ammo; + +public sealed class GunToggleableAmmoSystem : EntitySystem +{ + [Dependency] private readonly SharedActionsSystem _actions = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + + private EntityQuery _projectileQuery; + + public override void Initialize() + { + _projectileQuery = GetEntityQuery(); + + SubscribeLocalEvent(OnGetItemActions); + SubscribeLocalEvent(OnToggleAmmoAction); + SubscribeLocalEvent(OnAmmoShot); + SubscribeLocalEvent(OnUniqueAction); + } + + private void OnGetItemActions(Entity ent, ref GetItemActionsEvent args) + { + args.AddAction(ref ent.Comp.Action, ent.Comp.ActionId); + Dirty(ent); + } + + private void OnToggleAmmoAction(Entity ent, ref GunToggleAmmoActionEvent args) + { + if (ToggleAmmo(ent, args.Performer)) + args.Handled = true; + } + + private void OnAmmoShot(Entity ent, ref AmmoShotEvent args) + { + var settingIndex = ent.Comp.Setting; + if (settingIndex < 0 || settingIndex >= ent.Comp.Settings.Count) + return; + + ref var setting = ref CollectionsMarshal.AsSpan(ent.Comp.Settings)[settingIndex]; + foreach (var projectile in args.FiredProjectiles) + { + if (_projectileQuery.TryComp(projectile, out var projectileComp)) + { + projectileComp.Damage = new DamageSpecifier(setting.Damage); + Dirty(projectile, projectileComp); + } + } + } + + private void OnUniqueAction(Entity ent, ref UniqueActionEvent args) + { + if (args.Handled) + return; + + if (ToggleAmmo(ent, args.UserUid)) + args.Handled = true; + } + + private bool ToggleAmmo(Entity ent, EntityUid user) + { + if (ent.Comp.Settings.Count == 0) + return false; + + ref var settingIndex = ref ent.Comp.Setting; + settingIndex++; + if (settingIndex >= ent.Comp.Settings.Count) + settingIndex = 0; + + var setting = ent.Comp.Settings[settingIndex]; + var popup = Loc.GetString("rmc-toggleable-ammo-firing", ("ammo", Loc.GetString(setting.Name))); + _popup.PopupClient(popup, user, user, PopupType.Large); + + _audio.PlayPredicted(ent.Comp.ToggleSound, ent, user); + + if (_actions.TryGetActionData(ent.Comp.Action, out var action)) + { + action.Icon = setting.Icon; + Dirty(ent.Comp.Action.Value, action); + _actions.UpdateAction(ent.Comp.Action, action); + } + + Dirty(ent); + return true; + } +} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/BreechLoadedComponent.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/BreechLoadedComponent.cs new file mode 100644 index 00000000000..1fae1555f26 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/BreechLoadedComponent.cs @@ -0,0 +1,37 @@ +using Robust.Shared.Audio; +using Robust.Shared.GameStates; +using Robust.Shared.Serialization; + +namespace Content.Shared._RMC14.Weapons.Ranged; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(BreechLoadedSystem))] +public sealed partial class BreechLoadedComponent : Component +{ + [DataField, AutoNetworkedField] + public bool Open; + + /// + /// If this is set to true, the user must open and close the breech between every shot. + /// + [DataField, AutoNetworkedField] + public bool NeedOpenClose; + + [DataField, AutoNetworkedField] + public bool Ready; + + [DataField, AutoNetworkedField] + public SoundSpecifier OpenSound = new SoundPathSpecifier("/Audio/_RMC14/Weapons/Guns/Breech/ugl_open.ogg", AudioParams.Default.WithVolume(-6.5f)); + + [DataField, AutoNetworkedField] + public SoundSpecifier CloseSound = new SoundPathSpecifier("/Audio/_RMC14/Weapons/Guns/Breech/ugl_close.ogg", AudioParams.Default.WithVolume(-6.5f)); + + [DataField, AutoNetworkedField] + public bool ShowBreechOpen = true; +} + +[Serializable, NetSerializable] +public enum BreechVisuals : byte +{ + Open +} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/BreechLoadedSystem.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/BreechLoadedSystem.cs new file mode 100644 index 00000000000..7d88e042ca2 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/BreechLoadedSystem.cs @@ -0,0 +1,95 @@ +using Content.Shared._RMC14.Weapons.Common; +using Content.Shared.Examine; +using Content.Shared.Interaction; +using Content.Shared.Popups; +using Content.Shared.Tag; +using Content.Shared.Weapons.Ranged.Components; +using Content.Shared.Weapons.Ranged.Events; +using Content.Shared.Weapons.Ranged.Systems; +using Robust.Shared.Audio.Systems; +using Robust.Shared.GameObjects; + +namespace Content.Shared._RMC14.Weapons.Ranged; + +public sealed class BreechLoadedSystem : EntitySystem +{ + [Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!; + [Dependency] private readonly SharedAudioSystem _audioSystem = default!; + [Dependency] private readonly SharedGunSystem _gunSystem = default!; + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + [Dependency] private readonly TagSystem _tagSystem = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnAttemptShoot); + SubscribeLocalEvent(OnGunShot); + SubscribeLocalEvent(OnTryAmmoEject); + SubscribeLocalEvent(OnUniqueAction); + SubscribeLocalEvent(OnInteractUsing, + before: new[] { typeof(SharedGunSystem) }); + } + + private void OnAttemptShoot(Entity gun, ref AttemptShootEvent args) + { + if (args.Cancelled || !gun.Comp.Open && (!gun.Comp.NeedOpenClose || gun.Comp.Ready)) + return; + + args.Cancelled = true; + if (gun.Comp.Open) + _popupSystem.PopupClient(Loc.GetString("rmc-breech-loaded-open-shoot-attempt"), args.User, args.User); + else + _popupSystem.PopupClient(Loc.GetString("rmc-breech-loaded-not-ready-to-shoot"), args.User, args.User); + } + + private void OnGunShot(Entity gun, ref GunShotEvent args) + { + if (!gun.Comp.NeedOpenClose) + return; + + gun.Comp.Ready = false; + Dirty(gun); + } + + private void OnTryAmmoEject(Entity gun, ref RMCTryAmmoEjectEvent args) + { + if (gun.Comp.Open) + return; + + _popupSystem.PopupClient(Loc.GetString("rmc-breech-loaded-closed-extract-attempt"), args.User, args.User); + args.Cancelled = true; + } + + private void OnUniqueAction(Entity gun, ref UniqueActionEvent args) + { + if (args.Handled) + return; + + args.Handled = true; + + gun.Comp.Open = !gun.Comp.Open; + + if (!gun.Comp.Open) + gun.Comp.Ready = true; + + if (gun.Comp.ShowBreechOpen && TryComp(gun.Owner, out AppearanceComponent? appearanceComponent)) + _appearanceSystem.SetData(gun, BreechVisuals.Open, gun.Comp.Open, appearanceComponent); + + Dirty(gun); + var sound = gun.Comp.Open ? gun.Comp.OpenSound : gun.Comp.CloseSound; + //_audioSystem.PlayPredicted(sound, gun, args.UserUid, sound.Params); + _audioSystem.PlayPredicted(sound, gun, args.UserUid); + } + + private void OnInteractUsing(Entity gun, ref InteractUsingEvent args) + { + if (gun.Comp.Open || + !TryComp(gun.Owner, out BallisticAmmoProviderComponent? ammoProviderComponent) || + ammoProviderComponent.Whitelist == null || + ammoProviderComponent.Whitelist.Tags == null || + !_tagSystem.HasAnyTag(args.Used, ammoProviderComponent.Whitelist.Tags)) + return; + + _popupSystem.PopupClient(Loc.GetString("rmc-breech-loaded-closed-load-attempt"), args.User, args.User); + args.Handled = true; + } +} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/CMGunSystem.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/CMGunSystem.cs new file mode 100644 index 00000000000..cb75c4e3269 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/CMGunSystem.cs @@ -0,0 +1,107 @@ +using System.Numerics; +using Content.Shared._RMC14.Weapons.Common; +using Content.Shared.Containers.ItemSlots; +using Content.Shared.FixedPoint; +using Content.Shared.Hands; +using Content.Shared.Hands.Components; +using Content.Shared.Hands.EntitySystems; +using Content.Shared.Interaction; +using Content.Shared.Interaction.Components; +using Content.Shared.Inventory; +using Content.Shared.Physics; +using Content.Shared.Popups; +using Content.Shared.Projectiles; +using Content.Shared.Timing; +using Content.Shared.Weapons.Ranged; +using Content.Shared.Weapons.Ranged.Components; +using Content.Shared.Weapons.Ranged.Events; +using Content.Shared.Weapons.Ranged.Systems; +using Content.Shared.Whitelist; +using Content.Shared.Wieldable; +using Content.Shared.Wieldable.Components; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Containers; +using Robust.Shared.Physics; +using Robust.Shared.Physics.Components; +using Robust.Shared.Physics.Events; +using Robust.Shared.Physics.Systems; +using Robust.Shared.Random; +using Robust.Shared.Timing; + +namespace Content.Shared._RMC14.Weapons.Ranged; + +public sealed class CMGunSystem : EntitySystem +{ + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedBroadphaseSystem _broadphase = default!; + [Dependency] private readonly SharedContainerSystem _container = default!; + [Dependency] private readonly SharedGunSystem _gun = default!; + [Dependency] private readonly InventorySystem _inventory = default!; + [Dependency] private readonly ItemSlotsSystem _slots = default!; + [Dependency] private readonly SharedHandsSystem _hands = default!; + [Dependency] private readonly SharedPhysicsSystem _physics = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly UseDelaySystem _useDelay = default!; + + private EntityQuery _physicsQuery; + private EntityQuery _projectileQuery; + + private readonly int _blockArcCollisionGroup = (int) (CollisionGroup.HighImpassable | CollisionGroup.Impassable); + + public override void Initialize() + { + _physicsQuery = GetEntityQuery(); + _projectileQuery = GetEntityQuery(); + + SubscribeLocalEvent(OnAmmoEjectActivateInWorld); + } + + private void OnAmmoEjectActivateInWorld(Entity gun, ref ActivateInWorldEvent args) + { + if (args.Handled || + !_container.TryGetContainer(gun.Owner, gun.Comp.ContainerID, out var container) || + container.ContainedEntities.Count <= 0 || + !_hands.TryGetActiveHand(args.User, out var hand) || + !hand.IsEmpty || + !_hands.CanPickupToHand(args.User, container.ContainedEntities[0], hand)) + { + return; + } + + var cancelEvent = new RMCTryAmmoEjectEvent(args.User, false); + RaiseLocalEvent(gun.Owner, ref cancelEvent); + + if (cancelEvent.Cancelled) + return; + + args.Handled = true; + + var ejectedAmmo = container.ContainedEntities[0]; + + // For guns with a BallisticAmmoProviderComponent, if you just remove the ammo from its container, the gun system thinks it's still in the gun and you can still shoot it. + // So instead I'm having to inflict this shit on our codebase. + if (TryComp(gun.Owner, out BallisticAmmoProviderComponent? ammoProviderComponent)) + { + var takeAmmoEvent = new TakeAmmoEvent(1, new List<(EntityUid?, IShootable)>(), Transform(gun.Owner).Coordinates, args.User); + RaiseLocalEvent(gun.Owner, takeAmmoEvent); + + if (takeAmmoEvent.Ammo.Count <= 0) + return; + + var ammo = takeAmmoEvent.Ammo[0].Entity; + + if (ammo == null) + return; + + ejectedAmmo = ammo.Value; + } + + if (!HasComp(gun.Owner) || !_slots.TryEject(gun.Owner, gun.Comp.ContainerID, args.User, out _, excludeUserAudio: true)) + _audio.PlayPredicted(gun.Comp.EjectSound, gun.Owner, args.User); + + _hands.TryPickup(args.User, ejectedAmmo, hand); + } +} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/GetDamageFalloffEvent.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/GetDamageFalloffEvent.cs new file mode 100644 index 00000000000..ab26799cc93 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/GetDamageFalloffEvent.cs @@ -0,0 +1,8 @@ +using Content.Shared.FixedPoint; + +namespace Content.Shared._RMC14.Weapons.Ranged; + +[ByRefEvent] +public record struct GetDamageFalloffEvent( + FixedPoint2 FalloffMultiplier +); diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/GetFireModeValuesEvent.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/GetFireModeValuesEvent.cs new file mode 100644 index 00000000000..433472abed5 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/GetFireModeValuesEvent.cs @@ -0,0 +1,5 @@ + +namespace Content.Shared._RMC14.Weapons.Ranged; + +[ByRefEvent] +public record struct GetFireModeValuesEvent(double BurstScatterMult); diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/GetFireModesEvent.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/GetFireModesEvent.cs new file mode 100644 index 00000000000..5b75428729e --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/GetFireModesEvent.cs @@ -0,0 +1,6 @@ +using Content.Shared.Weapons.Ranged.Components; + +namespace Content.Shared._RMC14.Weapons.Ranged; + +[ByRefEvent] +public record struct GetFireModesEvent(SelectiveFire Modes, SelectiveFire Set = SelectiveFire.Invalid); diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/GetGunDamageModifierEvent.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/GetGunDamageModifierEvent.cs new file mode 100644 index 00000000000..37c8d401259 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/GetGunDamageModifierEvent.cs @@ -0,0 +1,6 @@ +using Content.Shared.FixedPoint; + +namespace Content.Shared._RMC14.Weapons.Ranged; + +[ByRefEvent] +public record struct GetGunDamageModifierEvent(FixedPoint2 Multiplier); diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/GunGetFireRateEvent.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/GunGetFireRateEvent.cs new file mode 100644 index 00000000000..84767763441 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/GunGetFireRateEvent.cs @@ -0,0 +1,5 @@ +namespace Content.Shared._RMC14.Weapons.Ranged; + + +[ByRefEvent] +public record struct GunGetFireRateEvent(float FireRate); diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/PumpActionComponent.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/PumpActionComponent.cs new file mode 100644 index 00000000000..706f29f0dd9 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/PumpActionComponent.cs @@ -0,0 +1,30 @@ +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Weapons.Ranged; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(SharedPumpActionSystem))] +public sealed partial class PumpActionComponent : Component +{ + [DataField, AutoNetworkedField] + public bool Pumped; + + [DataField, AutoNetworkedField] + public SoundSpecifier Sound = new SoundCollectionSpecifier("CMShotgunPump"); + + [DataField, AutoNetworkedField] + public LocId Examine = "cm-gun-pump-examine"; + + [DataField, AutoNetworkedField] + public LocId Popup = "cm-gun-pump-first"; + + [DataField, AutoNetworkedField] + public LocId PopupKey = "cm-gun-pump-first-with"; + + [DataField, AutoNetworkedField] + public bool Once; + + [DataField, AutoNetworkedField] + public string ContainerId = "gun_magazine"; +} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/RMCAmmoEjectComponent.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/RMCAmmoEjectComponent.cs new file mode 100644 index 00000000000..e4837ff9fb7 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/RMCAmmoEjectComponent.cs @@ -0,0 +1,23 @@ +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Weapons.Ranged; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(CMGunSystem))] +public sealed partial class RMCAmmoEjectComponent : Component +{ + /// + /// The ID of the container from which ammo should be ejected. + /// + [DataField, AutoNetworkedField] + public string ContainerID = "gun_magazine"; + + /// + /// This is the sound that will play if the container ID does not match an item slot on the weapon. + /// Otherwise, the item slot's eject sound will play instead. + /// This field is mainly for weapons that use BallisticAmmoProviderComponent to store their ammo, like grenade launchers and pump-action shotguns. + /// + [DataField, AutoNetworkedField] + public SoundSpecifier EjectSound = new SoundPathSpecifier("/Audio/Items/beep.ogg", AudioParams.Default.WithVolume(-2f)); +} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/RMCFireGroupComponent.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/RMCFireGroupComponent.cs new file mode 100644 index 00000000000..42c54a0d0d3 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/RMCFireGroupComponent.cs @@ -0,0 +1,30 @@ +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Weapons.Ranged; + +/// +/// Fire group component which prevents things like shotgun juggling. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(SharedFireGroupSystem))] +public sealed partial class RMCFireGroupComponent : Component +{ + /// + /// The fire group of the item + /// + [DataField, AutoNetworkedField] + public string Group = string.Empty; + + /// + /// How long the other gun(s) are delayed for + /// + [DataField, AutoNetworkedField] + public TimeSpan Delay = TimeSpan.FromSeconds(1); + + /// + /// The UseDelay ID + /// + [DataField, AutoNetworkedField] + public string UseDelayID = "RMCFireGroupDelay"; +} \ No newline at end of file diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/RMCFireModeChangedEvent.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/RMCFireModeChangedEvent.cs new file mode 100644 index 00000000000..22642ae3988 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/RMCFireModeChangedEvent.cs @@ -0,0 +1,6 @@ +using Content.Shared.Weapons.Ranged.Components; + +namespace Content.Shared._RMC14.Weapons.Ranged; + +[ByRefEvent] +public record struct RMCFireModeChangedEvent; diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/RMCSelectiveFireComponent.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/RMCSelectiveFireComponent.cs new file mode 100644 index 00000000000..fe153c6739c --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/RMCSelectiveFireComponent.cs @@ -0,0 +1,130 @@ +using Content.Shared.Weapons.Ranged.Components; +using Robust.Shared.GameStates; +using Robust.Shared.Serialization; + +namespace Content.Shared._RMC14.Weapons.Ranged; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(RMCSelectiveFireSystem))] +public sealed partial class RMCSelectiveFireComponent : Component +{ + /// + /// The base fire modes available to the weapon. This will override what's set in the weapon's GunComponent. + /// + [DataField, AutoNetworkedField] + public SelectiveFire BaseFireModes = SelectiveFire.SemiAuto; + + /// + /// The base recoil when the weapon is wielded. + /// + [DataField, AutoNetworkedField] + public float RecoilWielded = 1f; + + /// + /// The base recoil when the weapon is not wielded. + /// + [DataField, AutoNetworkedField] + public float RecoilUnwielded = 1f; + + /// + /// Equivalent to GunComponent.AngleIncrease. + /// This exists to properly reset the angle increase after switching firemodes. + /// This generally should not be changed. Instead, use ShotsToMaxScatter in the relevant firemode's entry in Modifiers. + /// + [DataField, AutoNetworkedField] + public Angle ScatterIncrease = Angle.FromDegrees(0.0); + + /// + /// Equivalent to GunComponent.AngleDecay. + /// This should not be changed. RMC guns reset their scatter to the minimum instantly after shooting. + /// This is here to make sure the scatter decay doesn't get overriden by something someone sets in the weapon's GunComponent. + /// + [DataField, AutoNetworkedField] + public Angle ScatterDecay = Angle.FromDegrees(0.0); + + /// + /// Equivalent to GunComponent.MinAngle and GunComponent.MaxAngle + /// This is the base scatter value for a wielded weapon. + /// Scatter is the angle of the cone within which your shots deviate from where your cursor is. + /// Conversion from 13 guns: scatter * 2 + /// + [DataField, AutoNetworkedField] + public Angle ScatterWielded = Angle.FromDegrees(10.0); + + /// + /// Equivalent to GunComponent.MinAngle and GunComponent.MaxAngle + /// This is the base scatter value for an unwielded weapon. + /// Scatter is the angle of the cone within which your shots deviate from where your cursor is. + /// Conversion from 13 guns: scatter_unwielded * 2 + /// + [DataField, AutoNetworkedField] + public Angle ScatterUnwielded = Angle.FromDegrees(10.0); + + /// + /// Equivalent to GunComponent.FireRate. + /// This is how many shots a weapon fires per second. + /// Conversion from 13 guns: 1 / (fire_delay / 10) + /// + [DataField, AutoNetworkedField] + public float BaseFireRate = 1.429f; + + /// + /// This is the multiplier applied to the additional scatter added by a SelectiveFireModifierSet with UseBurstScatterMult set to true. + /// Conversion from 13 guns: burst_scatter_mult + /// + [DataField, AutoNetworkedField] + public double BurstScatterMult = 4.0; + + /// + /// This is the modified burst scatter multiplier. This should not be set manually, it's handled by RMCSelectiveFireSystem. + /// + [DataField, AutoNetworkedField] + public double BurstScatterMultModified = 4.0; + + /// + /// This dictionary contains the modifiers used for different firemodes. + /// If a firemode isn't in here, it doesn't get any of the modifiers applied to it and will not have variable scatter. + /// + [DataField, AutoNetworkedField] + public Dictionary Modifiers = new() + { + { SelectiveFire.Burst, new SelectiveFireModifierSet(0.1f, 10.0, true, 2.0, 6) }, + { SelectiveFire.FullAuto, new SelectiveFireModifierSet(0f, 26.0, true, 2.0, 4) } + }; +} + +[DataRecord, Serializable, NetSerializable] +public record struct SelectiveFireModifierSet( + /// + /// Additional fire delay applied to the weapon when this mode is active. + /// A weapon's fire delay is the delay in seconds between each shot. It's inversely proportionate to the weapon's rate of fire. + /// Conversion from rate of fire: 1 / FireRate + /// Conversion from 13 guns for burst fire: burst_delay / 10 * 0.666. Due to how burst delay is handled in 13, we need the 0.666. + /// + float FireDelay, + + /// + /// A flat modifier applied to the weapon's maximum scatter. + /// This is multiplied by UnwieldedScatterMultiplier if the weapon is not wielded and by BurstScatterMultModified if UseBurstScatterMult is true. + /// This modifier will never reduce the weapon's scatter — only increase it or keep it the same — even if made negative by its multipliers. + /// Conversion from 13 guns for burst fire: 10 + /// Conversion from 13 guns for fully-automatic fire: fa_max_scatter * 2 + /// + double MaxScatterModifier, + + /// + /// If this is set to true, the additional scatter added by this modifier set will be multiplied by BurstScatterMultModified. + /// + bool UseBurstScatterMult, + + /// + /// The additional scatter added by this modifier set will be multiplied by this value if the weapon is not wielded. + /// + double UnwieldedScatterMultiplier, + + /// + /// This determines how many shots it takes to reach maximum scatter. + /// If it's set to null, the weapon will not accumulate scatter when firing. + /// + int? ShotsToMaxScatter +); diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/RMCSelectiveFireSystem.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/RMCSelectiveFireSystem.cs new file mode 100644 index 00000000000..74129a495e0 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/RMCSelectiveFireSystem.cs @@ -0,0 +1,231 @@ +using Content.Shared._RMC14.Attachable.Systems; +using Content.Shared._RMC14.Input; +using Content.Shared.Examine; +using Content.Shared.Weapons.Ranged.Components; +using Content.Shared.Weapons.Ranged.Events; +using Content.Shared.Weapons.Ranged.Systems; +using Content.Shared.Wieldable; +using Content.Shared.Wieldable.Components; +using Robust.Shared.Input.Binding; + +namespace Content.Shared._RMC14.Weapons.Ranged; + +public sealed class RMCSelectiveFireSystem : EntitySystem +{ + [Dependency] private readonly SharedGunSystem _gunSystem = default!; + + private const string scatterExamineColour = "yellow"; + + private const SelectiveFire allFireModes = SelectiveFire.SemiAuto | SelectiveFire.Burst | SelectiveFire.FullAuto; + + public override void Initialize() + { + SubscribeAllEvent(OnStopShootRequest); + + SubscribeLocalEvent(OnExamine); + SubscribeLocalEvent(SelectiveFireRefreshWield, + after: new[] { typeof(AttachableHolderSystem) }); + SubscribeLocalEvent(SelectiveFireRefreshWield, + after: new[] { typeof(AttachableHolderSystem) }); + SubscribeLocalEvent(OnSelectiveFireMapInit); + SubscribeLocalEvent(OnSelectiveFireModeChanged); + + CommandBinds.Builder + .Bind(CMKeyFunctions.RMCCycleFireMode, + InputCmdHandler.FromDelegate(session => + { + if (session?.AttachedEntity is { } userUid && _gunSystem.TryGetGun(userUid, out var gunUid, out var gunComponent)) + { + _gunSystem.CycleFire(gunUid, gunComponent, userUid); + } + }, + handle: false)) + .Register(); + } + + private void OnStopShootRequest(RequestStopShootEvent ev, EntitySessionEventArgs args) + { + var gunUid = GetEntity(ev.Gun); + + if (args.SenderSession.AttachedEntity == null || + !TryComp(gunUid, out GunComponent? gunComponent) || + !_gunSystem.TryGetGun(args.SenderSession.AttachedEntity.Value, out _, out var userGun)) + { + return; + } + + if (userGun != gunComponent) + return; + + gunComponent.CurrentAngle = gunComponent.MinAngleModified; + Dirty(gunUid, gunComponent); + } + + private void OnExamine(Entity gun, ref ExaminedEvent args) + { + if (!args.IsInDetailsRange || !TryComp(gun.Owner, out GunComponent? gunComponent)) + return; + + using (args.PushGroup(nameof(RMCSelectiveFireComponent))) + { + args.PushMarkup(Loc.GetString("rmc-examine-text-scatter-max", ("colour", scatterExamineColour), ("scatter", gunComponent.MaxAngleModified.Degrees))); + args.PushMarkup(Loc.GetString("rmc-examine-text-scatter-min", ("colour", scatterExamineColour), ("scatter", gunComponent.MinAngleModified.Degrees))); + + if (ContainsMods(gun, gunComponent.SelectedMode)) + { + var mods = gun.Comp.Modifiers[gunComponent.SelectedMode]; + if (mods.ShotsToMaxScatter != null) + args.PushMarkup(Loc.GetString("rmc-examine-text-shots-to-max-scatter", ("colour", scatterExamineColour), ("shots", mods.ShotsToMaxScatter))); + } + } + } + +#region Refresh calls + private void OnSelectiveFireMapInit(Entity gun, ref MapInitEvent args) + { + gun.Comp.BurstScatterMultModified = gun.Comp.BurstScatterMult; + RefreshFireModes((gun.Owner, gun.Comp), true); + } + + private void OnSelectiveFireModeChanged(Entity gun, ref RMCFireModeChangedEvent args) + { + RefreshFireModeGunValues(gun); + } + + private void SelectiveFireRefreshWield(Entity gun, ref T args) where T : notnull + { + RefreshWieldableFireModeValues(gun); + } +#endregion + +#region Refresh methods + public void RefreshFireModeGunValues(Entity gun) + { + if (!TryComp(gun.Owner, out GunComponent? gunComponent)) + return; + + gunComponent.AngleIncrease = gun.Comp.ScatterIncrease; + gunComponent.AngleDecay = gun.Comp.ScatterDecay; + + var ev = new GunGetFireRateEvent(gunComponent.SelectedMode == SelectiveFire.Burst ? gun.Comp.BaseFireRate * 2 : gun.Comp.BaseFireRate); + RaiseLocalEvent(gun, ref ev); + gunComponent.FireRate = ev.FireRate; + + if (ContainsMods(gun, gunComponent.SelectedMode)) + { + var mods = gun.Comp.Modifiers[gunComponent.SelectedMode]; + ev = new GunGetFireRateEvent(1f / (1f / gunComponent.FireRate + mods.FireDelay)); + RaiseLocalEvent(gun, ref ev); + gunComponent.FireRate = ev.FireRate; + } + + RefreshWieldableFireModeValues(gun); + } + + public bool ContainsMods(Entity gun, SelectiveFire mode) + { + return gun.Comp.Modifiers.ContainsKey(mode); + } + + public void RefreshWieldableFireModeValues(Entity gun) + { + if (!TryComp(gun.Owner, out GunComponent? gunComponent)) + return; + + bool wielded = TryComp(gun.Owner, out WieldableComponent? wieldableComponent) && wieldableComponent.Wielded; + + gunComponent.CameraRecoilScalar = wielded ? gun.Comp.RecoilWielded : gun.Comp.RecoilUnwielded; + gunComponent.MinAngle = wielded ? gun.Comp.ScatterWielded : gun.Comp.ScatterUnwielded; + gunComponent.MaxAngle = gunComponent.MinAngle; + + RefreshBurstScatter((gun.Owner, gun.Comp)); + + _gunSystem.RefreshModifiers(gun.Owner); + gunComponent.CurrentAngle = gunComponent.MinAngleModified; + } + + public void RefreshFireModes(Entity gun, bool forceValueRefresh = false) + { + if (gun.Comp == null && !TryComp(gun.Owner, out gun.Comp) || !TryComp(gun.Owner, out GunComponent? gunComponent)) + return; + + var initialMode = gunComponent.SelectedMode; + + var ev = new GetFireModesEvent(gun.Comp.BaseFireModes); + RaiseLocalEvent(gun.Owner, ref ev); + + SetFireModes((gun.Owner, gunComponent), ev.Modes, !(forceValueRefresh || initialMode != gunComponent.SelectedMode)); + + if (TryComp(gun, out GunComponent? gunComp) && + (gunComp.AvailableModes & ev.Set) != SelectiveFire.Invalid) + { + _gunSystem.SelectFire(gun, gunComponent, ev.Set); + } + + if (forceValueRefresh || initialMode != gunComponent.SelectedMode) + RefreshFireModeGunValues((gun.Owner, gun.Comp)); + } + + public void RefreshModifiableFireModeValues(Entity gun) + { + if (gun.Comp == null && !TryComp(gun.Owner, out gun.Comp)) + return; + + var ev = new GetFireModeValuesEvent(gun.Comp.BurstScatterMult); + RaiseLocalEvent(gun.Owner, ref ev); + + gun.Comp.BurstScatterMultModified = ev.BurstScatterMult; + + RefreshWieldableFireModeValues((gun.Owner, gun.Comp)); + } + + private void RefreshBurstScatter(Entity gun) + { + if (!TryComp(gun.Owner, out GunComponent? gunComponent)) + return; + + bool wielded = TryComp(gun.Owner, out WieldableComponent? wieldableComponent) && wieldableComponent.Wielded; + + if (ContainsMods(gun, gunComponent.SelectedMode)) + { + var mods = gun.Comp.Modifiers[gunComponent.SelectedMode]; + var mult = mods.UseBurstScatterMult ? gun.Comp.BurstScatterMultModified : 1.0; + gunComponent.MaxAngle = wielded + ? Angle.FromDegrees(Math.Max(gunComponent.MinAngle.Degrees + mods.MaxScatterModifier * mult, gunComponent.MinAngle.Degrees)) + : Angle.FromDegrees(Math.Max(gunComponent.MinAngle.Degrees + mods.MaxScatterModifier * mult * mods.UnwieldedScatterMultiplier, gunComponent.MinAngle.Degrees)); + + if (mods.ShotsToMaxScatter != null) + gunComponent.AngleIncrease = new Angle(((double)(gunComponent.MaxAngle - gunComponent.MinAngle)) / mods.ShotsToMaxScatter.Value); + } + } +#endregion + +#region Firemode changes + public void AddFireMode(Entity gun, SelectiveFire newMode) + { + if (gun.Comp == null && !TryComp(gun.Owner, out gun.Comp)) + return; + + gun.Comp.AvailableModes |= newMode; + Dirty(gun); + } + + public void SetFireModes(Entity gun, SelectiveFire modes, bool dirty = true) + { + if (gun.Comp == null && !TryComp(gun.Owner, out gun.Comp) || (modes & allFireModes) == SelectiveFire.Invalid) + return; + + gun.Comp.AvailableModes = allFireModes; + + while ((gun.Comp.SelectedMode & modes) != gun.Comp.SelectedMode) + _gunSystem.CycleFire(gun.Owner, gun.Comp); + + gun.Comp.AvailableModes = modes; + + if (!dirty) + return; + + Dirty(gun); + } +#endregion +} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/RMCTryAmmoEjectEvent.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/RMCTryAmmoEjectEvent.cs new file mode 100644 index 00000000000..82d66ace88e --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/RMCTryAmmoEjectEvent.cs @@ -0,0 +1,8 @@ + +namespace Content.Shared._RMC14.Weapons.Ranged; + +[ByRefEvent] +public record struct RMCTryAmmoEjectEvent( + EntityUid User, + bool Cancelled +); diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/Recoil/GunToggleRecoilActionEvent.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/Recoil/GunToggleRecoilActionEvent.cs new file mode 100644 index 00000000000..f317eb59449 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/Recoil/GunToggleRecoilActionEvent.cs @@ -0,0 +1,5 @@ +using Content.Shared.Actions; + +namespace Content.Shared._RMC14.Weapons.Ranged.Recoil; + +public sealed partial class GunToggleRecoilActionEvent : InstantActionEvent; diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/Recoil/GunToggleableRecoilComponent.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/Recoil/GunToggleableRecoilComponent.cs new file mode 100644 index 00000000000..6eb8c790c1e --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/Recoil/GunToggleableRecoilComponent.cs @@ -0,0 +1,25 @@ +using Robust.Shared.Audio; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared._RMC14.Weapons.Ranged.Recoil; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(GunToggleableRecoilSystem))] +public sealed partial class GunToggleableRecoilComponent : Component +{ + [DataField, AutoNetworkedField] + public bool Active; + + [DataField, AutoNetworkedField] + public float BatteryDrain = 1.25f; + + [DataField, AutoNetworkedField] + public EntProtoId ActionId = "RMCActionToggleRecoil"; + + [DataField, AutoNetworkedField] + public EntityUid? Action; + + [DataField, AutoNetworkedField] + public SoundSpecifier ToggleSound = new SoundPathSpecifier("/Audio/_RMC14/Machines/click.ogg"); +} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/Recoil/GunToggleableRecoilSystem.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/Recoil/GunToggleableRecoilSystem.cs new file mode 100644 index 00000000000..32b5c611faf --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/Recoil/GunToggleableRecoilSystem.cs @@ -0,0 +1,63 @@ +using Content.Shared.Actions; +using Content.Shared.Popups; +using Content.Shared.Weapons.Ranged.Events; +using Content.Shared.Weapons.Ranged.Systems; +using Robust.Shared.Audio.Systems; + +namespace Content.Shared._RMC14.Weapons.Ranged.Recoil; + +public sealed class GunToggleableRecoilSystem : EntitySystem +{ + [Dependency] private readonly SharedActionsSystem _actions = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedGunSystem _gun = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnGetItemActions); + SubscribeLocalEvent(OnToggleRecoil); + SubscribeLocalEvent(OnRefreshModifiers); + } + + private void OnGetItemActions(Entity ent, ref GetItemActionsEvent args) + { + args.AddAction(ref ent.Comp.Action, ent.Comp.ActionId); + Dirty(ent); + } + + private void OnToggleRecoil(Entity ent, ref GunToggleRecoilActionEvent args) + { + args.Handled = true; + ent.Comp.Active = !ent.Comp.Active; + ActiveChanged(ent, args.Performer); + } + + private void OnRefreshModifiers(Entity ent, ref GunRefreshModifiersEvent args) + { + if (!ent.Comp.Active) + return; + + args.MinAngle = Angle.Zero; + args.MaxAngle = Angle.Zero; + args.CameraRecoilScalar = 0; + } + + private void ActiveChanged(Entity ent, EntityUid? user) + { + Dirty(ent); + + _actions.SetToggled(ent.Comp.Action, ent.Comp.Active); + _gun.RefreshModifiers(ent.Owner); + + _audio.PlayPredicted(ent.Comp.ToggleSound, ent.Owner, user); + + if (user == null) + return; + + var popup = ent.Comp.Active + ? Loc.GetString("rmc-toggleable-recoil-compensation-on", ("gun", ent.Owner)) + : Loc.GetString("rmc-toggleable-recoil-compensation-off", ("gun", ent.Owner)); + _popup.PopupClient(popup, user.Value, user.Value, PopupType.Large); + } +} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/SharedFireGroupSystem.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/SharedFireGroupSystem.cs new file mode 100644 index 00000000000..41835613805 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/SharedFireGroupSystem.cs @@ -0,0 +1,55 @@ +using Content.Shared.Hands.EntitySystems; +using Content.Shared.Timing; +using Content.Shared.Weapons.Ranged.Events; +using Content.Shared.Weapons.Ranged.Systems; + +namespace Content.Shared._RMC14.Weapons.Ranged; + +public sealed class SharedFireGroupSystem : EntitySystem +{ + [Dependency] private readonly UseDelaySystem _delay = default!; + [Dependency] private readonly SharedHandsSystem _hands = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnGunShot); + SubscribeLocalEvent(OnShotAttempt); + } + + private void OnGunShot(Entity ent, ref GunShotEvent args) + { + var weapon = ent.Owner; + var comp = ent.Comp; + var user = args.User; + + foreach (var item in _hands.EnumerateHeld(user)) + { + if (TryComp(item, out var fireGroup)) + { + if (item == weapon) + continue; + + if (fireGroup.Group != comp.Group) + continue; + + if (!TryComp(item, out UseDelayComponent? useDelay)) + continue; + + var itemEnt = (item, useDelay); + _delay.SetLength(itemEnt, comp.Delay, comp.UseDelayID); + _delay.TryResetDelay(itemEnt, true, id: comp.UseDelayID); + } + } + } + + public void OnShotAttempt(Entity ent, ref ShotAttemptedEvent args) + { + if (!TryComp(ent.Owner, out UseDelayComponent? useDelayComponent) || + !_delay.IsDelayed((ent.Owner, useDelayComponent), ent.Comp.UseDelayID)) + { + return; + } + + args.Cancel(); + } +} \ No newline at end of file diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/SharedPumpActionSystem.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/SharedPumpActionSystem.cs new file mode 100644 index 00000000000..718b33ccca8 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/SharedPumpActionSystem.cs @@ -0,0 +1,79 @@ +using Content.Shared._RMC14.Weapons.Common; +using Content.Shared.Examine; +using Content.Shared.Popups; +using Content.Shared.Weapons.Ranged.Events; +using Content.Shared.Weapons.Ranged.Systems; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Containers; + +namespace Content.Shared._RMC14.Weapons.Ranged; + +public abstract class SharedPumpActionSystem : EntitySystem +{ + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnExamined, before: [typeof(SharedGunSystem)]); + SubscribeLocalEvent(OnAttemptShoot); + SubscribeLocalEvent(OnGunShot); + SubscribeLocalEvent(OnUniqueAction); + SubscribeLocalEvent(OnEntRemovedFromContainer); + } + + protected virtual void OnExamined(Entity ent, ref ExaminedEvent args) + { + // TODO RMC14 the server has no idea what this keybind is supposed to be for the client + args.PushMarkup(Loc.GetString(ent.Comp.Examine), 1); + } + + protected virtual void OnAttemptShoot(Entity ent, ref AttemptShootEvent args) + { + if (!ent.Comp.Pumped) + args.Cancelled = true; + } + + private void OnGunShot(Entity ent, ref GunShotEvent args) + { + if (ent.Comp.Once) + return; + + ent.Comp.Pumped = false; + Dirty(ent); + } + + private void OnUniqueAction(Entity ent, ref UniqueActionEvent args) + { + if (args.Handled) + return; + + var ammo = new GetAmmoCountEvent(); + RaiseLocalEvent(ent.Owner, ref ammo); + + if (ammo.Count <= 0) + { + _popup.PopupClient(Loc.GetString("cm-gun-no-ammo-message"), args.UserUid, args.UserUid); + args.Handled = true; + return; + } + + if (!ent.Comp.Running || ent.Comp.Pumped) + return; + + ent.Comp.Pumped = true; + Dirty(ent); + + args.Handled = true; + + _audio.PlayPredicted(ent.Comp.Sound, ent, args.UserUid); + } + + private void OnEntRemovedFromContainer(Entity ent, ref EntRemovedFromContainerMessage args) + { + if (args.Container.ID != ent.Comp.ContainerId || !ent.Comp.Once) + return; + + ent.Comp.Pumped = false; + } +} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/ShootUseDelayComponent.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/ShootUseDelayComponent.cs new file mode 100644 index 00000000000..adcced44242 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/ShootUseDelayComponent.cs @@ -0,0 +1,6 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Weapons.Ranged; + +[RegisterComponent, NetworkedComponent] +public sealed partial class ShootUseDelayComponent : Component; diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/ShootUseDelaySystem.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/ShootUseDelaySystem.cs new file mode 100644 index 00000000000..41d20abb757 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/ShootUseDelaySystem.cs @@ -0,0 +1,27 @@ +using Content.Shared.Timing; +using Content.Shared.Weapons.Ranged.Components; +using Content.Shared.Weapons.Ranged.Events; +using Content.Shared.Weapons.Ranged.Systems; + +namespace Content.Shared._RMC14.Weapons.Ranged; + +public sealed class ShootUseDelaySystem : EntitySystem +{ + [Dependency] private readonly UseDelaySystem _useDelay = default!; + + private const string shootUseDelayId = "CMShootUseDelay"; + + public override void Initialize() + { + SubscribeLocalEvent(OnGunShot); + } + + private void OnGunShot(Entity ent, ref GunShotEvent args) + { + if (!TryComp(ent, out UseDelayComponent? delayComponent) || !TryComp(ent, out GunComponent? gunComponent)) + return; + + _useDelay.SetLength((ent.Owner, delayComponent), TimeSpan.FromSeconds(1f / gunComponent.FireRate), shootUseDelayId); + _useDelay.TryResetDelay((ent.Owner, delayComponent), true, id: shootUseDelayId); + } +} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/Stacks/GunStacksComponent.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/Stacks/GunStacksComponent.cs new file mode 100644 index 00000000000..5884f17bb26 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/Stacks/GunStacksComponent.cs @@ -0,0 +1,31 @@ +using Content.Shared.FixedPoint; +using Robust.Shared.GameStates; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; + +namespace Content.Shared._RMC14.Weapons.Ranged.Stacks; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause] +[Access(typeof(GunStacksSystem))] +public sealed partial class GunStacksComponent : Component +{ + [DataField, AutoNetworkedField] + public int IncreaseAP = 10; + + [DataField, AutoNetworkedField] + public int MaxAP = 50; + + [DataField, AutoNetworkedField] + public FixedPoint2 DamageIncrease = FixedPoint2.New(0.5); + + [DataField, AutoNetworkedField] + public float SetFireRate = 1.4285f; + + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField, AutoPausedField] + public TimeSpan LastHitAt; + + [DataField, AutoNetworkedField] + public TimeSpan StacksExpire = TimeSpan.FromSeconds(4); + + [DataField, AutoNetworkedField] + public int Hits; +} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/Stacks/GunStacksProjectileComponent.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/Stacks/GunStacksProjectileComponent.cs new file mode 100644 index 00000000000..1e9c0221cd1 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/Stacks/GunStacksProjectileComponent.cs @@ -0,0 +1,11 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Weapons.Ranged.Stacks; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(GunStacksSystem))] +public sealed partial class GunStacksProjectileComponent : Component +{ + [DataField, AutoNetworkedField] + public EntityUid? Gun; +} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/Stacks/GunStacksSystem.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/Stacks/GunStacksSystem.cs new file mode 100644 index 00000000000..8fad757bd1b --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/Stacks/GunStacksSystem.cs @@ -0,0 +1,97 @@ +using Content.Shared._RMC14.Armor; +using Content.Shared.Interaction.Events; +using Content.Shared.Mobs.Systems; +using Content.Shared.Popups; +using Content.Shared.Projectiles; +using Content.Shared.Weapons.Ranged.Events; +using Robust.Shared.Network; +using Robust.Shared.Timing; + +namespace Content.Shared._RMC14.Weapons.Ranged.Stacks; + +public sealed class GunStacksSystem : EntitySystem +{ + [Dependency] private readonly MobStateSystem _mobState = default!; + [Dependency] private readonly INetManager _net = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly RMCSelectiveFireSystem _rmcSelectiveFire = default!; + [Dependency] private readonly IGameTiming _timing = default!; + + private EntityQuery _gunStacksQuery; + private EntityQuery _selectiveFireQuery; + + public override void Initialize() + { + _gunStacksQuery = GetEntityQuery(); + _selectiveFireQuery = GetEntityQuery(); + + SubscribeLocalEvent(OnStacksGetGunDamageModifier); + SubscribeLocalEvent(OnStacksGetGunFireRate); + SubscribeLocalEvent(OnStacksAmmoShot); + SubscribeLocalEvent(OnStacksDropped); + + SubscribeLocalEvent(OnStacksProjectileHit); + } + + private void OnStacksGetGunDamageModifier(Entity ent, ref GetGunDamageModifierEvent args) + { + if (ent.Comp.Hits > 0) + args.Multiplier += ent.Comp.DamageIncrease; + } + + private void OnStacksGetGunFireRate(Entity ent, ref GunGetFireRateEvent args) + { + if (ent.Comp.Hits > 0) + args.FireRate = ent.Comp.SetFireRate; + } + + private void OnStacksAmmoShot(Entity ent, ref AmmoShotEvent args) + { + var time = _timing.CurTime; + if (ent.Comp.Hits > 0 && time >= ent.Comp.LastHitAt + ent.Comp.StacksExpire) + { + ent.Comp.Hits = 0; + Dirty(ent); + } + + foreach (var bullet in args.FiredProjectiles) + { + var stacks = EnsureComp(bullet); + stacks.Gun = ent; + Dirty(bullet, stacks); + + var ap = Math.Min(ent.Comp.MaxAP, ent.Comp.IncreaseAP * ent.Comp.Hits); + } + } + + private void OnStacksDropped(Entity ent, ref DroppedEvent args) + { + Reset(ent); + } + + private void OnStacksProjectileHit(Entity ent, ref ProjectileHitEvent args) + { + if (!_gunStacksQuery.TryComp(ent.Comp.Gun, out var gun)) + return; + + if (TryComp(ent, out ProjectileComponent? projectile) && + projectile.DamagedEntity) + { + return; + } + + var target = args.Target; + + + if (_selectiveFireQuery.TryComp(ent.Comp.Gun, out var selective)) + _rmcSelectiveFire.RefreshFireModeGunValues((ent.Comp.Gun.Value, selective)); + + Dirty(ent); + } + + private void Reset(Entity gun) + { + gun.Comp.Hits = 0; + Dirty(gun); + } +} diff --git a/Content.Shared/ADT/_RMC14/Wieldable/Components/WieldDelayComponent.cs b/Content.Shared/ADT/_RMC14/Wieldable/Components/WieldDelayComponent.cs new file mode 100644 index 00000000000..53ce8febf5c --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Wieldable/Components/WieldDelayComponent.cs @@ -0,0 +1,18 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Wieldable.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(RMCWieldableSystem))] +public sealed partial class WieldDelayComponent : Component +{ + /// + /// The base delay which is then modified by attachments. + /// Conversion from 13: SS13_WIELD_DELAY / 10 + /// + [DataField, AutoNetworkedField] + public TimeSpan BaseDelay = TimeSpan.FromSeconds(0.4); + + [DataField, AutoNetworkedField] + public TimeSpan ModifiedDelay = TimeSpan.FromSeconds(0.4); +} diff --git a/Content.Shared/ADT/_RMC14/Wieldable/Components/WieldSlowdownCompensationComponent.cs b/Content.Shared/ADT/_RMC14/Wieldable/Components/WieldSlowdownCompensationComponent.cs new file mode 100644 index 00000000000..ef09741d814 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Wieldable/Components/WieldSlowdownCompensationComponent.cs @@ -0,0 +1,26 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Wieldable; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(RMCWieldableSystem))] +public sealed partial class WieldSlowdownCompensationComponent : Component +{ + // The generic conversion formula from move delay to additive speed multiplier is as follows: 1 / (1 / SS14_SPEED + SS13_MOVE_DELAY / 10) / SS14_SPEED - 1 + // The formulae below already have the default human speeds inserted. Use them when converting from SS13. + /// + /// This is the amount by which the additive speed multiplier from wielded items is changed. This one applies to walking speed. + /// Converting to an additive multiplier from SS13 move delay: 1 / (0.4 + SS13_MOVE_DELAY / 10) / 2.5 - 1 + /// Since this is supposed to increase speed, take the negative of the result. + /// + [DataField, AutoNetworkedField] + public float Walk = 0f; + + /// + /// This is the amount by which the additive speed multiplier from wielded items is changed. This one applies to sprinting speed. + /// Converting to an additive multiplier from SS13 move delay: 1 / (0.22 + SS13_MOVE_DELAY / 10) / 4.5 - 1 + /// Since this is supposed to increase speed, take the negative of the result. + /// + [DataField, AutoNetworkedField] + public float Sprint = 0f; +} diff --git a/Content.Shared/ADT/_RMC14/Wieldable/Components/WieldSlowdownCompensationUserComponent.cs b/Content.Shared/ADT/_RMC14/Wieldable/Components/WieldSlowdownCompensationUserComponent.cs new file mode 100644 index 00000000000..179d69e3ca2 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Wieldable/Components/WieldSlowdownCompensationUserComponent.cs @@ -0,0 +1,14 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Wieldable; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(RMCWieldableSystem))] +public sealed partial class WieldSlowdownCompensationUserComponent : Component +{ + [DataField, AutoNetworkedField] + public float Walk = 0f; + + [DataField, AutoNetworkedField] + public float Sprint = 0f; +} diff --git a/Content.Shared/ADT/_RMC14/Wieldable/Components/WieldableSpeedModifiersComponent.cs b/Content.Shared/ADT/_RMC14/Wieldable/Components/WieldableSpeedModifiersComponent.cs new file mode 100644 index 00000000000..e1dcf6842e4 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Wieldable/Components/WieldableSpeedModifiersComponent.cs @@ -0,0 +1,30 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Wieldable.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(RMCWieldableSystem))] +public sealed partial class WieldableSpeedModifiersComponent : Component +{ + // Generic formula: 1 / (1 / SS14_MOVE_SPEED + SS13_MOVE_DELAY / 10) / SS14_MOVE_SPEED + // Since dynamically calculating this isn't practical with how changing movespeed works, the formulae below have the default movement speeds already inserted. + /// + /// The base multiplier, which is then altered by attachments and armour movement compensation. + /// Formula for conversion from 13: 1 / (0.4 + SS13_MOVE_DELAY / 10) / 2.5 + /// + [DataField, AutoNetworkedField] + public float BaseWalk = 1f; + + [DataField, AutoNetworkedField] + public float ModifiedWalk = 1f; + + /// + /// The base multiplier, which is then altered by attachments and armour movement compensation. + /// Formula for conversion from 13: 1 / (0.22 + SS13_MOVE_DELAY / 10) / 4.5 + /// + [DataField, AutoNetworkedField] + public float BaseSprint = 1f; + + [DataField, AutoNetworkedField] + public float ModifiedSprint = 1f; +} diff --git a/Content.Shared/ADT/_RMC14/Wieldable/Events/GetWieldDelayEvent.cs b/Content.Shared/ADT/_RMC14/Wieldable/Events/GetWieldDelayEvent.cs new file mode 100644 index 00000000000..50be9d994b7 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Wieldable/Events/GetWieldDelayEvent.cs @@ -0,0 +1,7 @@ + +namespace Content.Shared._RMC14.Wieldable.Events; + +[ByRefEvent] +public record struct GetWieldDelayEvent( + TimeSpan Delay +); diff --git a/Content.Shared/ADT/_RMC14/Wieldable/Events/GetWieldableSpeedModifiersEvent.cs b/Content.Shared/ADT/_RMC14/Wieldable/Events/GetWieldableSpeedModifiersEvent.cs new file mode 100644 index 00000000000..85617314da2 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Wieldable/Events/GetWieldableSpeedModifiersEvent.cs @@ -0,0 +1,8 @@ + +namespace Content.Shared._RMC14.Wieldable.Events; + +[ByRefEvent] +public record struct GetWieldableSpeedModifiersEvent( + float Walk, + float Sprint +); diff --git a/Content.Shared/ADT/_RMC14/Wieldable/Events/RefreshWieldSlowdownCompensationEvent.cs b/Content.Shared/ADT/_RMC14/Wieldable/Events/RefreshWieldSlowdownCompensationEvent.cs new file mode 100644 index 00000000000..f89da3ee296 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Wieldable/Events/RefreshWieldSlowdownCompensationEvent.cs @@ -0,0 +1,10 @@ +using Content.Shared.Inventory; + +namespace Content.Shared._RMC14.Wieldable; + +[ByRefEvent] +public record struct RefreshWieldSlowdownCompensationEvent( + SlotFlags TargetSlots, + float Walk = 0f, + float Sprint = 0f +) : IInventoryRelayEvent; diff --git a/Content.Shared/ADT/_RMC14/Wieldable/RMCWieldableSystem.cs b/Content.Shared/ADT/_RMC14/Wieldable/RMCWieldableSystem.cs new file mode 100644 index 00000000000..0c8755b06f3 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Wieldable/RMCWieldableSystem.cs @@ -0,0 +1,234 @@ +using Content.Shared._RMC14.Wieldable.Components; +using Content.Shared._RMC14.Wieldable.Events; +using Content.Shared.Hands; +using Content.Shared.Hands.Components; +using Content.Shared.Interaction.Events; +using Content.Shared.Inventory; +using Content.Shared.Inventory.Events; +using Content.Shared.Movement.Systems; +using Content.Shared.Popups; +using Content.Shared.Timing; +using Content.Shared.Weapons.Ranged.Events; +using Content.Shared.Wieldable; +using Content.Shared.Wieldable.Components; +using Robust.Shared.Containers; +using Robust.Shared.Prototypes; +using Robust.Shared.Timing; + +namespace Content.Shared._RMC14.Wieldable; + +public sealed class RMCWieldableSystem : EntitySystem +{ + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly InventorySystem _inventorySystem = default!; + [Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifierSystem = default!; + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + [Dependency] private readonly UseDelaySystem _useDelaySystem = default!; + [Dependency] private readonly SharedContainerSystem _container = default!; + + private const string WieldUseDelayID = "RMCWieldDelay"; + + public override void Initialize() + { + SubscribeLocalEvent(OnGotEquippedHand); + SubscribeLocalEvent(OnGotUnequippedHand); + SubscribeLocalEvent>(OnRefreshMovementSpeedModifiers); + SubscribeLocalEvent(OnItemUnwielded); + SubscribeLocalEvent(OnItemWielded); + SubscribeLocalEvent(OnMapInit); + + SubscribeLocalEvent(OnGotEquipped); + SubscribeLocalEvent(OnGotUnequipped); + + SubscribeLocalEvent(OnGotEquippedHand); + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnUseInHand); + SubscribeLocalEvent(OnShotAttempt); + SubscribeLocalEvent(OnItemWieldedWithDelay); + + + SubscribeLocalEvent(_inventorySystem.RelayEvent); + } + + private void OnMapInit(Entity wieldable, ref MapInitEvent args) + { + RefreshSpeedModifiers((wieldable.Owner, wieldable.Comp)); + } + + private void OnMapInit(Entity wieldable, ref MapInitEvent args) + { + wieldable.Comp.ModifiedDelay = wieldable.Comp.BaseDelay; + } + + #region Wield speed modifiers + private void OnGotEquippedHand(Entity wieldable, ref GotEquippedHandEvent args) + { + _movementSpeedModifierSystem.RefreshMovementSpeedModifiers(args.User); + } + + private void OnGotUnequippedHand(Entity wieldable, ref GotUnequippedHandEvent args) + { + _movementSpeedModifierSystem.RefreshMovementSpeedModifiers(args.User); + } + + private void OnRefreshMovementSpeedModifiers(Entity wieldable, ref HeldRelayedEvent args) + { + if (TryComp(wieldable.Owner, out TransformComponent? transformComponent) && + transformComponent.ParentUid.Valid && + TryComp(transformComponent.ParentUid, out WieldSlowdownCompensationUserComponent? userComponent)) + { + args.Args.ModifySpeed( + Math.Min(wieldable.Comp.ModifiedWalk + userComponent.Walk, 1f), + Math.Min(wieldable.Comp.ModifiedSprint + userComponent.Sprint, 1f)); + return; + } + + args.Args.ModifySpeed(wieldable.Comp.ModifiedWalk, wieldable.Comp.ModifiedSprint); + } + + public void RefreshSpeedModifiers(Entity wieldable) + { + wieldable.Comp = EnsureComp(wieldable); + + var walkSpeed = wieldable.Comp.BaseWalk; + var sprintSpeed = wieldable.Comp.BaseSprint; + + if (!TryComp(wieldable.Owner, out WieldableComponent? wieldableComponent) || !wieldableComponent.Wielded) + { + walkSpeed = 1f; + sprintSpeed = 1f; + } + + var ev = new GetWieldableSpeedModifiersEvent(walkSpeed, sprintSpeed); + RaiseLocalEvent(wieldable, ref ev); + + wieldable.Comp.ModifiedWalk = ev.Walk > 0 ? ev.Walk : 0; + wieldable.Comp.ModifiedSprint = ev.Sprint > 0 ? ev.Sprint : 0; + + RefreshModifiersOnParent(wieldable.Owner); + } + + private void OnItemUnwielded(Entity wieldable, ref ItemUnwieldedEvent args) + { + RefreshSpeedModifiers((wieldable.Owner, wieldable.Comp)); + } + + private void OnItemWielded(Entity wieldable, ref ItemWieldedEvent args) + { + RefreshSpeedModifiers((wieldable.Owner, wieldable.Comp)); + } + + private void RefreshModifiersOnParent(EntityUid wieldableUid) + { + if (!TryComp(wieldableUid, out TransformComponent? transformComponent) || + !transformComponent.ParentUid.Valid || + !TryComp(transformComponent.ParentUid, out HandsComponent? handsComponent) || + handsComponent.ActiveHandEntity != wieldableUid) + { + return; + } + + _movementSpeedModifierSystem.RefreshMovementSpeedModifiers(transformComponent.ParentUid); + } + #endregion + + + #region Wield slowdown compensation + private void OnGotEquipped(Entity armour, ref GotEquippedEvent args) + { + EnsureComp(args.Equipee, out WieldSlowdownCompensationUserComponent comp); + + RefreshWieldSlowdownCompensation((args.Equipee, comp)); + } + + private void OnGotUnequipped(Entity armour, ref GotUnequippedEvent args) + { + EnsureComp(args.Equipee, out WieldSlowdownCompensationUserComponent comp); + + RefreshWieldSlowdownCompensation((args.Equipee, comp)); + } + + private void RefreshWieldSlowdownCompensation(Entity user) + { + var ev = new RefreshWieldSlowdownCompensationEvent(~SlotFlags.POCKET); + RaiseLocalEvent(user.Owner, ref ev); + + user.Comp.Walk = ev.Walk; + user.Comp.Walk = ev.Sprint; + } + + private void OnRefreshWieldSlowdownCompensation(Entity armour, ref InventoryRelayedEvent args) + { + args.Args.Walk += armour.Comp.Walk; + args.Args.Sprint += armour.Comp.Sprint; + } + #endregion + + #region Wield delay + private void OnGotEquippedHand(Entity wieldable, ref GotEquippedHandEvent args) + { + _useDelaySystem.SetLength(wieldable.Owner, wieldable.Comp.ModifiedDelay, WieldUseDelayID); + _useDelaySystem.TryResetDelay(wieldable.Owner, id: WieldUseDelayID); + } + + private void OnUseInHand(Entity wieldable, ref UseInHandEvent args) + { + if (!TryComp(wieldable.Owner, out UseDelayComponent? useDelayComponent) || + !_useDelaySystem.IsDelayed((wieldable.Owner, useDelayComponent), WieldUseDelayID)) + { + return; + } + + args.Handled = true; + + if (!_useDelaySystem.TryGetDelayInfo((wieldable.Owner, useDelayComponent), out var info, WieldUseDelayID)) + { + return; + } + + var time = $"{(info.EndTime - _timing.CurTime).TotalSeconds:F1}"; + + _popupSystem.PopupClient(Loc.GetString("rmc-wield-use-delay", ("seconds", time), ("wieldable", wieldable.Owner)), args.User, args.User); + } + + public void RefreshWieldDelay(Entity wieldable) + { + wieldable.Comp = EnsureComp(wieldable); + + var ev = new GetWieldDelayEvent(wieldable.Comp.BaseDelay); + RaiseLocalEvent(wieldable, ref ev); + + wieldable.Comp.ModifiedDelay = ev.Delay >= TimeSpan.Zero ? ev.Delay : TimeSpan.Zero; + } + + private void OnItemWieldedWithDelay(Entity wieldable, ref ItemWieldedEvent args) + { + // TODO RMC14 +0.5s if Dazed + var skillModifiedDelay = wieldable.Comp.ModifiedDelay; + + if (_container.TryGetContainingContainer((wieldable, null), out var container)) + skillModifiedDelay -= TimeSpan.FromSeconds(0.2) * 1; // ADT ЗАТЫЧКА + + _useDelaySystem.SetLength(wieldable.Owner, skillModifiedDelay, WieldUseDelayID); + _useDelaySystem.TryResetDelay(wieldable.Owner, id: WieldUseDelayID); + } + + public void OnShotAttempt(Entity wieldable, ref ShotAttemptedEvent args) + { + if (!TryComp(wieldable.Owner, out UseDelayComponent? useDelayComponent) || + !_useDelaySystem.IsDelayed((wieldable.Owner, useDelayComponent), WieldUseDelayID) || + !_useDelaySystem.TryGetDelayInfo((wieldable.Owner, useDelayComponent), out var info, WieldUseDelayID)) + { + return; + } + + args.Cancel(); + + var time = $"{(info.EndTime - _timing.CurTime).TotalSeconds:F1}"; + + //_popupSystem.PopupClient(Loc.GetString("rmc-shoot-use-delay", ("seconds", time), ("wieldable", wieldable.Owner)), args.User, args.User); + // Uncomment when there's a cooldown on popups from a source. + } + + #endregion +} diff --git a/Content.Shared/Actions/AttachableToggleActionEvent.cs b/Content.Shared/Actions/AttachableToggleActionEvent.cs new file mode 100644 index 00000000000..7b108cf0a0f --- /dev/null +++ b/Content.Shared/Actions/AttachableToggleActionEvent.cs @@ -0,0 +1,3 @@ +namespace Content.Shared.Actions.Events; + +public sealed partial class AttachableToggleActionEvent : InstantActionEvent; diff --git a/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs index f25273f4039..a2164473d21 100644 --- a/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs +++ b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs @@ -431,7 +431,7 @@ public bool TryGetAvailableSlot(Entity ent, return true; } - private static int SortEmpty(ItemSlot a, ItemSlot b) + public static int SortEmpty(ItemSlot a, ItemSlot b) { var aEnt = a.ContainerSlot?.ContainedEntity; var bEnt = b.ContainerSlot?.ContainedEntity; diff --git a/Content.Shared/Damage/Systems/DamageableSystem.cs b/Content.Shared/Damage/Systems/DamageableSystem.cs index 3c3e1b736df..2b2ab48f46c 100644 --- a/Content.Shared/Damage/Systems/DamageableSystem.cs +++ b/Content.Shared/Damage/Systems/DamageableSystem.cs @@ -124,7 +124,7 @@ public void DamageChanged(EntityUid uid, DamageableComponent component, DamageSp /// null if the user had no applicable components that can take damage. /// public DamageSpecifier? TryChangeDamage(EntityUid? uid, DamageSpecifier damage, bool ignoreResistances = false, - bool interruptsDoAfters = true, DamageableComponent? damageable = null, EntityUid? origin = null) + bool interruptsDoAfters = true, DamageableComponent? damageable = null, EntityUid? origin = null, EntityUid? tool = null) { if (!uid.HasValue || !_damageableQuery.Resolve(uid.Value, ref damageable, false)) { @@ -154,7 +154,7 @@ public void DamageChanged(EntityUid uid, DamageableComponent component, DamageSp damage = DamageSpecifier.ApplyModifierSet(damage, modifierSet); } - var ev = new DamageModifyEvent(damage, origin); + var ev = new DamageModifyEvent(damage, origin, tool); RaiseLocalEvent(uid.Value, ev); damage = ev.Damage; @@ -303,12 +303,15 @@ public sealed class DamageModifyEvent : EntityEventArgs, IInventoryRelayEvent public readonly DamageSpecifier OriginalDamage; public DamageSpecifier Damage; public EntityUid? Origin; + public EntityUid? Tool; - public DamageModifyEvent(DamageSpecifier damage, EntityUid? origin = null) + + public DamageModifyEvent(DamageSpecifier damage, EntityUid? origin = null, EntityUid? tool = null) { OriginalDamage = damage; Damage = damage; Origin = origin; + Tool = tool; } } diff --git a/Content.Shared/Projectiles/ProjectileComponent.cs b/Content.Shared/Projectiles/ProjectileComponent.cs index c24cf2b5ee5..cf5f45c75c4 100644 --- a/Content.Shared/Projectiles/ProjectileComponent.cs +++ b/Content.Shared/Projectiles/ProjectileComponent.cs @@ -73,4 +73,12 @@ public sealed partial class ProjectileComponent : Component /// [DataField] public bool DamagedEntity; + + /// + /// Sets the maximum range for a projectile fired with ShootAtFixedPointComponent. + /// This can be set on both the Projectile and ShootAtFixedPoint Components. + /// The default value is null for no cap. The minimum value between the two is used. + /// + [DataField, AutoNetworkedField] + public float? MaxFixedRange; } diff --git a/Content.Shared/Sound/SharedEmitSoundSystem.cs b/Content.Shared/Sound/SharedEmitSoundSystem.cs index 8733edf485d..e9e80bcfd36 100644 --- a/Content.Shared/Sound/SharedEmitSoundSystem.cs +++ b/Content.Shared/Sound/SharedEmitSoundSystem.cs @@ -136,6 +136,11 @@ private void OnEmitSoundOnInteractUsing(Entity +/// This is used to allow ranged weapons to make melee attacks by right-clicking. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(SharedMeleeWeaponSystem))] +public sealed partial class AltFireMeleeComponent : Component +{ + [DataField, AutoNetworkedField] + public AltFireAttackType AttackType = AltFireAttackType.Light; +} + + +[Flags] +public enum AltFireAttackType : byte +{ + Light = 0, // Standard single-target attack. + Heavy = 1 << 0, // Wide swing. + Disarm = 1 << 1 +} diff --git a/Content.Shared/Weapons/Ranged/Components/GunComponent.cs b/Content.Shared/Weapons/Ranged/Components/GunComponent.cs index b404221abfc..5d8641387d6 100644 --- a/Content.Shared/Weapons/Ranged/Components/GunComponent.cs +++ b/Content.Shared/Weapons/Ranged/Components/GunComponent.cs @@ -4,11 +4,12 @@ using Robust.Shared.GameStates; using Robust.Shared.Map; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; +using Content.Shared._RMC14.Weapons.Ranged; namespace Content.Shared.Weapons.Ranged.Components; [RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause] -[Access(typeof(SharedGunSystem))] +[Access(typeof(SharedGunSystem), typeof(RMCSelectiveFireSystem))] public sealed partial class GunComponent : Component { #region Sound diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Interactions.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Interactions.cs index f3ff89a660e..3e88559b855 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Interactions.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Interactions.cs @@ -4,6 +4,7 @@ using Content.Shared.Verbs; using Content.Shared.Weapons.Ranged.Components; using Robust.Shared.Utility; +using Content.Shared._RMC14.Weapons.Ranged; namespace Content.Shared.Weapons.Ranged.Systems; @@ -61,7 +62,7 @@ private SelectiveFire GetNextMode(GunComponent component) return modes[(index + 1) % modes.Count]; } - private void SelectFire(EntityUid uid, GunComponent component, SelectiveFire fire, EntityUid? user = null) + public void SelectFire(EntityUid uid, GunComponent component, SelectiveFire fire, EntityUid? user = null) { if (component.SelectedMode == fire) return; @@ -82,6 +83,10 @@ private void SelectFire(EntityUid uid, GunComponent component, SelectiveFire fir Audio.PlayPredicted(component.SoundMode, uid, user); Popup(Loc.GetString("gun-selected-mode", ("mode", GetLocSelector(fire))), uid, user); + + var ev = new RMCFireModeChangedEvent(); + RaiseLocalEvent(uid, ref ev); + Dirty(uid, component); } diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs index 6bf64c7e5fe..bcff3f0cfb6 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs @@ -375,7 +375,7 @@ private void AttemptShoot(EntityUid user, EntityUid gunUid, GunComponent gun) // Shoot confirmed - sounds also played here in case it's invalid (e.g. cartridge already spent). Shoot(gunUid, gun, ev.Ammo, fromCoordinates, toCoordinates.Value, out var userImpulse, user, throwItems: attemptEv.ThrowItems); - var shotEv = new GunShotEvent(user, ev.Ammo); + var shotEv = new GunShotEvent(user, ev.Ammo, fromCoordinates, toCoordinates.Value); RaiseLocalEvent(gunUid, ref shotEv); if (userImpulse && TryComp(user, out var userPhysics)) @@ -579,7 +579,7 @@ public record struct AttemptShootEvent(EntityUid User, string? Message, bool Can /// /// The user that fired this gun. [ByRefEvent] -public record struct GunShotEvent(EntityUid User, List<(EntityUid? Uid, IShootable Shootable)> Ammo); +public record struct GunShotEvent(EntityUid User, List<(EntityUid? Uid, IShootable Shootable)> Ammo, EntityCoordinates FromCoordinates, EntityCoordinates ToCoordinates); public enum EffectLayers : byte { diff --git a/Resources/Prototypes/ADT/_RMC14/Actions/Marines/marine_action_base.yml b/Resources/Prototypes/ADT/_RMC14/Actions/Marines/marine_action_base.yml new file mode 100644 index 00000000000..2c4891bfe51 --- /dev/null +++ b/Resources/Prototypes/ADT/_RMC14/Actions/Marines/marine_action_base.yml @@ -0,0 +1,4 @@ +- type: entity + id: ActionMarineBase + categories: + - HideSpawnMenu diff --git a/Resources/Prototypes/ADT/_RMC14/Actions/Marines/marine_action_items.yml b/Resources/Prototypes/ADT/_RMC14/Actions/Marines/marine_action_items.yml new file mode 100644 index 00000000000..514c2535b74 --- /dev/null +++ b/Resources/Prototypes/ADT/_RMC14/Actions/Marines/marine_action_items.yml @@ -0,0 +1,73 @@ +- type: entity + parent: ActionMarineBase + id: CMActionToggleScope + name: Toggle Optics + description: Scope in or out with your optics. + components: + - type: InstantAction + icon: + sprite: _RMC14/Actions/scope_actions.rsi + state: sniperscope + event: !type:ToggleActionEvent + useDelay: 0.25 + +- type: entity + parent: ActionMarineBase + id: RMCActionCycleZoomLevel + name: Cycle Zoom Level + description: Change the level of magnification of your optics. + components: + - type: InstantAction + icon: + sprite: _RMC14/Actions/scope_actions.rsi + state: sniperscope + event: !type:ScopeCycleZoomLevelEvent + useDelay: 0.25 + - type: Tag + tags: + - RMCActionCycleZoomLevel + +- type: entity + parent: ActionMarineBase + id: CMActionToggleScoutVision + name: Toggle the M42 scout sight + description: Allows you to see even in complete darkness. + components: + - type: InstantAction + icon: + sprite: _RMC14/Objects/Clothing/Eyes/Glasses/m42_scoutsight.rsi + state: icon + iconOn: + sprite: _RMC14/Objects/Clothing/Eyes/Glasses/m42_scoutsight.rsi + state: icon_on + event: !type:ToggleActionEvent + useDelay: 0.25 + +- type: entity + parent: ActionMarineBase + id: CMActionToggleAttachable + name: Toggle Attachable + description: Toggle an attachable. If you're seeing this, someone forgot to set the description properly. + components: + - type: InstantAction + icon: + sprite: _RMC14/Actions/scope_actions.rsi + state: sniperscope + event: !type:AttachableToggleActionEvent + +- type: entity + parent: ActionMarineBase + id: RMCActionWhistle + name: Whistle + description: Blow the whistle. + components: + - type: InstantAction + itemIconStyle: NoItem + icon: + sprite: _RMC14/Objects/Devices/whistle.rsi + state: whistle + event: !type:SoundActionEvent + useDelay: 10 + +- type: Tag + id: RMCActionCycleZoomLevel diff --git a/Resources/Prototypes/ADT/_RMC14/test.yml b/Resources/Prototypes/ADT/_RMC14/test.yml new file mode 100644 index 00000000000..2e4bd64acbe --- /dev/null +++ b/Resources/Prototypes/ADT/_RMC14/test.yml @@ -0,0 +1,366 @@ +- type: entity + abstract: true + id: RMCBaseAttachableHolder + components: + - type: AttachableHolder + - type: ItemSizeChange + - type: ActivatableUI + verbText: rmc-verb-strip-attachables + verbOnly: true + key: + enum.AttachmentUI.StripKey + - type: UserInterface + interfaces: + enum.AttachmentUI.StripKey: + type: AttachmentStripBui + enum.AttachmentUI.ChooseSlotKey: + type: AttachmentChooseSlotBui + +- type: entity + abstract: true + id: RMCBaseMeleeWeapon + +- type: entity + abstract: true + parent: RMCBaseMeleeWeapon + id: CMBaseWeaponGun + components: + - type: Clothing + quickEquip: false + - type: UseDelay + delay: 0 + - type: WieldDelay + - type: AltFireMelee + - type: MeleeWeapon + resetOnHandSelected: false + attackRate: 1 + damage: + types: + Blunt: 5 + soundHit: + collection: GenericHit + - type: Gun + meleeCooldownOnShoot: false + resetOnHandSelected: false + +- type: entity + parent: BaseBullet + id: RMCBaseBullet + components: + - type: Sprite + sprite: _RMC14/Objects/Weapons/Guns/Ammunition/Projectiles/bullet_projectiles.rsi + layers: + - state: bullet + shader: unshaded + +# BASE ======================================================================================================= + +- type: entity + abstract: true + parent: [ CMBaseWeaponGun, BaseItem, RMCBaseAttachableHolder ] + id: CMBaseWeaponRifle + components: + - type: Gun + shotsPerBurst: 3 + selectedMode: Burst + availableModes: + - SemiAuto + - Burst + - type: RMCSelectiveFire + baseFireModes: + - SemiAuto + - Burst + recoilWielded: 1 + recoilUnwielded: 4 + scatterWielded: 10 + scatterUnwielded: 20 + baseFireRate: 1.429 + burstScatterMult: 4 + modifiers: + Burst: + fireDelay: 0.1665 + maxScatterModifier: 10 + useBurstScatterMult: true + unwieldedScatterMultiplier: 2 + shotsToMaxScatter: 6 + FullAuto: + maxScatterModifier: 13 + useBurstScatterMult: true + unwieldedScatterMultiplier: 2 + shotsToMaxScatter: 4 + - type: Wieldable + - type: WieldableSpeedModifiers + baseWalk: 0.8 + baseSprint: 0.69 + - type: WieldDelay + baseDelay: 0.6 + - type: Item + size: Large + - type: Clothing + sprite: Objects/Weapons/Guns/SMGs/atreides.rsi + slots: + - suitStorage + - Back + - type: AmmoCounter + - type: ContainerContainer + containers: + gun_magazine: !type:ContainerSlot + gun_chamber: !type:ContainerSlot + - type: StaticPrice + price: 500 + - type: MagazineAmmoProvider + autoEject: true + - type: MagazineVisuals + magState: mag + steps: 1 + zeroVisible: true + - type: Appearance + - type: Sprite + sprite: Objects/Weapons/Guns/SMGs/atreides.rsi + layers: + - state: base + map: ["enum.GunVisualLayers.Base"] + - state: mag-0 + map: ["enum.GunVisualLayers.Mag"] + +- type: entity + parent: BaseMagazineRifle + id: CMMagazineRifleBase + name: "M5 'Night Raider' bayonet" + description: The standard-issue bayonet of the Marines. + abstract: true + components: + - type: Item + size: Normal + - type: Appearance + - type: Clothing + slots: + - suitStorage + - type: Sprite + sprite: Objects/Weapons/Guns/Ammunition/Magazine/CaselessRifle/caseless_rifle_mag.rsi + layers: + - state: base + map: ["enum.GunVisualLayers.Base"] + - state: mag-1 + map: ["enum.GunVisualLayers.Mag"] + - type: MagazineVisuals + magState: mag + steps: 2 + zeroVisible: false + - type: Tag + tags: + - CMMagazineRifle + + +- type: entity + parent: BaseCartridgeRifle + id: CMBaseCartridgeRifle + name: cartridge + abstract: true + components: + - type: CartridgeAmmo + deleteOnSpawn: true + - type: Sprite + sprite: Objects/Weapons/Guns/Ammunition/Casings/ammo_casing.rsi + layers: + - state: base + map: ["enum.AmmoVisualLayers.Base"] + +- type: Tag + id: CMMagazineRifle +- type: Tag + id: RMCAttachmentUnderbarrel +- type: Tag + id: RMCAttachmentU1GrenadeLauncher +# ================================ ATTACHMENT +- type: entity + parent: BaseItem + abstract: true + id: RMCAttachableBase + components: + - type: Item + size: Small + - type: Attachable + +- type: entity + parent: RMCAttachableBase + abstract: true + id: RMCAttachableToggleableBase + components: + - type: AttachableToggleable + - type: UseDelay + delay: 0 + +# =========== KNIFE + +- type: entity + parent: [ RMCBaseMeleeWeapon, BaseKnife, RMCAttachableBase ] + id: RMCM5Bayonet + name: "M5 'Night Raider' bayonet" + description: The standard-issue bayonet of the Marines. You can slide this knife into your boots. # TODO RMC14 , or attach it to the end of a rifle. + components: + - type: Clothing + slots: + - mask + - pocket + - suitstorage + sprite: Objects/Weapons/Melee/kitchen_knife.rsi + - type: Tag + tags: + - RMCM5Bayonet + - Knife + - RMCAttachmentBarrel + - type: Sprite + sprite: Objects/Weapons/Melee/kitchen_knife.rsi + state: icon + - type: Item + sprite: Objects/Weapons/Melee/kitchen_knife.rsi + size: Small + - type: MeleeWeapon + wideAnimationRotation: -135 + attackRate: 1 + damage: + types: + Slash: 25 + - type: DamageOtherOnHit + damage: + types: + Slash: 18 + - type: DisarmMalus + malus: 0.225 + - type: AttachableVisuals + rsi: Objects/Weapons/Melee/kitchen_knife.rsi + prefix: icon + - type: AttachableWeaponMeleeMods + modifiers: + - bonusDamage: + types: + Slash: 20 + - type: AttachableWeaponRangedMods + modifiers: + - conditions: + unwieldedOnly: true + accuracyAddMult: -0.05 + - type: AttachablePrying + +- type: Tag + id: RMCAttachmentBarrel +- type: Tag + id: RMCM5Bayonet +- type: entity + abstract: true + parent: RMCAttachableBase + id: RMCBarrelAttachmentBase + components: + - type: Sprite + sprite: Objects/Weapons/Melee/kitchen_knife.rsi + - type: Tag + tags: + - RMCAttachmentBarrel + +# =============================== RIFLE +- type: entity + parent: CMBaseWeaponRifle + name: M54C assault rifle MK2 + id: WeaponRifleM54C + description: The standard issue rifle of the Marines. Commonly carried by most combat personnel. Uses 10x24mm caseless ammunition. + components: + - type: ContainerContainer + containers: + gun_magazine: !type:ContainerSlot + gun_chamber: !type:ContainerSlot + - type: Gun + selectedMode: FullAuto + availableModes: + - SemiAuto + - Burst + - FullAuto + - type: RMCSelectiveFire + baseFireModes: + - SemiAuto + - Burst + - FullAuto + recoilUnwielded: 4 + scatterWielded: 6 + scatterUnwielded: 20 + baseFireRate: 4 + burstScatterMult: 1 + - type: ItemSlots + slots: + gun_magazine: + name: Magazine + priority: 2 + whitelist: + tags: + - CMMagazineRifle + - type: AttachableHolder + slots: + rmc-aslot-barrel: + whitelist: + tags: + - RMCM5Bayonet + rmc-aslot-underbarrel: + whitelist: + tags: + - RMCAttachmentU1GrenadeLauncher + - type: AttachableHolderVisuals + offsets: + rmc-aslot-barrel: 0.75, 0.00 + rmc-aslot-underbarrel: 0.75, 0.00 + +- type: entity + abstract: true + parent: RMCAttachableBase + id: RMCUnderAttachmentBase + components: + - type: Sprite + sprite: Objects/Weapons/Melee/kitchen_knife.rsi + - type: Tag + tags: + - RMCAttachmentUnderbarrel + +- type: entity + parent: [ RMCUnderAttachmentBase, RMCAttachableToggleableBase, BaseItem ] + id: RMCAttachmentU1GrenadeLauncher + name: U1 grenade launcher + description: A weapon-mounted, reloadable grenade launcher. + components: + - type: ContainerContainer + containers: + ballistic-ammo: !type:Container + ents: [] + - type: RMCAmmoEject + containerID: ballistic-ammo + - type: AmmoCounter + - type: Gun + projectileSpeed: 20 + resetOnHandSelected: false + - type: RMCSelectiveFire + baseFireRate: 0.417 + - type: BallisticAmmoProvider + cycleable: false + whitelist: + tags: + - CartridgeRocket + capacity: 3 + - type: UniqueAction + - type: Appearance + - type: AttachableToggleable + userOnly: true + attachedOnly: true + supercedeHolder: true + wieldedUseOnly: true + activatePopupText: attachable-popup-switch-to-generic + deactivatePopupText: attachable-popup-switch-from-generic + actionName: Switch to the U1 Grenade Launcher + actionDesc: Switch to using the underbarrel grenade launcher. + - type: Tag + tags: + - RMCAttachmentUnderbarrel + - RMCAttachmentU1GrenadeLauncher + - type: Sprite + sprite: Objects/Weapons/Melee/kitchen_knife.rsi + state: icon + - type: Item + sprite: Objects/Weapons/Melee/kitchen_knife.rsi + size: Small \ No newline at end of file diff --git a/Resources/Textures/Objects/Weapons/Melee/kitchen_knife.rsi/icon_a.png b/Resources/Textures/Objects/Weapons/Melee/kitchen_knife.rsi/icon_a.png new file mode 100644 index 0000000000000000000000000000000000000000..5ba284e8f71906b577c008608202e3a5c066c047 GIT binary patch literal 544 zcmV+*0^j|KP)Px$+DSw~R9J=Wlrby=Q5?p< zp==UcW1tZx7BMjhgNQ-G>CnkQgy^NwGdNRED|hd%y%UCh$y@IKzxVsT|J{2)MHT(A zh+1KBcEdEt=u|-Jayk`RRi;rW@HV?$wO(yx^QI1oTJP`clkQU~&xBab z?}0*iI-Qo`EXyL1NXYPm)XzAD0bo+n4UM005t0 zB|*qwWo=o0=JWYTA)Mnlc^xD#G{>*oz|-@GBnTM*z15!sK~) z_Wg}yAKuW~Trc;nMz;(Z(EJ32Z~$nuTF}!yYzV5$KsNhGa-xWwC}MYSn{>9fpwVi< iNHAg=yrPQ!g}wlKklGrIIpQ(^0000 Date: Thu, 14 Nov 2024 13:10:41 +0200 Subject: [PATCH 02/46] =?UTF-8?q?=D0=BF=D0=BE=D1=87=D0=B5=D0=BC=D1=83=20?= =?UTF-8?q?=D1=8F=20=D0=BD=D0=B5=20=D1=81=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB=20?= =?UTF-8?q?=D1=8D=D1=82=D0=BE=20=D1=81=D1=80=D0=B0=D0=B7=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Content.Client/Input/ContentContexts.cs | 16 +- .../Options/UI/Tabs/KeyRebindTab.xaml.cs | 13 +- .../Projectiles/ProjectileSystem.cs | 2 +- .../Weapons/Melee/MeleeWeaponSystem.cs | 8 +- Content.Client/_RMC14/Scoping/ScopeSystem.cs | 5 + .../_RMC14/Weapons/Ranged/PumpActionSystem.cs | 35 +++ .../ADT/_RMC14/Scoping/ScopeSystem.cs | 52 ++++ .../Weapons/Melee/RMCMeleeWeaponSystem.cs | 5 + .../_RMC14/Weapons/Ranged/PumpActionSystem.cs | 5 + .../ADT/_RMC14/Attachable/AttachableData.cs | 3 +- .../Components/AttachableSilencerComponent.cs | 2 +- .../AttachableModifiersSystem.Melee.cs | 12 + .../Containers/ItemSlot/ItemSlotsSystem.cs | 2 +- .../Damage/Systems/DamageableSystem.cs | 8 +- .../Projectiles/ProjectileComponent.cs | 8 - Content.Shared/Sound/SharedEmitSoundSystem.cs | 3 + .../Weapons/Melee/Events/MeleeHitEvent.cs | 1 + .../Weapons/Ranged/Components/GunComponent.cs | 2 +- .../Systems/SharedGunSystem.Interactions.cs | 8 +- .../Weapons/Ranged/Systems/SharedGunSystem.cs | 4 +- .../Components/WieldableComponent.cs | 2 +- Content.Shared/Wieldable/WieldableSystem.cs | 2 +- .../Guns/Revolvers/saber_revolvers.yml | 4 +- Resources/Prototypes/ADT/_RMC14/test.yml | 239 ++++++++++++++++-- .../Melee/kitchen_knife.rsi/icon_a.png | Bin 544 -> 0 bytes .../Weapons/Melee/kitchen_knife.rsi/meta.json | 3 - 26 files changed, 375 insertions(+), 69 deletions(-) create mode 100644 Content.Client/_RMC14/Scoping/ScopeSystem.cs create mode 100644 Content.Client/_RMC14/Weapons/Ranged/PumpActionSystem.cs create mode 100644 Content.Server/ADT/_RMC14/Scoping/ScopeSystem.cs create mode 100644 Content.Server/ADT/_RMC14/Weapons/Melee/RMCMeleeWeaponSystem.cs create mode 100644 Content.Server/ADT/_RMC14/Weapons/Ranged/PumpActionSystem.cs delete mode 100644 Resources/Textures/Objects/Weapons/Melee/kitchen_knife.rsi/icon_a.png diff --git a/Content.Client/Input/ContentContexts.cs b/Content.Client/Input/ContentContexts.cs index e26ce672367..aa5a00cbbe8 100644 --- a/Content.Client/Input/ContentContexts.cs +++ b/Content.Client/Input/ContentContexts.cs @@ -1,6 +1,6 @@ using Content.Shared.Input; using Robust.Shared.Input; -using Content.Shared._RMC14.Input; +using Content.Shared._RMC14.Input; // ADT TWEAK namespace Content.Client.Input { @@ -126,9 +126,10 @@ public static void SetupContexts(IInputContextContainer contexts) common.AddFunction(ContentKeyFunctions.OpenAdminMenu); common.AddFunction(ContentKeyFunctions.OpenGuidebook); - CMFunctions(contexts); + CMFunctions(contexts); // ADT TWEAK } + // ADT TWEAK START: private static void CMFunctions(IInputContextContainer contexts) { var human = contexts.GetContext("human"); @@ -138,10 +139,11 @@ private static void CMFunctions(IInputContextContainer contexts) human.AddFunction(CMKeyFunctions.RMCActivateAttachableUnderbarrel); human.AddFunction(CMKeyFunctions.RMCFieldStripHeldItem); human.AddFunction(CMKeyFunctions.CMUniqueAction); - human.AddFunction(CMKeyFunctions.CMHolsterPrimary); - human.AddFunction(CMKeyFunctions.CMHolsterSecondary); - human.AddFunction(CMKeyFunctions.CMHolsterTertiary); - human.AddFunction(CMKeyFunctions.CMHolsterQuaternary); + // human.AddFunction(CMKeyFunctions.CMHolsterPrimary); + // human.AddFunction(CMKeyFunctions.CMHolsterSecondary); + // human.AddFunction(CMKeyFunctions.CMHolsterTertiary); + // human.AddFunction(CMKeyFunctions.CMHolsterQuaternary); } + // ADT TWEAK END. } -} \ No newline at end of file +} diff --git a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs index 60685694ce5..eaaaeee1fe0 100644 --- a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs +++ b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs @@ -13,7 +13,7 @@ using Robust.Shared.Timing; using Robust.Shared.Utility; using static Robust.Client.UserInterface.Controls.BoxContainer; -using Content.Shared._RMC14.Input; +using Content.Shared._RMC14.Input; // ADT TWEAK namespace Content.Client.Options.UI.Tabs { @@ -151,7 +151,7 @@ void AddCheckBox(string checkBoxName, bool currentState, Action(OnProjectileImpact); + SubscribeNetworkEvent(OnProjectileImpact); } private void OnProjectileImpact(ImpactEffectEvent ev) diff --git a/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs b/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs index 609ea7c509e..a259d522398 100644 --- a/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs +++ b/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs @@ -1,13 +1,13 @@ using System.Linq; using Content.Client.Gameplay; -using Content.Shared._RMC14.Tackle; +using Content.Shared._RMC14.Tackle; // ADT TWEAK using Content.Shared.CombatMode; using Content.Shared.Effects; using Content.Shared.Hands.Components; using Content.Shared.Mobs.Components; using Content.Shared.StatusEffect; using Content.Shared.Weapons.Melee; -using Content.Shared.Weapons.Melee.Components; +using Content.Shared.Weapons.Melee.Components; // ADT TWEAK using Content.Shared.Weapons.Melee.Events; using Content.Shared.Weapons.Ranged.Components; using Robust.Client.GameObjects; @@ -89,7 +89,7 @@ public override void Update(float frameTime) } // TODO using targeted actions while combat mode is enabled should NOT trigger attacks. - + // ADT TWEAK START var mousePos = _eyeManager.PixelToMap(_inputManager.MouseScreenPosition); if (mousePos.MapId == MapId.Nullspace) @@ -258,7 +258,7 @@ private void ClientLightAttack(EntityUid attacker, MapCoordinates mousePos, Enti RaisePredictiveEvent(new LightAttackEvent(GetNetEntity(target), GetNetEntity(weaponUid), GetNetCoordinates(coordinates))); } - + // ADT TWEAK END private void OnMeleeLunge(MeleeLungeEvent ev) { var ent = GetEntity(ev.Entity); diff --git a/Content.Client/_RMC14/Scoping/ScopeSystem.cs b/Content.Client/_RMC14/Scoping/ScopeSystem.cs new file mode 100644 index 00000000000..5483c9a9baa --- /dev/null +++ b/Content.Client/_RMC14/Scoping/ScopeSystem.cs @@ -0,0 +1,5 @@ +using Content.Shared._RMC14.Scoping; + +namespace Content.Client._RMC14.Scoping; + +public sealed class ScopeSystem : SharedScopeSystem; diff --git a/Content.Client/_RMC14/Weapons/Ranged/PumpActionSystem.cs b/Content.Client/_RMC14/Weapons/Ranged/PumpActionSystem.cs new file mode 100644 index 00000000000..ffe6ad56286 --- /dev/null +++ b/Content.Client/_RMC14/Weapons/Ranged/PumpActionSystem.cs @@ -0,0 +1,35 @@ +using Content.Shared._RMC14.Input; +using Content.Shared._RMC14.Weapons.Ranged; +using Content.Shared.Examine; +using Content.Shared.Popups; +using Content.Shared.Weapons.Ranged.Systems; +using Robust.Client.Input; + +namespace Content.Client._RMC14.Weapons.Ranged; + +public sealed class PumpActionSystem : SharedPumpActionSystem +{ + [Dependency] private readonly IInputManager _input = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + + protected override void OnExamined(Entity ent, ref ExaminedEvent args) + { + if (!_input.TryGetKeyBinding(CMKeyFunctions.CMUniqueAction, out var bind)) + return; + + args.PushMarkup(Loc.GetString(ent.Comp.Examine), 1); + } + + protected override void OnAttemptShoot(Entity ent, ref AttemptShootEvent args) + { + base.OnAttemptShoot(ent, ref args); + + if (!ent.Comp.Pumped) + { + var message = _input.TryGetKeyBinding(CMKeyFunctions.CMUniqueAction, out var bind) + ? Loc.GetString(ent.Comp.PopupKey, ("key", bind.GetKeyString())) + : Loc.GetString(ent.Comp.Popup); + _popup.PopupClient(message, args.User, args.User); + } + } +} diff --git a/Content.Server/ADT/_RMC14/Scoping/ScopeSystem.cs b/Content.Server/ADT/_RMC14/Scoping/ScopeSystem.cs new file mode 100644 index 00000000000..91a49c34bea --- /dev/null +++ b/Content.Server/ADT/_RMC14/Scoping/ScopeSystem.cs @@ -0,0 +1,52 @@ +using Content.Shared._RMC14.Scoping; +using Robust.Server.GameObjects; +using Robust.Shared.Player; + +namespace Content.Server._RMC14.Scoping; + +public sealed class ScopeSystem : SharedScopeSystem +{ + [Dependency] private readonly ViewSubscriberSystem _viewSubscriber = default!; + + protected override Direction? StartScoping(Entity scope, EntityUid user) + { + if (base.StartScoping(scope, user) is not { } direction) + return null; + + scope.Comp.User = user; + + if (TryComp(user, out ActorComponent? actor)) + { + var coords = Transform(user).Coordinates; + var offset = GetScopeOffset(scope, direction); + scope.Comp.RelayEntity = SpawnAtPosition(null, coords.Offset(offset)); + _viewSubscriber.AddViewSubscriber(scope.Comp.RelayEntity.Value, actor.PlayerSession); + } + + return direction; + } + + protected override bool Unscope(Entity scope) + { + var user = scope.Comp.User; + if (!base.Unscope(scope)) + return false; + + DeleteRelay(scope, user); + return true; + } + + protected override void DeleteRelay(Entity scope, EntityUid? user) + { + if (scope.Comp.RelayEntity is not { } relay) + return; + + scope.Comp.RelayEntity = null; + + if (TryComp(user, out ActorComponent? actor)) + _viewSubscriber.RemoveViewSubscriber(relay, actor.PlayerSession); + + if (!TerminatingOrDeleted(relay)) + QueueDel(relay); + } +} diff --git a/Content.Server/ADT/_RMC14/Weapons/Melee/RMCMeleeWeaponSystem.cs b/Content.Server/ADT/_RMC14/Weapons/Melee/RMCMeleeWeaponSystem.cs new file mode 100644 index 00000000000..7df99629895 --- /dev/null +++ b/Content.Server/ADT/_RMC14/Weapons/Melee/RMCMeleeWeaponSystem.cs @@ -0,0 +1,5 @@ +using Content.Shared._RMC14.Weapons.Melee; + +namespace Content.Server._RMC14.Weapons.Melee; + +public sealed class RMCMeleeWeaponSystem : SharedRMCMeleeWeaponSystem; diff --git a/Content.Server/ADT/_RMC14/Weapons/Ranged/PumpActionSystem.cs b/Content.Server/ADT/_RMC14/Weapons/Ranged/PumpActionSystem.cs new file mode 100644 index 00000000000..b1b08add8d6 --- /dev/null +++ b/Content.Server/ADT/_RMC14/Weapons/Ranged/PumpActionSystem.cs @@ -0,0 +1,5 @@ +using Content.Shared._RMC14.Weapons.Ranged; + +namespace Content.Server._RMC14.Weapons.Ranged; + +public sealed class PumpActionSystem : SharedPumpActionSystem; diff --git a/Content.Shared/ADT/_RMC14/Attachable/AttachableData.cs b/Content.Shared/ADT/_RMC14/Attachable/AttachableData.cs index cccd1c2bb49..24719659bd6 100644 --- a/Content.Shared/ADT/_RMC14/Attachable/AttachableData.cs +++ b/Content.Shared/ADT/_RMC14/Attachable/AttachableData.cs @@ -27,7 +27,8 @@ public record struct AttachableModifierConditions( [DataRecord, Serializable, NetSerializable] public record struct AttachableWeaponMeleeModifierSet( AttachableModifierConditions? Conditions, - DamageSpecifier? BonusDamage + DamageSpecifier? BonusDamage, + DamageSpecifier? DecreaseDamage ); [DataRecord, Serializable, NetSerializable] diff --git a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableSilencerComponent.cs b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableSilencerComponent.cs index 2d53feee9e4..1dd3e7445ec 100644 --- a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableSilencerComponent.cs +++ b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableSilencerComponent.cs @@ -9,5 +9,5 @@ namespace Content.Shared._RMC14.Attachable.Components; public sealed partial class AttachableSilencerComponent : Component { [DataField, AutoNetworkedField] - public SoundSpecifier Sound = new SoundCollectionSpecifier("CMSilencedShoot"); + public SoundSpecifier Sound = new SoundCollectionSpecifier("sparks"); } diff --git a/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableModifiersSystem.Melee.cs b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableModifiersSystem.Melee.cs index 02220c942a8..38f44989db5 100644 --- a/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableModifiersSystem.Melee.cs +++ b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableModifiersSystem.Melee.cs @@ -63,6 +63,18 @@ private void ApplyModifierSet(Entity attacha if (modSet.BonusDamage != null) args.BonusDamage += modSet.BonusDamage; + if (modSet.DecreaseDamage != null) + { + foreach (var (decreaseId, decreaseDmg) in modSet.DecreaseDamage.DamageDict) + { + if (decreaseDmg <= FixedPoint2.Zero) + continue; + + if (args.BaseDamage.DamageDict.TryGetValue(decreaseId, out var baseDamage)) + args.BaseDamage.DamageDict[decreaseId] = FixedPoint2.Max(baseDamage - decreaseDmg, FixedPoint2.Zero); + } + } + if (args.BonusDamage.GetTotal() < FixedPoint2.Zero) { _damage.Clear(); diff --git a/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs index a2164473d21..d1c293988d7 100644 --- a/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs +++ b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs @@ -431,7 +431,7 @@ public bool TryGetAvailableSlot(Entity ent, return true; } - public static int SortEmpty(ItemSlot a, ItemSlot b) + public static int SortEmpty(ItemSlot a, ItemSlot b) // ADT TWEAK: PRIVATE TO PUBLIC { var aEnt = a.ContainerSlot?.ContainedEntity; var bEnt = b.ContainerSlot?.ContainedEntity; diff --git a/Content.Shared/Damage/Systems/DamageableSystem.cs b/Content.Shared/Damage/Systems/DamageableSystem.cs index 2b2ab48f46c..f02d2b1021a 100644 --- a/Content.Shared/Damage/Systems/DamageableSystem.cs +++ b/Content.Shared/Damage/Systems/DamageableSystem.cs @@ -124,7 +124,7 @@ public void DamageChanged(EntityUid uid, DamageableComponent component, DamageSp /// null if the user had no applicable components that can take damage. /// public DamageSpecifier? TryChangeDamage(EntityUid? uid, DamageSpecifier damage, bool ignoreResistances = false, - bool interruptsDoAfters = true, DamageableComponent? damageable = null, EntityUid? origin = null, EntityUid? tool = null) + bool interruptsDoAfters = true, DamageableComponent? damageable = null, EntityUid? origin = null, EntityUid? tool = null) // ADT TWEAK { if (!uid.HasValue || !_damageableQuery.Resolve(uid.Value, ref damageable, false)) { @@ -154,7 +154,7 @@ public void DamageChanged(EntityUid uid, DamageableComponent component, DamageSp damage = DamageSpecifier.ApplyModifierSet(damage, modifierSet); } - var ev = new DamageModifyEvent(damage, origin, tool); + var ev = new DamageModifyEvent(damage, origin, tool); // ADT TWEAK RaiseLocalEvent(uid.Value, ev); damage = ev.Damage; @@ -306,12 +306,12 @@ public sealed class DamageModifyEvent : EntityEventArgs, IInventoryRelayEvent public EntityUid? Tool; - public DamageModifyEvent(DamageSpecifier damage, EntityUid? origin = null, EntityUid? tool = null) + public DamageModifyEvent(DamageSpecifier damage, EntityUid? origin = null, EntityUid? tool = null) // ADT TWEAK { OriginalDamage = damage; Damage = damage; Origin = origin; - Tool = tool; + Tool = tool; // ADT TWEAK } } diff --git a/Content.Shared/Projectiles/ProjectileComponent.cs b/Content.Shared/Projectiles/ProjectileComponent.cs index cf5f45c75c4..c24cf2b5ee5 100644 --- a/Content.Shared/Projectiles/ProjectileComponent.cs +++ b/Content.Shared/Projectiles/ProjectileComponent.cs @@ -73,12 +73,4 @@ public sealed partial class ProjectileComponent : Component /// [DataField] public bool DamagedEntity; - - /// - /// Sets the maximum range for a projectile fired with ShootAtFixedPointComponent. - /// This can be set on both the Projectile and ShootAtFixedPoint Components. - /// The default value is null for no cap. The minimum value between the two is used. - /// - [DataField, AutoNetworkedField] - public float? MaxFixedRange; } diff --git a/Content.Shared/Sound/SharedEmitSoundSystem.cs b/Content.Shared/Sound/SharedEmitSoundSystem.cs index e9e80bcfd36..5c493bdb441 100644 --- a/Content.Shared/Sound/SharedEmitSoundSystem.cs +++ b/Content.Shared/Sound/SharedEmitSoundSystem.cs @@ -137,10 +137,13 @@ private void OnEmitSoundOnInteractUsing(Entity public DamageSpecifier BonusDamage = new(); + public DamageSpecifier DecreaseDamage = new(); /// /// A list containing every hit entity. Can be zero. diff --git a/Content.Shared/Weapons/Ranged/Components/GunComponent.cs b/Content.Shared/Weapons/Ranged/Components/GunComponent.cs index 5d8641387d6..9d29e742e45 100644 --- a/Content.Shared/Weapons/Ranged/Components/GunComponent.cs +++ b/Content.Shared/Weapons/Ranged/Components/GunComponent.cs @@ -9,7 +9,7 @@ namespace Content.Shared.Weapons.Ranged.Components; [RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause] -[Access(typeof(SharedGunSystem), typeof(RMCSelectiveFireSystem))] +[Access(typeof(SharedGunSystem), typeof(RMCSelectiveFireSystem))] // ADT TWEAK public sealed partial class GunComponent : Component { #region Sound diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Interactions.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Interactions.cs index 3e88559b855..d8cddd05a71 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Interactions.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Interactions.cs @@ -4,7 +4,7 @@ using Content.Shared.Verbs; using Content.Shared.Weapons.Ranged.Components; using Robust.Shared.Utility; -using Content.Shared._RMC14.Weapons.Ranged; +using Content.Shared._RMC14.Weapons.Ranged; // ADT TWEAK namespace Content.Shared.Weapons.Ranged.Systems; @@ -62,7 +62,7 @@ private SelectiveFire GetNextMode(GunComponent component) return modes[(index + 1) % modes.Count]; } - public void SelectFire(EntityUid uid, GunComponent component, SelectiveFire fire, EntityUid? user = null) + public void SelectFire(EntityUid uid, GunComponent component, SelectiveFire fire, EntityUid? user = null) // ADT TWEAK: PRIVATE TO PUBLIC { if (component.SelectedMode == fire) return; @@ -84,8 +84,8 @@ public void SelectFire(EntityUid uid, GunComponent component, SelectiveFire fire Audio.PlayPredicted(component.SoundMode, uid, user); Popup(Loc.GetString("gun-selected-mode", ("mode", GetLocSelector(fire))), uid, user); - var ev = new RMCFireModeChangedEvent(); - RaiseLocalEvent(uid, ref ev); + var ev = new RMCFireModeChangedEvent(); // ADT TWEAK + RaiseLocalEvent(uid, ref ev); // ADT TWEAK Dirty(uid, component); } diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs index bcff3f0cfb6..60fbc81f8fe 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs @@ -375,7 +375,7 @@ private void AttemptShoot(EntityUid user, EntityUid gunUid, GunComponent gun) // Shoot confirmed - sounds also played here in case it's invalid (e.g. cartridge already spent). Shoot(gunUid, gun, ev.Ammo, fromCoordinates, toCoordinates.Value, out var userImpulse, user, throwItems: attemptEv.ThrowItems); - var shotEv = new GunShotEvent(user, ev.Ammo, fromCoordinates, toCoordinates.Value); + var shotEv = new GunShotEvent(user, ev.Ammo, fromCoordinates, toCoordinates.Value); // ADT TWEAK RaiseLocalEvent(gunUid, ref shotEv); if (userImpulse && TryComp(user, out var userPhysics)) @@ -579,7 +579,7 @@ public record struct AttemptShootEvent(EntityUid User, string? Message, bool Can /// /// The user that fired this gun. [ByRefEvent] -public record struct GunShotEvent(EntityUid User, List<(EntityUid? Uid, IShootable Shootable)> Ammo, EntityCoordinates FromCoordinates, EntityCoordinates ToCoordinates); +public record struct GunShotEvent(EntityUid User, List<(EntityUid? Uid, IShootable Shootable)> Ammo, EntityCoordinates FromCoordinates, EntityCoordinates ToCoordinates); // ADT TWEAK public enum EffectLayers : byte { diff --git a/Content.Shared/Wieldable/Components/WieldableComponent.cs b/Content.Shared/Wieldable/Components/WieldableComponent.cs index 5dc6abbbbea..4dce8510d4b 100644 --- a/Content.Shared/Wieldable/Components/WieldableComponent.cs +++ b/Content.Shared/Wieldable/Components/WieldableComponent.cs @@ -28,7 +28,7 @@ public sealed partial class WieldableComponent : Component /// /// Whether using the item inhand while wielding causes the item to unwield. - /// Unwielding can conflict with other inhand actions. + /// Unwielding can conflict with other inhand actions. /// [DataField] public bool UnwieldOnUse = true; diff --git a/Content.Shared/Wieldable/WieldableSystem.cs b/Content.Shared/Wieldable/WieldableSystem.cs index d76876c0cff..857491c300f 100644 --- a/Content.Shared/Wieldable/WieldableSystem.cs +++ b/Content.Shared/Wieldable/WieldableSystem.cs @@ -125,7 +125,7 @@ private void OnExamineRequires(Entity entity, ref Exa private void OnExamine(EntityUid uid, GunWieldBonusComponent component, ref ExaminedEvent args) { - if (HasComp(uid)) + if (HasComp(uid)) return; if (component.WieldBonusExamineMessage != null) diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Revolvers/saber_revolvers.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Revolvers/saber_revolvers.yml index fcb3575f23c..f0b00f0ed67 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Revolvers/saber_revolvers.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Revolvers/saber_revolvers.yml @@ -39,7 +39,7 @@ projectileSpeed: 30 soundGunshot: path: /Audio/Weapons/Guns/Gunshots/laser_cannon.ogg - useKey: false + useKey: true - type: MeleeWeapon wideAnimationRotation: -135 attackRate: 1 @@ -103,3 +103,5 @@ whitelist: tags: - ADTLasgunRevolverCell + - type: AltFireMelee + AltFireAttackType: Heavy diff --git a/Resources/Prototypes/ADT/_RMC14/test.yml b/Resources/Prototypes/ADT/_RMC14/test.yml index 2e4bd64acbe..4ee05d5073d 100644 --- a/Resources/Prototypes/ADT/_RMC14/test.yml +++ b/Resources/Prototypes/ADT/_RMC14/test.yml @@ -53,7 +53,6 @@ - state: bullet shader: unshaded -# BASE ======================================================================================================= - type: entity abstract: true @@ -124,36 +123,24 @@ map: ["enum.GunVisualLayers.Mag"] - type: entity - parent: BaseMagazineRifle id: CMMagazineRifleBase - name: "M5 'Night Raider' bayonet" - description: The standard-issue bayonet of the Marines. - abstract: true + name: "magazine (.20 rifle)" + parent: BaseMagazineRifle components: - - type: Item - size: Normal - - type: Appearance - - type: Clothing - slots: - - suitStorage + - type: BallisticAmmoProvider + proto: CartridgeRifle - type: Sprite - sprite: Objects/Weapons/Guns/Ammunition/Magazine/CaselessRifle/caseless_rifle_mag.rsi layers: - - state: base + - state: red map: ["enum.GunVisualLayers.Base"] - state: mag-1 map: ["enum.GunVisualLayers.Mag"] - - type: MagazineVisuals - magState: mag - steps: 2 - zeroVisible: false - type: Tag tags: - CMMagazineRifle - - type: entity - parent: BaseCartridgeRifle + parent: BaseCartridge id: CMBaseCartridgeRifle name: cartridge abstract: true @@ -172,7 +159,9 @@ id: RMCAttachmentUnderbarrel - type: Tag id: RMCAttachmentU1GrenadeLauncher -# ================================ ATTACHMENT +- type: Tag + id: RMCAttachmentRail + - type: entity parent: BaseItem abstract: true @@ -191,7 +180,6 @@ - type: UseDelay delay: 0 -# =========== KNIFE - type: entity parent: [ RMCBaseMeleeWeapon, BaseKnife, RMCAttachableBase ] @@ -236,6 +224,9 @@ - bonusDamage: types: Slash: 20 + - decreaseDamage: + types: + Blunt: 5 - type: AttachableWeaponRangedMods modifiers: - conditions: @@ -258,7 +249,7 @@ tags: - RMCAttachmentBarrel -# =============================== RIFLE +# пример - type: entity parent: CMBaseWeaponRifle name: M54C assault rifle MK2 @@ -299,14 +290,25 @@ whitelist: tags: - RMCM5Bayonet + - RMCAttachmentSuppressor rmc-aslot-underbarrel: whitelist: tags: - RMCAttachmentU1GrenadeLauncher + rmc-aslot-stock: + whitelist: + tags: + - RMCAttachmentM54CStockSolid + rmc-aslot-rail: + whitelist: + tags: + - SlavikScope - type: AttachableHolderVisuals offsets: rmc-aslot-barrel: 0.75, 0.00 rmc-aslot-underbarrel: 0.75, 0.00 + rmc-aslot-stock: 0.75, 0.00 +# пример - type: entity abstract: true @@ -363,4 +365,195 @@ state: icon - type: Item sprite: Objects/Weapons/Melee/kitchen_knife.rsi - size: Small \ No newline at end of file + size: Small + +- type: entity + abstract: true + parent: RMCAttachableBase + id: RMCRailAttachmentBase + components: + - type: Sprite + sprite: _RMC14/Objects/Weapons/Guns/Attachments/rail.rsi + - type: Tag + tags: + - RMCAttachmentRail + +- type: entity + abstract: true + parent: [ RMCRailAttachmentBase, RMCAttachableToggleableBase ] + id: RMCAttachmentScopeBase + components: + - type: AttachableToggleable + needHand: true + heldOnlyActivate: true + userOnly: true + doInterrupt: true + attachedOnly: true + breakOnMove: true + breakOnRotate: true + wieldedOnly: true + useDelay: 0.5 + showTogglePopup: false + icon: + sprite: _RMC14/Objects/Weapons/Guns/Attachments/rail.rsi + state: sniperscope + actionName: Look through Scope + actionDesc: Scope in. If you're seeing this, someone forgot to set the description properly. + - type: AttachableToggleableSimpleActivate + - type: Scope + requireWielding: true + attachment: true + useInHand: true + zoomLevels: + - zoom: 1 + offset: 15 + allowMovement: false + doAfter: 0 + +- type: Tag + id: SlavikScope + +- type: entity + parent: RMCAttachmentScopeBase + id: RMCAttachmentSlavicScope + name: 4x telescopic scope + description: Oppa! How did you get this off glorious Stalin weapon? Blyat, put back on and do job tovarish. Yankee is not shoot self no? + components: + - type: Sprite + state: slavicscope + - type: Tag + tags: + - RMCAttachmentRail + - SlavikScope + - type: AttachableVisuals + - type: AttachableToggleable + actionName: Look through the S8 4x Telescopic Scope + actionDesc: An AEGIS S8 telescopic eye piece. Fixed at 4x zoom. + - type: AttachableToggleableSimpleActivate + - type: Scope + zoomLevels: + - zoom: 1.6 + offset: 14 + allowMovement: false + doAfter: 0 + - type: AttachableSpeedMods + modifiers: + - conditions: + wieldedOnly: true + walk: -0.23 + sprint: -0.35 + - type: AttachableWieldDelayMods + modifiers: + - delay: 0.4 + - type: AttachableWeaponRangedMods + modifiers: + - fireDelayFlat: 0.1 + - conditions: + activeOnly: true + fireDelayFlat: 0.25 + accuracyAddMult: 0.35 + damageFalloffAddMult: -0.4 + - conditions: + wieldedOnly: true + inactiveOnly: true + accuracyAddMult: -0.05 + - conditions: + unwieldedOnly: true + accuracyMovementPenaltyAddMult: 2 + +- type: Tag + id: RMCAttachmentSuppressor + +- type: entity + parent: RMCBarrelAttachmentBase + id: RMCAttachmentSuppressor + name: suppressor + description: "A small tube with exhaust ports to expel noise and gas. + Does not completely silence a weapon, but does make it much quieter at the cost of slightly reduced damage." + components: + - type: Sprite + state: suppressor + - type: Tag + tags: + - RMCAttachmentBarrel + - RMCAttachmentSuppressor + - type: AttachableVisuals + prefix: suppressor2 + - type: AttachableSilencer + sound: + collection: sparks + params: + maxDistance: 6 + - type: AttachableWeaponRangedMods + modifiers: + - damageFalloffAddMult: 0.1 + +- type: entity + abstract: true + parent: RMCAttachableBase + id: RMCStockAttachmentBase + components: + - type: Sprite + sprite: _RMC14/Objects/Weapons/Guns/Attachments/stock.rsi + - type: Tag + tags: + - RMCAttachmentStock + - type: AttachableWieldDelayMods + modifiers: + - delay: 0.2 + - type: AttachableSizeMods + modifiers: + - size: 2 + - type: AttachableWeaponMeleeMods + modifiers: + - bonusDamage: + types: + Blunt: 5 + +- type: entity + parent: RMCStockAttachmentBase + id: RMCAttachmentM54CStockSolid + name: M54C solid stock + description: A rare stock distributed in small numbers to UNMC forces. Compatible with the M54C, this stock reduces recoil and scatter, but at a reduction to handling and agility. Also enhances the thwacking of things with the stock-end of the rifle. + components: + - type: Sprite + sprite: _RMC14/Objects/Weapons/Guns/Attachments/rmc_stock.rsi + state: m54c-solid + - type: Tag + tags: + - RMCAttachmentStock + - RMCAttachmentM54CStockSolid + - type: AttachableVisuals + - type: AttachableSpeedMods + modifiers: + - conditions: + wieldedOnly: true + walk: -0.059 + sprint: -0.101 + - type: AttachableWieldDelayMods + modifiers: + - delay: 0.4 + - type: AttachableWeaponMeleeMods + modifiers: + - bonusDamage: + types: + Blunt: 10 + - type: AttachableWeaponRangedMods + modifiers: + - conditions: + wieldedOnly: true + accuracyAddMult: 0.25 + recoilFlat: -3 + scatterFlat: -8 + - conditions: + unwieldedOnly: true + accuracyMovementPenaltyAddMult: -2 + accuracyAddMult: -0.15 + recoilFlat: 2 + scatterFlat: 6 + +- type: Tag + id: RMCAttachmentM54CStockSolid + +- type: Tag + id: RMCAttachmentStock diff --git a/Resources/Textures/Objects/Weapons/Melee/kitchen_knife.rsi/icon_a.png b/Resources/Textures/Objects/Weapons/Melee/kitchen_knife.rsi/icon_a.png deleted file mode 100644 index 5ba284e8f71906b577c008608202e3a5c066c047..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 544 zcmV+*0^j|KP)Px$+DSw~R9J=Wlrby=Q5?p< zp==UcW1tZx7BMjhgNQ-G>CnkQgy^NwGdNRED|hd%y%UCh$y@IKzxVsT|J{2)MHT(A zh+1KBcEdEt=u|-Jayk`RRi;rW@HV?$wO(yx^QI1oTJP`clkQU~&xBab z?}0*iI-Qo`EXyL1NXYPm)XzAD0bo+n4UM005t0 zB|*qwWo=o0=JWYTA)Mnlc^xD#G{>*oz|-@GBnTM*z15!sK~) z_Wg}yAKuW~Trc;nMz;(Z(EJ32Z~$nuTF}!yYzV5$KsNhGa-xWwC}MYSn{>9fpwVi< iNHAg=yrPQ!g}wlKklGrIIpQ(^0000 Date: Thu, 14 Nov 2024 14:45:31 +0200 Subject: [PATCH 03/46] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=20=D0=BC=D0=B0?= =?UTF-8?q?=D0=B3=D0=BD=D0=B8=D1=82=D0=BD=D0=BE=D0=B3=D0=BE=20=D0=B6=D0=B3?= =?UTF-8?q?=D1=83=D1=82=D0=B0=20+=20=D1=84=D0=B8=D0=BA=D1=81=20=D1=8F?= =?UTF-8?q?=D0=BC=D0=BB=20=D0=BB=D0=B8=D0=BD=D1=82=D0=B5=D1=80=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Armor/Magnetic/RMCMagneticSystem.cs | 42 +- .../Components/AttachableIFFComponent.cs | 8 - .../Components/GunAttachableIFFComponent.cs | 8 - .../Events/AttachableGrantIFFEvent.cs | 4 - .../Attachable/Systems/AttachableIFFSystem.cs | 72 -- Resources/Prototypes/ADT/_RMC14/test.yml | 1088 +++++++++-------- 6 files changed, 557 insertions(+), 665 deletions(-) delete mode 100644 Content.Shared/ADT/_RMC14/Attachable/Components/AttachableIFFComponent.cs delete mode 100644 Content.Shared/ADT/_RMC14/Attachable/Components/GunAttachableIFFComponent.cs delete mode 100644 Content.Shared/ADT/_RMC14/Attachable/Events/AttachableGrantIFFEvent.cs delete mode 100644 Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableIFFSystem.cs diff --git a/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticSystem.cs b/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticSystem.cs index 9c5e909e06e..4488f3f1ca0 100644 --- a/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticSystem.cs +++ b/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticSystem.cs @@ -19,10 +19,6 @@ public override void Initialize() SubscribeLocalEvent(OnMagneticItemRMCDropped); SubscribeLocalEvent(OnMagneticItemThrown); SubscribeLocalEvent(OnMagneticItemDropAttempt); - - SubscribeLocalEvent>(OnMagnetizeItem); - - SubscribeLocalEvent(_inventory.RelayEvent); } private void OnMagneticItemDropped(Entity ent, ref DroppedEvent args) @@ -49,46 +45,13 @@ private void OnMagneticItemThrown(Entity ent, ref Thro private void OnMagneticItemDropAttempt(Entity ent, ref DropAttemptEvent args) { - if (!CanReturn(ent, args.Uid, out _)) - return; - args.Cancel(); } - private void OnMagnetizeItem(Entity ent, ref InventoryRelayedEvent args) - { - if ((ent.Comp.AllowMagnetizeToSlots & args.Args.MagnetizeToSlots) == SlotFlags.NONE) - return; - - var slotEnumerator = _inventory.GetSlotEnumerator(args.Args.User, ent.Comp.AllowMagnetizeToSlots & args.Args.MagnetizeToSlots); - - while (slotEnumerator.MoveNext(out var container)) - { - if (container.Count > 0) - continue; - - args.Args.Magnetizer = ent; - break; - } - } - - private bool CanReturn(Entity ent, EntityUid user, out EntityUid magnetizer) - { - var ev = new RMCMagnetizeItemEvent(user, ent.Comp.MagnetizeToSlots, SlotFlags.OUTERCLOTHING); - RaiseLocalEvent(user, ref ev); - - magnetizer = ev.Magnetizer ?? default; - return magnetizer != default; - } - private bool TryReturn(Entity ent, EntityUid user) { - if (!CanReturn(ent, user, out var magnetizer)) - return false; - var returnComp = EnsureComp(ent); returnComp.User = user; - returnComp.Magnetizer = magnetizer; Dirty(ent, returnComp); return true; @@ -109,8 +72,7 @@ public override void Update(float frameTime) continue; var user = comp.User; - var magnetizer = comp.Magnetizer; - if (!TerminatingOrDeleted(user) && !TerminatingOrDeleted(magnetizer)) + if (!TerminatingOrDeleted(user)) { var slots = _inventory.GetSlotEnumerator(user, SlotFlags.SUITSTORAGE); while (slots.MoveNext(out var slot)) @@ -119,7 +81,7 @@ public override void Update(float frameTime) { var popup = Loc.GetString("rmc-magnetize-return", ("item", uid), - ("magnetizer", magnetizer)); + ("user", user)); _popup.PopupClient(popup, user, user, PopupType.Medium); comp.Returned = true; diff --git a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableIFFComponent.cs b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableIFFComponent.cs deleted file mode 100644 index d003e631d05..00000000000 --- a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableIFFComponent.cs +++ /dev/null @@ -1,8 +0,0 @@ -// using Content.Shared._RMC14.Attachable.Systems; -// using Robust.Shared.GameStates; - -// namespace Content.Shared._RMC14.Attachable.Components; - -// [RegisterComponent, NetworkedComponent] -// [Access(typeof(AttachableIFFSystem))] -// public sealed partial class AttachableIFFComponent : Component; diff --git a/Content.Shared/ADT/_RMC14/Attachable/Components/GunAttachableIFFComponent.cs b/Content.Shared/ADT/_RMC14/Attachable/Components/GunAttachableIFFComponent.cs deleted file mode 100644 index cbe45806dc0..00000000000 --- a/Content.Shared/ADT/_RMC14/Attachable/Components/GunAttachableIFFComponent.cs +++ /dev/null @@ -1,8 +0,0 @@ -// using Content.Shared._RMC14.Attachable.Systems; -// using Robust.Shared.GameStates; - -// namespace Content.Shared._RMC14.Attachable.Components; - -// [RegisterComponent, NetworkedComponent] -// [Access(typeof(AttachableIFFSystem))] -// public sealed partial class GunAttachableIFFComponent : Component; diff --git a/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableGrantIFFEvent.cs b/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableGrantIFFEvent.cs deleted file mode 100644 index 05603e6330c..00000000000 --- a/Content.Shared/ADT/_RMC14/Attachable/Events/AttachableGrantIFFEvent.cs +++ /dev/null @@ -1,4 +0,0 @@ -// namespace Content.Shared._RMC14.Attachable.Events; - -// [ByRefEvent] -// public record struct AttachableGrantIFFEvent(bool Grants); diff --git a/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableIFFSystem.cs b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableIFFSystem.cs deleted file mode 100644 index 9b021878821..00000000000 --- a/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableIFFSystem.cs +++ /dev/null @@ -1,72 +0,0 @@ -// using Content.Shared._RMC14.Attachable.Components; -// using Content.Shared._RMC14.Attachable.Events; -// using Content.Shared._RMC14.Weapons.Ranged.IFF; -// using Content.Shared.Examine; -// using Content.Shared.Weapons.Ranged.Events; -// using Robust.Shared.Timing; - -// namespace Content.Shared._RMC14.Attachable.Systems; - -// public sealed class AttachableIFFSystem : EntitySystem -// { -// [Dependency] private readonly AttachableHolderSystem _holder = default!; -// [Dependency] private readonly GunIFFSystem _gunIFF = default!; -// [Dependency] private readonly IGameTiming _timing = default!; - -// public override void Initialize() -// { -// SubscribeLocalEvent(OnAttachableIFFAltered); -// SubscribeLocalEvent>(OnAttachableIFFGrant); - -// SubscribeLocalEvent(OnGunAttachableIFFAmmoShot); -// SubscribeLocalEvent(OnGunAttachableIFFExamined); -// } - -// private void OnAttachableIFFAltered(Entity ent, ref AttachableAlteredEvent args) -// { -// switch (args.Alteration) -// { -// case AttachableAlteredType.Attached: -// UpdateGunIFF(args.Holder); -// break; -// case AttachableAlteredType.Detached: -// UpdateGunIFF(args.Holder); -// break; -// } -// } - -// private void OnAttachableIFFGrant(Entity ent, ref AttachableRelayedEvent args) -// { -// args.Args.Grants = true; -// } - -// private void OnGunAttachableIFFAmmoShot(Entity ent, ref AmmoShotEvent args) -// { -// _gunIFF.GiveAmmoIFF(ent, ref args, false, true); -// } - -// private void OnGunAttachableIFFExamined(Entity ent, ref ExaminedEvent args) -// { -// using (args.PushGroup(nameof(GunAttachableIFFComponent))) -// { -// args.PushMarkup(Loc.GetString("rmc-examine-text-iff")); -// } -// } - -// private void UpdateGunIFF(EntityUid gun) -// { -// if (!TryComp(gun, out AttachableHolderComponent? holder)) -// return; - -// var ev = new AttachableGrantIFFEvent(); -// _holder.RelayEvent((gun, holder), ref ev); - -// if (_timing.ApplyingState) -// return; - -// if (ev.Grants) -// EnsureComp(gun); -// else -// RemCompDeferred(gun); -// } -// } diff --git a/Resources/Prototypes/ADT/_RMC14/test.yml b/Resources/Prototypes/ADT/_RMC14/test.yml index 4ee05d5073d..557134d0dce 100644 --- a/Resources/Prototypes/ADT/_RMC14/test.yml +++ b/Resources/Prototypes/ADT/_RMC14/test.yml @@ -1,559 +1,581 @@ -- type: entity - abstract: true - id: RMCBaseAttachableHolder - components: - - type: AttachableHolder - - type: ItemSizeChange - - type: ActivatableUI - verbText: rmc-verb-strip-attachables - verbOnly: true - key: - enum.AttachmentUI.StripKey - - type: UserInterface - interfaces: - enum.AttachmentUI.StripKey: - type: AttachmentStripBui - enum.AttachmentUI.ChooseSlotKey: - type: AttachmentChooseSlotBui +# - type: entity +# abstract: true +# id: RMCBaseAttachableHolder +# components: +# - type: AttachableHolder +# - type: ItemSizeChange +# - type: ActivatableUI +# verbText: rmc-verb-strip-attachables +# verbOnly: true +# key: +# enum.AttachmentUI.StripKey +# - type: UserInterface +# interfaces: +# enum.AttachmentUI.StripKey: +# type: AttachmentStripBui +# enum.AttachmentUI.ChooseSlotKey: +# type: AttachmentChooseSlotBui -- type: entity - abstract: true - id: RMCBaseMeleeWeapon +# - type: entity +# abstract: true +# id: RMCBaseMeleeWeapon -- type: entity - abstract: true - parent: RMCBaseMeleeWeapon - id: CMBaseWeaponGun - components: - - type: Clothing - quickEquip: false - - type: UseDelay - delay: 0 - - type: WieldDelay - - type: AltFireMelee - - type: MeleeWeapon - resetOnHandSelected: false - attackRate: 1 - damage: - types: - Blunt: 5 - soundHit: - collection: GenericHit - - type: Gun - meleeCooldownOnShoot: false - resetOnHandSelected: false +# - type: entity +# abstract: true +# parent: RMCBaseMeleeWeapon +# id: CMBaseWeaponGun +# components: +# - type: Clothing +# quickEquip: false +# - type: UseDelay +# delay: 0 +# - type: WieldDelay +# - type: AltFireMelee +# - type: MeleeWeapon +# resetOnHandSelected: false +# attackRate: 1 +# damage: +# types: +# Blunt: 5 +# soundHit: +# collection: GenericHit +# - type: Gun +# meleeCooldownOnShoot: false +# resetOnHandSelected: false -- type: entity - parent: BaseBullet - id: RMCBaseBullet - components: - - type: Sprite - sprite: _RMC14/Objects/Weapons/Guns/Ammunition/Projectiles/bullet_projectiles.rsi - layers: - - state: bullet - shader: unshaded +# - type: entity +# parent: BaseBullet +# id: RMCBaseBullet +# components: +# - type: Sprite +# sprite: _RMC14/Objects/Weapons/Guns/Ammunition/Projectiles/bullet_projectiles.rsi +# layers: +# - state: bullet +# shader: unshaded -- type: entity - abstract: true - parent: [ CMBaseWeaponGun, BaseItem, RMCBaseAttachableHolder ] - id: CMBaseWeaponRifle - components: - - type: Gun - shotsPerBurst: 3 - selectedMode: Burst - availableModes: - - SemiAuto - - Burst - - type: RMCSelectiveFire - baseFireModes: - - SemiAuto - - Burst - recoilWielded: 1 - recoilUnwielded: 4 - scatterWielded: 10 - scatterUnwielded: 20 - baseFireRate: 1.429 - burstScatterMult: 4 - modifiers: - Burst: - fireDelay: 0.1665 - maxScatterModifier: 10 - useBurstScatterMult: true - unwieldedScatterMultiplier: 2 - shotsToMaxScatter: 6 - FullAuto: - maxScatterModifier: 13 - useBurstScatterMult: true - unwieldedScatterMultiplier: 2 - shotsToMaxScatter: 4 - - type: Wieldable - - type: WieldableSpeedModifiers - baseWalk: 0.8 - baseSprint: 0.69 - - type: WieldDelay - baseDelay: 0.6 - - type: Item - size: Large - - type: Clothing - sprite: Objects/Weapons/Guns/SMGs/atreides.rsi - slots: - - suitStorage - - Back - - type: AmmoCounter - - type: ContainerContainer - containers: - gun_magazine: !type:ContainerSlot - gun_chamber: !type:ContainerSlot - - type: StaticPrice - price: 500 - - type: MagazineAmmoProvider - autoEject: true - - type: MagazineVisuals - magState: mag - steps: 1 - zeroVisible: true - - type: Appearance - - type: Sprite - sprite: Objects/Weapons/Guns/SMGs/atreides.rsi - layers: - - state: base - map: ["enum.GunVisualLayers.Base"] - - state: mag-0 - map: ["enum.GunVisualLayers.Mag"] +# - type: entity +# abstract: true +# parent: [ CMBaseWeaponGun, BaseItem, RMCBaseAttachableHolder ] +# id: CMBaseWeaponRifle +# components: +# - type: Gun +# shotsPerBurst: 3 +# selectedMode: Burst +# availableModes: +# - SemiAuto +# - Burst +# - type: RMCSelectiveFire +# baseFireModes: +# - SemiAuto +# - Burst +# recoilWielded: 1 +# recoilUnwielded: 4 +# scatterWielded: 10 +# scatterUnwielded: 20 +# baseFireRate: 1.429 +# burstScatterMult: 4 +# modifiers: +# Burst: +# fireDelay: 0.1665 +# maxScatterModifier: 10 +# useBurstScatterMult: true +# unwieldedScatterMultiplier: 2 +# shotsToMaxScatter: 6 +# FullAuto: +# maxScatterModifier: 13 +# useBurstScatterMult: true +# unwieldedScatterMultiplier: 2 +# shotsToMaxScatter: 4 +# - type: Wieldable +# - type: WieldableSpeedModifiers +# baseWalk: 0.8 +# baseSprint: 0.69 +# - type: WieldDelay +# baseDelay: 0.6 +# - type: Item +# size: Large +# - type: Clothing +# sprite: Objects/Weapons/Guns/SMGs/atreides.rsi +# slots: +# - suitStorage +# - Back +# - type: AmmoCounter +# - type: ContainerContainer +# containers: +# gun_magazine: !type:ContainerSlot +# gun_chamber: !type:ContainerSlot +# - type: StaticPrice +# price: 500 +# - type: MagazineAmmoProvider +# autoEject: true +# - type: MagazineVisuals +# magState: mag +# steps: 1 +# zeroVisible: true +# - type: Appearance +# - type: Sprite +# sprite: Objects/Weapons/Guns/SMGs/atreides.rsi +# layers: +# - state: base +# map: ["enum.GunVisualLayers.Base"] +# - state: mag-0 +# map: ["enum.GunVisualLayers.Mag"] -- type: entity - id: CMMagazineRifleBase - name: "magazine (.20 rifle)" - parent: BaseMagazineRifle - components: - - type: BallisticAmmoProvider - proto: CartridgeRifle - - type: Sprite - layers: - - state: red - map: ["enum.GunVisualLayers.Base"] - - state: mag-1 - map: ["enum.GunVisualLayers.Mag"] - - type: Tag - tags: - - CMMagazineRifle +# - type: entity +# id: CMMagazineRifleBase +# name: "magazine (.20 rifle)" +# parent: BaseMagazineRifle +# components: +# - type: BallisticAmmoProvider +# proto: CartridgeRifle +# - type: Sprite +# layers: +# - state: red +# map: ["enum.GunVisualLayers.Base"] +# - state: mag-1 +# map: ["enum.GunVisualLayers.Mag"] +# - type: Tag +# tags: +# - CMMagazineRifle -- type: entity - parent: BaseCartridge - id: CMBaseCartridgeRifle - name: cartridge - abstract: true - components: - - type: CartridgeAmmo - deleteOnSpawn: true - - type: Sprite - sprite: Objects/Weapons/Guns/Ammunition/Casings/ammo_casing.rsi - layers: - - state: base - map: ["enum.AmmoVisualLayers.Base"] +# - type: entity +# parent: BaseCartridge +# id: CMBaseCartridgeRifle +# name: cartridge +# abstract: true +# components: +# - type: CartridgeAmmo +# deleteOnSpawn: true +# - type: Sprite +# sprite: Objects/Weapons/Guns/Ammunition/Casings/ammo_casing.rsi +# layers: +# - state: base +# map: ["enum.AmmoVisualLayers.Base"] -- type: Tag - id: CMMagazineRifle -- type: Tag - id: RMCAttachmentUnderbarrel -- type: Tag - id: RMCAttachmentU1GrenadeLauncher -- type: Tag - id: RMCAttachmentRail +# - type: Tag +# id: CMMagazineRifle +# - type: Tag +# id: RMCAttachmentUnderbarrel +# - type: Tag +# id: RMCAttachmentU1GrenadeLauncher +# - type: Tag +# id: RMCAttachmentRail -- type: entity - parent: BaseItem - abstract: true - id: RMCAttachableBase - components: - - type: Item - size: Small - - type: Attachable +# - type: entity +# parent: BaseItem +# abstract: true +# id: RMCAttachableBase +# components: +# - type: Item +# size: Small +# - type: Attachable -- type: entity - parent: RMCAttachableBase - abstract: true - id: RMCAttachableToggleableBase - components: - - type: AttachableToggleable - - type: UseDelay - delay: 0 +# - type: entity +# parent: RMCAttachableBase +# abstract: true +# id: RMCAttachableToggleableBase +# components: +# - type: AttachableToggleable +# - type: UseDelay +# delay: 0 -- type: entity - parent: [ RMCBaseMeleeWeapon, BaseKnife, RMCAttachableBase ] - id: RMCM5Bayonet - name: "M5 'Night Raider' bayonet" - description: The standard-issue bayonet of the Marines. You can slide this knife into your boots. # TODO RMC14 , or attach it to the end of a rifle. - components: - - type: Clothing - slots: - - mask - - pocket - - suitstorage - sprite: Objects/Weapons/Melee/kitchen_knife.rsi - - type: Tag - tags: - - RMCM5Bayonet - - Knife - - RMCAttachmentBarrel - - type: Sprite - sprite: Objects/Weapons/Melee/kitchen_knife.rsi - state: icon - - type: Item - sprite: Objects/Weapons/Melee/kitchen_knife.rsi - size: Small - - type: MeleeWeapon - wideAnimationRotation: -135 - attackRate: 1 - damage: - types: - Slash: 25 - - type: DamageOtherOnHit - damage: - types: - Slash: 18 - - type: DisarmMalus - malus: 0.225 - - type: AttachableVisuals - rsi: Objects/Weapons/Melee/kitchen_knife.rsi - prefix: icon - - type: AttachableWeaponMeleeMods - modifiers: - - bonusDamage: - types: - Slash: 20 - - decreaseDamage: - types: - Blunt: 5 - - type: AttachableWeaponRangedMods - modifiers: - - conditions: - unwieldedOnly: true - accuracyAddMult: -0.05 - - type: AttachablePrying +# - type: entity +# parent: [ RMCBaseMeleeWeapon, BaseKnife, RMCAttachableBase ] +# id: RMCM5Bayonet +# name: "M5 'Night Raider' bayonet" +# description: The standard-issue bayonet of the Marines. You can slide this knife into your boots. # TODO RMC14 , or attach it to the end of a rifle. +# components: +# - type: Clothing +# slots: +# - mask +# - pocket +# - suitstorage +# sprite: Objects/Weapons/Melee/kitchen_knife.rsi +# - type: Tag +# tags: +# - RMCM5Bayonet +# - Knife +# - RMCAttachmentBarrel +# - type: Sprite +# sprite: Objects/Weapons/Melee/kitchen_knife.rsi +# state: icon +# - type: Item +# sprite: Objects/Weapons/Melee/kitchen_knife.rsi +# size: Small +# - type: MeleeWeapon +# wideAnimationRotation: -135 +# attackRate: 1 +# damage: +# types: +# Slash: 25 +# - type: DamageOtherOnHit +# damage: +# types: +# Slash: 18 +# - type: DisarmMalus +# malus: 0.225 +# - type: AttachableVisuals +# rsi: Objects/Weapons/Melee/kitchen_knife.rsi +# prefix: icon +# - type: AttachableWeaponMeleeMods +# modifiers: +# - bonusDamage: +# types: +# Slash: 20 +# - decreaseDamage: +# types: +# Blunt: 5 +# - type: AttachableWeaponRangedMods +# modifiers: +# - conditions: +# unwieldedOnly: true +# accuracyAddMult: -0.05 +# - type: AttachablePrying -- type: Tag - id: RMCAttachmentBarrel -- type: Tag - id: RMCM5Bayonet -- type: entity - abstract: true - parent: RMCAttachableBase - id: RMCBarrelAttachmentBase - components: - - type: Sprite - sprite: Objects/Weapons/Melee/kitchen_knife.rsi - - type: Tag - tags: - - RMCAttachmentBarrel +# - type: Tag +# id: RMCAttachmentBarrel +# - type: Tag +# id: RMCM5Bayonet +# - type: entity +# abstract: true +# parent: RMCAttachableBase +# id: RMCBarrelAttachmentBase +# components: +# - type: Sprite +# sprite: Objects/Weapons/Melee/kitchen_knife.rsi +# - type: Tag +# tags: +# - RMCAttachmentBarrel -# пример -- type: entity - parent: CMBaseWeaponRifle - name: M54C assault rifle MK2 - id: WeaponRifleM54C - description: The standard issue rifle of the Marines. Commonly carried by most combat personnel. Uses 10x24mm caseless ammunition. - components: - - type: ContainerContainer - containers: - gun_magazine: !type:ContainerSlot - gun_chamber: !type:ContainerSlot - - type: Gun - selectedMode: FullAuto - availableModes: - - SemiAuto - - Burst - - FullAuto - - type: RMCSelectiveFire - baseFireModes: - - SemiAuto - - Burst - - FullAuto - recoilUnwielded: 4 - scatterWielded: 6 - scatterUnwielded: 20 - baseFireRate: 4 - burstScatterMult: 1 - - type: ItemSlots - slots: - gun_magazine: - name: Magazine - priority: 2 - whitelist: - tags: - - CMMagazineRifle - - type: AttachableHolder - slots: - rmc-aslot-barrel: - whitelist: - tags: - - RMCM5Bayonet - - RMCAttachmentSuppressor - rmc-aslot-underbarrel: - whitelist: - tags: - - RMCAttachmentU1GrenadeLauncher - rmc-aslot-stock: - whitelist: - tags: - - RMCAttachmentM54CStockSolid - rmc-aslot-rail: - whitelist: - tags: - - SlavikScope - - type: AttachableHolderVisuals - offsets: - rmc-aslot-barrel: 0.75, 0.00 - rmc-aslot-underbarrel: 0.75, 0.00 - rmc-aslot-stock: 0.75, 0.00 -# пример +# # пример +# - type: entity +# parent: CMBaseWeaponRifle +# name: M54C assault rifle MK2 +# id: WeaponRifleM54C +# description: The standard issue rifle of the Marines. Commonly carried by most combat personnel. Uses 10x24mm caseless ammunition. +# components: +# - type: ContainerContainer +# containers: +# gun_magazine: !type:ContainerSlot +# gun_chamber: !type:ContainerSlot +# - type: Gun +# selectedMode: FullAuto +# availableModes: +# - SemiAuto +# - Burst +# - FullAuto +# - type: RMCSelectiveFire +# baseFireModes: +# - SemiAuto +# - Burst +# - FullAuto +# recoilUnwielded: 4 +# scatterWielded: 6 +# scatterUnwielded: 20 +# baseFireRate: 4 +# burstScatterMult: 1 +# - type: ItemSlots +# slots: +# gun_magazine: +# name: Magazine +# priority: 2 +# whitelist: +# tags: +# - CMMagazineRifle +# - type: AttachableHolder +# slots: +# rmc-aslot-barrel: +# whitelist: +# tags: +# - RMCM5Bayonet +# - RMCAttachmentSuppressor +# rmc-aslot-underbarrel: +# whitelist: +# tags: +# - RMCAttachmentU1GrenadeLauncher +# rmc-aslot-stock: +# whitelist: +# tags: +# - RMCAttachmentM54CStockSolid +# rmc-aslot-rail: +# whitelist: +# tags: +# - SlavikScope +# - RMCAttachmentMagneticHarness +# - type: AttachableHolderVisuals +# offsets: +# rmc-aslot-barrel: 0.75, 0.00 +# rmc-aslot-underbarrel: 0.75, 0.00 +# rmc-aslot-stock: 0.75, 0.00 +# # пример -- type: entity - abstract: true - parent: RMCAttachableBase - id: RMCUnderAttachmentBase - components: - - type: Sprite - sprite: Objects/Weapons/Melee/kitchen_knife.rsi - - type: Tag - tags: - - RMCAttachmentUnderbarrel +# - type: entity +# abstract: true +# parent: RMCAttachableBase +# id: RMCUnderAttachmentBase +# components: +# - type: Sprite +# sprite: Objects/Weapons/Melee/kitchen_knife.rsi +# - type: Tag +# tags: +# - RMCAttachmentUnderbarrel -- type: entity - parent: [ RMCUnderAttachmentBase, RMCAttachableToggleableBase, BaseItem ] - id: RMCAttachmentU1GrenadeLauncher - name: U1 grenade launcher - description: A weapon-mounted, reloadable grenade launcher. - components: - - type: ContainerContainer - containers: - ballistic-ammo: !type:Container - ents: [] - - type: RMCAmmoEject - containerID: ballistic-ammo - - type: AmmoCounter - - type: Gun - projectileSpeed: 20 - resetOnHandSelected: false - - type: RMCSelectiveFire - baseFireRate: 0.417 - - type: BallisticAmmoProvider - cycleable: false - whitelist: - tags: - - CartridgeRocket - capacity: 3 - - type: UniqueAction - - type: Appearance - - type: AttachableToggleable - userOnly: true - attachedOnly: true - supercedeHolder: true - wieldedUseOnly: true - activatePopupText: attachable-popup-switch-to-generic - deactivatePopupText: attachable-popup-switch-from-generic - actionName: Switch to the U1 Grenade Launcher - actionDesc: Switch to using the underbarrel grenade launcher. - - type: Tag - tags: - - RMCAttachmentUnderbarrel - - RMCAttachmentU1GrenadeLauncher - - type: Sprite - sprite: Objects/Weapons/Melee/kitchen_knife.rsi - state: icon - - type: Item - sprite: Objects/Weapons/Melee/kitchen_knife.rsi - size: Small +# - type: entity +# parent: [ RMCUnderAttachmentBase, RMCAttachableToggleableBase, BaseItem ] +# id: RMCAttachmentU1GrenadeLauncher +# name: U1 grenade launcher +# description: A weapon-mounted, reloadable grenade launcher. +# components: +# - type: ContainerContainer +# containers: +# ballistic-ammo: !type:Container +# ents: [] +# - type: RMCAmmoEject +# containerID: ballistic-ammo +# - type: AmmoCounter +# - type: Gun +# projectileSpeed: 20 +# resetOnHandSelected: false +# - type: RMCSelectiveFire +# baseFireRate: 0.417 +# - type: BallisticAmmoProvider +# cycleable: false +# whitelist: +# tags: +# - CartridgeRocket +# capacity: 3 +# - type: UniqueAction +# - type: Appearance +# - type: AttachableToggleable +# userOnly: true +# attachedOnly: true +# supercedeHolder: true +# wieldedUseOnly: true +# activatePopupText: attachable-popup-switch-to-generic +# deactivatePopupText: attachable-popup-switch-from-generic +# actionName: Switch to the U1 Grenade Launcher +# actionDesc: Switch to using the underbarrel grenade launcher. +# - type: Tag +# tags: +# - RMCAttachmentUnderbarrel +# - RMCAttachmentU1GrenadeLauncher +# - type: Sprite +# sprite: Objects/Weapons/Melee/kitchen_knife.rsi +# state: icon +# - type: Item +# sprite: Objects/Weapons/Melee/kitchen_knife.rsi +# size: Small -- type: entity - abstract: true - parent: RMCAttachableBase - id: RMCRailAttachmentBase - components: - - type: Sprite - sprite: _RMC14/Objects/Weapons/Guns/Attachments/rail.rsi - - type: Tag - tags: - - RMCAttachmentRail +# - type: entity +# abstract: true +# parent: RMCAttachableBase +# id: RMCRailAttachmentBase +# components: +# - type: Sprite +# sprite: _RMC14/Objects/Weapons/Guns/Attachments/rail.rsi +# - type: Tag +# tags: +# - RMCAttachmentRail -- type: entity - abstract: true - parent: [ RMCRailAttachmentBase, RMCAttachableToggleableBase ] - id: RMCAttachmentScopeBase - components: - - type: AttachableToggleable - needHand: true - heldOnlyActivate: true - userOnly: true - doInterrupt: true - attachedOnly: true - breakOnMove: true - breakOnRotate: true - wieldedOnly: true - useDelay: 0.5 - showTogglePopup: false - icon: - sprite: _RMC14/Objects/Weapons/Guns/Attachments/rail.rsi - state: sniperscope - actionName: Look through Scope - actionDesc: Scope in. If you're seeing this, someone forgot to set the description properly. - - type: AttachableToggleableSimpleActivate - - type: Scope - requireWielding: true - attachment: true - useInHand: true - zoomLevels: - - zoom: 1 - offset: 15 - allowMovement: false - doAfter: 0 +# - type: entity +# abstract: true +# parent: [ RMCRailAttachmentBase, RMCAttachableToggleableBase ] +# id: RMCAttachmentScopeBase +# components: +# - type: AttachableToggleable +# needHand: true +# heldOnlyActivate: true +# userOnly: true +# doInterrupt: true +# attachedOnly: true +# breakOnMove: true +# breakOnRotate: true +# wieldedOnly: true +# useDelay: 0.5 +# showTogglePopup: false +# icon: +# sprite: _RMC14/Objects/Weapons/Guns/Attachments/rail.rsi +# state: sniperscope +# actionName: Look through Scope +# actionDesc: Scope in. If you're seeing this, someone forgot to set the description properly. +# - type: AttachableToggleableSimpleActivate +# - type: Scope +# requireWielding: true +# attachment: true +# useInHand: true +# zoomLevels: +# - zoom: 1 +# offset: 15 +# allowMovement: false +# doAfter: 0 -- type: Tag - id: SlavikScope +# - type: Tag +# id: SlavikScope -- type: entity - parent: RMCAttachmentScopeBase - id: RMCAttachmentSlavicScope - name: 4x telescopic scope - description: Oppa! How did you get this off glorious Stalin weapon? Blyat, put back on and do job tovarish. Yankee is not shoot self no? - components: - - type: Sprite - state: slavicscope - - type: Tag - tags: - - RMCAttachmentRail - - SlavikScope - - type: AttachableVisuals - - type: AttachableToggleable - actionName: Look through the S8 4x Telescopic Scope - actionDesc: An AEGIS S8 telescopic eye piece. Fixed at 4x zoom. - - type: AttachableToggleableSimpleActivate - - type: Scope - zoomLevels: - - zoom: 1.6 - offset: 14 - allowMovement: false - doAfter: 0 - - type: AttachableSpeedMods - modifiers: - - conditions: - wieldedOnly: true - walk: -0.23 - sprint: -0.35 - - type: AttachableWieldDelayMods - modifiers: - - delay: 0.4 - - type: AttachableWeaponRangedMods - modifiers: - - fireDelayFlat: 0.1 - - conditions: - activeOnly: true - fireDelayFlat: 0.25 - accuracyAddMult: 0.35 - damageFalloffAddMult: -0.4 - - conditions: - wieldedOnly: true - inactiveOnly: true - accuracyAddMult: -0.05 - - conditions: - unwieldedOnly: true - accuracyMovementPenaltyAddMult: 2 +# - type: entity +# parent: RMCAttachmentScopeBase +# id: RMCAttachmentSlavicScope +# name: 4x telescopic scope +# description: Oppa! How did you get this off glorious Stalin weapon? Blyat, put back on and do job tovarish. Yankee is not shoot self no? +# components: +# - type: Sprite +# state: slavicscope +# - type: Tag +# tags: +# - RMCAttachmentRail +# - SlavikScope +# - type: AttachableVisuals +# - type: AttachableToggleable +# actionName: Look through the S8 4x Telescopic Scope +# actionDesc: An AEGIS S8 telescopic eye piece. Fixed at 4x zoom. +# - type: AttachableToggleableSimpleActivate +# - type: Scope +# zoomLevels: +# - zoom: 1.6 +# offset: 14 +# allowMovement: false +# doAfter: 0 +# - type: AttachableSpeedMods +# modifiers: +# - conditions: +# wieldedOnly: true +# walk: -0.23 +# sprint: -0.35 +# - type: AttachableWieldDelayMods +# modifiers: +# - delay: 0.4 +# - type: AttachableWeaponRangedMods +# modifiers: +# - fireDelayFlat: 0.1 +# - conditions: +# activeOnly: true +# fireDelayFlat: 0.25 +# accuracyAddMult: 0.35 +# damageFalloffAddMult: -0.4 +# - conditions: +# wieldedOnly: true +# inactiveOnly: true +# accuracyAddMult: -0.05 +# - conditions: +# unwieldedOnly: true +# accuracyMovementPenaltyAddMult: 2 -- type: Tag - id: RMCAttachmentSuppressor +# - type: Tag +# id: RMCAttachmentSuppressor -- type: entity - parent: RMCBarrelAttachmentBase - id: RMCAttachmentSuppressor - name: suppressor - description: "A small tube with exhaust ports to expel noise and gas. - Does not completely silence a weapon, but does make it much quieter at the cost of slightly reduced damage." - components: - - type: Sprite - state: suppressor - - type: Tag - tags: - - RMCAttachmentBarrel - - RMCAttachmentSuppressor - - type: AttachableVisuals - prefix: suppressor2 - - type: AttachableSilencer - sound: - collection: sparks - params: - maxDistance: 6 - - type: AttachableWeaponRangedMods - modifiers: - - damageFalloffAddMult: 0.1 +# - type: entity +# parent: RMCBarrelAttachmentBase +# id: RMCAttachmentSuppressor +# name: suppressor +# description: "A small tube with exhaust ports to expel noise and gas. +# Does not completely silence a weapon, but does make it much quieter at the cost of slightly reduced damage." +# components: +# - type: Sprite +# state: suppressor +# - type: Tag +# tags: +# - RMCAttachmentBarrel +# - RMCAttachmentSuppressor +# - type: AttachableVisuals +# prefix: suppressor2 +# - type: AttachableSilencer +# sound: +# collection: sparks +# params: +# maxDistance: 6 +# - type: AttachableWeaponRangedMods +# modifiers: +# - damageFalloffAddMult: 0.1 -- type: entity - abstract: true - parent: RMCAttachableBase - id: RMCStockAttachmentBase - components: - - type: Sprite - sprite: _RMC14/Objects/Weapons/Guns/Attachments/stock.rsi - - type: Tag - tags: - - RMCAttachmentStock - - type: AttachableWieldDelayMods - modifiers: - - delay: 0.2 - - type: AttachableSizeMods - modifiers: - - size: 2 - - type: AttachableWeaponMeleeMods - modifiers: - - bonusDamage: - types: - Blunt: 5 +# - type: entity +# abstract: true +# parent: RMCAttachableBase +# id: RMCStockAttachmentBase +# components: +# - type: Sprite +# sprite: _RMC14/Objects/Weapons/Guns/Attachments/stock.rsi +# - type: Tag +# tags: +# - RMCAttachmentStock +# - type: AttachableWieldDelayMods +# modifiers: +# - delay: 0.2 +# - type: AttachableSizeMods +# modifiers: +# - size: 2 +# - type: AttachableWeaponMeleeMods +# modifiers: +# - bonusDamage: +# types: +# Blunt: 5 -- type: entity - parent: RMCStockAttachmentBase - id: RMCAttachmentM54CStockSolid - name: M54C solid stock - description: A rare stock distributed in small numbers to UNMC forces. Compatible with the M54C, this stock reduces recoil and scatter, but at a reduction to handling and agility. Also enhances the thwacking of things with the stock-end of the rifle. - components: - - type: Sprite - sprite: _RMC14/Objects/Weapons/Guns/Attachments/rmc_stock.rsi - state: m54c-solid - - type: Tag - tags: - - RMCAttachmentStock - - RMCAttachmentM54CStockSolid - - type: AttachableVisuals - - type: AttachableSpeedMods - modifiers: - - conditions: - wieldedOnly: true - walk: -0.059 - sprint: -0.101 - - type: AttachableWieldDelayMods - modifiers: - - delay: 0.4 - - type: AttachableWeaponMeleeMods - modifiers: - - bonusDamage: - types: - Blunt: 10 - - type: AttachableWeaponRangedMods - modifiers: - - conditions: - wieldedOnly: true - accuracyAddMult: 0.25 - recoilFlat: -3 - scatterFlat: -8 - - conditions: - unwieldedOnly: true - accuracyMovementPenaltyAddMult: -2 - accuracyAddMult: -0.15 - recoilFlat: 2 - scatterFlat: 6 +# - type: entity +# parent: RMCStockAttachmentBase +# id: RMCAttachmentM54CStockSolid +# name: M54C solid stock +# description: A rare stock distributed in small numbers to UNMC forces. Compatible with the M54C, this stock reduces recoil and scatter, but at a reduction to handling and agility. Also enhances the thwacking of things with the stock-end of the rifle. +# components: +# - type: Sprite +# sprite: _RMC14/Objects/Weapons/Guns/Attachments/rmc_stock.rsi +# state: m54c-solid +# - type: Tag +# tags: +# - RMCAttachmentStock +# - RMCAttachmentM54CStockSolid +# - type: AttachableVisuals +# - type: AttachableSpeedMods +# modifiers: +# - conditions: +# wieldedOnly: true +# walk: -0.059 +# sprint: -0.101 +# - type: AttachableWieldDelayMods +# modifiers: +# - delay: 0.4 +# - type: AttachableWeaponMeleeMods +# modifiers: +# - bonusDamage: +# types: +# Blunt: 10 +# - type: AttachableWeaponRangedMods +# modifiers: +# - conditions: +# wieldedOnly: true +# accuracyAddMult: 0.25 +# recoilFlat: -3 +# scatterFlat: -8 +# - conditions: +# unwieldedOnly: true +# accuracyMovementPenaltyAddMult: -2 +# accuracyAddMult: -0.15 +# recoilFlat: 2 +# scatterFlat: 6 -- type: Tag - id: RMCAttachmentM54CStockSolid +# - type: Tag +# id: RMCAttachmentM54CStockSolid -- type: Tag - id: RMCAttachmentStock +# - type: Tag +# id: RMCAttachmentStock + +# - type: Tag +# id: RMCAttachmentMagneticHarness + +# - type: entity +# parent: RMCRailAttachmentBase +# id: RMCAttachmentMagneticHarness +# name: magnetic harness +# description: A magnetically attached harness kit that attaches to the rail mount of a weapon. When dropped, the weapon will sling to any set of Marine armor. +# components: +# - type: Sprite +# state: magnetic +# - type: Tag +# tags: +# - RMCAttachmentRail +# - RMCAttachmentMagneticHarness +# - type: AttachableMagnetic +# - type: AttachableVisuals +# - type: AttachableWeaponRangedMods +# modifiers: +# - accuracyAddMult: -0.05 From 684f0d52cbc71550cac0161918d7709aad8b2a15 Mon Sep 17 00:00:00 2001 From: Inconnu <177014427+Inconnu1337@users.noreply.github.com> Date: Thu, 14 Nov 2024 14:57:47 +0200 Subject: [PATCH 04/46] =?UTF-8?q?=D1=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Entities/Objects/Weapons/Guns/Revolvers/saber_revolvers.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Revolvers/saber_revolvers.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Revolvers/saber_revolvers.yml index f0b00f0ed67..81bd4050b23 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Revolvers/saber_revolvers.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Revolvers/saber_revolvers.yml @@ -104,4 +104,4 @@ tags: - ADTLasgunRevolverCell - type: AltFireMelee - AltFireAttackType: Heavy + attackType: Heavy From a925490ef085dbd4a837f9a50d2ef4829786d63c Mon Sep 17 00:00:00 2001 From: Inconnu1337 Date: Sat, 16 Nov 2024 02:07:26 +0200 Subject: [PATCH 05/46] =?UTF-8?q?=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Magnetic/RMCMagneticArmorComponent.cs | 12 - Content.Shared/ADT/_RMC14/CCVar/RMCCVars.cs | 232 ------------------ .../ADT/_RMC14/Input/CMKeyFunctions.cs | 8 +- .../Weapons/Melee/ImmuneToMeleeComponent.cs | 12 - .../Weapons/Melee/ImmuneToUnarmedComponent.cs | 11 - .../Melee/MeleeDamageMultiplierComponent.cs | 6 +- .../Melee/SharedRMCMeleeWeaponSystem.cs | 44 +--- .../Weapons/Melee/StunOnHitComponent.cs | 15 -- .../ADT/_RMC14/Weapons/Ranged/CMGunSystem.cs | 50 ++-- .../Recoil/GunToggleRecoilActionEvent.cs | 5 - .../Recoil/GunToggleableRecoilComponent.cs | 25 -- .../Recoil/GunToggleableRecoilSystem.cs | 63 ----- .../Ranged/Stacks/GunStacksComponent.cs | 31 --- .../Stacks/GunStacksProjectileComponent.cs | 11 - .../Weapons/Ranged/Stacks/GunStacksSystem.cs | 97 -------- .../Guns/Revolvers/saber_revolvers.yml | 2 +- 16 files changed, 27 insertions(+), 597 deletions(-) delete mode 100644 Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticArmorComponent.cs delete mode 100644 Content.Shared/ADT/_RMC14/Weapons/Melee/ImmuneToMeleeComponent.cs delete mode 100644 Content.Shared/ADT/_RMC14/Weapons/Melee/ImmuneToUnarmedComponent.cs delete mode 100644 Content.Shared/ADT/_RMC14/Weapons/Melee/StunOnHitComponent.cs delete mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/Recoil/GunToggleRecoilActionEvent.cs delete mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/Recoil/GunToggleableRecoilComponent.cs delete mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/Recoil/GunToggleableRecoilSystem.cs delete mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/Stacks/GunStacksComponent.cs delete mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/Stacks/GunStacksProjectileComponent.cs delete mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/Stacks/GunStacksSystem.cs diff --git a/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticArmorComponent.cs b/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticArmorComponent.cs deleted file mode 100644 index a043d1cfe49..00000000000 --- a/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticArmorComponent.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Content.Shared.Inventory; -using Robust.Shared.GameStates; - -namespace Content.Shared._RMC14.Armor.Magnetic; - -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] -[Access(typeof(RMCMagneticSystem))] -public sealed partial class RMCMagneticArmorComponent : Component -{ - [DataField, AutoNetworkedField] - public SlotFlags AllowMagnetizeToSlots = SlotFlags.SUITSTORAGE; -} diff --git a/Content.Shared/ADT/_RMC14/CCVar/RMCCVars.cs b/Content.Shared/ADT/_RMC14/CCVar/RMCCVars.cs index e81d261dca7..ca8f695e1e4 100644 --- a/Content.Shared/ADT/_RMC14/CCVar/RMCCVars.cs +++ b/Content.Shared/ADT/_RMC14/CCVar/RMCCVars.cs @@ -6,238 +6,6 @@ namespace Content.Shared._RMC14.CCVar; [CVarDefs] public sealed class RMCCVars : CVars { - public static readonly CVarDef CMXenoDamageDealtMultiplier = - CVarDef.Create("rmc.xeno_damage_dealt_multiplier", 1f, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef CMXenoDamageReceivedMultiplier = - CVarDef.Create("rmc.xeno_damage_received_multiplier", 1f, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef CMXenoSpeedMultiplier = - CVarDef.Create("rmc.xeno_speed_multiplier", 1f, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef CMPlayVoicelinesArachnid = - CVarDef.Create("rmc.play_voicelines_arachnid", true, CVar.REPLICATED | CVar.CLIENT | CVar.ARCHIVE); - - public static readonly CVarDef CMPlayVoicelinesDiona = - CVarDef.Create("rmc.play_voicelines_diona", true, CVar.REPLICATED | CVar.CLIENT | CVar.ARCHIVE); - - public static readonly CVarDef CMPlayVoicelinesDwarf = - CVarDef.Create("rmc.play_voicelines_dwarf", true, CVar.REPLICATED | CVar.CLIENT | CVar.ARCHIVE); - - public static readonly CVarDef CMPlayVoicelinesFelinid = - CVarDef.Create("rmc.play_voicelines_felinid", true, CVar.REPLICATED | CVar.CLIENT | CVar.ARCHIVE); - - public static readonly CVarDef CMPlayVoicelinesHuman = - CVarDef.Create("rmc.play_voicelines_human", true, CVar.REPLICATED | CVar.CLIENT | CVar.ARCHIVE); - - public static readonly CVarDef CMPlayVoicelinesMoth = - CVarDef.Create("rmc.play_voicelines_moth", true, CVar.REPLICATED | CVar.CLIENT | CVar.ARCHIVE); - - public static readonly CVarDef CMPlayVoicelinesReptilian = - CVarDef.Create("rmc.play_voicelines_reptilian", true, CVar.REPLICATED | CVar.CLIENT | CVar.ARCHIVE); - - public static readonly CVarDef CMPlayVoicelinesSlime = - CVarDef.Create("rmc.play_voicelines_slime", true, CVar.REPLICATED | CVar.CLIENT | CVar.ARCHIVE); - - public static readonly CVarDef CMOocWebhook = - CVarDef.Create("rmc.ooc_webhook", "", CVar.SERVERONLY | CVar.CONFIDENTIAL); - - public static readonly CVarDef CMMaxHeavyAttackTargets = - CVarDef.Create("rmc.max_heavy_attack_targets", 3, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef CMBloodlossMultiplier = - CVarDef.Create("rmc.bloodloss_multiplier", 1.5f, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef CMBleedTimeMultiplier = - CVarDef.Create("rmc.bleed_time_multiplier", 1f, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef CMMarinesPerXeno = - CVarDef.Create("rmc.marines_per_xeno", 6f, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCPatronLobbyMessageTimeSeconds = - CVarDef.Create("rmc.patron_lobby_message_time_seconds", 30, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCPatronLobbyMessageInitialDelaySeconds = - CVarDef.Create("rmc.patron_lobby_message_initial_delay_seconds", 5, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCDiscordAccountLinkingMessageLink = - CVarDef.Create("rmc.discord_account_linking_message_link", "", CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCRequisitionsStartingBalance = - CVarDef.Create("rmc.requisitions_starting_balance", 0, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCRequisitionsBalanceGain = - CVarDef.Create("rmc.requisitions_balance_gain", 750, CVar.REPLICATED | CVar.SERVER); - - // TODO RMC14 400 - public static readonly CVarDef RMCRequisitionsStartingDollarsPerMarine = - CVarDef.Create("rmc.requisitions_starting_dollars_per_marine", 1750, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCDiscordToken = - CVarDef.Create("rmc.discord_token", "", CVar.SERVER | CVar.SERVERONLY | CVar.CONFIDENTIAL); - - public static readonly CVarDef RMCDiscordAdminChatChannel = - CVarDef.Create("rmc.discord_admin_chat_channel", 0UL, CVar.SERVER | CVar.SERVERONLY | CVar.CONFIDENTIAL); - - /// - /// Comma-separated list of maps to load as the planet in the distress signal gamemode. - /// - public static readonly CVarDef RMCPlanetMaps = - CVarDef.Create("rmc.planet_maps", "/Maps/_RMC14/lv624.yml,/Maps/_RMC14/solaris.yml,/Maps/_RMC14/prison.yml,/Maps/_RMC14/shiva.yml,/Maps/_RMC14/trijent.yml,/Maps/_RMC14/varadero.yml", CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCPlanetCoordinateVariance = - CVarDef.Create("rmc.planet_coordinate_variance", 500, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCDrawStorageIconLabels = - CVarDef.Create("rmc.draw_storage_icon_labels", true, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCFTLCrashLand = - CVarDef.Create("rmc.ftl_crash_land", true, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCDropshipInitialDelayMinutes = - CVarDef.Create("rmc.dropship_initial_delay_minutes", 15f, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCLandingZonePrimaryAutoMinutes = - CVarDef.Create("rmc.landing_zone_primary_auto_minutes", 25f, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCCorrosiveAcidTickDelaySeconds = - CVarDef.Create("rmc.corrosive_acid_tick_delay_seconds", 10, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCCorrosiveAcidDamageType = - CVarDef.Create("rmc.corrosive_acid_damage_type", "Heat", CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCCorrosiveAcidDamageTimeSeconds = - CVarDef.Create("rmc.corrosive_acid_damage_time_seconds", 45, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCTailStabMaxTargets = - CVarDef.Create("rmc.tail_stab_max_targets", 1, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCEvolutionPointsRequireOvipositorMinutes = - CVarDef.Create("rmc.evolution_points_require_ovipositor_minutes", 5, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCEvolutionPointsAccumulateBeforeMinutes = - CVarDef.Create("rmc.evolution_points_accumulate_before_minutes", 15, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCAtmosTileEqualize = - CVarDef.Create("rmc.atmos_tile_equalize", false, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCGasTileOverlayUpdate = - CVarDef.Create("rmc.gas_tile_overlay_update", false, CVar.REPLICATED | CVar.SERVER); - public static readonly CVarDef RMCActiveInputMoverEnabled = CVarDef.Create("rmc.active_input_mover_enabled", true, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCAdminFaxAreaMap = - CVarDef.Create("rmc.admin_fax_area_map", "Maps/_RMC14/admin_fax.yml", CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCBioscanInitialDelaySeconds = - CVarDef.Create("rmc.bioscan_initial_delay_seconds", 300, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCBioscanCheckDelaySeconds = - CVarDef.Create("rmc.bioscan_check_delay_seconds", 60, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCBioscanMinimumCooldownSeconds = - CVarDef.Create("rmc.bioscan_minimum_cooldown_seconds", 300, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCBioscanBaseCooldownSeconds = - CVarDef.Create("rmc.bioscan_base_cooldown_seconds", 1800, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCBioscanVariance = - CVarDef.Create("rmc.bioscan_variance", 2, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCDropshipFabricatorStartingPoints = - CVarDef.Create("rmc.dropship_fabricator_starting_points", 20000, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCDropshipFabricatorGainEverySeconds = - CVarDef.Create("rmc.dropship_fabricator_gain_every_seconds", 3.33333f, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCDropshipCASDebug = - CVarDef.Create("rmc.dropship_cas_debug", false, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCDropshipFlyByTimeSeconds = - CVarDef.Create("rmc.dropship_fly_by_time_seconds", 100, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCDropshipHijackTravelTimeSeconds = - CVarDef.Create("rmc.dropship_hijack_travel_time_seconds", 180, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCEntitiesLogDelete = - CVarDef.Create("rmc.entities_log_delete", false, CVar.SERVER | CVar.SERVERONLY); - - public static readonly CVarDef RMCPlanetMapVote = - CVarDef.Create("rmc.planet_map_vote", true, CVar.SERVER | CVar.SERVERONLY); - - public static readonly CVarDef RMCPlanetMapVoteExcludeLast = - CVarDef.Create("rmc.planet_map_vote_exclude_last", 2, CVar.SERVER | CVar.SERVERONLY); - - public static readonly CVarDef RMCTacticalMapAnnounceCooldownSeconds = - CVarDef.Create("rmc.tactical_map_announce_cooldown_seconds", 240, CVar.SERVER | CVar.SERVERONLY); - - public static readonly CVarDef RMCTacticalMapLineLimit = - CVarDef.Create("rmc.tactical_map_line_limit", 1000, CVar.SERVER | CVar.REPLICATED); - - public static readonly CVarDef RMCTacticalMapAdminHistorySize = - CVarDef.Create("rmc.tactical_map_admin_history_size", 100, CVar.SERVER | CVar.REPLICATED); - - public static readonly CVarDef RMCTacticalMapUpdateEverySeconds = - CVarDef.Create("rmc.tactical_map_update_every_seconds", 1f, CVar.SERVER | CVar.REPLICATED); - - public static readonly CVarDef RMCGunPrediction = - CVarDef.Create("rmc.gun_prediction", true, CVar.SERVER | CVar.REPLICATED); - - public static readonly CVarDef RMCGunPredictionPreventCollision = - CVarDef.Create("rmc.gun_prediction_prevent_collision", false, CVar.SERVER | CVar.REPLICATED); - - public static readonly CVarDef RMCGunPredictionLogHits = - CVarDef.Create("rmc.gun_prediction_log_hits", false, CVar.SERVER | CVar.REPLICATED); - - public static readonly CVarDef RMCGunPredictionCoordinateDeviation = - CVarDef.Create("rmc.gun_prediction_coordinate_deviation", 1f, CVar.SERVER | CVar.REPLICATED); - - public static readonly CVarDef RMCGunPredictionLowestCoordinateDeviation = - CVarDef.Create("rmc.gun_prediction_lowest_coordinate_deviation", 1f, CVar.SERVER | CVar.REPLICATED); - - public static readonly CVarDef RMCGunPredictionAabbEnlargement = - CVarDef.Create("rmc.gun_prediction_aabb_enlargement", 0.3f, CVar.SERVER | CVar.REPLICATED); - - public static readonly CVarDef RMCJobSlotScaling = - CVarDef.Create("rmc.job_slot_scaling", true, CVar.SERVER | CVar.REPLICATED); - - public static readonly CVarDef RMCEmoteCooldownSeconds = - CVarDef.Create("rmc.emote_cooldown_seconds", 20f, CVar.SERVER | CVar.REPLICATED); - - public static readonly CVarDef RMCPowerUpdateEverySeconds = - CVarDef.Create("rmc.power_update_every_seconds", 1f, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCPowerLoadMultiplier = - CVarDef.Create("rmc.power_load_multiplier", 0.01f, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCMarinesPerSurvivor = - CVarDef.Create("rmc.marines_per_survivor", 20, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCSurvivorsMinimum = - CVarDef.Create("rmc.survivors_minimum", 2, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCSurvivorsMaximum = - CVarDef.Create("rmc.survivors_maximum", 6, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCSpawnerMaxCorpses = - CVarDef.Create("rmc.spawner_max_corpses", 25, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCHiveSpreadEarlyMinutes = - CVarDef.Create("rmc.hive_spread_early_minutes", 40, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCNewPlayerTimeTotalHours = - CVarDef.Create("rmc.new_player_time_total_hours", 25, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCNewPlayerTimeJobHours = - CVarDef.Create("rmc.new_player_time_job_hours", 10, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCLateJoinsPerBurrowedLarvaEarlyThresholdMinutes = - CVarDef.Create("rmc.late_joins_per_burrowed_larva_early_threshold_minutes", 15f, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCLateJoinsPerBurrowedLarvaEarly = - CVarDef.Create("rmc.late_joins_per_burrowed_larva_early", 5.5f, CVar.REPLICATED | CVar.SERVER); - - public static readonly CVarDef RMCLateJoinsPerBurrowedLarva = - CVarDef.Create("rmc.late_joins_per_burrowed_larva", 4f, CVar.REPLICATED | CVar.SERVER); } diff --git a/Content.Shared/ADT/_RMC14/Input/CMKeyFunctions.cs b/Content.Shared/ADT/_RMC14/Input/CMKeyFunctions.cs index cf25188c598..23512343e59 100644 --- a/Content.Shared/ADT/_RMC14/Input/CMKeyFunctions.cs +++ b/Content.Shared/ADT/_RMC14/Input/CMKeyFunctions.cs @@ -12,8 +12,8 @@ public sealed class CMKeyFunctions public static readonly BoundKeyFunction RMCFieldStripHeldItem = "RMCFieldStripHeldItem"; public static readonly BoundKeyFunction RMCCycleFireMode = "RMCCycleFireMode"; public static readonly BoundKeyFunction CMUniqueAction = "CMUniqueAction"; - public static readonly BoundKeyFunction CMHolsterPrimary = "CMHolsterPrimary"; - public static readonly BoundKeyFunction CMHolsterSecondary = "CMHolsterSecondary"; - public static readonly BoundKeyFunction CMHolsterTertiary = "CMHolsterTertiary"; - public static readonly BoundKeyFunction CMHolsterQuaternary = "CMHolsterQuaternary"; +// public static readonly BoundKeyFunction CMHolsterPrimary = "CMHolsterPrimary"; +// public static readonly BoundKeyFunction CMHolsterSecondary = "CMHolsterSecondary"; +// public static readonly BoundKeyFunction CMHolsterTertiary = "CMHolsterTertiary"; +// public static readonly BoundKeyFunction CMHolsterQuaternary = "CMHolsterQuaternary"; } diff --git a/Content.Shared/ADT/_RMC14/Weapons/Melee/ImmuneToMeleeComponent.cs b/Content.Shared/ADT/_RMC14/Weapons/Melee/ImmuneToMeleeComponent.cs deleted file mode 100644 index 4a877aa907d..00000000000 --- a/Content.Shared/ADT/_RMC14/Weapons/Melee/ImmuneToMeleeComponent.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Content.Shared.Whitelist; -using Robust.Shared.GameStates; - -namespace Content.Shared._RMC14.Weapons.Melee; - -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] -[Access(typeof(SharedRMCMeleeWeaponSystem))] -public sealed partial class ImmuneToMeleeComponent : Component -{ - [DataField(required: true), AutoNetworkedField] - public EntityWhitelist? Whitelist; -} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Melee/ImmuneToUnarmedComponent.cs b/Content.Shared/ADT/_RMC14/Weapons/Melee/ImmuneToUnarmedComponent.cs deleted file mode 100644 index 72d0338f528..00000000000 --- a/Content.Shared/ADT/_RMC14/Weapons/Melee/ImmuneToUnarmedComponent.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Robust.Shared.GameStates; - -namespace Content.Shared._RMC14.Weapons.Melee; - -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] -[Access(typeof(SharedRMCMeleeWeaponSystem))] -public sealed partial class ImmuneToUnarmedComponent : Component -{ - [DataField, AutoNetworkedField] - public bool ApplyToXenos; -} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Melee/MeleeDamageMultiplierComponent.cs b/Content.Shared/ADT/_RMC14/Weapons/Melee/MeleeDamageMultiplierComponent.cs index 9c58c834a9b..b58a21e1fa8 100644 --- a/Content.Shared/ADT/_RMC14/Weapons/Melee/MeleeDamageMultiplierComponent.cs +++ b/Content.Shared/ADT/_RMC14/Weapons/Melee/MeleeDamageMultiplierComponent.cs @@ -1,5 +1,4 @@ -using Content.Shared.Whitelist; -using Robust.Shared.GameStates; +using Robust.Shared.GameStates; namespace Content.Shared._RMC14.Weapons.Melee; @@ -15,7 +14,4 @@ public sealed partial class MeleeDamageMultiplierComponent : Component /// [DataField, AutoNetworkedField] public float Multiplier = 0.5f; // x1.5 extra damage - - [DataField, AutoNetworkedField] - public EntityWhitelist Whitelist = new(); } diff --git a/Content.Shared/ADT/_RMC14/Weapons/Melee/SharedRMCMeleeWeaponSystem.cs b/Content.Shared/ADT/_RMC14/Weapons/Melee/SharedRMCMeleeWeaponSystem.cs index 3bd1b366bad..45184bcac7a 100644 --- a/Content.Shared/ADT/_RMC14/Weapons/Melee/SharedRMCMeleeWeaponSystem.cs +++ b/Content.Shared/ADT/_RMC14/Weapons/Melee/SharedRMCMeleeWeaponSystem.cs @@ -1,18 +1,14 @@ using Content.Shared.Damage; using Content.Shared.Interaction.Events; -using Content.Shared.Stunnable; using Content.Shared.Weapons.Melee; using Content.Shared.Weapons.Melee.Events; -using Content.Shared.Whitelist; using Robust.Shared.Timing; namespace Content.Shared._RMC14.Weapons.Melee; public abstract class SharedRMCMeleeWeaponSystem : EntitySystem { - [Dependency] private readonly SharedStunSystem _stun = default!; [Dependency] private readonly IGameTiming _timing = default!; - [Dependency] private readonly EntityWhitelistSystem _whitelist = default!; [Dependency] private readonly SharedMeleeWeaponSystem _melee = default!; private EntityQuery _meleeWeaponQuery; @@ -21,14 +17,8 @@ public override void Initialize() { _meleeWeaponQuery = GetEntityQuery(); - SubscribeLocalEvent(OnImmuneToUnarmedGettingAttacked); - - SubscribeLocalEvent(OnImmuneToMeleeGettingAttacked); - SubscribeLocalEvent(OnMeleeReceivedMultiplierDamageModify); - SubscribeLocalEvent(OnStunOnHitMeleeHit); - SubscribeLocalEvent(OnMultiplierOnHitMeleeHit); SubscribeAllEvent(OnLightAttack, before: new[] { typeof(SharedMeleeWeaponSystem) }); @@ -53,18 +43,6 @@ public void MeleeResetInit(Entity ent) Dirty(ent, ent.Comp); } - private void OnStunOnHitMeleeHit(Entity ent, ref MeleeHitEvent args) - { - if (!args.IsHit) - return; - - foreach (var hit in args.HitEntities) - { - if (_whitelist.IsValid(ent.Comp.Whitelist, hit)) - _stun.TryParalyze(hit, ent.Comp.Duration, true); - } - } - private void OnMultiplierOnHitMeleeHit(Entity ent, ref MeleeHitEvent args) { if (!args.IsHit) @@ -74,28 +52,12 @@ private void OnMultiplierOnHitMeleeHit(Entity en foreach (var hit in args.HitEntities) { - if (_whitelist.IsValid(comp.Whitelist, hit)) - { - var damage = args.BaseDamage * comp.Multiplier; - args.BonusDamage += damage; - break; - } + var damage = args.BaseDamage * comp.Multiplier; + args.BonusDamage += damage; + break; } } - private void OnImmuneToUnarmedGettingAttacked(Entity ent, ref GettingAttackedAttemptEvent args) - { - - if (args.Attacker == args.Weapon) - args.Cancelled = true; - } - - private void OnImmuneToMeleeGettingAttacked(Entity ent, ref GettingAttackedAttemptEvent args) - { - if (_whitelist.IsWhitelistPassOrNull(ent.Comp.Whitelist, args.Attacker)) - args.Cancelled = true; - } - private void OnMeleeReceivedMultiplierDamageModify(Entity ent, ref DamageModifyEvent args) { if (!_meleeWeaponQuery.HasComp(args.Tool)) diff --git a/Content.Shared/ADT/_RMC14/Weapons/Melee/StunOnHitComponent.cs b/Content.Shared/ADT/_RMC14/Weapons/Melee/StunOnHitComponent.cs deleted file mode 100644 index 5e02a697afd..00000000000 --- a/Content.Shared/ADT/_RMC14/Weapons/Melee/StunOnHitComponent.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Content.Shared.Whitelist; -using Robust.Shared.GameStates; - -namespace Content.Shared._RMC14.Weapons.Melee; - -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] -[Access(typeof(SharedRMCMeleeWeaponSystem))] -public sealed partial class StunOnHitComponent : Component -{ - [DataField, AutoNetworkedField] - public TimeSpan Duration = TimeSpan.FromSeconds(12); - - [DataField(required: true), AutoNetworkedField] - public EntityWhitelist Whitelist = new(); -} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/CMGunSystem.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/CMGunSystem.cs index cb75c4e3269..dd18baadd2c 100644 --- a/Content.Shared/ADT/_RMC14/Weapons/Ranged/CMGunSystem.cs +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/CMGunSystem.cs @@ -1,61 +1,31 @@ -using System.Numerics; -using Content.Shared._RMC14.Weapons.Common; +using Content.Shared._RMC14.Weapons.Common; using Content.Shared.Containers.ItemSlots; -using Content.Shared.FixedPoint; -using Content.Shared.Hands; -using Content.Shared.Hands.Components; using Content.Shared.Hands.EntitySystems; using Content.Shared.Interaction; -using Content.Shared.Interaction.Components; -using Content.Shared.Inventory; -using Content.Shared.Physics; using Content.Shared.Popups; -using Content.Shared.Projectiles; -using Content.Shared.Timing; using Content.Shared.Weapons.Ranged; using Content.Shared.Weapons.Ranged.Components; using Content.Shared.Weapons.Ranged.Events; using Content.Shared.Weapons.Ranged.Systems; -using Content.Shared.Whitelist; -using Content.Shared.Wieldable; -using Content.Shared.Wieldable.Components; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; -using Robust.Shared.Physics; -using Robust.Shared.Physics.Components; -using Robust.Shared.Physics.Events; -using Robust.Shared.Physics.Systems; using Robust.Shared.Random; -using Robust.Shared.Timing; namespace Content.Shared._RMC14.Weapons.Ranged; public sealed class CMGunSystem : EntitySystem { [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] private readonly SharedBroadphaseSystem _broadphase = default!; [Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly SharedGunSystem _gun = default!; - [Dependency] private readonly InventorySystem _inventory = default!; [Dependency] private readonly ItemSlotsSystem _slots = default!; [Dependency] private readonly SharedHandsSystem _hands = default!; - [Dependency] private readonly SharedPhysicsSystem _physics = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly IRobustRandom _random = default!; - [Dependency] private readonly IGameTiming _timing = default!; - [Dependency] private readonly SharedTransformSystem _transform = default!; - [Dependency] private readonly UseDelaySystem _useDelay = default!; - - private EntityQuery _physicsQuery; - private EntityQuery _projectileQuery; - - private readonly int _blockArcCollisionGroup = (int) (CollisionGroup.HighImpassable | CollisionGroup.Impassable); public override void Initialize() { - _physicsQuery = GetEntityQuery(); - _projectileQuery = GetEntityQuery(); - + SubscribeLocalEvent(OnRevolverUniqueAction); SubscribeLocalEvent(OnAmmoEjectActivateInWorld); } @@ -104,4 +74,20 @@ private void OnAmmoEjectActivateInWorld(Entity gun, ref A _hands.TryPickup(args.User, ejectedAmmo, hand); } + + private void OnRevolverUniqueAction(Entity gun, ref UniqueActionEvent args) + { + if (args.Handled) + return; + + int randomCount = _random.Next(1, gun.Comp.Capacity + 1); + + gun.Comp.CurrentIndex = (gun.Comp.CurrentIndex + randomCount) % gun.Comp.Capacity; + + _audio.PlayPredicted(gun.Comp.SoundSpin, gun.Owner, args.UserUid); + var popup = Loc.GetString("rmc-revolver-spin", ("gun", args.UserUid)); + _popup.PopupClient(popup, args.UserUid, args.UserUid, PopupType.SmallCaution); + + Dirty(gun); + } } diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/Recoil/GunToggleRecoilActionEvent.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/Recoil/GunToggleRecoilActionEvent.cs deleted file mode 100644 index f317eb59449..00000000000 --- a/Content.Shared/ADT/_RMC14/Weapons/Ranged/Recoil/GunToggleRecoilActionEvent.cs +++ /dev/null @@ -1,5 +0,0 @@ -using Content.Shared.Actions; - -namespace Content.Shared._RMC14.Weapons.Ranged.Recoil; - -public sealed partial class GunToggleRecoilActionEvent : InstantActionEvent; diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/Recoil/GunToggleableRecoilComponent.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/Recoil/GunToggleableRecoilComponent.cs deleted file mode 100644 index 6eb8c790c1e..00000000000 --- a/Content.Shared/ADT/_RMC14/Weapons/Ranged/Recoil/GunToggleableRecoilComponent.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Robust.Shared.Audio; -using Robust.Shared.GameStates; -using Robust.Shared.Prototypes; - -namespace Content.Shared._RMC14.Weapons.Ranged.Recoil; - -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] -[Access(typeof(GunToggleableRecoilSystem))] -public sealed partial class GunToggleableRecoilComponent : Component -{ - [DataField, AutoNetworkedField] - public bool Active; - - [DataField, AutoNetworkedField] - public float BatteryDrain = 1.25f; - - [DataField, AutoNetworkedField] - public EntProtoId ActionId = "RMCActionToggleRecoil"; - - [DataField, AutoNetworkedField] - public EntityUid? Action; - - [DataField, AutoNetworkedField] - public SoundSpecifier ToggleSound = new SoundPathSpecifier("/Audio/_RMC14/Machines/click.ogg"); -} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/Recoil/GunToggleableRecoilSystem.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/Recoil/GunToggleableRecoilSystem.cs deleted file mode 100644 index 32b5c611faf..00000000000 --- a/Content.Shared/ADT/_RMC14/Weapons/Ranged/Recoil/GunToggleableRecoilSystem.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Content.Shared.Actions; -using Content.Shared.Popups; -using Content.Shared.Weapons.Ranged.Events; -using Content.Shared.Weapons.Ranged.Systems; -using Robust.Shared.Audio.Systems; - -namespace Content.Shared._RMC14.Weapons.Ranged.Recoil; - -public sealed class GunToggleableRecoilSystem : EntitySystem -{ - [Dependency] private readonly SharedActionsSystem _actions = default!; - [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] private readonly SharedGunSystem _gun = default!; - [Dependency] private readonly SharedPopupSystem _popup = default!; - - public override void Initialize() - { - SubscribeLocalEvent(OnGetItemActions); - SubscribeLocalEvent(OnToggleRecoil); - SubscribeLocalEvent(OnRefreshModifiers); - } - - private void OnGetItemActions(Entity ent, ref GetItemActionsEvent args) - { - args.AddAction(ref ent.Comp.Action, ent.Comp.ActionId); - Dirty(ent); - } - - private void OnToggleRecoil(Entity ent, ref GunToggleRecoilActionEvent args) - { - args.Handled = true; - ent.Comp.Active = !ent.Comp.Active; - ActiveChanged(ent, args.Performer); - } - - private void OnRefreshModifiers(Entity ent, ref GunRefreshModifiersEvent args) - { - if (!ent.Comp.Active) - return; - - args.MinAngle = Angle.Zero; - args.MaxAngle = Angle.Zero; - args.CameraRecoilScalar = 0; - } - - private void ActiveChanged(Entity ent, EntityUid? user) - { - Dirty(ent); - - _actions.SetToggled(ent.Comp.Action, ent.Comp.Active); - _gun.RefreshModifiers(ent.Owner); - - _audio.PlayPredicted(ent.Comp.ToggleSound, ent.Owner, user); - - if (user == null) - return; - - var popup = ent.Comp.Active - ? Loc.GetString("rmc-toggleable-recoil-compensation-on", ("gun", ent.Owner)) - : Loc.GetString("rmc-toggleable-recoil-compensation-off", ("gun", ent.Owner)); - _popup.PopupClient(popup, user.Value, user.Value, PopupType.Large); - } -} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/Stacks/GunStacksComponent.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/Stacks/GunStacksComponent.cs deleted file mode 100644 index 5884f17bb26..00000000000 --- a/Content.Shared/ADT/_RMC14/Weapons/Ranged/Stacks/GunStacksComponent.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Content.Shared.FixedPoint; -using Robust.Shared.GameStates; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; - -namespace Content.Shared._RMC14.Weapons.Ranged.Stacks; - -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause] -[Access(typeof(GunStacksSystem))] -public sealed partial class GunStacksComponent : Component -{ - [DataField, AutoNetworkedField] - public int IncreaseAP = 10; - - [DataField, AutoNetworkedField] - public int MaxAP = 50; - - [DataField, AutoNetworkedField] - public FixedPoint2 DamageIncrease = FixedPoint2.New(0.5); - - [DataField, AutoNetworkedField] - public float SetFireRate = 1.4285f; - - [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField, AutoPausedField] - public TimeSpan LastHitAt; - - [DataField, AutoNetworkedField] - public TimeSpan StacksExpire = TimeSpan.FromSeconds(4); - - [DataField, AutoNetworkedField] - public int Hits; -} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/Stacks/GunStacksProjectileComponent.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/Stacks/GunStacksProjectileComponent.cs deleted file mode 100644 index 1e9c0221cd1..00000000000 --- a/Content.Shared/ADT/_RMC14/Weapons/Ranged/Stacks/GunStacksProjectileComponent.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Robust.Shared.GameStates; - -namespace Content.Shared._RMC14.Weapons.Ranged.Stacks; - -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] -[Access(typeof(GunStacksSystem))] -public sealed partial class GunStacksProjectileComponent : Component -{ - [DataField, AutoNetworkedField] - public EntityUid? Gun; -} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/Stacks/GunStacksSystem.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/Stacks/GunStacksSystem.cs deleted file mode 100644 index 8fad757bd1b..00000000000 --- a/Content.Shared/ADT/_RMC14/Weapons/Ranged/Stacks/GunStacksSystem.cs +++ /dev/null @@ -1,97 +0,0 @@ -using Content.Shared._RMC14.Armor; -using Content.Shared.Interaction.Events; -using Content.Shared.Mobs.Systems; -using Content.Shared.Popups; -using Content.Shared.Projectiles; -using Content.Shared.Weapons.Ranged.Events; -using Robust.Shared.Network; -using Robust.Shared.Timing; - -namespace Content.Shared._RMC14.Weapons.Ranged.Stacks; - -public sealed class GunStacksSystem : EntitySystem -{ - [Dependency] private readonly MobStateSystem _mobState = default!; - [Dependency] private readonly INetManager _net = default!; - [Dependency] private readonly SharedPopupSystem _popup = default!; - [Dependency] private readonly RMCSelectiveFireSystem _rmcSelectiveFire = default!; - [Dependency] private readonly IGameTiming _timing = default!; - - private EntityQuery _gunStacksQuery; - private EntityQuery _selectiveFireQuery; - - public override void Initialize() - { - _gunStacksQuery = GetEntityQuery(); - _selectiveFireQuery = GetEntityQuery(); - - SubscribeLocalEvent(OnStacksGetGunDamageModifier); - SubscribeLocalEvent(OnStacksGetGunFireRate); - SubscribeLocalEvent(OnStacksAmmoShot); - SubscribeLocalEvent(OnStacksDropped); - - SubscribeLocalEvent(OnStacksProjectileHit); - } - - private void OnStacksGetGunDamageModifier(Entity ent, ref GetGunDamageModifierEvent args) - { - if (ent.Comp.Hits > 0) - args.Multiplier += ent.Comp.DamageIncrease; - } - - private void OnStacksGetGunFireRate(Entity ent, ref GunGetFireRateEvent args) - { - if (ent.Comp.Hits > 0) - args.FireRate = ent.Comp.SetFireRate; - } - - private void OnStacksAmmoShot(Entity ent, ref AmmoShotEvent args) - { - var time = _timing.CurTime; - if (ent.Comp.Hits > 0 && time >= ent.Comp.LastHitAt + ent.Comp.StacksExpire) - { - ent.Comp.Hits = 0; - Dirty(ent); - } - - foreach (var bullet in args.FiredProjectiles) - { - var stacks = EnsureComp(bullet); - stacks.Gun = ent; - Dirty(bullet, stacks); - - var ap = Math.Min(ent.Comp.MaxAP, ent.Comp.IncreaseAP * ent.Comp.Hits); - } - } - - private void OnStacksDropped(Entity ent, ref DroppedEvent args) - { - Reset(ent); - } - - private void OnStacksProjectileHit(Entity ent, ref ProjectileHitEvent args) - { - if (!_gunStacksQuery.TryComp(ent.Comp.Gun, out var gun)) - return; - - if (TryComp(ent, out ProjectileComponent? projectile) && - projectile.DamagedEntity) - { - return; - } - - var target = args.Target; - - - if (_selectiveFireQuery.TryComp(ent.Comp.Gun, out var selective)) - _rmcSelectiveFire.RefreshFireModeGunValues((ent.Comp.Gun.Value, selective)); - - Dirty(ent); - } - - private void Reset(Entity gun) - { - gun.Comp.Hits = 0; - Dirty(gun); - } -} diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Revolvers/saber_revolvers.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Revolvers/saber_revolvers.yml index f0b00f0ed67..f7549fcc04c 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Revolvers/saber_revolvers.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Revolvers/saber_revolvers.yml @@ -104,4 +104,4 @@ tags: - ADTLasgunRevolverCell - type: AltFireMelee - AltFireAttackType: Heavy + AttackType: Heavy From 2611001acff875696e65e273d6844dc14ed5ec73 Mon Sep 17 00:00:00 2001 From: Inconnu1337 Date: Sat, 16 Nov 2024 02:20:05 +0200 Subject: [PATCH 06/46] =?UTF-8?q?=D0=B4=D0=BE=D0=BB=D0=B1=D0=B0=D0=B5?= =?UTF-8?q?=D0=B1=20=D0=B1=D0=BB=D1=8F=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Content.Shared/ADT/_RMC14/Input/CMKeyFunctions.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Content.Shared/ADT/_RMC14/Input/CMKeyFunctions.cs b/Content.Shared/ADT/_RMC14/Input/CMKeyFunctions.cs index 23512343e59..cf25188c598 100644 --- a/Content.Shared/ADT/_RMC14/Input/CMKeyFunctions.cs +++ b/Content.Shared/ADT/_RMC14/Input/CMKeyFunctions.cs @@ -12,8 +12,8 @@ public sealed class CMKeyFunctions public static readonly BoundKeyFunction RMCFieldStripHeldItem = "RMCFieldStripHeldItem"; public static readonly BoundKeyFunction RMCCycleFireMode = "RMCCycleFireMode"; public static readonly BoundKeyFunction CMUniqueAction = "CMUniqueAction"; -// public static readonly BoundKeyFunction CMHolsterPrimary = "CMHolsterPrimary"; -// public static readonly BoundKeyFunction CMHolsterSecondary = "CMHolsterSecondary"; -// public static readonly BoundKeyFunction CMHolsterTertiary = "CMHolsterTertiary"; -// public static readonly BoundKeyFunction CMHolsterQuaternary = "CMHolsterQuaternary"; + public static readonly BoundKeyFunction CMHolsterPrimary = "CMHolsterPrimary"; + public static readonly BoundKeyFunction CMHolsterSecondary = "CMHolsterSecondary"; + public static readonly BoundKeyFunction CMHolsterTertiary = "CMHolsterTertiary"; + public static readonly BoundKeyFunction CMHolsterQuaternary = "CMHolsterQuaternary"; } From 8d4eb9b616746bf79b16d618780b7749a5adedd1 Mon Sep 17 00:00:00 2001 From: Inconnu1337 Date: Tue, 19 Nov 2024 10:51:01 +0200 Subject: [PATCH 07/46] =?UTF-8?q?=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_RMC14/Inventory/CMHolsterComponent.cs | 4 +- .../Weapons/Ranged/PumpActionComponent.cs | 2 +- .../Objects/Weapons/Shotguns/shotguns.yml | 9 ++++ .../Actions/Marines/marine_action_base.yml | 4 -- .../Actions/Marines/marine_action_items.yml | 47 ++++-------------- .../Weapons/Guns/Shotguns/shotguns.yml | 2 +- .../Attachments/scope_actions.rsi/meta.json | 14 ++++++ .../scope_actions.rsi/sniperscope.png | Bin 0 -> 370 bytes 8 files changed, 38 insertions(+), 44 deletions(-) delete mode 100644 Resources/Prototypes/ADT/_RMC14/Actions/Marines/marine_action_base.yml create mode 100644 Resources/Textures/ADT/Objects/Attachments/scope_actions.rsi/meta.json create mode 100644 Resources/Textures/ADT/Objects/Attachments/scope_actions.rsi/sniperscope.png diff --git a/Content.Shared/ADT/_RMC14/Inventory/CMHolsterComponent.cs b/Content.Shared/ADT/_RMC14/Inventory/CMHolsterComponent.cs index 19bf140620b..4e45e5ea770 100644 --- a/Content.Shared/ADT/_RMC14/Inventory/CMHolsterComponent.cs +++ b/Content.Shared/ADT/_RMC14/Inventory/CMHolsterComponent.cs @@ -37,11 +37,11 @@ public sealed partial class CMHolsterComponent : Component /// Sound played whenever an entity is inserted into holster. /// [DataField] - public SoundSpecifier? InsertSound = new SoundPathSpecifier("/Audio/_RMC14/Weapons/Guns/gun_pistol_sheathe.ogg"); + public SoundSpecifier? InsertSound = new SoundPathSpecifier("/Audio/Corvax/Weapons/Guns/Cock/shotgun_cock.ogg"); // затычка /// /// Sound played whenever an entity is removed from holster. /// [DataField] - public SoundSpecifier? EjectSound = new SoundPathSpecifier("/Audio/_RMC14/Weapons/Guns/gun_pistol_draw.ogg"); + public SoundSpecifier? EjectSound = new SoundPathSpecifier("/Audio/Corvax/Weapons/Guns/Cock/shotgun_cock.ogg"); // затычка } diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/PumpActionComponent.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/PumpActionComponent.cs index 706f29f0dd9..b4e7476c7e0 100644 --- a/Content.Shared/ADT/_RMC14/Weapons/Ranged/PumpActionComponent.cs +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/PumpActionComponent.cs @@ -11,7 +11,7 @@ public sealed partial class PumpActionComponent : Component public bool Pumped; [DataField, AutoNetworkedField] - public SoundSpecifier Sound = new SoundCollectionSpecifier("CMShotgunPump"); + public SoundSpecifier? Sound = new SoundPathSpecifier("/Audio/Corvax/Weapons/Guns/Cock/shotgun_cock.ogg"); [DataField, AutoNetworkedField] public LocId Examine = "cm-gun-pump-examine"; diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Shotguns/shotguns.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Shotguns/shotguns.yml index 2ff844c9278..9e023a802e5 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Shotguns/shotguns.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Shotguns/shotguns.yml @@ -33,3 +33,12 @@ ents: [] - type: StaticPrice price: 4500 + +- type: entity + id: ADTBasePumpingGun + components: + - type: UniqueAction + - type: PumpAction + - type: Appearance + - type: BallisticAmmoProvider + cycleable: true diff --git a/Resources/Prototypes/ADT/_RMC14/Actions/Marines/marine_action_base.yml b/Resources/Prototypes/ADT/_RMC14/Actions/Marines/marine_action_base.yml deleted file mode 100644 index 2c4891bfe51..00000000000 --- a/Resources/Prototypes/ADT/_RMC14/Actions/Marines/marine_action_base.yml +++ /dev/null @@ -1,4 +0,0 @@ -- type: entity - id: ActionMarineBase - categories: - - HideSpawnMenu diff --git a/Resources/Prototypes/ADT/_RMC14/Actions/Marines/marine_action_items.yml b/Resources/Prototypes/ADT/_RMC14/Actions/Marines/marine_action_items.yml index 514c2535b74..9d03cc25cf9 100644 --- a/Resources/Prototypes/ADT/_RMC14/Actions/Marines/marine_action_items.yml +++ b/Resources/Prototypes/ADT/_RMC14/Actions/Marines/marine_action_items.yml @@ -1,25 +1,30 @@ - type: entity - parent: ActionMarineBase + id: ADTActionBase + categories: + - HideSpawnMenu + +- type: entity + parent: ADTActionBase id: CMActionToggleScope name: Toggle Optics description: Scope in or out with your optics. components: - type: InstantAction icon: - sprite: _RMC14/Actions/scope_actions.rsi + sprite: ADT/Objects/Attachments/scope_actions.rsi state: sniperscope event: !type:ToggleActionEvent useDelay: 0.25 - type: entity - parent: ActionMarineBase + parent: ADTActionBase id: RMCActionCycleZoomLevel name: Cycle Zoom Level description: Change the level of magnification of your optics. components: - type: InstantAction icon: - sprite: _RMC14/Actions/scope_actions.rsi + sprite: ADT/Objects/Attachments/scope_actions.rsi state: sniperscope event: !type:ScopeCycleZoomLevelEvent useDelay: 0.25 @@ -28,46 +33,16 @@ - RMCActionCycleZoomLevel - type: entity - parent: ActionMarineBase - id: CMActionToggleScoutVision - name: Toggle the M42 scout sight - description: Allows you to see even in complete darkness. - components: - - type: InstantAction - icon: - sprite: _RMC14/Objects/Clothing/Eyes/Glasses/m42_scoutsight.rsi - state: icon - iconOn: - sprite: _RMC14/Objects/Clothing/Eyes/Glasses/m42_scoutsight.rsi - state: icon_on - event: !type:ToggleActionEvent - useDelay: 0.25 - -- type: entity - parent: ActionMarineBase + parent: ADTActionBase id: CMActionToggleAttachable name: Toggle Attachable description: Toggle an attachable. If you're seeing this, someone forgot to set the description properly. components: - type: InstantAction icon: - sprite: _RMC14/Actions/scope_actions.rsi + sprite: ADT/Objects/Attachments/scope_actions.rsi state: sniperscope event: !type:AttachableToggleActionEvent -- type: entity - parent: ActionMarineBase - id: RMCActionWhistle - name: Whistle - description: Blow the whistle. - components: - - type: InstantAction - itemIconStyle: NoItem - icon: - sprite: _RMC14/Objects/Devices/whistle.rsi - state: whistle - event: !type:SoundActionEvent - useDelay: 10 - - type: Tag id: RMCActionCycleZoomLevel diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Shotguns/shotguns.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Shotguns/shotguns.yml index 473ba3f3983..f1661ad952c 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Shotguns/shotguns.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Shotguns/shotguns.yml @@ -167,7 +167,7 @@ - type: entity name: Kammerer - parent: [BaseWeaponShotgun, BaseGunWieldable, BaseRestrictedContraband] + parent: [BaseWeaponShotgun, BaseGunWieldable, BaseRestrictedContraband, ADTBasePumpingGun] # adt tweak id: WeaponShotgunKammerer description: When an old Remington design meets modern materials, this is the result. A favourite weapon of militia forces throughout many worlds. Uses .50 shotgun shells. components: diff --git a/Resources/Textures/ADT/Objects/Attachments/scope_actions.rsi/meta.json b/Resources/Textures/ADT/Objects/Attachments/scope_actions.rsi/meta.json new file mode 100644 index 00000000000..13673645db9 --- /dev/null +++ b/Resources/Textures/ADT/Objects/Attachments/scope_actions.rsi/meta.json @@ -0,0 +1,14 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from cmss13 at https://github.com/cmss13-devs/cmss13/blob/7cb618c69b75873f3ce893022fe08d1233b3152d/icons/obj/items/weapons/guns/attachments/rail.dmi", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "sniperscope" + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/ADT/Objects/Attachments/scope_actions.rsi/sniperscope.png b/Resources/Textures/ADT/Objects/Attachments/scope_actions.rsi/sniperscope.png new file mode 100644 index 0000000000000000000000000000000000000000..d408b671953a843baf6d7abfaf05854f4991a45b GIT binary patch literal 370 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv(mfq_xQ z)5S5QV$R!18~d6Z1lrnNxH)$jszfCymIZuf*`sBu%gO8S;G3z__sFLsQZ*uC&CI>g z=Zy6PzZ9MQbF%Gcx!LCX2G&jWVvGU|V01vC;cS{}$ez1(61AWG8EpRt5;oe%3#zv&2;|r6j9f}14)KcpA}e~I(lP?t^NG-Ps;b( zAFR;1Wpk*+lly=K^YzkH8CSsv_Z>QxWu_#SKGePNG^yeJ?+MQ>XDs79@4 Date: Tue, 19 Nov 2024 11:05:04 +0200 Subject: [PATCH 08/46] =?UTF-8?q?=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ADT/_RMC14/attachable/attachable.ftl | 69 +++++++++++++++++++ .../Locale/ru-RU/ADT/_RMC14/weapons/guns.ftl | 26 +++++++ .../ru-RU/ADT/_RMC14/weapons/magnetize.ftl | 1 + 3 files changed, 96 insertions(+) create mode 100644 Resources/Locale/ru-RU/ADT/_RMC14/attachable/attachable.ftl create mode 100644 Resources/Locale/ru-RU/ADT/_RMC14/weapons/guns.ftl create mode 100644 Resources/Locale/ru-RU/ADT/_RMC14/weapons/magnetize.ftl diff --git a/Resources/Locale/ru-RU/ADT/_RMC14/attachable/attachable.ftl b/Resources/Locale/ru-RU/ADT/_RMC14/attachable/attachable.ftl new file mode 100644 index 00000000000..c0f987002fd --- /dev/null +++ b/Resources/Locale/ru-RU/ADT/_RMC14/attachable/attachable.ftl @@ -0,0 +1,69 @@ +rmc-attachable-holder-strip-ui-title = strip attachables +rmc-attachable-holder-strip-ui-empty-slot = nothing + +rmc-verb-strip-attachables = Strip Attachables + +rmc-aslot-barrel = Barrel +rmc-aslot-rail = Rail +rmc-aslot-stock = Stock +rmc-aslot-underbarrel = Underbarrel + +rmc-attachable-activation-fail-not-wielded = {CAPITALIZE(THE($holder))} must be wielded to activate {THE($attachable)}! +rmc-attachable-activation-fail-not-held = {CAPITALIZE(THE($holder))} must be held to activate {THE($attachable)}! +rmc-attachable-activation-fail-not-owned = {CAPITALIZE(THE($holder))} must be held or equipped by you to activate {THE($attachable)}! + +rmc-attachable-shoot-fail-not-wielded = {CAPITALIZE(THE($holder))} must be wielded to shoot {THE($attachable)}! + +rmc-attachable-verb-toggle = Toggle {THE($attachable)} + +attachable-popup-activate-generic = You activate {THE($attachable)}. +attachable-popup-deactivate-generic = You deactivate {THE($attachable)}. + +attachable-popup-activate-deploy-on-generic = You deploy {THE($attachable)} on {THE($surface)}. +attachable-popup-activate-deploy-on-ground = You deploy {THE($attachable)} on the ground. +attachable-popup-deactivate-retract = You retract {THE($attachable)}. + +attachable-popup-activate-unfold = You unfold {THE($attachable)}. +attachable-popup-deactivate-collapse = You collapse {THE($attachable)}. + +attachable-popup-activate-lock = You lock {THE($attachable)}. +attachable-popup-deactivate-unlock = You unlock {THE($attachable)}. + +attachable-popup-switch-to-generic = You switch to using {THE($attachable)}. +attachable-popup-switch-from-generic = You stop using {THE($attachable)}. + +rmc-attachable-examinable-verb-text = Attachable Modifiers +rmc-attachable-examinable-verb-message = Examine the modifiers applied by this attachable. + +rmc-attachable-examine-condition-always = [bold]Always:[/bold] +rmc-attachable-examine-condition-when = When +rmc-attachable-examine-condition-wielded = the holder is [bold]wielded[/bold] +rmc-attachable-examine-condition-unwielded = the holder is [bold]not wielded[/bold] +rmc-attachable-examine-condition-active = {THE($attachable)} is [bold]active[/bold] +rmc-attachable-examine-condition-inactive = {THE($attachable)} is [bold]inactive[/bold] + +rmc-attachable-examine-condition-whitelist-comps = the holder [bold]has {$compNumber}[/bold] of the following components: [bold]{$comps}[/bold] +rmc-attachable-examine-condition-whitelist-sizes = the holder [bold]is[/bold] one of the following sizes: [bold]{$sizes}[/bold] +rmc-attachable-examine-condition-whitelist-tags = the holder [bold]has {$tagNumber}[/bold] of the following tags: [bold]{$tags}[/bold] + +rmc-attachable-examine-condition-blacklist-comps = the holder [bold]lacks {$compNumber}[/bold] of the following components: [bold]{$comps}[/bold] +rmc-attachable-examine-condition-blacklist-sizes = the holder [bold]is not[/bold] one of the following sizes: [bold]{$sizes}[/bold] +rmc-attachable-examine-condition-blacklist-tags = the holder [bold]lacks {$tagNumber}[/bold] of the following tags: [bold]{$tags}[/bold] + +rmc-attachable-examine-ranged-scatter = [color={$colour}]{$sign}{$scatter}[/color] degrees of scatter. +rmc-attachable-examine-ranged-burst-scatter = [color={$colour}]{$sign}{$burstScatterMult}[/color] burst scatter multiplier. +rmc-attachable-examine-ranged-shots-per-burst = [color={$colour}]{$sign}{$shots}[/color] burst shots. +rmc-attachable-examine-ranged-fire-delay = [color={$colour}]{$sign}{TOSTRING($fireDelay, "F2")}[/color] seconds of fire delay. +rmc-attachable-examine-ranged-recoil = [color={$colour}]{$sign}{$recoil}[/color] recoil. +rmc-attachable-examine-ranged-damage = [color={$colour}]{$sign}{$damage}[/color] ranged damage multiplier. +rmc-attachable-examine-ranged-projectile-speed = [color={$colour}]{$sign}{$projectileSpeed}[/color] projectile speed. +rmc-attachable-examine-ranged-damage-falloff = [color={$colour}]{$sign}{$falloff}[/color] falloff multiplier. + +rmc-attachable-examine-melee-damage = [color={$colour}]{$sign}{$damage}[/color] melee damage. + +rmc-attachable-examine-size = [color={$colour}]{$sign}{$size}[/color] item size. + +rmc-attachable-examine-speed-walk = [color={$colour}]{$sign}{TOSTRING($speed, "F2")}[/color] walking speed multiplier. +rmc-attachable-examine-speed-sprint = [color={$colour}]{$sign}{TOSTRING($speed, "F2")}[/color] running speed multiplier. + +rmc-attachable-examine-wield-delay = [color={$colour}]{$sign}{$delay}[/color] seconds of wield delay. \ No newline at end of file diff --git a/Resources/Locale/ru-RU/ADT/_RMC14/weapons/guns.ftl b/Resources/Locale/ru-RU/ADT/_RMC14/weapons/guns.ftl new file mode 100644 index 00000000000..45333c50378 --- /dev/null +++ b/Resources/Locale/ru-RU/ADT/_RMC14/weapons/guns.ftl @@ -0,0 +1,26 @@ +cm-gun-no-ammo-message = You don't have any ammo left! +cm-gun-use-delay = You need to wait {$seconds} seconds before shooting again! +cm-gun-pump-examine = [bold]Press your [color=cyan]unique action[/color] keybind (Spacebar by default) to pump before shooting.[/bold] +cm-gun-pump-first-with = You need to pump the gun with {$key} first! +cm-gun-pump-first = You need to pump the gun first! + +rmc-breech-loaded-open-shoot-attempt = You need to close the breech first! +rmc-breech-loaded-not-ready-to-shoot = You need to open and close the breech first! +rmc-breech-loaded-closed-load-attempt = You need to open the breech first! +rmc-breech-loaded-closed-extract-attempt = You need to open the breech first! + +rmc-wield-use-delay = You need to wait {$seconds} seconds before wielding {THE($wieldable)}! +rmc-shoot-use-delay = You need to wait {$seconds} seconds before shooting {THE($wieldable)}! + +rmc-shoot-harness-required = Harness required +rmc-wear-smart-gun-required = You must have your smart gun equipped to wear these. + +rmc-revolver-spin = You spin the cylinder. + +rmc-examine-text-scatter-max = Current maximum scatter is [color={$colour}]{TOSTRING($scatter, "F1")}[/color] degrees. +rmc-examine-text-scatter-min = Current minimum scatter is [color={$colour}]{TOSTRING($scatter, "F1")}[/color] degrees. +rmc-examine-text-shots-to-max-scatter = It takes [color={$colour}]{$shots}[/color] shots to reach maximum scatter. + +rmc-gun-rack-examine = [bold]Press your [color=cyan]unique action[/color] keybind (Spacebar by default) to rack before shooting.[/bold] +rmc-gun-rack-first-with = You need to rack the gun with {$key} first! +rmc-gun-rack-first = You need to rack the gun first! \ No newline at end of file diff --git a/Resources/Locale/ru-RU/ADT/_RMC14/weapons/magnetize.ftl b/Resources/Locale/ru-RU/ADT/_RMC14/weapons/magnetize.ftl new file mode 100644 index 00000000000..9a011089725 --- /dev/null +++ b/Resources/Locale/ru-RU/ADT/_RMC14/weapons/magnetize.ftl @@ -0,0 +1 @@ +rmc-magnetize-return = {CAPITALIZE(THE($item))} snaps into place on {$magnetizer}. \ No newline at end of file From 8e708598f840460fc5b276e05f677375d65f1950 Mon Sep 17 00:00:00 2001 From: Inconnu1337 Date: Fri, 22 Nov 2024 03:39:57 +0200 Subject: [PATCH 09/46] =?UTF-8?q?=D1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AttachableHolderVisualsComponent.cs | 0 .../Components/AttachableVisualsComponent.cs | 0 .../Systems/AttachableHolderVisualsSystem.cs | 0 .../Ui/AttachableHolderChooseSlotMenu.xaml | 0 .../Ui/AttachableHolderChooseSlotMenu.xaml.cs | 2 +- .../Ui/AttachableHolderStripMenu.xaml | 0 .../Ui/AttachableHolderStripMenu.xaml.cs | 2 +- .../Attachable/Ui/AttachmentChooseSlotBui.cs | 2 +- .../Attachable/Ui/AttachmentStripBui.cs | 2 +- .../{ => ADT}/_RMC14/Scoping/ScopeSystem.cs | 0 .../_RMC14/Weapons/Ranged/PumpActionSystem.cs | 0 Content.Client/Input/ContentContexts.cs | 8 +- .../Options/UI/Tabs/KeyRebindTab.xaml.cs | 8 +- .../ActiveTriggerOnThrowEndComponent.cs | 12 ++ .../OnShootTriggerAmmoTimerComponent.cs | 20 ++++ .../ADT/_RMC14/Trigger/RMCTriggerSystem.cs | 48 ++++++++ .../TriggerOnFixedDistanceStopComponent.cs | 11 ++ .../Components/AttachableComponent.cs | 4 +- .../AttachableToggleableComponent.cs | 6 +- .../ADT/_RMC14/Scoping/ScopeComponent.cs | 4 +- .../Weapons/Common/UniqueActionSystem.cs | 30 ++--- .../ADT/_RMC14/Weapons/Ranged/CMGunSystem.cs | 105 ++++++++++++++++-- .../ProjectileFixedDistanceComponent.cs | 21 ++++ .../ProjectileFixedDistanceStopEvent.cs | 4 + .../Ranged/ShootAtFixedPointComponent.cs | 23 ++++ .../Projectiles/ProjectileComponent.cs | 13 ++- .../ADT/Attachments/attachment_activate.ogg | Bin 0 -> 8467 bytes .../Audio/ADT/Attachments/attachment_add.ogg | Bin 0 -> 11583 bytes .../ADT/Attachments/attachment_deactivate.ogg | Bin 0 -> 8436 bytes .../ADT/Attachments/attachment_remove.ogg | Bin 0 -> 11428 bytes .../Audio/ADT/Attachments/attributions.yml | 19 ++++ .../Weapons/Guns/Breech/attributions.yml | 9 ++ .../_RMC14/Weapons/Guns/Breech/ugl_close.ogg | Bin 0 -> 6685 bytes .../_RMC14/Weapons/Guns/Breech/ugl_open.ogg | Bin 0 -> 6685 bytes .../ADT/_RMC14/attachable/attachable.ftl | 69 ------------ .../Locale/ru-RU/ADT/_RMC14/weapons/guns.ftl | 26 ----- .../ru-RU/ADT/_RMC14/weapons/magnetize.ftl | 1 - .../ADT/attachments/attachable/attachable.ftl | 69 ++++++++++++ .../ru-RU/ADT/attachments/weapons/guns.ftl | 23 ++++ .../ADT/attachments/weapons/magnetize.ftl | 1 + .../Guns/Attachments/Actions/actions.yml} | 16 +-- .../Weapons/Guns/Attachments}/test.yml | 12 ++ .../Objects/Weapons/Shotguns/shotguns.yml | 6 + .../Weapons/Guns/Revolvers/revolvers.yml | 1 + 44 files changed, 429 insertions(+), 148 deletions(-) rename Content.Client/{ => ADT}/_RMC14/Attachable/Components/AttachableHolderVisualsComponent.cs (100%) rename Content.Client/{ => ADT}/_RMC14/Attachable/Components/AttachableVisualsComponent.cs (100%) rename Content.Client/{ => ADT}/_RMC14/Attachable/Systems/AttachableHolderVisualsSystem.cs (100%) rename Content.Client/{ => ADT}/_RMC14/Attachable/Ui/AttachableHolderChooseSlotMenu.xaml (100%) rename Content.Client/{ => ADT}/_RMC14/Attachable/Ui/AttachableHolderChooseSlotMenu.xaml.cs (97%) rename Content.Client/{ => ADT}/_RMC14/Attachable/Ui/AttachableHolderStripMenu.xaml (100%) rename Content.Client/{ => ADT}/_RMC14/Attachable/Ui/AttachableHolderStripMenu.xaml.cs (98%) rename Content.Client/{ => ADT}/_RMC14/Attachable/Ui/AttachmentChooseSlotBui.cs (95%) rename Content.Client/{ => ADT}/_RMC14/Attachable/Ui/AttachmentStripBui.cs (95%) rename Content.Client/{ => ADT}/_RMC14/Scoping/ScopeSystem.cs (100%) rename Content.Client/{ => ADT}/_RMC14/Weapons/Ranged/PumpActionSystem.cs (100%) create mode 100644 Content.Server/ADT/_RMC14/Trigger/ActiveTriggerOnThrowEndComponent.cs create mode 100644 Content.Server/ADT/_RMC14/Trigger/OnShootTriggerAmmoTimerComponent.cs create mode 100644 Content.Server/ADT/_RMC14/Trigger/RMCTriggerSystem.cs create mode 100644 Content.Server/ADT/_RMC14/Trigger/TriggerOnFixedDistanceStopComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/ProjectileFixedDistanceComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/ProjectileFixedDistanceStopEvent.cs create mode 100644 Content.Shared/ADT/_RMC14/Weapons/Ranged/ShootAtFixedPointComponent.cs create mode 100644 Resources/Audio/ADT/Attachments/attachment_activate.ogg create mode 100644 Resources/Audio/ADT/Attachments/attachment_add.ogg create mode 100644 Resources/Audio/ADT/Attachments/attachment_deactivate.ogg create mode 100644 Resources/Audio/ADT/Attachments/attachment_remove.ogg create mode 100644 Resources/Audio/ADT/Attachments/attributions.yml create mode 100644 Resources/Audio/_RMC14/Weapons/Guns/Breech/attributions.yml create mode 100644 Resources/Audio/_RMC14/Weapons/Guns/Breech/ugl_close.ogg create mode 100644 Resources/Audio/_RMC14/Weapons/Guns/Breech/ugl_open.ogg delete mode 100644 Resources/Locale/ru-RU/ADT/_RMC14/attachable/attachable.ftl delete mode 100644 Resources/Locale/ru-RU/ADT/_RMC14/weapons/guns.ftl delete mode 100644 Resources/Locale/ru-RU/ADT/_RMC14/weapons/magnetize.ftl create mode 100644 Resources/Locale/ru-RU/ADT/attachments/attachable/attachable.ftl create mode 100644 Resources/Locale/ru-RU/ADT/attachments/weapons/guns.ftl create mode 100644 Resources/Locale/ru-RU/ADT/attachments/weapons/magnetize.ftl rename Resources/Prototypes/ADT/{_RMC14/Actions/Marines/marine_action_items.yml => Entities/Objects/Weapons/Guns/Attachments/Actions/actions.yml} (69%) rename Resources/Prototypes/ADT/{_RMC14 => Entities/Objects/Weapons/Guns/Attachments}/test.yml (98%) diff --git a/Content.Client/_RMC14/Attachable/Components/AttachableHolderVisualsComponent.cs b/Content.Client/ADT/_RMC14/Attachable/Components/AttachableHolderVisualsComponent.cs similarity index 100% rename from Content.Client/_RMC14/Attachable/Components/AttachableHolderVisualsComponent.cs rename to Content.Client/ADT/_RMC14/Attachable/Components/AttachableHolderVisualsComponent.cs diff --git a/Content.Client/_RMC14/Attachable/Components/AttachableVisualsComponent.cs b/Content.Client/ADT/_RMC14/Attachable/Components/AttachableVisualsComponent.cs similarity index 100% rename from Content.Client/_RMC14/Attachable/Components/AttachableVisualsComponent.cs rename to Content.Client/ADT/_RMC14/Attachable/Components/AttachableVisualsComponent.cs diff --git a/Content.Client/_RMC14/Attachable/Systems/AttachableHolderVisualsSystem.cs b/Content.Client/ADT/_RMC14/Attachable/Systems/AttachableHolderVisualsSystem.cs similarity index 100% rename from Content.Client/_RMC14/Attachable/Systems/AttachableHolderVisualsSystem.cs rename to Content.Client/ADT/_RMC14/Attachable/Systems/AttachableHolderVisualsSystem.cs diff --git a/Content.Client/_RMC14/Attachable/Ui/AttachableHolderChooseSlotMenu.xaml b/Content.Client/ADT/_RMC14/Attachable/Ui/AttachableHolderChooseSlotMenu.xaml similarity index 100% rename from Content.Client/_RMC14/Attachable/Ui/AttachableHolderChooseSlotMenu.xaml rename to Content.Client/ADT/_RMC14/Attachable/Ui/AttachableHolderChooseSlotMenu.xaml diff --git a/Content.Client/_RMC14/Attachable/Ui/AttachableHolderChooseSlotMenu.xaml.cs b/Content.Client/ADT/_RMC14/Attachable/Ui/AttachableHolderChooseSlotMenu.xaml.cs similarity index 97% rename from Content.Client/_RMC14/Attachable/Ui/AttachableHolderChooseSlotMenu.xaml.cs rename to Content.Client/ADT/_RMC14/Attachable/Ui/AttachableHolderChooseSlotMenu.xaml.cs index 704d2eb1aa1..27c30ab2274 100644 --- a/Content.Client/_RMC14/Attachable/Ui/AttachableHolderChooseSlotMenu.xaml.cs +++ b/Content.Client/ADT/_RMC14/Attachable/Ui/AttachableHolderChooseSlotMenu.xaml.cs @@ -5,7 +5,7 @@ using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.XAML; -namespace Content.Client._RMC14.Attachable.Ui; +namespace Content.Client.ADT._RMC14.Attachable.Ui; [GenerateTypedNameReferences] public sealed partial class AttachableHolderChooseSlotMenu : FancyWindow diff --git a/Content.Client/_RMC14/Attachable/Ui/AttachableHolderStripMenu.xaml b/Content.Client/ADT/_RMC14/Attachable/Ui/AttachableHolderStripMenu.xaml similarity index 100% rename from Content.Client/_RMC14/Attachable/Ui/AttachableHolderStripMenu.xaml rename to Content.Client/ADT/_RMC14/Attachable/Ui/AttachableHolderStripMenu.xaml diff --git a/Content.Client/_RMC14/Attachable/Ui/AttachableHolderStripMenu.xaml.cs b/Content.Client/ADT/_RMC14/Attachable/Ui/AttachableHolderStripMenu.xaml.cs similarity index 98% rename from Content.Client/_RMC14/Attachable/Ui/AttachableHolderStripMenu.xaml.cs rename to Content.Client/ADT/_RMC14/Attachable/Ui/AttachableHolderStripMenu.xaml.cs index ce1fe4be914..0f045d1068f 100644 --- a/Content.Client/_RMC14/Attachable/Ui/AttachableHolderStripMenu.xaml.cs +++ b/Content.Client/ADT/_RMC14/Attachable/Ui/AttachableHolderStripMenu.xaml.cs @@ -8,7 +8,7 @@ using Robust.Client.UserInterface.XAML; using static Robust.Client.UserInterface.Controls.BoxContainer; -namespace Content.Client._RMC14.Attachable.Ui; +namespace Content.Client.ADT._RMC14.Attachable.Ui; [GenerateTypedNameReferences] public sealed partial class AttachableHolderStripMenu : FancyWindow diff --git a/Content.Client/_RMC14/Attachable/Ui/AttachmentChooseSlotBui.cs b/Content.Client/ADT/_RMC14/Attachable/Ui/AttachmentChooseSlotBui.cs similarity index 95% rename from Content.Client/_RMC14/Attachable/Ui/AttachmentChooseSlotBui.cs rename to Content.Client/ADT/_RMC14/Attachable/Ui/AttachmentChooseSlotBui.cs index cdc48adb9a1..6d46808bb7b 100644 --- a/Content.Client/_RMC14/Attachable/Ui/AttachmentChooseSlotBui.cs +++ b/Content.Client/ADT/_RMC14/Attachable/Ui/AttachmentChooseSlotBui.cs @@ -1,6 +1,6 @@ using Content.Shared._RMC14.Attachable; -namespace Content.Client._RMC14.Attachable.Ui; +namespace Content.Client.ADT._RMC14.Attachable.Ui; public sealed class AttachmentChooseSlotBui : BoundUserInterface { diff --git a/Content.Client/_RMC14/Attachable/Ui/AttachmentStripBui.cs b/Content.Client/ADT/_RMC14/Attachable/Ui/AttachmentStripBui.cs similarity index 95% rename from Content.Client/_RMC14/Attachable/Ui/AttachmentStripBui.cs rename to Content.Client/ADT/_RMC14/Attachable/Ui/AttachmentStripBui.cs index 69fdbdc55bc..b4a9a1afcdd 100644 --- a/Content.Client/_RMC14/Attachable/Ui/AttachmentStripBui.cs +++ b/Content.Client/ADT/_RMC14/Attachable/Ui/AttachmentStripBui.cs @@ -1,6 +1,6 @@ using Content.Shared._RMC14.Attachable; -namespace Content.Client._RMC14.Attachable.Ui; +namespace Content.Client.ADT._RMC14.Attachable.Ui; public sealed class AttachmentStripBui : BoundUserInterface { diff --git a/Content.Client/_RMC14/Scoping/ScopeSystem.cs b/Content.Client/ADT/_RMC14/Scoping/ScopeSystem.cs similarity index 100% rename from Content.Client/_RMC14/Scoping/ScopeSystem.cs rename to Content.Client/ADT/_RMC14/Scoping/ScopeSystem.cs diff --git a/Content.Client/_RMC14/Weapons/Ranged/PumpActionSystem.cs b/Content.Client/ADT/_RMC14/Weapons/Ranged/PumpActionSystem.cs similarity index 100% rename from Content.Client/_RMC14/Weapons/Ranged/PumpActionSystem.cs rename to Content.Client/ADT/_RMC14/Weapons/Ranged/PumpActionSystem.cs diff --git a/Content.Client/Input/ContentContexts.cs b/Content.Client/Input/ContentContexts.cs index aa5a00cbbe8..f4826dc183b 100644 --- a/Content.Client/Input/ContentContexts.cs +++ b/Content.Client/Input/ContentContexts.cs @@ -139,10 +139,10 @@ private static void CMFunctions(IInputContextContainer contexts) human.AddFunction(CMKeyFunctions.RMCActivateAttachableUnderbarrel); human.AddFunction(CMKeyFunctions.RMCFieldStripHeldItem); human.AddFunction(CMKeyFunctions.CMUniqueAction); - // human.AddFunction(CMKeyFunctions.CMHolsterPrimary); - // human.AddFunction(CMKeyFunctions.CMHolsterSecondary); - // human.AddFunction(CMKeyFunctions.CMHolsterTertiary); - // human.AddFunction(CMKeyFunctions.CMHolsterQuaternary); + human.AddFunction(CMKeyFunctions.CMHolsterPrimary); + human.AddFunction(CMKeyFunctions.CMHolsterSecondary); + human.AddFunction(CMKeyFunctions.CMHolsterTertiary); + human.AddFunction(CMKeyFunctions.CMHolsterQuaternary); } // ADT TWEAK END. } diff --git a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs index eaaaeee1fe0..7348acef796 100644 --- a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs +++ b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs @@ -159,10 +159,10 @@ void AddCheckBox(string checkBoxName, bool currentState, Action(OnTriggerTimerAmmoShot); + SubscribeLocalEvent(OnTriggerOnFixedDistanceStop); + } + + private void OnTriggerTimerAmmoShot(Entity ent, ref AmmoShotEvent args) + { + foreach (var projectile in args.FiredProjectiles) + { + _trigger.HandleTimerTrigger(projectile, null, ent.Comp.Delay, ent.Comp.BeepInterval, ent.Comp.InitialBeepDelay, ent.Comp.BeepSound); + } + } + + private void OnTriggerOnFixedDistanceStop(Entity ent, ref ProjectileFixedDistanceStopEvent args) + { + var active = EnsureComp(ent); + active.TriggerAt = _timing.CurTime + ent.Comp.Delay; + } + + public override void Update(float frameTime) + { + var time = _timing.CurTime; + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var active)) + { + if (time < active.TriggerAt) + continue; + + _trigger.Trigger(uid); + if (!EntityManager.IsQueuedForDeletion(uid) && !TerminatingOrDeleted(uid)) + QueueDel(uid); + } + } +} diff --git a/Content.Server/ADT/_RMC14/Trigger/TriggerOnFixedDistanceStopComponent.cs b/Content.Server/ADT/_RMC14/Trigger/TriggerOnFixedDistanceStopComponent.cs new file mode 100644 index 00000000000..f3346372fa2 --- /dev/null +++ b/Content.Server/ADT/_RMC14/Trigger/TriggerOnFixedDistanceStopComponent.cs @@ -0,0 +1,11 @@ +using Robust.Shared.GameStates; + +namespace Content.Server._RMC14.Trigger; + +[RegisterComponent] +[Access(typeof(RMCTriggerSystem))] +public sealed partial class TriggerOnFixedDistanceStopComponent : Component +{ + [DataField] + public TimeSpan Delay; +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableComponent.cs b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableComponent.cs index dd55d2bf9eb..31cd00678e9 100644 --- a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableComponent.cs +++ b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableComponent.cs @@ -12,8 +12,8 @@ public sealed partial class AttachableComponent : Component public float AttachDoAfter = 1.5f; [DataField, AutoNetworkedField] - public SoundSpecifier? AttachSound = new SoundPathSpecifier("/Audio/Items/beep.ogg", AudioParams.Default.WithVolume(-6.5f)); + public SoundSpecifier? AttachSound = new SoundPathSpecifier("/Audio/ADT/Attachments/attachment_add.ogg", AudioParams.Default.WithVolume(-6.5f)); [DataField, AutoNetworkedField] - public SoundSpecifier? DetachSound = new SoundPathSpecifier("/Audio/Items/beep.ogg", AudioParams.Default.WithVolume(-5.5f)); + public SoundSpecifier? DetachSound = new SoundPathSpecifier("/Audio/ADT/Attachments/attachment_remove.ogg", AudioParams.Default.WithVolume(-5.5f)); } diff --git a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableToggleableComponent.cs b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableToggleableComponent.cs index 28ea58fa290..66520bbccea 100644 --- a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableToggleableComponent.cs +++ b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableToggleableComponent.cs @@ -102,10 +102,10 @@ public sealed partial class AttachableToggleableComponent : Component public bool AttachedOnly = false; [DataField, AutoNetworkedField] - public SoundSpecifier? ActivateSound = new SoundPathSpecifier("/Audio/Items/beep.ogg"); + public SoundSpecifier? ActivateSound = new SoundPathSpecifier("/Audio/ADT/Attachments/attachment_activate.ogg"); [DataField, AutoNetworkedField] - public SoundSpecifier? DeactivateSound = new SoundPathSpecifier("/Audio/Items/beep.ogg"); + public SoundSpecifier? DeactivateSound = new SoundPathSpecifier("/Audio/ADT/Attachments/attachment_deactivate.ogg"); [DataField, AutoNetworkedField] public bool ShowTogglePopup = true; @@ -120,7 +120,7 @@ public sealed partial class AttachableToggleableComponent : Component public EntityUid? Action; [DataField, AutoNetworkedField] - public string ActionId = "CMActionToggleAttachable"; + public string ActionId = "ADTActionToggleAttachable"; [DataField, AutoNetworkedField] public string ActionName = "Toggle Attachable"; diff --git a/Content.Shared/ADT/_RMC14/Scoping/ScopeComponent.cs b/Content.Shared/ADT/_RMC14/Scoping/ScopeComponent.cs index 0074295f4ba..ab5d64241a8 100644 --- a/Content.Shared/ADT/_RMC14/Scoping/ScopeComponent.cs +++ b/Content.Shared/ADT/_RMC14/Scoping/ScopeComponent.cs @@ -24,13 +24,13 @@ public sealed partial class ScopeComponent : Component public EntityUid? User; [DataField, AutoNetworkedField] - public EntProtoId ScopingToggleAction = "CMActionToggleScope"; + public EntProtoId ScopingToggleAction = "ADTActionToggleScope"; [DataField, AutoNetworkedField] public EntityUid? ScopingToggleActionEntity; [DataField, AutoNetworkedField] - public EntProtoId CycleZoomLevelAction = "RMCActionCycleZoomLevel"; + public EntProtoId CycleZoomLevelAction = "ADTActionCycleZoomLevel"; [DataField, AutoNetworkedField] public EntityUid? CycleZoomLevelActionEntity; diff --git a/Content.Shared/ADT/_RMC14/Weapons/Common/UniqueActionSystem.cs b/Content.Shared/ADT/_RMC14/Weapons/Common/UniqueActionSystem.cs index 390409a15ed..d5bdb59846d 100644 --- a/Content.Shared/ADT/_RMC14/Weapons/Common/UniqueActionSystem.cs +++ b/Content.Shared/ADT/_RMC14/Weapons/Common/UniqueActionSystem.cs @@ -1,7 +1,7 @@ using Content.Shared._RMC14.Input; using Content.Shared.ActionBlocker; using Content.Shared.Hands.Components; -using Content.Shared.Verbs; +// using Content.Shared.Verbs; using Robust.Shared.Input.Binding; namespace Content.Shared._RMC14.Weapons.Common; @@ -14,7 +14,7 @@ public sealed class UniqueActionSystem : EntitySystem public override void Initialize() { - SubscribeLocalEvent>(OnGetVerbs); + // SubscribeLocalEvent>(OnGetVerbs); CommandBinds.Builder .Bind(CMKeyFunctions.CMUniqueAction, @@ -33,21 +33,21 @@ public override void Shutdown() CommandBinds.Unregister(); } - private void OnGetVerbs(Entity ent, ref GetVerbsEvent args) - { - if (!args.CanAccess || !args.CanInteract) - return; + // private void OnGetVerbs(Entity ent, ref GetVerbsEvent args) + // { + // if (!args.CanAccess || !args.CanInteract) + // return; - if (!_actionBlockerSystem.CanInteract(args.User, args.Target)) - return; + // if (!_actionBlockerSystem.CanInteract(args.User, args.Target)) + // return; - var user = args.User; - args.Verbs.Add(new InteractionVerb - { - Act = () => TryUniqueAction(user, ent.Owner), - Text = "Unique action", - }); - } + // var user = args.User; + // args.Verbs.Add(new InteractionVerb + // { + // Act = () => TryUniqueAction(user, ent.Owner), + // Text = "Unique action", + // }); + // } private void TryUniqueAction(EntityUid userUid) { diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/CMGunSystem.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/CMGunSystem.cs index dd18baadd2c..5a2b25078c7 100644 --- a/Content.Shared/ADT/_RMC14/Weapons/Ranged/CMGunSystem.cs +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/CMGunSystem.cs @@ -1,18 +1,22 @@ -using Content.Shared._RMC14.Weapons.Common; +using System.Numerics; +using Content.Shared._RMC14.Weapons.Common; using Content.Shared.Containers.ItemSlots; using Content.Shared.Hands.EntitySystems; using Content.Shared.Interaction; using Content.Shared.Popups; +using Content.Shared.Projectiles; using Content.Shared.Weapons.Ranged; using Content.Shared.Weapons.Ranged.Components; using Content.Shared.Weapons.Ranged.Events; using Content.Shared.Weapons.Ranged.Systems; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; +using Robust.Shared.Physics.Components; +using Robust.Shared.Physics.Systems; using Robust.Shared.Random; +using Robust.Shared.Timing; namespace Content.Shared._RMC14.Weapons.Ranged; - public sealed class CMGunSystem : EntitySystem { [Dependency] private readonly SharedAudioSystem _audio = default!; @@ -22,9 +26,18 @@ public sealed class CMGunSystem : EntitySystem [Dependency] private readonly SharedHandsSystem _hands = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly SharedPhysicsSystem _physics = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly IGameTiming _timing = default!; + private EntityQuery _physicsQuery; + private EntityQuery _projectileQuery; + private bool _isRevolverActionInProgress = false; public override void Initialize() { + _physicsQuery = GetEntityQuery(); + _projectileQuery = GetEntityQuery(); + SubscribeLocalEvent(OnShootAtFixedPointShot); SubscribeLocalEvent(OnRevolverUniqueAction); SubscribeLocalEvent(OnAmmoEjectActivateInWorld); } @@ -77,17 +90,91 @@ private void OnAmmoEjectActivateInWorld(Entity gun, ref A private void OnRevolverUniqueAction(Entity gun, ref UniqueActionEvent args) { - if (args.Handled) + if (args.Handled || _isRevolverActionInProgress) + return; + + _isRevolverActionInProgress = true; + + try + { + int randomCount = _random.Next(1, gun.Comp.Capacity + 1); + + gun.Comp.CurrentIndex = (gun.Comp.CurrentIndex + randomCount) % gun.Comp.Capacity; + + _audio.PlayPredicted(gun.Comp.SoundSpin, gun.Owner, args.UserUid); + var popup = Loc.GetString("rmc-revolver-spin", ("gun", args.UserUid)); + _popup.PopupClient(popup, args.UserUid, args.UserUid, PopupType.SmallCaution); + + Dirty(gun); + } + finally + { + _isRevolverActionInProgress = false; + } + } + + /// + /// Shoot at a targeted point's coordinates. The projectile will stop at that location instead of continuing on until it hits something. + /// There is also an option to arc the projectile with ShootArcProj or ArcProj = true, making it ignore most collision. + /// + /// + /// For some reason, the engine seem to cause MaxFixedRange's conversion to actual projectile max ranges of around +1 tile. + /// As a result, conversions should be 1 less than max_range when porting, and the minimum range for this feature is around 2 tiles. + /// This could be manually tweaked try and fix it, but the math seems like it should be fine and it's predictable enough to be worked around for now. + /// + private void OnShootAtFixedPointShot(Entity ent, ref AmmoShotEvent args) + { + if (!TryComp(ent, out GunComponent? gun) || + gun.ShootCoordinates is not { } target) + { return; + } - int randomCount = _random.Next(1, gun.Comp.Capacity + 1); + // Find start and end coordinates for vector. + var from = _transform.GetMapCoordinates(ent); + var to = _transform.ToMapCoordinates(target); + // Must be same map. + if (from.MapId != to.MapId) + return; - gun.Comp.CurrentIndex = (gun.Comp.CurrentIndex + randomCount) % gun.Comp.Capacity; + // Calculate vector, cancel if it ends up at 0. + var direction = to.Position - from.Position; + if (direction == Vector2.Zero) + return; - _audio.PlayPredicted(gun.Comp.SoundSpin, gun.Owner, args.UserUid); - var popup = Loc.GetString("rmc-revolver-spin", ("gun", args.UserUid)); - _popup.PopupClient(popup, args.UserUid, args.UserUid, PopupType.SmallCaution); + // Check for a max range from the ShootAtFixedPointComponent. If defined, take the minimum between that and the calculated distance. + var distance = ent.Comp.MaxFixedRange != null ? Math.Min(ent.Comp.MaxFixedRange.Value, direction.Length()) : direction.Length(); + // Get current time and normalize the vector for physics math. + var time = _timing.CurTime; + var normalized = direction.Normalized(); - Dirty(gun); + // Send each FiredProjectile with a PhysicsComponent off with the same Vector. Max + foreach (var projectile in args.FiredProjectiles) + { + if (!_physicsQuery.TryComp(projectile, out var physics)) + continue; + + // Calculate needed impulse to get to target, remove all velocity from projectile, then apply. + var impulse = normalized * gun.ProjectileSpeedModified * physics.Mass; + _physics.SetLinearVelocity(projectile, Vector2.Zero, body: physics); + _physics.ApplyLinearImpulse(projectile, impulse, body: physics); + _physics.SetBodyStatus(projectile, physics, BodyStatus.InAir); + + // Apply the ProjectileFixedDistanceComponent onto each fired projectile, which both holds the FlyEndTime to be continually checked + // and will trigger the OnEventToStopProjectile function once the PFD Component is deleted at that time. See Update() + var comp = EnsureComp(projectile); + + // Transfer arcing to the projectile. + if (Comp(ent).ShootArcProj) + comp.ArcProj = true; + + // Take the lowest nonzero MaxFixedRange between projectile and gun for the capped vector length. + if (TryComp(projectile, out ProjectileComponent? normalProjectile) && normalProjectile.MaxFixedRange > 0) + { + distance = distance > 0 ? Math.Min(normalProjectile.MaxFixedRange.Value, distance) : normalProjectile.MaxFixedRange.Value; + } + // Calculate travel time and equivalent distance based either on click location or calculated max range, whichever is shorter. + comp.FlyEndTime = time + TimeSpan.FromSeconds(distance / gun.ProjectileSpeedModified); + } } } diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/ProjectileFixedDistanceComponent.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/ProjectileFixedDistanceComponent.cs new file mode 100644 index 00000000000..b768b771ec1 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/ProjectileFixedDistanceComponent.cs @@ -0,0 +1,21 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Weapons.Ranged; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(CMGunSystem))] +public sealed partial class ProjectileFixedDistanceComponent : Component +{ + /// + /// Used when firing a FixedDistance to time effectively limit the range. + /// This component removes itself when CurTime = FlyEndTime to trigger that Event. + /// + [DataField, AutoNetworkedField] + public TimeSpan FlyEndTime; + /// + /// If true, the entity containing this component will ignore most collisions except for Impassable fixture layers. + /// This is granted to a fired entity by the ShootAtFixedPointComponent based on its ShootArcProj boolean. + /// + [DataField, AutoNetworkedField] + public bool ArcProj = false; +} diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/ProjectileFixedDistanceStopEvent.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/ProjectileFixedDistanceStopEvent.cs new file mode 100644 index 00000000000..93f93b3c54a --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/ProjectileFixedDistanceStopEvent.cs @@ -0,0 +1,4 @@ +namespace Content.Shared._RMC14.Weapons.Ranged; + +[ByRefEvent] +public readonly record struct ProjectileFixedDistanceStopEvent; diff --git a/Content.Shared/ADT/_RMC14/Weapons/Ranged/ShootAtFixedPointComponent.cs b/Content.Shared/ADT/_RMC14/Weapons/Ranged/ShootAtFixedPointComponent.cs new file mode 100644 index 00000000000..14267cb6be0 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Weapons/Ranged/ShootAtFixedPointComponent.cs @@ -0,0 +1,23 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Weapons.Ranged; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(CMGunSystem))] +public sealed partial class ShootAtFixedPointComponent : Component // TODO: Make it so weapons with this component can have arc fire disabled. +{ + /// + /// Sets the maximum range for a projectile fired with ShootAtFixedPointComponent. + /// This can be set on both the Projectile and ShootAtFixedPoint Components. + /// The default value is null for no cap. The minimum value between the two is used. + /// + [DataField, AutoNetworkedField] + public float? MaxFixedRange; + + /// + /// Should projectiles launched by a gun with this component be fired in an 'arc'? + /// If true, they will ignore most collisions except for Impassable fixture layers. + /// + [DataField, AutoNetworkedField] + public bool ShootArcProj = false; +} \ No newline at end of file diff --git a/Content.Shared/Projectiles/ProjectileComponent.cs b/Content.Shared/Projectiles/ProjectileComponent.cs index c24cf2b5ee5..9afd51f491a 100644 --- a/Content.Shared/Projectiles/ProjectileComponent.cs +++ b/Content.Shared/Projectiles/ProjectileComponent.cs @@ -71,6 +71,17 @@ public sealed partial class ProjectileComponent : Component /// /// Whether this projectile has already damaged an entity. /// - [DataField] + [DataField, AutoNetworkedField] public bool DamagedEntity; + + // ADT TWEAK START + /// + /// Sets the maximum range for a projectile fired with ShootAtFixedPointComponent. + /// This can be set on both the Projectile and ShootAtFixedPoint Components. + /// The default value is null for no cap. The minimum value between the two is used. + /// + [DataField, AutoNetworkedField] + public float? MaxFixedRange; + + // ADT TWEAK END } diff --git a/Resources/Audio/ADT/Attachments/attachment_activate.ogg b/Resources/Audio/ADT/Attachments/attachment_activate.ogg new file mode 100644 index 0000000000000000000000000000000000000000..3b7d1ff2abab7ba01157fd7c47eefd7fe6a3bdca GIT binary patch literal 8467 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 W1~g%HMf=JX4ks^$Rnjp3qx=^VG8PR0 literal 0 HcmV?d00001 diff --git a/Resources/Audio/ADT/Attachments/attachment_add.ogg b/Resources/Audio/ADT/Attachments/attachment_add.ogg new file mode 100644 index 0000000000000000000000000000000000000000..75ce0fabe2217d368b932c318a2c90e3f17891b7 GIT binary patch literal 11583 zcmaia1z1(j^Y9~Nvr9ryk(yfAYgTw`q5|A!w1f;t|S_Gs^Kv7T- zeGmBk#q)pP=l`B(@3Lp-?9A@WXJ+T@LDSw|2S5e>xpwvcHfH1GI=VaD)%3K7ARMjq zZ`ngsA%gsZ{QRQ)LJ&^4t&NYhqpLkc(bd<{)6Lbz*3}z&!ViEO3B;I;1~%DoGCjhycKX6-tn5rwT1X=5q#Q zAXRQ!{roW*$e4aA>v(~Ie^n468*%_Z2ZA}V6JPJBI!%b%Q*k7E=7~E#6f1#X#%iyN zWA}V#w{|UVD0X(8fU;rX8{Gjw9m=RMMUcU7DywLwNGh<3qVpVLD#`Z5;VR7w#St8W zgsBVe7p6Xx*e`vZC~?5qFeQh}+b{!D7nswxu5QOLed;wKzMK6|g?+mY2sjrx3~C!9 zIjkG@(a_=yPmtB$WkG;oaG8K|GMQ>E*=Q}@_%y5LR~~Ir;puydI=UKq;N@d#;A^|! z>$Bh+Xp|9Q@;1=uZG_2Ugy}_uB~|1<VY6H&u-c#7XOKQPOV*ymfjYj_WE94e0;6j*k?9!crvF;^V-l`=S zWJ{HgC6D)468J!L{uU&2D)VeyoFH>MuZ%3~eRqs*7Dr22M%Jwb5fjv#pe>;zFZ=Ue zPGx#csN!W7{cQ!1WMNj7&47K>yV(Q-)Ry3Ljx(8FMej__`Rq@cGajVY=wEwh*|s zkYG+3`9Fd6Z_fchrwPCHNu*W0z+iURLpkif2L6}lc#sVy(+wxHs@1V-%yW2T!dLX zaZ@D){Xd?Q$CN70k@zdWZ)fKDFtraB&tv%hPUng$i>tw{Ob1^|Gr zBs{g-IHC>bor4R{!Fly`rT%x10jYCB8t;Wb#ijuOH2|=HMh+*6^-Pj;l`_N<*kQes zFOHGlM-^T|bPrD)pV>P}mP6`oig+*H**ct)TtPi7flV|Kg5Oj8NOfBb3k-YcfHnXG z3k(VLQF%_N4(BOM2w>+Rhr~IGQfE}5yy;Z;plrn?)|=U{XHNw&^}I2L{QhyX@T7!kCHPG#WNd1rij!ov3#1wgX+q;d!rHoe zqojIsx_TcdH1wL-G)OfxzUk_bD(aEzy-(NBYjl|uvR%^E`$(ZT*JS&FBFG@!XYHPb z5qLWfQhgTE1I_1MOf&vrr9pPfN(P={)cg)eYx`IUkT}Id5y(?6bz{nCa+LP+FeJ zSzcaN-sDnVU1d_RS6)y)QfFUYT{%+srlJ~g2vVy{%j4VGlkBv4L`f4bl;rd?s$x zU@;T`gK3vchlr~m;!OlUfE4NqU@&<-g!R)QwO~$6$XTudh;E|lP6%|sb!33JfOk4%#>A(?%BqplR0WuvI-hoV(0SL%y z_(u4xjO`30$m(TS3Jg}2mI5EkPQ76jmIzaYHl@JS!CApzwGnV*gur|@93c$O3S^Z6 zL+}n5o2WPX5E zhEJ$E5_yh^b79MkiF1^Bs>?y4dSkL!Y>gA*P-y?WI2KzGg&G%czrHgR3a)||%sXz~ z7DFSZ9|Z^B2pdoUy?6iu#vKgmBC4<{szNerBIY70&@M$})}U^wya?pDsI4btIicZN zFfM2W5loe>2uy}?=)imqF@-dw11I!1j#%JX;R!@SymbY+h{M%k9AzP(Myq^4C=~UN z89P-qEXrV2Ma&DTv4K#qtLn=z<_3Txa6(77afA&>!USZfUW0PQ?TM_$#P{fgz{p4! zPQW#g9Y!FBMGj5_+^fdK!HP%@B!Kx|ei&F4A!lv~aM(Ts?1L70-w=>+901^Q2Q#7? zZ5yx9{tPh3DWB3E=GjND$wpyQ#9h691E!{HKNe|5!vBm}e2| zgS+(r6)o1^tXzrY_SPElPm-ST_x8VX_Wxw>|69w%xeA2be^-D^Ck`g?2a{G`Sqw^p z%X70vA_6ec>&*aXj6okB3Ee9U2hEc&4-@BP15pBng75)78fgrB=>>;#u@$A?gpOHb z7%#{hldWhT?gUDaz$$8(y%Du2s{$>WH;&^4T@D7`TEz=T!of%S7p*D<3TNP;e^Oaj zf(~Tt3{Ksd7uq;)72gQzAB+(5R&m1f#<;+`t2+>^QsWVsR#@LNy?$$JCNSBSyVds1 zivb+8Mcxfsm=s_js%|jC6b_oP1k~=|=a5=*x6s1M2m7G(Ajmjx zTWnwp`)>kw3&wB~FqK1sod5PANkAF5=^YY&gGf*{H-uZL-nOurZq#-AFw@_$H@P4P zQM8*V%(BP&dW0Dv^r;6;%V7ux1mgjK$D-3AbbbiZpB=;&J{f;f0MgW+B?j%WZ;_z+%lv>_e|X?aM2l>}h;$YKaH7%w5AAr5y> zuDV|91oG^(f znK*?cl@tlW7Xa3QU_v06^-gqjv|Zxs-c2-C1)K1~zAbdNTk=hXh4uGU1^u@D&&%}f zyEXvayiDJS;q5`&QKI#Bb@QdArK6)~hA;-Yx_Q#kFwoO8GBEkOdpo)LKc%Oqr=h23 zVuFNu_&{h}>Pj$N%U_8p|RYk!t~hIO0go`C`eve|gfufxj;4(gCTfw5w!^ z{(yaYXu{BKVPBj@oLUzaG#F|lc_iHbDA#PGb`IT*^n|5~EznSp??uh;KhOSbemBQN zVR+%NI;hq0P{H?Q@1|Kgz+k9b@3*%>f;^?g;7>{mq#w|B4)YBt&t1LR2za=;jy~Bu z^N^K@GSrwYYxe0Ws;fk*iJEwGeTntc^Cz;D-AOLTCG#(jStYzT-gK|VSDLxY`kki1 zi7q8RNV6EaUr)<~_A)x<>3F&Y>EHki_H=Znt}kQdV2(@tzr8 zLrj;-v?9}^jXF+5v~lnk-c(Mwk{--9I?cb%#;P678JY&dVK0kGw5tJtM=&n;bF#7p zi7FZmTX4VWy5jyd$2Rs1i7ToNb3bL64O7@e5}wRB!6KSDWywRvugDKCx$)_kagTEY zc+iphh1Ra@WUZ_YaYjDxf0V!!R`UZfiTkfkxgpxg4(4A_beX?1o)@^e=!USmIY@+Vt}S?_w6&d5 zuU$Tv4jrQ?-~bR@?V=iF0@4-TUgiq!Tg{^ygto5}+h&W8x%4`b^nQd;>2r^C2TS4cV)s3i1Pwi2!)hwc(@pSPv+Ao50=ynXb>yuCd!06xYs zv!=V>q4;!}y3J>P2RhB*Zk~LdqZDeP-$rzeiK4ZvMi|MD7JX4ws@e4vs4r>fZArtCrxobk;!dJF!jf3)kY}|=qY%0 z1~Q0{b6n&Fy2mQE!&UYxxw}sug-``>FZ&k;=Z{r>6Ox`e*5iBpL%uKmYaL_Jg}gAd1_%bi{_ zE`uRQUw>DveOxExq<|wuZ&cWD${a{IXl2(`9N7MH`4=t+T6z(iXS#Jh@MaS^( z2G`}x?~F&ZHe9OT_cZY|siTE*AIrKIs*aC9cBOx@ouU1}wCrWM16-!B#CMyo2ZcmY z2c3BrAc6z8&Rb@KNBCtoNa#35GxlYh*10IDUFDVElVN;NG*G;MU^PRdih_cO!wf<1 z`u*F^yz}FA-jZwGno_7jBT1|>YGKr>+|_I&ODlUm6l?2gXTSP^66Jv)Dp7lsUx}jY zXJ_UDRNyz(xUpZK$XzYR&JdIrCwB&tQwe_L`CR51z<17RTF#RWeY6zhkc{czrf|AzG9z&;DXS5vVzRd_UjYk>)7&RTMtA^uT)4M}tia?aykF z9@*A-v{sC2j*&wSv;fdyh*x!=h!*lR_^SpQ8Bj=WnxFXr|FQr3CUe?U_pjq$MH}N3 zD0o9dN+jNuxgQ`yU)qc`Sp79>6;Oro+>d(V|yX?d6)jjxho`}pIxG= zAIF#=W`E}DISK5aoZuFQfgI0$k+tYHTfS*_$U*slw-+w^! z{PgS^Id7Btsm+Agc8_M3+MAaBd6=SYyoUXs=ry(d-6ox@saj$-dBZR3@0ZSu2_9QJ zW+i-o)NpDi*&2sgIzM0t-`V=5?b8ql#jjI)Ag%@E4$)D)?T+U~m7XhT@Yt&xy@x#! zxwQMhygkdxRE2%lwJ`yfm|*Do1pA^cq%K)IWV`-nNn%;cCv~P$opaXmm7|6y5IB)d zB(~-AsR^C;8-~A*C(Y`YqGVE^irFl5e1hA)KoJZI+1B(PD}4_H4bhFQa zZl{rsk-G=Bu=eki9bNRxdl~#ZNz=4*9ubSR)0Qnvh`S~X`sRw5N%qdgSa4@+K>yBA zQ}jJDmNigyV{sN@i$SBak*$MU%H~w1GSW1vZpr%n3ai(FYX2R_w?%H=9NFZfpDACt z%f`ae5^8Ix?O(rUkLr|nG7Os;I5mII&Y%s>hv~}s{i=Hr*raB}M9u&Fggp3r z@JUQ=5^GMNSOtZy^yqchJ*$saGBb#Hw1dt+?h{6CnkB`lEj@Qok#bUmG3rsfWVt52 zK=+qZv^wV#MNy|NL;*BG`Rj=$c04R@%_S{MK}Hbh1kgEPi-jCb$A;Fmm#|l)OD=~? zvX!vF6P#WN2!kr=tUCIjbN$BV%$Uey;WuK%a;Yt4BsAh5qaP0ri^yEa?$`teF#>s6 z{;oim1tV@v-k*tQ__BqMD)=A23r%uF3z}@*N_JPZec0LVqVfsVO zu=#tTmYxf0b^L0WK8MP$nWz=p5%b#jUSdlvIQD9B&gbNsl=mSTBqz-2P|6M>@nS3} zT27C6_B0EDT#4-#a&;QKm*4Y4dsffF4TJIX(h{Q9T(ik0!?SAR15Z*i<2}e#VE}2vP4!(2w?iY9QfZW9uh<{itE?Lp2} z6i|5oNf-d87xkFb8r_S11N(@524u@Q+l1!oM?YrvX5VQmkF*}ZX44PJ%MOf{4Ar~m z2Su;f;}yIkk)Omz(^418hR1R^(r8SRhot%PGIf{pv>|%}D!B1zAeH?4#FbR0699<3 zSo!gbR-sd7*SixBi8pnE1{Cr_OMW1Uqbg92D_-H`T)aCk)t!~(++H$#9$h^a5|Z~* zD>rTvlREKPWhf63>xVB!n6vwz2{u1p7~-P>E8F5;cR#4;N))lLXi@kqh4D-*KhykS z9RXXU)I5{tElK?J%}{x;gTT5P4GnmD*XPOPo=p&{FTRC2-RpjV*=0CRc(@UUg2c5Z zis53g+6=mIZ}9e{J^F(=2jeswK`xc2B0iLw6(*8s3>sm}nhSj<5l4-y`b{K%bO2qE zxHZYuD<}7La@9;(w8bU!FT>V&1~We!HdDalG0yG$Qv0m0yMs`{-LvOV^;O4fDcRH0 zQ6i{8$vi!t0?qYsv6^Sb%8hbQq>XF;QlJenw8npmRe#8bI)$Jv=D3RQ%uedlBO7-e__g(JOh0uq2FT# zW|S0S9}Cq(3NiX0Rg6%qwq<=W9tC(%dWx5T=ecPSvJ*ePY{f`?&1B^dM>sp2QY3{9 z-T`pRoO(ib$s2n;1R6Dfgi7p&ds1F5zT%YlYM9~Ai#|jRSq%4`GTXO4P7Bl0HE8F+|!})!LP2*4PZo4sVsx#$1o2+8+&RrB;0wU$##phVt83N}Go zGY8KEvh4!1?BloI>#TdI?v_26?f7WasJr{k>LXTX07+Rh%9vAo6umwTxN%L*F5{?| ze)N7)_W3;BvL=<331?|Ip6H$H^^+%+R=FOknfV>1xQU;d_P0(iQ`}kdwLac;eIX3EJ!nAJyVcL%g9bEEQy&qK zGsY+0!J**+{=WXc?j8YdZte&d7i&j*8+&^@TMNraM2~;2M7N_Fp8nbsqqcY@_NwXQ z9Thd$I94#Ft@IoHh8&jp{2ixk5veD&lW+M60ryV}4}Z!kzSLFQ+pui8?C;rr66ID@ zQc>kWT@rRnwZHZC|82*JiA<-N#11Y?V)nt_4&JG1ti!N!H%dID zdB3ZAc-Yz6`D)o513ccTWV2AF79=e)p@QBW91DfLH;b}AF^~C_^zw_}tE>5()t^oy zZ}V{wE3q!(W;*XerFY-u_gr9m*Yvm(@=AZ3{4}U3H%AmArW4rSBP5mi!6N$G%=Gnw znt)QAgAIdrrYweDyzcrW-yibN&EQ#d@8<)#F0ukNaZ}I^Gr{C0*tW zUR^Ry5*NP*&*Hj#@T8sf9At-9B=XRKb9UmLouef zR!kz#1l5m&KSXbv`oaJ1i?pf+-VBLwlT_FYKqX?X{*?On6E~mxE6Xm&J<~2-4z+-c z@r?YZP2A?tWtHex$Nc%@68sXiO*XROR~P*xdp@DPOG`jZ@4Toh%r^cFmc+<8P*6O3 zm9F?lr9_|y#Q-aKj|1gbfMocjJdlfx--0cW*iy!McwjB#(2}j6CK#7QeWc^zUf^c-E1@@ImI-sKxJNGJFyfx&SsgqpFIYEPyHA8|)W zmF5_7Aw5`f`3PY*zEtyavcNW4e_T8Qj{S%^wj-$TEf70e4f~#Cz4L zV0rc6r_#BX-geJJD`J=S_LOzfePuposm@&cS3Zh?*~DMtiSo9*7ZtDTm2$7Xc49&B z0fv`&d+~JYt_6m~UnWScP=KE4HyGlKO*|zN&5N>Na-6LY>Q7hnCFf08vup!)8tJvX zPNMCm-HV5Wh%{lxc?(@=H(?!{#VXI2%A!USyGM$9wQ;?}X^%=UaRrhqummO5x(P4P zFEr7_u+4Zwqs|@qb+LdT!-msXw=ux#k4*ZaS0y@NnykuLZJgjhpn5DPP~dn(VY-eO zuO<`dhq87v3aiWB?_g9PAbI*=FJ>rED%#NHU7lK;uZK~6%lhtVfRddHK^;3xJ(R}1FDe{Fpx-Rt_!a>54fnOp~&5sxj zyx!d#DL^i2=$=uO)vzLgRq;}X)o$NyzPp^jOte%r2-Ok$H{#-DK+1YtXyxId9b+RMl;*RXbaja{e&zn$N$SzJx!b16kF9OcHgnBk8!ny#6T9&?@~gyfo<_4!bnw6EfM;m!N4X16eb;{CAOb?3G+~^CZ28JEbx=5s8m*I;$IsP3DuHeNKmqz>>Mqq zfHB(4prH%f-BIQbtrePSbxl;0F>l1UGQuxY;!KNzg(*Pz#PYS3u0x_Rcl4s4g1+*=;HM5$d^uGz3Dd+eftDtkdm zbX+j3JKcQqziYV$3hoifYM8BST{82s&-k0B)w*8CSG+O5o;X%}E8OU`(Q$n}{^xDF zbBj-cyqKln!Jg_$?*!{rr<31&(9GP2{dWqUesZDt%i5m}wX{7Q6siOxxV0$Ywe2f- zcVy3Bo?8wC=e`l@so+X~4}P!CHPG!RkMy;L`Chbz@!E*Z6Ems=y6~Pa1hj?4Y}GDY z8`)(ooK{X8riY!sa#$x!u+`*$dl`YU_s+B6^{;s1hb1h-&3%Ho2}`dGUzo-c3m(|K zi(RAAo;mi3B=>K7G@Rqgw#OF)zwcxOtm-RR$$EL&>JWFi^K{0`aPNADzWB1AbKg<( zd55i&lYP5fqu-n>-Z{dd=;*_)mfc!?FgZh)DE5#lWhXqry`@c!i55YI14g;6_uQ1k9y?k`UdF7E)1#z`%`tjq}%3<8@3 zlA_i;B_8{F%?jn+$Q4Z+XX{1mo##{*RJ*>ZKqD846*~bA^^}-$YRe-R}5EuWugTXbLTmzb$ z8%>{H`0*7EUH^3Q{Pe_Xf%vXdnM&kp88wjsx1?3XdFj)hvAD5&QT4Nx+^@^2=pQM) z+Y&yA)a7IFBCr%2V$CLeYbD$$EQMO{6=Z}4=l8aaXETbd^zmVd#ep?u*tqr{)t}hb;Y=%2cYTueDqKSuf2z<+45d zrF&@9vL5M2=g^FjO4f-xXsj*5jTcd%;%d)V>-eSa$3;G;;LLE+O7bpUl>FIupCHUG}=Y(S?rbwI1eHeVoS=n

)U}5`Kn?E0UR!~qd18NLcs${>E7Nfn$=48G^$v>ZH$lm z@U)uy?)_e_-M?$mfbhw?BBH4oSqNlrAOM1NS+x$c(1G#$r+AZT+EJ&RbiI7`gdGpA zf&#O!f($my4J$VL*DbFTHVn8gR?0n%;(oWhrgSfkgp2=I zVIS5IP0B9u>eEV3#4jpz)InEgMGO`oSC`ECX%h-$x<-ClklIYGjS2OErJ5`+p-J-_ zn~nFamZw_+#FH2{Rl_nKN$F4Rc24NDQ%l3y_s+t;4Oq{ny_kTOzOE|Vv2%I5@z5`= z@f<_NHldBMSE|?nO)>rjYKN|R)Gt#kz(w!AJN{%XJRdq1$;-Fa^RD@!UP0RxbVD%4 zg~T*o(nqUF<;g&ea!;)VR&0bxmS!}~w(%6td_ literal 0 HcmV?d00001 diff --git a/Resources/Audio/ADT/Attachments/attachment_deactivate.ogg b/Resources/Audio/ADT/Attachments/attachment_deactivate.ogg new file mode 100644 index 0000000000000000000000000000000000000000..9047e9b845763c67fd64adc4193833bf1b6c401e GIT binary patch literal 8436 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 literal 0 HcmV?d00001 diff --git a/Resources/Audio/ADT/Attachments/attachment_remove.ogg b/Resources/Audio/ADT/Attachments/attachment_remove.ogg new file mode 100644 index 0000000000000000000000000000000000000000..593cc6ab66661026ac81516b969099361311086d GIT binary patch literal 11428 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 literal 0 HcmV?d00001 diff --git a/Resources/Audio/ADT/Attachments/attributions.yml b/Resources/Audio/ADT/Attachments/attributions.yml new file mode 100644 index 00000000000..c01ce44d729 --- /dev/null +++ b/Resources/Audio/ADT/Attachments/attributions.yml @@ -0,0 +1,19 @@ +- files: ["attachment_add.ogg"] + license: "CC-BY-SA-3.0" + copyright: "The CM-SS13 development team" + source: "https://github.com/cmss13-devs/cmss13/blob/master/sound/handling/attachment_add.ogg" + +- files: ["attachment_remove.ogg"] + license: "CC-BY-SA-3.0" + copyright: "The CM-SS13 development team" + source: "https://github.com/cmss13-devs/cmss13/blob/master/sound/handling/attachment_remove.ogg" + +- files: ["attachment_activate.ogg"] + license: "CC-BY-SA-3.0" + copyright: "The CM-SS13 development team" + source: "https://github.com/cmss13-devs/cmss13/blob/master/sound/handling/gun_underbarrel_activate.ogg" + +- files: ["attachment_deactivate.ogg"] + license: "CC-BY-SA-3.0" + copyright: "The CM-SS13 development team" + source: "https://github.com/cmss13-devs/cmss13/blob/master/sound/handling/gun_underbarrel_deactivate.ogg" diff --git a/Resources/Audio/_RMC14/Weapons/Guns/Breech/attributions.yml b/Resources/Audio/_RMC14/Weapons/Guns/Breech/attributions.yml new file mode 100644 index 00000000000..580f900d818 --- /dev/null +++ b/Resources/Audio/_RMC14/Weapons/Guns/Breech/attributions.yml @@ -0,0 +1,9 @@ +- files: ["ugl_close.ogg"] + license: "CC-BY-SA-3.0" + copyright: "Taken from cmss13" + source: "https://github.com/cmss13-devs/cmss13/blob/master/sound/weapons/handling/ugl_close.ogg" + +- files: ["ugl_open.ogg"] + license: "CC-BY-SA-3.0" + copyright: "Taken from cmss13" + source: "https://github.com/cmss13-devs/cmss13/blob/master/sound/weapons/handling/ugl_open.ogg" diff --git a/Resources/Audio/_RMC14/Weapons/Guns/Breech/ugl_close.ogg b/Resources/Audio/_RMC14/Weapons/Guns/Breech/ugl_close.ogg new file mode 100644 index 0000000000000000000000000000000000000000..7ca25520cce2e9c2ca96390c85b323d8904d0733 GIT binary patch literal 6685 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 DWJ4vb literal 0 HcmV?d00001 diff --git a/Resources/Audio/_RMC14/Weapons/Guns/Breech/ugl_open.ogg b/Resources/Audio/_RMC14/Weapons/Guns/Breech/ugl_open.ogg new file mode 100644 index 0000000000000000000000000000000000000000..580df16ac2c4a88aaef0e285ead24ff91aaf6d2e GIT binary patch literal 6685 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 Date: Sat, 23 Nov 2024 03:39:34 +0200 Subject: [PATCH 10/46] uh --- .../Components/AttachableSilencerComponent.cs | 2 +- .../Weapons/Guns/Gunshots/attributions.yml | 14 ++ .../Guns/Gunshots/gun_silenced_shot1.ogg | Bin 0 -> 21458 bytes .../Guns/Gunshots/gun_silenced_shot2.ogg | Bin 0 -> 21458 bytes .../_RMC14/Weapons/Guns/Gunshots/gun_ugl.ogg | Bin 0 -> 9676 bytes .../Weapons/Guns/Reload/attributions.yml | 4 + .../Weapons/Guns/Reload/grenade_insert.ogg | Bin 0 -> 14118 bytes .../ADT/Catalog/Fills/Items/weaponcase.yml | 26 +++- .../Prototypes/ADT/Catalog/boobr_catalog.yml | 24 ++- .../Entities/Objects/Specific/uplink_ERT.yml | 1 + .../Attachments/barrel_attachment.yml | 0 .../Attachments/rail_attachment.yml | 0 .../Attachments/stock_attachment.yml | 0 .../Attachments/under_attachment.yml | 137 ++++++++++++++++++ .../Guns/Attachments/attachable_base.yml | 17 +++ .../Attachments/attachable_holder_base.yml | 17 +++ .../Objects/Weapons/Guns/Attachments/tags.yml | 9 ++ .../ADT/SoundCollections/attachments.yml | 5 + Resources/Prototypes/ADT/Store/categories.yml | 5 + .../Objects/Weapons/Guns/Rifles/rifles.yml | 17 ++- .../ADT/Attachments/under.rsi/grenade-on.png | Bin 0 -> 344 bytes .../Attachments/under.rsi/grenade-open.png | Bin 0 -> 213 bytes .../Attachments/under.rsi/grenade-open_a.png | Bin 0 -> 213 bytes .../ADT/Attachments/under.rsi/grenade.png | Bin 0 -> 218 bytes .../ADT/Attachments/under.rsi/grenade_a.png | Bin 0 -> 218 bytes .../ADT/Attachments/under.rsi/meta.json | 27 ++++ .../Weapons/Guns/Rifles/carbine.rsi/base.png | Bin 357 -> 313 bytes .../Guns/Rifles/carbine.rsi/bolt-open.png | Bin 356 -> 313 bytes .../Weapons/Guns/Rifles/carbine.rsi/icon.png | Bin 369 -> 313 bytes .../Weapons/Guns/Rifles/carbine.rsi/meta.json | 2 +- 30 files changed, 301 insertions(+), 6 deletions(-) create mode 100644 Resources/Audio/_RMC14/Weapons/Guns/Gunshots/attributions.yml create mode 100644 Resources/Audio/_RMC14/Weapons/Guns/Gunshots/gun_silenced_shot1.ogg create mode 100644 Resources/Audio/_RMC14/Weapons/Guns/Gunshots/gun_silenced_shot2.ogg create mode 100644 Resources/Audio/_RMC14/Weapons/Guns/Gunshots/gun_ugl.ogg create mode 100644 Resources/Audio/_RMC14/Weapons/Guns/Reload/attributions.yml create mode 100644 Resources/Audio/_RMC14/Weapons/Guns/Reload/grenade_insert.ogg create mode 100644 Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/barrel_attachment.yml create mode 100644 Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/rail_attachment.yml create mode 100644 Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/stock_attachment.yml create mode 100644 Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml create mode 100644 Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/attachable_base.yml create mode 100644 Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/attachable_holder_base.yml create mode 100644 Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/tags.yml create mode 100644 Resources/Prototypes/ADT/SoundCollections/attachments.yml create mode 100644 Resources/Textures/ADT/Attachments/under.rsi/grenade-on.png create mode 100644 Resources/Textures/ADT/Attachments/under.rsi/grenade-open.png create mode 100644 Resources/Textures/ADT/Attachments/under.rsi/grenade-open_a.png create mode 100644 Resources/Textures/ADT/Attachments/under.rsi/grenade.png create mode 100644 Resources/Textures/ADT/Attachments/under.rsi/grenade_a.png create mode 100644 Resources/Textures/ADT/Attachments/under.rsi/meta.json diff --git a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableSilencerComponent.cs b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableSilencerComponent.cs index 1dd3e7445ec..58fd203003b 100644 --- a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableSilencerComponent.cs +++ b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableSilencerComponent.cs @@ -9,5 +9,5 @@ namespace Content.Shared._RMC14.Attachable.Components; public sealed partial class AttachableSilencerComponent : Component { [DataField, AutoNetworkedField] - public SoundSpecifier Sound = new SoundCollectionSpecifier("sparks"); + public SoundSpecifier Sound = new SoundCollectionSpecifier("ADTSilencedShoot"); } diff --git a/Resources/Audio/_RMC14/Weapons/Guns/Gunshots/attributions.yml b/Resources/Audio/_RMC14/Weapons/Guns/Gunshots/attributions.yml new file mode 100644 index 00000000000..829b5e4d542 --- /dev/null +++ b/Resources/Audio/_RMC14/Weapons/Guns/Gunshots/attributions.yml @@ -0,0 +1,14 @@ +- files: ["gun_silenced_shot1.ogg"] + license: "CC-BY-SA-3.0" + copyright: "Taken from cmss13" + source: "https://github.com/cmss13-devs/cmss13/blob/97365cd3721e668f87a7b180f5bd47e8d976e451/sound/weapons/gun_silenced_shot1.ogg" + +- files: ["gun_silenced_shot2.ogg"] + license: "CC-BY-SA-3.0" + copyright: "Taken from cmss13" + source: "https://github.com/cmss13-devs/cmss13/blob/97365cd3721e668f87a7b180f5bd47e8d976e451/sound/weapons/gun_silenced_shot1.ogg" + +- files: ["gun_ugl.ogg"] + license: "CC-BY-SA-3.0" + copyright: "Taken from cmss13" + source: "https://github.com/cmss13-devs/cmss13/blob/8086109b2dbf8d1d98aec106a07d86b65fe63e1b/sound/weapons/gun_m92_attachable.ogg" \ No newline at end of file diff --git a/Resources/Audio/_RMC14/Weapons/Guns/Gunshots/gun_silenced_shot1.ogg b/Resources/Audio/_RMC14/Weapons/Guns/Gunshots/gun_silenced_shot1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..a78d57f602e63563c57b26ff28d9826dc12911c8 GIT binary patch literal 21458 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 B1>yhz literal 0 HcmV?d00001 diff --git a/Resources/Audio/_RMC14/Weapons/Guns/Gunshots/gun_silenced_shot2.ogg b/Resources/Audio/_RMC14/Weapons/Guns/Gunshots/gun_silenced_shot2.ogg new file mode 100644 index 0000000000000000000000000000000000000000..a5e92e7c35f2d8965ccf1caaeef52a6a49c8d027 GIT binary patch literal 21458 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 B0onin literal 0 HcmV?d00001 diff --git a/Resources/Audio/_RMC14/Weapons/Guns/Gunshots/gun_ugl.ogg b/Resources/Audio/_RMC14/Weapons/Guns/Gunshots/gun_ugl.ogg new file mode 100644 index 0000000000000000000000000000000000000000..dc260889808f270293fdfce37b7fff4ad24621a7 GIT binary patch literal 9676 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 literal 0 HcmV?d00001 diff --git a/Resources/Prototypes/ADT/Catalog/Fills/Items/weaponcase.yml b/Resources/Prototypes/ADT/Catalog/Fills/Items/weaponcase.yml index a2e3d1881fd..2a6ea3198ed 100644 --- a/Resources/Prototypes/ADT/Catalog/Fills/Items/weaponcase.yml +++ b/Resources/Prototypes/ADT/Catalog/Fills/Items/weaponcase.yml @@ -10,11 +10,35 @@ - id: WeaponRifleM90GrenadeLauncher - id: MagazineRifle amount: 5 + +- type: entity + id: WeaponCaseNTM90GrenadeLauncherAttachment + name: weapon Case + suffix: M-90gl + description: Case with weapons. + parent: WeaponCaseNT + components: + - type: StorageFill + contents: + - id: ADTAttachmentM90GrenadeLauncher - id: GrenadeFrag - amount: 2 + amount: 3 - id: GrenadeBlast amount: 3 +- type: entity + id: WeaponCaseNTM90UnderBarrelShotGunAttachment + name: weapon Case + suffix: M-90gl + description: Case with weapons. + parent: WeaponCaseNT + components: + - type: StorageFill + contents: + - id: ADTAttachmentM90UnderbarrelShotgun + - id: MagazineShotgun + amount: 2 + - type: entity id: WeaponCaseNTLecter name: weapon case diff --git a/Resources/Prototypes/ADT/Catalog/boobr_catalog.yml b/Resources/Prototypes/ADT/Catalog/boobr_catalog.yml index 382ecae2bdd..799b82c0dc6 100644 --- a/Resources/Prototypes/ADT/Catalog/boobr_catalog.yml +++ b/Resources/Prototypes/ADT/Catalog/boobr_catalog.yml @@ -5,10 +5,32 @@ icon: { sprite: /Textures/Objects/Weapons/Guns/Rifles/carbine.rsi, state: base } productEntity: WeaponCaseNTM90 cost: - Productunit: 30 + Productunit: 21 categories: - ADTUplinkERTWeapon +- type: listing + id: ADTBoberM90GrenadeLauncher + name: boobr-m90-grenadelauncher-name + description: boobr-m90-grenadelauncher-desc + icon: { sprite: /Textures/Objects/Weapons/Guns/Rifles/carbine.rsi, state: base } + productEntity: WeaponCaseNTM90GrenadeLauncherAttachment + cost: + Productunit: 5 + categories: + - ADTUplinkERTAttachments + +- type: listing + id: ADTBoberM90UnderbarrelShotgun + name: boobr-m90-shotgun-name + description: boobr-m90-shotgun-desc + icon: { sprite: /Textures/Objects/Weapons/Guns/Rifles/carbine.rsi, state: base } + productEntity: WeaponCaseNTM90UnderBarrelShotGunAttachment + cost: + Productunit: 5 + categories: + - ADTUplinkERTAttachments + - type: listing id: ADTBoberLecter name: boobr-lecter-name diff --git a/Resources/Prototypes/ADT/Entities/Objects/Specific/uplink_ERT.yml b/Resources/Prototypes/ADT/Entities/Objects/Specific/uplink_ERT.yml index ff49502dbec..e16b2e2a88b 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Specific/uplink_ERT.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Specific/uplink_ERT.yml @@ -7,6 +7,7 @@ categories: - ADTUplinkERTWeapon - ADTUplinkERTMisc + - ADTUplinkERTAttachments currencyWhitelist: - Productunit diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/barrel_attachment.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/barrel_attachment.yml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/rail_attachment.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/rail_attachment.yml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/stock_attachment.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/stock_attachment.yml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml new file mode 100644 index 00000000000..6eaff22464b --- /dev/null +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml @@ -0,0 +1,137 @@ +## BASE +- type: entity + abstract: true + parent: ADTAttachableBase + id: ADTUnderAttachmentBase + components: + - type: Sprite + sprite: ADT/Attachments/under.rsi + - type: Tag + tags: + - ADTAttachmentUnderbarrel +## BASE + +- type: entity + parent: [ ADTUnderAttachmentBase, ADTAttachableToggleableBase ] + id: ADTAttachmentM90GrenadeLauncher + name: M90 Grenade Launcher + description: A weapon-mounted, reloadable grenade launcher. + components: + - type: Sprite + layers: + - state: grenade + map: [ "enum.BreechVisuals.Open" ] + - type: ContainerContainer + containers: + ballistic-ammo: !type:Container + ents: [] + - type: RMCAmmoEject + containerID: ballistic-ammo + ejectSound: + path: /Audio/_RMC14/Weapons/Guns/Reload/grenade_insert.ogg + - type: AmmoCounter + - type: Gun + projectileSpeed: 20 + soundGunshot: + path: /Audio/_RMC14/Weapons/Guns/Gunshots/gun_ugl.ogg + resetOnHandSelected: false + - type: RMCSelectiveFire + baseFireRate: 0.417 + - type: BallisticAmmoProvider + cycleable: false + whitelist: + tags: + - Grenade + proto: GrenadeFrag + capacity: 1 + soundInsert: + path: /Audio/_RMC14/Weapons/Guns/Reload/grenade_insert.ogg + params: + volume: -2 + - type: ShootAtFixedPoint + maxFixedRange: 10 + - type: UniqueAction + - type: BreechLoaded + needOpenClose: true + - type: Appearance + - type: GenericVisualizer + visuals: + enum.BreechVisuals.Open: + enum.BreechVisuals.Open: + True: { state: grenade-open } + False: { state: grenade } + - type: AttachableToggleable + userOnly: true + attachedOnly: true + supercedeHolder: true + wieldedUseOnly: true + activatePopupText: attachable-popup-switch-to-generic + deactivatePopupText: attachable-popup-switch-from-generic + actionName: Switch to the M90 Grenade Launcher + actionDesc: Switch to using the underbarrel grenade launcher. + icon: + sprite: ADT/Attachments/under.rsi + state: grenade + iconActive: + sprite: ADT/Attachments/under.rsi + state: grenade-on + - type: AttachableVisuals + redrawOnAppearanceChange: true + - type: Tag + tags: + - ADTAttachmentUnderbarrel + - ADTAttachmentM90GrenadeLauncher + +- type: entity + parent: [ ADTUnderAttachmentBase, ADTAttachableToggleableBase ] + id: ADTAttachmentM90UnderbarrelShotgun + name: M90 underbarrel shotgun + description: MEOW + components: + - type: Sprite + state: grenade + - type: Tag + tags: + - ADTAttachmentUnderbarrel + - ADTAttachmentM90UnderbarrelShotgun + - type: Gun + soundGunshot: + path: /Audio/Corvax/Weapons/Guns/Gunshots/shotgun_alt.ogg + params: + volume: -2 + - type: RMCSelectiveFire + baseFireRate: 0.476 + - type: ContainerContainer + containers: + ballistic-ammo: !type:Container + - type: RMCAmmoEject + containerID: ballistic-ammo + ejectSound: /Audio/Weapons/Guns/MagIn/shotgun_insert.ogg + - type: BallisticAmmoProvider + cycleable: false + whitelist: + tags: + - ShellShotgun + capacity: 3 + proto: ShellShotgun + soundInsert: + path: /Audio/Weapons/Guns/MagIn/shotgun_insert.ogg + - type: UseDelay + - type: AttachableToggleable + userOnly: true + attachedOnly: true + supercedeHolder: true + wieldedUseOnly: true + activatePopupText: attachable-popup-switch-to-generic + deactivatePopupText: attachable-popup-switch-from-generic + actionName: Switch to the M90 underbarrel shotgun + actionDesc: Switch to using the underbarrel shotgun. + icon: + sprite: _RMC14/Objects/Weapons/Guns/Attachments/under.rsi + state: grenade + iconActive: + sprite: _RMC14/Objects/Weapons/Guns/Attachments/under.rsi + state: grenade-on + - type: AttachableVisuals + - type: UniqueAction + - type: PumpAction diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/attachable_base.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/attachable_base.yml new file mode 100644 index 00000000000..601efb23e97 --- /dev/null +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/attachable_base.yml @@ -0,0 +1,17 @@ +- type: entity + parent: BaseItem + abstract: true + id: ADTAttachableBase + components: + - type: Item + size: Small + - type: Attachable + +- type: entity + parent: ADTAttachableBase + abstract: true + id: ADTAttachableToggleableBase + components: + - type: AttachableToggleable + - type: UseDelay + delay: 0 diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/attachable_holder_base.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/attachable_holder_base.yml new file mode 100644 index 00000000000..72adb3f8d96 --- /dev/null +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/attachable_holder_base.yml @@ -0,0 +1,17 @@ +- type: entity + abstract: true + id: ADTBaseAttachableHolder + components: + - type: AttachableHolder + - type: ItemSizeChange + - type: ActivatableUI + verbText: rmc-verb-strip-attachables + verbOnly: true + key: + enum.AttachmentUI.StripKey + - type: UserInterface + interfaces: + enum.AttachmentUI.StripKey: + type: AttachmentStripBui + enum.AttachmentUI.ChooseSlotKey: + type: AttachmentChooseSlotBui diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/tags.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/tags.yml new file mode 100644 index 00000000000..ad214ad96cb --- /dev/null +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/tags.yml @@ -0,0 +1,9 @@ +- type: Tag + id: ADTAttachmentUnderbarrel + +- type: Tag + id: ADTAttachmentM90GrenadeLauncher + +- type: Tag + id: ADTAttachmentM90UnderbarrelShotgun + diff --git a/Resources/Prototypes/ADT/SoundCollections/attachments.yml b/Resources/Prototypes/ADT/SoundCollections/attachments.yml new file mode 100644 index 00000000000..9735d8f9795 --- /dev/null +++ b/Resources/Prototypes/ADT/SoundCollections/attachments.yml @@ -0,0 +1,5 @@ +- type: soundCollection + id: ADTSilencedShoot + files: + - /Audio/_RMC14/Weapons/Guns/Gunshots/gun_silenced_shot1.ogg + - /Audio/_RMC14/Weapons/Guns/Gunshots/gun_silenced_shot2.ogg diff --git a/Resources/Prototypes/ADT/Store/categories.yml b/Resources/Prototypes/ADT/Store/categories.yml index f451cd24eda..ce8db77fb89 100644 --- a/Resources/Prototypes/ADT/Store/categories.yml +++ b/Resources/Prototypes/ADT/Store/categories.yml @@ -7,3 +7,8 @@ id: ADTUplinkERTMisc name: прочее priority: 2 + +- type: storeCategory + id: ADTUplinkERTAttachments + name: Обвесы|Модули + priority: 3 diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml index 242f43b702f..846605d2deb 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml @@ -102,7 +102,7 @@ - type: entity name: M-90gl - parent: [BaseWeaponRifle, BaseSyndicateContraband] + parent: [BaseWeaponRifle, ADTBaseAttachableHolder] # ADT TWEAK М90 ОБР ЯВЛЯЕТСЯ КОНТРАБАНДОЙ СИНДИКАТА XDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD id: WeaponRifleM90GrenadeLauncher description: An older bullpup carbine model, with an attached underbarrel grenade launcher. Uses .20 rifle ammo. components: @@ -134,7 +134,20 @@ whitelist: tags: - CartridgeRifle - - Grenade + # ADT TWEAK START + #- Grenade # ADT TWEAK + - type: AttachableHolder + slots: + rmc-aslot-underbarrel: + whitelist: + tags: + - ADTAttachmentM90GrenadeLauncher + - ADTAttachmentM90UnderbarrelShotgun + - type: AttachableHolderVisuals + offsets: + rmc-aslot-underbarrel: 0.3125, -0.0625 + # ADT TWEAK END + - type: ContainerContainer containers: gun_magazine: !type:ContainerSlot diff --git a/Resources/Textures/ADT/Attachments/under.rsi/grenade-on.png b/Resources/Textures/ADT/Attachments/under.rsi/grenade-on.png new file mode 100644 index 0000000000000000000000000000000000000000..101a03e8f130bd84aea2446ca3d002f883901038 GIT binary patch literal 344 zcmV-e0jK_nP)Px$5=lfsR9J=Wm$8b3Fcd{^hAk`x=2b#^ZBon+2!71|lBM9k_z9-oDrIcmfcm=lkgF=CR^ddn>m3A8*ENP=5CA|#P)a##RaL8SX5RJQeFOl|G|l%I znHhcGJ8Rpv&{_)sFvf&f?*mwC#rz&vYggvJ`WFRFU=EIMjx&>NM(#PoB__f0E&x$`J|qq6fW`{%MTIJhV%F%)pBFG|0#YSpVxd*8BUt$neVoniWi z&8uE*nie$eeQtk3kKnu4!Csl`W*KenSH5xV%;$gNbBfRHoL|Q9^OzZPy!H0`K<y My85}Sb4q9e0MJ5J*8l(j literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Attachments/under.rsi/grenade-open_a.png b/Resources/Textures/ADT/Attachments/under.rsi/grenade-open_a.png new file mode 100644 index 0000000000000000000000000000000000000000..1e84784660335b11f50b41dbb135509d50ddb517 GIT binary patch literal 213 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}{hlt4ArY-_ zFKy&yR^(y5;ICGY`mn9Mjx&>NM(#PoB__f0E&x$`J|qq6fW`{%MTIJhV%F%)pBFG|0#YSpVxd*8BUt$neVoniWi z&8uE*nie$eeQtk3kKnu4!Csl`W*KenSH5xV%;$gNbBfRHoL|Q9^OzZPy!H0`K<y My85}Sb4q9e0MJ5J*8l(j literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Attachments/under.rsi/grenade.png b/Resources/Textures/ADT/Attachments/under.rsi/grenade.png new file mode 100644 index 0000000000000000000000000000000000000000..d59ff4624c24a07ca519808d5a708418d90de1c0 GIT binary patch literal 218 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}Q#@T9Ln2z= zUNYozR^(xOaNkeTm{U%{d!0f>G5RUXYQ*8g1bKNUb=A@(g R6M*hx@O1TaS?83{1OPG}S3dv% literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Attachments/under.rsi/grenade_a.png b/Resources/Textures/ADT/Attachments/under.rsi/grenade_a.png new file mode 100644 index 0000000000000000000000000000000000000000..d59ff4624c24a07ca519808d5a708418d90de1c0 GIT binary patch literal 218 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}Q#@T9Ln2z= zUNYozR^(xOaNkeTm{U%{d!0f>G5RUXYQ*8g1bKNUb=A@(g R6M*hx@O1TaS?83{1OPG}S3dv% literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Attachments/under.rsi/meta.json b/Resources/Textures/ADT/Attachments/under.rsi/meta.json new file mode 100644 index 00000000000..dd0216df263 --- /dev/null +++ b/Resources/Textures/ADT/Attachments/under.rsi/meta.json @@ -0,0 +1,27 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Created by discord: inconnu1337", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + + { + "name": "grenade" + }, + { + "name": "grenade-open" + }, + { + "name": "grenade-on" + }, + { + "name": "grenade_a" + }, + { + "name": "grenade-open_a" + } + ] +} diff --git a/Resources/Textures/Objects/Weapons/Guns/Rifles/carbine.rsi/base.png b/Resources/Textures/Objects/Weapons/Guns/Rifles/carbine.rsi/base.png index c9f1ce49e3745c478166924941dbc9a1cc24cb8a..4cb8b48b7ded719e597c13726d6139b44c41dbce 100644 GIT binary patch delta 298 zcmaFLw3BIqL_G&H0|SH0lCEPwim^Dz-HBn{IhmJ0j&6WYh%1oR*VlJ;cFxVsU9nF2#i${W{qN?n?!wDiwL<_*gwWLQ*KyOk&U z1T0oli&YJHxrZa~a_2qe7+Iwjtw&w~S!`j`XGk8I-5+;zh9nW&~K}AoOfH^DX#ve<{Rl7gO7Bz_a~fRYn#4B`8sR- kEd4dHoTqljezx!7zaPNtaW&Sw6zEt6Pgg&ebxsLQ084#wegFUf delta 317 zcmdnV^pt6Wgfm@(X784+bo(K#G%(>)UQE1)$V6PZ!6KiaBQ| z81fx5;Bk#@JJ3=Ptd)9L^OX;$xWgkQ!%6M)ngq?lRJIi{<{g??;Kjbn_`_0_PrtXN zvOl;#Mb}Nx@!F62Rq2vSO|JgGg1Wi|%C5Ae7Ojm7c_LX(MGmZONWZir4&!5@$f9BrP&rp_oG&Nop=miE(c2_@_bxsLQ0Qb3g AS^xk5 diff --git a/Resources/Textures/Objects/Weapons/Guns/Rifles/carbine.rsi/bolt-open.png b/Resources/Textures/Objects/Weapons/Guns/Rifles/carbine.rsi/bolt-open.png index 477b65066e29f35f3165a7e6a8041dc9757bfc44..4cb8b48b7ded719e597c13726d6139b44c41dbce 100644 GIT binary patch delta 214 zcmV;{04e|E0=WW^7#0Wv0000)q>9D>0004VQb$4nuFf3kkwaI1pGibPR5*?8Pzw%2 zAqca@!OTAQKkfiE^S#7(fvt%e(v~8n{ILVDrx+XrBn68jkxWpdCMI1aQ0cq~Zqte0 zBU~LKgeu}nP-+HNmzWvEn~z@Ko@7zFG~hg^cRcZ?pbzF1PEe0XLB>YWb-I3CpL(Js@ z+=L_Hln!)f;7dv5_if7#z`rS5O(KG<@zuaGL*QL!tQr_d@=`>q zBS2wYXZ=>whExyCA?$svwjQoUfwq%~AC;hhM8IHbOQB+jv4lA+*li3l^9hWc(=@r8 znO)!ak8x5%P7B+%RKRP2D5d5YT00000NkvXX Hu0mjfqhD!w diff --git a/Resources/Textures/Objects/Weapons/Guns/Rifles/carbine.rsi/icon.png b/Resources/Textures/Objects/Weapons/Guns/Rifles/carbine.rsi/icon.png index 34f9741a5f5dbce8416ccdb765638e9c0e24fad0..4cb8b48b7ded719e597c13726d6139b44c41dbce 100644 GIT binary patch delta 281 zcmey!w3BIqWchV#l;M0pd|Ylvguer&=6kw0hFJ8z4dCW;R^-@x z^xzr0@AmH)Oh4~EQr@_>Q|i(*rTV3RHZpHmE+NCB!rHAo(I;TBnp&)Cz{@=xd6zry zDaXhvwP-!^3dmv$n?6JG$n5^O`}0x)cbPn}Szd1QaoGa?XQF-q{T`0T+%A^xs*7D1 zTlxL+6oYpMF;=jP_F zSh2#@)m2VT&cVhaDl9-lLqk$ROdJd})Kv8J^dM{?=~Qz^1*lV~B*-tA;Xe$pumV|} zd|bZYjdlQKw|UmPIEGZrc^k+mbVz|`v1Xap-7Ej=uWjL(doNf1!WX`EDw*6d0N7-x3eHTb* z@J=}XVO{ha%@@svll3K{mnhtJyHqN@q4mR+WuKpVIU08;w Date: Mon, 25 Nov 2024 09:36:37 +0200 Subject: [PATCH 11/46] =?UTF-8?q?=D0=A8=D0=A0=D0=95=D0=94=D0=AF=20=D0=90?= =?UTF-8?q?=D0=A5=D0=A3=D0=95=D0=95=D0=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Weapons/Melee/MeleeWeaponSystem.cs | 219 ++++++++++++++++++ .../Attachments/under_attachment.yml | 4 +- 2 files changed, 221 insertions(+), 2 deletions(-) diff --git a/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs b/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs index a259d522398..d75cd52cb97 100644 --- a/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs +++ b/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs @@ -20,6 +20,7 @@ using Robust.Shared.Player; namespace Content.Client.Weapons.Melee; +/* public sealed partial class MeleeWeaponSystem : SharedMeleeWeaponSystem { @@ -30,6 +31,7 @@ public sealed partial class MeleeWeaponSystem : SharedMeleeWeaponSystem [Dependency] private readonly AnimationPlayerSystem _animation = default!; [Dependency] private readonly InputSystem _inputSystem = default!; [Dependency] private readonly SharedColorFlashEffectSystem _color = default!; + [Dependency] private readonly MapSystem _map = default!; private EntityQuery _xformQuery; @@ -89,7 +91,224 @@ public override void Update(float frameTime) } // TODO using targeted actions while combat mode is enabled should NOT trigger attacks. + + // TODO: Need to make alt-fire melee its own component I guess? + // Melee and guns share a lot in the middle but share virtually nothing at the start and end so + // it's kinda tricky. + // I think as long as we make secondaries their own component it's probably fine + // as long as guncomp has an alt-use key then it shouldn't be too much of a PITA to deal with. + if (TryComp(weaponUid, out var gun) && gun.UseKey) + { + return; + } + + var mousePos = _eyeManager.PixelToMap(_inputManager.MouseScreenPosition); + + if (mousePos.MapId == MapId.Nullspace) + { + return; + } + + EntityCoordinates coordinates; + + if (MapManager.TryFindGridAt(mousePos, out var gridUid, out _)) + { + coordinates = TransformSystem.ToCoordinates(gridUid, mousePos); + } + else + { + coordinates = TransformSystem.ToCoordinates(_map.GetMap(mousePos.MapId), mousePos); + } + + // Heavy attack. + if (altDown == BoundKeyState.Down) + { + // If it's an unarmed attack then do a disarm + if (weapon.AltDisarm && weaponUid == entity) + { + EntityUid? target = null; + + if (_stateManager.CurrentState is GameplayStateBase screen) + { + target = screen.GetClickedEntity(mousePos); + } + + EntityManager.RaisePredictiveEvent(new DisarmAttackEvent(GetNetEntity(target), GetNetCoordinates(coordinates))); + return; + } + + ClientHeavyAttack(entity, coordinates, weaponUid, weapon); + return; + } + + // Light attack + if (useDown == BoundKeyState.Down) + { + var attackerPos = TransformSystem.GetMapCoordinates(entity); + + if (mousePos.MapId != attackerPos.MapId || + (attackerPos.Position - mousePos.Position).Length() > weapon.Range) + { + return; + } + + EntityUid? target = null; + + if (_stateManager.CurrentState is GameplayStateBase screen) + { + target = screen.GetClickedEntity(mousePos); + } + + // Don't light-attack if interaction will be handling this instead + if (Interaction.CombatModeCanHandInteract(entity, target)) + return; + + RaisePredictiveEvent(new LightAttackEvent(GetNetEntity(target), GetNetEntity(weaponUid), GetNetCoordinates(coordinates))); + } + } + + protected override bool InRange(EntityUid user, EntityUid target, float range, ICommonSession? session) + { + var xform = Transform(target); + var targetCoordinates = xform.Coordinates; + var targetLocalAngle = xform.LocalRotation; + + return Interaction.InRangeUnobstructed(user, target, targetCoordinates, targetLocalAngle, range); + } + + protected override void DoDamageEffect(List targets, EntityUid? user, TransformComponent targetXform) + { + // Server never sends the event to us for predictiveeevent. + _color.RaiseEffect(Color.Red, targets, Filter.Local()); + } + + protected override bool DoDisarm(EntityUid user, DisarmAttackEvent ev, EntityUid meleeUid, MeleeWeaponComponent component, ICommonSession? session) + { + if (!base.DoDisarm(user, ev, meleeUid, component, session)) + return false; + + if (!TryComp(user, out var combatMode) || + combatMode.CanDisarm != true) + { + return false; + } + + var target = GetEntity(ev.Target); + + // They need to either have hands... + if (!HasComp(target!.Value)) + { + // or just be able to be shoved over. + if (TryComp(target, out var status) && status.AllowedEffects.Contains("KnockedDown")) + return true; + + if (Timing.IsFirstTimePredicted && HasComp(target.Value)) + PopupSystem.PopupEntity(Loc.GetString("disarm-action-disarmable", ("targetName", target.Value)), target.Value); + + return false; + } + + return true; + } + + ///

+ /// Raises a heavy attack event with the relevant attacked entities. + /// This is to avoid lag effecting the client's perspective too much. + /// + private void ClientHeavyAttack(EntityUid user, EntityCoordinates coordinates, EntityUid meleeUid, MeleeWeaponComponent component) + { + // Only run on first prediction to avoid the potential raycast entities changing. + if (!_xformQuery.TryGetComponent(user, out var userXform) || + !Timing.IsFirstTimePredicted) + { + return; + } + + var targetMap = TransformSystem.ToMapCoordinates(coordinates); + + if (targetMap.MapId != userXform.MapID) + return; + + var userPos = TransformSystem.GetWorldPosition(userXform); + var direction = targetMap.Position - userPos; + var distance = MathF.Min(component.Range, direction.Length()); + + // This should really be improved. GetEntitiesInArc uses pos instead of bounding boxes. + // Server will validate it with InRangeUnobstructed. + var entities = GetNetEntityList(ArcRayCast(userPos, direction.ToWorldAngle(), component.Angle, distance, userXform.MapID, user).ToList()); + RaisePredictiveEvent(new HeavyAttackEvent(GetNetEntity(meleeUid), entities.GetRange(0, Math.Min(MaxTargets, entities.Count)), GetNetCoordinates(coordinates))); + } +} +*/// ADT TWEAK + +public sealed partial class MeleeWeaponSystem : SharedMeleeWeaponSystem +{ + [Dependency] private readonly IEyeManager _eyeManager = default!; + [Dependency] private readonly IInputManager _inputManager = default!; + [Dependency] private readonly IPlayerManager _player = default!; + [Dependency] private readonly IStateManager _stateManager = default!; + [Dependency] private readonly AnimationPlayerSystem _animation = default!; + [Dependency] private readonly InputSystem _inputSystem = default!; + [Dependency] private readonly SharedColorFlashEffectSystem _color = default!; + + private EntityQuery _xformQuery; + + private const string MeleeLungeKey = "melee-lunge"; + + public override void Initialize() + { + base.Initialize(); + _xformQuery = GetEntityQuery(); + SubscribeNetworkEvent(OnMeleeLunge); + UpdatesOutsidePrediction = true; + } + + public override void FrameUpdate(float frameTime) + { + base.FrameUpdate(frameTime); + UpdateEffects(); + } // ADT TWEAK START + public override void Update(float frameTime) + { + base.Update(frameTime); + + if (!Timing.IsFirstTimePredicted) + return; + + var entityNull = _player.LocalEntity; + + if (entityNull == null) + return; + + var entity = entityNull.Value; + + if (!TryGetWeapon(entity, out var weaponUid, out var weapon)) + return; + + if (!CombatMode.IsInCombatMode(entity) || !Blocker.CanAttack(entity, weapon: (weaponUid, weapon))) + { + weapon.Attacking = false; + return; + } + + var useDown = _inputSystem.CmdStates.GetState(EngineKeyFunctions.Use); + var altDown = _inputSystem.CmdStates.GetState(EngineKeyFunctions.UseSecondary); + + if (weapon.AutoAttack || useDown != BoundKeyState.Down && altDown != BoundKeyState.Down) + { + if (weapon.Attacking) + { + RaisePredictiveEvent(new StopAttackEvent(GetNetEntity(weaponUid))); + } + } + + if (weapon.Attacking || weapon.NextAttack > Timing.CurTime) + { + return; + } + + // TODO using targeted actions while combat mode is enabled should NOT trigger attacks. var mousePos = _eyeManager.PixelToMap(_inputManager.MouseScreenPosition); if (mousePos.MapId == MapId.Nullspace) diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml index 6eaff22464b..ebc26a09552 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml @@ -127,10 +127,10 @@ actionName: Switch to the M90 underbarrel shotgun actionDesc: Switch to using the underbarrel shotgun. icon: - sprite: _RMC14/Objects/Weapons/Guns/Attachments/under.rsi + sprite: ADT/Attachments/under.rsi state: grenade iconActive: - sprite: _RMC14/Objects/Weapons/Guns/Attachments/under.rsi + sprite: ADT/Attachments/under.rsi state: grenade-on - type: AttachableVisuals - type: UniqueAction From 2fc25e52562fef694fa19f847ef7cc58ca858364 Mon Sep 17 00:00:00 2001 From: Inconnu <177014427+Inconnu1337@users.noreply.github.com> Date: Mon, 25 Nov 2024 09:49:41 +0200 Subject: [PATCH 12/46] fix MeleeWeaponSystem.cs --- Content.Client/Weapons/Melee/MeleeWeaponSystem.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs b/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs index 67a563646b3..2e7ef75264e 100644 --- a/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs +++ b/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs @@ -240,7 +240,7 @@ private void ClientHeavyAttack(EntityUid user, EntityCoordinates coordinates, En } } */// ADT TWEAK - +// ADT TWEAK START public sealed partial class MeleeWeaponSystem : SharedMeleeWeaponSystem { [Dependency] private readonly IEyeManager _eyeManager = default!; @@ -250,7 +250,7 @@ public sealed partial class MeleeWeaponSystem : SharedMeleeWeaponSystem [Dependency] private readonly AnimationPlayerSystem _animation = default!; [Dependency] private readonly InputSystem _inputSystem = default!; [Dependency] private readonly SharedColorFlashEffectSystem _color = default!; - + [Dependency] private readonly MapSystem _map = default!; private EntityQuery _xformQuery; private const string MeleeLungeKey = "melee-lunge"; @@ -268,7 +268,6 @@ public override void FrameUpdate(float frameTime) base.FrameUpdate(frameTime); UpdateEffects(); } - // ADT TWEAK START public override void Update(float frameTime) { base.Update(frameTime); From f84967e0c4d8c73701a98146e6dbecc55473171e Mon Sep 17 00:00:00 2001 From: Inconnu1337 Date: Sat, 30 Nov 2024 22:44:54 +0200 Subject: [PATCH 13/46] =?UTF-8?q?=D0=B7=D0=B0=D0=B5=D0=B1=D0=B0=D0=BB?= =?UTF-8?q?=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Weapons/Melee/MeleeWeaponSystem.cs | 2 +- .../Armor/Magnetic/RMCMagneticSystem.cs | 23 +- .../ADT/attachments/attachable/attachable.ftl | 8 +- .../ADT/attachments/weapons/magnetize.ftl | 2 +- .../Attachments/barrel_attachment.yml | 12 + .../Attachments/rail_attachment.yml | 29 + .../Attachments/under_attachment.yml | 16 + .../Weapons/Guns/Attachments/guns_base.yml | 28 + .../Objects/Weapons/Guns/Attachments/tags.yml | 14 + .../Objects/Weapons/Guns/Attachments/test.yml | 593 ------------------ .../Weapons/Guns/Battery/battery_gun.yml | 2 +- .../Objects/Weapons/Guns/Rifles/rifles.yml | 4 +- .../Objects/Weapons/Shotguns/shotguns.yml | 15 - .../Objects/Weapons/Guns/Basic/base_pka.yml | 31 +- .../Weapons/Guns/Battery/battery_guns.yml | 2 +- .../Objects/Weapons/Guns/LMGs/lmgs.yml | 2 +- .../Weapons/Guns/Launchers/launchers.yml | 2 +- .../Objects/Weapons/Guns/Rifles/rifles.yml | 6 +- .../Objects/Weapons/Guns/SMGs/smgs.yml | 10 +- .../Weapons/Guns/Shotguns/shotguns.yml | 6 +- .../Objects/Weapons/Guns/Snipers/snipers.yml | 2 +- .../Entities/Objects/Weapons/Melee/knife.yml | 23 +- .../ADT/Attachments/rail.rsi/magnetic.png | Bin 0 -> 248 bytes .../ADT/Attachments/rail.rsi/meta.json | 14 + .../Basic/kinetic_accelerator.rsi/icon-a.png | Bin 0 -> 281 bytes .../Basic/kinetic_accelerator.rsi/meta.json | 3 + 26 files changed, 204 insertions(+), 645 deletions(-) create mode 100644 Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/guns_base.yml delete mode 100644 Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/test.yml create mode 100644 Resources/Textures/ADT/Attachments/rail.rsi/magnetic.png create mode 100644 Resources/Textures/ADT/Attachments/rail.rsi/meta.json create mode 100644 Resources/Textures/Objects/Weapons/Guns/Basic/kinetic_accelerator.rsi/icon-a.png diff --git a/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs b/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs index 67a563646b3..d7f6da34a0c 100644 --- a/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs +++ b/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs @@ -250,7 +250,7 @@ public sealed partial class MeleeWeaponSystem : SharedMeleeWeaponSystem [Dependency] private readonly AnimationPlayerSystem _animation = default!; [Dependency] private readonly InputSystem _inputSystem = default!; [Dependency] private readonly SharedColorFlashEffectSystem _color = default!; - + [Dependency] private readonly MapSystem _map = default!; private EntityQuery _xformQuery; private const string MeleeLungeKey = "melee-lunge"; diff --git a/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticSystem.cs b/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticSystem.cs index 4488f3f1ca0..b5809b942cf 100644 --- a/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticSystem.cs +++ b/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticSystem.cs @@ -1,4 +1,4 @@ -using Content.Shared._RMC14.Inventory; +using Content.Shared._RMC14.Inventory; using Content.Shared.Hands; using Content.Shared.Interaction.Events; using Content.Shared.Inventory; @@ -77,16 +77,19 @@ public override void Update(float frameTime) var slots = _inventory.GetSlotEnumerator(user, SlotFlags.SUITSTORAGE); while (slots.MoveNext(out var slot)) { - if (_inventory.TryEquip(user, uid, slot.ID, force: true)) + if (_inventory.TryGetSlotEntity(user, "outerClothing", out _)) { - var popup = Loc.GetString("rmc-magnetize-return", - ("item", uid), - ("user", user)); - _popup.PopupClient(popup, user, user, PopupType.Medium); - - comp.Returned = true; - Dirty(uid, comp); - break; + if (_inventory.TryEquip(user, uid, slot.ID, force: true)) + { + var popup = Loc.GetString("rmc-magnetize-return", + ("item", uid), + ("user", user)); + _popup.PopupClient(popup, user, user, PopupType.Medium); + + comp.Returned = true; + Dirty(uid, comp); + break; + } } } } diff --git a/Resources/Locale/ru-RU/ADT/attachments/attachable/attachable.ftl b/Resources/Locale/ru-RU/ADT/attachments/attachable/attachable.ftl index 408faf862bb..d971585b0b4 100644 --- a/Resources/Locale/ru-RU/ADT/attachments/attachable/attachable.ftl +++ b/Resources/Locale/ru-RU/ADT/attachments/attachable/attachable.ftl @@ -1,12 +1,12 @@ -rmc-attachable-holder-strip-ui-title = снять модули -rmc-attachable-holder-strip-ui-empty-slot = ничего +rmc-attachable-holder-strip-ui-title = Модули +rmc-attachable-holder-strip-ui-empty-slot = Ничего rmc-verb-strip-attachables = Снять модули rmc-aslot-barrel = Ствол -rmc-aslot-rail = Планка +rmc-aslot-rail = Верхняя планка rmc-aslot-stock = Приклад -rmc-aslot-underbarrel = Подствольный +rmc-aslot-underbarrel = Подствольное rmc-attachable-activation-fail-not-wielded = {CAPITALIZE(THE($holder))} должен быть экипирован, чтобы активировать {THE($attachable)}! rmc-attachable-activation-fail-not-held = {CAPITALIZE(THE($holder))} должен быть в руках, чтобы активировать {THE($attachable)}! diff --git a/Resources/Locale/ru-RU/ADT/attachments/weapons/magnetize.ftl b/Resources/Locale/ru-RU/ADT/attachments/weapons/magnetize.ftl index 475d59acfe1..d722c488656 100644 --- a/Resources/Locale/ru-RU/ADT/attachments/weapons/magnetize.ftl +++ b/Resources/Locale/ru-RU/ADT/attachments/weapons/magnetize.ftl @@ -1 +1 @@ -rmc-magnetize-return = {CAPITALIZE(THE($item))} притягивается на место к {$magnetizer}. \ No newline at end of file +rmc-magnetize-return = {CAPITALIZE($item)} притягивается на место \ No newline at end of file diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/barrel_attachment.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/barrel_attachment.yml index e69de29bb2d..71c95ec87ff 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/barrel_attachment.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/barrel_attachment.yml @@ -0,0 +1,12 @@ +## BASE +- type: entity + abstract: true + parent: ADTAttachableBase + id: ADTBarrelAttachmentBase + components: + - type: Sprite + sprite: ADT/Attachments/barrel.rsi + - type: Tag + tags: + - ADTAttachmentBarrel +## diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/rail_attachment.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/rail_attachment.yml index e69de29bb2d..8abb6699ea4 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/rail_attachment.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/rail_attachment.yml @@ -0,0 +1,29 @@ +## BASE +- type: entity + abstract: true + parent: ADTAttachableBase + id: ADTRailAttachmentBase + components: + - type: Sprite + sprite: ADT/Attachments/rail.rsi + - type: Tag + tags: + - ADTAttachmentRail +## BASE + +- type: entity + parent: ADTRailAttachmentBase + id: ADTAttachmentMagneticHarness + name: magnetic harness + description: A magnetically attached harness kit that attaches to the rail mount of a weapon. When dropped, the weapon will sling to any set of Marine armor. + components: + - type: Sprite + state: magnetic + - type: Tag + tags: + - ADTAttachmentRail + - ADTAttachmentMagneticHarness + - type: AttachableMagnetic + - type: AttachableWeaponRangedMods + modifiers: + - accuracyAddMult: -0.05 diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml index ebc26a09552..0d9d4053d41 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml @@ -135,3 +135,19 @@ - type: AttachableVisuals - type: UniqueAction - type: PumpAction + +- type: entity + parent: ADTUnderAttachmentBase + id: ADTMicroAccelerator + name: micro accelerator + description: sus + components: + - type: Sprite + sprite: ADT/Objects/Weapons/Guns/Saber_revolvers/battery.rsi # затычка + state: base + - type: Tag + tags: + - ADTAttachmentMicroAccelerator + - type: AttachableWeaponRangedMods + modifiers: + - fireDelayFlat: -1.0 diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/guns_base.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/guns_base.yml new file mode 100644 index 00000000000..3b4a398001d --- /dev/null +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/guns_base.yml @@ -0,0 +1,28 @@ +- type: entity + id: ADTBasePumpingGun + categories: + - HideSpawnMenu + components: + - type: UniqueAction + - type: PumpAction + - type: Appearance + - type: BallisticAmmoProvider + cycleable: true + - type: ContainerContainer + containers: + ballistic-ammo: !type:Container + ents: [] + +- type: entity + parent: ADTBaseAttachableHolder + id: ADTBaseMagneticGun + categories: + - HideSpawnMenu + components: + - type: AttachableHolder + slots: + rmc-aslot-rail: + whitelist: + tags: + - ADTAttachmentMagneticHarness + - type: Appearance diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/tags.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/tags.yml index ad214ad96cb..289dae44fcc 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/tags.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/tags.yml @@ -7,3 +7,17 @@ - type: Tag id: ADTAttachmentM90UnderbarrelShotgun +- type: Tag + id: ADTAttachmentBarrel + +- type: Tag + id: SurvivalKnifeAttachment + +- type: Tag + id: ADTAttachmentMicroAccelerator + +- type: Tag + id: ADTAttachmentRail + +- type: Tag + id: ADTAttachmentMagneticHarness diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/test.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/test.yml deleted file mode 100644 index cab74a31d43..00000000000 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/test.yml +++ /dev/null @@ -1,593 +0,0 @@ -# - type: entity -# abstract: true -# id: RMCBaseAttachableHolder -# components: -# - type: AttachableHolder -# - type: ItemSizeChange -# - type: ActivatableUI -# verbText: rmc-verb-strip-attachables -# verbOnly: true -# key: -# enum.AttachmentUI.StripKey -# - type: UserInterface -# interfaces: -# enum.AttachmentUI.StripKey: -# type: AttachmentStripBui -# enum.AttachmentUI.ChooseSlotKey: -# type: AttachmentChooseSlotBui - -# - type: entity -# abstract: true -# id: RMCBaseMeleeWeapon - -# - type: entity -# abstract: true -# parent: RMCBaseMeleeWeapon -# id: CMBaseWeaponGun -# components: -# - type: Clothing -# quickEquip: false -# - type: UseDelay -# delay: 0 -# - type: WieldDelay -# - type: AltFireMelee -# - type: MeleeWeapon -# resetOnHandSelected: false -# attackRate: 1 -# damage: -# types: -# Blunt: 5 -# soundHit: -# collection: GenericHit -# - type: Gun -# meleeCooldownOnShoot: false -# resetOnHandSelected: false - -# - type: entity -# parent: BaseBullet -# id: RMCBaseBullet -# components: -# - type: Sprite -# sprite: _RMC14/Objects/Weapons/Guns/Ammunition/Projectiles/bullet_projectiles.rsi -# layers: -# - state: bullet -# shader: unshaded - - -# - type: entity -# abstract: true -# parent: [ CMBaseWeaponGun, BaseItem, RMCBaseAttachableHolder ] -# id: CMBaseWeaponRifle -# components: -# - type: Gun -# shotsPerBurst: 3 -# selectedMode: Burst -# availableModes: -# - SemiAuto -# - Burst -# - type: RMCSelectiveFire -# baseFireModes: -# - SemiAuto -# - Burst -# recoilWielded: 1 -# recoilUnwielded: 4 -# scatterWielded: 10 -# scatterUnwielded: 20 -# baseFireRate: 1.429 -# burstScatterMult: 4 -# modifiers: -# Burst: -# fireDelay: 0.1665 -# maxScatterModifier: 10 -# useBurstScatterMult: true -# unwieldedScatterMultiplier: 2 -# shotsToMaxScatter: 6 -# FullAuto: -# maxScatterModifier: 13 -# useBurstScatterMult: true -# unwieldedScatterMultiplier: 2 -# shotsToMaxScatter: 4 -# - type: Wieldable -# - type: WieldableSpeedModifiers -# baseWalk: 0.8 -# baseSprint: 0.69 -# - type: WieldDelay -# baseDelay: 0.6 -# - type: Item -# size: Large -# - type: Clothing -# sprite: Objects/Weapons/Guns/SMGs/atreides.rsi -# slots: -# - suitStorage -# - Back -# - type: AmmoCounter -# - type: ContainerContainer -# containers: -# gun_magazine: !type:ContainerSlot -# gun_chamber: !type:ContainerSlot -# - type: StaticPrice -# price: 500 -# - type: MagazineAmmoProvider -# autoEject: true -# - type: MagazineVisuals -# magState: mag -# steps: 1 -# zeroVisible: true -# - type: Appearance -# - type: Sprite -# sprite: Objects/Weapons/Guns/SMGs/atreides.rsi -# layers: -# - state: base -# map: ["enum.GunVisualLayers.Base"] -# - state: mag-0 -# map: ["enum.GunVisualLayers.Mag"] - -# - type: entity -# id: CMMagazineRifleBase -# name: "magazine (.20 rifle)" -# parent: BaseMagazineRifle -# components: -# - type: BallisticAmmoProvider -# proto: CartridgeRifle -# - type: Sprite -# layers: -# - state: red -# map: ["enum.GunVisualLayers.Base"] -# - state: mag-1 -# map: ["enum.GunVisualLayers.Mag"] -# - type: Tag -# tags: -# - CMMagazineRifle - -# - type: entity -# parent: BaseCartridge -# id: CMBaseCartridgeRifle -# name: cartridge -# abstract: true -# components: -# - type: CartridgeAmmo -# deleteOnSpawn: true -# - type: Sprite -# sprite: Objects/Weapons/Guns/Ammunition/Casings/ammo_casing.rsi -# layers: -# - state: base -# map: ["enum.AmmoVisualLayers.Base"] - -# - type: Tag -# id: CMMagazineRifle -# - type: Tag -# id: RMCAttachmentUnderbarrel -# - type: Tag -# id: RMCAttachmentU1GrenadeLauncher -# - type: Tag -# id: RMCAttachmentRail - -# - type: entity -# parent: BaseItem -# abstract: true -# id: RMCAttachableBase -# components: -# - type: Item -# size: Small -# - type: Attachable - -# - type: entity -# parent: RMCAttachableBase -# abstract: true -# id: RMCAttachableToggleableBase -# components: -# - type: AttachableToggleable -# - type: UseDelay -# delay: 0 - - -# - type: entity -# parent: [ RMCBaseMeleeWeapon, BaseKnife, RMCAttachableBase ] -# id: RMCM5Bayonet -# name: "M5 'Night Raider' bayonet" -# description: The standard-issue bayonet of the Marines. You can slide this knife into your boots. # TODO RMC14 , or attach it to the end of a rifle. -# components: -# - type: Clothing -# slots: -# - mask -# - pocket -# - suitstorage -# sprite: Objects/Weapons/Melee/kitchen_knife.rsi -# - type: Tag -# tags: -# - RMCM5Bayonet -# - Knife -# - RMCAttachmentBarrel -# - type: Sprite -# sprite: Objects/Weapons/Melee/kitchen_knife.rsi -# state: icon -# - type: Item -# sprite: Objects/Weapons/Melee/kitchen_knife.rsi -# size: Small -# - type: MeleeWeapon -# wideAnimationRotation: -135 -# attackRate: 1 -# damage: -# types: -# Slash: 25 -# - type: DamageOtherOnHit -# damage: -# types: -# Slash: 18 -# - type: DisarmMalus -# malus: 0.225 -# - type: AttachableVisuals -# rsi: Objects/Weapons/Melee/kitchen_knife.rsi -# prefix: icon -# - type: AttachableWeaponMeleeMods -# modifiers: -# - bonusDamage: -# types: -# Slash: 20 -# - decreaseDamage: -# types: -# Blunt: 5 -# - type: AttachableWeaponRangedMods -# modifiers: -# - conditions: -# unwieldedOnly: true -# accuracyAddMult: -0.05 -# - type: AttachablePrying - -# - type: Tag -# id: RMCAttachmentBarrel -# - type: Tag -# id: RMCM5Bayonet -# - type: entity -# abstract: true -# parent: RMCAttachableBase -# id: RMCBarrelAttachmentBase -# components: -# - type: Sprite -# sprite: Objects/Weapons/Melee/kitchen_knife.rsi -# - type: Tag -# tags: -# - RMCAttachmentBarrel - -# # пример -# - type: entity -# parent: CMBaseWeaponRifle -# name: M54C assault rifle MK2 -# id: WeaponRifleM54C -# description: The standard issue rifle of the Marines. Commonly carried by most combat personnel. Uses 10x24mm caseless ammunition. -# components: -# - type: ContainerContainer -# containers: -# gun_magazine: !type:ContainerSlot -# gun_chamber: !type:ContainerSlot -# - type: Gun -# selectedMode: FullAuto -# availableModes: -# - SemiAuto -# - Burst -# - FullAuto -# - type: RMCSelectiveFire -# baseFireModes: -# - SemiAuto -# - Burst -# - FullAuto -# recoilUnwielded: 4 -# scatterWielded: 6 -# scatterUnwielded: 20 -# baseFireRate: 4 -# burstScatterMult: 1 -# - type: ItemSlots -# slots: -# gun_magazine: -# name: Magazine -# priority: 2 -# whitelist: -# tags: -# - CMMagazineRifle -# - type: AttachableHolder -# slots: -# rmc-aslot-barrel: -# whitelist: -# tags: -# - RMCM5Bayonet -# - RMCAttachmentSuppressor -# rmc-aslot-underbarrel: -# whitelist: -# tags: -# - RMCAttachmentU1GrenadeLauncher -# rmc-aslot-stock: -# whitelist: -# tags: -# - RMCAttachmentM54CStockSolid -# rmc-aslot-rail: -# whitelist: -# tags: -# - SlavikScope -# - RMCAttachmentMagneticHarness -# - type: AttachableHolderVisuals -# offsets: -# rmc-aslot-barrel: 0.75, 0.00 -# rmc-aslot-underbarrel: 0.75, 0.00 -# rmc-aslot-stock: 0.75, 0.00 -# # пример - -# - type: entity -# abstract: true -# parent: RMCAttachableBase -# id: RMCUnderAttachmentBase -# components: -# - type: Sprite -# sprite: Objects/Weapons/Melee/kitchen_knife.rsi -# - type: Tag -# tags: -# - RMCAttachmentUnderbarrel - -# - type: entity -# parent: [ RMCUnderAttachmentBase, RMCAttachableToggleableBase, BaseItem ] -# id: RMCAttachmentU1GrenadeLauncher -# name: U1 grenade launcher -# description: A weapon-mounted, reloadable grenade launcher. -# components: -# - type: ContainerContainer -# containers: -# ballistic-ammo: !type:Container -# ents: [] -# - type: RMCAmmoEject -# containerID: ballistic-ammo -# - type: AmmoCounter -# - type: Gun -# projectileSpeed: 20 -# resetOnHandSelected: false -# - type: RMCSelectiveFire -# baseFireRate: 0.417 -# - type: BallisticAmmoProvider -# cycleable: false -# whitelist: -# tags: -# - CartridgeRocket -# capacity: 3 -# - type: UniqueAction -# - type: Appearance -# - type: AttachableToggleable -# userOnly: true -# attachedOnly: true -# supercedeHolder: true -# wieldedUseOnly: true -# activatePopupText: attachable-popup-switch-to-generic -# deactivatePopupText: attachable-popup-switch-from-generic -# actionName: Switch to the U1 Grenade Launcher -# actionDesc: Switch to using the underbarrel grenade launcher. -# - type: Tag -# tags: -# - RMCAttachmentUnderbarrel -# - RMCAttachmentU1GrenadeLauncher -# - type: Sprite -# sprite: Objects/Weapons/Melee/kitchen_knife.rsi -# state: icon -# - type: Item -# sprite: Objects/Weapons/Melee/kitchen_knife.rsi -# size: Small -# - type: BreechLoaded -# needOpenClose: true -# - type: OnShootTriggerAmmoTimer -# delay: 1 -# beepInterval: 2 -# initialBeepDelay: 0 -# beepSound: -# path: "/Audio/Effects/beep1.ogg" -# params: -# volume: 5 -# - type: ShootAtFixedPoint -# maxFixedRange: 7 - -# - type: entity -# abstract: true -# parent: RMCAttachableBase -# id: RMCRailAttachmentBase -# components: -# - type: Sprite -# sprite: _RMC14/Objects/Weapons/Guns/Attachments/rail.rsi -# - type: Tag -# tags: -# - RMCAttachmentRail - -# - type: entity -# abstract: true -# parent: [ RMCRailAttachmentBase, RMCAttachableToggleableBase ] -# id: RMCAttachmentScopeBase -# components: -# - type: AttachableToggleable -# needHand: true -# heldOnlyActivate: true -# userOnly: true -# doInterrupt: true -# attachedOnly: true -# breakOnMove: true -# breakOnRotate: true -# wieldedOnly: true -# useDelay: 0.5 -# showTogglePopup: false -# icon: -# sprite: _RMC14/Objects/Weapons/Guns/Attachments/rail.rsi -# state: sniperscope -# actionName: Look through Scope -# actionDesc: Scope in. If you're seeing this, someone forgot to set the description properly. -# - type: AttachableToggleableSimpleActivate -# - type: Scope -# requireWielding: true -# attachment: true -# useInHand: true -# zoomLevels: -# - zoom: 1 -# offset: 15 -# allowMovement: false -# doAfter: 0 - -# - type: Tag -# id: SlavikScope - -# - type: entity -# parent: RMCAttachmentScopeBase -# id: RMCAttachmentSlavicScope -# name: 4x telescopic scope -# description: Oppa! How did you get this off glorious Stalin weapon? Blyat, put back on and do job tovarish. Yankee is not shoot self no? -# components: -# - type: Sprite -# state: slavicscope -# - type: Tag -# tags: -# - RMCAttachmentRail -# - SlavikScope -# - type: AttachableVisuals -# - type: AttachableToggleable -# actionName: Look through the S8 4x Telescopic Scope -# actionDesc: An AEGIS S8 telescopic eye piece. Fixed at 4x zoom. -# - type: AttachableToggleableSimpleActivate -# - type: Scope -# zoomLevels: -# - zoom: 1.6 -# offset: 14 -# allowMovement: false -# doAfter: 0 -# - type: AttachableSpeedMods -# modifiers: -# - conditions: -# wieldedOnly: true -# walk: -0.23 -# sprint: -0.35 -# - type: AttachableWieldDelayMods -# modifiers: -# - delay: 0.4 -# - type: AttachableWeaponRangedMods -# modifiers: -# - fireDelayFlat: 0.1 -# - conditions: -# activeOnly: true -# fireDelayFlat: 0.25 -# accuracyAddMult: 0.35 -# damageFalloffAddMult: -0.4 -# - conditions: -# wieldedOnly: true -# inactiveOnly: true -# accuracyAddMult: -0.05 -# - conditions: -# unwieldedOnly: true -# accuracyMovementPenaltyAddMult: 2 - -# - type: Tag -# id: RMCAttachmentSuppressor - -# - type: entity -# parent: RMCBarrelAttachmentBase -# id: RMCAttachmentSuppressor -# name: suppressor -# description: "A small tube with exhaust ports to expel noise and gas. -# Does not completely silence a weapon, but does make it much quieter at the cost of slightly reduced damage." -# components: -# - type: Sprite -# state: suppressor -# - type: Tag -# tags: -# - RMCAttachmentBarrel -# - RMCAttachmentSuppressor -# - type: AttachableVisuals -# prefix: suppressor2 -# - type: AttachableSilencer -# sound: -# collection: sparks -# params: -# maxDistance: 6 -# - type: AttachableWeaponRangedMods -# modifiers: -# - damageFalloffAddMult: 0.1 - -# - type: entity -# abstract: true -# parent: RMCAttachableBase -# id: RMCStockAttachmentBase -# components: -# - type: Sprite -# sprite: _RMC14/Objects/Weapons/Guns/Attachments/stock.rsi -# - type: Tag -# tags: -# - RMCAttachmentStock -# - type: AttachableWieldDelayMods -# modifiers: -# - delay: 0.2 -# - type: AttachableSizeMods -# modifiers: -# - size: 2 -# - type: AttachableWeaponMeleeMods -# modifiers: -# - bonusDamage: -# types: -# Blunt: 5 - -# - type: entity -# parent: RMCStockAttachmentBase -# id: RMCAttachmentM54CStockSolid -# name: M54C solid stock -# description: A rare stock distributed in small numbers to UNMC forces. Compatible with the M54C, this stock reduces recoil and scatter, but at a reduction to handling and agility. Also enhances the thwacking of things with the stock-end of the rifle. -# components: -# - type: Sprite -# sprite: _RMC14/Objects/Weapons/Guns/Attachments/rmc_stock.rsi -# state: m54c-solid -# - type: Tag -# tags: -# - RMCAttachmentStock -# - RMCAttachmentM54CStockSolid -# - type: AttachableVisuals -# - type: AttachableSpeedMods -# modifiers: -# - conditions: -# wieldedOnly: true -# walk: -0.059 -# sprint: -0.101 -# - type: AttachableWieldDelayMods -# modifiers: -# - delay: 0.4 -# - type: AttachableWeaponMeleeMods -# modifiers: -# - bonusDamage: -# types: -# Blunt: 10 -# - type: AttachableWeaponRangedMods -# modifiers: -# - conditions: -# wieldedOnly: true -# accuracyAddMult: 0.25 -# recoilFlat: -3 -# scatterFlat: -8 -# - conditions: -# unwieldedOnly: true -# accuracyMovementPenaltyAddMult: -2 -# accuracyAddMult: -0.15 -# recoilFlat: 2 -# scatterFlat: 6 - -# - type: Tag -# id: RMCAttachmentM54CStockSolid - -# - type: Tag -# id: RMCAttachmentStock - -# - type: Tag -# id: RMCAttachmentMagneticHarness - -# - type: entity -# parent: RMCRailAttachmentBase -# id: RMCAttachmentMagneticHarness -# name: magnetic harness -# description: A magnetically attached harness kit that attaches to the rail mount of a weapon. When dropped, the weapon will sling to any set of Marine armor. -# components: -# - type: Sprite -# state: magnetic -# - type: Tag -# tags: -# - RMCAttachmentRail -# - RMCAttachmentMagneticHarness -# - type: AttachableMagnetic -# - type: AttachableVisuals -# - type: AttachableWeaponRangedMods -# modifiers: -# - accuracyAddMult: -0.05 diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Battery/battery_gun.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Battery/battery_gun.yml index 25432adafdf..467e579d043 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Battery/battery_gun.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Battery/battery_gun.yml @@ -1,6 +1,6 @@ - type: entity name: ion rifle - parent: BaseWeaponBattery + parent: [BaseWeaponBattery, ADTBaseMagneticGun] id: ADTWeaponIonRifle description: An ion-electronic disruptor rifle specifically designed to fight cyborgs and mechs. components: diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Rifles/rifles.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Rifles/rifles.yml index fd8b1982ac4..381b33ebd7d 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Rifles/rifles.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Rifles/rifles.yml @@ -100,7 +100,7 @@ - type: entity name: AR-12 - parent: WeaponRifleLecter + parent: [WeaponRifleLecter, ADTBaseMagneticGun] id: ADTWeaponRifleAR12 description: AR-12 components: @@ -155,7 +155,7 @@ - type: entity name: xC67 - parent: BaseWeaponRifle + parent: [BaseWeaponRifle, ADTBaseMagneticGun] id: ADTWeaponRifleXC67 description: A high end prototipe assault rifle. Uses .20 rifle ammo. components: diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Shotguns/shotguns.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Shotguns/shotguns.yml index 320b4223c92..2ff844c9278 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Shotguns/shotguns.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Shotguns/shotguns.yml @@ -33,18 +33,3 @@ ents: [] - type: StaticPrice price: 4500 - -- type: entity - id: ADTBasePumpingGun - categories: - - HideSpawnMenu - components: - - type: UniqueAction - - type: PumpAction - - type: Appearance - - type: BallisticAmmoProvider - cycleable: true - - type: ContainerContainer - containers: - ballistic-ammo: !type:Container - ents: [] diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/base_pka.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/base_pka.yml index f85e93b893f..cc48d0dae03 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/base_pka.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/base_pka.yml @@ -1,7 +1,7 @@ - type: entity id: WeaponProtoKineticAcceleratorBase abstract: true - parent: BaseItem + parent: [BaseItem, ADTBaseAttachableHolder] # ADT TWEAK components: - type: Sprite sprite: Objects/Weapons/Guns/Basic/kinetic_accelerator.rsi @@ -47,3 +47,32 @@ - Belt - type: UseDelay delay: 1 + - type: AttachableHolder + slots: + rmc-aslot-barrel: + whitelist: + tags: + - SurvivalKnifeAttachment + rmc-aslot-underbarrel: + whitelist: + tags: + - ADTAttachmentMicroAccelerator + # rmc-aslot-stock: + # whitelist: + # tags: + # rmc-aslot-rail: + # whitelist: + # tags: + - type: AttachableHolderVisuals + offsets: + rmc-aslot-barrel: 0.59375, -0.15625 + - type: MeleeWeapon + resetOnHandSelected: false + attackRate: 1 + damage: + types: + Blunt: 5 + soundHit: + collection: GenericHit + - type: AltFireMelee + 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 ddb2263d3a3..22d3105c65e 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml @@ -720,7 +720,7 @@ - type: entity name: energy shotgun - parent: [BaseWeaponBattery, BaseGunWieldable, BaseGrandTheftContraband] + parent: [BaseWeaponBattery, BaseGunWieldable, BaseGrandTheftContraband, ADTBaseMagneticGun] # ADT TWEAK id: WeaponEnergyShotgun description: A one-of-a-kind prototype energy weapon that uses various shotgun configurations. It offers the possibility of both lethal and non-lethal shots, making it a versatile weapon. components: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/LMGs/lmgs.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/LMGs/lmgs.yml index a415927cc56..c7db7f3879a 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/LMGs/lmgs.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/LMGs/lmgs.yml @@ -68,7 +68,7 @@ - type: entity name: L6 SAW id: WeaponLightMachineGunL6 - parent: [BaseWeaponLightMachineGun, BaseSyndicateContraband] + parent: [BaseWeaponLightMachineGun, BaseSyndicateContraband, ADTBaseMagneticGun] # adt tweak description: A rather traditionally made LMG with a pleasantly lacquered wooden pistol grip. Uses .30 rifle ammo. components: - type: Sprite diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml index 725254d8782..62a0a278ad2 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml @@ -22,7 +22,7 @@ - type: entity name: china lake - parent: [BaseWeaponLauncher, BaseGunWieldable, BaseSyndicateContraband] + parent: [BaseWeaponLauncher, BaseGunWieldable, BaseSyndicateContraband, ADTBaseMagneticGun] # ADT TWEAK id: WeaponLauncherChinaLake description: PLOOP. components: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml index 846605d2deb..1c915fb911e 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml @@ -102,7 +102,7 @@ - type: entity name: M-90gl - parent: [BaseWeaponRifle, ADTBaseAttachableHolder] # ADT TWEAK М90 ОБР ЯВЛЯЕТСЯ КОНТРАБАНДОЙ СИНДИКАТА XDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD + parent: [BaseWeaponRifle, ADTBaseAttachableHolder, ADTBaseMagneticGun] # ADT TWEAK М90 ОБР ЯВЛЯЕТСЯ КОНТРАБАНДОЙ СИНДИКАТА XDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD id: WeaponRifleM90GrenadeLauncher description: An older bullpup carbine model, with an attached underbarrel grenade launcher. Uses .20 rifle ammo. components: @@ -135,7 +135,6 @@ tags: - CartridgeRifle # ADT TWEAK START - #- Grenade # ADT TWEAK - type: AttachableHolder slots: rmc-aslot-underbarrel: @@ -147,7 +146,6 @@ offsets: rmc-aslot-underbarrel: 0.3125, -0.0625 # ADT TWEAK END - - type: ContainerContainer containers: gun_magazine: !type:ContainerSlot @@ -160,7 +158,7 @@ - type: entity name: Lecter - parent: [BaseWeaponRifle, BaseRestrictedContraband] + parent: [BaseWeaponRifle, BaseRestrictedContraband, ADTBaseMagneticGun] # ADT TWEAK id: WeaponRifleLecter description: A high end military grade assault rifle. Uses .20 rifle ammo. components: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml index a22be1da042..5325a94f6cf 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml @@ -58,7 +58,7 @@ - type: entity name: Atreides - parent: [BaseWeaponSubMachineGun, BaseMajorContraband] + parent: [BaseWeaponSubMachineGun, BaseMajorContraband, ADTBaseMagneticGun] # ADT TWEAK id: WeaponSubMachineGunAtreides description: Pla-ket-ket-ket-ket! Uses .35 auto ammo. components: @@ -81,7 +81,7 @@ - type: entity name: C-20r sub machine gun - parent: [BaseWeaponSubMachineGun, BaseSyndicateContraband] + parent: [BaseWeaponSubMachineGun, BaseSyndicateContraband, ADTBaseMagneticGun] # ADT TWEAK id: WeaponSubMachineGunC20r description: A firearm that is often used by the infamous nuclear operatives. Uses .35 auto ammo. components: @@ -119,7 +119,7 @@ - type: entity name: Drozd - parent: [BaseWeaponSubMachineGun, BaseRestrictedContraband] + parent: [BaseWeaponSubMachineGun, BaseRestrictedContraband, ADTBaseMagneticGun] # ADT TWEAK id: WeaponSubMachineGunDrozd description: An excellent fully automatic Heavy SMG. components: @@ -173,7 +173,7 @@ - type: entity name: Vector - parent: BaseWeaponSubMachineGun + parent: [BaseWeaponSubMachineGun, ADTBaseMagneticGun] # ADT TWEAK id: WeaponSubMachineGunVector suffix: Deprecated use Drozd description: An excellent fully automatic Heavy SMG. Uses .45 magnum ammo. @@ -221,7 +221,7 @@ - type: entity name: WT550 - parent: [ BaseWeaponSubMachineGun, BaseRestrictedContraband ] + parent: [ BaseWeaponSubMachineGun, BaseRestrictedContraband, ADTBaseMagneticGun] # ADT TWEAK id: WeaponSubMachineGunWt550 description: An excellent SMG, produced by NanoTrasen's Small Arms Division. Uses .35 auto ammo. components: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Shotguns/shotguns.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Shotguns/shotguns.yml index f1661ad952c..a3124155245 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Shotguns/shotguns.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Shotguns/shotguns.yml @@ -46,7 +46,7 @@ - type: entity name: Bulldog # Don't parent to BaseWeaponShotgun because it differs significantly - parent: [BaseItem, BaseGunWieldable, BaseSyndicateContraband] + parent: [BaseItem, BaseGunWieldable, BaseSyndicateContraband, ADTBaseMagneticGun] # adt tweak id: WeaponShotgunBulldog description: It's a magazine-fed shotgun designed for close quarters combat. Uses .50 shotgun shells. components: @@ -138,7 +138,7 @@ - type: entity name: Enforcer - parent: [BaseWeaponShotgun, BaseGunWieldable, BaseRestrictedContraband] + parent: [BaseWeaponShotgun, BaseGunWieldable, BaseRestrictedContraband, ADTBaseMagneticGun] # adt tweak id: WeaponShotgunEnforcer description: A premium combat shotgun based on the Kammerer design, featuring an upgraded clip capacity. .50 shotgun shells. components: @@ -167,7 +167,7 @@ - type: entity name: Kammerer - parent: [BaseWeaponShotgun, BaseGunWieldable, BaseRestrictedContraband, ADTBasePumpingGun] # adt tweak + parent: [BaseWeaponShotgun, BaseGunWieldable, BaseRestrictedContraband, ADTBasePumpingGun, ADTBaseMagneticGun] # adt tweak id: WeaponShotgunKammerer description: When an old Remington design meets modern materials, this is the result. A favourite weapon of militia forces throughout many worlds. Uses .50 shotgun shells. components: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml index 4ea0061c961..e9cfd87e825 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml @@ -49,7 +49,7 @@ - type: entity name: Hristov - parent: [BaseWeaponSniper, BaseGunWieldable, BaseSyndicateContraband] + parent: [BaseWeaponSniper, BaseGunWieldable, BaseSyndicateContraband, ADTBaseMagneticGun] # ADT TWEAK id: WeaponSniperHristov description: A portable anti-materiel rifle. Fires armor piercing 14.5mm shells. Uses .60 anti-materiel ammo. components: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml index eacb2d044ab..5e9def6bd99 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml @@ -124,7 +124,7 @@ - type: entity name: survival knife - parent: [CombatKnife, BaseSecurityCargoContraband] + parent: [CombatKnife, BaseSecurityCargoContraband, ADTBarrelAttachmentBase] # ADT TWEAK id: SurvivalKnife description: Weapon of first and last resort for combatting space carp. components: @@ -133,6 +133,27 @@ state: icon - type: Item sprite: Objects/Weapons/Melee/survival_knife.rsi +# ADT TWEAK START + - type: Tag + tags: + - SurvivalKnifeAttachment + - Knife + - type: AttachableWeaponMeleeMods + modifiers: + - bonusDamage: + types: + Slash: 15 + - decreaseDamage: + types: + Blunt: 5 + - type: AttachableWeaponRangedMods + modifiers: + - accuracyAddMult: -0.05 + - type: AttachablePrying + - type: AttachableVisuals + rsi: Objects/Weapons/Melee/survival_knife.rsi + prefix: icon +# ADT TWEAK END - type: entity name: kukri knife diff --git a/Resources/Textures/ADT/Attachments/rail.rsi/magnetic.png b/Resources/Textures/ADT/Attachments/rail.rsi/magnetic.png new file mode 100644 index 0000000000000000000000000000000000000000..f52e9133eb9abb297a07a0333a7f829e0c43661e GIT binary patch literal 248 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}n><|{Ln2z= zUNYorF%WRLxPQacxh$(6$l5fkpGqx~J+BZEbxK6&h+gits6GQ^=S&i0bZI* z|FstDRlW~i_xYas^O$YFtERWT-o=#A;~5$nYi8*7tkUk5(E3RyBqp!fYT_GgV$#yk zu^~6Qtj;Xsw%OIv-VTO@wM*asK3yi!Hb3uv`LxuXcLQsh*1cwsI6g6RmY%er3~l|7IgZWHcw*!4z;Mp;&F{KQN3WNL6567Dj{}86bXpj)b6EtAEzewK)^IT5 ze!QHN3S)uM*ZEU} Date: Sat, 30 Nov 2024 22:45:44 +0200 Subject: [PATCH 14/46] =?UTF-8?q?=D0=B4=D0=B0=20=D0=B1=D0=BB=D1=8F=D1=82?= =?UTF-8?q?=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Resources/Locale/ru-RU/ADT/attachments/weapons/magnetize.ftl | 2 +- .../Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Resources/Locale/ru-RU/ADT/attachments/weapons/magnetize.ftl b/Resources/Locale/ru-RU/ADT/attachments/weapons/magnetize.ftl index d722c488656..d4c77aecb3b 100644 --- a/Resources/Locale/ru-RU/ADT/attachments/weapons/magnetize.ftl +++ b/Resources/Locale/ru-RU/ADT/attachments/weapons/magnetize.ftl @@ -1 +1 @@ -rmc-magnetize-return = {CAPITALIZE($item)} притягивается на место \ No newline at end of file +rmc-magnetize-return = {CAPITALIZE($item)} притягивается на место. \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml index 1c915fb911e..78c377d3f82 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml @@ -53,7 +53,7 @@ - type: entity name: AKMS - parent: [BaseWeaponRifle, BaseRestrictedContraband] + parent: [BaseWeaponRifle, BaseRestrictedContraband, ADTBaseMagneticGun] # adt tweak id: WeaponRifleAk description: An iconic weapon of war. Uses .30 rifle ammo. components: From 5e2ff2ada9926ac472eb1800814d2f8dfbea4a4a Mon Sep 17 00:00:00 2001 From: Eugeny Date: Sun, 1 Dec 2024 08:05:20 +0400 Subject: [PATCH 15/46] =?UTF-8?q?40=D0=BC=D0=BC=5F=D0=B3=D1=80=D0=B0=D0=BD?= =?UTF-8?q?=D0=B0=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ADT/Catalog/Fills/Items/weaponcase.yml | 16 ++- .../Ammunition/Projectiles/projectiles.yml | 118 ++++++++++++++++++ .../Weapons/Guns/Ammunition/explosives.yml | 104 +++++++++++++++ .../Attachments/under_attachment.yml | 12 +- Resources/Prototypes/ADT/tags.yml | 3 + .../40mm_grenade.rsi/base-spent.png | Bin 0 -> 202 bytes .../Explosives/40mm_grenade.rsi/emp.png | Bin 0 -> 304 bytes .../Explosives/40mm_grenade.rsi/flash.png | Bin 0 -> 304 bytes .../Explosives/40mm_grenade.rsi/he.png | Bin 0 -> 305 bytes .../Explosives/40mm_grenade.rsi/heat.png | Bin 0 -> 309 bytes .../Explosives/40mm_grenade.rsi/meta.json | 35 ++++++ .../Explosives/40mm_grenade.rsi/smoke.png | Bin 0 -> 291 bytes .../Explosives/40mm_grenade.rsi/stinger.png | Bin 0 -> 311 bytes .../Explosives/40mm_grenade.rsi/stun.png | Bin 0 -> 305 bytes 14 files changed, 278 insertions(+), 10 deletions(-) create mode 100644 Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/projectiles.yml create mode 100644 Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Ammunition/explosives.yml create mode 100644 Resources/Textures/ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi/base-spent.png create mode 100644 Resources/Textures/ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi/emp.png create mode 100644 Resources/Textures/ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi/flash.png create mode 100644 Resources/Textures/ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi/he.png create mode 100644 Resources/Textures/ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi/heat.png create mode 100644 Resources/Textures/ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi/meta.json create mode 100644 Resources/Textures/ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi/smoke.png create mode 100644 Resources/Textures/ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi/stinger.png create mode 100644 Resources/Textures/ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi/stun.png diff --git a/Resources/Prototypes/ADT/Catalog/Fills/Items/weaponcase.yml b/Resources/Prototypes/ADT/Catalog/Fills/Items/weaponcase.yml index 2a6ea3198ed..e12b0573b55 100644 --- a/Resources/Prototypes/ADT/Catalog/Fills/Items/weaponcase.yml +++ b/Resources/Prototypes/ADT/Catalog/Fills/Items/weaponcase.yml @@ -21,10 +21,18 @@ - type: StorageFill contents: - id: ADTAttachmentM90GrenadeLauncher - - id: GrenadeFrag - amount: 3 - - id: GrenadeBlast - amount: 3 + - id: ADT40mmGrenadeBlast + amount: 6 + - id: ADT40mmGrenadeHEAT + amount: 4 + - id: ADT40mmGrenadeBaton + amount: 4 + - id: ADT40mmGrenadeEMP + amount: 4 + - id: ADT40mmGrenadeFlash + amount: 4 + - id: ADT40mmGrenadeSmoke + amount: 4 - type: entity id: WeaponCaseNTM90UnderBarrelShotGunAttachment diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/projectiles.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/projectiles.yml new file mode 100644 index 00000000000..6caf83b46dc --- /dev/null +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/projectiles.yml @@ -0,0 +1,118 @@ +- type: entity + id: ADTBullet40mmGrenadeBaton + name: baton grenade + parent: BaseBullet + categories: [ HideSpawnMenu ] + components: + - type: Sprite + sprite: Objects/Weapons/Guns/Projectiles/projectiles2.rsi + layers: + - state: grenade + - type: Projectile + deleteOnCollide: true + damage: + types: + Blunt: 25 + soundHit: + path: /Audio/Effects/gen_hit.ogg + - type: StaminaDamageOnCollide + damage: 160 + +- type: entity + id: ADTBullet40mmGrenadeBlast + name: blast grenade + parent: BaseBulletTrigger + categories: [ HideSpawnMenu ] + components: + - type: Sprite + sprite: Objects/Weapons/Guns/Projectiles/projectiles2.rsi + layers: + - state: grenade + - type: ExplodeOnTrigger + - type: Explosive + explosionType: Default + maxIntensity: 10 + intensitySlope: 3 + totalIntensity: 120 # about a ~4 tile radius + canCreateVacuum: false + +- type: entity + id: ADTBullet40mmGrenadeFlash + name: flash grenade + parent: BaseBulletTrigger + categories: [ HideSpawnMenu ] + components: + - type: Sprite + sprite: Objects/Weapons/Guns/Projectiles/projectiles2.rsi + layers: + - state: grenade + - type: FlashOnTrigger + range: 5 + - type: SpawnOnTrigger + proto: GrenadeFlashEffect + - type: ActiveTimerTrigger + timeRemaining: 0.3 + - type: DeleteOnTrigger + +- type: entity + id: ADTBullet40mmGrenadeHEAT + name: heat grenade + parent: BaseBulletTrigger + categories: [ HideSpawnMenu ] + components: + - type: Sprite + sprite: Objects/Weapons/Guns/Projectiles/projectiles2.rsi + layers: + - state: grenade + - type: ExplodeOnTrigger + - type: Explosive # Powerful explosion in a very small radius. Doesn't break underplating. + explosionType: DemolitionCharge + totalIntensity: 150 + intensitySlope: 25 + maxIntensity: 50 + canCreateVacuum: false + - type: Projectile + deleteOnCollide: true + damage: + types: + Structural: 1000 + Piercing: 75 + soundHit: + path: /Audio/Effects/gen_hit.ogg + +- type: entity + id: ADTBullet40mmGrenadeEMP + name: EMP grenade + parent: BaseBulletTrigger + categories: [ HideSpawnMenu ] + components: + - type: Sprite + sprite: Objects/Weapons/Guns/Projectiles/projectiles2.rsi + layers: + - state: frag + - type: EmpOnTrigger + range: 4 + energyConsumption: 50000 + disableDuration: 10 + - type: Ammo + muzzleFlash: null + - type: PointLight + radius: 3.5 + color: blue + energy: 0.5 + +- type: entity + id: ADTBullet40mmGrenadeSmoke + name: smoke grenade + parent: BaseBulletTrigger + categories: [ HideSpawnMenu ] + components: + - type: Sprite + sprite: Objects/Weapons/Guns/Projectiles/projectiles2.rsi + layers: + - state: grenade + - type: SmokeOnTrigger + duration: 30 + spreadAmount: 40 + - type: SoundOnTrigger + sound: /Audio/Items/smoke_grenade_smoke.ogg diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Ammunition/explosives.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Ammunition/explosives.yml new file mode 100644 index 00000000000..6342c3bbc97 --- /dev/null +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Ammunition/explosives.yml @@ -0,0 +1,104 @@ +- type: entity + id: ADTBase40mmGrenade + name: base 40 mm grenade + parent: [BaseItem, BaseMajorContraband] + abstract: true + components: + - type: Tag + tags: + - ADT40mmGrenade + - type: Item + size: Tiny + - type: Sprite + - type: CartridgeAmmo + deleteOnSpawn: true + +- type: entity + id: ADT40mmGrenadeBaton + name: 40 mm baton grenade + parent: ADTBase40mmGrenade + components: + - type: CartridgeAmmo + proto: ADTBullet40mmGrenadeBaton + - type: Sprite + sprite: ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi + layers: + - state: stun + map: ["enum.AmmoVisualLayers.Base"] + - type: Appearance + - type: SpentAmmoVisuals + +- type: entity + id: ADT40mmGrenadeBlast + name: 40 mm blast grenade + parent: ADTBase40mmGrenade + components: + - type: CartridgeAmmo + proto: ADTBullet40mmGrenadeBlast + - type: Sprite + sprite: ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi + layers: + - state: he + map: ["enum.AmmoVisualLayers.Base"] + - type: Appearance + - type: SpentAmmoVisuals + +- type: entity + id: ADT40mmGrenadeHEAT + name: 40 mm HEAT grenade + parent: ADTBase40mmGrenade + components: + - type: CartridgeAmmo + proto: ADTBullet40mmGrenadeHEAT + - type: Sprite + sprite: ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi + layers: + - state: heat + map: ["enum.AmmoVisualLayers.Base"] + - type: Appearance + - type: SpentAmmoVisuals + +- type: entity + id: ADT40mmGrenadeEMP + name: 40 mm EMP grenade + parent: ADTBase40mmGrenade + components: + - type: CartridgeAmmo + proto: ADTBullet40mmGrenadeEMP + - type: Sprite + sprite: ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi + layers: + - state: emp + map: ["enum.AmmoVisualLayers.Base"] + - type: Appearance + - type: SpentAmmoVisuals + +- type: entity + id: ADT40mmGrenadeFlash + name: 40 mm flash grenade + parent: ADTBase40mmGrenade + components: + - type: CartridgeAmmo + proto: ADTBullet40mmGrenadeFlash + - type: Sprite + sprite: ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi + layers: + - state: flash + map: ["enum.AmmoVisualLayers.Base"] + - type: Appearance + - type: SpentAmmoVisuals + +- type: entity + id: ADT40mmGrenadeSmoke + name: 40 mm smoke grenade + parent: ADTBase40mmGrenade + components: + - type: CartridgeAmmo + proto: ADTBullet40mmGrenadeSmoke + - type: Sprite + sprite: ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi + layers: + - state: smoke + map: ["enum.AmmoVisualLayers.Base"] + - type: Appearance + - type: SpentAmmoVisuals diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml index 0d9d4053d41..e39ef8db2ec 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml @@ -38,11 +38,11 @@ - type: RMCSelectiveFire baseFireRate: 0.417 - type: BallisticAmmoProvider - cycleable: false + # cycleable: false whitelist: tags: - - Grenade - proto: GrenadeFrag + - ADT40mmGrenade + proto: ADT40mmGrenadeBlast capacity: 1 soundInsert: path: /Audio/_RMC14/Weapons/Guns/Reload/grenade_insert.ogg @@ -50,9 +50,9 @@ volume: -2 - type: ShootAtFixedPoint maxFixedRange: 10 - - type: UniqueAction - - type: BreechLoaded - needOpenClose: true + # - type: UniqueAction + # - type: BreechLoaded + # needOpenClose: false - type: Appearance - type: GenericVisualizer visuals: diff --git a/Resources/Prototypes/ADT/tags.yml b/Resources/Prototypes/ADT/tags.yml index 3300045e31f..517c9166d2d 100644 --- a/Resources/Prototypes/ADT/tags.yml +++ b/Resources/Prototypes/ADT/tags.yml @@ -402,3 +402,6 @@ - type: Tag id: ADTDogEmotes + +- type: Tag + id: ADT40mmGrenade diff --git a/Resources/Textures/ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi/base-spent.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi/base-spent.png new file mode 100644 index 0000000000000000000000000000000000000000..3ed5e72b69a7fe79fb446fa98b0dfacb8e29efa2 GIT binary patch literal 202 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}EuJopArY-_ zFE12qR^(}Wxc;yD36;(xM%>&6PSzZ|U6c}8)DAof3cnxoUTfCz=ew`7a45D29O}Po zw0S@p8NT)q4?b5@Bd0dfkwqwGlm7Kv(G(}(h77BgQu&X%Q~loCIHZTNtplu literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi/emp.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi/emp.png new file mode 100644 index 0000000000000000000000000000000000000000..297921e5ee04244aed5299fd34b460958eb27d6e GIT binary patch literal 304 zcmV-00nh%4P)Px#>PbXFR9J=WmA^^^F%XA8|A2)c3^w}~8Du%Ou}CNQ7~5HGWv#96a1UW&A2^UL zliF&n?9v?z7O^_PcJ5d>%-5xuUp^+21S*xvF*6K9@!pqxGS01q-uu$FEdV*^5@S5E z%_9Ie+lI@F74d2VKqM|B0Pt{k z4SWL)eBKhb8&l44&cNH(3-7N&-}kIP)_cu>sRJUy?ixDh5RqjC4oMX-5kf#!%kDE$ z)e=H5Wt~}yrfDi&*Zp|~=Xrh_$MM-@QK?ia|C%3m*-bflp9&iQ0000Px#>PbXFR9J=WmA!4lFc5{GV=r(;YQq!o3L#JxfLTQg2=D^-AR53$c3>5#i#S0b zB%OhN>zd~a8IZfm>F`;0Dzn`%#1cb^=fB50ZhUDq9FfLTSV0wRLL8io)cB8&`g;GPr%6e%UBsvkZh zRrQn-r8Q@g#&Ptzt}kA}X__{D-)|`wg+ih5ulWY;gHDG1_-j@G0000Px#>q$gGR9J=Wl{<<8K@f)j^)+z?USL7fu3&;m`w-s2aB`Csyw6^t!DPU|>3E_B zmlX`kL>S$mjTB64MG^apx`X=bqn|(`k$7dwvW(W+_@9iPw$NG|^E?Lth)AsK`a_e` z(Ka{6T<1gtW>&3)O5mQTwm?MSy$1kz?;#?O6&Q|=0Ja!>X6XHF(LbpB>kr{{UoGPoUDGDLPq9|@&!M1I`s;Zi+EE0)C;;lIYw&zXjLcN3A00000NkvXXu0mjf D<41&* literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi/heat.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi/heat.png new file mode 100644 index 0000000000000000000000000000000000000000..875f8a3cc783b1d7ee673c7ffd49a9198d091366 GIT binary patch literal 309 zcmV-50m}Y~P)Px#?@2^KR9J=Wm9a_#K@f(&B*ICWun!=DV7*gZaqT{b;0xH?BbcYL^c5Ctu9Dk2 z)qz5az>w~OaBCI8b_@}5zix~9=VNzv7Yc>KU#4x_974!H$+)lHyQ0n_0#Cv}G~b=g>Ta4|i9< z1YGm-I-qKk`1Khu32gQi>!%OimiIjO2R8eP-Td-=0?s*(*U)>9bI#PPx#-AP12R9J=WmA!FStfKm#~j5a{^E$8e2&@>IUZNt9r0Dxf_Ue=?Bux;C?_%!hsx|Pn_T+6s`aO002ovPDHLkV1m7Eb(sJF literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi/stinger.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi/stinger.png new file mode 100644 index 0000000000000000000000000000000000000000..c87f92af28091b55be5a216d63e16d1e7245872d GIT binary patch literal 311 zcmV-70m%M|P)Px#@kvBMR9J=Wm9c8WFc60S#vQsIUHcBY!Gl*lM4)5AbHI;~JVWQcMaB#oJz5Xo zL6f04+-NODUFtxF6nY7UP<`7W-LIe1odjeunR}*bnq;j_*JwOy6RowWEK2}@h@`IT z9yB^D?cv6lQ%po)W>qCr25yP!3Pc3ndjNp<9wM@=fv=}`j1v$(pD|8H4ATFsye(q@ z0AAPCSv(B=g`K~1pFL2-4Gw!kUDr4aA1I>Wg@7^qT}xE~BEmd|#uyNhMn-SomSh7e zoO592G=E0SoSbtitwNI&LP%9roxOrF#%Px#>q$gGR9J=Wl|M=YK@^9-xVgZ?);r7;TP#@3Ei40Dim*q}Gg#*)DW(y(+-dAA zwo0?|+Jz9tLSnG=83Muix?y;~`FQgW3WdTY({)`AA>_YgEUkqhgk0A(0IHgYVOUsl zuB?kY=f1}xg7@Ck36sDnF>QgWl2QU7rG%=US73kp%mj?}HPh~cE$?3w!|FT&0C)Gz zaq!Af;+I_J8K_ Date: Sun, 1 Dec 2024 17:51:06 +0400 Subject: [PATCH 16/46] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=20=D0=B8=D0=BA?= =?UTF-8?q?=D0=BE=D0=BD=D0=BA=D0=B8=20=D1=88=D1=82=D1=8B=D0=BA=D0=B0=20?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=BF=D1=80=D0=BE=D1=82=D0=BE=D0=BA=D0=B8=D0=BD?= =?UTF-8?q?=D0=B5=D1=82=D0=B8=D0=BA=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{icon-a.png => icon_a.png} | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename Resources/Textures/Objects/Weapons/Guns/Basic/kinetic_accelerator.rsi/{icon-a.png => icon_a.png} (100%) diff --git a/Resources/Textures/Objects/Weapons/Guns/Basic/kinetic_accelerator.rsi/icon-a.png b/Resources/Textures/Objects/Weapons/Guns/Basic/kinetic_accelerator.rsi/icon_a.png similarity index 100% rename from Resources/Textures/Objects/Weapons/Guns/Basic/kinetic_accelerator.rsi/icon-a.png rename to Resources/Textures/Objects/Weapons/Guns/Basic/kinetic_accelerator.rsi/icon_a.png From dfabb2a432d378e14669c54e2c5e52d97c0ab0df Mon Sep 17 00:00:00 2001 From: Eugeny Date: Sun, 1 Dec 2024 22:25:51 +0400 Subject: [PATCH 17/46] =?UTF-8?q?=D1=88=D1=82=D1=8B=D0=BA=20=D0=BE=D1=82?= =?UTF-8?q?=20=D0=B2=D0=B8=D0=BD=D1=82=D0=BE=D0=B2=D0=BA=D0=B8=20=D0=9C?= =?UTF-8?q?=D0=BE=D1=81=D0=B8=D0=BD=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Entities/Objects/Weapons/Melee/melee.ftl | 2 + .../Entities/Objects/Weapons/Melee/knife.yml | 29 +++++++++++++ Resources/Prototypes/ADT/tags.yml | 3 ++ .../Objects/Weapons/Guns/Basic/base_pka.yml | 8 ++-- .../Objects/Weapons/Guns/Snipers/snipers.yml | 26 ++++++++++- .../Weapons/Guns/Rifles/mosin.rsi/base.png | Bin 0 -> 448 bytes .../Guns/Rifles/mosin.rsi/bolt-open.png | Bin 0 -> 454 bytes .../Rifles/mosin.rsi/equipped-BACKPACK.png | Bin 0 -> 1180 bytes .../Rifles/mosin.rsi/equipped-SUITSTORAGE.png | Bin 0 -> 1180 bytes .../Guns/Rifles/mosin.rsi/inhand-left.png | Bin 0 -> 744 bytes .../Guns/Rifles/mosin.rsi/inhand-right.png | Bin 0 -> 734 bytes .../Weapons/Guns/Rifles/mosin.rsi/meta.json | 41 ++++++++++++++++++ .../Rifles/mosin.rsi/wielded-inhand-left.png | Bin 0 -> 973 bytes .../Rifles/mosin.rsi/wielded-inhand-right.png | Bin 0 -> 968 bytes .../ADT/Attachments/under.rsi/meta.json | 24 ++++++---- .../Attachments/under.rsi/mosinbayonet.png | Bin 0 -> 207 bytes .../Attachments/under.rsi/mosinbayonet_a.png | Bin 0 -> 182 bytes .../Objects/bone_shard.rsi/festive.png | Bin 0 -> 4334 bytes .../Objects/bone_shard.rsi/meta.json | 9 ++-- .../Melee/mosin_bayonet.rsi/equipped-BELT.png | Bin 0 -> 3612 bytes .../Weapons/Melee/mosin_bayonet.rsi/icon.png | Bin 0 -> 207 bytes .../Melee/mosin_bayonet.rsi/inhand-left.png | Bin 0 -> 753 bytes .../Melee/mosin_bayonet.rsi/inhand-right.png | Bin 0 -> 742 bytes .../Weapons/Melee/mosin_bayonet.rsi/meta.json | 26 +++++++++++ 24 files changed, 150 insertions(+), 18 deletions(-) create mode 100644 Resources/Prototypes/ADT/Entities/Objects/Weapons/Melee/knife.yml create mode 100644 Resources/Textures/ADT/ADTGlobalEvents/WorldWar1/Objects/Weapons/Guns/Rifles/mosin.rsi/base.png create mode 100644 Resources/Textures/ADT/ADTGlobalEvents/WorldWar1/Objects/Weapons/Guns/Rifles/mosin.rsi/bolt-open.png create mode 100644 Resources/Textures/ADT/ADTGlobalEvents/WorldWar1/Objects/Weapons/Guns/Rifles/mosin.rsi/equipped-BACKPACK.png create mode 100644 Resources/Textures/ADT/ADTGlobalEvents/WorldWar1/Objects/Weapons/Guns/Rifles/mosin.rsi/equipped-SUITSTORAGE.png create mode 100644 Resources/Textures/ADT/ADTGlobalEvents/WorldWar1/Objects/Weapons/Guns/Rifles/mosin.rsi/inhand-left.png create mode 100644 Resources/Textures/ADT/ADTGlobalEvents/WorldWar1/Objects/Weapons/Guns/Rifles/mosin.rsi/inhand-right.png create mode 100644 Resources/Textures/ADT/ADTGlobalEvents/WorldWar1/Objects/Weapons/Guns/Rifles/mosin.rsi/meta.json create mode 100644 Resources/Textures/ADT/ADTGlobalEvents/WorldWar1/Objects/Weapons/Guns/Rifles/mosin.rsi/wielded-inhand-left.png create mode 100644 Resources/Textures/ADT/ADTGlobalEvents/WorldWar1/Objects/Weapons/Guns/Rifles/mosin.rsi/wielded-inhand-right.png create mode 100644 Resources/Textures/ADT/Attachments/under.rsi/mosinbayonet.png create mode 100644 Resources/Textures/ADT/Attachments/under.rsi/mosinbayonet_a.png create mode 100644 Resources/Textures/ADT/Changeling/Objects/bone_shard.rsi/festive.png create mode 100644 Resources/Textures/ADT/Objects/Weapons/Melee/mosin_bayonet.rsi/equipped-BELT.png create mode 100644 Resources/Textures/ADT/Objects/Weapons/Melee/mosin_bayonet.rsi/icon.png create mode 100644 Resources/Textures/ADT/Objects/Weapons/Melee/mosin_bayonet.rsi/inhand-left.png create mode 100644 Resources/Textures/ADT/Objects/Weapons/Melee/mosin_bayonet.rsi/inhand-right.png create mode 100644 Resources/Textures/ADT/Objects/Weapons/Melee/mosin_bayonet.rsi/meta.json diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Melee/melee.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Melee/melee.ftl index c34729023e9..f68c14706b3 100644 --- a/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Melee/melee.ftl +++ b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Melee/melee.ftl @@ -30,4 +30,6 @@ ent-ADTJasonMachette = мачете Джейсона .suffix = Хеллоуин .desc = Мачете одного из самых ужасающих маньяков. Сбоку маленькая надпись "полиуретан". +ent-ADTMosinBayonet = штык от винтовки Мосина + .desc = Потому что раны от игольчатого штыка невозможно сшить... diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Melee/knife.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Melee/knife.yml new file mode 100644 index 00000000000..da029374013 --- /dev/null +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Melee/knife.yml @@ -0,0 +1,29 @@ +- type: entity + name: Mosin`s rifle bayonet + parent: [CombatKnife, BaseSecurityCargoContraband, ADTBarrelAttachmentBase] + id: ADTMosinBayonet + description: Triangular bayonet wounds are impossible to stitch up. + components: + - type: Sprite + sprite: ADT/Objects/Weapons/Melee/mosin_bayonet.rsi + state: icon + - type: Item + sprite: ADT/Objects/Weapons/Melee/mosin_bayonet.rsi + - type: Tag + tags: + - ADTMosinBayonetAttachment + - type: AttachableWeaponMeleeMods + modifiers: + - bonusDamage: + types: + Piercing: 20 + - decreaseDamage: + types: + Blunt: 5 + - type: AttachableWeaponRangedMods + modifiers: + - accuracyAddMult: -0.05 + - type: AttachablePrying + - type: AttachableVisuals + rsi: ADT/Attachments/under.rsi + prefix: mosinbayonet diff --git a/Resources/Prototypes/ADT/tags.yml b/Resources/Prototypes/ADT/tags.yml index 517c9166d2d..b9ff5559675 100644 --- a/Resources/Prototypes/ADT/tags.yml +++ b/Resources/Prototypes/ADT/tags.yml @@ -405,3 +405,6 @@ - type: Tag id: ADT40mmGrenade + +- type: Tag + id: ADTMosinBayonetAttachment diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/base_pka.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/base_pka.yml index cc48d0dae03..33918811aca 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/base_pka.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/base_pka.yml @@ -47,7 +47,7 @@ - Belt - type: UseDelay delay: 1 - - type: AttachableHolder + - type: AttachableHolder #ADT_Tweak slots: rmc-aslot-barrel: whitelist: @@ -63,10 +63,10 @@ # rmc-aslot-rail: # whitelist: # tags: - - type: AttachableHolderVisuals + - type: AttachableHolderVisuals #ADT_Tweak offsets: rmc-aslot-barrel: 0.59375, -0.15625 - - type: MeleeWeapon + - type: MeleeWeapon #ADT_Tweak resetOnHandSelected: false attackRate: 1 damage: @@ -74,5 +74,5 @@ Blunt: 5 soundHit: collection: GenericHit - - type: AltFireMelee + - type: AltFireMelee #ADT_Tweak diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml index e9cfd87e825..2e27501c748 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml @@ -40,12 +40,34 @@ - type: entity name: Kardashev-Mosin - parent: [BaseWeaponSniper, BaseGunWieldable, BaseSyndicateContraband] + parent: [BaseWeaponSniper, BaseGunWieldable, BaseSyndicateContraband, ADTBaseAttachableHolder] #ADT_Tweak id: WeaponSniperMosin description: A weapon for hunting, or endless trench warfare. Uses .30 rifle ammo. components: - type: Sprite - sprite: Objects/Weapons/Guns/Snipers/bolt_gun_wood.rsi + sprite: ADT/ADTGlobalEvents/WorldWar1/Objects/Weapons/Guns/Rifles/mosin.rsi #ADT_Tweak +#ADT_Tweak START + - type: AttachableHolder #ADT_Tweak + slots: + rmc-aslot-barrel: + startingAttachable: ADTMosinBayonet + whitelist: + tags: + - ADTMosinBayonetAttachment + - type: AttachableHolderVisuals #ADT_Tweak + offsets: + rmc-aslot-barrel: 0.59375, 0 + # rmc-aslot-barrel: 0.59375, -0.15625 + - type: MeleeWeapon #ADT_Tweak + resetOnHandSelected: false + attackRate: 1 + damage: + types: + Blunt: 5 + soundHit: + collection: GenericHit + - type: AltFireMelee +#ADT_Tweak END - type: entity name: Hristov diff --git a/Resources/Textures/ADT/ADTGlobalEvents/WorldWar1/Objects/Weapons/Guns/Rifles/mosin.rsi/base.png b/Resources/Textures/ADT/ADTGlobalEvents/WorldWar1/Objects/Weapons/Guns/Rifles/mosin.rsi/base.png new file mode 100644 index 0000000000000000000000000000000000000000..ceee92fa80ecf2c30151c69ef5041384ed09d1dc GIT binary patch literal 448 zcmV;x0YCnUP)Px$dPzh6K@`V7ySBLLZri4*NReQW27(Y&5M4a=hjx$%I(DmDP(*cz zGR&YuV$o_^P>a@f$Q9Q;WIqUk`J86noA7>$W0Ni)scJu85`e{DB0#LC!oV3~>g1}~Ry(jV;!Y&d(Ar^GpIajO>;JwmBBH8Px$fJsC_R9J=WlFv#4Q5431GbRqHT}@MwBEg_P6tt=!+O+BcTD0f|+C*>COSo_$ zZQIql7S%$mD50SUi$+nS8nkR7GdPZrR78vWTYl%>^L_W80}_cuB9Z)8wzhX#-P+Rf zic6cEns#aZVD(aZ71uX59Zm0Ubt=Xa0J^RN@b>zmBofJ1DxGHV>KK568e!(caP{ld z3u*)r5&(oF(cS^NS&jJ|fx>>Z=efKu#jJUQ2zaPIzas)3;z5nQ@(9b`TjD{D-P0FB zA_Ra436%LEZwp{pb2dGAG!@I(G86$10Pp)zg1d~qVke!j{@!^@Pn;R@ENza}RD zxV$)50F>33ueG)irBXH>myWLMg#9Wa;Ne6!`HHhzqp#oWW&og4HhHMOISOIFO3`S7 z(L|eDVsvbrTsC9R9kBPpdd;^3bW(kO2cT#)Ijc3=hCnWxu}yx%*g}E!l38;u8co3Y wrHMq+Ucyr8{>P@S0M;UQ8%rb-iR3T%1l?zXo>#eF1^@s607*qoM6N<$f}m5%LjV8( literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/ADTGlobalEvents/WorldWar1/Objects/Weapons/Guns/Rifles/mosin.rsi/equipped-BACKPACK.png b/Resources/Textures/ADT/ADTGlobalEvents/WorldWar1/Objects/Weapons/Guns/Rifles/mosin.rsi/equipped-BACKPACK.png new file mode 100644 index 0000000000000000000000000000000000000000..d5bca755fb3084106dbcc7220aee0e420ed2b8f1 GIT binary patch literal 1180 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/ADTGlobalEvents/WorldWar1/Objects/Weapons/Guns/Rifles/mosin.rsi/meta.json b/Resources/Textures/ADT/ADTGlobalEvents/WorldWar1/Objects/Weapons/Guns/Rifles/mosin.rsi/meta.json new file mode 100644 index 00000000000..7db8a827350 --- /dev/null +++ b/Resources/Textures/ADT/ADTGlobalEvents/WorldWar1/Objects/Weapons/Guns/Rifles/mosin.rsi/meta.json @@ -0,0 +1,41 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Created by discord:prazat911", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "base" + }, + { + "name": "bolt-open" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "wielded-inhand-left", + "directions": 4 + }, + { + "name": "wielded-inhand-right", + "directions": 4 + }, + { + "name": "equipped-BACKPACK", + "directions": 4 + }, + { + "name": "equipped-SUITSTORAGE", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/ADT/ADTGlobalEvents/WorldWar1/Objects/Weapons/Guns/Rifles/mosin.rsi/wielded-inhand-left.png b/Resources/Textures/ADT/ADTGlobalEvents/WorldWar1/Objects/Weapons/Guns/Rifles/mosin.rsi/wielded-inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..2c3de531eaacaf5ce8153005f01209db2b6b07af GIT binary patch literal 973 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-HD>U~czxaSW-5 zdpql_pKzea@%)QzP1mM1c_}QLmE^LRvyO%LNb9AJA+N*R46+RL(+ANhM{*WbFr{F9ga z-#cG-dH-Cp`p?r__v(FDv!_?BNsnK>jkjN&ZO!wgkCTjk`p)rLe&q6Z(TQhMPTsqE zb!v;P;FGE_v5bU$(?k}Zl-es^e=XzOjg2aerW|r8VYvAs!||Q$ z33nys1)`VQN>%ON;Cx=gq2i{r1cOo_KVLMVs-@)iajpx#H@^IhWL)O%vAuQ; zsZx1@Mbl;&y8m4k*7BrkyXi7_`ERlT46mw>mTyjab1HPz&xO05Qgj#cV+e6l{3|4K5@q1=~I^5N5`sYN*(Hswt}le*TwR6w=xX3GUX zRq+oS*GpG8xCJoS&Ogs>QnFwr^MTYbKT6@Q)q-12$aI&nP9{_R|KB(Fv-~dnYdXQW#puG8Lbik`7pq);?FE;Q_*(aiBJPx&f=NU{RCr$PT1{&cVGw@P8uFnrY1-6MkyKN$6@+M^iouH~&-zQe_!m6-5BvcI z_2Qu?JxGfdKMIOgY|tPrQS)guNr@&hBNI0Jk$0244ZG~@WjDL;JM+vl&%8Oz_=LwV zpU2}DOaLpu;|y>Kcw7K{2yzK<33!|VE&-1Vfd2)!1coVrE17GZ=Nr#@$b)y~Vgb#4 z-1*R#Sp9x8d&A%wX3szh&<1%Sy@LJ{vom;qw6-P|QYm~6f7%l7C#J>ub`gK;pQEv8 zm#A|~%N_VptyB%`pL{>);)8WEVh^2w>$3p_3s?Q@syMm-($eROE8_OWu=rMMijCGOaWnoy+}$j63AlAS)Oql^F;K$n z5Yl5XecX>=;=u{rtIYreKXvr~`{=PryhCtLeao0}xJu17-nW0Y&@S2AY5B#HzlGl# z^NXe>0vQhN@8TL-Pj>7CVzq{nrpHF>dkBEVH&$mvxpaWvDFYOIw)m$n78QU;30Aw8 z0>8W%!PisqfLPxu^duGD8wh|6AVawBzx`!6=-}`J*;2jRJ@`}wX2%XFFExF{pw<_= zwf+Ra4z1K7@(_If^?z`28DGKovf5+WtQYG#0% zsL*r-K$%dvCk`th!!%O~12k%3P(t6P*EVor?I3M>DFIe917<*g0dPJj2$=#1!=1-_ zh!;k6;Ql3>#VHfn{(j%3o56X%nSo#^+-WxII5PlcFieJJ0T2cl*q{T?O42f0`tMQ# zV1w1n0L=@)no%<$15OxJ&k5NgK-OcIfmiWedk(0uM>cE`pwgk!Y%u{&%gDI#umZ-- qxYPWx0-TnSapPeHjGJ+%`TGYAj+9XAKF&J;0000uUxnA=ltH*=7-nk%k#+F*Q8W@d?Xq7^$CMo&7}Ep`&t;ucLK6T5M@n@7 literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Attachments/under.rsi/mosinbayonet_a.png b/Resources/Textures/ADT/Attachments/under.rsi/mosinbayonet_a.png new file mode 100644 index 0000000000000000000000000000000000000000..428cec765c3355104455ad0ab09e3e26fafdbfba GIT binary patch literal 182 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Objects/Weapons/Melee/mosin_bayonet.rsi/inhand-left.png b/Resources/Textures/ADT/Objects/Weapons/Melee/mosin_bayonet.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..b2fd137cf79ab4d3445730bc64930d23ea732a99 GIT binary patch literal 753 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-HD>U|Q|z;uumf z=k2VGrye;79RF{*F6hSrD~?T>*RSb)vuk|6z?G}EXZIne`A5_*ob%fv%Id4>*s*br z_PMV~exEZp{WLp%mOn^i_vZhSYP-GD7}^pg;ON=^LzgmpIxggxWp0gHdaG21eOvDR zI{)RtH8nLhGPhrrFf{PBGhccW6=oK`FMZb3zNIem{q8zq-TSBHn$4cxE6c~u;2_bq z>&x9h7ls16`I;O|E`cn^3-1+0Jhb3r2v{1l@sPolSt|?oy)=thebr$8`L$oGaw`ur zG6d|tTX*_csSS{Q$Y9Ccyyekph5~{y*I5}nG#MEdpPbPm@MM=BkS}OkdqqN#rB^MP zsljbABg6c2XS=@fa5OOlc>%3bWZ4sU|5F?DkA43qdENhhQkw6<*I(0$;=DQ)I7+-( z0}jY7Fk4-=L6!Xc`s8%iZ zSIkQV9$oIAQ8~~3o44bp6M-$C&%c?*r1|u)SHIrz$=e>iPIY}Px1eib*Ug+|m;cPQ zJzgl_Dmd$Gn%?ZF*G#MQUi_|G*7afak>A|ke%o%loxAfD)3)5lcY#7Gv$dz4PSvZ9 z%5J`zCF+scbHaJ|-D5dsyHBqPTkU!`PyEEhlTpkI78^d2Jo(qeM+#07jA;^iNFr4rDOis_|SEH74IxW6faYI<4MM0L) zW7*y)@6t&rj;{?R>?h^iZhO6JyO^Zxig$t!&d*iesdw0b=QG=WhUpU4H!Eu7%7AH@ N!PC{xWt~$(698h5R$c%A literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Objects/Weapons/Melee/mosin_bayonet.rsi/inhand-right.png b/Resources/Textures/ADT/Objects/Weapons/Melee/mosin_bayonet.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..6adba6750c8ca3fe50517412ac17c8c41703720f GIT binary patch literal 742 zcmVPx%ph-kQRCt{2nz2sfKomufS6d<^i_##4acj49rsr4KB1Q5UyG0846?#g#h_nd> zaT$$}CQ!~6SzC@1dvQE4tK}Ujk{#P`?zA<70cz4^?KbrHF^@qvFnn7F(&v^+y1ToUIQ*KF9GauJYqJR1zKyu zFm!U~!Z0ki&(F`9&*#N>&NwXZ4dL0X8NKuYUx?@rXRn_ddp3FE*uA*}PJUD2f1hetrhv>FKGrz@q81voiql zJZCIO7^2z?dA0N(<9BL?^u z;2SZ(w*cRW0lo$JMhx&Rz&B!mZvnm$1AGhcjTqotfN#VA-vWFi2KW}>8!^DQ0N=C* zB-*&Tx&pAP)ryCQ2Pff)HmYHbeaVkQIoN>pdTq7VyuQ8?$Fb7|&N{`~;oI9AVHjE* zrB$HEBcQcrHk$>VLkJz&7uNVNx&#q`avi=NLU0wNXbNlesq4&uBuP+8l`G0s6I>Zk zZN3;QNfM_99Q+6vV~CCDyZ`_I07*qoM6N<$f}HzQYybcN literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Objects/Weapons/Melee/mosin_bayonet.rsi/meta.json b/Resources/Textures/ADT/Objects/Weapons/Melee/mosin_bayonet.rsi/meta.json new file mode 100644 index 00000000000..01a363305a1 --- /dev/null +++ b/Resources/Textures/ADT/Objects/Weapons/Melee/mosin_bayonet.rsi/meta.json @@ -0,0 +1,26 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Created by discord:not_so_big_chungus", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "equipped-BELT", + "directions": 4 + } + ] +} From 7b031f4e2c4d20953c5c458480f71b03c08af8e4 Mon Sep 17 00:00:00 2001 From: Eugeny Date: Mon, 2 Dec 2024 00:20:22 +0400 Subject: [PATCH 18/46] =?UTF-8?q?=D0=BF=D1=80=D0=B8=D1=86=D0=B5=D0=BB?= =?UTF-8?q?=D1=8B=20=D0=B8=20=D0=B1=D0=B8=D0=BD=D0=BE=D0=BA=D0=BB=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Entities/Objects/Devices/binoculars.yml | 18 +++ .../Attachments/rail_attachment.yml | 127 ++++++++++++++++++ .../Objects/Weapons/Guns/Attachments/tags.yml | 9 ++ .../Objects/Weapons/Guns/Rifles/rifles.yml | 21 +++ .../Objects/Weapons/Guns/Snipers/snipers.yml | 21 +++ Resources/Prototypes/ADT/tags.yml | 3 - .../Objects/Weapons/Guns/Snipers/snipers.yml | 9 ++ .../Devices/binoculars.rsi/binoculars.png | Bin 0 -> 408 bytes .../Devices/binoculars.rsi/binoculars_civ.png | Bin 0 -> 615 bytes .../binoculars.rsi/binoculars_laser_civ.png | Bin 0 -> 187 bytes .../binoculars.rsi/binoculars_range_civ.png | Bin 0 -> 182 bytes .../Devices/binoculars.rsi/c_binoculars.png | Bin 0 -> 408 bytes .../Devices/binoculars.rsi/c_rangefinder.png | Bin 0 -> 487 bytes .../Devices/binoculars.rsi/d_binoculars.png | Bin 0 -> 410 bytes .../Devices/binoculars.rsi/d_designator_b.png | Bin 0 -> 388 bytes .../Devices/binoculars.rsi/d_designator_e.png | Bin 0 -> 388 bytes .../Devices/binoculars.rsi/d_designator_r.png | Bin 0 -> 390 bytes .../Devices/binoculars.rsi/d_rangefinder.png | Bin 0 -> 514 bytes .../Devices/binoculars.rsi/designator_b.png | Bin 0 -> 388 bytes .../Devices/binoculars.rsi/designator_e.png | Bin 0 -> 388 bytes .../Devices/binoculars.rsi/designator_r.png | Bin 0 -> 390 bytes .../Objects/Devices/binoculars.rsi/las_b.png | Bin 0 -> 337 bytes .../Objects/Devices/binoculars.rsi/las_r.png | Bin 0 -> 326 bytes .../Devices/binoculars.rsi/laser_cas.png | Bin 0 -> 218 bytes .../Devices/binoculars.rsi/laser_range.png | Bin 0 -> 214 bytes .../Devices/binoculars.rsi/laser_spotter.png | Bin 0 -> 207 bytes .../Devices/binoculars.rsi/laslock_b.png | Bin 0 -> 299 bytes .../Devices/binoculars.rsi/laslock_r.png | Bin 0 -> 280 bytes .../Objects/Devices/binoculars.rsi/meta.json | 124 +++++++++++++++++ .../Devices/binoculars.rsi/rangefinder.png | Bin 0 -> 507 bytes .../Devices/binoculars.rsi/s_binoculars.png | Bin 0 -> 403 bytes .../Devices/binoculars.rsi/s_rangefinder.png | Bin 0 -> 507 bytes .../binoculars.rsi/spotter_overlay.png | Bin 0 -> 226 bytes .../Devices/binoculars.rsi/u_binoculars.png | Bin 0 -> 406 bytes .../Devices/binoculars.rsi/u_rangefinder.png | Bin 0 -> 480 bytes 35 files changed, 329 insertions(+), 3 deletions(-) create mode 100644 Resources/Prototypes/ADT/Entities/Objects/Devices/binoculars.yml create mode 100644 Resources/Textures/ADT/Objects/Devices/binoculars.rsi/binoculars.png create mode 100644 Resources/Textures/ADT/Objects/Devices/binoculars.rsi/binoculars_civ.png create mode 100644 Resources/Textures/ADT/Objects/Devices/binoculars.rsi/binoculars_laser_civ.png create mode 100644 Resources/Textures/ADT/Objects/Devices/binoculars.rsi/binoculars_range_civ.png create mode 100644 Resources/Textures/ADT/Objects/Devices/binoculars.rsi/c_binoculars.png create mode 100644 Resources/Textures/ADT/Objects/Devices/binoculars.rsi/c_rangefinder.png create mode 100644 Resources/Textures/ADT/Objects/Devices/binoculars.rsi/d_binoculars.png create mode 100644 Resources/Textures/ADT/Objects/Devices/binoculars.rsi/d_designator_b.png create mode 100644 Resources/Textures/ADT/Objects/Devices/binoculars.rsi/d_designator_e.png create mode 100644 Resources/Textures/ADT/Objects/Devices/binoculars.rsi/d_designator_r.png create mode 100644 Resources/Textures/ADT/Objects/Devices/binoculars.rsi/d_rangefinder.png create mode 100644 Resources/Textures/ADT/Objects/Devices/binoculars.rsi/designator_b.png create mode 100644 Resources/Textures/ADT/Objects/Devices/binoculars.rsi/designator_e.png create mode 100644 Resources/Textures/ADT/Objects/Devices/binoculars.rsi/designator_r.png create mode 100644 Resources/Textures/ADT/Objects/Devices/binoculars.rsi/las_b.png create mode 100644 Resources/Textures/ADT/Objects/Devices/binoculars.rsi/las_r.png create mode 100644 Resources/Textures/ADT/Objects/Devices/binoculars.rsi/laser_cas.png create mode 100644 Resources/Textures/ADT/Objects/Devices/binoculars.rsi/laser_range.png create mode 100644 Resources/Textures/ADT/Objects/Devices/binoculars.rsi/laser_spotter.png create mode 100644 Resources/Textures/ADT/Objects/Devices/binoculars.rsi/laslock_b.png create mode 100644 Resources/Textures/ADT/Objects/Devices/binoculars.rsi/laslock_r.png create mode 100644 Resources/Textures/ADT/Objects/Devices/binoculars.rsi/meta.json create mode 100644 Resources/Textures/ADT/Objects/Devices/binoculars.rsi/rangefinder.png create mode 100644 Resources/Textures/ADT/Objects/Devices/binoculars.rsi/s_binoculars.png create mode 100644 Resources/Textures/ADT/Objects/Devices/binoculars.rsi/s_rangefinder.png create mode 100644 Resources/Textures/ADT/Objects/Devices/binoculars.rsi/spotter_overlay.png create mode 100644 Resources/Textures/ADT/Objects/Devices/binoculars.rsi/u_binoculars.png create mode 100644 Resources/Textures/ADT/Objects/Devices/binoculars.rsi/u_rangefinder.png diff --git a/Resources/Prototypes/ADT/Entities/Objects/Devices/binoculars.yml b/Resources/Prototypes/ADT/Entities/Objects/Devices/binoculars.yml new file mode 100644 index 00000000000..9d4d726449a --- /dev/null +++ b/Resources/Prototypes/ADT/Entities/Objects/Devices/binoculars.yml @@ -0,0 +1,18 @@ +- type: entity + name: binoculars + parent: BaseItem + id: ADTBinoculars + description: A military-issued pair of binoculars. + components: + - type: Item + size: Small + - type: Sprite + sprite: ADT/Objects/Devices/binoculars.rsi + state: binoculars + - type: Scope + useInHand: true + zoomLevels: + - zoom: 1.6 + offset: 14 + allowMovement: true + doAfter: 0 diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/rail_attachment.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/rail_attachment.yml index 8abb6699ea4..a8c3e5d9662 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/rail_attachment.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/rail_attachment.yml @@ -27,3 +27,130 @@ - type: AttachableWeaponRangedMods modifiers: - accuracyAddMult: -0.05 + +- type: entity + abstract: true + parent: [ ADTRailAttachmentBase, ADTAttachableToggleableBase ] + id: ADTAttachmentScopeBase + components: + - type: AttachableToggleable + needHand: true + heldOnlyActivate: true + userOnly: true + doInterrupt: true + attachedOnly: true + breakOnMove: true + breakOnRotate: true + wieldedOnly: true + useDelay: 0.5 + showTogglePopup: false + icon: + sprite: ADT/Objects/Attachments/scope_actions.rsi + state: sniperscope + actionName: Look through Scope + actionDesc: Scope in. If you're seeing this, someone forgot to set the description properly. + - type: AttachableToggleableSimpleActivate + - type: Scope + requireWielding: true + attachment: true + useInHand: true + zoomLevels: + - zoom: 1 + offset: 15 + allowMovement: false + doAfter: 0 + +- type: entity + parent: ADTAttachmentScopeBase + id: ADTAttachmentHristovScope + name: Hristov x6 scope + description: Hristov x6 scope + components: + - type: Sprite + sprite: ADT/Objects/Attachments/scope_actions.rsi + state: sniperscope + - type: Tag + tags: + - ADTAttachmentRail + - ADTAttachmentHristovScope + - type: AttachableVisuals + - type: AttachableToggleable + actionName: Look through the Hristov scope + actionDesc: An Hristov telescopic eye piece. Fixed at 6x zoom. + - type: AttachableToggleableSimpleActivate + - type: Scope + zoomLevels: + - zoom: 1.6 + offset: 14 + allowMovement: false + doAfter: 0 + - type: AttachableSpeedMods + modifiers: + - conditions: + wieldedOnly: true + walk: -0.23 + sprint: -0.35 + - type: AttachableWieldDelayMods + modifiers: + - delay: 0.4 + - type: AttachableWeaponRangedMods + modifiers: + - fireDelayFlat: 0.1 + - conditions: + activeOnly: true + fireDelayFlat: 0.25 + accuracyAddMult: 0.35 + damageFalloffAddMult: -0.4 + - conditions: + wieldedOnly: true + inactiveOnly: true + accuracyAddMult: -0.05 + +- type: entity + parent: ADTAttachmentScopeBase + id: ADTAttachmentXC67Miniscope + name: xC-67 scope + description: xC-67 scope + components: + - type: Sprite + sprite: ADT/Objects/Attachments/scope_actions.rsi + state: sniperscope + - type: Tag + tags: + - ADTAttachmentRail + - ADTAttachmentXC67Miniscope + # - type: AttachableVisuals + - type: AttachableToggleable + breakOnMove: false + actionName: Look through the xC-67 scope + actionDesc: An xC-67 telescoping eye piece. Fixed at a modest 2x zoom. + wieldedOnly: false + breakOnRotate: false + - type: AttachableToggleableSimpleActivate + - type: Scope + zoomLevels: + - zoom: 1.2 + offset: 12 + allowMovement: true + doAfter: 0 + requireWielding: false + - type: AttachableSpeedMods + modifiers: + - conditions: + activeOnly: true + walk: -0.31 + sprint: -0.448 + - type: AttachableWieldDelayMods + modifiers: + - delay: 0.4 + - type: AttachableWeaponRangedMods + modifiers: + - conditions: + activeOnly: true + fireDelayFlat: 0.15 + accuracyAddMult: 0.35 + damageFalloffAddMult: -0.2 + - conditions: + wieldedOnly: true + inactiveOnly: true + accuracyAddMult: -0.05 #TODO: Add flare gun modifiers when it's implemented. diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/tags.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/tags.yml index 289dae44fcc..38573d61a52 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/tags.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/tags.yml @@ -21,3 +21,12 @@ - type: Tag id: ADTAttachmentMagneticHarness + +- type: Tag + id: ADTAttachmentHristovScope + +- type: Tag + id: ADTMosinBayonetAttachment + +- type: Tag + id: ADTAttachmentXC67Miniscope diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Rifles/rifles.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Rifles/rifles.yml index 381b33ebd7d..edc712e76a3 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Rifles/rifles.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Rifles/rifles.yml @@ -208,3 +208,24 @@ steps: 1 zeroVisible: true - type: Appearance + - type: AttachableHolder + slots: + rmc-aslot-rail: + locked: true + startingAttachable: ADTAttachmentXC67Miniscope + whitelist: + tags: + - ADTAttachmentMagneticHarness + - ADTAttachmentXC67Miniscope + - type: ItemSizeChange + - type: ActivatableUI + verbText: rmc-verb-strip-attachables + verbOnly: true + key: + enum.AttachmentUI.StripKey + - type: UserInterface + interfaces: + enum.AttachmentUI.StripKey: + type: AttachmentStripBui + enum.AttachmentUI.ChooseSlotKey: + type: AttachmentChooseSlotBui diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Snipers/snipers.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Snipers/snipers.yml index 7e03dbeacc3..32bac904254 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Snipers/snipers.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Snipers/snipers.yml @@ -54,3 +54,24 @@ - type: Appearance - type: StaticPrice price: 5000 + - type: AttachableHolder + slots: + rmc-aslot-rail: + locked: true + startingAttachable: ADTAttachmentHristovScope + whitelist: + tags: + - ADTAttachmentMagneticHarness + - ADTAttachmentHristovScope + - type: ItemSizeChange + - type: ActivatableUI + verbText: rmc-verb-strip-attachables + verbOnly: true + key: + enum.AttachmentUI.StripKey + - type: UserInterface + interfaces: + enum.AttachmentUI.StripKey: + type: AttachmentStripBui + enum.AttachmentUI.ChooseSlotKey: + type: AttachmentChooseSlotBui diff --git a/Resources/Prototypes/ADT/tags.yml b/Resources/Prototypes/ADT/tags.yml index b9ff5559675..517c9166d2d 100644 --- a/Resources/Prototypes/ADT/tags.yml +++ b/Resources/Prototypes/ADT/tags.yml @@ -405,6 +405,3 @@ - type: Tag id: ADT40mmGrenade - -- type: Tag - id: ADTMosinBayonetAttachment diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml index 2e27501c748..8bf9c580094 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml @@ -85,6 +85,15 @@ - CartridgeAntiMateriel capacity: 5 proto: CartridgeAntiMateriel + - type: AttachableHolder + slots: + rmc-aslot-rail: + locked: true + startingAttachable: ADTAttachmentHristovScope + whitelist: + tags: + - ADTAttachmentMagneticHarness + - ADTAttachmentHristovScope - type: entity name: musket diff --git a/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/binoculars.png b/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/binoculars.png new file mode 100644 index 0000000000000000000000000000000000000000..7fc7f7f9c800de4a7922b0dfbfb63badc5e7e4ed GIT binary patch literal 408 zcmV;J0cZY+P)c9 z$N<3HtQ1+f{D3l_&p(gj%E3Uy0&w$YtIDt{J>|V99zwbXmWvO;BziqgQUJZ~yZ;Oj z^IQ3CogBcnzNBJufX1`Q2K|{I$E}kC1m71ElLJH<$QnxnsH(#LLMQ+ztnp|nwK29B zQ2R|CKsd+qjgIxq-n#b>!-QCUVzbKNu933<0000~Qbf=Y7~grBc}DPKVn%G{H1FfyH}^O1 z-FriLWd#5MKmZT`1OT1^bX~Xa+qW!Bd(7q=z)WTy?*~UPIXi}QY7XmbTljTxirrjR z*}i;TfU#f1;qMb=^9_K?Zfqb?dxL7ZgdaP57)~dZZEJf6E!)DMqXU$U8e*S5dithk z0P#24(7?FejEtgWUZHW>kb9jr?nBstnzH!@@KW*&(4YBcx5Stn(2)IW-+QoP^3mxD+?YH{&1Vu_^cj8rc7(>ZbL*E2w-a3TEk>l)xC6#%?Czzy$2<&ZL1eck{7002ovPDHLkV1fnR BAJ+f? literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/binoculars_laser_civ.png b/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/binoculars_laser_civ.png new file mode 100644 index 0000000000000000000000000000000000000000..569325e4ab0355a0669abd0f0661ac20fec41281 GIT binary patch literal 187 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5D46T% z;uumf=k3LdoDBv%t`|A_9+`$?Lf)yLIb;%HcqRx$Wl0 znR~q%fZ24`!xqgc8i3X1DlbheZlJrvV*t&YMKck8h-+ZPOb`0{1 W1BBg61wS@|jPZ2!b6Mw<&;$TQhdBQL literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/binoculars_range_civ.png b/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/binoculars_range_civ.png new file mode 100644 index 0000000000000000000000000000000000000000..fc03bc8070e5453de4b4fff18b2989f92bef820d GIT binary patch literal 182 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5D45~t z;uumf=k4W#oDBv%tq;o!7V9bMU7E~XDp=V0ZplG0o8=c4{COW#R3)z%D=l?I_dxb literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/c_binoculars.png b/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/c_binoculars.png new file mode 100644 index 0000000000000000000000000000000000000000..16b9d7121654e1cce757e4f37c79c4a449f445bd GIT binary patch literal 408 zcmV;J0cZY+P)k~nv2v+(6(LpD~;3YFUARhUfOm^7)zug^%eO7l?3XlRk4nQtve9pq# z?fgj$0L)AEvMT8}lKIqItLaer6o^CsG;cKBmQfPd#%- z-r-*(KwM4?00ai_#z3fl2Yqr*3;=cq2Kc4sZU%rmKDArioxaeD&vN0Sycqxs?6r_T zg9i=E<1@js&I2!Z@qS$ouEkA=^;r4FL07P3QUpR(CIk)nTp|}nIajy&kSR6cltPG*D z=_(OG-W3AOFD``}wO#9_{SbcrwiqDEW&{uy0&LngrdH?vPTQ6V0ADeD&Ez%g4gq-7 zwPgZe2()CR;=2X&?ku?tt8BW>NGkyR4LSaYf2WgedjY!u~R?W_> dxB&RK0H1V2(|~z;^XC8n002ovPDHLkV1hY*&)on3 literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/d_binoculars.png b/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/d_binoculars.png new file mode 100644 index 0000000000000000000000000000000000000000..203735f581e6a6614a34360636bcc9b59b3f0dc5 GIT binary patch literal 410 zcmV;L0cHM)P)CH=YOg1Dz&1^CvO5V#3JFxGwyTdRK?8=G(Vu0HLc*;no$ib`4 zUxEw(%&Tt&_EOBE%)cgU#`LL)fd~ZP=IvIEVO1&TtN;NaTm#=fbFWFjevpI!)b7~% z28j8qoZ2S`FpP~*Ob*a&ys}>Z(}{!j$pPH|i;2kr&KZar3j?H661#*@08m&1O&2;C zTZ||GD6B9~+)*_e05FF}b7--){B7Bvvw(>JxVisXImEFXR_G!GgYDzw=)&T0Cx+p18CK?INgih-2eap07*qoM6N<$ Ef+^{#b^rhX literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/d_designator_b.png b/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/d_designator_b.png new file mode 100644 index 0000000000000000000000000000000000000000..1ff805589e2bea296bfafeb233cb3ab484df44e4 GIT binary patch literal 388 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv(mfq~J? z)5S5QVoq|RM1sMqhCucntAs0zi}@r<89ezOJb(VbU+>$;$L?-1k3z~DwoKx3_DB+G zUbv6(@Xu~>iEC%#kA3*~Cvpx@l7ZvQ`*{Zr1Vk|`t8_iW(G`4^@%p*>sZ*v-{agS3 zT&%(W&$GjM6zn?K7-v}c%q`DRIehKtX-PTzx*lUIk0OQ>0ldY<2G)Wvq5~!zX3%)y z$k%Y{e|sxa$28VYg_cbj>E`Z{LGK#;=i3?1*tx6ern%odmdhJ-I`zu3zUQ^QK7ZfXBGb#r=Klxg^*fie z9=Q9v;JCu)!p^t5|IJx2)5V%0Wao#ym8|PZ5(>Gr8804ncw>4rPNPb*jDh2UcF;-I f!{#9CBN!OWt@`HdY~Wc33|0nDS3j3^P6VQ!Pj5=V{0izBWbpS~Y;OFQ6k1qD{<3~nZ z;#7Blw2}%#NMaO&p}qmb`HL4A*34hV@bUavoZ?h>00_+Qp1{CRS^%bbMZ^e-Q`G_2 z&YxwJm6iQ}@6KH?|MQzy3?M#;1_78jOr3XZB*WIl%NZU&evC6ZNOAzkPz`f)Fgp?G zTTqb004V4|4uH!4hlK)&mId;0If7^hfGj5^Xo&?wD;thFfE4ib-W`VJQ}2M;e0+S= zaRA6r5GDo)%gDpoZ=XD*+yS3HePS?kbp^9;oIDApVObJg?9}ev47^+%3=i%}Tw)4}3SjyzH5>q{T=?F+0#`b)IE9sf=wcxDgIhOI^iu2q5WrWY ik_(1!HXL;Tu>b&oUyGPl;XoAt0000$;$L?-1k3z~DwoKx3_DB+G zUbv6(@Xu~>iEC%#kA3*~Cvpx@l7ZvQ`*{Zr1Vk|`t8_iW(G`4^@%p*>sZ*v-{agS3 zT&%(W&$GjM6zn?K7-v}c%q`DRIehKtX-PTzx*lUIk0OQ>0ldY<2G)Wvq5~!zX3%)y z$k%Y{e|sxa$28VYg_cbj>HjwywA59fENG6FSif^g z>w&w!3yv#%F6>K5vuNsM0KB;CP@N ibdvS3ImiJK3=9YF^cKhD-Jb&tSO!m5KbLh*2~7a!52MTg literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/d_rangefinder.png b/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/d_rangefinder.png new file mode 100644 index 0000000000000000000000000000000000000000..2ffe3abe1c417adc732cc7be747923df0fc45db8 GIT binary patch literal 514 zcmV+d0{#7oP)cRjGQYu7MxvEqM3>9+;xsVI4NmD0Ig^KcD;@H;R&v%!L=irZ(1LOeH z1F%xi-6V!zoc>H^0O)*Ydkv0{_G9-|Yj$;$L?-1k3z~DwoKx3_DB+G zUbv6(@Xu~>iEC%#kA3*~Cvpx@l7ZvQ`*{Zr1Vk|`t8_iW(G`4^@%p*>sZ*v-{agS3 zT&%(W&$GjM6zn?K7-v}c%q`DRIehKtX-PTzx*lUIk0OQ>0ldY<2G)Wvq5~!zX3%)y z$k%Y{e|sxa$28VYg_cbj>E`Z{LGK#;=i3?1*tx6ern%odmdhJ-I`zu3zUQ^QK7ZfXBGb#r=Klxg^*fie z9=Q9v;JCu)!p^t5|IJx2)5V%0Wao#ym8|PZ5(>Gr8804ncw>4rPNPb*jDh2UcF;-I f!{#9CBN!OWt@`HdY~Wc33|0nDS3j3^P6VQ!Pj5=V{0izBWbpS~Y;OFQ6k1qD{<3~nZ z;#7Blw2}%#NMaO&p}qmb`HL4A*34hV@bUavoZ?h>00_+Qp1{CRS^%bbMZ^e-Q`G_2 z&YxwJm6iQ}@6KH?|MQzy3?M#;1_78jOr3XZB*WIl%NZU&evC6ZNOAzkPz`f)Fgp?G zTTqb004V4|4uH!4hlK)&mId;0If7^hfGj5^Xo&?wD;thFfE4ib-W`VJQ}2M;e0+S= zaRA6r5GDo)%gDpoZ=XD*+yS3HePS?kbp^9;oIDApVObJg?9}ev47^+%3=i%}Tw)4}3SjyzH5>q{T=?F+0#`b)IE9sf=wcxDgIhOI^iu2q5WrWY ik_(1!HXL;Tu>b&oUyGPl;XoAt0000$;$L?-1k3z~DwoKx3_DB+G zUbv6(@Xu~>iEC%#kA3*~Cvpx@l7ZvQ`*{Zr1Vk|`t8_iW(G`4^@%p*>sZ*v-{agS3 zT&%(W&$GjM6zn?K7-v}c%q`DRIehKtX-PTzx*lUIk0OQ>0ldY<2G)Wvq5~!zX3%)y z$k%Y{e|sxa$28VYg_cbj>HjwywA59fENG6FSif^g z>w&w!3yv#%F6>K5vuNsM0KB;CP@N ibdvS3ImiJK3=9YF^cKhD-Jb&tSO!m5KbLh*2~7a!52MTg literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/las_b.png b/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/las_b.png new file mode 100644 index 0000000000000000000000000000000000000000..749a47c1bde6e9240f7b3e77612c8083f00b0b3a GIT binary patch literal 337 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|O(o zr;B4q#hkY{H}W1b5NUbnyy(2un#Kib7Fhz>DRX@os)Ax%H0Pw7KYRC2P4mu=?xzu- zBp*pKKv5u*&-wSd^G-khvaWY2bAP zxHz$Mx(1_BDPv06?Z9ld6YsVyzP6RgX!qL{rpzhjw*y~CGuGRDob;bb;5-9il+S*k z;OX2<<^x4Qayyg6x;@6Z3=u%`ZFs|pBi{eG9c-Av$g1H@;5@DcPc{5m1ycJzg)r#4 pS86qAR8LvXd?JmZL!JKv^EKP>wNXox4gkZ5!PC{xWt~$(69Dx5fcF3Z literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/las_r.png b/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/las_r.png new file mode 100644 index 0000000000000000000000000000000000000000..8e93d3cd1e89f13da3cabc00257f35206822dfd9 GIT binary patch literal 326 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAQ1FMR zi(^Q|oVPa}`3@;axI8rc*jB~H|5Wlz&#U=UTracA-gt0k&ygFf())zG4v9WvWq=}2 zrkaN6zwr&_`D(Sr3C57~_um&5t&wrq`?2ct+nwfdd<(3MKTcC&xGci3 z`S!Y71`NA_DevJ0XsjXS*>Ac z)y`ig+i+^C`Q=2`9X@-eu4g#I4Mvlh6Z$^|F(|uNYBqG)p7Lhwk$Jk5LF=1_KKlVN eh8gMnA6U=$YZX?UxEu=%0|rl5KbLh*2~7a7YIlSH literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/laser_cas.png b/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/laser_cas.png new file mode 100644 index 0000000000000000000000000000000000000000..cfe7dcd96e8decc14fa34d9e92c3759cd2ed9d12 GIT binary patch literal 218 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DA?oa z;uumf=k4XQoDB*R?H{-I^GYprTcO!x_VSwLisJ2NFE5Dn2IvY@e3+N|fPqWj^W%4= zrcZxZdQW}^>IQ={huO=+_vbW<9}xEcc9`=ZTY$^W6_2M*Fqv8Ev1K1yMUvNvp!nS@ zTV-+{tzl@M;lD`f(&o34-`rO`o_qS=|5|5=DR%5T7_$xJU*3p16AlvbboFyt=akR{ E01?ekhyVZp literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/laser_range.png b/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/laser_range.png new file mode 100644 index 0000000000000000000000000000000000000000..b902edac18521c1354ddbbb7fae73410ba525360 GIT binary patch literal 214 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DA?iY z;uumf=k4WdnOQaNUi?0!0jqv(n8!ty=P-eV&!|e)b0j`5}j| zp6K}JxkKlH+lObrGI!WKaN;q1{NLIcVuBsJ1>>z(s`?KkwB0}=p00i_>zopr0Fk;% AP5=M^ literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/laser_spotter.png b/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/laser_spotter.png new file mode 100644 index 0000000000000000000000000000000000000000..ce2fd93faa68f3ee2aa464b2dd9505b4d7cf6ed2 GIT binary patch literal 207 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DA?%f z;uumf=k4WV`Q+S;^7_W6^DS20heKNYPXB8F4yhFl$cCNYd`FrYm rTonp?9zSZ37X0+TKAi)s`@nMsb&)QG89_CMGeH8Lu6{1-oD!MtOJi~2{)*%b@8rg2}N`F3IK9Rffw9Dhha)BpV9Y6rjun&z?Q}xpV6IpM_Ny9lL+-W?pmn_}5=`B`sl}SMOu|{3UHi%*&PE zcy=>Sd9?IT+1Z2Jem;G;`wz=D=L><|KmTzHoMUJ)W_ZZsV8M)&X==V(p5gJQs$G}s z4&;A}xW`w1n?Hi@Qlb5Vqi^=#=U*}ReI2F=@3_S)Bkum_T~Y${D1)b~pUXO@geCy9 C#CY@o literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/laslock_r.png b/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/laslock_r.png new file mode 100644 index 0000000000000000000000000000000000000000..55853498f284f7362723f088e976d3359448475b GIT binary patch literal 280 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAQ1Fze zi(^Q|oVT|wayB~%us!5la(GFb_9-c!-cI&7=6er?{{3|L;u^+wbb77OIffQvhKD>3 z7R&-rra|#%@wmT#8u(em&g_?YAhU1&_4m7#*UYm2%9eBd;tJE>Jky!KJlgwb$FsEL zy2USqCHNf|ihlmf4bzWg6b94Se78KqZ@0U32Mnw8Mc%QOO#RKMo%a84-GMhX-mdKI;Vst097Ss!vFvP literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/meta.json b/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/meta.json new file mode 100644 index 00000000000..b27d1219afa --- /dev/null +++ b/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/meta.json @@ -0,0 +1,124 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from cmss13 at https://github.com/cmss13-devs/cmss13/blob/c67c5213507a19e10e252ef2898d94354c0709bf/icons/obj/items/binoculars.dmi", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "binoculars_civ" + }, + { + "name": "binoculars_laser_civ" + }, + { + "name": "binoculars_range_civ" + }, + { + "name": "designator_b" + }, + { + "name": "designator_r" + }, + { + "name": "designator_e" + }, + { + "name": "d_designator_b" + }, + { + "name": "d_designator_r" + }, + { + "name": "d_designator_e" + }, + { + "name": "las_r", + "delays": [ + [ + 0.2, + 0.2, + 0.2, + 0.2 + ] + ] + }, + { + "name": "las_b", + "delays": [ + [ + 0.2, + 0.2, + 0.2, + 0.2 + ] + ] + }, + { + "name": "laslock_r", + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + }, + { + "name": "laslock_b", + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + }, + { + "name": "binoculars" + }, + { + "name": "s_binoculars" + }, + { + "name": "d_binoculars" + }, + { + "name": "u_binoculars" + }, + { + "name": "c_binoculars" + }, + { + "name": "rangefinder" + }, + { + "name": "s_rangefinder" + }, + { + "name": "d_rangefinder" + }, + { + "name": "u_rangefinder" + }, + { + "name": "c_rangefinder" + }, + { + "name": "laser_cas" + }, + { + "name": "laser_range" + }, + { + "name": "laser_spotter" + }, + { + "name": "spotter_overlay" + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/rangefinder.png b/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/rangefinder.png new file mode 100644 index 0000000000000000000000000000000000000000..f15d1d8820c34fdc4eb0ad53f8c442e5a2150ee4 GIT binary patch literal 507 zcmVQ!=St)LAeVgp4z_zL1tPd<#`QSbo- zU!r)>lZYM_FCMfO5)YxY7OeIXyj$}n*|^!J$>vXyO212Xcb1vo&Q2zoqd(RZUWrBh-6c2YKu%SE~0D+c_t6(jdosMtAzRk``!JErABdIH31;#fQF@R{x xr4K;f55)leAgOZsBa(HLR+IBrJO%i-06*?1$kM&|3n%~p002ovPDHLkV1kX3;pPAU literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/s_binoculars.png b/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/s_binoculars.png new file mode 100644 index 0000000000000000000000000000000000000000..f2ada91f70926acff08cef8f9c668ddc1bc782fa GIT binary patch literal 403 zcmV;E0c`$>P)ENCi;l-Cm!#vh6kv9b!Rf*MR5EBNNVinzR6h&LFx5#OhS8 z&5Hx9*DI}99N_z>L+*4E#cA{60P*|f#Nq(A40MgP0Zh}RXNU!W!gAfI*23IkWC5VC z?m6P|$dLhnIT{UGtWvTqCv*5m3_zJDk5xfj%5lXmLKy6dUz>{EwpQMJbNIFtz^$AZ z00e_-sf5t_pUv1gF#zli1{m{)k(+xM0C#+9x5wSV;6f`t%f*ZGVE|QN<#Oc=Dz0Qs xtPh+X6rt~LNmn8-BJM)>>V00t8NkN^>;V`ex;wlOgG>Mb002ovPDHLkV1j#MtCj!& literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/s_rangefinder.png b/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/s_rangefinder.png new file mode 100644 index 0000000000000000000000000000000000000000..5593796c1c273efd01ee920d7144be0ce5bb0f84 GIT binary patch literal 507 zcmVy0LqlE^HxR*Ag%BmXPkOnIRKj9+}^>(`Ptm~!Ql~@gXiRWX#glq(|(Py z`@ZxV@H{Vde33C8KlWD|fK}RR@WPr1j~+Ce8_?-&$pc(pT_%A|bC4N`PKM(^WR4)x z0N;V8QL%~aH~Wlb>G1T}mjl48FcS=n&4=Av%9zB@;eVt7NMz2RdxA)t6ICVvn-v-~ zTH0(=HXjXucg9pPH`tM!Z8;D z;9CseX6zVdhX%L;yl9M`kp>_LY{|G4aSKkeW7{yb=Xg~VyccaoLR&xu#x@t;fS(gB x%3Of>gCf9wP*jzC5s3yWtJV1`t^xinz!ze$(RZTAJD>mn002ovPDHLkV1ix+-LL=v literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/spotter_overlay.png b/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/spotter_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..748fdd65eaa46f2806a69e109a40915eeb267c61 GIT binary patch literal 226 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5C^*H_ z#WAE}&f5z+c^eFPSTDFF@k#Y@N;I}{&QN6)Wu2_x;^=#r!{@-o4ITonOC~Vstn+xW zd()aDb=wZ>umkmf(090g&4|awtjD-}@)Ucnh-GoB?tE3wyLM{T&As|XimqXElsp>N z&a{kqYUOl4>VL6x0^hPLnz!dOU6EXQcHI%h2WJne91v#&8U+CfvKyGTIBA?N=0C&% O67h8Pb6Mw<&;$VZrAv?i literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/u_binoculars.png b/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/u_binoculars.png new file mode 100644 index 0000000000000000000000000000000000000000..cf5561ef5c55db0fdf61115c8483e5a7a176227e GIT binary patch literal 406 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv(mfq~J( z)5S5QVoq|RM1sMqhCp^6S@sW~Pybav`k-H4-Z1Daqrz!b6<3KE*`|(7HQyUc6<*mJ z_9?tz2-0O|oDh{H>sTbUqvo~DjBBCBN?vmW6izZK#Cv*Z9=N$7;Gn8sDSOTDKYb66 z8neuvU~yG;!IHcq1@E6(T7Y>CGW(BgSow~jMr=Zs;Yq#=S1&4`Ovo@>(#Pz;nSFB? ztBPgAjUygYfV}QG3i}Ga@s!FiY?2ANu&3f1gC5)I?*zopr0ALfD-T(jq literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/u_rangefinder.png b/Resources/Textures/ADT/Objects/Devices/binoculars.rsi/u_rangefinder.png new file mode 100644 index 0000000000000000000000000000000000000000..d632e837fff7f90b0f5affdc3fc7ddc692f18d07 GIT binary patch literal 480 zcmV<60U!Q}P)VQ!P3>^pX^UM7w#o&)0A2CwR0U*mIBt;lp z9fI(x+kIdigM^d z?=(*Xm#6x=XJV3Q*j;B^49uRsLR6vVhnD1ne zi(zbX#1=+GMFFe=LM~j;EkKu}N;v=mkf@OR4=N8x1ypGf5o-{+VCb}pM;$P19RL7r WW7=1vi&7E*0000 Date: Mon, 2 Dec 2024 04:04:21 +0200 Subject: [PATCH 19/46] holster fix --- .../Inventory/CMHolsterVisualizerSystem.cs | 32 ++++++++++++++++ .../ADT/_RMC14/Inventory/CMInventorySystem.cs | 37 +++++++++++++++++++ .../ADT/_RMC14/Inventory/CMInventorySystem.cs | 5 +++ .../Inventory/SharedCMInventorySystem.cs | 16 ++++---- 4 files changed, 82 insertions(+), 8 deletions(-) create mode 100644 Content.Client/ADT/_RMC14/Inventory/CMHolsterVisualizerSystem.cs create mode 100644 Content.Client/ADT/_RMC14/Inventory/CMInventorySystem.cs create mode 100644 Content.Server/ADT/_RMC14/Inventory/CMInventorySystem.cs diff --git a/Content.Client/ADT/_RMC14/Inventory/CMHolsterVisualizerSystem.cs b/Content.Client/ADT/_RMC14/Inventory/CMHolsterVisualizerSystem.cs new file mode 100644 index 00000000000..3fd709ae338 --- /dev/null +++ b/Content.Client/ADT/_RMC14/Inventory/CMHolsterVisualizerSystem.cs @@ -0,0 +1,32 @@ +using Content.Shared._RMC14.Inventory; +using Robust.Client.GameObjects; + +namespace Content.Client._RMC14.Inventory; + +/// +/// Sets the gun underlay of holsters +/// +public sealed class CMHolsterVisualizerSystem : VisualizerSystem +{ + + protected override void OnAppearanceChange(EntityUid uid, + CMHolsterComponent component, + ref AppearanceChangeEvent args) + { + if (args.Sprite is not { } sprite || + !sprite.LayerMapTryGet(CMHolsterLayers.Fill, out var layer)) + return; + + if (component.Contents.Count != 0) + { + // TODO: implement per-gun underlay here + // sprite.LayerSetState(layer, $"{}"); + sprite.LayerSetVisible(layer, true); + + // TODO: account for the gunslinger belt + return; + } + + sprite.LayerSetVisible(layer, false); + } +} diff --git a/Content.Client/ADT/_RMC14/Inventory/CMInventorySystem.cs b/Content.Client/ADT/_RMC14/Inventory/CMInventorySystem.cs new file mode 100644 index 00000000000..46a434b3fbe --- /dev/null +++ b/Content.Client/ADT/_RMC14/Inventory/CMInventorySystem.cs @@ -0,0 +1,37 @@ +using Content.Shared._RMC14.Inventory; +using Content.Shared.Containers.ItemSlots; +using Robust.Client.GameObjects; + +namespace Content.Client._RMC14.Inventory; + +public sealed class CMInventorySystem : SharedCMInventorySystem +{ + protected override void ContentsUpdated(Entity ent) + { + base.ContentsUpdated(ent); + + if (!TryComp(ent, out SpriteComponent? sprite) || + !sprite.LayerMapTryGet(CMItemSlotsLayers.Fill, out var layer)) + { + return; + } + + if (!TryComp(ent, out ItemSlotsComponent? itemSlots)) + { + sprite.LayerSetVisible(layer, false); + return; + } + + foreach (var (_, slot) in itemSlots.Slots) + { + if (slot.ContainerSlot?.ContainedEntity is { } contained && + !TerminatingOrDeleted(contained)) + { + sprite.LayerSetVisible(layer, true); + return; + } + } + + sprite.LayerSetVisible(layer, false); + } +} diff --git a/Content.Server/ADT/_RMC14/Inventory/CMInventorySystem.cs b/Content.Server/ADT/_RMC14/Inventory/CMInventorySystem.cs new file mode 100644 index 00000000000..c8ffb1ba4fc --- /dev/null +++ b/Content.Server/ADT/_RMC14/Inventory/CMInventorySystem.cs @@ -0,0 +1,5 @@ +using Content.Shared._RMC14.Inventory; + +namespace Content.Server._RMC14.Inventory; + +public sealed class CMInventorySystem : SharedCMInventorySystem; diff --git a/Content.Shared/ADT/_RMC14/Inventory/SharedCMInventorySystem.cs b/Content.Shared/ADT/_RMC14/Inventory/SharedCMInventorySystem.cs index bd9720a644b..c736c8725aa 100644 --- a/Content.Shared/ADT/_RMC14/Inventory/SharedCMInventorySystem.cs +++ b/Content.Shared/ADT/_RMC14/Inventory/SharedCMInventorySystem.cs @@ -322,7 +322,7 @@ private bool PickupSlot(EntityUid user, EntityUid holster) if (_itemSlots.TryEjectToHands(holster, slot, user, true)) { if (item != null) - //_adminLog.Add(LogType.RMCHolster, $"{ToPrettyString(user)} unholstered {ToPrettyString(item)}"); + _adminLog.Add(LogType.Action, $"{ToPrettyString(user)} unholstered {ToPrettyString(item)}"); return true; } @@ -414,7 +414,7 @@ private void Holster(EntityUid user, EntityUid item) if (slot.ItemSlot != null && _itemSlots.TryInsert(slot.Ent, slot.ItemSlot, item, user, excludeUserAudio: true)) { - //_adminLog.Add(LogType.RMCHolster, $"{ToPrettyString(user)} holstered {ToPrettyString(item)}"); + _adminLog.Add(LogType.Action, $"{ToPrettyString(user)} holstered {ToPrettyString(item)}"); return; } @@ -422,13 +422,13 @@ private void Holster(EntityUid user, EntityUid item) if (slot.ItemSlot == null && TryComp(slot.Ent, out StorageComponent? storage) && TryComp(slot.Ent, out CMHolsterComponent? holster) && - !holster.Contents.Contains(item)) + !holster.Contents.Contains(item) && + _hands.TryDrop(user, item) && + _storage.Insert(slot.Ent, item, out _, user, storage, playSound: false)) { holster.Contents.Add(item); - _hands.TryDrop(user, item); - _storage.Insert(slot.Ent, item, out _, user, storage, playSound: false); _audio.PlayPredicted(holster.InsertSound, item, user); - //_adminLog.Add(LogType.RMCHolster, $"{ToPrettyString(user)} holstered {ToPrettyString(item)}"); + _adminLog.Add(LogType.Action, $"{ToPrettyString(user)} holstered {ToPrettyString(item)}"); return; } } @@ -602,7 +602,7 @@ private bool Unholster(EntityUid user, EntityUid item, out bool stop) if (PickupSlot(user, item)) { - //_adminLog.Add(LogType.RMCHolster, $"{ToPrettyString(user)} unholstered {ToPrettyString(item)}"); + _adminLog.Add(LogType.Action, $"{ToPrettyString(user)} unholstered {ToPrettyString(item)}"); return true; } } @@ -613,7 +613,7 @@ private bool Unholster(EntityUid user, EntityUid item, out bool stop) if (!ev.Unholsterable) return false; - //_adminLog.Add(LogType.RMCHolster, $"{ToPrettyString(user)} unholstered {ToPrettyString(item)}"); + _adminLog.Add(LogType.Action, $"{ToPrettyString(user)} unholstered {ToPrettyString(item)}"); return _hands.TryPickup(user, item); } From 0fa98ea8d5beead9d31ab4ed244e914b1831151f Mon Sep 17 00:00:00 2001 From: Eugeny Date: Mon, 2 Dec 2024 11:17:52 +0400 Subject: [PATCH 20/46] =?UTF-8?q?=D0=BB=D0=BE=D0=BA=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=B0=D1=86=D0=B8=D0=B8,=20=D1=87=D0=B0=D1=81=D1=82?= =?UTF-8?q?=D1=8C=201?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru-RU/ADT/escape-menu/ui/options-menu.ftl | 13 +++++++++++++ .../Entities/Objects/Device/binocular.ftl | 3 +++ .../Objects/Weapons/Guns/Attachments.ftl | 19 +++++++++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 Resources/Locale/ru-RU/ADT/escape-menu/ui/options-menu.ftl create mode 100644 Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Device/binocular.ftl create mode 100644 Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Guns/Attachments.ftl diff --git a/Resources/Locale/ru-RU/ADT/escape-menu/ui/options-menu.ftl b/Resources/Locale/ru-RU/ADT/escape-menu/ui/options-menu.ftl new file mode 100644 index 00000000000..fcb19b61de5 --- /dev/null +++ b/Resources/Locale/ru-RU/ADT/escape-menu/ui/options-menu.ftl @@ -0,0 +1,13 @@ +## Кнопки работы с модулями +ui-options-header-rmc = Оружейные модули +ui-options-function-rmc-activate-attachable-barrel = Активировать модуль ствола +ui-options-function-rmc-activate-attachable-rail = Активировать модуль верхней планки +ui-options-function-rmc-activate-attachable-stock = Активировать модуль приклада +ui-options-function-rmc-activate-attachable-underbarrel = Активировать подствольный модуль +ui-options-function-rmc-field-strip-held-item = Осмотр оружейных модулей +ui-options-function-rmc-cycle-fire-mode = Циклический режим огня +ui-options-function-cm-unique-action = Передернуть затвор +ui-options-function-cm-holster-primary = Вытащить из кобуры оружие +ui-options-function-cm-holster-secondary = Вытащить из кобуры, второе оружие +ui-options-function-cm-holster-tertiary = Вытащить из кобуры, третье оружие +ui-options-function-cm-holster-quaternary = Вытащить из кобуры, четвертое оружие diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Device/binocular.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Device/binocular.ftl new file mode 100644 index 00000000000..028f5985262 --- /dev/null +++ b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Device/binocular.ftl @@ -0,0 +1,3 @@ +ent-ADTBinoculars = бинокль +.desc = Позволяет разглядеть получше противника вдали. Или ту пару вульп в соседнем здании. +.suffix = { "ОСЩ" } diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Guns/Attachments.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Guns/Attachments.ftl new file mode 100644 index 00000000000..63dc05a347a --- /dev/null +++ b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Guns/Attachments.ftl @@ -0,0 +1,19 @@ +ent-ADTAttachmentMagneticHarness = магнитный ремень +.desc = Комплект из ремня и магнитных креплений, которые крепятся к верхней планке. В случае потери бойцом равновесия - оружие не падает на землю и остается с владельцем. +.suffix = { "Оруж. модуль, Верхняя планка" } + +ent-ADTAttachmentHristovScope = прицел Христова +.desc = Штатный прицел для снайперской винтовки "Христов", с шестикратным увеличением. +.suffix = { "Оруж. модуль, Прицел" } + +ent-ADTAttachmentXC67Miniscope = прицел хС-67 +.desc = Штатный прицел для штурмовой винтовки хС-67, с двухкратным увеличением. +.suffix = { "Оруж. модуль, Прицел" } + +ent-ADTAttachmentM90GrenadeLauncher = подствольный гранатомёт GL90 +.desc = Один из наиболее распространенных подствольных гранатомётов, изначально разработанный для карабина M-90gl. Заряжается 40-мм выстрелами. +.suffix = { "Оруж. модуль, Подствольный" } + +ent-ADTAttachmentM90UnderbarrelShotgun = подствольный дробовик US90 +.desc = Трехзарядный подствольный дробовик, сделанный изначально для карабина М-90gl. Прекрасно подходит для вышибания дверей или мозгов зомби. +.suffix = { "Оруж. модуль, Подствольный" } From ac3d7af885b3b357eb495c2d49694f0ccc275172 Mon Sep 17 00:00:00 2001 From: Inconnu1337 Date: Tue, 3 Dec 2024 02:57:12 +0200 Subject: [PATCH 21/46] =?UTF-8?q?=D0=B4=D0=B0=20=D0=BD=D0=B0=D1=85=D1=83?= =?UTF-8?q?=D0=B9=20=D0=B8=D0=B4=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Weapons/Melee/survival_knife.rsi/icon_a.png | Bin 0 -> 281 bytes .../Weapons/Melee/survival_knife.rsi/meta.json | 3 +++ 2 files changed, 3 insertions(+) create mode 100644 Resources/Textures/Objects/Weapons/Melee/survival_knife.rsi/icon_a.png diff --git a/Resources/Textures/Objects/Weapons/Melee/survival_knife.rsi/icon_a.png b/Resources/Textures/Objects/Weapons/Melee/survival_knife.rsi/icon_a.png new file mode 100644 index 0000000000000000000000000000000000000000..28f96dcc283cc9e4874ad46afab2cb1aeb8f3a22 GIT binary patch literal 281 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}mpxq^Ln7SY zPPOK1Q4nZzujb)gt0s4#sYSa$U;oiUn3~l|7IgZWHcw*!4z;Mp;&F{KQN3WNL6567Dj{}86bXpj)b6EtAEzewK)^IT5 ze!QHN3S)uM*ZEU} Date: Tue, 3 Dec 2024 06:29:10 +0400 Subject: [PATCH 22/46] =?UTF-8?q?=D0=BB=D0=BE=D0=BA=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20=D1=87=D0=B0=D1=81=D1=82=D1=8C?= =?UTF-8?q?=202?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ADT/Objects/Specific/product-unit.ftl | 2 - .../Locale/ru-RU/ADT/actions/scoping.ftl | 17 +++++ .../ADT/attachments/attachable/attachable.ftl | 32 ++++----- .../ru-RU/ADT/attachments/weapons/guns.ftl | 4 +- .../Catalog/Fills/Items/weaponcases.ftl | 8 +++ .../ADT/prototypes/Catalog/store/bobr.ftl | 70 ++++++++++--------- .../Entities/Clothing/Shoes/magboots.ftl | 2 + .../Entities/Objects/Specific/uplink_ert.ftl | 11 +++ .../Ammunition/Projectiles/projectiles.ftl | 20 +++++- .../Weapons/Guns/Ammunition/explosives.ftl | 20 ++++++ .../Locale/ru-RU/ADT/store/categories,ftl | 3 + .../objects/weapons/guns/rifles/rifles.ftl | 2 +- .../ADT/Catalog/Fills/Items/weaponcase.yml | 5 ++ .../Prototypes/ADT/Catalog/boobr_catalog.yml | 30 ++++---- .../Entities/Objects/Specific/uplink_ERT.yml | 2 +- .../Weapons/Guns/Ammunition/explosives.yml | 8 +-- .../Attachments/rail_attachment.yml | 12 ++-- Resources/Prototypes/ADT/Store/categories.yml | 6 +- 18 files changed, 171 insertions(+), 83 deletions(-) delete mode 100644 Resources/Locale/ru-RU/ADT/Objects/Specific/product-unit.ftl create mode 100644 Resources/Locale/ru-RU/ADT/actions/scoping.ftl create mode 100644 Resources/Locale/ru-RU/ADT/prototypes/Entities/Clothing/Shoes/magboots.ftl create mode 100644 Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Specific/uplink_ert.ftl create mode 100644 Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Guns/Ammunition/explosives.ftl create mode 100644 Resources/Locale/ru-RU/ADT/store/categories,ftl diff --git a/Resources/Locale/ru-RU/ADT/Objects/Specific/product-unit.ftl b/Resources/Locale/ru-RU/ADT/Objects/Specific/product-unit.ftl deleted file mode 100644 index e292734ab82..00000000000 --- a/Resources/Locale/ru-RU/ADT/Objects/Specific/product-unit.ftl +++ /dev/null @@ -1,2 +0,0 @@ -ent-Productunit = торговая единица - .desc = Кажется, этот предмет пульсирует подозрительно притягательной энергией. diff --git a/Resources/Locale/ru-RU/ADT/actions/scoping.ftl b/Resources/Locale/ru-RU/ADT/actions/scoping.ftl new file mode 100644 index 00000000000..10fb58d4fc3 --- /dev/null +++ b/Resources/Locale/ru-RU/ADT/actions/scoping.ftl @@ -0,0 +1,17 @@ +rcm-action-popup-scope-cycle-zoom = Уровень приближения изменен на {$zoom}. +cm-action-popup-scoping-must-attach = {CAPITALIZE($scope)} должен быть закреплен на оружии для корректной работы! +cm-action-popup-scoping-user-must-hold = Вы должны держать {$scope} в своей активной руке, чтобы посмотреть через него. +cm-action-popup-scoping-user-must-not-pulled = Вы не можете смотреть в {$scope} пока вас тащат! +cm-action-popup-scoping-user-must-not-contained = Вы не можете смотреть в {$scope}, будучи в ящике! +cm-action-popup-scoping-user-must-wield = Вы должны держать {$scope} в двух руках чтобы его использовать. +cm-action-popup-scoping-user = Вы смотрите через {$scope}. +cm-action-popup-scoping-stopping-user = Вы прекращаете смотреть через {$scope}. + +action-name-basescope = Посмотреть в прицел +action-description-basescope = Воспользоваться прицелом и рассмотреть цель получше. + +action-name-hristovscope = Посмотреть в прицел Христова +action-description-hristovscope = Воспользоваться прицелом и рассмотреть цель получше. + +action-name-xc67scope = Посмотреть в прицел xC-67 +action-description-xc67scope = Воспользоваться прицелом и рассмотреть цель получше. diff --git a/Resources/Locale/ru-RU/ADT/attachments/attachable/attachable.ftl b/Resources/Locale/ru-RU/ADT/attachments/attachable/attachable.ftl index d971585b0b4..ab36271657b 100644 --- a/Resources/Locale/ru-RU/ADT/attachments/attachable/attachable.ftl +++ b/Resources/Locale/ru-RU/ADT/attachments/attachable/attachable.ftl @@ -8,29 +8,29 @@ rmc-aslot-rail = Верхняя планка rmc-aslot-stock = Приклад rmc-aslot-underbarrel = Подствольное -rmc-attachable-activation-fail-not-wielded = {CAPITALIZE(THE($holder))} должен быть экипирован, чтобы активировать {THE($attachable)}! -rmc-attachable-activation-fail-not-held = {CAPITALIZE(THE($holder))} должен быть в руках, чтобы активировать {THE($attachable)}! -rmc-attachable-activation-fail-not-owned = {CAPITALIZE(THE($holder))} должен быть в ваших руках или экипирован, чтобы активировать {THE($attachable)}! +rmc-attachable-activation-fail-not-wielded = {CAPITALIZE($holder)} должен быть экипирован, чтобы активировать {$attachable}! +rmc-attachable-activation-fail-not-held = {CAPITALIZE($holder)} должен быть в руках, чтобы активировать {$attachable}! +rmc-attachable-activation-fail-not-owned = {CAPITALIZE($holder)} должен быть в ваших руках или экипирован, чтобы активировать {$attachable}! -rmc-attachable-shoot-fail-not-wielded = {CAPITALIZE(THE($holder))} должен быть экипирован, чтобы стрелять из {THE($attachable)}! +rmc-attachable-shoot-fail-not-wielded = {CAPITALIZE($holder)} должен быть экипирован, чтобы стрелять из {THE($attachable)}! -rmc-attachable-verb-toggle = Переключить {THE($attachable)} +rmc-attachable-verb-toggle = Переключить {$attachable} -attachable-popup-activate-generic = Вы активируете {THE($attachable)}. -attachable-popup-deactivate-generic = Вы деактивируете {THE($attachable)}. +attachable-popup-activate-generic = Вы активируете {$attachable}. +attachable-popup-deactivate-generic = Вы деактивируете {$attachable}. -attachable-popup-activate-deploy-on-generic = Вы устанавливаете {THE($attachable)} на {THE($surface)}. -attachable-popup-activate-deploy-on-ground = Вы устанавливаете {THE($attachable)} на землю. -attachable-popup-deactivate-retract = Вы убираете {THE($attachable)}. +attachable-popup-activate-deploy-on-generic = Вы устанавливаете {$attachable} на {$surface}. +attachable-popup-activate-deploy-on-ground = Вы устанавливаете {$attachable} на землю. +attachable-popup-deactivate-retract = Вы убираете {$attachable}. -attachable-popup-activate-unfold = Вы разворачиваете {THE($attachable)}. -attachable-popup-deactivate-collapse = Вы складываете {THE($attachable)}. +attachable-popup-activate-unfold = Вы разворачиваете {$attachable}. +attachable-popup-deactivate-collapse = Вы складываете {$attachable}. -attachable-popup-activate-lock = Вы блокируете {THE($attachable)}. -attachable-popup-deactivate-unlock = Вы разблокируете {THE($attachable)}. +attachable-popup-activate-lock = Вы блокируете {$attachable}. +attachable-popup-deactivate-unlock = Вы разблокируете {$attachable}. -attachable-popup-switch-to-generic = Вы переключаетесь на использование {THE($attachable)}. -attachable-popup-switch-from-generic = Вы перестаёте использовать {THE($attachable)}. +attachable-popup-switch-to-generic = Вы переключаетесь на использование {$attachable}. +attachable-popup-switch-from-generic = Вы перестаёте использовать {$attachable}. rmc-attachable-examinable-verb-text = Модификаторы модулей rmc-attachable-examinable-verb-message = Изучить модификаторы, применяемые этим модулем. diff --git a/Resources/Locale/ru-RU/ADT/attachments/weapons/guns.ftl b/Resources/Locale/ru-RU/ADT/attachments/weapons/guns.ftl index 9498804a92f..cf0050b0963 100644 --- a/Resources/Locale/ru-RU/ADT/attachments/weapons/guns.ftl +++ b/Resources/Locale/ru-RU/ADT/attachments/weapons/guns.ftl @@ -9,8 +9,8 @@ rmc-breech-loaded-not-ready-to-shoot = Сначала нужно открыть rmc-breech-loaded-closed-load-attempt = Сначала нужно открыть затвор! rmc-breech-loaded-closed-extract-attempt = Сначала нужно открыть затвор! -rmc-wield-use-delay = Вам нужно подождать {$seconds} секунд, прежде чем использовать {THE($wieldable)}! -rmc-shoot-use-delay = Вам нужно подождать {$seconds} секунд, прежде чем стрелять из {THE($wieldable)}! +rmc-wield-use-delay = Вам нужно подождать {$seconds} секунд, прежде чем использовать {$wieldable}! +rmc-shoot-use-delay = Вам нужно подождать {$seconds} секунд, прежде чем стрелять из {$wieldable}! rmc-revolver-spin = Вы раскручиваете барабан. diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Catalog/Fills/Items/weaponcases.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Catalog/Fills/Items/weaponcases.ftl index 38ef5e71cb9..58f7253bce4 100644 --- a/Resources/Locale/ru-RU/ADT/prototypes/Catalog/Fills/Items/weaponcases.ftl +++ b/Resources/Locale/ru-RU/ADT/prototypes/Catalog/Fills/Items/weaponcases.ftl @@ -41,3 +41,11 @@ ent-WeaponCaseBulldog = { ent-WeaponCaseNTM90 } ent-ADTWeaponCaseAR12 = { ent-WeaponCaseNTM90 } .desc = { ent-WeaponCaseNTM90.desc }. .suffix = { "AR-12" } + +ent-WeaponCaseNTM90GrenadeLauncherAttachment = { ent-WeaponCaseNTM90 } + .desc = { ent-WeaponCaseNTM90.desc }. + .suffix = { "Подствольный гранатомёт" } + +ent-WeaponCaseNTM90UnderBarrelShotGunAttachment = { ent-WeaponCaseNTM90 } + .desc = { ent-WeaponCaseNTM90.desc }. + .suffix = { "Подствольный дробовик" } diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/bobr.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/bobr.ftl index 0079650754d..b2e15d2fc78 100644 --- a/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/bobr.ftl +++ b/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/bobr.ftl @@ -1,65 +1,71 @@ -boobr-bulldog-name = набор бульдог -boobr-bulldog-desc = классический автоматический дробовик, заряжаемый барабанами 12х70. +boobr-bulldog-name = Набор "Бульдог" +boobr-bulldog-desc = Классический автоматический дробовик, заряжаемый барабанами 12х70. -boobr-m90-name = набор m-90 -boobr-m90-desc = Старый карабин, оборудованный подствольным гранатомётом. Разрывные и световые гранаты в комплекте. +boobr-m90-name = Набор "М-90gl" +boobr-m90-desc = Старый карабин, на который можно установить подствольный гранатомёт. -boobr-lecter-name = набор лектер +boobr-lecter-name = Набор "Лектер" boobr-lecter-desc = Первоклассная армейская штурмовая винтовка. Использует патроны калибра 6.5х39 мм TSF, входящие в набор. -boobr-ar12-name = набор AR-12 -boobr-ar12-desc = Продвинутая штурмовая винтовка подогнанная специально под быстрое уничтожение противника. Использует патроны калибра 6.5 мм ТСФ, входящие в набор. +boobr-ar12-name = Набор "АR-12" +boobr-ar12-desc = Продвинутая штурмовая винтовка. Использует патроны калибра 6.5 мм ТСФ, входящие в набор. -boobr-pulse-name = импульсный карабин +boobr-pulse-name = Импульсный карабин boobr-pulse-desc = Высокотехнологичный энергетический карабин, который предпочитают оперативники ОБР NT. -boobr-mateba-name = набор матеба -boobr-mateba-desc = Чертовски стильный и шумный револьвер, использующий .44 магнум. +boobr-mateba-name = Набор "Матеба" +boobr-mateba-desc = Чертовски стильный и шумный револьвер, использующий патроны .44 магнум. -boobr-ap-name = набор пробития брони -boobr-ap-desc = Набор из 10-ти бронебойных патронов .44 магнум, идеально подходящих для матебы и desert eagle. +boobr-ap-name = Набор бронебойщика +boobr-ap-desc = Набор из 10-ти бронебойных патронов .44 магнум, идеально подходящих для Матебы и Десерт Игла. boobr-deagle-name = Дезерт Игл -boobr-deagle-desc = Дезерт Игл, также известный как "пустынный орёл", - это мощный пистолет калибра .44, который выглядит металлическим и блестящим. +boobr-deagle-desc = Дезерт Игл, также известный как "Пустынный Орёл", - это мощный пистолет калибра .44, который выглядит металлическим и блестящим. -boobr-disabler-name = набор дизаблеров -boobr-disabler-desc = НТ не смогли выбрать, что лучше - станнер ПП или просто станнер. Потому, они добавили в набор оба. +boobr-disabler-name = Набор станнеров +boobr-disabler-desc = NT не смогли выбрать, что лучше - станнер-пулемет или просто станнер. Потому они добавили в набор оба. -boobr-ion-name = ионная винтовка -boobr-ion-desc = Ионно-электрическая разрушительная винтовка, специально разработана против мехов и боргов. +boobr-ion-name = Ионная винтовка +boobr-ion-desc = Ионно-электрическая винтовка, специально разработана против мехов и боргов. -boobr-drozd-name = Дрозд +boobr-drozd-name = Набор "Дрозд" boobr-drozd-desc = Превосходный, полностью автоматический, тяжёлый пистолет-пулемёт. Использует патроны калибра 9х19 мм. -boobr-riot-shield-name = противоударный щит -boobr-riot-shield-desc = Большой башенный щит на случай беспорядков. Хорошо подходит для контроля толпы. +boobr-riot-shield-name = Противоударный щит +boobr-riot-shield-desc = Большой ростовой щит на случай беспорядков. Хорошо подходит для контроля толпы. -boobr-bullet-shield-name = противопульный щит +boobr-bullet-shield-name = Противопульный щит boobr-bullet-shield-desc = Щит на случай беспорядков, созданный противостоять пулям, но не более того. -boobr-mag-boots-name = магнитные сапоги обр -boobr-mag-boots-desc = Магнитные сапоги, специально разработанные для ведения боевых действий в космосе. Данная модель выдается бойцам отрядов ОБР. +boobr-mag-boots-name = Магнитные сапоги ОБР. +boobr-mag-boots-desc = Продвинутые магнитные сапоги, специально разработанные для ведения боевых действий в космосе. Данная модель выдается бойцам отрядов ОБР. -boobr-JawsOfLife-name = челюсти жизни -boobr-JawsOfLife-desc = Набор челюстей жизни, скомпонованных при помощи магии науки. +boobr-JawsOfLife-name = Челюсти жизни +boobr-JawsOfLife-desc = Приспособление для быстрого вскрытия дверей. boobr-c4-name = C-4 boobr-c4-desc = Используйте её, чтобы разрушать стены, шлюзы. Её можно прикрепить практически к любому объекту, а таймер можно изменять, минимальное значение - 10 секунд. -boobr-grenade-name = шрапнельная граната +boobr-grenade-name = Гапнельная граната boobr-grenade-desc = Разбрасывает вокруг себя облако шрапнели, вызывающей множественные раны и кровотечения. -boobr-jetpack-name = джетпак +boobr-jetpack-name = Джетпак boobr-jetpack-desc = Позволяет с лёгкостью передвигаться вне станции. -boobr-grappling-gun-name = крюк-кошка +boobr-grappling-gun-name = Крюк-кошка boobr-grappling-gun-desc = Для лёгкого перемещения вне станции. Меч со сменным лезвием не в комплекте. -boobr-medikit-name = продвинутая аптечка +boobr-medikit-name = Продвинутая аптечка boobr-medikit-desc = Продвинутый набор для оказания помощи при продвинутых ранах. -boobr-portable-recharger-name = переносной перезарядник -boobr-portable-recharger-desc = Переносной зарядник выделенный для своевременной зарядки в условиях боевых действий. +boobr-portable-recharger-name = Переносной зарядник +boobr-portable-recharger-desc = Переносной зарядник выделенный для своевременной зарядки энергооружия в условиях боевых действий. -boobr-holo-projector-name = продвинутый голопроектор +boobr-holo-projector-name = Продвинутый голопроектор boobr-holo-projector-desc = Продвинутая версия обычного голопроектора, используемая для сдерживания угрозы или создания укреплений. + +boobr-m90-grenadelauncher-name = Подствольный гранатомёт GL90 +boobr-m90-grenadelauncher-desc = Один из наиболее распространенных подствольных гранатомётов, изначально разработанный для карабина M-90gl. Заряжается 40-мм выстрелами. + +boobr-m90-shotgun-name = Подствольный дробовик US90 +boobr-m90-shotgun-desc = Трехзарядный подствольный дробовик, сделанный изначально для карабина М-90gl. Прекрасно подходит для вышибания дверей или мозгов зомби. diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Entities/Clothing/Shoes/magboots.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Clothing/Shoes/magboots.ftl new file mode 100644 index 00000000000..9f86824d2bf --- /dev/null +++ b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Clothing/Shoes/magboots.ftl @@ -0,0 +1,2 @@ +ent-ADTClothingShoesBootsMagERT = магнитные сапоги ОБР + .desc = Продвинутые магнитные сапоги, специально разработанные для ведения боевых действий в космосе. Данная модель выдается бойцам отрядов ОБР. diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Specific/uplink_ert.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Specific/uplink_ert.ftl new file mode 100644 index 00000000000..94e927d0d84 --- /dev/null +++ b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Specific/uplink_ert.ftl @@ -0,0 +1,11 @@ +ent-ADTBaseUplinkBOBERT = Б.О.О.Б.Р. + .desc = Блюспейс-оружейная Отряда Быстрого Реагирования. + .suffix = 35 ЕТ + +ent-Productunit = торговая единица + .desc = Кажется, этот предмет пульсирует подозрительно притягательной энергией. + .suffix = 20 ЕТ + +ent-Productunit1 = торговая единица + .desc = Кажется, этот предмет пульсирует подозрительно притягательной энергией. + .suffix = 1 ЕТ diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/projectiles.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/projectiles.ftl index 201d95d9e23..86df664b194 100644 --- a/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/projectiles.ftl +++ b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/projectiles.ftl @@ -1,3 +1,21 @@ ent-ADTBulletBibis = страйкбольный шарик .desc = Если ты увидел этот шарик в полете - ты пекуш бубиш шимбамбулеш. И выйди уже из матрицы. - .suffix = { "Страйкбол" } \ No newline at end of file + .suffix = { "Страйкбол" } + +ent-ADTBullet40mmGrenadeBaton = травматическая граната + .desc = { ent-BaseBullet.desc } + +ent-ADTBullet40mmGrenadeBlast = фугасная граната + .desc = { ent-BaseBullet.desc } + +ent-ADTBullet40mmGrenadeHEAT = кумулятивная граната + .desc = { ent-BaseBullet.desc } + +ent-ADTBullet40mmGrenadeEMP = ЭМИ граната + .desc = { ent-BaseBullet.desc } + +ent-ADTBullet40mmGrenadeFlash = светошумовая граната + .desc = { ent-BaseBullet.desc } + +ent-ADTBullet40mmGrenadeSmoke = дымовая граната + .desc = { ent-BaseBullet.desc } diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Guns/Ammunition/explosives.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Guns/Ammunition/explosives.ftl new file mode 100644 index 00000000000..2aeb335eac1 --- /dev/null +++ b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Guns/Ammunition/explosives.ftl @@ -0,0 +1,20 @@ +ent-ADTBase40mmGrenade = базовая 40-мм граната + .desc = Основа. + +ent-ADT40mmGrenadeBaton = травматическая 40-мм граната + .desc = Гранатометный выстрел нелетального действия. Гарантированно собъет с ног незащищенного противника. + +ent-ADT40mmGrenadeBlast = фугасная 40-мм граната + .desc = Фугасный гранатометный выстрел. + +ent-ADT40mmGrenadeHEAT = кумулятивная 40-мм граната + .desc = Гранатометный выстрел для разрушения структур и выведения из строя техники. Обладает слабым фугасным воздействием. + +ent-ADT40mmGrenadeEMP = ЭМИ 40-мм граната + .desc = Гранатометный выстрел, создающий при подрыве электромагнитный импульс, выводящий из строя электронику. + +ent-ADT40mmGrenadeFlash = светошумовая 40-мм граната + .desc = Гранатометный выстрел, ослепляющий и оглушающий свою цель. + +ent-ADT40mmGrenadeSmoke = дымовая 40-мм граната + .desc = Гранатометный выстрел, выпускающий при срабатывании облако дыма. diff --git a/Resources/Locale/ru-RU/ADT/store/categories,ftl b/Resources/Locale/ru-RU/ADT/store/categories,ftl new file mode 100644 index 00000000000..808ff2f2886 --- /dev/null +++ b/Resources/Locale/ru-RU/ADT/store/categories,ftl @@ -0,0 +1,3 @@ +store-category-ert-weapon = Оружие +store-category-ert-other = Прочее +store-category-ert-attachment = Оруж. модули diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/weapons/guns/rifles/rifles.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/weapons/guns/rifles/rifles.ftl index 90a88612314..b355213e0e1 100644 --- a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/weapons/guns/rifles/rifles.ftl +++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/weapons/guns/rifles/rifles.ftl @@ -4,7 +4,7 @@ ent-WeaponRifleAk = АКМС .desc = Культовое оружие всех войн. Использует патроны калибра 7.62х39 мм. .suffix = Автомат ent-WeaponRifleM90GrenadeLauncher = М-90gl - .desc = Карабин старой модели, выполненный по схеме булл-пап, с подствольным гранатомётом. Использует патроны калибра 6.5 мм ТСФ. + .desc = Карабин старой модели, выполненный по схеме булл-пап, с возможностью установки подствольного гранатомета. Использует патроны калибра 6.5 мм ТСФ. .suffix = Автомат ent-WeaponRifleLecter = Лектер .desc = Первоклассная армейская штурмовая винтовка. Использует патроны калибра 6.5 мм ТСФ. diff --git a/Resources/Prototypes/ADT/Catalog/Fills/Items/weaponcase.yml b/Resources/Prototypes/ADT/Catalog/Fills/Items/weaponcase.yml index e12b0573b55..4ee2256410b 100644 --- a/Resources/Prototypes/ADT/Catalog/Fills/Items/weaponcase.yml +++ b/Resources/Prototypes/ADT/Catalog/Fills/Items/weaponcase.yml @@ -46,6 +46,11 @@ - id: ADTAttachmentM90UnderbarrelShotgun - id: MagazineShotgun amount: 2 + - id: MagazineShotgunBeanbag + amount: 2 + - id: MagazineShotgunIncendiary + amount: 2 + - id: MagazineShotgunSlug - type: entity id: WeaponCaseNTLecter diff --git a/Resources/Prototypes/ADT/Catalog/boobr_catalog.yml b/Resources/Prototypes/ADT/Catalog/boobr_catalog.yml index 799b82c0dc6..d6c44118bc4 100644 --- a/Resources/Prototypes/ADT/Catalog/boobr_catalog.yml +++ b/Resources/Prototypes/ADT/Catalog/boobr_catalog.yml @@ -5,7 +5,7 @@ icon: { sprite: /Textures/Objects/Weapons/Guns/Rifles/carbine.rsi, state: base } productEntity: WeaponCaseNTM90 cost: - Productunit: 21 + Productunit: 18 categories: - ADTUplinkERTWeapon @@ -38,7 +38,7 @@ icon: { sprite: /Textures/Objects/Weapons/Guns/Rifles/lecter.rsi, state: icon } productEntity: WeaponCaseNTLecter cost: - Productunit: 22 + Productunit: 18 categories: - ADTUplinkERTWeapon @@ -49,7 +49,7 @@ icon: { sprite: /Textures/Objects/Weapons/Guns/Battery/pulse_carbine.rsi, state: icon } productEntity: WeaponCaseNTnPulseCarbine cost: - Productunit: 27 + Productunit: 24 categories: - ADTUplinkERTWeapon @@ -60,7 +60,7 @@ icon: { sprite: /Textures/ADT/Objects/Weapons/Guns/Revolvers/mateba.rsi, state: icon } productEntity: WeaponCaseNTMateba cost: - Productunit: 10 + Productunit: 8 categories: - ADTUplinkERTWeapon @@ -71,7 +71,7 @@ description: boobr-ap-desc productEntity: WeaponCaseNTAPAmmo cost: - Productunit: 10 + Productunit: 8 categories: - ADTUplinkERTWeapon @@ -104,7 +104,7 @@ icon: { sprite: ADT/Objects/Weapons/Guns/Battery/ion_rifle.rsi, state: base } productEntity: WeaponCaseNTIonRifle cost: - Productunit: 10 + Productunit: 8 categories: - ADTUplinkERTWeapon @@ -115,7 +115,7 @@ icon: { sprite: Objects/Weapons/Guns/SMGs/drozd.rsi, state: base } productEntity: WeaponCaseNTDrozd cost: - Productunit: 15 + Productunit: 14 categories: - ADTUplinkERTWeapon @@ -126,7 +126,7 @@ icon: { sprite: Objects/Weapons/Guns/Shotguns/bulldog.rsi, state: base } productEntity: WeaponCaseBulldog cost: - Productunit: 25 + Productunit: 20 categories: - ADTUplinkERTWeapon @@ -137,7 +137,7 @@ icon: { sprite: ADT/Objects/Weapons/Guns/Rifles/ar12.rsi, state: icon } productEntity: ADTWeaponCaseAR12 cost: - Productunit: 27 + Productunit: 24 categories: - ADTUplinkERTWeapon @@ -149,7 +149,7 @@ description: boobr-riot-shield-desc productEntity: RiotShield cost: - Productunit: 10 + Productunit: 4 categories: - ADTUplinkERTMisc @@ -159,7 +159,7 @@ description: boobr-bullet-shield-desc productEntity: RiotBulletShield cost: - Productunit: 15 + Productunit: 6 categories: - ADTUplinkERTMisc @@ -169,7 +169,7 @@ description: boobr-mag-boots-desc productEntity: ADTClothingShoesBootsMagERT cost: - Productunit: 3 + Productunit: 2 categories: - ADTUplinkERTMisc @@ -189,7 +189,7 @@ description: boobr-grenade-desc productEntity: GrenadeShrapnel cost: - Productunit: 3 + Productunit: 2 categories: - ADTUplinkERTMisc @@ -239,7 +239,7 @@ description: boobr-portable-recharger-desc productEntity: PortableRecharger cost: - Productunit: 5 + Productunit: 4 categories: - ADTUplinkERTMisc @@ -249,6 +249,6 @@ description: boobr-holo-projector-desc productEntity: ADTAdvancedHoloprojectorField cost: - Productunit: 5 + Productunit: 4 categories: - ADTUplinkERTMisc diff --git a/Resources/Prototypes/ADT/Entities/Objects/Specific/uplink_ERT.yml b/Resources/Prototypes/ADT/Entities/Objects/Specific/uplink_ERT.yml index e16b2e2a88b..4436c9764a3 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Specific/uplink_ERT.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Specific/uplink_ERT.yml @@ -16,7 +16,7 @@ id: ADTBaseUplinkBOBERT name: Б.О.О.Б.Р. description: Блюспейс оружейная отряда быстрого реагирования. - suffix: 35 PU + suffix: 35 ЕТ components: - type: Sprite sprite: ADT/Objects/Specific/bobert.rsi diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Ammunition/explosives.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Ammunition/explosives.yml index 6342c3bbc97..9f023609090 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Ammunition/explosives.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Ammunition/explosives.yml @@ -49,7 +49,7 @@ parent: ADTBase40mmGrenade components: - type: CartridgeAmmo - proto: ADTBullet40mmGrenadeHEAT + proto: ADTBullet40mmGrenadeHEAT - type: Sprite sprite: ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi layers: @@ -64,7 +64,7 @@ parent: ADTBase40mmGrenade components: - type: CartridgeAmmo - proto: ADTBullet40mmGrenadeEMP + proto: ADTBullet40mmGrenadeEMP - type: Sprite sprite: ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi layers: @@ -79,7 +79,7 @@ parent: ADTBase40mmGrenade components: - type: CartridgeAmmo - proto: ADTBullet40mmGrenadeFlash + proto: ADTBullet40mmGrenadeFlash - type: Sprite sprite: ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi layers: @@ -94,7 +94,7 @@ parent: ADTBase40mmGrenade components: - type: CartridgeAmmo - proto: ADTBullet40mmGrenadeSmoke + proto: ADTBullet40mmGrenadeSmoke - type: Sprite sprite: ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi layers: diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/rail_attachment.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/rail_attachment.yml index a8c3e5d9662..2acbaed305a 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/rail_attachment.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/rail_attachment.yml @@ -47,8 +47,8 @@ icon: sprite: ADT/Objects/Attachments/scope_actions.rsi state: sniperscope - actionName: Look through Scope - actionDesc: Scope in. If you're seeing this, someone forgot to set the description properly. + actionName: action-name-basescope + actionDesc: action-description-basescope - type: AttachableToggleableSimpleActivate - type: Scope requireWielding: true @@ -75,8 +75,8 @@ - ADTAttachmentHristovScope - type: AttachableVisuals - type: AttachableToggleable - actionName: Look through the Hristov scope - actionDesc: An Hristov telescopic eye piece. Fixed at 6x zoom. + actionName: action-name-hristovscope + actionDesc: action-description-hristovscope - type: AttachableToggleableSimpleActivate - type: Scope zoomLevels: @@ -122,8 +122,8 @@ # - type: AttachableVisuals - type: AttachableToggleable breakOnMove: false - actionName: Look through the xC-67 scope - actionDesc: An xC-67 telescoping eye piece. Fixed at a modest 2x zoom. + actionName: action-name-xc67scope + actionDesc: action-description-xc67scope wieldedOnly: false breakOnRotate: false - type: AttachableToggleableSimpleActivate diff --git a/Resources/Prototypes/ADT/Store/categories.yml b/Resources/Prototypes/ADT/Store/categories.yml index 238dd9adefa..ab527ad5958 100644 --- a/Resources/Prototypes/ADT/Store/categories.yml +++ b/Resources/Prototypes/ADT/Store/categories.yml @@ -1,16 +1,16 @@ - type: storeCategory id: ADTUplinkERTWeapon - name: вооружение + name: Оружие priority: 1 - type: storeCategory id: ADTUplinkERTMisc - name: прочее + name: Прочее priority: 2 - type: storeCategory id: ADTUplinkERTAttachments - name: Обвесы|Модули + name: Оруж. обвесы priority: 3 - type: storeCategory From 29b415dfd444b25e5a0660b0acfa8c4acda67188 Mon Sep 17 00:00:00 2001 From: Eugeny Date: Wed, 4 Dec 2024 07:20:52 +0400 Subject: [PATCH 23/46] =?UTF-8?q?=D0=B7=D0=B0=D0=BC=D0=B5=D0=BD=D0=B0=20?= =?UTF-8?q?=D1=81=D0=BD=D0=B0=D1=80=D1=8F=D0=B4=D0=BE=D0=B2=20=D0=B2=20?= =?UTF-8?q?=D0=BF=D1=83=D1=81=D0=BA=D0=BE=D0=B2=D1=8B=D1=85=20=D1=83=D1=81?= =?UTF-8?q?=D1=82=D0=B0=D0=BD=D0=BE=D0=B2=D0=BA=D0=B0=D1=85=20=D0=BC=D0=B5?= =?UTF-8?q?=D1=85=D0=BE=D0=B2=20=D0=BD=D0=B0=2040=20=D0=BC=D0=BC=20=D0=B3?= =?UTF-8?q?=D1=80=D0=B0=D0=BD=D0=B0=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Objects/Specific/Mech/mechgun.ftl | 8 +++---- .../Objects/Specific/Mech/mech_gun.yml | 22 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Specific/Mech/mechgun.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Specific/Mech/mechgun.ftl index a1d483e76d3..9d379adb059 100644 --- a/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Specific/Mech/mechgun.ftl +++ b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Specific/Mech/mechgun.ftl @@ -22,14 +22,14 @@ ent-ADTMechGunUltraAC2 = AC-2 "Ультра" ent-ADTMechGunMHAR21 = антиматериальная мех-винтовка mHAR-21 "Ma Deuce" .desc = Пушка под крайне разрушительный патрон .50 калибра. Равно хороша и против других мехов и иных бронированных целей, и против незащищенной агрессивной фауны. -ent-ADTMechGunSGL6 = гранатомет SGL-6 +ent-ADTMechGunSGL6 = гранатомёт SGL-6 .desc = Второе по популярности мех-оружие сил правопорядка - SGL-6. Запускает несколько светошумовых гранат и позволит в кратчайший срок вывести из боя любую группу преступников. Если они, конечно, не носят солнцезащитные очки. -ent-ADTMechGunSRM8 = ракетная установка SRM-8 +ent-ADTMechGunSRM8 = гранатомёт SRM-8 .desc = Пусковая установка для девяти 40-мм гранатометных выстрелов. -ent-ADTMechGunBRM6 = ракетная установка BRM-6 - .desc = Уменьшенный вариант пусковой установки SRM-8. Снаряжена 6 гранатометными выстрелами калибра 40 мм. +ent-ADTMechGunBRM6 = гранатомёт BRM-6 + .desc = Уменьшенный вариант пусковой установки SRM-8 для борьбы с беспорядками. Снаряжена 6 травматическими гранатометными выстрелами калибра 40 мм. ent-ADTMechGunFNX99Hades = мех-карабин FNX-99 "Аид" .desc = Пулемёт для меха под патрон 7.62 зажигательные. Лучше всего проявит себя против легковоспламенимых целей или красных бочек с топливом. diff --git a/Resources/Prototypes/ADT/Entities/Objects/Specific/Mech/mech_gun.yml b/Resources/Prototypes/ADT/Entities/Objects/Specific/Mech/mech_gun.yml index 34c4a330ec8..2ce0d2e2356 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Specific/Mech/mech_gun.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Specific/Mech/mech_gun.yml @@ -317,9 +317,9 @@ soundEmpty: path: /Audio/Weapons/Guns/Empty/empty.ogg - type: BallisticMechAmmoProvider - proto: GrenadeFlash - shots: 3 - capacity: 3 + proto: ADT40mmGrenadeFlash + shots: 6 + capacity: 6 ammoType: granade reloadTime: 5 - type: UIFragment @@ -340,13 +340,13 @@ availableModes: - FullAuto soundGunshot: - path: /Audio/Weapons/Guns/Gunshots/rpgfire.ogg + path: /Audio/Weapons/Guns/Gunshots/grenade_launcher.ogg soundEmpty: path: /Audio/Weapons/Guns/Empty/empty.ogg - type: BallisticMechAmmoProvider - proto: BulletRocket - shots: 2 - capacity: 2 + proto: ADT40mmGrenadeHEAT + shots: 9 + capacity: 9 ammoType: granade reloadTime: 5 - type: UIFragment @@ -367,13 +367,13 @@ availableModes: - FullAuto soundGunshot: - path: /Audio/Weapons/Guns/Gunshots/rpgfire.ogg + path: /Audio/Weapons/Guns/Gunshots/grenade_launcher.ogg soundEmpty: path: /Audio/Weapons/Guns/Empty/empty.ogg - type: BallisticMechAmmoProvider - proto: GrenadeBaton - shots: 3 - capacity: 3 + proto: ADT40mmGrenadeBaton + shots: 6 + capacity: 6 ammoType: granade reloadTime: 5 - type: UIFragment From 4e5ff4703f95e8bcf173ebef662379672dc6bc8c Mon Sep 17 00:00:00 2001 From: Inconnu1337 Date: Thu, 5 Dec 2024 20:06:08 +0200 Subject: [PATCH 24/46] =?UTF-8?q?=D1=83=D0=B4=D0=B0=D0=BB=D0=B8=D0=BB=20?= =?UTF-8?q?=D0=BB=D0=B8=D1=88=D0=BD=D0=B8=D0=B9=20=D1=84=D0=B0=D0=B9=D0=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Attachments/under_attachment.yml | 16 ---------------- .../Guns/Attachments/attachable_base.yml | 18 ++++++++++++++++++ .../Attachments/attachable_holder_base.yml | 17 ----------------- 3 files changed, 18 insertions(+), 33 deletions(-) delete mode 100644 Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/attachable_holder_base.yml diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml index e39ef8db2ec..ecbd4a95f54 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml @@ -135,19 +135,3 @@ - type: AttachableVisuals - type: UniqueAction - type: PumpAction - -- type: entity - parent: ADTUnderAttachmentBase - id: ADTMicroAccelerator - name: micro accelerator - description: sus - components: - - type: Sprite - sprite: ADT/Objects/Weapons/Guns/Saber_revolvers/battery.rsi # затычка - state: base - - type: Tag - tags: - - ADTAttachmentMicroAccelerator - - type: AttachableWeaponRangedMods - modifiers: - - fireDelayFlat: -1.0 diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/attachable_base.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/attachable_base.yml index 601efb23e97..e0f23c9e5ae 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/attachable_base.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/attachable_base.yml @@ -15,3 +15,21 @@ - type: AttachableToggleable - type: UseDelay delay: 0 + +- type: entity + abstract: true + id: ADTBaseAttachableHolder + components: + - type: AttachableHolder + - type: ItemSizeChange + - type: ActivatableUI + verbText: rmc-verb-strip-attachables + verbOnly: true + key: + enum.AttachmentUI.StripKey + - type: UserInterface + interfaces: + enum.AttachmentUI.StripKey: + type: AttachmentStripBui + enum.AttachmentUI.ChooseSlotKey: + type: AttachmentChooseSlotBui diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/attachable_holder_base.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/attachable_holder_base.yml deleted file mode 100644 index 72adb3f8d96..00000000000 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/attachable_holder_base.yml +++ /dev/null @@ -1,17 +0,0 @@ -- type: entity - abstract: true - id: ADTBaseAttachableHolder - components: - - type: AttachableHolder - - type: ItemSizeChange - - type: ActivatableUI - verbText: rmc-verb-strip-attachables - verbOnly: true - key: - enum.AttachmentUI.StripKey - - type: UserInterface - interfaces: - enum.AttachmentUI.StripKey: - type: AttachmentStripBui - enum.AttachmentUI.ChooseSlotKey: - type: AttachmentChooseSlotBui From 62f390627b7db77fec77f162907799fa2cef75ee Mon Sep 17 00:00:00 2001 From: Eugeny Date: Tue, 10 Dec 2024 06:39:53 +0400 Subject: [PATCH 25/46] =?UTF-8?q?=D0=BA=D0=BE=D0=BB=D0=BB=D0=B8=D0=BC?= =?UTF-8?q?=D0=B0=D1=82=D0=BE=D1=80=D0=BD=D1=8B=D0=B5=20=D0=BF=D1=80=D0=B8?= =?UTF-8?q?=D1=86=D0=B5=D0=BB=D1=8B,=20=D1=80=D1=83=D0=BA=D0=BE=D1=8F?= =?UTF-8?q?=D1=82=D1=8C,=20=D0=BB=D0=B0=D0=B7=D0=B5=D1=80=D0=BD=D1=8B?= =?UTF-8?q?=D0=B9=20=D1=86=D0=B5=D0=BB=D0=B5=D1=83=D0=BA=D0=B0=D0=B7=D0=B0?= =?UTF-8?q?=D1=82=D0=B5=D0=BB=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Locale/ru-RU/ADT/actions/scoping.ftl | 2 +- .../Objects/Weapons/Guns/Attachments.ftl | 16 ++++- .../Attachments/rail_attachment.yml | 65 ++++++++++++----- .../Attachments/under_attachment.yml | 68 +++++++++++++++++- .../Objects/Weapons/Guns/Attachments/tags.yml | 11 ++- .../Objects/Weapons/Guns/Rifles/rifles.yml | 34 ++++++--- .../Objects/Weapons/Guns/Rifles/rifles.yml | 36 +++++++++- .../Objects/Weapons/Guns/SMGs/smgs.yml | 21 +++++- .../ADT/Attachments/rail.rsi/meta.json | 24 +++++-- .../ADT/Attachments/rail.rsi/miniscope.png | Bin 0 -> 294 bytes .../ADT/Attachments/rail.rsi/miniscope_a.png | Bin 0 -> 209 bytes .../ADT/Attachments/rail.rsi/reflex.png | Bin 0 -> 269 bytes .../ADT/Attachments/rail.rsi/reflex_a.png | Bin 0 -> 190 bytes .../ADT/Attachments/under.rsi/lasersight.png | Bin 0 -> 274 bytes .../Attachments/under.rsi/lasersight_a.png | Bin 0 -> 194 bytes .../Attachments/under.rsi/masterkey-on.png | Bin 0 -> 443 bytes .../ADT/Attachments/under.rsi/masterkey.png | Bin 0 -> 351 bytes .../ADT/Attachments/under.rsi/masterkey_a.png | Bin 0 -> 249 bytes .../ADT/Attachments/under.rsi/meta.json | 21 ++++++ .../Attachments/under.rsi/verticalgrip.png | Bin 0 -> 355 bytes .../Attachments/under.rsi/verticalgrip_a.png | Bin 0 -> 174 bytes .../40mm_grenade.rsi/base-spent.png | Bin 202 -> 202 bytes .../Explosives/40mm_grenade.rsi/emp.png | Bin 304 -> 304 bytes .../Explosives/40mm_grenade.rsi/flash.png | Bin 304 -> 304 bytes .../Explosives/40mm_grenade.rsi/he.png | Bin 305 -> 305 bytes .../Explosives/40mm_grenade.rsi/heat.png | Bin 309 -> 309 bytes .../Explosives/40mm_grenade.rsi/smoke.png | Bin 291 -> 291 bytes .../Explosives/40mm_grenade.rsi/stinger.png | Bin 311 -> 311 bytes .../Explosives/40mm_grenade.rsi/stun.png | Bin 305 -> 305 bytes .../Weapons/Guns/Rifles/xc67.rsi/base.png | Bin 539 -> 472 bytes .../Guns/Rifles/xc67.rsi/bolt-open.png | Bin 537 -> 472 bytes .../Weapons/Guns/Rifles/xc67.rsi/icon.png | Bin 576 -> 657 bytes .../Rifles/xc67.rsi/wielded-inhand-left.png | Bin 1098 -> 1138 bytes .../Rifles/xc67.rsi/wielded-inhand-right.png | Bin 1099 -> 1137 bytes 34 files changed, 252 insertions(+), 46 deletions(-) create mode 100644 Resources/Textures/ADT/Attachments/rail.rsi/miniscope.png create mode 100644 Resources/Textures/ADT/Attachments/rail.rsi/miniscope_a.png create mode 100644 Resources/Textures/ADT/Attachments/rail.rsi/reflex.png create mode 100644 Resources/Textures/ADT/Attachments/rail.rsi/reflex_a.png create mode 100644 Resources/Textures/ADT/Attachments/under.rsi/lasersight.png create mode 100644 Resources/Textures/ADT/Attachments/under.rsi/lasersight_a.png create mode 100644 Resources/Textures/ADT/Attachments/under.rsi/masterkey-on.png create mode 100644 Resources/Textures/ADT/Attachments/under.rsi/masterkey.png create mode 100644 Resources/Textures/ADT/Attachments/under.rsi/masterkey_a.png create mode 100644 Resources/Textures/ADT/Attachments/under.rsi/verticalgrip.png create mode 100644 Resources/Textures/ADT/Attachments/under.rsi/verticalgrip_a.png diff --git a/Resources/Locale/ru-RU/ADT/actions/scoping.ftl b/Resources/Locale/ru-RU/ADT/actions/scoping.ftl index 10fb58d4fc3..9114a945f96 100644 --- a/Resources/Locale/ru-RU/ADT/actions/scoping.ftl +++ b/Resources/Locale/ru-RU/ADT/actions/scoping.ftl @@ -13,5 +13,5 @@ action-description-basescope = Воспользоваться прицелом action-name-hristovscope = Посмотреть в прицел Христова action-description-hristovscope = Воспользоваться прицелом и рассмотреть цель получше. -action-name-xc67scope = Посмотреть в прицел xC-67 +action-name-xc67scope = Посмотреть в прицел T2 action-description-xc67scope = Воспользоваться прицелом и рассмотреть цель получше. diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Guns/Attachments.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Guns/Attachments.ftl index 63dc05a347a..6eb77e49e1a 100644 --- a/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Guns/Attachments.ftl +++ b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Guns/Attachments.ftl @@ -6,8 +6,8 @@ ent-ADTAttachmentHristovScope = прицел Христова .desc = Штатный прицел для снайперской винтовки "Христов", с шестикратным увеличением. .suffix = { "Оруж. модуль, Прицел" } -ent-ADTAttachmentXC67Miniscope = прицел хС-67 -.desc = Штатный прицел для штурмовой винтовки хС-67, с двухкратным увеличением. +ent-ADTAttachmentT2Miniscope = прицел T2 Miniscope +.desc = Оптический прицел малой кратности, подходящий для ведения боя в замкнутых пространствах. Производства Shellguard Munitions. .suffix = { "Оруж. модуль, Прицел" } ent-ADTAttachmentM90GrenadeLauncher = подствольный гранатомёт GL90 @@ -17,3 +17,15 @@ ent-ADTAttachmentM90GrenadeLauncher = подствольный гранатом ent-ADTAttachmentM90UnderbarrelShotgun = подствольный дробовик US90 .desc = Трехзарядный подствольный дробовик, сделанный изначально для карабина М-90gl. Прекрасно подходит для вышибания дверей или мозгов зомби. .suffix = { "Оруж. модуль, Подствольный" } + +ent-ADTAttachmentReflexSight = коллиматорный прицел Red Dot +.desc = Коллиматорный прицел, повышающий меткость стрельбы с одной руки и из неустойчивых положений. Производства Shellguard Munitions. +.suffix = { "Оруж. модуль, Прицел" } + +ent-ADTAttachmentVerticalGrip = вертикальная рукоять +.desc = Вертикальная рукоять, позволяющая при установке бойцу стрелять точнее. +.suffix = { "Оруж. модуль, Подствольный" } + +ent-ADTAttachmentLaserSight = лазерный целеуказатель +.desc = Устанавливаемый под ствол маленький лазер, позволяющий бойцу стрелять точнее даже без прицела и с одной руки. +.suffix = { "Оруж. модуль, Подствольный" } diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/rail_attachment.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/rail_attachment.yml index 2acbaed305a..a29b02334c3 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/rail_attachment.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/rail_attachment.yml @@ -100,32 +100,35 @@ activeOnly: true fireDelayFlat: 0.25 accuracyAddMult: 0.35 - damageFalloffAddMult: -0.4 - - conditions: - wieldedOnly: true - inactiveOnly: true - accuracyAddMult: -0.05 + # damageFalloffAddMult: -0.4 + # - conditions: + # wieldedOnly: true + # inactiveOnly: true + # accuracyAddMult: -0.05 - type: entity parent: ADTAttachmentScopeBase - id: ADTAttachmentXC67Miniscope - name: xC-67 scope - description: xC-67 scope + id: ADTAttachmentT2Miniscope + name: T2 scope + description: T2 scope components: - type: Sprite - sprite: ADT/Objects/Attachments/scope_actions.rsi - state: sniperscope + sprite: ADT/Attachments/rail.rsi + state: miniscope - type: Tag tags: - ADTAttachmentRail - - ADTAttachmentXC67Miniscope - # - type: AttachableVisuals + - ADTAttachmentT2Miniscope + - type: AttachableVisuals - type: AttachableToggleable breakOnMove: false - actionName: action-name-xc67scope - actionDesc: action-description-xc67scope + actionName: action-name-t2scope + actionDesc: action-description-t2scope wieldedOnly: false breakOnRotate: false + icon: + sprite: ADT/Attachments/rail.rsi + state: miniscope - type: AttachableToggleableSimpleActivate - type: Scope zoomLevels: @@ -142,15 +145,41 @@ sprint: -0.448 - type: AttachableWieldDelayMods modifiers: - - delay: 0.4 + - delay: 0.2 - type: AttachableWeaponRangedMods modifiers: - conditions: activeOnly: true fireDelayFlat: 0.15 accuracyAddMult: 0.35 - damageFalloffAddMult: -0.2 + # damageFalloffAddMult: -0.2 + # - conditions: + # wieldedOnly: true + # inactiveOnly: true + # accuracyAddMult: -0.05 #TODO: Add flare gun modifiers when it's implemented. + +- type: entity + parent: ADTRailAttachmentBase + id: ADTAttachmentReflexSight + name: reflex sight + description: Areflex sight + components: + - type: Sprite + sprite: ADT/Attachments/rail.rsi + state: reflex + - type: Tag + tags: + - ADTAttachmentRail + - ADTAttachmentReflexSight + - type: AttachableVisuals + - type: AttachableWeaponRangedMods + modifiers: - conditions: wieldedOnly: true - inactiveOnly: true - accuracyAddMult: -0.05 #TODO: Add flare gun modifiers when it's implemented. + accuracyAddMult: 0.20 + scatterFlat: -4 + burstScatterAddMult: -2 + - conditions: + unwieldedOnly: true + accuracyAddMult: 0.4 + scatterFlat: -8 diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml index e39ef8db2ec..95c54c8fa9f 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml @@ -81,6 +81,9 @@ tags: - ADTAttachmentUnderbarrel - ADTAttachmentM90GrenadeLauncher + - type: Item + sprite: ADT/Attachments/under.rsi + storedRotation: -90 - type: entity parent: [ ADTUnderAttachmentBase, ADTAttachableToggleableBase ] @@ -89,7 +92,7 @@ description: MEOW components: - type: Sprite - state: grenade + state: masterkey - type: Tag tags: - ADTAttachmentUnderbarrel @@ -128,13 +131,16 @@ actionDesc: Switch to using the underbarrel shotgun. icon: sprite: ADT/Attachments/under.rsi - state: grenade + state: masterkey iconActive: sprite: ADT/Attachments/under.rsi - state: grenade-on + state: masterkey-on - type: AttachableVisuals - type: UniqueAction - type: PumpAction + - type: Item + sprite: ADT/Attachments/under.rsi + storedRotation: -90 - type: entity parent: ADTUnderAttachmentBase @@ -151,3 +157,59 @@ - type: AttachableWeaponRangedMods modifiers: - fireDelayFlat: -1.0 + +- type: entity + parent: ADTUnderAttachmentBase + id: ADTAttachmentVerticalGrip + name: vertical grip + description: "A vertical foregrip that offers better accuracy, less recoil, and less scatter, especially during burst fire. + However, it also increases weapon size." + components: + - type: Sprite + state: verticalgrip + - type: AttachableVisuals + - type: Tag + tags: + - ADTAttachmentUnderbarrel + - ADTAttachmentVerticalGrip + # - type: AttachableSizeMods + # modifiers: + # - size: 1 + - type: AttachableWeaponRangedMods + modifiers: + - conditions: + wieldedOnly: true + accuracyAddMult: 0.3 + recoilFlat: -2 + scatterFlat: -4 + burstScatterAddMult: -4 + # - conditions: + # unwieldedOnly: true + # accuracyAddMult: -0.15 + # scatterFlat: 2 + +- type: entity + parent: ADTUnderAttachmentBase + id: ADTAttachmentLaserSight + name: laser sight + description: A laser sight that attaches to the underside of most weapons. Increases accuracy and decreases scatter, especially while one-handed. + components: + - type: Sprite + state: lasersight + - type: AttachableVisuals + - type: Tag + tags: + - ADTAttachmentUnderbarrel + - ADTAttachmentLaserSight + - type: AttachableWeaponRangedMods + modifiers: + - conditions: + wieldedOnly: true + accuracyAddMult: 0.15 + scatterFlat: -2 + recoilFlat: -2 + - conditions: + unwieldedOnly: true + accuracyAddMult: 0.3 + scatterFlat: -6 + recoilFlat: -4 diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/tags.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/tags.yml index 38573d61a52..9c0f834d6f5 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/tags.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/tags.yml @@ -29,4 +29,13 @@ id: ADTMosinBayonetAttachment - type: Tag - id: ADTAttachmentXC67Miniscope + id: ADTAttachmentT2Miniscope + +- type: Tag + id: ADTAttachmentVerticalGrip + +- type: Tag + id: ADTAttachmentReflexSight + +- type: Tag + id: ADTAttachmentLaserSight diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Rifles/rifles.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Rifles/rifles.yml index edc712e76a3..2b17573f6ff 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Rifles/rifles.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Rifles/rifles.yml @@ -155,7 +155,7 @@ - type: entity name: xC67 - parent: [BaseWeaponRifle, ADTBaseMagneticGun] + parent: [BaseWeaponRifle, ADTBaseAttachableHolder] id: ADTWeaponRifleXC67 description: A high end prototipe assault rifle. Uses .20 rifle ammo. components: @@ -169,8 +169,8 @@ - type: Clothing sprite: ADT/Objects/Weapons/Guns/Rifles/xc67.rsi - type: Gun - #minAngle: 2 - #maxAngle: 8 + minAngle: 20.5 + maxAngle: 31 fireRate: 6 #angleIncrease: 1 #angleDecay: 12 @@ -210,19 +210,31 @@ - type: Appearance - type: AttachableHolder slots: + rmc-aslot-underbarrel: + startingAttachable: ADTAttachmentVerticalGrip + whitelist: + tags: + - ADTAttachmentM90GrenadeLauncher + - ADTAttachmentM90UnderbarrelShotgun + - ADTAttachmentVerticalGrip + - ADTAttachmentLaserSight rmc-aslot-rail: - locked: true - startingAttachable: ADTAttachmentXC67Miniscope + startingAttachable: ADTAttachmentT2Miniscope whitelist: tags: - ADTAttachmentMagneticHarness - - ADTAttachmentXC67Miniscope + - ADTAttachmentReflexSight + - ADTAttachmentT2Miniscope + - type: AttachableHolderVisuals + offsets: + rmc-aslot-underbarrel: 0.3125, -0.0315 + rmc-aslot-rail: -0.0940, -0.0325 - type: ItemSizeChange - - type: ActivatableUI - verbText: rmc-verb-strip-attachables - verbOnly: true - key: - enum.AttachmentUI.StripKey + # - type: ActivatableUI + # verbText: rmc-verb-strip-attachables + # verbOnly: true + # key: + # enum.AttachmentUI.StripKey - type: UserInterface interfaces: enum.AttachmentUI.StripKey: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml index 78c377d3f82..8bb8e2e9598 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml @@ -134,7 +134,7 @@ whitelist: tags: - CartridgeRifle - # ADT TWEAK START +# ADT TWEAK START - type: AttachableHolder slots: rmc-aslot-underbarrel: @@ -142,10 +142,19 @@ tags: - ADTAttachmentM90GrenadeLauncher - ADTAttachmentM90UnderbarrelShotgun + - ADTAttachmentVerticalGrip + - ADTAttachmentLaserSight + rmc-aslot-rail: + whitelist: + tags: + - ADTAttachmentMagneticHarness + - ADTAttachmentReflexSight + - ADTAttachmentT2Miniscope - type: AttachableHolderVisuals offsets: rmc-aslot-underbarrel: 0.3125, -0.0625 - # ADT TWEAK END + rmc-aslot-rail: -0.0325, -0.0325 +# ADT TWEAK END - type: ContainerContainer containers: gun_magazine: !type:ContainerSlot @@ -158,7 +167,7 @@ - type: entity name: Lecter - parent: [BaseWeaponRifle, BaseRestrictedContraband, ADTBaseMagneticGun] # ADT TWEAK + parent: [BaseWeaponRifle, BaseRestrictedContraband, ADTBaseAttachableHolder] # ADT TWEAK id: WeaponRifleLecter description: A high end military grade assault rifle. Uses .20 rifle ammo. components: @@ -202,6 +211,27 @@ steps: 1 zeroVisible: true - type: Appearance +# ADT TWEAK START + - type: AttachableHolder + slots: + rmc-aslot-underbarrel: + whitelist: + tags: + - ADTAttachmentM90GrenadeLauncher + - ADTAttachmentM90UnderbarrelShotgun + - ADTAttachmentVerticalGrip + - ADTAttachmentLaserSight + rmc-aslot-rail: + whitelist: + tags: + - ADTAttachmentMagneticHarness + - ADTAttachmentReflexSight + - ADTAttachmentT2Miniscope + - type: AttachableHolderVisuals + offsets: + rmc-aslot-underbarrel: 0.3125, -0.0625 + rmc-aslot-rail: 0, 0 +# ADT TWEAK END - type: entity name: Foam Force Astro Ace diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml index 5325a94f6cf..8752caafc09 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml @@ -119,7 +119,7 @@ - type: entity name: Drozd - parent: [BaseWeaponSubMachineGun, BaseRestrictedContraband, ADTBaseMagneticGun] # ADT TWEAK + parent: [BaseWeaponSubMachineGun, BaseRestrictedContraband, ADTBaseAttachableHolder] # ADT TWEAK id: WeaponSubMachineGunDrozd description: An excellent fully automatic Heavy SMG. components: @@ -170,6 +170,25 @@ steps: 1 zeroVisible: true - type: Appearance + # ADT TWEAK START + - type: AttachableHolder + slots: + rmc-aslot-underbarrel: + whitelist: + tags: + - ADTAttachmentVerticalGrip + - ADTAttachmentLaserSight + rmc-aslot-rail: + whitelist: + tags: + - ADTAttachmentMagneticHarness + - ADTAttachmentReflexSight + - ADTAttachmentT2Miniscope + - type: AttachableHolderVisuals + offsets: + rmc-aslot-underbarrel: 0.28, -0.1250 + rmc-aslot-rail: -0.0325, -0.0625 + # ADT TWEAK END - type: entity name: Vector diff --git a/Resources/Textures/ADT/Attachments/rail.rsi/meta.json b/Resources/Textures/ADT/Attachments/rail.rsi/meta.json index 16447e2f116..1cd81382e43 100644 --- a/Resources/Textures/ADT/Attachments/rail.rsi/meta.json +++ b/Resources/Textures/ADT/Attachments/rail.rsi/meta.json @@ -6,9 +6,21 @@ "x": 32, "y": 32 }, - "states": [ - { - "name": "magnetic" - } - ] -} \ No newline at end of file + "states": [ + { + "name": "magnetic" + }, + { + "name": "miniscope" + }, + { + "name": "miniscope_a" + }, + { + "name": "reflex" + }, + { + "name": "reflex_a" + } + ] +} diff --git a/Resources/Textures/ADT/Attachments/rail.rsi/miniscope.png b/Resources/Textures/ADT/Attachments/rail.rsi/miniscope.png new file mode 100644 index 0000000000000000000000000000000000000000..b186d9d4da7db25e6988ee130b318caa574f9486 GIT binary patch literal 294 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5D0suu z#WAE}&f6)D+|33&t=ey%_%2y~Y4!jA_MPgQO9S?l?Mw11*igDIndg(krCS%itFq<4 zIxfV(C;&ta|5-L%Q;RzP`A)59g3R$N-)jvI*GaG~-5U0K*Q(sxlZw|VZ>U{Aq2J@Z zJ=1|y1Dh$l(^5~Kmz?xT;~m5Lb?bk#tPpF`40XRK5qxf0X3)LgbNV9|YcXt*YLaYk zaN^*v6q(I1K`=h}X+x*swBnGn#j_Y>nx`zEw|#z8jno#GXQs>%tOtB=1T0OjeE;H7 i{e!N+;D%{1r&*`9w0b+nZgT>QT-EA_e4xfka1hE$YGKHEQ_E;CePJc?}sZY%K4Woq?=dD zACX`*Fg_;H|Ni&2S=ygp=`!rGzq_qBh-+&Y!?T}m+2!Fgb~nsq+^|mDGTn*e%RR;j zvHV+&qD!XK_0>I(J$N+wL8{T_S}FPG&6P?Z@X6laKuE6qgNB(J&{+(gu6{1-oD!M< DQ|e8} literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Attachments/rail.rsi/reflex.png b/Resources/Textures/ADT/Attachments/rail.rsi/reflex.png new file mode 100644 index 0000000000000000000000000000000000000000..4f478522a2dfab592ff00ad607c1c89dd86e3231 GIT binary patch literal 269 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5D7fF# z#WAE}&f80de1{Z7*dFZf3=WU+n10VOy)Q)F|6$5`*W+zhTT29Y9gJvQa_pc<$lBhM zzo)b7Gwu^Ji?C!-U|{5MX!y@=aICE`r{`oHABSa#=(*Cr*KYMQx&|KjX1i`#PQ#}u z3oZ5dIQHAh$Sm607Q_`@cJuD~1pD&!DGdTiFLv==yJhkHUURYB>M5TXXaDA##F%^g z*sSN3YZ#4^j?F9PE1t|#@oQ7!s_haFjxLySW&1gmeSF O!ru;s0GjpG~Z)$q_-tXj? zzCCk_1KU<=KA2lRn~0v(6l{Q`EW&w#ziE29 z*e8RzwXaz3{7+-3So6B9K5Ld4dtgcQ`_*0nZ4G}|uPA=z`w+{M0J65h*z=RiQO3i{ R6+r(mc)I$ztaD0e0sv=0V#ojh literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Attachments/under.rsi/lasersight_a.png b/Resources/Textures/ADT/Attachments/under.rsi/lasersight_a.png new file mode 100644 index 0000000000000000000000000000000000000000..a916d13483eb5f5df54035a31781445ccac02d87 GIT binary patch literal 194 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}HJ&bxArY-_ z&u!#7N>eis*) zZ|iRDl1MITFkHHQ=T+11b6&P5UVVF((TStZ04TZe z0*eUcY9NRuNI&OEOqyU1ph@0crYVGGjbdLy5LaO88TgUUhEAV7DvRaLeA_vwUJhh&kiDZ?ND+H@p&o(E}~5-m~?1fx#^ z6@XSVR9DAwuurm+9>Z(EZq<7Kgd4#B2I#iUQ;Bxx=mDUv6?Lz3TvA50<+OowsRf|5 l&2xx&HM{(vhUApZ zY~RT z8}_|7?0fuk@2XW7N@Wuz4t=lXo2PP8OG2~Z^{xPs*5{S;CZ%3NWtt68U8TbI@ZRL$C>vN7-9^bu6{1-oD!M<}3|Ln2z= zUNYorF%WRLxZhifS!~iV;U_Hf4sut-RdZMGzLKdU<9Pb6UxB0VtGVoo!V*S@RTfMM z^7^|w+;3CyyUCN%*B-6*zyH18)W?sR!S^zQL7#H&?M>^nfA3=s5MfP?G~!`aY+3Sq zlX}2)QwBq~HCw0ey!Tsq-|QpS%NZF29bNj0ua|~|mfq?$Y!T=yRsYSoE!X)78&qol`;+0JT_M761SM literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Attachments/under.rsi/meta.json b/Resources/Textures/ADT/Attachments/under.rsi/meta.json index a54df8451b9..47b23158b5f 100644 --- a/Resources/Textures/ADT/Attachments/under.rsi/meta.json +++ b/Resources/Textures/ADT/Attachments/under.rsi/meta.json @@ -28,6 +28,27 @@ }, { "name": "mosinbayonet_a" + }, + { + "name": "masterkey" + }, + { + "name": "masterkey-on" + }, + { + "name": "masterkey_a" + }, + { + "name": "verticalgrip" + }, + { + "name": "verticalgrip_a" + }, + { + "name": "lasersight" + }, + { + "name": "lasersight_a" } ] } diff --git a/Resources/Textures/ADT/Attachments/under.rsi/verticalgrip.png b/Resources/Textures/ADT/Attachments/under.rsi/verticalgrip.png new file mode 100644 index 0000000000000000000000000000000000000000..2eb28365708225227d01d1341b0d6f1ad9bc459c GIT binary patch literal 355 zcmV-p0i6DcP)0->$`R zeB@R80Gkudx~@ZA*I*b1G)+V9d7ekQ(p zRj~ymNg}juOIC4Nmb=z3HGsD0DS)$r132JvzzdG-Z5+5|ocRC%002ovPDHLkV1jcw BiT3~i literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Attachments/under.rsi/verticalgrip_a.png b/Resources/Textures/ADT/Attachments/under.rsi/verticalgrip_a.png new file mode 100644 index 0000000000000000000000000000000000000000..1ad553627cc4f30787a439f329d653bce572bcbb GIT binary patch literal 174 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}8J;eVArY-_ zFKy&Kpupo2C=^!kR#C%-<#eU7{~@juD_1BNc6k)8FKS#HAHXFjcrj6YQ%v?*)AN=K zqoeQGp4GW)dq2M3A$0Tid8>BG7AzKAYnma?*U_<=F}Y_mqf*nn0}ApJIy&keGK%+$ Vy*@jY@gC4l22WQ%mvv4FO#nzvJv{&b literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi/base-spent.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi/base-spent.png index 3ed5e72b69a7fe79fb446fa98b0dfacb8e29efa2..2e79a9fc148619b0f2a5afb5e92a0c11de0d4d61 100644 GIT binary patch delta 106 zcmV-w0G0pB0m=c8XJbP6v76^eM2v_~Ne3R-K}djkN*7$5K5Jpn`nW(EK-GlGtlc<;+T8RynQ?|o_87J!^{i7}p7a!#$AJLi7aB7&-# zI$;txB&H+CIg?TXAf-gkd0Bz`<`ICKZNufoig>jFAQG1m0C>2&2EKs?K5vQJjVb3i zXW;GYh4)vX?|arC>%C^c)BzD;cMY9$h{&=6holOa2qB=VWi|I1scH!!n6l0+Mbk8u quIv81g7Z8-jpO)ivZz!l|C%44*G)O|1xqae0000z7q8$nO`E>&x0H)Qq42Ny2FBPL5^8f$< delta 190 zcmV;v073t-0$mZ{VI30~9GGs5hz~J|k82loF*iXOhNo s^t!GuUcqUaHhtf3DHnx8q42Ny2JM4RhW+?!RsaA107*qoM6N<$fA_6n3 zRzf9kPgGkVBJkb=0KE4Qk;e)QM@Il#3_dgTezxcz)cy5`a5kM>$7=-agD&UkXFw&e zYck9iOKg6}SbZO{Ycl+uvd0M!5iZxz7y}|wHCGGVlO&+RIXDMqj+f7fnWJ+~mDSZ0 tg%Dy<6gRJ6+qPd-Rn1iviA3V9IRh+#P3v*49ZmoM002ovPDHLkV1nieP_O_1 delta 191 zcmV;w06_n-0-s~J)6q6J#$4w_1ZGyP zgi7F^sJ1{v;JpU`c<&)1j};h>jsUh8d}iqVY|%fc`|A(kY&yA)*9h1LUCz_bfJ$K3 zWSB3O*!+&M`aWXUWcWK}j}sswT&|%p21KN4t`@i_NkD~j4mivlFP{-JN9UX>tE(vr tA;h96ZeGE*ZNI9jnyV}liA3V9IRm!mP3uCvgWCWA002ovPDHLkV1l+pTEGAR diff --git a/Resources/Textures/ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi/heat.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi/heat.png index 875f8a3cc783b1d7ee673c7ffd49a9198d091366..2ee5f0e2ef5f2de66cfdca32091f538d8baefb08 100644 GIT binary patch delta 193 zcmV;y06zb<0<{8=e1AgWFVnVd4k6^9WL#JaLkPL9YXDR=_kBOJh=Nuwp z+6j}uDKQ;^s*+LyAf<$=o>$;@b%1Hh&8*^m+OnAJb7&sIhr26a0X5fRD9&qzdajM0>} vuoMl$kejCY_6m;U_}F#b+GJ5E6#g}zj@eQ*bfdO300000NkvXXu0mjfr7m3^ delta 193 zcmV;y06zb<0<{8=e1F1Urfu6CLdZYKxUd$65OQ7D0H|v2`+jE0nOmEC@4wd0IYh*? z6DEOEVmbmcUQm!T=VieplXx&^%*b; zZ1xrFrw`ti_dNFpHv5X*{PKJP&N+_P(0h+_&eYs2a7v1Ri8>e~B9f1vk%;6NqbX}) vDH?_$H%;^H6&%O$vFp0E$)Zpw6#g}zY#vfI0_bPb00000NkvXXu0mjfi^W}d diff --git a/Resources/Textures/ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi/smoke.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi/smoke.png index 430e616cc54c3a76df293fe0d81e4d1eae112bf6..40df04afdb20b3c462ca60f6c93d633e86bbc91e 100644 GIT binary patch delta 186 zcmV;r07d_!0;2+uaeq|)GSf79jM0Ch@x>;_7`^K{0DzhKvMe8r&W(LMgmA?o0#&6d zK^b@_R13@ur4#@_DFtRm8=(4@b9Mk|ng-jpVc&NEz%UFi>(N8lw(V1Vns}98p8=`` zs_G(waU3zv^ECs^DpC~?5u9rnLV$=cGQ5FzQVmd~l%T49eltd@>M12k>yt@Z*VX&J of4YLlaolsx-;|3=rSh+N07|}3oO2KMwEzGB07*qoM6N<$f>9$=R{#J2 delta 186 zcmV;r07d_!0;2+uaew?}rfKpRqyI$Xi%pC%de?OT05kJtSw0w@8~b<&;fh5Bs!COY zGVo5Q7MK}IDFA>{3e1c)K=m!>>;TX-4YqB=zV85lVHjT4qld6<+o$+6@hZPQ15^uC z)kOs3IAWgXYX+EAq$(gHIM*0=EK?et*n8(=<)8)~0JT9<_ulq2%pawry~aGe^%a>F#rIs>*_2XhW^6N-?`5o zDB=c(J)y2^9EJ}RQSd^*82+xMssIsT9z$ach)5%&H*ia`0Xh}VIWTjYKO<&N&N-D< vp-BoMq^hdUUcngSwr$&;%0(uV`PX~{dn8d`(*m7P00000NkvXXu0mjfwa!uM delta 193 zcmV;y06zb>0=EK?et&zWX_{oMP1k5VY7?!ssVqwXfQY27>mD>ZEA8RNm{UwdU}jY% zR0eK|>Iy^z-g^Lm_Z}j$tbwnmcZ?GdKA$m8M-0;cth_B_003Us)mc0Y{e_*sbDup> z#0?I6LS5H53?C?>;DvxO{9Q{`0V2XYhQ=5Wkw!*u;Fe?qDmt8VVCFP`M$DX?b1JPu vlN3ToRaKq6f-%Nz+qOHEi%cey`PX~{fUZ$rPpUX?00000NkvXXu0mjf#tl*S diff --git a/Resources/Textures/ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi/stun.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Ammunition/Explosives/40mm_grenade.rsi/stun.png index d2cafc264a132ecd6add7e9450943b30b36e875c..46539d089dfc40172472e773b368d21ea28bf651 100644 GIT binary patch delta 190 zcmV;v073t;0V!$)l$f?aRY@rUkWxZb&nvLMeP#m2`kHC?!It;0iD7jf0f4*v<~VreDDg`!^9)ok z4{Y9qwr$z0*Ho(90Fxoh)BzFUa1EVvh=?V|E^tbUfQc9*-Z%Sv_>8>wImT$psw_q0 sIOe8le!PP7JU{k*|75Z#6bk>EPjxs>YR1>tO#lD@07*qoM6N<$g8QdjegFUf delta 190 zcmV;v073t;0_YgEUkqhgk0A(0IHgYVOUsluB?kY=f1}xg7@Ck z36sDnF>QgWl2QU7rG%=US73kp%mj?}HPh~cE$?3w!|FT&0C)Gzaq!Af;+I_J8K_jM0=;S&GJS s%uUn$cm?Nqe(d}H$z)L|6bk>EPk*aUYPaJeDgXcg07*qoM6N<$f}aFiO8@`> diff --git a/Resources/Textures/ADT/Objects/Weapons/Guns/Rifles/xc67.rsi/base.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Rifles/xc67.rsi/base.png index f1353406806e593ea29424cacb757b66e04375b9..02236c1be596412f8db4d6b3ed755703ef90fdaf 100644 GIT binary patch delta 433 zcmV;i0Z#s#1lR+RF@KUtL_t(oh3%40F9Sgsho6mAi9fBhHQGi@xDXB!cNbR&H}MI4 z2_M1NaB!1I93+CHgtL1Sv6PAx>7=8K1G9G9E`mfN^IYbAXWpIP@11?Y;cz(q81E}Z zQcA=~+0?EBlv2p?N#gOz>G7BD`IZ4GrFqmXdNclqb+%@0Wq*#VoBNLQ(PB1{uW#&l zpBj)-8i2k`f3$ZO)}wehR{-GQ;hw?4EKS{Dd2xcR-7^4Imu6Dq(PEbMjUCUkB5B0M zo4V1Fx3e%W5_x`jAocF8-81}lkz6hp#bFpGK3KfG)A~n6H#dTz?c7wa@MM^a8M#FM@7G=Z`x1uZ=N)&s|ujQW#2I&x2bww@+SYKnP*% zzqC)Plmehut9kG~3tDTYr)D`k+V_MICSLPhqS0>ZMu)H!7b9iDFhpz3;nDt&1iKor z;_cnU#qH~qOBDm~^xXP!_mP2a;&wki6G0ICYWD#CXDVIT&a2hxuZu%$2GX!|;cz${ bj(^Jwi#N|t@K$F{00000NkvXXu0mjflJ44U delta 500 zcmV{=RSrQ3Ky<3As&zou z^?}3t)v{H8ZhuD600A?pAiOlfu#zyO`)Vo<2u1+dTr8y>mE{i3ggpJTOw)wyngXSA z8*=Ll(jA=@iqHKX5CJd)T-|P$_IkZeMqDPtFkmaY1Gj~1Iw#tUA{5KZD%)p>1%Scr zfjPLglmaYAyVHbPtwvB@0N4%{mJKfgP!xrNbHo4oWbKZJssx&(_?1i1Q+{9s(@2_bDiCq&CLgvSoZ&L9mSsRpMw!6 qA#21x2XITk2k;f}74Q|9x&l7}Ki{L92qhr^0000V*bT+p@9Tlaty0wgA8U$Zm2v-94}&H@@58XA8L zW0oLFDM&ge+$RT&G0?3YsCMK2Zl*kQ380jU0Usg~HGhrsV}CBr4)OT>GIpLx#RGn^ zR57Lspp*&#SdFg9y}s9#cEYj)ek>NlX<-}XY7+o(ezG5GXHsz#OBKWLNy4C#zwy^G zpD`8?aC}4p_mheB(A?!}6Xqz1Wm(epJTGve(COedn+=E?71VZmc<4rvxB2%v>T_)7 zl2Vw-7z-p(Nq_zJnkx|iz;!YO@S!{(@ZehuApn@@dtK!1jnK92^l*9A_?iJih)7tr ztN?&)tLwT3@G}dXbL{ONpjN*z2q8j^nHO@j)%R4BQc49$=iqrBIOnLU6m3YbLh@2fN6IL=b52LN+g6)Jw^tyXL4!FMr!MT;_6Yd^8%3(C0<- zCeQ(9{poZenNp-Pi)@Y#w&3~Yb-;FEZnp2;@yQvBEd}5ur_(LF={ZVkS>X4os>1$W z0Zz|r%;vCM68=UYgh)^jQF>T!S|83kt3SW*bUNN10d}|bK3AFav`{$&WdOWWP1C#s zwr%$v-g&Hh^?#>kj54BGr&c%T9(C(s7#LIzmUebq2&mKlml+uLfd8s?H4b!0OIxs2dB!E0(6*6 z0$;*M@I^ce-UNFr=(&QT(2K!np|QnctVU+b#O>D2rZiHN>?O%&XXcxKXD5llh(~P1 z@gV|;6!=>TtgfuPcxrBLuR{YL$WbnrV*umHiO?Vd0~m(Ef`4n8=CzJmtrpl`)^C&! zFza`x1BqnZw`b9s!~IQoe17R$J3l+!Gk0`+%3}Kh@RE~ttM%3@wGP;dl91;FhdoR7~AyZR|W z0O%k6TwYcBPMs&E7@Vi40uvh#!m9vO-P5-ZkU9t;>v}2(0+1@;SKhSGd_juqRRENP z?E9f?#j5ic1OR==3NaJ_Dl*w|^h;uB04i2hG0GtR4*+IJ{|bZrCxoJas!)Hu1|on+ dfngN*0u*k?II=h!pGN=y002ovPDHLkV1fyo`nmuB diff --git a/Resources/Textures/ADT/Objects/Weapons/Guns/Rifles/xc67.rsi/wielded-inhand-left.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Rifles/xc67.rsi/wielded-inhand-left.png index 28796011f65c22909ed32d6f2fe2101e2441359f..5c24ca5f496b73c5c6f33e3279c6e086268e6778 100644 GIT binary patch delta 1104 zcmV-W1h4zb2=WM!F@G#cL_t(|ob8%VXd6cq#=lLZ6)VM7UWax=Z9;DaHg244gXfnH>6W4kg~TaTrnl^rcwDV-k5$h)iA zKl+o<(D{LpEX|vl_s!c~Nu&tFt<(P(39yNa#tDga<>yE+iWGz;i? zedP2!dR~9~fweL7^1`{{Z8v3$I=P)hl<`Vk_7pFCdY zTYuYCJbF+X*yG~8VHn8id0bz&VVVV8U*8BMoZ@i}4PaRKsGbC1a{nRH(h|0^A7MT3 zy=8&VWqx1S2u-`uXHOsU=PxP)vBf@KzCM+TZkmOOsvt5j&LY2kD-&st3;G{=@LS$# zHYpQ6N%U}~g?kN>gpd7Fn2Y|?l=+0UvwssX#xPeNQj zLK;^))*U`P+Sd+`_O+azhwHkDNgN#P2YzRaX|C&z>@WIz6AZ(E=t-#C=bGqAi0elf zrC%vl03e-3E>xD?`NuIh{ldo))sHZW;E4hVi&=L1_wTLo-``XMB`=#}91(=@;Ys!4 zV#NA!eF$L^{}6H5BJ&At3*pp^2YDo`jC3WY+UNXtLg W*>A&7v_Y2u0000(u5e8iBV4ZC+^x{J4 zC6IHj`3G{#Dd(JW%C)!LOm8XpR#HPRf|fuoGPbc@1+1;dR?w=B7Oj*{4`Jlp)$9-b zXxhO0fY6VfAMd?+Gh_UH06`E0K@bE%5Ckzj>uVeGzqVl-jDJ}N;G9bUD4Asdz|rx+ z%wv8^3c4SkKE6L%&5NsUBRPe)(Z!idkD4I9j`$6wtG4QLEs#Nndo6U)W8}{SL zv!AqmZ|OQ+Ty^pMMI9GcUF_~Pu)Eg)0POBHMgg(y3I@RtC9{k{FdV(+xfM9)(zYuo zndMQ2W%20YPJhH{|+HIv$e$(v!yK83RX;;IYAm=r=pGC`XbJKJB&#_3Kzo#0;<(J7=9R_<(?aN?`~+F=y+}PgI?w; zsy3>R5W*;$1r*H!B>tY%cL2bmvy|vOkZ=eBH>dgf+J=m;SQ5YN|2)=4^<#`hZVMg0 z???Io0DoIvf#-P$f*@;pEm^mcHUkvvYa6m3^k7+5>Lf|QQBJEiLI|VdwY6iYAjh|c z=XvM{J-Dtrar);ukP|Zi0364Gxa^HxKUUfO9U{@(RSII~PX@f*=Tj zAP9mW2!bF8g7`f793}EpU0@QFhVZGFSFlt6qpK9vxJ3T))!CRl9%c{>r_%BA!a0}o zsz*rd{OIA1+}&&7!M)l@9#@|&%RfCNz8&%!`tMd||d|(_M9~dRG41eGEGo3g*JcxW3LKwd9PpmJ7YZENXf~rYq zx#xzeNl2?lnB+Ffyaw|~&T=OJ8X iWdT7D1VIo)Uj6}U2Vh_*=B$wb0000S1nt=5brIG4fNL0}ZJ zF{VSHyN%q&EFlS?K=(1VIo4K@bE%5bq#TmcgcJvVRxNm$<%q4c)GRCr^IM z6n`Gcl)(C0nE}Aa8v+0<%X+sKz%UFJ{ch|{kW*yb`R-G6x`WWZ%O5TI+dtp`Gxc2e z?%ww2$r2aTIQAxJwGR_xFQh&2`dXQdy$SeVUMXPgO;9YpPO{S-pi*rB04mi6D%A!$ z-2s02qmE8@5PwQ)7WeMnW;`yK{Et6ur;5)j1>}_iip3@235y~F;xh|`OMK)F{bc#) zoFe;|!%_bf-+W=igtH4@$2ulzwfAjnv{#L zE3Xv%&q=vSeBx#8;?$sL&-X%NudI}W2V;z3<6{+#=6^8&U~}~YG@8eu|F!x->Qdg` z`h+!_$C$NPaRfC^&c+bs)pvUSu|t=@$Qxqh4bgXc=sUfsz>SSETJ1w=ayCY(bQL*8 zMyYfa?Y~=6t$rZcwk@fuiWlt(R8>W*r(jvTm??PxsMQZ7k?=Gyyh2WqkyB*Ywk`2o zcy3YT;C~0#bparDXquK)e+W&}Qr*d?v{{xUDtBNyS6MhJFn>7fP3hyY}C^OFlBb$`b-A^e7OAn)YwY3AvAgt#YBY!%RG2y(u#=_5+&#h z_MIN&_i{7GGsbZCY62jeJ)bBf+B=Y@XMZ5BUm%Os#uwgo-B8?@+h4PXwFi=}>&&>e zibs#@k|+*%Q#G@k=G4Ceyl)^1?-}6z0C?TLah7FC zuInPN6!7f%o|I&>r(OV&7$CW4AgvG)qWO5^)2wRBV$Y{qfM82WT+aX}YL(C1CrA*N zU~v9NkLyx&J|LStpSS>`-T{$kAM6*HM@U+tT6lkg=w`jBJ)aqo5P~2Gf*^?V%D-XH VVo8s$?~4Ec002ovPDHLkV1loADBA!4 delta 1065 zcmV+^1lIfU2+IhNF@FU~L_t(|ob8&yYui>F$G@+WW#oEMSXY(Qbly6WkX#01gTNT1 zrR);uZX>s`%Z}Trr=5G+Y5NDpZaxouE7V6rdv<6`QZ$G)t9G!Q#1G3(-wx%elKgBv z#n~3d?*k@s^nQBZ-_uXB(Dw%r1VIo4K@bE%5ZSD)ZixR{!+%A>@(h;AkHR4Uz;)eR z@t2WY2~?}qsk1*0Cn%T(zW?SEbh?AYz8mi^McY69{D<~j4zVFXGD~{s`Sw*`$oA~uNKiYTHKh4S|(p5A|(f6#}n4EaozBV=J z`HQ`T*qbXA<-vpySpU#M>);pwuzCAkv<{9Fe;dtx?SE3<-uhUy4vsNzv1Sq1I5`_b zl~+ILMaNED0;6z3 zvhdQIz_Ki~dnT6cYq^pKfJSqlsf6nw@EQfvK*2QN`#zJo$lTHx@h_Zn0GPS*j~kCN z6LDRa$$yGUS5O`ni7lEX*tQMVb)#Gy#}RU0oTvh1S;UioQfj1Jk)0%2Bbwc_)`}&JhH`dBXt!K@dcjWq)3DAJP_jlB-s$LRP{5;i-@y2!bF8 zf*=TjAP9mWh|9-C+wyPg+p-8vAeSw+4OSzjnmvv z&VRko0<5iW2q`EnMxG5RpjL0;$8Wc^7a_f{X-^Npl-c>^rw#z%z2&P@V{7%6(&)() zlNJ&$^Z1$36*Egnn)r3z4|*`(Da;)&guvPB34na|e5R0e?|@Fvz^s0OJXV`rc+Pnu z?#}i-@woAbIgTT$AKb>1r%k4c1Kw86Jb$NI`&U5r4WyAh1F~PB?Hw}NFJM_#qE8?X zob##V0pQuQy}5C&>oU$cie?GVU+l3gn_YVWRAPYao&jAUDpd2y#;1AJl*gXeT7Y;< z$*i6MN!ltu@9*}k1mp8RdD>*@`G9=(eC7hEdIwaVeY{`bJVJCyYmxm4s+;wq_9A?4 jR6+=XAP9mWE-QZnz!6j&XB)o%00000NkvXXu0mjfcS#vB From 2048fbb60bffdb6b7e7781c95a525af5fdb02f0e Mon Sep 17 00:00:00 2001 From: Eugeny Date: Thu, 12 Dec 2024 05:29:31 +0400 Subject: [PATCH 26/46] =?UTF-8?q?=D0=BC=D0=BE=D0=B4=D1=83=D0=BB=D0=B8=20?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=B2=D1=81=D0=B5=20=D0=BE=D1=80=D1=83=D0=B6?= =?UTF-8?q?=D0=B8=D0=B5=20+=20=D1=88=D1=82=D1=8B=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Objects/Weapons/Guns/Rifles/rifles.yml | 1 + .../Objects/Weapons/Guns/Basic/base_pka.yml | 7 +- .../Weapons/Guns/Battery/battery_guns.yml | 30 +++++++- .../Objects/Weapons/Guns/LMGs/lmgs.yml | 15 +++- .../Objects/Weapons/Guns/Pistols/pistols.yml | 39 ++++++++++- .../Objects/Weapons/Guns/Rifles/rifles.yml | 15 +++- .../Objects/Weapons/Guns/SMGs/smgs.yml | 15 +++- .../Weapons/Guns/Shotguns/shotguns.yml | 64 +++++++++++++++++- .../Entities/Objects/Weapons/Melee/knife.yml | 37 +++++++--- .../Attachments/under.rsi/combatknife_a.png | Bin 0 -> 237 bytes .../ADT/Attachments/under.rsi/meta.json | 3 + .../Melee/survival_knife.rsi/icon_a.png | Bin 281 -> 207 bytes 12 files changed, 203 insertions(+), 23 deletions(-) create mode 100644 Resources/Textures/ADT/Attachments/under.rsi/combatknife_a.png diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Rifles/rifles.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Rifles/rifles.yml index 2b17573f6ff..17baa3cfc90 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Rifles/rifles.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Rifles/rifles.yml @@ -218,6 +218,7 @@ - ADTAttachmentM90UnderbarrelShotgun - ADTAttachmentVerticalGrip - ADTAttachmentLaserSight + - SurvivalKnifeAttachment rmc-aslot-rail: startingAttachable: ADTAttachmentT2Miniscope whitelist: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/base_pka.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/base_pka.yml index 33918811aca..646e8db669d 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/base_pka.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/base_pka.yml @@ -49,14 +49,11 @@ delay: 1 - type: AttachableHolder #ADT_Tweak slots: - rmc-aslot-barrel: - whitelist: - tags: - - SurvivalKnifeAttachment rmc-aslot-underbarrel: whitelist: tags: - ADTAttachmentMicroAccelerator + - SurvivalKnifeAttachment # rmc-aslot-stock: # whitelist: # tags: @@ -65,7 +62,7 @@ # tags: - type: AttachableHolderVisuals #ADT_Tweak offsets: - rmc-aslot-barrel: 0.59375, -0.15625 + rmc-aslot-underbarrel: 0.315, -0.209 - type: MeleeWeapon #ADT_Tweak resetOnHandSelected: false attackRate: 1 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 be0cabd26b1..543a8150a8c 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml @@ -226,7 +226,7 @@ - type: entity name: laser rifle - parent: [WeaponLaserCarbinePractice, BaseGunWieldable, BaseRestrictedContraband] + parent: [WeaponLaserCarbinePractice, BaseGunWieldable, BaseRestrictedContraband, ADTBaseAttachableHolder] # ADT TWEAK id: WeaponLaserCarbine description: Favoured by Nanotrasen Security for being cheap and easy to use. components: @@ -235,6 +235,34 @@ - type: HitscanBatteryAmmoProvider proto: RedLaser fireCost: 62.5 + - type: MeleeWeapon #ADT_Tweak + resetOnHandSelected: false + attackRate: 1 + damage: + types: + Blunt: 5 + soundHit: + collection: GenericHit + - type: AltFireMelee #ADT_Tweak +# ADT TWEAK START + - type: AttachableHolder + slots: + rmc-aslot-underbarrel: + whitelist: + tags: + - ADTAttachmentLaserSight + - SurvivalKnifeAttachment + rmc-aslot-rail: + whitelist: + tags: + - ADTAttachmentMagneticHarness + - ADTAttachmentReflexSight + - ADTAttachmentT2Miniscope + - type: AttachableHolderVisuals + offsets: + rmc-aslot-underbarrel: 0.345, -0.125 + rmc-aslot-rail: -0.1185, -0.0325 +# ADT TWEAK END - type: entity name: pulse pistol diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/LMGs/lmgs.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/LMGs/lmgs.yml index c7db7f3879a..e0a1b5cab6f 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/LMGs/lmgs.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/LMGs/lmgs.yml @@ -68,7 +68,7 @@ - type: entity name: L6 SAW id: WeaponLightMachineGunL6 - parent: [BaseWeaponLightMachineGun, BaseSyndicateContraband, ADTBaseMagneticGun] # adt tweak + parent: [BaseWeaponLightMachineGun, BaseSyndicateContraband, ADTBaseAttachableHolder] # adt tweak description: A rather traditionally made LMG with a pleasantly lacquered wooden pistol grip. Uses .30 rifle ammo. components: - type: Sprite @@ -83,6 +83,19 @@ steps: 4 zeroVisible: true - type: Appearance +# ADT TWEAK START + - type: AttachableHolder + slots: + rmc-aslot-rail: + whitelist: + tags: + - ADTAttachmentMagneticHarness + - ADTAttachmentReflexSight + - ADTAttachmentT2Miniscope + - type: AttachableHolderVisuals + offsets: + rmc-aslot-rail: -0.2275, -0.1575 +# ADT TWEAK END - type: entity name: L6C ROW diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Pistols/pistols.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Pistols/pistols.yml index fbc1f9e8426..e75f4273760 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Pistols/pistols.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Pistols/pistols.yml @@ -70,7 +70,7 @@ - type: entity name: viper - parent: [BaseWeaponPistol, BaseSyndicateContraband] + parent: [BaseWeaponPistol, BaseSyndicateContraband, ADTBaseAttachableHolder] # adt tweak id: WeaponPistolViper description: A small, easily concealable, but somewhat underpowered gun. Retrofitted with a fully automatic receiver. Uses .35 auto ammo. components: @@ -100,6 +100,17 @@ containers: gun_magazine: !type:ContainerSlot gun_chamber: !type:ContainerSlot +# ADT TWEAK START + - type: AttachableHolder + slots: + rmc-aslot-underbarrel: + whitelist: + tags: + - ADTAttachmentLaserSight + - type: AttachableHolderVisuals + offsets: + rmc-aslot-underbarrel: 0.235, -0.00875 +# ADT TWEAK END - type: entity name: echis @@ -138,7 +149,7 @@ - type: entity name: cobra - parent: [ BaseWeaponPistol, BaseSyndicateContraband ] + parent: [ BaseWeaponPistol, BaseSyndicateContraband, ADTBaseAttachableHolder] # adt tweak id: WeaponPistolCobra description: A rugged, robust operator handgun with inbuilt silencer. Uses .25 caseless ammo. components: @@ -184,10 +195,21 @@ containers: gun_magazine: !type:ContainerSlot gun_chamber: !type:ContainerSlot +# ADT TWEAK START + - type: AttachableHolder + slots: + rmc-aslot-underbarrel: + whitelist: + tags: + - ADTAttachmentLaserSight + - type: AttachableHolderVisuals + offsets: + rmc-aslot-underbarrel: 0.16, 0.035 +# ADT TWEAK END - type: entity name: mk 58 - parent: [BaseWeaponPistol, BaseRestrictedContraband] + parent: [BaseWeaponPistol, BaseRestrictedContraband, ADTBaseAttachableHolder] # adt tweak id: WeaponPistolMk58 description: A cheap, ubiquitous sidearm, produced by a NanoTrasen subsidiary. Uses .35 auto ammo. components: @@ -210,6 +232,17 @@ - Burst soundGunshot: path: /Audio/Weapons/Guns/Gunshots/mk58.ogg +# ADT TWEAK START + - type: AttachableHolder + slots: + rmc-aslot-underbarrel: + whitelist: + tags: + - ADTAttachmentLaserSight + - type: AttachableHolderVisuals + offsets: + rmc-aslot-underbarrel: 0.17, -0.014 +# ADT TWEAK END - type: entity name: N1984 diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml index 8bb8e2e9598..e70bce8e7b3 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml @@ -50,6 +50,15 @@ gun_chamber: !type:ContainerSlot - type: StaticPrice price: 500 + - type: MeleeWeapon #ADT_Tweak. Для ШТЫКОВОЙ + resetOnHandSelected: false + attackRate: 1 + damage: + types: + Blunt: 5 + soundHit: + collection: GenericHit + - type: AltFireMelee #ADT_Tweak - type: entity name: AKMS @@ -102,7 +111,7 @@ - type: entity name: M-90gl - parent: [BaseWeaponRifle, ADTBaseAttachableHolder, ADTBaseMagneticGun] # ADT TWEAK М90 ОБР ЯВЛЯЕТСЯ КОНТРАБАНДОЙ СИНДИКАТА XDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD + parent: [BaseWeaponRifle, ADTBaseAttachableHolder] # ADT TWEAK М90 ОБР ЯВЛЯЕТСЯ КОНТРАБАНДОЙ СИНДИКАТА XDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD id: WeaponRifleM90GrenadeLauncher description: An older bullpup carbine model, with an attached underbarrel grenade launcher. Uses .20 rifle ammo. components: @@ -144,6 +153,7 @@ - ADTAttachmentM90UnderbarrelShotgun - ADTAttachmentVerticalGrip - ADTAttachmentLaserSight + - SurvivalKnifeAttachment rmc-aslot-rail: whitelist: tags: @@ -153,7 +163,7 @@ - type: AttachableHolderVisuals offsets: rmc-aslot-underbarrel: 0.3125, -0.0625 - rmc-aslot-rail: -0.0325, -0.0325 + rmc-aslot-rail: 0.0, -0.0325 # ADT TWEAK END - type: ContainerContainer containers: @@ -221,6 +231,7 @@ - ADTAttachmentM90UnderbarrelShotgun - ADTAttachmentVerticalGrip - ADTAttachmentLaserSight + - SurvivalKnifeAttachment rmc-aslot-rail: whitelist: tags: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml index 8752caafc09..fc578280015 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml @@ -81,7 +81,7 @@ - type: entity name: C-20r sub machine gun - parent: [BaseWeaponSubMachineGun, BaseSyndicateContraband, ADTBaseMagneticGun] # ADT TWEAK + parent: [BaseWeaponSubMachineGun, BaseSyndicateContraband, ADTBaseAttachableHolder] # ADT TWEAK id: WeaponSubMachineGunC20r description: A firearm that is often used by the infamous nuclear operatives. Uses .35 auto ammo. components: @@ -116,6 +116,19 @@ steps: 6 zeroVisible: true - type: Appearance +# ADT TWEAK START + - type: AttachableHolder + slots: + rmc-aslot-rail: + whitelist: + tags: + - ADTAttachmentMagneticHarness + - ADTAttachmentReflexSight + - ADTAttachmentT2Miniscope + - type: AttachableHolderVisuals + offsets: + rmc-aslot-rail: -0.0325, -0.0325 +# ADT TWEAK END - type: entity name: Drozd diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Shotguns/shotguns.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Shotguns/shotguns.yml index a3124155245..6b5f1387c8e 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Shotguns/shotguns.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Shotguns/shotguns.yml @@ -46,7 +46,7 @@ - type: entity name: Bulldog # Don't parent to BaseWeaponShotgun because it differs significantly - parent: [BaseItem, BaseGunWieldable, BaseSyndicateContraband, ADTBaseMagneticGun] # adt tweak + parent: [BaseItem, BaseGunWieldable, BaseSyndicateContraband, ADTBaseAttachableHolder] # adt tweak id: WeaponShotgunBulldog description: It's a magazine-fed shotgun designed for close quarters combat. Uses .50 shotgun shells. components: @@ -100,6 +100,37 @@ - type: Appearance - type: StaticPrice price: 500 + - type: MeleeWeapon #ADT_Tweak. Для ШТЫКОВОЙ + resetOnHandSelected: false + attackRate: 1 + damage: + types: + Blunt: 5 + soundHit: + collection: GenericHit + - type: AltFireMelee #ADT_Tweak +# ADT TWEAK START + - type: AttachableHolder + slots: + rmc-aslot-underbarrel: + whitelist: + tags: + - ADTAttachmentM90GrenadeLauncher + - ADTAttachmentM90UnderbarrelShotgun + - ADTAttachmentVerticalGrip + - ADTAttachmentLaserSight + - SurvivalKnifeAttachment + rmc-aslot-rail: + whitelist: + tags: + - ADTAttachmentMagneticHarness + - ADTAttachmentReflexSight + - ADTAttachmentT2Miniscope + - type: AttachableHolderVisuals + offsets: + rmc-aslot-underbarrel: 0.365, -0.1075 + rmc-aslot-rail: -0.02375, -0.0325 +# ADT TWEAK END - type: entity name: double-barreled shotgun @@ -138,7 +169,7 @@ - type: entity name: Enforcer - parent: [BaseWeaponShotgun, BaseGunWieldable, BaseRestrictedContraband, ADTBaseMagneticGun] # adt tweak + parent: [BaseWeaponShotgun, BaseGunWieldable, BaseRestrictedContraband, ADTBaseAttachableHolder] # adt tweak id: WeaponShotgunEnforcer description: A premium combat shotgun based on the Kammerer design, featuring an upgraded clip capacity. .50 shotgun shells. components: @@ -153,6 +184,35 @@ - type: Gun # Corvax-Guns soundGunshot: path: /Audio/Corvax/Weapons/Guns/Gunshots/shotgun_metal.ogg + - type: MeleeWeapon #ADT_Tweak. Для ШТЫКОВОЙ + resetOnHandSelected: false + attackRate: 1 + damage: + types: + Blunt: 5 + soundHit: + collection: GenericHit + - type: AltFireMelee #ADT_Tweak +# ADT TWEAK START + - type: AttachableHolder + slots: + rmc-aslot-underbarrel: + whitelist: + tags: + - ADTAttachmentVerticalGrip + - ADTAttachmentLaserSight + - SurvivalKnifeAttachment + rmc-aslot-rail: + whitelist: + tags: + - ADTAttachmentMagneticHarness + - ADTAttachmentReflexSight + - ADTAttachmentT2Miniscope + - type: AttachableHolderVisuals + offsets: + rmc-aslot-underbarrel: 0.2875, -0.125 + rmc-aslot-rail: -0.0375, -0.1575 +# ADT TWEAK END - type: entity parent: WeaponShotgunEnforcer diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml index 5e9def6bd99..ddfa665d9fc 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml @@ -89,14 +89,14 @@ - type: entity name: combat knife - parent: [BaseKnife, BaseRestrictedContraband] + parent: [BaseKnife, BaseRestrictedContraband, ADTUnderAttachmentBase] # ADT TWEAK id: CombatKnife description: A deadly knife intended for melee confrontations. components: - - type: Tag - tags: - - CombatKnife - - Knife + # - type: Tag + # tags: + # - CombatKnife + # - Knife - type: Sprite sprite: Objects/Weapons/Melee/combat_knife.rsi state: icon @@ -117,14 +117,35 @@ sprite: Objects/Weapons/Melee/combat_knife.rsi - type: DisarmMalus malus: 0.225 - #ADT add start +# ADT TWEAK START - type: ThrowingAngle angle: 225 - #ADT add end + - type: Tag + tags: + - SurvivalKnifeAttachment + - CombatKnife + - Knife + - type: AttachableWeaponMeleeMods + modifiers: + - bonusDamage: + types: + Slash: 5 + Piercing: 12 + - decreaseDamage: + types: + Blunt: 5 + - type: AttachableWeaponRangedMods + modifiers: + - accuracyAddMult: -0.05 + - type: AttachablePrying + - type: AttachableVisuals + rsi: ADT/Attachments/under.rsi + prefix: combatknife +# ADT TWEAK END - type: entity name: survival knife - parent: [CombatKnife, BaseSecurityCargoContraband, ADTBarrelAttachmentBase] # ADT TWEAK + parent: [CombatKnife, BaseSecurityCargoContraband, ADTUnderAttachmentBase] # ADT TWEAK id: SurvivalKnife description: Weapon of first and last resort for combatting space carp. components: diff --git a/Resources/Textures/ADT/Attachments/under.rsi/combatknife_a.png b/Resources/Textures/ADT/Attachments/under.rsi/combatknife_a.png new file mode 100644 index 0000000000000000000000000000000000000000..4c92b4dc2664fd8773fe0037d71b57f29238c5be GIT binary patch literal 237 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}%ROBjLn2z= zUQpyd6d-c+=HBGyiy?tkv&Zv_s! le`~%s+ztZT@oM>8#_5yQFWj;0Dh4{4!PC{xWt~$(69DXRWH0~# literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Attachments/under.rsi/meta.json b/Resources/Textures/ADT/Attachments/under.rsi/meta.json index 47b23158b5f..68b63235826 100644 --- a/Resources/Textures/ADT/Attachments/under.rsi/meta.json +++ b/Resources/Textures/ADT/Attachments/under.rsi/meta.json @@ -49,6 +49,9 @@ }, { "name": "lasersight_a" + }, + { + "name": "combatknife_a" } ] } diff --git a/Resources/Textures/Objects/Weapons/Melee/survival_knife.rsi/icon_a.png b/Resources/Textures/Objects/Weapons/Melee/survival_knife.rsi/icon_a.png index 28f96dcc283cc9e4874ad46afab2cb1aeb8f3a22..f02f0a4b5675109203952f191676292280f76ced 100644 GIT binary patch delta 166 zcmV;X09pT;0?z@EF@K3kL_t(oh3(QY3Irhx1<;IaYffO116X*7kZXBG?;&>SooWjg zmSM+*h2_6e2>)v&0ssK`Cn7RGojG;_bIwbkyHg0^a*mlP#z?hRdhCR!l&JT<6kuj* zt-ZZiDP=yxRrR=Cz}>0$PGgMa+|0<#E?1$dTdz+dGGBLo=N}Jz)z1q6007)^0y%*u U`@+9@NdN!<07*qoM6N<$f|OTD6aWAK delta 240 zcmV4 zGn-KC@(>euX=X|u^M8Iq=%8_Rjq`y3$N(8217v^<+%_=JvpDC9g(Kmg7;>}mUcX+cWqF&HZqj^j}i zR4jx5Yi$G&#;0kjHh{rc-(MaYBmrKP4s|LsgX8}r`1HjJ@VF}_dx1ieZ q0}C%t@&g&g76d>B$N(8=Zr}w^zdRxJMy>$>0000 Date: Thu, 12 Dec 2024 21:40:17 +0200 Subject: [PATCH 27/46] =?UTF-8?q?=D0=BC=D0=BD=D0=BE=D0=B3=D0=BE=20=D0=B1?= =?UTF-8?q?=D1=83=D0=BA=D0=B0=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/AntiLyingWarriorComponent.cs | 8 ++ .../Armor/Magnetic/RMCMagneticSystem.cs | 22 +++--- .../AttachableAntiLyingWarriorComponent.cs | 9 +++ .../AttachableAntiLyingWarriorSystem.cs | 28 +++++++ .../Systems/AttachableToggleableSystem.cs | 7 +- .../Weapons/Ranged/Components/GunComponent.cs | 2 +- .../Weapons/Ranged/Systems/SharedGunSystem.cs | 1 - .../ADT/Objects/Weapons/Guns/launchers.ftl | 4 + .../Catalog/store/uplink-catalog.ftl | 3 + .../ADT/Catalog/Fills/Backpacks/duffelbag.yml | 29 +++++++ .../Prototypes/ADT/Catalog/uplink_catalog.yml | 14 ++++ .../ADT/Entities/Clothing/Masks/mask.yml | 22 ++++++ .../Ammunition/Projectiles/projectiles.yml | 42 ++++++++++ .../Weapons/Guns/Ammunition/explosives.yml | 40 ++++++++++ .../Attachments/barrel_attachment.yml | 24 ++++++ .../Attachments/under_attachment.yml | 4 - .../Objects/Weapons/Guns/Attachments/tags.yml | 3 - .../Objects/Weapons/Guns/Launchers/fill.txt | 1 - .../Weapons/Guns/Launchers/launchers.yml | 74 ++++++++++++++++++ .../Objects/Weapons/Guns/Rifles/rifles.yml | 7 +- .../Prototypes/Catalog/uplink_catalog.yml | 2 +- .../Objects/Weapons/Guns/Basic/base_pka.yml | 1 - .../Clothing/Mask/coif.rsi/equipped-MASK.png | Bin 0 -> 576 bytes .../ADT/Clothing/Mask/coif.rsi/icon.png | Bin 0 -> 411 bytes .../ADT/Clothing/Mask/coif.rsi/meta.json | 22 ++++++ .../Mask/coif.rsi/up-equipped-MASK.png | Bin 0 -> 567 bytes 26 files changed, 337 insertions(+), 32 deletions(-) create mode 100644 Content.Shared/ADT/Crawling/Components/AntiLyingWarriorComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Components/AttachableAntiLyingWarriorComponent.cs create mode 100644 Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableAntiLyingWarriorSystem.cs create mode 100644 Resources/Locale/ru-RU/ADT/Objects/Weapons/Guns/launchers.ftl delete mode 100644 Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Launchers/fill.txt create mode 100644 Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Launchers/launchers.yml create mode 100644 Resources/Textures/ADT/Clothing/Mask/coif.rsi/equipped-MASK.png create mode 100644 Resources/Textures/ADT/Clothing/Mask/coif.rsi/icon.png create mode 100644 Resources/Textures/ADT/Clothing/Mask/coif.rsi/meta.json create mode 100644 Resources/Textures/ADT/Clothing/Mask/coif.rsi/up-equipped-MASK.png diff --git a/Content.Shared/ADT/Crawling/Components/AntiLyingWarriorComponent.cs b/Content.Shared/ADT/Crawling/Components/AntiLyingWarriorComponent.cs new file mode 100644 index 00000000000..a983e677250 --- /dev/null +++ b/Content.Shared/ADT/Crawling/Components/AntiLyingWarriorComponent.cs @@ -0,0 +1,8 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.ADT.Crawling; + +[RegisterComponent, NetworkedComponent] +public sealed partial class AntiLyingWarriorComponent : Component +{ +} diff --git a/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticSystem.cs b/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticSystem.cs index b5809b942cf..dd2a052a735 100644 --- a/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticSystem.cs +++ b/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticSystem.cs @@ -17,7 +17,7 @@ public override void Initialize() { SubscribeLocalEvent(OnMagneticItemDropped); SubscribeLocalEvent(OnMagneticItemRMCDropped); - SubscribeLocalEvent(OnMagneticItemThrown); + // SubscribeLocalEvent(OnMagneticItemThrown); SubscribeLocalEvent(OnMagneticItemDropAttempt); } @@ -31,17 +31,17 @@ private void OnMagneticItemRMCDropped(Entity ent, ref TryReturn(ent, args.User); } - private void OnMagneticItemThrown(Entity ent, ref ThrownEvent args) - { - if (args.User is not { } user) - return; + // private void OnMagneticItemThrown(Entity ent, ref ThrownEvent args) + // { + // if (args.User is not { } user) + // return; - if (!TryReturn(ent, user)) - return; + // if (!TryReturn(ent, user)) + // return; - if (TryComp(ent, out ThrownItemComponent? thrown)) - _thrownItem.StopThrow(ent, thrown); - } + // if (TryComp(ent, out ThrownItemComponent? thrown)) + // _thrownItem.StopThrow(ent, thrown); + // } private void OnMagneticItemDropAttempt(Entity ent, ref DropAttemptEvent args) { @@ -79,7 +79,7 @@ public override void Update(float frameTime) { if (_inventory.TryGetSlotEntity(user, "outerClothing", out _)) { - if (_inventory.TryEquip(user, uid, slot.ID, force: true)) + if (_inventory.TryEquip(user, uid, slot.ID, force: false)) { var popup = Loc.GetString("rmc-magnetize-return", ("item", uid), diff --git a/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableAntiLyingWarriorComponent.cs b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableAntiLyingWarriorComponent.cs new file mode 100644 index 00000000000..4a4d3d6c963 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Components/AttachableAntiLyingWarriorComponent.cs @@ -0,0 +1,9 @@ +using Content.Shared._RMC14.Attachable.Systems; +using Robust.Shared.GameStates; + +namespace Content.Shared._RMC14.Attachable.Components; + +[RegisterComponent, NetworkedComponent] +public sealed partial class AttachableAntiLyingWarriorComponent : Component +{ +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableAntiLyingWarriorSystem.cs b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableAntiLyingWarriorSystem.cs new file mode 100644 index 00000000000..8c554d558e5 --- /dev/null +++ b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableAntiLyingWarriorSystem.cs @@ -0,0 +1,28 @@ +using Content.Shared._RMC14.Attachable.Components; +using Content.Shared._RMC14.Attachable.Events; +using Content.Shared.ADT.Crawling; + +namespace Content.Shared._RMC14.Attachable.Systems; + +public sealed class AttachableAntiLyingWarriorSystem : EntitySystem +{ + + public override void Initialize() + { + SubscribeLocalEvent(OnAttachableAltered); + } + + private void OnAttachableAltered(Entity attachable, ref AttachableAlteredEvent args) + { + switch (args.Alteration) + { + case AttachableAlteredType.Attached: + EnsureComp(args.Holder); + break; + + case AttachableAlteredType.Detached: + RemCompDeferred(args.Holder); + break; + } + } +} diff --git a/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableToggleableSystem.cs b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableToggleableSystem.cs index 65e5f3a5f49..1f21cf1b50b 100644 --- a/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableToggleableSystem.cs +++ b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableToggleableSystem.cs @@ -21,6 +21,7 @@ using Robust.Shared.Map; using Robust.Shared.Physics; using Robust.Shared.Timing; +using Content.Shared._RMC14.Weapons.Common; namespace Content.Shared._RMC14.Attachable.Systems; @@ -59,7 +60,7 @@ public override void Initialize() SubscribeLocalEvent(OnGunShot); SubscribeLocalEvent(OnToggleAction, before: new[] { typeof(SharedHandheldLightSystem) }); - //SubscribeLocalEvent(OnUniqueAction); + SubscribeLocalEvent(OnUniqueAction); SubscribeLocalEvent(OnGrantAttachableActions); SubscribeLocalEvent(OnRemoveAttachableActions); SubscribeLocalEvent>(OnHandDeselected); @@ -249,11 +250,11 @@ private void OnAttemptShoot(Entity gun, ref _popupSystem.PopupClient(gun.Comp.Message, args.User, args.User); } -/* private void OnUniqueAction(Entity attachable, ref UniqueActionEvent args) + private void OnUniqueAction(Entity attachable, ref UniqueActionEvent args) { if (attachable.Comp.AttachedOnly && !attachable.Comp.Attached) args.Handled = true; - }*/ + } private void OnHandDeselected(Entity attachable, ref AttachableRelayedEvent args) { diff --git a/Content.Shared/Weapons/Ranged/Components/GunComponent.cs b/Content.Shared/Weapons/Ranged/Components/GunComponent.cs index 9d29e742e45..6254a973c33 100644 --- a/Content.Shared/Weapons/Ranged/Components/GunComponent.cs +++ b/Content.Shared/Weapons/Ranged/Components/GunComponent.cs @@ -188,7 +188,7 @@ public sealed partial class GunComponent : Component /// The base value for how fast the projectile moves. /// [DataField] - public float ProjectileSpeed = 25f; + public float ProjectileSpeed = 62f; /// /// How fast the projectile moves. diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs index f42c960472d..3fc19542e0e 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs @@ -37,7 +37,6 @@ using Robust.Shared.Utility; using Content.Shared.ADT.DNAGunLocker; using Content.Shared.Electrocution; -using Content.Shared.CombatMode; namespace Content.Shared.Weapons.Ranged.Systems; diff --git a/Resources/Locale/ru-RU/ADT/Objects/Weapons/Guns/launchers.ftl b/Resources/Locale/ru-RU/ADT/Objects/Weapons/Guns/launchers.ftl new file mode 100644 index 00000000000..37e3891148f --- /dev/null +++ b/Resources/Locale/ru-RU/ADT/Objects/Weapons/Guns/launchers.ftl @@ -0,0 +1,4 @@ +ent-ADTWeaponLauncherChinaLake = China Lake + .desc = БЛУП +ent-ADTWeaponLauncherRocket = РПГ-7 + .desc = Древний ручной реактивный гранатомёт. diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/uplink-catalog.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/uplink-catalog.ftl index beb65be4886..665b6749f51 100644 --- a/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/uplink-catalog.ftl +++ b/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/uplink-catalog.ftl @@ -92,3 +92,6 @@ uplink-blackmail-bundle-desc = Набор для относительно эфф uplink-syndicate-helmet-name = шлем спецназа uplink-syndicate-helmet-desc = Очень прочный шлем, широко используемый военизированными организациями. Его украшает ужасный узор из красных и чёрных полос. Да пребудет с вами робаст. + +ADTuplink-grenade-launcher-bundle-name = РПГ-7 +ADTuplink-grenade-launcher-bundle-desc = Набор,содержащий в себе Ручной Противотанковый Гранатомет и 8 ракет для него! diff --git a/Resources/Prototypes/ADT/Catalog/Fills/Backpacks/duffelbag.yml b/Resources/Prototypes/ADT/Catalog/Fills/Backpacks/duffelbag.yml index e4f495860a4..328836c322c 100644 --- a/Resources/Prototypes/ADT/Catalog/Fills/Backpacks/duffelbag.yml +++ b/Resources/Prototypes/ADT/Catalog/Fills/Backpacks/duffelbag.yml @@ -181,3 +181,32 @@ - id: ADTClothingShoesBootsMagAdvSynd - id: EnergyShield - id: EnergySword + +- type: entity + parent: ClothingBackpackDuffelSyndicateBundle + id: ADTClothingBackpackDuffelSyndicateFilledChinaLikeGrenadeLauncher + name: China-Lake bundle + description: "An old China-Lake grenade launcher bundled with 11 rounds of various destruction capability." + components: + - type: StorageFill + contents: + - id: ADTWeaponLauncherChinaLake + - id: ADT40mmGrenadeBlast + amount: 4 + - id: ADT40mmGrenadeHEAT + amount: 8 + - id: ADT40mmGrenadeSmoke + amount: 4 + +- type: entity + parent: ClothingBackpackDuffelSyndicateBundle + id: ADTClothingBackpackDuffelSyndicateFilledGrenadeLauncher + name: Rocket Launcher bundle + components: + - type: StorageFill + contents: + - id: ADTWeaponLauncherRocket + - id: ADTCartridgeFragRocket + amount: 4 + - id: ADTCartridgeBlastRocket + amount: 4 diff --git a/Resources/Prototypes/ADT/Catalog/uplink_catalog.yml b/Resources/Prototypes/ADT/Catalog/uplink_catalog.yml index 0a66378bf08..13988d1daf6 100644 --- a/Resources/Prototypes/ADT/Catalog/uplink_catalog.yml +++ b/Resources/Prototypes/ADT/Catalog/uplink_catalog.yml @@ -456,3 +456,17 @@ Telecrystal: 2 categories: - UplinkWearables + +- type: listing + id: ADTUplinkGrenadeLauncherBundle + name: ADTuplink-grenade-launcher-bundle-name + description: ADTuplink-grenade-launcher-bundle-desc + icon: { sprite: /Textures/Objects/Weapons/Guns/Launchers/rocket.rsi, state: base } + productEntity: ADTClothingBackpackDuffelSyndicateFilledGrenadeLauncher + discountCategory: veryRareDiscounts + discountDownTo: + Telecrystal: 20 + cost: + Telecrystal: 25 + categories: + - UplinkWeaponry diff --git a/Resources/Prototypes/ADT/Entities/Clothing/Masks/mask.yml b/Resources/Prototypes/ADT/Entities/Clothing/Masks/mask.yml index e3d79a0adb8..90b01473f43 100644 --- a/Resources/Prototypes/ADT/Entities/Clothing/Masks/mask.yml +++ b/Resources/Prototypes/ADT/Entities/Clothing/Masks/mask.yml @@ -439,3 +439,25 @@ - type: Clothing sprite: ADT/Clothing/Mask/payday_wolf.rsi - type: BreathMask + +- type: entity + id: ADTMaskCoif + parent: BaseItem + name: heat absorbent coif + description: A close-fitting cap that covers the top, back, and sides of the head. Can also be adjusted to cover the lower part of the face so it keeps the user warm in harsh conditions. + components: + - type: Sprite + sprite: _RMC14/Objects/Clothing/Mask/coif.rsi + state: icon + - type: Item + size: Small + - type: Clothing + slots: [mask] + sprite: _RMC14/Objects/Clothing/Mask/coif.rsi + - type: StaticPrice + price: 25 + - type: IdentityBlocker + coverage: MOUTH + - type: Item + storedRotation: -90 + - type: Mask diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/projectiles.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/projectiles.yml index 6caf83b46dc..55d12000dd8 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/projectiles.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/projectiles.yml @@ -116,3 +116,45 @@ spreadAmount: 40 - type: SoundOnTrigger sound: /Audio/Items/smoke_grenade_smoke.ogg + +- type: entity + id: ADTBulletFragRocket + name: frag rocket + parent: BaseBulletTrigger + categories: [ HideSpawnMenu ] + components: + - type: Sprite + sprite: Objects/Weapons/Guns/Projectiles/projectiles2.rsi + layers: + - state: frag + - type: ExplodeOnTrigger + - type: Explosive + explosionType: Default + totalIntensity: 175 # about a ~6 tile radius + intensitySlope: 1 + maxIntensity: 10 + - type: PointLight + radius: 3.5 + color: orange + energy: 0.5 + +- type: entity + id: ADTBulletBlastRocket + name: blast rocket + parent: BaseBulletTrigger + categories: [ HideSpawnMenu ] + components: + - type: Sprite + sprite: Objects/Weapons/Guns/Projectiles/projectiles2.rsi + layers: + - state: frag + - type: ExplodeOnTrigger + - type: Explosive + explosionType: Default + totalIntensity: 150 # a ~2 tile radius + intensitySlope: 5 + maxIntensity: 10 + - type: PointLight + radius: 3.5 + color: orange + energy: 0.5 diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Ammunition/explosives.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Ammunition/explosives.yml index 9f023609090..0258be6d508 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Ammunition/explosives.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Ammunition/explosives.yml @@ -102,3 +102,43 @@ map: ["enum.AmmoVisualLayers.Base"] - type: Appearance - type: SpentAmmoVisuals + +- type: entity + id: ADTCartridgeFragRocket + name: PG-7VL frag grenade + parent: [BaseItem, BaseMajorContraband] + description: A 1.5 warhead designed for the RPG-7 launcher. Has tubular shape. + components: + - type: Tag + tags: + - CartridgeRocket + - type: Item + size: Small + - type: CartridgeAmmo + proto: ADTBulletFragRocket + deleteOnSpawn: true + - type: Sprite + sprite: Objects/Weapons/Guns/Ammunition/Explosives/explosives.rsi + state: rpg + - type: StaticPrice + price: 20 + +- type: entity + id: ADTCartridgeBlastRocket + name: PG-7VL blast grenade + parent: [BaseItem, BaseMajorContraband] + description: A 1.5 warhead designed for the RPG-7 launcher. Has tubular shape. + components: + - type: Tag + tags: + - CartridgeRocket + - type: Item + size: Small + - type: CartridgeAmmo + proto: ADTBulletBlastRocket + deleteOnSpawn: true + - type: Sprite + sprite: Objects/Weapons/Guns/Ammunition/Explosives/explosives.rsi + state: rpg + - type: StaticPrice + price: 20 diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/barrel_attachment.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/barrel_attachment.yml index 71c95ec87ff..95d51e953cd 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/barrel_attachment.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/barrel_attachment.yml @@ -10,3 +10,27 @@ tags: - ADTAttachmentBarrel ## + +- type: entity + parent: ADTBarrelAttachmentBase + id: RMCAttachmentSuppressor + name: suppressor + description: "A small tube with exhaust ports to expel noise and gas. + Does not completely silence a weapon, but does make it much quieter at the cost of slightly reduced damage." + components: + - type: Sprite + state: suppressor + - type: Tag + tags: + - ADTAttachmentBarrel + - ADTAttachmentLaserSight + - type: AttachableVisuals + prefix: suppressor2 + - type: AttachableSilencer + sound: + collection: ADTSilencedShoot + params: + maxDistance: 6 + - type: AttachableWeaponRangedMods + modifiers: + - damageFalloffAddMult: 0.1 diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml index 9385cd07fbf..be103ed8839 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml @@ -38,7 +38,6 @@ - type: RMCSelectiveFire baseFireRate: 0.417 - type: BallisticAmmoProvider - # cycleable: false whitelist: tags: - ADT40mmGrenade @@ -50,9 +49,6 @@ volume: -2 - type: ShootAtFixedPoint maxFixedRange: 10 - # - type: UniqueAction - # - type: BreechLoaded - # needOpenClose: false - type: Appearance - type: GenericVisualizer visuals: diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/tags.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/tags.yml index 9c0f834d6f5..e742f9a4177 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/tags.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/tags.yml @@ -13,9 +13,6 @@ - type: Tag id: SurvivalKnifeAttachment -- type: Tag - id: ADTAttachmentMicroAccelerator - - type: Tag id: ADTAttachmentRail diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Launchers/fill.txt b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Launchers/fill.txt deleted file mode 100644 index b4954caf47d..00000000000 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Launchers/fill.txt +++ /dev/null @@ -1 +0,0 @@ -# Данный файл существует по причине того что Githab плохо дружит с пустыми папками, при работе с этой папкой этот файл можно спокойно удалить \ No newline at end of file diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Launchers/launchers.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Launchers/launchers.yml new file mode 100644 index 00000000000..b07c58bafbb --- /dev/null +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Launchers/launchers.yml @@ -0,0 +1,74 @@ +- type: entity + name: china lake + parent: [BaseWeaponLauncher, BaseGunWieldable, BaseSyndicateContraband, ADTBaseMagneticGun, ADTBasePumpingGun] + id: ADTWeaponLauncherChinaLake + description: PLOOP. + components: + - type: Sprite + sprite: Objects/Weapons/Guns/Launchers/china_lake.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 + selectedMode: SemiAuto + availableModes: + - SemiAuto + soundGunshot: + path: /Audio/Weapons/Guns/Gunshots/grenade_launcher.ogg + - type: BallisticAmmoProvider + whitelist: + tags: + - ADT40mmGrenade + capacity: 4 + proto: ADT40mmGrenadeBlast + soundInsert: + path: /Audio/Weapons/Guns/MagIn/batrifle_magin.ogg + +- type: entity + name: RPG-7 + parent: [BaseWeaponLauncher, BaseMajorContraband, ADTBaseMagneticGun, BaseGunWieldable] + id: ADTWeaponLauncherRocket + description: A modified ancient rocket-propelled grenade launcher. + components: + - type: Sprite + sprite: Objects/Weapons/Guns/Launchers/rocket.rsi + layers: + - state: base + map: ["enum.GunVisualLayers.Base"] + - state: mag-0 + map: ["enum.GunVisualLayers.Mag"] + - type: Clothing + sprite: Objects/Weapons/Guns/Launchers/rocket.rsi + - type: Gun + fireRate: 0.5 + soundGunshot: + path: /Audio/Weapons/Guns/Gunshots/rpgfire.ogg + - type: BallisticAmmoProvider + whitelist: + tags: + - CartridgeRocket + proto: ADTCartridgeBlastRocket + capacity: 1 + soundInsert: + path: /Audio/Weapons/Guns/MagIn/batrifle_magin.ogg + - type: MagazineVisuals + magState: mag + steps: 2 + zeroVisible: false + - type: Appearance + - type: Scope + zoomLevels: + - zoom: 1.2 + offset: 12 + allowMovement: true + doAfter: 0 + requireWielding: false + attachment: false + - type: GunRequiresWield diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Rifles/rifles.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Rifles/rifles.yml index 17baa3cfc90..975ae78b897 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Rifles/rifles.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Rifles/rifles.yml @@ -170,7 +170,7 @@ sprite: ADT/Objects/Weapons/Guns/Rifles/xc67.rsi - type: Gun minAngle: 20.5 - maxAngle: 31 + maxAngle: 31 fireRate: 6 #angleIncrease: 1 #angleDecay: 12 @@ -231,11 +231,6 @@ rmc-aslot-underbarrel: 0.3125, -0.0315 rmc-aslot-rail: -0.0940, -0.0325 - type: ItemSizeChange - # - type: ActivatableUI - # verbText: rmc-verb-strip-attachables - # verbOnly: true - # key: - # enum.AttachmentUI.StripKey - type: UserInterface interfaces: enum.AttachmentUI.StripKey: diff --git a/Resources/Prototypes/Catalog/uplink_catalog.yml b/Resources/Prototypes/Catalog/uplink_catalog.yml index 56262428ac7..baa4ac0e441 100644 --- a/Resources/Prototypes/Catalog/uplink_catalog.yml +++ b/Resources/Prototypes/Catalog/uplink_catalog.yml @@ -198,7 +198,7 @@ name: uplink-grenade-launcher-bundle-name description: uplink-grenade-launcher-bundle-desc icon: { sprite: /Textures/Objects/Weapons/Guns/Launchers/china_lake.rsi, state: icon } - productEntity: ClothingBackpackDuffelSyndicateFilledGrenadeLauncher + productEntity: ADTClothingBackpackDuffelSyndicateFilledChinaLikeGrenadeLauncher # adt tweak discountCategory: veryRareDiscounts discountDownTo: Telecrystal: 20 diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/base_pka.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/base_pka.yml index 646e8db669d..9fc5e6bc427 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/base_pka.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/base_pka.yml @@ -52,7 +52,6 @@ rmc-aslot-underbarrel: whitelist: tags: - - ADTAttachmentMicroAccelerator - SurvivalKnifeAttachment # rmc-aslot-stock: # whitelist: diff --git a/Resources/Textures/ADT/Clothing/Mask/coif.rsi/equipped-MASK.png b/Resources/Textures/ADT/Clothing/Mask/coif.rsi/equipped-MASK.png new file mode 100644 index 0000000000000000000000000000000000000000..1bffbcba02bd69767d90ba6f42a2c1547a8d686c GIT binary patch literal 576 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc4Ocx~978JN-rn-|KI|aE`ru-&wuV@cV?g1< z#S3nQa!{&e8yLZ^kx7oeF+#oJb_v$^)6X!Q=a~9)QIM2S1J1}_O_eGx< zTQAsCalp3DKhZ+wr__cQdEfIkRs6{lyvx{otSQ?}`kzP#YmZz0)^di=hgm=0n|lx7X%Ml{Y0b>%x@~>tz}H*9R_)&=*OtjFaOS6tITNeHT-k$X+l%rxiK{5s z@aC~_HCP>gdZ&h?cy-C#odJ1Hk+I#&BcFC5Ji&NwFZ21F*emh7J>`M1&fw|l=d#Wz Gp$PyoO9BS~ literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Clothing/Mask/coif.rsi/icon.png b/Resources/Textures/ADT/Clothing/Mask/coif.rsi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..0c5c4851be40691973eea9e2aa9158a82c7241a5 GIT binary patch literal 411 zcmV;M0c8G(P)~5Ao1Z~q>4pPRs6@a0tE3nohjsS zAXpW^%^|*CM|*yV!-v?e9oEJIz>RUsDEdx5S}zWAUYgJO1EBoqG0G3&Q-&CFkh?Xj zHdt4{9J)MntpTXVzuB=FxflSYtOh@OZf-yjRFb&X%XBp%j#gY{3t$k>mYBp5djXkfF3T7W77*_KtFCjtDEC68qF;R5p_Fe>F8dZVL zQWF8ts+j}F?Y$U)W+CgBlwSm3K;&Y#`5_v@d0O7?f}|Joqc^7K z-z_Q5(f76gAMjsxZRFF{axOmt%Q7aV+~r}5f41+tK&g;Qe9M#dw?5C`+3bJWuku)W zx$Co&XQwNx+|RzIQe*MMWP7>!)y?Y1mp}H~Wcc0Bp>9?g@1_*SPc;!`idm;V?H-_R}3*yy?P?%c1cH*YAO+qAc+{Kw0Wu5;H`*)Pca@UHCY9tGye z6E0?1Gp<~kdrNZv$9aY=bK>Vry?sd_`|0aDehho`3rZ{B#Nb0lg<=aB;?+rNNvhB*kT1V%ryNnXnH0)U+ z@Y Date: Thu, 12 Dec 2024 21:43:59 +0200 Subject: [PATCH 28/46] =?UTF-8?q?=D1=88=D0=B8=D1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Armor/Magnetic/RMCMagneticSystem.cs | 13 ---------- .../Systems/RequireProjectileTargetSystem.cs | 9 ++++--- .../Catalog/store/uplink-catalog.ftl | 3 +++ .../Entities/Clothing/Mask/mask.ftl | 5 +++- .../Prototypes/ADT/Catalog/uplink_catalog.yml | 11 +++++++++ .../ADT/Entities/Clothing/Masks/mask.yml | 7 +++--- .../Attachments/barrel_attachment.yml | 24 ------------------- 7 files changed, 27 insertions(+), 45 deletions(-) diff --git a/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticSystem.cs b/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticSystem.cs index dd2a052a735..049439c315b 100644 --- a/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticSystem.cs +++ b/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticSystem.cs @@ -17,7 +17,6 @@ public override void Initialize() { SubscribeLocalEvent(OnMagneticItemDropped); SubscribeLocalEvent(OnMagneticItemRMCDropped); - // SubscribeLocalEvent(OnMagneticItemThrown); SubscribeLocalEvent(OnMagneticItemDropAttempt); } @@ -31,18 +30,6 @@ private void OnMagneticItemRMCDropped(Entity ent, ref TryReturn(ent, args.User); } - // private void OnMagneticItemThrown(Entity ent, ref ThrownEvent args) - // { - // if (args.User is not { } user) - // return; - - // if (!TryReturn(ent, user)) - // return; - - // if (TryComp(ent, out ThrownItemComponent? thrown)) - // _thrownItem.StopThrow(ent, thrown); - // } - private void OnMagneticItemDropAttempt(Entity ent, ref DropAttemptEvent args) { args.Cancel(); diff --git a/Content.Shared/Damage/Systems/RequireProjectileTargetSystem.cs b/Content.Shared/Damage/Systems/RequireProjectileTargetSystem.cs index 209704064b8..a2ea4e36193 100644 --- a/Content.Shared/Damage/Systems/RequireProjectileTargetSystem.cs +++ b/Content.Shared/Damage/Systems/RequireProjectileTargetSystem.cs @@ -3,6 +3,7 @@ using Content.Shared.Standing; using Robust.Shared.Physics.Events; using Robust.Shared.Containers; +using Content.Shared.ADT.Crawling; namespace Content.Shared.Damage.Components; @@ -21,7 +22,7 @@ public override void Initialize() private void PreventCollide(Entity ent, ref PreventCollideEvent args) { if (args.Cancelled) - return; + return; if (!ent.Comp.Active) return; @@ -39,14 +40,16 @@ private void PreventCollide(Entity ent, ref Pr } } // ADT Crawling abuse fix end - + var weapon = projectile.Weapon; + if (weapon.HasValue && HasComp(weapon)) + return; // Prevents shooting out of while inside of crates var shooter = projectile.Shooter; if (!shooter.HasValue) return; if (!_container.IsEntityOrParentInContainer(shooter.Value)) - args.Cancelled = true; + args.Cancelled = true; } } diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/uplink-catalog.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/uplink-catalog.ftl index 665b6749f51..9f662f889ab 100644 --- a/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/uplink-catalog.ftl +++ b/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/uplink-catalog.ftl @@ -95,3 +95,6 @@ uplink-syndicate-helmet-desc = Очень прочный шлем, широко ADTuplink-grenade-launcher-bundle-name = РПГ-7 ADTuplink-grenade-launcher-bundle-desc = Набор,содержащий в себе Ручной Противотанковый Гранатомет и 8 ракет для него! + +uplink-mask-name = балаклава +uplink-mask-desc = Идеально, если вы террорист. diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Entities/Clothing/Mask/mask.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Clothing/Mask/mask.ftl index 1ec1b4542c8..ff0d7224ccf 100644 --- a/Resources/Locale/ru-RU/ADT/prototypes/Entities/Clothing/Mask/mask.ftl +++ b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Clothing/Mask/mask.ftl @@ -64,4 +64,7 @@ ent-ADTPayDayWolfMask = маска клоуна Волка с Уолл-стри .desc = Одевая эту маску, вы почему то начинаете чувствовать разделение надвое и желание переворачивать маску совсем пропадает.. ent-ClothingMaskMadHeretic = маска бездны - .desc = Маска, созданная из страданий. Когда вы смотрите в ее глаза, она смотрит в ответ. \ No newline at end of file + .desc = Маска, созданная из страданий. Когда вы смотрите в ее глаза, она смотрит в ответ. + +ent-ADTMaskCoif = балаклава + .desc = Идеально, если вы террорист. diff --git a/Resources/Prototypes/ADT/Catalog/uplink_catalog.yml b/Resources/Prototypes/ADT/Catalog/uplink_catalog.yml index 13988d1daf6..44953728b4b 100644 --- a/Resources/Prototypes/ADT/Catalog/uplink_catalog.yml +++ b/Resources/Prototypes/ADT/Catalog/uplink_catalog.yml @@ -470,3 +470,14 @@ Telecrystal: 25 categories: - UplinkWeaponry + +- type: listing + id: ADTUplinkMask + name: uplink-mask-name + description: uplink-mask-desc + productEntity: ADTMaskCoif + categories: + - UplinkPointless + conditions: + - !type:ListingLimitedStockCondition + stock: 3 diff --git a/Resources/Prototypes/ADT/Entities/Clothing/Masks/mask.yml b/Resources/Prototypes/ADT/Entities/Clothing/Masks/mask.yml index 90b01473f43..ae1eb9f5f80 100644 --- a/Resources/Prototypes/ADT/Entities/Clothing/Masks/mask.yml +++ b/Resources/Prototypes/ADT/Entities/Clothing/Masks/mask.yml @@ -447,17 +447,16 @@ description: A close-fitting cap that covers the top, back, and sides of the head. Can also be adjusted to cover the lower part of the face so it keeps the user warm in harsh conditions. components: - type: Sprite - sprite: _RMC14/Objects/Clothing/Mask/coif.rsi + sprite: ADT/Clothing/Mask/coif.rsi state: icon - - type: Item - size: Small - type: Clothing slots: [mask] - sprite: _RMC14/Objects/Clothing/Mask/coif.rsi + sprite: ADT/Clothing/Mask/coif.rsi - type: StaticPrice price: 25 - type: IdentityBlocker coverage: MOUTH - type: Item storedRotation: -90 + size: Small - type: Mask diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/barrel_attachment.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/barrel_attachment.yml index 95d51e953cd..71c95ec87ff 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/barrel_attachment.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/barrel_attachment.yml @@ -10,27 +10,3 @@ tags: - ADTAttachmentBarrel ## - -- type: entity - parent: ADTBarrelAttachmentBase - id: RMCAttachmentSuppressor - name: suppressor - description: "A small tube with exhaust ports to expel noise and gas. - Does not completely silence a weapon, but does make it much quieter at the cost of slightly reduced damage." - components: - - type: Sprite - state: suppressor - - type: Tag - tags: - - ADTAttachmentBarrel - - ADTAttachmentLaserSight - - type: AttachableVisuals - prefix: suppressor2 - - type: AttachableSilencer - sound: - collection: ADTSilencedShoot - params: - maxDistance: 6 - - type: AttachableWeaponRangedMods - modifiers: - - damageFalloffAddMult: 0.1 From 11e5113b3eb0669d05c7209f6d4929d9ffe4978d Mon Sep 17 00:00:00 2001 From: PyotrIgn <131798882+PyotrIgn@users.noreply.github.com> Date: Fri, 13 Dec 2024 17:07:30 +0400 Subject: [PATCH 29/46] Update uplink-catalog.ftl --- .../ru-RU/ADT/prototypes/Catalog/store/uplink-catalog.ftl | 2 -- 1 file changed, 2 deletions(-) diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/uplink-catalog.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/uplink-catalog.ftl index 9fc742bcfe1..6519dd0b98b 100644 --- a/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/uplink-catalog.ftl +++ b/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/uplink-catalog.ftl @@ -99,8 +99,6 @@ ADTuplink-grenade-launcher-bundle-desc = Набор,содержащий в се uplink-mask-name = балаклава uplink-mask-desc = Идеально, если вы террорист. -uplink-syndicate-helmet-desc = Очень прочный шлем, широко используемый военизированными организациями. Его украшает ужасный узор из красных и чёрных полос. Да прибудет с вами робаст - uplink-nukiesShield-name = двуручный штурмовой щит uplink-nukiesShield-desc = Массивный и опасный, двуручный щит из элитных материалов для лучшей защиты, имеет несколько рядов пластин, а также несколько шипов на основе щита. From c549c9bf2d724af7342c4f89ec79877a201266f5 Mon Sep 17 00:00:00 2001 From: Eugeny Date: Sat, 14 Dec 2024 07:56:20 +0400 Subject: [PATCH 30/46] =?UTF-8?q?=D0=B3=D0=BB=D1=83=D1=88=D0=B8=D1=82?= =?UTF-8?q?=D0=B5=D0=BB=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Objects/Weapons/Guns/Attachments.ftl | 4 +++ .../Attachments/barrel_attachment.yml | 24 ++++++++++++++++++ .../Objects/Weapons/Guns/Attachments/tags.yml | 3 +++ .../Objects/Weapons/Guns/Rifles/rifles.yml | 7 ++++- .../Objects/Weapons/Guns/Pistols/pistols.yml | 10 ++++++++ .../Objects/Weapons/Guns/Rifles/rifles.yml | 10 ++++++++ .../Objects/Weapons/Guns/SMGs/smgs.yml | 10 ++++++++ .../ADT/Attachments/barrel.rsi/meta.json | 17 +++++++++++++ .../ADT/Attachments/barrel.rsi/suppressor.png | Bin 0 -> 259 bytes .../Attachments/barrel.rsi/suppressor_a.png | Bin 0 -> 193 bytes .../ADT/Attachments/under.rsi/meta.json | 2 +- 11 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 Resources/Textures/ADT/Attachments/barrel.rsi/meta.json create mode 100644 Resources/Textures/ADT/Attachments/barrel.rsi/suppressor.png create mode 100644 Resources/Textures/ADT/Attachments/barrel.rsi/suppressor_a.png diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Guns/Attachments.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Guns/Attachments.ftl index 6eb77e49e1a..e928660b057 100644 --- a/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Guns/Attachments.ftl +++ b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Guns/Attachments.ftl @@ -29,3 +29,7 @@ ent-ADTAttachmentVerticalGrip = вертикальная рукоять ent-ADTAttachmentLaserSight = лазерный целеуказатель .desc = Устанавливаемый под ствол маленький лазер, позволяющий бойцу стрелять точнее даже без прицела и с одной руки. .suffix = { "Оруж. модуль, Подствольный" } + +ent-ADTAttachmentSuppressor = глушитель +.desc = Устанавлаемый на ствол универсальный мультикалиберный глушитель. Существенно снижает звук от стрельбы и скрывает дульную вспышку. +.suffix = { "Оруж. модуль, Подствольный" } diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/barrel_attachment.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/barrel_attachment.yml index 71c95ec87ff..a70d3d4069b 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/barrel_attachment.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/barrel_attachment.yml @@ -10,3 +10,27 @@ tags: - ADTAttachmentBarrel ## + +- type: entity + parent: ADTBarrelAttachmentBase + id: ADTAttachmentSuppressor + name: suppressor + description: "A small tube with exhaust ports to expel noise and gas. + Does not completely silence a weapon, but does make it much quieter at the cost of slightly reduced damage." + components: + - type: Sprite + state: suppressor + - type: Tag + tags: + - ADTAttachmentBarrel + - ADTAttachmentSuppressor + - type: AttachableVisuals + prefix: suppressor + - type: AttachableSilencer + sound: + collection: ADTSilencedShoot + params: + maxDistance: 6 + # - type: AttachableWeaponRangedMods Пока не работает + # modifiers: + # - damageFalloffAddMult: 0.1 diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/tags.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/tags.yml index e742f9a4177..9aa50cc4965 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/tags.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/tags.yml @@ -36,3 +36,6 @@ - type: Tag id: ADTAttachmentLaserSight + +- type: Tag + id: ADTAttachmentSuppressor diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Rifles/rifles.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Rifles/rifles.yml index 975ae78b897..f1744e9ce7b 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Rifles/rifles.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Rifles/rifles.yml @@ -226,10 +226,15 @@ - ADTAttachmentMagneticHarness - ADTAttachmentReflexSight - ADTAttachmentT2Miniscope + rmc-aslot-barrel: + whitelist: + tags: + - ADTAttachmentSuppressor - type: AttachableHolderVisuals offsets: - rmc-aslot-underbarrel: 0.3125, -0.0315 + rmc-aslot-underbarrel: 0.3125, -0.03125 rmc-aslot-rail: -0.0940, -0.0325 + rmc-aslot-barrel: 0.96875, 0.03125 - type: ItemSizeChange - type: UserInterface interfaces: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Pistols/pistols.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Pistols/pistols.yml index e75f4273760..907e5a3fc42 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Pistols/pistols.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Pistols/pistols.yml @@ -107,9 +107,14 @@ whitelist: tags: - ADTAttachmentLaserSight + rmc-aslot-barrel: + whitelist: + tags: + - ADTAttachmentSuppressor - type: AttachableHolderVisuals offsets: rmc-aslot-underbarrel: 0.235, -0.00875 + rmc-aslot-barrel: 0.84375, 0.09735 # ADT TWEAK END - type: entity @@ -239,9 +244,14 @@ whitelist: tags: - ADTAttachmentLaserSight + rmc-aslot-barrel: + whitelist: + tags: + - ADTAttachmentSuppressor - type: AttachableHolderVisuals offsets: rmc-aslot-underbarrel: 0.17, -0.014 + rmc-aslot-barrel: 0.84375, 0.125 # ADT TWEAK END - type: entity diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml index e70bce8e7b3..f161a907353 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml @@ -160,10 +160,15 @@ - ADTAttachmentMagneticHarness - ADTAttachmentReflexSight - ADTAttachmentT2Miniscope + rmc-aslot-barrel: + whitelist: + tags: + - ADTAttachmentSuppressor - type: AttachableHolderVisuals offsets: rmc-aslot-underbarrel: 0.3125, -0.0625 rmc-aslot-rail: 0.0, -0.0325 + rmc-aslot-barrel: 0.96875, 0 # ADT TWEAK END - type: ContainerContainer containers: @@ -238,10 +243,15 @@ - ADTAttachmentMagneticHarness - ADTAttachmentReflexSight - ADTAttachmentT2Miniscope + rmc-aslot-barrel: + whitelist: + tags: + - ADTAttachmentSuppressor - type: AttachableHolderVisuals offsets: rmc-aslot-underbarrel: 0.3125, -0.0625 rmc-aslot-rail: 0, 0 + rmc-aslot-barrel: 0.96875, 0 # ADT TWEAK END - type: entity diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml index fc578280015..48b41445964 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml @@ -125,9 +125,14 @@ - ADTAttachmentMagneticHarness - ADTAttachmentReflexSight - ADTAttachmentT2Miniscope + rmc-aslot-barrel: + whitelist: + tags: + - ADTAttachmentSuppressor - type: AttachableHolderVisuals offsets: rmc-aslot-rail: -0.0325, -0.0325 + rmc-aslot-barrel: 0.75, 0 # ADT TWEAK END - type: entity @@ -197,10 +202,15 @@ - ADTAttachmentMagneticHarness - ADTAttachmentReflexSight - ADTAttachmentT2Miniscope + rmc-aslot-barrel: + whitelist: + tags: + - ADTAttachmentSuppressor - type: AttachableHolderVisuals offsets: rmc-aslot-underbarrel: 0.28, -0.1250 rmc-aslot-rail: -0.0325, -0.0625 + rmc-aslot-barrel: 0.90625, 0 # ADT TWEAK END - type: entity diff --git a/Resources/Textures/ADT/Attachments/barrel.rsi/meta.json b/Resources/Textures/ADT/Attachments/barrel.rsi/meta.json new file mode 100644 index 00000000000..631d8271e20 --- /dev/null +++ b/Resources/Textures/ADT/Attachments/barrel.rsi/meta.json @@ -0,0 +1,17 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "taken from cmss13 at https://github.com/cmss13-devs/cmss13/blob/7e38a6a747b200b3854888a3eacd18b47992d066/icons/obj/items/weapons/guns/attachments", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "suppressor" + }, + { + "name": "suppressor_a" + } + ] +} diff --git a/Resources/Textures/ADT/Attachments/barrel.rsi/suppressor.png b/Resources/Textures/ADT/Attachments/barrel.rsi/suppressor.png new file mode 100644 index 0000000000000000000000000000000000000000..de1d235845d9d0dd22cbee27a5036f72c0223551 GIT binary patch literal 259 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5D7e+r z#WAE}&f6=7T!$4z*bK-rrupmxRykqlngKmWsk&O=>cc~> zt|@{BJj{jX_A=b}6BKY#aN^jc!#(HszV>_HWp71s&n@0JH=OyLc*ayEhiu;NBNDq~ zoxC)^>{>Uy(rcw$f!eVf6WM;wuLs%2z$9=%%im_VWf6ywQaaEB44$rjF6*2UngD{+ BT{i## literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Attachments/barrel.rsi/suppressor_a.png b/Resources/Textures/ADT/Attachments/barrel.rsi/suppressor_a.png new file mode 100644 index 0000000000000000000000000000000000000000..aa07789eef658fb994f29f2fdb576c27cad84884 GIT binary patch literal 193 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R})t)YnArY-_ zFDmk}DDtpg@Rv|o)wcS91;ci?1v^>Um}iyTQL)Yrd+^Qv>XYZoeYpe#FYY&H5OBH> z&%L+2_)~-S(j|s&9UR9bR%}&z{^!j5HQ(!s?AHZxJ)864Uh>-3Yf>R!XWqY=c`T}X r?{=n!;&;j-6W1SlDJ~!=D0ug{x6QJht)54K&S3C#^>bP0l+XkKFsVwS literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Attachments/under.rsi/meta.json b/Resources/Textures/ADT/Attachments/under.rsi/meta.json index 68b63235826..cc656885167 100644 --- a/Resources/Textures/ADT/Attachments/under.rsi/meta.json +++ b/Resources/Textures/ADT/Attachments/under.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Created by discord: inconnu1337", + "copyright": "Created by discord: inconnu1337 and taken from RMC-14", "size": { "x": 32, "y": 32 From e6bc6598c0ce4ca1005014c9aca4b02be12489e7 Mon Sep 17 00:00:00 2001 From: Inconnu1337 Date: Sun, 15 Dec 2024 00:16:10 +0200 Subject: [PATCH 31/46] =?UTF-8?q?=D0=B3=D0=BE=D0=B2=D0=BD=D0=BE=D1=87?= =?UTF-8?q?=D0=B8=D1=81=D1=82=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Inventory/CMHolsterVisualizerSystem.cs | 32 - .../ADT/_RMC14/Inventory/CMInventorySystem.cs | 37 - Content.Client/Input/ContentContexts.cs | 4 - .../Options/UI/Tabs/KeyRebindTab.xaml.cs | 4 - .../Weapons/Melee/MeleeWeaponSystem.cs | 12 +- .../ADT/_RMC14/Inventory/CMInventorySystem.cs | 5 - .../Armor/Magnetic/RMCMagneticSystem.cs | 13 +- .../Armor/Magnetic/RMCMagnetizeItemEvent.cs | 11 - .../Magnetic/RMCReturnToInventoryComponent.cs | 3 - Content.Shared/ADT/_RMC14/CCVar/RMCCVars.cs | 11 - .../_RMC14/Input/ActiveInputMoverComponent.cs | 7 - .../ADT/_RMC14/Input/CMKeyFunctions.cs | 4 - .../ADT/_RMC14/Input/RMCInputSystem.cs | 53 -- .../ADT/_RMC14/Inventory/CMHolsterChoose.cs | 10 - .../_RMC14/Inventory/CMHolsterComponent.cs | 47 -- .../ADT/_RMC14/Inventory/CMHolsterLayers.cs | 9 - .../ADT/_RMC14/Inventory/CMHolsterVisuals.cs | 10 - .../_RMC14/Inventory/CMInventoryExtensions.cs | 39 -- .../_RMC14/Inventory/CMItemSlotsComponent.cs | 29 - .../ADT/_RMC14/Inventory/CMItemSlotsLayers.cs | 9 - .../_RMC14/Inventory/CMItemSlotsVisuals.cs | 13 - .../Inventory/CMVirtualItemComponent.cs | 7 - .../_RMC14/Inventory/IsUnholsterableEvent.cs | 4 - .../ADT/_RMC14/Inventory/RMCDroppedEvent.cs | 4 - .../Inventory/SharedCMInventorySystem.cs | 661 ------------------ .../ADT/_RMC14/Random/SplitMix64.cs | 39 -- .../ADT/_RMC14/Random/Xoroshiro64S.cs | 65 -- .../ADT/_RMC14/Tackle/CMDisarmEvent.cs | 4 - .../ADT/_RMC14/Tackle/TackleComponent.cs | 20 - .../ADT/_RMC14/Tackle/TackleSystem.cs | 112 --- .../ADT/_RMC14/Tackle/TackleableComponent.cs | 10 - .../_RMC14/Tackle/TackledRecentlyComponent.cs | 17 - 32 files changed, 4 insertions(+), 1301 deletions(-) delete mode 100644 Content.Client/ADT/_RMC14/Inventory/CMHolsterVisualizerSystem.cs delete mode 100644 Content.Client/ADT/_RMC14/Inventory/CMInventorySystem.cs delete mode 100644 Content.Server/ADT/_RMC14/Inventory/CMInventorySystem.cs delete mode 100644 Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagnetizeItemEvent.cs delete mode 100644 Content.Shared/ADT/_RMC14/CCVar/RMCCVars.cs delete mode 100644 Content.Shared/ADT/_RMC14/Input/ActiveInputMoverComponent.cs delete mode 100644 Content.Shared/ADT/_RMC14/Input/RMCInputSystem.cs delete mode 100644 Content.Shared/ADT/_RMC14/Inventory/CMHolsterChoose.cs delete mode 100644 Content.Shared/ADT/_RMC14/Inventory/CMHolsterComponent.cs delete mode 100644 Content.Shared/ADT/_RMC14/Inventory/CMHolsterLayers.cs delete mode 100644 Content.Shared/ADT/_RMC14/Inventory/CMHolsterVisuals.cs delete mode 100644 Content.Shared/ADT/_RMC14/Inventory/CMInventoryExtensions.cs delete mode 100644 Content.Shared/ADT/_RMC14/Inventory/CMItemSlotsComponent.cs delete mode 100644 Content.Shared/ADT/_RMC14/Inventory/CMItemSlotsLayers.cs delete mode 100644 Content.Shared/ADT/_RMC14/Inventory/CMItemSlotsVisuals.cs delete mode 100644 Content.Shared/ADT/_RMC14/Inventory/CMVirtualItemComponent.cs delete mode 100644 Content.Shared/ADT/_RMC14/Inventory/IsUnholsterableEvent.cs delete mode 100644 Content.Shared/ADT/_RMC14/Inventory/RMCDroppedEvent.cs delete mode 100644 Content.Shared/ADT/_RMC14/Inventory/SharedCMInventorySystem.cs delete mode 100644 Content.Shared/ADT/_RMC14/Random/SplitMix64.cs delete mode 100644 Content.Shared/ADT/_RMC14/Random/Xoroshiro64S.cs delete mode 100644 Content.Shared/ADT/_RMC14/Tackle/CMDisarmEvent.cs delete mode 100644 Content.Shared/ADT/_RMC14/Tackle/TackleComponent.cs delete mode 100644 Content.Shared/ADT/_RMC14/Tackle/TackleSystem.cs delete mode 100644 Content.Shared/ADT/_RMC14/Tackle/TackleableComponent.cs delete mode 100644 Content.Shared/ADT/_RMC14/Tackle/TackledRecentlyComponent.cs diff --git a/Content.Client/ADT/_RMC14/Inventory/CMHolsterVisualizerSystem.cs b/Content.Client/ADT/_RMC14/Inventory/CMHolsterVisualizerSystem.cs deleted file mode 100644 index 3fd709ae338..00000000000 --- a/Content.Client/ADT/_RMC14/Inventory/CMHolsterVisualizerSystem.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Content.Shared._RMC14.Inventory; -using Robust.Client.GameObjects; - -namespace Content.Client._RMC14.Inventory; - -/// -/// Sets the gun underlay of holsters -/// -public sealed class CMHolsterVisualizerSystem : VisualizerSystem -{ - - protected override void OnAppearanceChange(EntityUid uid, - CMHolsterComponent component, - ref AppearanceChangeEvent args) - { - if (args.Sprite is not { } sprite || - !sprite.LayerMapTryGet(CMHolsterLayers.Fill, out var layer)) - return; - - if (component.Contents.Count != 0) - { - // TODO: implement per-gun underlay here - // sprite.LayerSetState(layer, $"{}"); - sprite.LayerSetVisible(layer, true); - - // TODO: account for the gunslinger belt - return; - } - - sprite.LayerSetVisible(layer, false); - } -} diff --git a/Content.Client/ADT/_RMC14/Inventory/CMInventorySystem.cs b/Content.Client/ADT/_RMC14/Inventory/CMInventorySystem.cs deleted file mode 100644 index 46a434b3fbe..00000000000 --- a/Content.Client/ADT/_RMC14/Inventory/CMInventorySystem.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Content.Shared._RMC14.Inventory; -using Content.Shared.Containers.ItemSlots; -using Robust.Client.GameObjects; - -namespace Content.Client._RMC14.Inventory; - -public sealed class CMInventorySystem : SharedCMInventorySystem -{ - protected override void ContentsUpdated(Entity ent) - { - base.ContentsUpdated(ent); - - if (!TryComp(ent, out SpriteComponent? sprite) || - !sprite.LayerMapTryGet(CMItemSlotsLayers.Fill, out var layer)) - { - return; - } - - if (!TryComp(ent, out ItemSlotsComponent? itemSlots)) - { - sprite.LayerSetVisible(layer, false); - return; - } - - foreach (var (_, slot) in itemSlots.Slots) - { - if (slot.ContainerSlot?.ContainedEntity is { } contained && - !TerminatingOrDeleted(contained)) - { - sprite.LayerSetVisible(layer, true); - return; - } - } - - sprite.LayerSetVisible(layer, false); - } -} diff --git a/Content.Client/Input/ContentContexts.cs b/Content.Client/Input/ContentContexts.cs index f4826dc183b..3fa68d7e815 100644 --- a/Content.Client/Input/ContentContexts.cs +++ b/Content.Client/Input/ContentContexts.cs @@ -139,10 +139,6 @@ private static void CMFunctions(IInputContextContainer contexts) human.AddFunction(CMKeyFunctions.RMCActivateAttachableUnderbarrel); human.AddFunction(CMKeyFunctions.RMCFieldStripHeldItem); human.AddFunction(CMKeyFunctions.CMUniqueAction); - human.AddFunction(CMKeyFunctions.CMHolsterPrimary); - human.AddFunction(CMKeyFunctions.CMHolsterSecondary); - human.AddFunction(CMKeyFunctions.CMHolsterTertiary); - human.AddFunction(CMKeyFunctions.CMHolsterQuaternary); } // ADT TWEAK END. } diff --git a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs index 7348acef796..f940815634a 100644 --- a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs +++ b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs @@ -159,10 +159,6 @@ void AddCheckBox(string checkBoxName, bool currentState, Action(weaponUid, out var altFireComponent) || altDown != BoundKeyState.Down) return; - switch(altFireComponent.AttackType) + switch (altFireComponent.AttackType) { case AltFireAttackType.Light: ClientLightAttack(entity, mousePos, coordinates, weaponUid, weapon); @@ -396,13 +395,6 @@ protected override bool DoDisarm(EntityUid user, DisarmAttackEvent ev, EntityUid } var target = GetEntity(ev.Target); - if (target != null && InRange(user, target.Value, component.Range, session)) - { - var cmDisarmEvent = new CMDisarmEvent(user); - RaiseLocalEvent(target.Value, ref cmDisarmEvent); - if (cmDisarmEvent.Handled) - return true; - } // They need to either have hands... if (!HasComp(target!.Value)) @@ -476,7 +468,7 @@ private void ClientLightAttack(EntityUid attacker, MapCoordinates mousePos, Enti RaisePredictiveEvent(new LightAttackEvent(GetNetEntity(target), GetNetEntity(weaponUid), GetNetCoordinates(coordinates))); } - // ADT TWEAK END + // ADT TWEAK END private void OnMeleeLunge(MeleeLungeEvent ev) { var ent = GetEntity(ev.Entity); diff --git a/Content.Server/ADT/_RMC14/Inventory/CMInventorySystem.cs b/Content.Server/ADT/_RMC14/Inventory/CMInventorySystem.cs deleted file mode 100644 index c8ffb1ba4fc..00000000000 --- a/Content.Server/ADT/_RMC14/Inventory/CMInventorySystem.cs +++ /dev/null @@ -1,5 +0,0 @@ -using Content.Shared._RMC14.Inventory; - -namespace Content.Server._RMC14.Inventory; - -public sealed class CMInventorySystem : SharedCMInventorySystem; diff --git a/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticSystem.cs b/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticSystem.cs index 049439c315b..d70d58ea8c7 100644 --- a/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticSystem.cs +++ b/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagneticSystem.cs @@ -1,9 +1,7 @@ -using Content.Shared._RMC14.Inventory; -using Content.Shared.Hands; +using Content.Shared.Hands; using Content.Shared.Interaction.Events; using Content.Shared.Inventory; using Content.Shared.Popups; -using Content.Shared.Throwing; namespace Content.Shared._RMC14.Armor.Magnetic; @@ -11,12 +9,10 @@ public sealed class RMCMagneticSystem : EntitySystem { [Dependency] private readonly InventorySystem _inventory = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; - [Dependency] private readonly ThrownItemSystem _thrownItem = default!; public override void Initialize() { SubscribeLocalEvent(OnMagneticItemDropped); - SubscribeLocalEvent(OnMagneticItemRMCDropped); SubscribeLocalEvent(OnMagneticItemDropAttempt); } @@ -25,11 +21,6 @@ private void OnMagneticItemDropped(Entity ent, ref Dro TryReturn(ent, args.User); } - private void OnMagneticItemRMCDropped(Entity ent, ref RMCDroppedEvent args) - { - TryReturn(ent, args.User); - } - private void OnMagneticItemDropAttempt(Entity ent, ref DropAttemptEvent args) { args.Cancel(); @@ -66,7 +57,7 @@ public override void Update(float frameTime) { if (_inventory.TryGetSlotEntity(user, "outerClothing", out _)) { - if (_inventory.TryEquip(user, uid, slot.ID, force: false)) + if (_inventory.TryEquip(user, uid, slot.ID, force: true)) { var popup = Loc.GetString("rmc-magnetize-return", ("item", uid), diff --git a/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagnetizeItemEvent.cs b/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagnetizeItemEvent.cs deleted file mode 100644 index c922aa48992..00000000000 --- a/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCMagnetizeItemEvent.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Content.Shared.Inventory; - -namespace Content.Shared._RMC14.Armor.Magnetic; - -[ByRefEvent] -public record struct RMCMagnetizeItemEvent( - EntityUid User, - SlotFlags MagnetizeToSlots, - SlotFlags TargetSlots, - EntityUid? Magnetizer = null -) : IInventoryRelayEvent; diff --git a/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCReturnToInventoryComponent.cs b/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCReturnToInventoryComponent.cs index 5d85fa47e1e..23dbc58ac0d 100644 --- a/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCReturnToInventoryComponent.cs +++ b/Content.Shared/ADT/_RMC14/Armor/Magnetic/RMCReturnToInventoryComponent.cs @@ -9,9 +9,6 @@ public sealed partial class RMCReturnToInventoryComponent : Component [DataField, AutoNetworkedField] public EntityUid User; - [DataField, AutoNetworkedField] - public EntityUid Magnetizer; - [DataField, AutoNetworkedField] public bool Returned; } diff --git a/Content.Shared/ADT/_RMC14/CCVar/RMCCVars.cs b/Content.Shared/ADT/_RMC14/CCVar/RMCCVars.cs deleted file mode 100644 index ca8f695e1e4..00000000000 --- a/Content.Shared/ADT/_RMC14/CCVar/RMCCVars.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Robust.Shared; -using Robust.Shared.Configuration; - -namespace Content.Shared._RMC14.CCVar; - -[CVarDefs] -public sealed class RMCCVars : CVars -{ - public static readonly CVarDef RMCActiveInputMoverEnabled = - CVarDef.Create("rmc.active_input_mover_enabled", true, CVar.REPLICATED | CVar.SERVER); -} diff --git a/Content.Shared/ADT/_RMC14/Input/ActiveInputMoverComponent.cs b/Content.Shared/ADT/_RMC14/Input/ActiveInputMoverComponent.cs deleted file mode 100644 index 0c98fa7b5e8..00000000000 --- a/Content.Shared/ADT/_RMC14/Input/ActiveInputMoverComponent.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Robust.Shared.GameStates; - -namespace Content.Shared._RMC14.Input; - -[RegisterComponent, NetworkedComponent] -[Access(typeof(RMCInputSystem))] -public sealed partial class ActiveInputMoverComponent : Component; diff --git a/Content.Shared/ADT/_RMC14/Input/CMKeyFunctions.cs b/Content.Shared/ADT/_RMC14/Input/CMKeyFunctions.cs index cf25188c598..1fb151bf921 100644 --- a/Content.Shared/ADT/_RMC14/Input/CMKeyFunctions.cs +++ b/Content.Shared/ADT/_RMC14/Input/CMKeyFunctions.cs @@ -12,8 +12,4 @@ public sealed class CMKeyFunctions public static readonly BoundKeyFunction RMCFieldStripHeldItem = "RMCFieldStripHeldItem"; public static readonly BoundKeyFunction RMCCycleFireMode = "RMCCycleFireMode"; public static readonly BoundKeyFunction CMUniqueAction = "CMUniqueAction"; - public static readonly BoundKeyFunction CMHolsterPrimary = "CMHolsterPrimary"; - public static readonly BoundKeyFunction CMHolsterSecondary = "CMHolsterSecondary"; - public static readonly BoundKeyFunction CMHolsterTertiary = "CMHolsterTertiary"; - public static readonly BoundKeyFunction CMHolsterQuaternary = "CMHolsterQuaternary"; } diff --git a/Content.Shared/ADT/_RMC14/Input/RMCInputSystem.cs b/Content.Shared/ADT/_RMC14/Input/RMCInputSystem.cs deleted file mode 100644 index c1da449df21..00000000000 --- a/Content.Shared/ADT/_RMC14/Input/RMCInputSystem.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Content.Shared._RMC14.CCVar; -using Content.Shared.Movement.Components; -using Robust.Shared.Configuration; -using Robust.Shared.Player; - -namespace Content.Shared._RMC14.Input; - -public sealed class RMCInputSystem : EntitySystem -{ - [Dependency] private readonly IConfigurationManager _config = default!; - - private bool _activeInputMoverEnabled; - - private EntityQuery _actorQuery; - - public override void Initialize() - { - _actorQuery = GetEntityQuery(); - - SubscribeLocalEvent(OnActiveMapInit); - SubscribeLocalEvent(OnActiveAttached); - SubscribeLocalEvent(OnActiveDetached); - - Subs.CVar(_config, RMCCVars.RMCActiveInputMoverEnabled, v => _activeInputMoverEnabled = v, true); - } - - private void OnActiveMapInit(Entity ent, ref MapInitEvent args) - { - if (!_activeInputMoverEnabled) - return; - - if (_actorQuery.HasComp(ent)) - EnsureComp(ent); - else - RemCompDeferred(ent); - } - - private void OnActiveAttached(Entity ent, ref PlayerAttachedEvent args) - { - if (!_activeInputMoverEnabled) - return; - - EnsureComp(ent); - } - - private void OnActiveDetached(Entity ent, ref PlayerDetachedEvent args) - { - if (!_activeInputMoverEnabled) - return; - - RemCompDeferred(ent); - } -} diff --git a/Content.Shared/ADT/_RMC14/Inventory/CMHolsterChoose.cs b/Content.Shared/ADT/_RMC14/Inventory/CMHolsterChoose.cs deleted file mode 100644 index 47a75483dac..00000000000 --- a/Content.Shared/ADT/_RMC14/Inventory/CMHolsterChoose.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Robust.Shared.Serialization; - -namespace Content.Shared._RMC14.Inventory; - -[Serializable, NetSerializable] -public enum CMHolsterChoose -{ - First, - Last -} diff --git a/Content.Shared/ADT/_RMC14/Inventory/CMHolsterComponent.cs b/Content.Shared/ADT/_RMC14/Inventory/CMHolsterComponent.cs deleted file mode 100644 index 4e45e5ea770..00000000000 --- a/Content.Shared/ADT/_RMC14/Inventory/CMHolsterComponent.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Robust.Shared.Audio; -using Robust.Shared.GameStates; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; -using Content.Shared.Whitelist; - -namespace Content.Shared._RMC14.Inventory; - -// TODO RMC14 add to rifle holster -// TODO RMC14 add to machete scabbard pouch -// TODO RMC14 add to all large scabbards (machete scabbard, katana scabbard, m63 holster rig) -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true), AutoGenerateComponentPause] -[Access(typeof(SharedCMInventorySystem))] -public sealed partial class CMHolsterComponent : Component -{ - // List of entities "inside" the holster - [DataField] - public List Contents = new(); - - // Whitelist for entities that can be (un)holstered - // Note: this does not block them from being inserted (use other whitelists for that), - // this is here to prevent "unholstering" non-weapons (e.g. tools from the combat toolbelt) - [DataField] - public EntityWhitelist? Whitelist; - - // Variables to mitigate holster spamming - [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField, AutoPausedField] - public TimeSpan LastEjectAt; - - [DataField, AutoNetworkedField] - public TimeSpan? Cooldown; - - [DataField, AutoNetworkedField] - public string? CooldownPopup; - - /// - /// Sound played whenever an entity is inserted into holster. - /// - [DataField] - public SoundSpecifier? InsertSound = new SoundPathSpecifier("/Audio/Corvax/Weapons/Guns/Cock/shotgun_cock.ogg"); // затычка - - /// - /// Sound played whenever an entity is removed from holster. - /// - [DataField] - public SoundSpecifier? EjectSound = new SoundPathSpecifier("/Audio/Corvax/Weapons/Guns/Cock/shotgun_cock.ogg"); // затычка -} diff --git a/Content.Shared/ADT/_RMC14/Inventory/CMHolsterLayers.cs b/Content.Shared/ADT/_RMC14/Inventory/CMHolsterLayers.cs deleted file mode 100644 index b1129ce9361..00000000000 --- a/Content.Shared/ADT/_RMC14/Inventory/CMHolsterLayers.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Robust.Shared.Serialization; - -namespace Content.Shared._RMC14.Inventory; - -[Serializable, NetSerializable] -public enum CMHolsterLayers -{ - Fill, // For displaying the weapon underlay -} diff --git a/Content.Shared/ADT/_RMC14/Inventory/CMHolsterVisuals.cs b/Content.Shared/ADT/_RMC14/Inventory/CMHolsterVisuals.cs deleted file mode 100644 index fc9b37dd906..00000000000 --- a/Content.Shared/ADT/_RMC14/Inventory/CMHolsterVisuals.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Robust.Shared.Serialization; - -namespace Content.Shared._RMC14.Inventory; - -[Serializable, NetSerializable] -public enum CMHolsterVisuals -{ - Empty, // TODO: account for the gunslinger belt - Full, -} diff --git a/Content.Shared/ADT/_RMC14/Inventory/CMInventoryExtensions.cs b/Content.Shared/ADT/_RMC14/Inventory/CMInventoryExtensions.cs deleted file mode 100644 index 977ac2ad16e..00000000000 --- a/Content.Shared/ADT/_RMC14/Inventory/CMInventoryExtensions.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Content.Shared.Item; -using Content.Shared.Storage; -using Content.Shared.Storage.EntitySystems; - -namespace Content.Shared._RMC14.Inventory; - -public static class CMInventoryExtensions -{ - public static bool TryGetFirst(EntityUid storageId, EntityUid itemId, out ItemStorageLocation location) - { - location = default; - - var entities = IoCManager.Resolve(); - var storageSystem = entities.System(); - - if (!entities.TryGetComponent(storageId, out StorageComponent? storage) || - !entities.TryGetComponent(itemId, out ItemComponent? item)) - { - return false; - } - - var storageBounding = storage.Grid.GetBoundingBox(); - - for (var y = storageBounding.Bottom; y <= storageBounding.Top; y++) - { - for (var x = storageBounding.Left; x <= storageBounding.Right; x++) - { - location = new ItemStorageLocation(0, (x, y)); - if (storageSystem.ItemFitsInGridLocation(itemId, storageId, location)) - { - return true; - } - } - } - - location = default; - return false; - } -} diff --git a/Content.Shared/ADT/_RMC14/Inventory/CMItemSlotsComponent.cs b/Content.Shared/ADT/_RMC14/Inventory/CMItemSlotsComponent.cs deleted file mode 100644 index aad4ad69387..00000000000 --- a/Content.Shared/ADT/_RMC14/Inventory/CMItemSlotsComponent.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Content.Shared.Containers.ItemSlots; -using Robust.Shared.GameStates; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; - -namespace Content.Shared._RMC14.Inventory; - -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true), AutoGenerateComponentPause] -[Access(typeof(SharedCMInventorySystem))] -public sealed partial class CMItemSlotsComponent : Component -{ - [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField, AutoPausedField] - public TimeSpan LastEjectAt; - - [DataField, AutoNetworkedField] - public TimeSpan? Cooldown; - - [DataField, AutoNetworkedField] - public string? CooldownPopup; - - [DataField, AutoNetworkedField] - public int? Count; - - [DataField, AutoNetworkedField] - public ItemSlot? Slot; - - [DataField, AutoNetworkedField] - public EntProtoId? StartingItem; -} diff --git a/Content.Shared/ADT/_RMC14/Inventory/CMItemSlotsLayers.cs b/Content.Shared/ADT/_RMC14/Inventory/CMItemSlotsLayers.cs deleted file mode 100644 index 606faaea066..00000000000 --- a/Content.Shared/ADT/_RMC14/Inventory/CMItemSlotsLayers.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Robust.Shared.Serialization; - -namespace Content.Shared._RMC14.Inventory; - -[Serializable, NetSerializable] -public enum CMItemSlotsLayers -{ - Fill, -} diff --git a/Content.Shared/ADT/_RMC14/Inventory/CMItemSlotsVisuals.cs b/Content.Shared/ADT/_RMC14/Inventory/CMItemSlotsVisuals.cs deleted file mode 100644 index fd4568312ad..00000000000 --- a/Content.Shared/ADT/_RMC14/Inventory/CMItemSlotsVisuals.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Robust.Shared.Serialization; - -namespace Content.Shared._RMC14.Inventory; - -[Serializable, NetSerializable] -public enum CMItemSlotsVisuals -{ - Empty, - Low, - Medium, - High, - Full, -} diff --git a/Content.Shared/ADT/_RMC14/Inventory/CMVirtualItemComponent.cs b/Content.Shared/ADT/_RMC14/Inventory/CMVirtualItemComponent.cs deleted file mode 100644 index f0f1ef6d22a..00000000000 --- a/Content.Shared/ADT/_RMC14/Inventory/CMVirtualItemComponent.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Robust.Shared.GameStates; - -namespace Content.Shared._RMC14.Inventory; - -[RegisterComponent, NetworkedComponent] -[Access(typeof(SharedCMInventorySystem))] -public sealed partial class CMVirtualItemComponent : Component; diff --git a/Content.Shared/ADT/_RMC14/Inventory/IsUnholsterableEvent.cs b/Content.Shared/ADT/_RMC14/Inventory/IsUnholsterableEvent.cs deleted file mode 100644 index 51956c76452..00000000000 --- a/Content.Shared/ADT/_RMC14/Inventory/IsUnholsterableEvent.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Content.Shared._RMC14.Inventory; - -[ByRefEvent] -public record struct IsUnholsterableEvent(bool Unholsterable); diff --git a/Content.Shared/ADT/_RMC14/Inventory/RMCDroppedEvent.cs b/Content.Shared/ADT/_RMC14/Inventory/RMCDroppedEvent.cs deleted file mode 100644 index 08c1cbaec67..00000000000 --- a/Content.Shared/ADT/_RMC14/Inventory/RMCDroppedEvent.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Content.Shared._RMC14.Inventory; - -[ByRefEvent] -public readonly record struct RMCDroppedEvent(EntityUid User); diff --git a/Content.Shared/ADT/_RMC14/Inventory/SharedCMInventorySystem.cs b/Content.Shared/ADT/_RMC14/Inventory/SharedCMInventorySystem.cs deleted file mode 100644 index c736c8725aa..00000000000 --- a/Content.Shared/ADT/_RMC14/Inventory/SharedCMInventorySystem.cs +++ /dev/null @@ -1,661 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using Content.Shared._RMC14.Input; -using Content.Shared.Administration.Logs; -using Content.Shared.Clothing.Components; -using Content.Shared.Containers.ItemSlots; -using Content.Shared.Database; -using Content.Shared.Hands.Components; -using Content.Shared.Hands.EntitySystems; -using Content.Shared.Interaction; -using Content.Shared.Inventory; -using Content.Shared.Item; -using Content.Shared.Popups; -using Content.Shared.Storage; -using Content.Shared.Storage.EntitySystems; -using Content.Shared.Verbs; -using Content.Shared.Weapons.Melee; -using Content.Shared.Weapons.Ranged.Components; -using Content.Shared.Whitelist; -using Robust.Shared.Audio.Systems; -using Robust.Shared.Containers; -using Robust.Shared.Input.Binding; -using Robust.Shared.Timing; -using Robust.Shared.Utility; - -namespace Content.Shared._RMC14.Inventory; - -public abstract class SharedCMInventorySystem : EntitySystem -{ - [Dependency] private readonly ISharedAdminLogManager _adminLog = default!; - [Dependency] private readonly SharedAppearanceSystem _appearance = default!; - [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] private readonly SharedContainerSystem _container = default!; - [Dependency] private readonly SharedHandsSystem _hands = default!; - [Dependency] private readonly InventorySystem _inventory = default!; - [Dependency] private readonly ItemSlotsSystem _itemSlots = default!; - [Dependency] private readonly SharedPopupSystem _popup = default!; - [Dependency] private readonly SharedStorageSystem _storage = default!; - [Dependency] private readonly IGameTiming _timing = default!; - [Dependency] private readonly EntityWhitelistSystem _whitelist = default!; - [Dependency] private readonly SharedItemSystem _item = default!; - - private readonly SlotFlags[] _order = - [ - SlotFlags.SUITSTORAGE, SlotFlags.BELT, SlotFlags.BACK, - SlotFlags.POCKET, SlotFlags.INNERCLOTHING, SlotFlags.FEET - ]; - - private readonly SlotFlags[] _quickEquipOrder = - [ - SlotFlags.BACK, - SlotFlags.IDCARD, - SlotFlags.INNERCLOTHING, - SlotFlags.OUTERCLOTHING, - SlotFlags.HEAD, - SlotFlags.FEET, - SlotFlags.MASK, - SlotFlags.GLOVES, - SlotFlags.EARS, - SlotFlags.EYES, - SlotFlags.BELT, - SlotFlags.SUITSTORAGE, - SlotFlags.NECK, - SlotFlags.POCKET, - SlotFlags.LEGS - ]; - - public override void Initialize() - { - SubscribeLocalEvent(AllowUnholster); - SubscribeLocalEvent(AllowUnholster); - - SubscribeLocalEvent(OnSlotsFillMapInit); - SubscribeLocalEvent(OnSlotsComponentHandleState); - SubscribeLocalEvent(OnSlotsActivateInWorld); - SubscribeLocalEvent(OnSlotsEjectAttempt); - SubscribeLocalEvent(OnSlotsEntInsertedIntoContainer); - SubscribeLocalEvent(OnSlotsEntRemovedFromContainer); - - SubscribeLocalEvent>(OnHolsterGetAltVerbs); - SubscribeLocalEvent(OnHolsterComponentHandleState); - SubscribeLocalEvent(OnHolsterEntInsertedIntoContainer); - SubscribeLocalEvent(OnHolsterEntRemovedFromContainer); - - CommandBinds.Builder - .Bind(CMKeyFunctions.CMHolsterPrimary, - InputCmdHandler.FromDelegate(session => - { - if (session?.AttachedEntity is { } entity) - OnHolster(entity, 0); - }, handle: false)) - .Bind(CMKeyFunctions.CMHolsterSecondary, - InputCmdHandler.FromDelegate(session => - { - if (session?.AttachedEntity is { } entity) - OnHolster(entity, 1); - }, handle: false)) - .Bind(CMKeyFunctions.CMHolsterTertiary, - InputCmdHandler.FromDelegate(session => - { - if (session?.AttachedEntity is { } entity) - OnHolster(entity, 2); - }, handle: false)) - .Bind(CMKeyFunctions.CMHolsterQuaternary, - InputCmdHandler.FromDelegate(session => - { - if (session?.AttachedEntity is { } entity) - OnHolster(entity, 3, CMHolsterChoose.Last); - }, handle: false)) - .Register(); - } - - private void OnHolsterGetAltVerbs(EntityUid holster, CMHolsterComponent comp, GetVerbsEvent args) - { - if (!args.CanAccess || !args.CanInteract) - return; - - if (comp.Contents.Count == 0) - return; - - // CMItemSlots-based holsters have their own eject verb, no need to add a duplicate - if (HasComp(holster)) - return; - - AlternativeVerb holsterVerb = new() - { - Act = () => Unholster(args.User, holster, out _), - Text = Loc.GetString("rmc-storage-holster-eject-verb"), - IconEntity = GetNetEntity(comp.Contents[0]), - Priority = 5 // Higher priority to appear above folding verbs (for webbing-based holsters) - }; - args.Verbs.Add(holsterVerb); - } - - public override void Shutdown() - { - base.Shutdown(); - CommandBinds.Unregister(); - } - - private void AllowUnholster(Entity ent, ref IsUnholsterableEvent args) where T : IComponent? - { - args.Unholsterable = true; - } - - private void OnSlotsFillMapInit(Entity ent, ref MapInitEvent args) - { - if (ent.Comp.Slot is not { } slot || ent.Comp.Count is not { } count) - return; - - var itemId = ent.Comp.StartingItem; - var slots = EnsureComp(ent); - var coordinates = Transform(ent).Coordinates; - for (var i = 0; i < count; i++) - { - var n = i + 1; - var copy = new ItemSlot(slot); - copy.Name = $"{copy.Name} {n}"; - - _itemSlots.AddItemSlot(ent, $"{slot.Name}{n}", copy); - - if (itemId != null) - { - if (copy.ContainerSlot is { } containerSlot) - { - var item = Spawn(itemId, coordinates); - _container.Insert(item, containerSlot); - } - else - { - copy.StartingItem = itemId; - } - } - } - - ContentsUpdated(ent); - Dirty(ent, slots); - } - - private void OnSlotsComponentHandleState(Entity ent, ref AfterAutoHandleStateEvent args) - { - ContentsUpdated(ent); - } - - private void OnHolsterComponentHandleState(Entity ent, ref AfterAutoHandleStateEvent args) - { - ContentsUpdated(ent); - } - - private void OnSlotsActivateInWorld(Entity ent, ref ActivateInWorldEvent args) - { - // If holster belongs to storage item, open it instead of unholstering - if (HasComp(ent)) - return; - - PickupSlot(args.User, ent); - } - - private void OnSlotsEjectAttempt(Entity ent, ref ItemSlotEjectAttemptEvent args) - { - if (args.Cancelled) - return; - - if (ent.Comp.Cooldown is { } cooldown && - _timing.CurTime < ent.Comp.LastEjectAt + cooldown) - { - args.Cancelled = true; - } - } - - protected void OnSlotsEntInsertedIntoContainer(Entity ent, ref EntInsertedIntoContainerMessage args) - { - ContentsUpdated(ent); - } - - protected void OnSlotsEntRemovedFromContainer(Entity ent, ref EntRemovedFromContainerMessage args) - { - if (!_timing.ApplyingState) - { - ent.Comp.LastEjectAt = _timing.CurTime; - Dirty(ent); - } - - ContentsUpdated(ent); - } - - protected void OnHolsterEntInsertedIntoContainer(Entity ent, ref EntInsertedIntoContainerMessage args) - { - var item = args.Entity; - var ev = new IsUnholsterableEvent(); - RaiseLocalEvent(item, ref ev); - - if (ev.Unholsterable && // Check if unholsterable - !ent.Comp.Contents.Contains(item) && // Here to prevent holster from counting one item twice - (ent.Comp.Whitelist is not { } whitelist || // Check if no whitelist - _whitelist.IsWhitelistPass(whitelist, item))) // or if item matches whitelist - ent.Comp.Contents.Add(item); - - ContentsUpdated(ent); - } - - protected void OnHolsterEntRemovedFromContainer(Entity ent, ref EntRemovedFromContainerMessage args) - { - if (!_timing.ApplyingState) - { - ent.Comp.LastEjectAt = _timing.CurTime; - Dirty(ent); - } - - var item = args.Entity; - ent.Comp.Contents.Remove(item); - - ContentsUpdated(ent); - } - - protected virtual void ContentsUpdated(Entity ent) - { - var (filled, total) = GetItemSlotsFilled(ent.Owner); - CMItemSlotsVisuals visuals; - if (total == 0) - visuals = CMItemSlotsVisuals.Empty; - else if (filled >= total) - visuals = CMItemSlotsVisuals.Full; - else if (filled >= total * 0.666f) - visuals = CMItemSlotsVisuals.High; - else if (filled >= total * 0.333f) - visuals = CMItemSlotsVisuals.Medium; - else if (filled > 0) - visuals = CMItemSlotsVisuals.Low; - else - visuals = CMItemSlotsVisuals.Empty; - - _appearance.SetData(ent, CMItemSlotsLayers.Fill, visuals); - } - - protected virtual void ContentsUpdated(Entity ent) - { - CMHolsterVisuals visuals = CMHolsterVisuals.Empty; - var size = 0; - - // TODO: account for the gunslinger belt - if (ent.Comp.Contents.Count != 0) - { - // Display weapon underlay - visuals = CMHolsterVisuals.Full; - // Get weapons size to accurately display storage visuals - foreach (var item in ent.Comp.Contents) - { - if (TryComp(item, out ItemComponent? itemComp)) - size += _item.GetItemShape(itemComp).GetArea(); - } - } - - _appearance.SetData(ent, CMHolsterLayers.Fill, visuals); - } - - private bool SlotCanInteract(EntityUid user, EntityUid holster, [NotNullWhen(true)] out ItemSlotsComponent? itemSlots) - { - if (!TryComp(holster, out itemSlots)) - return false; - - // no quick unholstering other's holsters - if (_container.TryGetContainingContainer((holster, null), out var container) && - container.Owner != user && - _inventory.HasSlot(container.Owner, container.ID)) - { - itemSlots = default; - return false; - } - - return true; - } - - private bool PickupSlot(EntityUid user, EntityUid holster) - { - if (!SlotCanInteract(user, holster, out var itemSlots)) - return false; - - foreach (var slot in itemSlots.Slots.Values.OrderBy(s => s.Priority)) - { - var item = slot.ContainerSlot?.ContainedEntity; - if (_itemSlots.TryEjectToHands(holster, slot, user, true)) - { - if (item != null) - _adminLog.Add(LogType.Action, $"{ToPrettyString(user)} unholstered {ToPrettyString(item)}"); - - return true; - } - } - - return false; - } - - private void OnHolster(EntityUid user, int startIndex, CMHolsterChoose choose = CMHolsterChoose.First) - { - if (_hands.TryGetActiveItem(user, out var active)) - { - Holster(user, active.Value); - return; - } - - Unholster(user, startIndex, choose); - } - - private void Holster(EntityUid user, EntityUid item) - { - // TODO RMC14 try uniform-attached weapon and ammo holsters first - var validSlots = new List(); - - var priority = 0; - foreach (var flag in _quickEquipOrder) - { - var slots = _inventory.GetSlotEnumerator(user, flag); - while (slots.MoveNext(out var slot)) - { - if (slot.ContainedEntity is not { } clothing) - { - // If slot is empty and can equip - if (_inventory.CanEquip(user, item, slot.ID, out _)) - { - validSlots.Add(new HolsterSlot(priority, false, slot, user, null)); - } - - continue; - } - - // Check if the slot item has a CMHolsterComponent - if (!TryComp(clothing, out CMHolsterComponent? holster)) - continue; - - // Check if item matches holster whitelist (if it has one) - // This is to prevent e.g. tools from being "holstered" - if (holster.Whitelist is { } whitelist && - !_whitelist.IsWhitelistPass(whitelist, item)) - continue; - - // If holster has ItemSlotsComponent - // Check if can be inserted into item slot - if (HasComp(clothing) && - SlotCanInteract(user, clothing, out var slotComp) && - TryGetAvailableSlot((clothing, slotComp), - item, - user, - out var itemSlot, - emptyOnly: true) && - itemSlot.ContainerSlot != null) - { - validSlots.Add(new HolsterSlot(priority, true, null, clothing, ItemSlot: itemSlot)); - continue; - } - - // If holster has StorageComponent - // And item can be inserted - if (HasComp(clothing) && - _storage.CanInsert(clothing, item, out _)) - { - validSlots.Add(new HolsterSlot(priority, true, null, clothing, null)); - } - } - priority++; - } - - validSlots.Sort(); - - foreach (var slot in validSlots) - { - // Try equip to inventory slot - if (!slot.IsHolster && - slot.Slot != null && - _inventory.TryEquip(user, item, slot.Slot.ID, true, checkDoafter: true)) - return; - - // Try insert into ItemSlot-based holster - if (slot.ItemSlot != null && - _itemSlots.TryInsert(slot.Ent, slot.ItemSlot, item, user, excludeUserAudio: true)) - { - _adminLog.Add(LogType.Action, $"{ToPrettyString(user)} holstered {ToPrettyString(item)}"); - return; - } - - // Try insert into Storage-based holster - if (slot.ItemSlot == null && - TryComp(slot.Ent, out StorageComponent? storage) && - TryComp(slot.Ent, out CMHolsterComponent? holster) && - !holster.Contents.Contains(item) && - _hands.TryDrop(user, item) && - _storage.Insert(slot.Ent, item, out _, user, storage, playSound: false)) - { - holster.Contents.Add(item); - _audio.PlayPredicted(holster.InsertSound, item, user); - _adminLog.Add(LogType.Action, $"{ToPrettyString(user)} holstered {ToPrettyString(item)}"); - return; - } - } - - _popup.PopupClient(Loc.GetString("cm-inventory-unable-equip"), user, user, PopupType.SmallCaution); - } - - private readonly record struct HolsterSlot( - int Priority, - bool IsHolster, - ContainerSlot? Slot, - EntityUid Ent, - ItemSlot? ItemSlot) : IComparable - { - public int CompareTo(HolsterSlot other) - { - // Sort holsters first - // Then sort by priority between each holster and non-holster - - // If holster and holster - // Sort by priority higher first - if (IsHolster && other.IsHolster) - return Priority.CompareTo(other.Priority); - - // If only first is holster, then sort it higher - if (IsHolster) - return -1; - return 1; - } - } - - /// - /// Tries to get any slot that the can be inserted into. - /// - /// Entity that is being inserted into. - /// Entity being inserted into . - /// Entity inserting into . - /// The ItemSlot on to insert into. - /// True only returns slots that are empty. - /// False returns any slot that is able to receive . - /// True when a slot is found. Otherwise, false. - private bool TryGetAvailableSlot(Entity ent, - EntityUid item, - Entity? userEnt, - [NotNullWhen(true)] out ItemSlot? itemSlot, - bool emptyOnly = false) - { - // TODO Replace with ItemSlotsSystem version when upstream is merged - itemSlot = null; - - if (userEnt is { } user && Resolve(user, ref user.Comp) && _hands.IsHolding(user, item)) - { - if (!_hands.CanDrop(user, item, user.Comp)) - return false; - } - - if (!Resolve(ent, ref ent.Comp, false)) - return false; - - var slots = new List(); - foreach (var slot in ent.Comp.Slots.Values) - { - if (emptyOnly && slot.ContainerSlot?.ContainedEntity != null) - continue; - - if (_itemSlots.CanInsert(ent, item, userEnt, slot)) - slots.Add(slot); - } - - if (slots.Count == 0) - return false; - - slots.Sort(ItemSlotsSystem.SortEmpty); - - itemSlot = slots[0]; - return true; - } - - // Get last item inserted into holster (can also be used to check if holster is empty) - private bool TryGetLastInserted(Entity holster, out EntityUid item) - { - item = default; - - if (!Resolve(holster, ref holster.Comp)) - return false; - - var contents = holster.Comp.Contents; - - if (contents.Count == 0) - return false; - - item = contents[contents.Count - 1]; - return true; - } - - private void Unholster(EntityUid user, int startIndex, CMHolsterChoose choose) - { - if (_order.Length == 0) - return; - - if (startIndex >= _order.Length) - startIndex = _order.Length - 1; - - for (var i = startIndex; i < _order.Length; i++) - { - if (Unholster(user, _order[i], choose, out var stop) || stop) - return; - } - - for (var i = 0; i < startIndex; i++) - { - if (Unholster(user, _order[i], choose, out var stop) || stop) - return; - } - } - - private bool Unholster(EntityUid user, SlotFlags flag, CMHolsterChoose choose, out bool stop) - { - stop = false; - var enumerator = _inventory.GetSlotEnumerator(user, flag); - - if (choose == CMHolsterChoose.Last) - { - var items = new List(); - while (enumerator.NextItem(out var next)) - { - items.Add(next); - } - - items.Reverse(); - - foreach (var item in items) - { - if (Unholster(user, item, out stop)) - return true; - } - } - while (enumerator.NextItem(out var item)) - { - if (Unholster(user, item, out stop)) - return true; - } - - return false; - } - - private bool Unholster(EntityUid user, EntityUid item, out bool stop) - { - stop = false; - if (TryComp(item, out CMHolsterComponent? holster)) - { - if (holster.Cooldown is { } cooldown && - _timing.CurTime < holster.LastEjectAt + cooldown) - { - stop = true; - _popup.PopupPredicted(holster.CooldownPopup, user, user, PopupType.SmallCaution); - return false; - } - - if (TryComp(item, out StorageComponent? storage) && - TryGetLastInserted((item, holster), out var weapon)) - { - if (!_hands.TryPickup(user, weapon)) - return false; - - holster.Contents.Remove(weapon); - _audio.PlayPredicted(holster.EjectSound, item, user); - stop = true; - return true; - } - - if (PickupSlot(user, item)) - { - _adminLog.Add(LogType.Action, $"{ToPrettyString(user)} unholstered {ToPrettyString(item)}"); - return true; - } - } - - var ev = new IsUnholsterableEvent(); - RaiseLocalEvent(item, ref ev); - - if (!ev.Unholsterable) - return false; - - _adminLog.Add(LogType.Action, $"{ToPrettyString(user)} unholstered {ToPrettyString(item)}"); - return _hands.TryPickup(user, item); - } - - public bool TryEquipClothing(EntityUid user, Entity clothing) - { - foreach (var order in _quickEquipOrder) - { - if ((clothing.Comp.Slots & order) == 0) - continue; - - if (!_inventory.TryGetContainerSlotEnumerator(user, out var slots, clothing.Comp.Slots)) - continue; - - while (slots.MoveNext(out var slot)) - { - if (_inventory.TryEquip(user, clothing, slot.ID)) - return true; - } - } - - return false; - } - - public (int Filled, int Total) GetItemSlotsFilled(Entity slots) - { - if (!Resolve(slots, ref slots.Comp, false)) - return (0, 0); - - var total = slots.Comp.Slots.Count; - if (total == 0) - return (0, 0); - - var filled = 0; - foreach (var (_, slot) in slots.Comp.Slots) - { - if (slot.ContainerSlot?.ContainedEntity is { } contained && - !TerminatingOrDeleted(contained)) - { - filled++; - } - } - - return (filled, slots.Comp.Slots.Count); - } -} diff --git a/Content.Shared/ADT/_RMC14/Random/SplitMix64.cs b/Content.Shared/ADT/_RMC14/Random/SplitMix64.cs deleted file mode 100644 index 8f427f057c0..00000000000 --- a/Content.Shared/ADT/_RMC14/Random/SplitMix64.cs +++ /dev/null @@ -1,39 +0,0 @@ -namespace Content.Shared._RMC14.Random; - -/// -/// Seed initializer PRNG (splitmix64). -/// -/// http://prng.di.unimi.it/splitmix64.c -public record struct SplitMix64 -{ - /// - /// Creates a new instance. - /// - public SplitMix64() - : this(DateTime.UtcNow.Ticks) - { - } - - /// - /// Creates a new instance. - /// - /// Seed value. - public SplitMix64(long seed) - { - x = (UInt64) seed; - } - - - private UInt64 x; - - /// - /// Returns the next 64-bit pseudo-random number. - /// - public long Next() - { - UInt64 z = unchecked(x += 0x9e3779b97f4a7c15); - z = unchecked((z ^ (z >> 30)) * 0xbf58476d1ce4e5b9); - z = unchecked((z ^ (z >> 27)) * 0x94d049bb133111eb); - return unchecked((Int64) (z ^ (z >> 31))); - } -} diff --git a/Content.Shared/ADT/_RMC14/Random/Xoroshiro64S.cs b/Content.Shared/ADT/_RMC14/Random/Xoroshiro64S.cs deleted file mode 100644 index 68d525e31b2..00000000000 --- a/Content.Shared/ADT/_RMC14/Random/Xoroshiro64S.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System.Runtime.CompilerServices; - -namespace Content.Shared._RMC14.Random; - -// https://github.com/medo64/Medo.ScrambledLinear/blob/main/src/Xoroshiro/Xoroshiro64S.cs -/// -/// 32-bit random number generator intended for floating point numbers with 64-bit state (xoroshiro64*). -/// -/// http://prng.di.unimi.it/xoroshiro64star.c -public record struct Xoroshiro64S -{ - /// - /// Creates a new instance. - /// - public Xoroshiro64S() - : this(DateTime.UtcNow.Ticks) - { - } - - /// - /// Creates a new instance. - /// - /// Seed value. - public Xoroshiro64S(long seed) - { - var sm64 = new SplitMix64(seed); - _s0 = unchecked((UInt32) sm64.Next()); - _s1 = unchecked((UInt32) sm64.Next()); - } - - - private UInt32 _s0; - private UInt32 _s1; - - /// - /// Returns the next 32-bit pseudo-random number. - /// - public int Next() - { - UInt32 s0 = _s0; - UInt32 s1 = _s1; - UInt32 result = unchecked(s0 * (UInt32) 0x9E3779BB); - - s1 ^= s0; - _s0 = RotateLeft(s0, 26) ^ s1 ^ (s1 << 9); - _s1 = RotateLeft(s1, 13); - - return Math.Abs((int) result); - } - - public float NextFloat() - { - return Next() * 4.6566128752458E-10f; - } - - public float NextFloat(float min, float max) - { - return NextFloat() * (max - min) + min; - } - - private static UInt32 RotateLeft(UInt32 x, int k) - { - return (x << k) | (x >> (32 - k)); - } -} diff --git a/Content.Shared/ADT/_RMC14/Tackle/CMDisarmEvent.cs b/Content.Shared/ADT/_RMC14/Tackle/CMDisarmEvent.cs deleted file mode 100644 index 0847cab7c35..00000000000 --- a/Content.Shared/ADT/_RMC14/Tackle/CMDisarmEvent.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Content.Shared._RMC14.Tackle; - -[ByRefEvent] -public record struct CMDisarmEvent(EntityUid User, bool Handled = false); diff --git a/Content.Shared/ADT/_RMC14/Tackle/TackleComponent.cs b/Content.Shared/ADT/_RMC14/Tackle/TackleComponent.cs deleted file mode 100644 index dd70dc85f46..00000000000 --- a/Content.Shared/ADT/_RMC14/Tackle/TackleComponent.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Content.Shared.FixedPoint; -using Robust.Shared.GameStates; - -namespace Content.Shared._RMC14.Tackle; - -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] -public sealed partial class TackleComponent : Component -{ - [DataField, AutoNetworkedField] - public FixedPoint2 Strength = 1; - - [DataField, AutoNetworkedField] - public FixedPoint2 Threshold = 4; - - [DataField, AutoNetworkedField] - public TimeSpan Stun = TimeSpan.FromSeconds(5); - - [DataField, AutoNetworkedField] - public float Chance = 0.35f; -} diff --git a/Content.Shared/ADT/_RMC14/Tackle/TackleSystem.cs b/Content.Shared/ADT/_RMC14/Tackle/TackleSystem.cs deleted file mode 100644 index 1f11d39a777..00000000000 --- a/Content.Shared/ADT/_RMC14/Tackle/TackleSystem.cs +++ /dev/null @@ -1,112 +0,0 @@ -using Content.Shared.Administration.Logs; -using Content.Shared.CombatMode; -using Content.Shared.Damage.Systems; -using Content.Shared.Database; -using Content.Shared.Effects; -using Content.Shared.Hands.EntitySystems; -using Content.Shared.Popups; -using Content.Shared.Stunnable; -using Robust.Shared.Audio; -using Robust.Shared.Audio.Systems; -using Robust.Shared.Network; -using Robust.Shared.Player; -using Robust.Shared.Random; -using Robust.Shared.Timing; - -namespace Content.Shared._RMC14.Tackle; - -public sealed class TackleSystem : EntitySystem -{ - [Dependency] private readonly ISharedAdminLogManager _adminLog = default!; - [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] private readonly SharedColorFlashEffectSystem _colorFlash = default!; - [Dependency] private readonly INetManager _net = default!; - [Dependency] private readonly SharedPopupSystem _popup = default!; - [Dependency] private readonly SharedStunSystem _stun = default!; - [Dependency] private readonly IGameTiming _timing = default!; - - public override void Initialize() - { - SubscribeLocalEvent(OnDisarmed, before: [typeof(SharedHandsSystem), typeof(StaminaSystem)]); - } - - private void OnDisarmed(Entity target, ref CMDisarmEvent args) - { - var user = args.User; - if (!TryComp(user, out TackleComponent? tackle)) - return; - - args.Handled = true; - - _colorFlash.RaiseEffect(Color.Aqua, new List { target.Owner }, Filter.PvsExcept(user)); - - var time = _timing.CurTime; - var recently = EnsureComp(target); - recently.LastTackled = time; - recently.LastTackledDuration = target.Comp.ExpireAfter; - recently.Current += tackle.Strength; - - Dirty(target, recently); - - if (recently.Current < tackle.Threshold) - { - //_adminLog.Add(LogType.RMCTackle, $"{ToPrettyString(user)} tried to tackle {ToPrettyString(target)}."); - - if (_net.IsServer) - _popup.PopupEntity(Loc.GetString("cm-tackle-try-self", ("target", target.Owner)), user, user); - - foreach (var session in Filter.PvsExcept(user).Recipients) - { - if (session.AttachedEntity is not { } recipient) - continue; - - if (recipient == target.Owner) - _popup.PopupEntity(Loc.GetString("cm-tackle-try-target", ("user", user)), user, recipient, PopupType.MediumCaution); - else - _popup.PopupEntity(Loc.GetString("cm-tackle-try-observer", ("user", user), ("target", target.Owner)), user, recipient); - } - - return; - } - else - { - //_adminLog.Add(LogType.RMCTackle, $"{ToPrettyString(user)} tackled down {ToPrettyString(target)}."); - _popup.PopupClient(Loc.GetString("cm-tackle-success-self", ("target", target.Owner)), user, user); - - foreach (var session in Filter.PvsExcept(user).Recipients) - { - if (session.AttachedEntity is not { } recipient) - continue; - - if (recipient == target.Owner) - _popup.PopupEntity(Loc.GetString("cm-tackle-success-target", ("user", user)), user, recipient, PopupType.MediumCaution); - else - _popup.PopupEntity(Loc.GetString("cm-tackle-success-observer", ("user", user), ("target", target.Owner)), user, recipient); - } - } - - if (_net.IsClient) - return; - - if (TryComp(user, out CombatModeComponent? combatMode)) - { - var audioParams = AudioParams.Default.WithVariation(0.025f).WithVolume(5f); - _audio.PlayPredicted(combatMode.DisarmSuccessSound, target, user, audioParams); - } - - _stun.TryParalyze(target, tackle.Stun, true); - } - - public override void Update(float frameTime) - { - base.Update(frameTime); - - var time = _timing.CurTime; - var query = EntityQueryEnumerator(); - while (query.MoveNext(out var uid, out var recently, out _)) - { - if (time > recently.LastTackled + recently.LastTackledDuration) - RemCompDeferred(uid); - } - } -} diff --git a/Content.Shared/ADT/_RMC14/Tackle/TackleableComponent.cs b/Content.Shared/ADT/_RMC14/Tackle/TackleableComponent.cs deleted file mode 100644 index 446a5320554..00000000000 --- a/Content.Shared/ADT/_RMC14/Tackle/TackleableComponent.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Robust.Shared.GameStates; - -namespace Content.Shared._RMC14.Tackle; - -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] -public sealed partial class TackleableComponent : Component -{ - [DataField, AutoNetworkedField] - public TimeSpan ExpireAfter = TimeSpan.FromSeconds(4); -} diff --git a/Content.Shared/ADT/_RMC14/Tackle/TackledRecentlyComponent.cs b/Content.Shared/ADT/_RMC14/Tackle/TackledRecentlyComponent.cs deleted file mode 100644 index 82349489fde..00000000000 --- a/Content.Shared/ADT/_RMC14/Tackle/TackledRecentlyComponent.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Content.Shared.FixedPoint; -using Robust.Shared.GameStates; - -namespace Content.Shared._RMC14.Tackle; - -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] -public sealed partial class TackledRecentlyComponent : Component -{ - [DataField, AutoNetworkedField] - public FixedPoint2 Current; - - [DataField, AutoNetworkedField] - public TimeSpan LastTackled; - - [DataField, AutoNetworkedField] - public TimeSpan LastTackledDuration; -} From b5c22eaf748eec540752d6215accfae612c5a514 Mon Sep 17 00:00:00 2001 From: Eugeny Date: Sun, 15 Dec 2024 03:00:29 +0400 Subject: [PATCH 32/46] =?UTF-8?q?=D1=82=D0=B5=D1=85=D0=BD=D0=BE=D0=BB?= =?UTF-8?q?=D0=BE=D0=B3=D0=B8=D0=B8,=20=D0=BF=D0=BE=D0=BA=D1=83=D0=BF?= =?UTF-8?q?=D0=BA=D0=B8=20=D0=BC=D0=BE=D0=B4=D1=83=D0=BB=D0=B5=D0=B9=20?= =?UTF-8?q?=D0=B2=20=D0=B0=D0=BF=D0=BB=D0=B8=D0=BD=D0=BA=D0=B0=D1=85,=20?= =?UTF-8?q?=D1=81=D0=BE=D1=80=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=BA=D0=B0=20?= =?UTF-8?q?=D1=81=D0=BF=D1=80=D0=B0=D0=B9=D1=82=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Catalog/Fills/Items/weaponcases.ftl | 4 + .../Catalog/Fills/backpacks/duffelbag.ftl | 3 + .../ADT/prototypes/Catalog/store/bobr.ftl | 9 ++ .../Catalog/store/uplink-catalog.ftl | 12 +++ .../Objects/Weapons/Guns/Attachments.ftl | 6 +- .../ru-RU/ADT/prototypes/Research/arsenal.ftl | 4 +- .../ADT/Catalog/Fills/Backpacks/duffelbag.yml | 12 +++ .../ADT/Catalog/Fills/Items/weaponcase.yml | 18 +++- .../Prototypes/ADT/Catalog/boobr_catalog.yml | 33 ++++++ .../Prototypes/ADT/Catalog/uplink_catalog.yml | 58 ++++++++++ .../Guns/Attachments/Actions/actions.yml | 6 +- .../Attachments/barrel_attachment.yml | 20 +++- .../Attachments/rail_attachment.yml | 12 +-- .../Attachments/under_attachment.yml | 18 ++-- .../Objects/Weapons/Guns/Attachments/tags.yml | 3 + .../Objects/Weapons/Guns/Rifles/rifles.yml | 1 + .../Entities/Objects/Weapons/Melee/knife.yml | 2 +- .../Prototypes/ADT/Recipes/Lathes/armory.yml | 100 +++++++++++++++++- Resources/Prototypes/ADT/Research/arsenal.yml | 40 ++++++- .../ADT/Research/mech_tecnology.yml | 54 +++++----- .../Objects/Weapons/Guns/Pistols/pistols.yml | 2 + .../Objects/Weapons/Guns/Rifles/rifles.yml | 2 + .../Objects/Weapons/Guns/SMGs/smgs.yml | 2 + .../Entities/Objects/Weapons/Melee/knife.yml | 5 +- .../Entities/Structures/Machines/lathe.yml | 11 ++ Resources/Prototypes/Research/arsenal.yml | 33 +++--- .../Guns/Attachments/barrel.rsi/antilying.png | Bin 0 -> 402 bytes .../Attachments/barrel.rsi/antilying_a.png | Bin 0 -> 318 bytes .../Guns}/Attachments/barrel.rsi/meta.json | 6 ++ .../Attachments/barrel.rsi/suppressor.png | Bin .../Attachments/barrel.rsi/suppressor_a.png | Bin .../Guns}/Attachments/rail.rsi/magnetic.png | Bin .../Guns}/Attachments/rail.rsi/meta.json | 0 .../Guns}/Attachments/rail.rsi/miniscope.png | Bin .../Attachments/rail.rsi/miniscope_a.png | Bin .../Guns}/Attachments/rail.rsi/reflex.png | Bin .../Guns}/Attachments/rail.rsi/reflex_a.png | Bin .../Attachments/scope_actions.rsi/meta.json | 0 .../scope_actions.rsi/sniperscope.png | Bin .../Attachments/under.rsi/combatknife_a.png | Bin .../Attachments/under.rsi/grenade-on.png | Bin .../Attachments/under.rsi/grenade-open.png | Bin .../Attachments/under.rsi/grenade-open_a.png | Bin .../Guns}/Attachments/under.rsi/grenade.png | Bin .../Guns}/Attachments/under.rsi/grenade_a.png | Bin .../Attachments/under.rsi/lasersight.png | Bin .../Attachments/under.rsi/lasersight_a.png | Bin .../Attachments/under.rsi/masterkey-on.png | Bin .../Guns}/Attachments/under.rsi/masterkey.png | Bin .../Attachments/under.rsi/masterkey_a.png | Bin .../Guns}/Attachments/under.rsi/meta.json | 9 ++ .../Attachments/under.rsi/mosinbayonet.png | Bin .../Attachments/under.rsi/mosinbayonet_a.png | Bin .../Guns/Attachments/under.rsi/tech_basic.png | Bin 0 -> 1112 bytes .../Attachments/under.rsi/tech_extented.png | Bin 0 -> 1103 bytes .../Attachments/under.rsi/uplink_modules.png | Bin 0 -> 1047 bytes .../Attachments/under.rsi/verticalgrip.png | Bin .../Attachments/under.rsi/verticalgrip_a.png | Bin 58 files changed, 419 insertions(+), 66 deletions(-) create mode 100644 Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/barrel.rsi/antilying.png create mode 100644 Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/barrel.rsi/antilying_a.png rename Resources/Textures/ADT/{ => Objects/Weapons/Guns}/Attachments/barrel.rsi/meta.json (78%) rename Resources/Textures/ADT/{ => Objects/Weapons/Guns}/Attachments/barrel.rsi/suppressor.png (100%) rename Resources/Textures/ADT/{ => Objects/Weapons/Guns}/Attachments/barrel.rsi/suppressor_a.png (100%) rename Resources/Textures/ADT/{ => Objects/Weapons/Guns}/Attachments/rail.rsi/magnetic.png (100%) rename Resources/Textures/ADT/{ => Objects/Weapons/Guns}/Attachments/rail.rsi/meta.json (100%) rename Resources/Textures/ADT/{ => Objects/Weapons/Guns}/Attachments/rail.rsi/miniscope.png (100%) rename Resources/Textures/ADT/{ => Objects/Weapons/Guns}/Attachments/rail.rsi/miniscope_a.png (100%) rename Resources/Textures/ADT/{ => Objects/Weapons/Guns}/Attachments/rail.rsi/reflex.png (100%) rename Resources/Textures/ADT/{ => Objects/Weapons/Guns}/Attachments/rail.rsi/reflex_a.png (100%) rename Resources/Textures/ADT/Objects/{ => Weapons/Guns}/Attachments/scope_actions.rsi/meta.json (100%) rename Resources/Textures/ADT/Objects/{ => Weapons/Guns}/Attachments/scope_actions.rsi/sniperscope.png (100%) rename Resources/Textures/ADT/{ => Objects/Weapons/Guns}/Attachments/under.rsi/combatknife_a.png (100%) rename Resources/Textures/ADT/{ => Objects/Weapons/Guns}/Attachments/under.rsi/grenade-on.png (100%) rename Resources/Textures/ADT/{ => Objects/Weapons/Guns}/Attachments/under.rsi/grenade-open.png (100%) rename Resources/Textures/ADT/{ => Objects/Weapons/Guns}/Attachments/under.rsi/grenade-open_a.png (100%) rename Resources/Textures/ADT/{ => Objects/Weapons/Guns}/Attachments/under.rsi/grenade.png (100%) rename Resources/Textures/ADT/{ => Objects/Weapons/Guns}/Attachments/under.rsi/grenade_a.png (100%) rename Resources/Textures/ADT/{ => Objects/Weapons/Guns}/Attachments/under.rsi/lasersight.png (100%) rename Resources/Textures/ADT/{ => Objects/Weapons/Guns}/Attachments/under.rsi/lasersight_a.png (100%) rename Resources/Textures/ADT/{ => Objects/Weapons/Guns}/Attachments/under.rsi/masterkey-on.png (100%) rename Resources/Textures/ADT/{ => Objects/Weapons/Guns}/Attachments/under.rsi/masterkey.png (100%) rename Resources/Textures/ADT/{ => Objects/Weapons/Guns}/Attachments/under.rsi/masterkey_a.png (100%) rename Resources/Textures/ADT/{ => Objects/Weapons/Guns}/Attachments/under.rsi/meta.json (85%) rename Resources/Textures/ADT/{ => Objects/Weapons/Guns}/Attachments/under.rsi/mosinbayonet.png (100%) rename Resources/Textures/ADT/{ => Objects/Weapons/Guns}/Attachments/under.rsi/mosinbayonet_a.png (100%) create mode 100644 Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/tech_basic.png create mode 100644 Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/tech_extented.png create mode 100644 Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/uplink_modules.png rename Resources/Textures/ADT/{ => Objects/Weapons/Guns}/Attachments/under.rsi/verticalgrip.png (100%) rename Resources/Textures/ADT/{ => Objects/Weapons/Guns}/Attachments/under.rsi/verticalgrip_a.png (100%) diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Catalog/Fills/Items/weaponcases.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Catalog/Fills/Items/weaponcases.ftl index 58f7253bce4..85483ed2d32 100644 --- a/Resources/Locale/ru-RU/ADT/prototypes/Catalog/Fills/Items/weaponcases.ftl +++ b/Resources/Locale/ru-RU/ADT/prototypes/Catalog/Fills/Items/weaponcases.ftl @@ -49,3 +49,7 @@ ent-WeaponCaseNTM90GrenadeLauncherAttachment = { ent-WeaponCaseNTM90 } ent-WeaponCaseNTM90UnderBarrelShotGunAttachment = { ent-WeaponCaseNTM90 } .desc = { ent-WeaponCaseNTM90.desc }. .suffix = { "Подствольный дробовик" } + +ent-WeaponCaseNTGunsModules = { ent-WeaponCaseNTM90 } + .desc = { ent-WeaponCaseNTM90.desc }. + .suffix = { "Оружейные модули" } diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Catalog/Fills/backpacks/duffelbag.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Catalog/Fills/backpacks/duffelbag.ftl index e237188eba7..4b8830bbe73 100644 --- a/Resources/Locale/ru-RU/ADT/prototypes/Catalog/Fills/backpacks/duffelbag.ftl +++ b/Resources/Locale/ru-RU/ADT/prototypes/Catalog/Fills/backpacks/duffelbag.ftl @@ -36,3 +36,6 @@ ent-ADTClothingBackpackDuffelSyndicateFilledBlackmail = набор шантаж ent-ADTClothingBackpackDuffelSyndicateFilledElite = набор элитного налетчика .desc = Содержит улучшенный скафандр Синдиката, продвинутые магнитные сапоги и энергомеч с щитом. + +ent-ADTClothingBackpackDuffelSyndicateFilledWeaponAttachments = набор оружейных модулей + .desc = Комплект из вертикальной рукояти, лазерного целеуказателя, коллиматорного и оптического прицелов. diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/bobr.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/bobr.ftl index b2e15d2fc78..1caed113595 100644 --- a/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/bobr.ftl +++ b/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/bobr.ftl @@ -69,3 +69,12 @@ boobr-m90-grenadelauncher-desc = Один из наиболее распрост boobr-m90-shotgun-name = Подствольный дробовик US90 boobr-m90-shotgun-desc = Трехзарядный подствольный дробовик, сделанный изначально для карабина М-90gl. Прекрасно подходит для вышибания дверей или мозгов зомби. + +boobr-weapon-attachments-name = Набор оружейных модулей +boobr-weapon-attachments-desc = Кейс, в котором лежит лазерный целеуказатель, вертикальная рукоять, коллиматорный и оптический прицелы. + +boobr-weapon-attachments-antilying-name = Модуль коррекции огня +boobr-weapon-attachments-antilying-desc = Особо продвинутый модуль, позволяющий попадать даже в лежащих под укрытиями противников. + +boobr-weapon-attachments-suppressor-name = Глушитель +boobr-weapon-attachments-suppressor-desc = Устанавлаемый на ствол универсальный мультикалиберный глушитель. Существенно снижает звук от стрельбы и скрывает дульную вспышку. diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/uplink-catalog.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/uplink-catalog.ftl index 6519dd0b98b..a89c9cd01be 100644 --- a/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/uplink-catalog.ftl +++ b/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/uplink-catalog.ftl @@ -104,3 +104,15 @@ uplink-nukiesShield-desc = Массивный и опасный, двуручн uplink-omnizinpizza-name = коробка с пиццей Синдиката uplink-omnizinpizza-desc = Это коробка, с самой обычной пиццей внутри, это именно то, что используют элитные агенты для перекуса между стрельбой с капитаном, и кражей Иана. + +uplink-attachmentsbundle-name = Набор оружейных модулей +uplink-attachmentsbundle-description = Комплект из вертикальной рукояти, лазерного целеуказателя, коллиматорного и оптического прицелов. + +uplink-lasersight-name = Лазерный целеуказатель +uplink-lasersight-description = Маломощный лазер, закрепляемый под оружием и позволяющий прицеливаться значительно быстрее, особенно с одной руки. + +uplink-attachments-antilying-name = Модуль коррекции огня +uplink-attachments-antilying-description = Особо продвинутый модуль, позволяющий попадать даже в лежащих под укрытиями противников. + +uplink-suppressor-name = Глушитель +uplink-suppressor-description = Устанавлаемый на ствол универсальный мультикалиберный глушитель. Существенно снижает звук от стрельбы и скрывает дульную вспышку. diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Guns/Attachments.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Guns/Attachments.ftl index e928660b057..771def432d6 100644 --- a/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Guns/Attachments.ftl +++ b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Guns/Attachments.ftl @@ -32,4 +32,8 @@ ent-ADTAttachmentLaserSight = лазерный целеуказатель ent-ADTAttachmentSuppressor = глушитель .desc = Устанавлаемый на ствол универсальный мультикалиберный глушитель. Существенно снижает звук от стрельбы и скрывает дульную вспышку. -.suffix = { "Оруж. модуль, Подствольный" } +.suffix = { "Оруж. модуль, Наствольный" } + +ent-ADTAttachmentAntiLyingWarrior = модуль коррекции огня +.desc = Особо продвинутый модуль со встроенными микро пИИ, анализирующим угрозы вокруг. С помощью электромагнита и магии блюспейс-технологий корректирует полет пули так, чтобы она точно попала в цель на своём пути, даже если она залегла под столом или в груде мусора. +.suffix = { "Оруж. модуль, Наствольный" } diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Research/arsenal.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Research/arsenal.ftl index 71f4a916310..012a3e29172 100644 --- a/Resources/Locale/ru-RU/ADT/prototypes/Research/arsenal.ftl +++ b/Resources/Locale/ru-RU/ADT/prototypes/Research/arsenal.ftl @@ -1 +1,3 @@ -research-technology-salvage-weapons-adv = Продвинутое оружие утилизаторов \ No newline at end of file +research-technology-salvage-weapons-adv = Продвинутое оружие утилизаторов +research-technology-modules-based = Базовые оружейные модули +research-technology-modules-extended = Продвинутые оружейные модули diff --git a/Resources/Prototypes/ADT/Catalog/Fills/Backpacks/duffelbag.yml b/Resources/Prototypes/ADT/Catalog/Fills/Backpacks/duffelbag.yml index 328836c322c..3994d3e71d5 100644 --- a/Resources/Prototypes/ADT/Catalog/Fills/Backpacks/duffelbag.yml +++ b/Resources/Prototypes/ADT/Catalog/Fills/Backpacks/duffelbag.yml @@ -210,3 +210,15 @@ amount: 4 - id: ADTCartridgeBlastRocket amount: 4 + +- type: entity + parent: ClothingBackpackDuffelSyndicateBundle + id: ADTClothingBackpackDuffelSyndicateFilledWeaponAttachments + name: weapon attachments bundle + components: + - type: StorageFill + contents: + - id: ADTAttachmentVerticalGrip + - id: ADTAttachmentLaserSight + - id: ADTAttachmentReflexSight + - id: ADTAttachmentT2Miniscope diff --git a/Resources/Prototypes/ADT/Catalog/Fills/Items/weaponcase.yml b/Resources/Prototypes/ADT/Catalog/Fills/Items/weaponcase.yml index 4ee2256410b..7178552c22f 100644 --- a/Resources/Prototypes/ADT/Catalog/Fills/Items/weaponcase.yml +++ b/Resources/Prototypes/ADT/Catalog/Fills/Items/weaponcase.yml @@ -45,12 +45,26 @@ contents: - id: ADTAttachmentM90UnderbarrelShotgun - id: MagazineShotgun - amount: 2 + amount: 3 - id: MagazineShotgunBeanbag amount: 2 - id: MagazineShotgunIncendiary amount: 2 - - id: MagazineShotgunSlug + - id: MagazineShotgunSlug + +- type: entity + id: WeaponCaseNTGunsModules + name: weapon Case + suffix: Weapon Attacments + description: Case with weapons. + parent: WeaponCaseNT + components: + - type: StorageFill + contents: + - id: ADTAttachmentVerticalGrip + - id: ADTAttachmentLaserSight + - id: ADTAttachmentReflexSight + - id: ADTAttachmentT2Miniscope - type: entity id: WeaponCaseNTLecter diff --git a/Resources/Prototypes/ADT/Catalog/boobr_catalog.yml b/Resources/Prototypes/ADT/Catalog/boobr_catalog.yml index d6c44118bc4..51b8047a3c6 100644 --- a/Resources/Prototypes/ADT/Catalog/boobr_catalog.yml +++ b/Resources/Prototypes/ADT/Catalog/boobr_catalog.yml @@ -31,6 +31,39 @@ categories: - ADTUplinkERTAttachments +- type: listing + id: ADTBoberWeaponAttachments + name: boobr-weapon-attachments-name + description: boobr-weapon-attachments-desc + icon: { sprite: /Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi, state: tech_basic } + productEntity: WeaponCaseNTGunsModules + cost: + Productunit: 3 + categories: + - ADTUplinkERTAttachments + +- type: listing + id: ADTBoberAntilyingAttachment + name: boobr-weapon-attachments-antilying-name + description: boobr-weapon-attachments-antilying-desc + icon: { sprite: /Textures/ADT/Objects/Weapons/Guns/Attachments/barrel.rsi, state: antilying } + productEntity: ADTAttachmentAntiLyingWarrior + cost: + Productunit: 4 + categories: + - ADTUplinkERTAttachments + +- type: listing + id: ADTBoberSuppressorAttachment + name: boobr-weapon-attachments-suppressor-name + description: boobr-weapon-attachments-suppressor-desc + icon: { sprite: /Textures/ADT/Objects/Weapons/Guns/Attachments/barrel.rsi, state: suppressor } + productEntity: ADTAttachmentSuppressor + cost: + Productunit: 3 + categories: + - ADTUplinkERTAttachments + - type: listing id: ADTBoberLecter name: boobr-lecter-name diff --git a/Resources/Prototypes/ADT/Catalog/uplink_catalog.yml b/Resources/Prototypes/ADT/Catalog/uplink_catalog.yml index cca40e6eb1a..9f6e6c7a942 100644 --- a/Resources/Prototypes/ADT/Catalog/uplink_catalog.yml +++ b/Resources/Prototypes/ADT/Catalog/uplink_catalog.yml @@ -42,6 +42,9 @@ description: uplink-xc67-description icon: { sprite: /Textures/ADT/Objects/Weapons/Guns/Rifles/xc67.rsi, state: icon} productEntity: ADTClothingBackpackDuffelSyndicateFilledXC67 + discountCategory: usualDiscounts + discountDownTo: + Telecrystal: 12 cost: Telecrystal: 18 categories: @@ -52,6 +55,61 @@ tags: - NukeOpsUplink +- type: listing + id: ADTUplinkWeaponAttachmentsBundle + name: uplink-attachmentsbundle-name + description: uplink-attachmentsbundle-description + icon: { sprite: /Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi, state: uplink_modules } + productEntity: ADTClothingBackpackDuffelSyndicateFilledWeaponAttachments + discountCategory: usualDiscounts + discountDownTo: + Telecrystal: 2 + cost: + Telecrystal: 4 + categories: + - UplinkWeaponry + +- type: listing + id: ADTUplinkLaserSightAttachment + name: uplink-lasersight-name + description: uplink-lasersight-description + icon: { sprite: /Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi, state: lasersight} + productEntity: ADTAttachmentLaserSight + cost: + Telecrystal: 1 + categories: + - UplinkWeaponry + +- type: listing + id: ADTUplinkSuppressorAttachment + name: uplink-suppressor-name + description: uplink-suppressor-description + icon: { sprite: /Textures/ADT/Objects/Weapons/Guns/Attachments/barrel.rsi, state: suppressor} + productEntity: ADTAttachmentSuppressor + cost: + Telecrystal: 2 + categories: + - UplinkWeaponry + +- type: listing + id: ADTUplinkAntilyingAttachment + name: uplink-attachments-antilying-name + description: uplink-attachments-antilying-description + icon: { sprite: /Textures/ADT/Objects/Weapons/Guns/Attachments/barrel.rsi, state: antilying } + productEntity: ADTAttachmentAntiLyingWarrior + discountCategory: usualDiscounts + discountDownTo: + Telecrystal: 5 + cost: + Telecrystal: 8 + categories: + - UplinkWeaponry + conditions: + - !type:StoreWhitelistCondition + whitelist: + tags: + - NukeOpsUplink + #UplinkAmmo - type: listing diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Actions/actions.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Actions/actions.yml index 9c664f77228..964582d707d 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Actions/actions.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Actions/actions.yml @@ -11,7 +11,7 @@ components: - type: InstantAction icon: - sprite: ADT/Objects/Attachments/scope_actions.rsi + sprite: ADT/Objects/Weapons/Guns/Attachments/scope_actions.rsi state: sniperscope event: !type:ToggleActionEvent useDelay: 0.25 @@ -24,7 +24,7 @@ components: - type: InstantAction icon: - sprite: ADT/Objects/Attachments/scope_actions.rsi + sprite: ADT/Objects/Weapons/Guns/Attachments/scope_actions.rsi state: sniperscope event: !type:ScopeCycleZoomLevelEvent useDelay: 0.25 @@ -40,7 +40,7 @@ components: - type: InstantAction icon: - sprite: ADT/Objects/Attachments/scope_actions.rsi + sprite: ADT/Objects/Weapons/Guns/Attachments/scope_actions.rsi state: sniperscope event: !type:AttachableToggleActionEvent diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/barrel_attachment.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/barrel_attachment.yml index a70d3d4069b..310b29db812 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/barrel_attachment.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/barrel_attachment.yml @@ -5,7 +5,7 @@ id: ADTBarrelAttachmentBase components: - type: Sprite - sprite: ADT/Attachments/barrel.rsi + sprite: ADT/Objects/Weapons/Guns/Attachments/barrel.rsi - type: Tag tags: - ADTAttachmentBarrel @@ -17,6 +17,8 @@ name: suppressor description: "A small tube with exhaust ports to expel noise and gas. Does not completely silence a weapon, but does make it much quieter at the cost of slightly reduced damage." + # categories: + # - HideSpawnMenu components: - type: Sprite state: suppressor @@ -34,3 +36,19 @@ # - type: AttachableWeaponRangedMods Пока не работает # modifiers: # - damageFalloffAddMult: 0.1 + +- type: entity + parent: ADTBarrelAttachmentBase + id: ADTAttachmentAntiLyingWarrior + name: Anti Lying Warrior + description: AntiLyingWarrior + components: + - type: Sprite + state: antilying + - type: Tag + tags: + - ADTAttachmentBarrel + - ADTAttachmentAntiLyingWarrior + - type: AttachableVisuals + prefix: antilying + - type: AttachableAntiLyingWarrior diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/rail_attachment.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/rail_attachment.yml index a29b02334c3..f576b3e9068 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/rail_attachment.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/rail_attachment.yml @@ -5,7 +5,7 @@ id: ADTRailAttachmentBase components: - type: Sprite - sprite: ADT/Attachments/rail.rsi + sprite: ADT/Objects/Weapons/Guns/Attachments/rail.rsi - type: Tag tags: - ADTAttachmentRail @@ -45,7 +45,7 @@ useDelay: 0.5 showTogglePopup: false icon: - sprite: ADT/Objects/Attachments/scope_actions.rsi + sprite: ADT/Objects/Weapons/Guns/Attachments/scope_actions.rsi state: sniperscope actionName: action-name-basescope actionDesc: action-description-basescope @@ -67,7 +67,7 @@ description: Hristov x6 scope components: - type: Sprite - sprite: ADT/Objects/Attachments/scope_actions.rsi + sprite: ADT/Objects/Weapons/Guns/Attachments/scope_actions.rsi state: sniperscope - type: Tag tags: @@ -113,7 +113,7 @@ description: T2 scope components: - type: Sprite - sprite: ADT/Attachments/rail.rsi + sprite: ADT/Objects/Weapons/Guns/Attachments/rail.rsi state: miniscope - type: Tag tags: @@ -127,7 +127,7 @@ wieldedOnly: false breakOnRotate: false icon: - sprite: ADT/Attachments/rail.rsi + sprite: ADT/Objects/Weapons/Guns/Attachments/rail.rsi state: miniscope - type: AttachableToggleableSimpleActivate - type: Scope @@ -165,7 +165,7 @@ description: Areflex sight components: - type: Sprite - sprite: ADT/Attachments/rail.rsi + sprite: ADT/Objects/Weapons/Guns/Attachments/rail.rsi state: reflex - type: Tag tags: diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml index be103ed8839..85136e47496 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/under_attachment.yml @@ -5,7 +5,7 @@ id: ADTUnderAttachmentBase components: - type: Sprite - sprite: ADT/Attachments/under.rsi + sprite: ADT/Objects/Weapons/Guns/Attachments/under.rsi - type: Tag tags: - ADTAttachmentUnderbarrel @@ -41,7 +41,7 @@ whitelist: tags: - ADT40mmGrenade - proto: ADT40mmGrenadeBlast + proto: null capacity: 1 soundInsert: path: /Audio/_RMC14/Weapons/Guns/Reload/grenade_insert.ogg @@ -66,10 +66,10 @@ actionName: Switch to the M90 Grenade Launcher actionDesc: Switch to using the underbarrel grenade launcher. icon: - sprite: ADT/Attachments/under.rsi + sprite: ADT/Objects/Weapons/Guns/Attachments/under.rsi state: grenade iconActive: - sprite: ADT/Attachments/under.rsi + sprite: ADT/Objects/Weapons/Guns/Attachments/under.rsi state: grenade-on - type: AttachableVisuals redrawOnAppearanceChange: true @@ -78,7 +78,7 @@ - ADTAttachmentUnderbarrel - ADTAttachmentM90GrenadeLauncher - type: Item - sprite: ADT/Attachments/under.rsi + sprite: ADT/Objects/Weapons/Guns/Attachments/under.rsi storedRotation: -90 - type: entity @@ -112,7 +112,7 @@ tags: - ShellShotgun capacity: 3 - proto: ShellShotgun + proto: null soundInsert: path: /Audio/Weapons/Guns/MagIn/shotgun_insert.ogg - type: UseDelay @@ -126,16 +126,16 @@ actionName: Switch to the M90 underbarrel shotgun actionDesc: Switch to using the underbarrel shotgun. icon: - sprite: ADT/Attachments/under.rsi + sprite: ADT/Objects/Weapons/Guns/Attachments/under.rsi state: masterkey iconActive: - sprite: ADT/Attachments/under.rsi + sprite: ADT/Objects/Weapons/Guns/Attachments/under.rsi state: masterkey-on - type: AttachableVisuals - type: UniqueAction - type: PumpAction - type: Item - sprite: ADT/Attachments/under.rsi + sprite: ADT/Objects/Weapons/Guns/Attachments/under.rsi storedRotation: -90 - type: entity diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/tags.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/tags.yml index 9aa50cc4965..fb6066b6344 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/tags.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/tags.yml @@ -39,3 +39,6 @@ - type: Tag id: ADTAttachmentSuppressor + +- type: Tag + id: ADTAttachmentAntiLyingWarrior diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Rifles/rifles.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Rifles/rifles.yml index f1744e9ce7b..85a3c4279ad 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Rifles/rifles.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Rifles/rifles.yml @@ -230,6 +230,7 @@ whitelist: tags: - ADTAttachmentSuppressor + - ADTAttachmentAntiLyingWarrior - type: AttachableHolderVisuals offsets: rmc-aslot-underbarrel: 0.3125, -0.03125 diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Melee/knife.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Melee/knife.yml index da029374013..86bea65efa3 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Melee/knife.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Melee/knife.yml @@ -25,5 +25,5 @@ - accuracyAddMult: -0.05 - type: AttachablePrying - type: AttachableVisuals - rsi: ADT/Attachments/under.rsi + rsi: ADT/Objects/Weapons/Guns/Attachments/under.rsi prefix: mosinbayonet diff --git a/Resources/Prototypes/ADT/Recipes/Lathes/armory.yml b/Resources/Prototypes/ADT/Recipes/Lathes/armory.yml index 8e27d4722ff..36d921d1dae 100644 --- a/Resources/Prototypes/ADT/Recipes/Lathes/armory.yml +++ b/Resources/Prototypes/ADT/Recipes/Lathes/armory.yml @@ -17,4 +17,102 @@ Glass: 200 Gold: 300 Plasma: 900 - Diamond: 200 \ No newline at end of file + Diamond: 200 + +- type: latheRecipe + id: ADTAttachmentVerticalGripRecipe + result: ADTAttachmentVerticalGrip + completetime: 5 + materials: + Steel: 100 + Plastic: 500 + +- type: latheRecipe + id: ADTAttachmentLaserSightRecipe + result: ADTAttachmentLaserSight + completetime: 8 + materials: + Steel: 500 + Plastic: 500 + Gold: 100 + Glass: 200 + +- type: latheRecipe + id: ADTAttachmentReflexSightRecipe + result: ADTAttachmentReflexSight + completetime: 8 + materials: + Steel: 300 + Plastic: 300 + Gold: 100 + Glass: 500 + +- type: latheRecipe + id: ADTAttachmentT2MiniscopeRecipe + result: ADTAttachmentT2Miniscope + completetime: 10 + materials: + Steel: 500 + Plastic: 300 + Gold: 200 + Glass: 500 + +- type: latheRecipe + id: ADTAttachmentM90UnderbarrelShotgunRecipe + result: ADTAttachmentM90UnderbarrelShotgun + completetime: 10 + materials: + Steel: 1000 + Plastic: 500 + Plasma: 100 + +- type: latheRecipe + id: ADTAttachmentM90GrenadeLauncherRecipe + result: ADTAttachmentM90GrenadeLauncher + completetime: 10 + materials: + Steel: 1500 + Plastic: 500 + Plasma: 500 + +- type: latheRecipe + id: ADT40mmGrenadeHEATRecipe + result: ADT40mmGrenadeHEAT + completetime: 5 + materials: + Steel: 300 + Plastic: 100 + Plasma: 100 + +- type: latheRecipe + id: ADT40mmGrenadeBatonRecipe + result: ADT40mmGrenadeBaton + completetime: 5 + materials: + Steel: 300 + Plastic: 300 + +- type: latheRecipe + id: ADT40mmGrenadeEMPRecipe + result: ADT40mmGrenadeEMP + completetime: 5 + materials: + Steel: 300 + Plastic: 100 + Gold: 100 + +- type: latheRecipe + id: ADT40mmGrenadeFlashRecipe + result: ADT40mmGrenadeFlash + completetime: 5 + materials: + Steel: 300 + Plastic: 200 + +- type: latheRecipe + id: ADT40mmGrenadeSmokeRecipe + result: ADT40mmGrenadeSmoke + completetime: 5 + materials: + Steel: 300 + Plastic: 200 diff --git a/Resources/Prototypes/ADT/Research/arsenal.yml b/Resources/Prototypes/ADT/Research/arsenal.yml index df4e6fad0da..d906ba7cac7 100644 --- a/Resources/Prototypes/ADT/Research/arsenal.yml +++ b/Resources/Prototypes/ADT/Research/arsenal.yml @@ -10,4 +10,42 @@ recipeUnlocks: - ADTWeaponCutterAdv technologyPrerequisites: - - SalvageWeapons \ No newline at end of file + - SalvageWeapons + +#Технологии модулей +- type: technology + id: ADTArsenalBasicModules + name: research-technology-modules-based + icon: + sprite: ADT/Objects/Weapons/Guns/Attachments/under.rsi + state: tech_basic + discipline: Arsenal + tier: 1 + cost: 5000 + recipeUnlocks: + - ADTAttachmentVerticalGripRecipe + - ADTAttachmentLaserSightRecipe + - ADTAttachmentReflexSightRecipe + # technologyPrerequisites: + # - SalvageWeapons + +- type: technology + id: ADTArsenalExtendedModules + name: research-technology-modules-extended + icon: + sprite: ADT/Objects/Weapons/Guns/Attachments/under.rsi + state: tech_extented + discipline: Arsenal + tier: 2 + cost: 10000 + recipeUnlocks: + - ADTAttachmentT2MiniscopeRecipe + - ADTAttachmentM90UnderbarrelShotgunRecipe + - ADTAttachmentM90GrenadeLauncherRecipe + - ADT40mmGrenadeHEATRecipe + - ADT40mmGrenadeBatonRecipe + - ADT40mmGrenadeEMPRecipe + - ADT40mmGrenadeFlashRecipe + - ADT40mmGrenadeSmokeRecipe + technologyPrerequisites: + - ADTArsenalBasicModules diff --git a/Resources/Prototypes/ADT/Research/mech_tecnology.yml b/Resources/Prototypes/ADT/Research/mech_tecnology.yml index 0be8078bb30..8ea031c2974 100644 --- a/Resources/Prototypes/ADT/Research/mech_tecnology.yml +++ b/Resources/Prototypes/ADT/Research/mech_tecnology.yml @@ -76,7 +76,7 @@ state: durand discipline: Arsenal tier: 2 - cost: 20000 + cost: 12500 recipeUnlocks: - ADTDurandHarness - ADTDurandLArm @@ -96,7 +96,7 @@ state: phazon discipline: Arsenal tier: 3 - cost: 30000 + cost: 25000 recipeUnlocks: - ADTPhazonHarness - ADTPhazonLArm @@ -222,31 +222,31 @@ #Технологии оружия -- type: technology - id: ADTMechEnergyGunSmallTechnology - name: research-technology-mech-energy-gun-small - icon: - sprite: Objects/Specific/Mech/mecha_equipment.rsi - state: mecha_laser - discipline: Arsenal - tier: 2 - cost: 15000 - recipeUnlocks: - - ADTMechGunImmolatorLaser - - ADTMechGunPeacemakerDisabler +# - type: technology +# id: ADTMechEnergyGunSmallTechnology +# name: research-technology-mech-energy-gun-small +# icon: +# sprite: Objects/Specific/Mech/mecha_equipment.rsi +# state: mecha_laser +# discipline: Arsenal +# tier: 2 +# cost: 15000 +# recipeUnlocks: +# - ADTMechGunImmolatorLaser +# - ADTMechGunPeacemakerDisabler -- type: technology - id: ADTMechEnergyGunHeavyTechnology - name: research-technology-mech-energy-gun-heavy - icon: - sprite: Objects/Specific/Mech/mecha_equipment.rsi - state: mecha_pulse - discipline: Arsenal - tier: 2 - cost: 20000 - recipeUnlocks: - - ADTMechGunSolarisLaserCannon - - ADTMechGunTeslaCannon +# - type: technology +# id: ADTMechEnergyGunHeavyTechnology +# name: research-technology-mech-energy-gun-heavy +# icon: +# sprite: Objects/Specific/Mech/mecha_equipment.rsi +# state: mecha_pulse +# discipline: Arsenal +# tier: 2 +# cost: 20000 +# recipeUnlocks: +# - ADTMechGunSolarisLaserCannon +# - ADTMechGunTeslaCannon - type: technology id: ADTMechGunSmallTechnology @@ -280,4 +280,4 @@ - ADTMechGunSRM8 - ADTMechGunBRM6 - ADTBoxAmmoSniper - - ADTBoxAmmoGranade \ No newline at end of file + - ADTBoxAmmoGranade diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Pistols/pistols.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Pistols/pistols.yml index 907e5a3fc42..396268bbba5 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Pistols/pistols.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Pistols/pistols.yml @@ -111,6 +111,7 @@ whitelist: tags: - ADTAttachmentSuppressor + - ADTAttachmentAntiLyingWarrior - type: AttachableHolderVisuals offsets: rmc-aslot-underbarrel: 0.235, -0.00875 @@ -248,6 +249,7 @@ whitelist: tags: - ADTAttachmentSuppressor + - ADTAttachmentAntiLyingWarrior - type: AttachableHolderVisuals offsets: rmc-aslot-underbarrel: 0.17, -0.014 diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml index f161a907353..40b4a16fd4a 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml @@ -164,6 +164,7 @@ whitelist: tags: - ADTAttachmentSuppressor + - ADTAttachmentAntiLyingWarrior - type: AttachableHolderVisuals offsets: rmc-aslot-underbarrel: 0.3125, -0.0625 @@ -247,6 +248,7 @@ whitelist: tags: - ADTAttachmentSuppressor + - ADTAttachmentAntiLyingWarrior - type: AttachableHolderVisuals offsets: rmc-aslot-underbarrel: 0.3125, -0.0625 diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml index 48b41445964..28608afdd8e 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml @@ -129,6 +129,7 @@ whitelist: tags: - ADTAttachmentSuppressor + - ADTAttachmentAntiLyingWarrior - type: AttachableHolderVisuals offsets: rmc-aslot-rail: -0.0325, -0.0325 @@ -206,6 +207,7 @@ whitelist: tags: - ADTAttachmentSuppressor + - ADTAttachmentAntiLyingWarrior - type: AttachableHolderVisuals offsets: rmc-aslot-underbarrel: 0.28, -0.1250 diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml index ddfa665d9fc..cf23b9bfcd6 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml @@ -139,7 +139,7 @@ - accuracyAddMult: -0.05 - type: AttachablePrying - type: AttachableVisuals - rsi: ADT/Attachments/under.rsi + rsi: ADT/Objects/Weapons/Guns/Attachments/under.rsi prefix: combatknife # ADT TWEAK END @@ -154,6 +154,9 @@ state: icon - type: Item sprite: Objects/Weapons/Melee/survival_knife.rsi + storedSprite: + state: storage + sprite: Objects/Weapons/Melee/survival_knife.rsi # ADT TWEAK START - type: Tag tags: diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index b63a3a44fbe..379341459c5 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -967,6 +967,17 @@ # Start ADT tweak - ADTMagazineMagnumIncendiary - ADTMagazineMagnumUranium + - ADTAttachmentVerticalGripRecipe + - ADTAttachmentLaserSightRecipe + - ADTAttachmentReflexSightRecipe + - ADTAttachmentT2MiniscopeRecipe + - ADTAttachmentM90UnderbarrelShotgunRecipe + - ADTAttachmentM90GrenadeLauncherRecipe + - ADT40mmGrenadeHEATRecipe + - ADT40mmGrenadeBatonRecipe + - ADT40mmGrenadeEMPRecipe + - ADT40mmGrenadeFlashRecipe + - ADT40mmGrenadeSmokeRecipe # Start ADT tweak - MagazineRifleIncendiary - MagazineRifleUranium diff --git a/Resources/Prototypes/Research/arsenal.yml b/Resources/Prototypes/Research/arsenal.yml index dc2fdc92561..13ec745fd70 100644 --- a/Resources/Prototypes/Research/arsenal.yml +++ b/Resources/Prototypes/Research/arsenal.yml @@ -50,7 +50,10 @@ cost: 7500 recipeUnlocks: - WeaponLaserCarbine + # Start ADT tweak - ADTBorgModuleHarm #ADT secborg + - ADTMechGunImmolatorLaser + # End ADT tweak - type: technology id: NonlethalAmmunition @@ -83,7 +86,7 @@ - MagazinePistolUranium # Start ADT tweak - ADTMagazineMagnumUranium - # Start ADT tweak + # End ADT tweak - MagazineLightRifleUranium - SpeedLoaderMagnumUranium - MagazineBoxPistolUranium @@ -106,6 +109,10 @@ - TelescopicShield - HoloprojectorSecurity - WeaponDisablerSMG + # Start ADT tweak - часть технологий подходящих по стилю переношу сюда + - ClothingBackpackElectropack + - ADTMechGunPeacemakerDisabler + # End ADT tweak - type: technology id: ExplosiveTechnology @@ -125,17 +132,17 @@ - ExplosivePayload - ChemicalPayload -- type: technology - id: SpecialMeans - name: research-technology-special-means - icon: - sprite: Clothing/Back/Backpacks/electropack.rsi - state: icon - discipline: Arsenal - tier: 1 - cost: 5000 - recipeUnlocks: - - ClothingBackpackElectropack +# - type: technology #ADT_Tweak - электрорюкзак перенесен в технологию контроля беспорядков +# id: SpecialMeans +# name: research-technology-special-means +# icon: +# sprite: Clothing/Back/Backpacks/electropack.rsi +# state: icon +# discipline: Arsenal +# tier: 1 +# cost: 5000 +# recipeUnlocks: +# - ClothingBackpackElectropack # Tier 2 @@ -150,6 +157,7 @@ cost: 10000 recipeUnlocks: - WeaponLaserCannon + - ADTMechGunSolarisLaserCannon #ADT_Tweak - type: technology id: WaveParticleHarnessing @@ -162,6 +170,7 @@ cost: 10000 recipeUnlocks: - WeaponXrayCannon + - ADTMechGunTeslaCannon #ADT_Tweak - type: technology id: BasicShuttleArmament diff --git a/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/barrel.rsi/antilying.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/barrel.rsi/antilying.png new file mode 100644 index 0000000000000000000000000000000000000000..0bc188086fc71730fe764e990ada3d375ef86216 GIT binary patch literal 402 zcmV;D0d4+?P)Px$Oi4sRR9J=Wk}*reKp2J}#W)#B?O?N%;wqx;E)FgoI_Picq>e%-$3j%Hs*|(m zBxK4Y*rA)Hh`YEngQ0;8LQAbfZAe?n-8nhjGu^%S-Fq+heW1~3G#bqx=ss9O(OQ-T z*}_~dr)(YsfzW?RR8TILhnY-mP`~L5v;CUW#98)VoqtO@@9-D~{&~CS- z0x18$!PPd8CnNLy^9?@l%o$w;=^-=>LwN}M{l3s&I>0!D<2V3>VF-+dGQD?Qm+$T> zz-j90(|9ph30rAT;S5aUc^&|99P_gE2D{7bU6hjE0}P&f0PCr1YxDe+1EeXvZeqTh wvj_J*fNo0pn&+X^0+62tnf_}u8qL4p2l=UVOs2ysssI2007*qoM6N<$f)9PNQvd(} literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/barrel.rsi/antilying_a.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/barrel.rsi/antilying_a.png new file mode 100644 index 0000000000000000000000000000000000000000..f89641b8c5bf03fa41458d23c0ff84051ad6a229 GIT binary patch literal 318 zcmV-E0m1%>P)Px#_(?=TR9J=W(XDF4KoAG;f0(YT2t+gwacXo+BI1tqm7&llsI00ARP+G~)d#WB zS5bAgPterGgouR_8p2c@caUB`j$_4%`Ke()W`-F+DW%jg>B><4i+u|KAdcg`3p7m= z_-ugEG!<(tvMj^XQ(V2qhuMp3l$!S@O#$&4{l6b0J0-8Qg^?{6Og;O3_!<7xYF zXagtT52~tya}KXB?>L{&;GA0*x%dQtvqKC0W@iF_JsyU^>-d#YN~xpp1r|nIOzv>< QhyVZp07*qoM6N<$f_guOF#rGn literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Attachments/barrel.rsi/meta.json b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/barrel.rsi/meta.json similarity index 78% rename from Resources/Textures/ADT/Attachments/barrel.rsi/meta.json rename to Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/barrel.rsi/meta.json index 631d8271e20..064fa3a1bf6 100644 --- a/Resources/Textures/ADT/Attachments/barrel.rsi/meta.json +++ b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/barrel.rsi/meta.json @@ -12,6 +12,12 @@ }, { "name": "suppressor_a" + }, + { + "name": "antilying" + }, + { + "name": "antilying_a" } ] } diff --git a/Resources/Textures/ADT/Attachments/barrel.rsi/suppressor.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/barrel.rsi/suppressor.png similarity index 100% rename from Resources/Textures/ADT/Attachments/barrel.rsi/suppressor.png rename to Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/barrel.rsi/suppressor.png diff --git a/Resources/Textures/ADT/Attachments/barrel.rsi/suppressor_a.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/barrel.rsi/suppressor_a.png similarity index 100% rename from Resources/Textures/ADT/Attachments/barrel.rsi/suppressor_a.png rename to Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/barrel.rsi/suppressor_a.png diff --git a/Resources/Textures/ADT/Attachments/rail.rsi/magnetic.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/rail.rsi/magnetic.png similarity index 100% rename from Resources/Textures/ADT/Attachments/rail.rsi/magnetic.png rename to Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/rail.rsi/magnetic.png diff --git a/Resources/Textures/ADT/Attachments/rail.rsi/meta.json b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/rail.rsi/meta.json similarity index 100% rename from Resources/Textures/ADT/Attachments/rail.rsi/meta.json rename to Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/rail.rsi/meta.json diff --git a/Resources/Textures/ADT/Attachments/rail.rsi/miniscope.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/rail.rsi/miniscope.png similarity index 100% rename from Resources/Textures/ADT/Attachments/rail.rsi/miniscope.png rename to Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/rail.rsi/miniscope.png diff --git a/Resources/Textures/ADT/Attachments/rail.rsi/miniscope_a.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/rail.rsi/miniscope_a.png similarity index 100% rename from Resources/Textures/ADT/Attachments/rail.rsi/miniscope_a.png rename to Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/rail.rsi/miniscope_a.png diff --git a/Resources/Textures/ADT/Attachments/rail.rsi/reflex.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/rail.rsi/reflex.png similarity index 100% rename from Resources/Textures/ADT/Attachments/rail.rsi/reflex.png rename to Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/rail.rsi/reflex.png diff --git a/Resources/Textures/ADT/Attachments/rail.rsi/reflex_a.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/rail.rsi/reflex_a.png similarity index 100% rename from Resources/Textures/ADT/Attachments/rail.rsi/reflex_a.png rename to Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/rail.rsi/reflex_a.png diff --git a/Resources/Textures/ADT/Objects/Attachments/scope_actions.rsi/meta.json b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/scope_actions.rsi/meta.json similarity index 100% rename from Resources/Textures/ADT/Objects/Attachments/scope_actions.rsi/meta.json rename to Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/scope_actions.rsi/meta.json diff --git a/Resources/Textures/ADT/Objects/Attachments/scope_actions.rsi/sniperscope.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/scope_actions.rsi/sniperscope.png similarity index 100% rename from Resources/Textures/ADT/Objects/Attachments/scope_actions.rsi/sniperscope.png rename to Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/scope_actions.rsi/sniperscope.png diff --git a/Resources/Textures/ADT/Attachments/under.rsi/combatknife_a.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/combatknife_a.png similarity index 100% rename from Resources/Textures/ADT/Attachments/under.rsi/combatknife_a.png rename to Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/combatknife_a.png diff --git a/Resources/Textures/ADT/Attachments/under.rsi/grenade-on.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/grenade-on.png similarity index 100% rename from Resources/Textures/ADT/Attachments/under.rsi/grenade-on.png rename to Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/grenade-on.png diff --git a/Resources/Textures/ADT/Attachments/under.rsi/grenade-open.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/grenade-open.png similarity index 100% rename from Resources/Textures/ADT/Attachments/under.rsi/grenade-open.png rename to Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/grenade-open.png diff --git a/Resources/Textures/ADT/Attachments/under.rsi/grenade-open_a.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/grenade-open_a.png similarity index 100% rename from Resources/Textures/ADT/Attachments/under.rsi/grenade-open_a.png rename to Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/grenade-open_a.png diff --git a/Resources/Textures/ADT/Attachments/under.rsi/grenade.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/grenade.png similarity index 100% rename from Resources/Textures/ADT/Attachments/under.rsi/grenade.png rename to Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/grenade.png diff --git a/Resources/Textures/ADT/Attachments/under.rsi/grenade_a.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/grenade_a.png similarity index 100% rename from Resources/Textures/ADT/Attachments/under.rsi/grenade_a.png rename to Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/grenade_a.png diff --git a/Resources/Textures/ADT/Attachments/under.rsi/lasersight.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/lasersight.png similarity index 100% rename from Resources/Textures/ADT/Attachments/under.rsi/lasersight.png rename to Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/lasersight.png diff --git a/Resources/Textures/ADT/Attachments/under.rsi/lasersight_a.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/lasersight_a.png similarity index 100% rename from Resources/Textures/ADT/Attachments/under.rsi/lasersight_a.png rename to Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/lasersight_a.png diff --git a/Resources/Textures/ADT/Attachments/under.rsi/masterkey-on.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/masterkey-on.png similarity index 100% rename from Resources/Textures/ADT/Attachments/under.rsi/masterkey-on.png rename to Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/masterkey-on.png diff --git a/Resources/Textures/ADT/Attachments/under.rsi/masterkey.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/masterkey.png similarity index 100% rename from Resources/Textures/ADT/Attachments/under.rsi/masterkey.png rename to Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/masterkey.png diff --git a/Resources/Textures/ADT/Attachments/under.rsi/masterkey_a.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/masterkey_a.png similarity index 100% rename from Resources/Textures/ADT/Attachments/under.rsi/masterkey_a.png rename to Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/masterkey_a.png diff --git a/Resources/Textures/ADT/Attachments/under.rsi/meta.json b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/meta.json similarity index 85% rename from Resources/Textures/ADT/Attachments/under.rsi/meta.json rename to Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/meta.json index cc656885167..f7b7c80f7c3 100644 --- a/Resources/Textures/ADT/Attachments/under.rsi/meta.json +++ b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/meta.json @@ -52,6 +52,15 @@ }, { "name": "combatknife_a" + }, + { + "name": "tech_basic" + }, + { + "name": "tech_extented" + }, + { + "name": "uplink_modules" } ] } diff --git a/Resources/Textures/ADT/Attachments/under.rsi/mosinbayonet.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/mosinbayonet.png similarity index 100% rename from Resources/Textures/ADT/Attachments/under.rsi/mosinbayonet.png rename to Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/mosinbayonet.png diff --git a/Resources/Textures/ADT/Attachments/under.rsi/mosinbayonet_a.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/mosinbayonet_a.png similarity index 100% rename from Resources/Textures/ADT/Attachments/under.rsi/mosinbayonet_a.png rename to Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/mosinbayonet_a.png diff --git a/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/tech_basic.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/tech_basic.png new file mode 100644 index 0000000000000000000000000000000000000000..a8221b729cb57d42023fc9e2eb26329c4dde1504 GIT binary patch literal 1112 zcmV-e1gHCnP)Px(5=lfsR9J>~nQuuzD=~rzGPuxq2U^)Y2Fxy;R8q{5;%_IiVy%VpFi`Afj|FR763y-L-O?Wl+n>q4i67W zrBco6u8EQW|I6pkWF!*y9JKx3lHqWeSS&`FNl_F9UDvTJ>qgggzhznF({k6>*S_yx zM0qp6gxB-8-~W)Brul5!&iS|Bf1JFRIO6Q$%Ke|sW_j}D39(oVUDpYR3qr%;Fs3=o z=H|BFG>3^qBJP}5uU`A&@i<#sI{=GI+qPXx)WX=<7*Gfww{81I=(;W+f6>9&#TAxi30>D^*&=R)o5N4#fYAfM+CN*&&d##2vC*-! zvvaN}ioe`C>2w+?rB^=4QaG~hwr$^lM;<6Atwtmgc6~WFHzxqPy1M-3I|c}LKIYwa zT$G5RbZOmAL~TGt;CaCuek#A6nPO{ehrPrR0Gg&{P1DQuZKhY_``Pq zba#FAd1-#>#`H@0{(3tukq;O>F1d4Z=I*K#BL%`<2@u^yC6E7Wn4}t} zV&~+nqV1K>OGw%&x;51m0mw(c#_L{U4Fwbl8=kG?@u7fT2?Y`Ji*IQ}4tKZ>8=>Ti z-ZzI0ix7BA3g# z?{CGx^z^g@IN03+?fgM$O{sJ&gDo}UA7ad}B! z_a%vBaPx(2}wjjR9JUsY%)Ct_uR*MOpFnyh@Uwi^g^GIyqF%49P6V10cZ03pP+s;Z@% zfyl~IZeq)ur-n!;&OaoR$p>p|YZ!(>@$#JRP%kShD=qslO|xVeMgYLFEQAmq2?gN! zlgGYO@Ymn#3c%>-sLbc{OiWC0a&p4i*;%{1o1#J>`25LZnMlNZD;>PCWh@pWola9F zDXOZX>pHe=mvmhZ+O}QY?E32JD)8c2lHXsi;aC3l>QAX@TEKCf>)^qg+s4P%DTVi! z-g~iFWMpK7bUKZ$>%?MZqOn*E(~OhJ90W}>P9l-;+Pr-EYvAzkkp2B50N+wk6lHvT zyab>`qfr_EUiX~O&dwr)06+*qBogryxEVEoXLogVdG$f^@ndJ{pn(8@rfC2;j^ioO z43m?SKsmT{UH87*wv7-1RaG$z!yANQ80_rqAf@bf9H*q{x-K7n8KUt165F;FUDst* zCtie`@kjDI;~N0B|Ji4LexBXk-O$m|(YdOs!D@AKxg1i;h8&=2T9NXS?RFfe1hsoX zgVTB>5;1QsmzI_kfWg7RVD*Rr2EKa8-oc?#aa?I{{NXg@oi3mz@cdxLAIZ6=v+VC5 zacq^hXid|KrfC)j1_sFGa=5O`5Ai6!Ec^t((BRi!RQJ(r!)l#Gs-!=*P7&`4zA1HR za9ECweha|l_!zHOH#`;YBG51e^$_n0HMXDg3f?+r3~3S4yL&u)Itw884i4|!u3Hkg zaoBQgz5Vw@fnf<{67>o+LybhODz}T17sEG%TA!F|6u6Hg_tX}$;=CO+Oo6JZZ7I>y z(?dKSXLWTIngnw@M>XFVn4X>nAeBlnH#f)m`8k)D<)s=5h3M_=Wpi_rY&P2t*E``$ zz_KjQ-q_e^+BhDM6OBdzWVI5Ncxq=#ea~-&LV-fzcKIzVEYRQIUsDEyL9*Gb_f%th z2BqD2@>SsC;-bdRWHRLQ`I@p&DBR0!sb!{W7L?7LcX~%?oe4kFozR!S=eYg0!hfM~ V5YZ-u13>@)002ovPDHLkV1gCp4J7~o literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/uplink_modules.png b/Resources/Textures/ADT/Objects/Weapons/Guns/Attachments/under.rsi/uplink_modules.png new file mode 100644 index 0000000000000000000000000000000000000000..e6db6fe903d3d37300d2721dcdeb65277dcc5e30 GIT binary patch literal 1047 zcmV+y1nB#TP)Px&(Md!>R9J<*mrYL_R}_Yy0pk#ALnJeK7}8PCWL2#h;jICmJ2#|B%ZN3!n6+5*p)g62!MVf6gKLH zWrdK~RLlgZR4dX|eczsKr+CM~xKsns-g{`%7bcaylRbd1YtslzjF z#&`gxrxO&51wQQUuLeKw{BbQci(@D-|uI9d>pUW zODGh={P$9)2cTFibg;S`jS!9Aab*m!x|-(Y%NHH(&%gY{>S~(o)^D7joziT!_`>Jo z#~(7T)&rcMoifs>8w3Jv%XD1>AR4_xVrHh}CkQp0Ewb4yE-ucjc60MB9~%ueH{a5{ zXj-9oytc;q*{N#_?VRw~V+HLvW-?EEvJQqExuI!YYaXwyk;y#e!`?nXN9(NI^wPYpJ{=u#U?NcN2r>1F)jg5AZ5&7Vh z;?dudMLiyJ8$Z`!QAY; z`Ql)=>y6;%3D;6Ah%79&Uqqq+3HQ5MZ}+4Vq~C?-ahnv%D%Hv*DKJIV)OCYeP3v0k z25z_BIkyd_D}i35Vm3>P#X{G8aMd+DIy!3YZ?#(g-}B!7EtN`{_Ib}$n|p~f#@Bg@ zDT-o7A`uitF-xVA1hyO)Jm@=cd3l+gogHi3kpn9$D<*(?cnCl!5J1y)@<&HE z_7cu!vmN6O0{MKNFGC^ZnHdbjz|eILjv_$hE3rl*_ik8lfJh`lwOVy2psK1gF*arz z^*SF Date: Sun, 15 Dec 2024 01:16:25 +0200 Subject: [PATCH 33/46] tweak --- .../Systems/RequireProjectileTargetSystem.cs | 15 ++++++++++----- .../prototypes/Catalog/store/uplink-catalog.ftl | 2 +- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Content.Shared/Damage/Systems/RequireProjectileTargetSystem.cs b/Content.Shared/Damage/Systems/RequireProjectileTargetSystem.cs index a2ea4e36193..1aa3b5bef51 100644 --- a/Content.Shared/Damage/Systems/RequireProjectileTargetSystem.cs +++ b/Content.Shared/Damage/Systems/RequireProjectileTargetSystem.cs @@ -3,7 +3,8 @@ using Content.Shared.Standing; using Robust.Shared.Physics.Events; using Robust.Shared.Containers; -using Content.Shared.ADT.Crawling; +using Content.Shared.ADT.Crawling; // ADT Anti-Lying-Warrior +using Content.Shared.Mobs.Systems; // ADT Anti-Lying-Warrior namespace Content.Shared.Damage.Components; @@ -11,6 +12,7 @@ public sealed class RequireProjectileTargetSystem : EntitySystem { [Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly EntityLookupSystem _lookup = default!; + [Dependency] private readonly MobStateSystem _mobState = default!; // ADT Anti-Lying-Warrior public override void Initialize() { @@ -38,11 +40,14 @@ private void PreventCollide(Entity ent, ref Pr if (item == ent.Owner) return; } + // ADT Crawling abuse fix end + // ADT ALW Tweak + var weapon = projectile.Weapon; + var alwTarget = targeted.Target; + if (weapon.HasValue && HasComp(weapon) && _mobState.IsDead(alwTarget)) + return; } - // ADT Crawling abuse fix end - var weapon = projectile.Weapon; - if (weapon.HasValue && HasComp(weapon)) - return; + // ADT ALW Tweak // Prevents shooting out of while inside of crates var shooter = projectile.Shooter; if (!shooter.HasValue) diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/uplink-catalog.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/uplink-catalog.ftl index 6519dd0b98b..7d3d35bbd46 100644 --- a/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/uplink-catalog.ftl +++ b/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/uplink-catalog.ftl @@ -96,7 +96,7 @@ uplink-syndicate-helmet-desc = Очень прочный шлем, широко ADTuplink-grenade-launcher-bundle-name = РПГ-7 ADTuplink-grenade-launcher-bundle-desc = Набор,содержащий в себе Ручной Противотанковый Гранатомет и 8 ракет для него! -uplink-mask-name = балаклава +uplink-mask-name = Балаклава uplink-mask-desc = Идеально, если вы террорист. uplink-nukiesShield-name = двуручный штурмовой щит From 16771d24b5e72eabecc725ae873996ccc1873858 Mon Sep 17 00:00:00 2001 From: Jungar <145219878+jungarikjan@users.noreply.github.com> Date: Sun, 15 Dec 2024 02:18:03 +0300 Subject: [PATCH 34/46] fix locale --- Resources/Locale/ru-RU/ADT/actions/scoping.ftl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Resources/Locale/ru-RU/ADT/actions/scoping.ftl b/Resources/Locale/ru-RU/ADT/actions/scoping.ftl index 9114a945f96..81be6417e96 100644 --- a/Resources/Locale/ru-RU/ADT/actions/scoping.ftl +++ b/Resources/Locale/ru-RU/ADT/actions/scoping.ftl @@ -1,9 +1,9 @@ rcm-action-popup-scope-cycle-zoom = Уровень приближения изменен на {$zoom}. cm-action-popup-scoping-must-attach = {CAPITALIZE($scope)} должен быть закреплен на оружии для корректной работы! cm-action-popup-scoping-user-must-hold = Вы должны держать {$scope} в своей активной руке, чтобы посмотреть через него. -cm-action-popup-scoping-user-must-not-pulled = Вы не можете смотреть в {$scope} пока вас тащат! +cm-action-popup-scoping-user-must-not-pulled = Вы не можете смотреть в {$scope}, пока вас тащат! cm-action-popup-scoping-user-must-not-contained = Вы не можете смотреть в {$scope}, будучи в ящике! -cm-action-popup-scoping-user-must-wield = Вы должны держать {$scope} в двух руках чтобы его использовать. +cm-action-popup-scoping-user-must-wield = Вы должны держать {$scope} в двух руках, чтобы его использовать. cm-action-popup-scoping-user = Вы смотрите через {$scope}. cm-action-popup-scoping-stopping-user = Вы прекращаете смотреть через {$scope}. From d7bd62458f182974ff3c0d32ff4a4273ae0fb453 Mon Sep 17 00:00:00 2001 From: Eugeny Date: Sun, 15 Dec 2024 03:18:50 +0400 Subject: [PATCH 35/46] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=20=D1=80=D1=81?= =?UTF-8?q?=D0=B8=20(=D1=82=D1=8B=20=D0=BA=D0=B0=D0=BA=20=D1=81=D0=BB?= =?UTF-8?q?=D0=BE=D0=BC=D0=B0=D0=BB=D1=81=D1=8F=20=D1=85=D0=BC)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ADT/Objects/Fun/sharkplushie.rsi/meta.json | 3 +++ .../sharkplushie.rsi/mopbucket_shark_black.png | Bin 0 -> 281 bytes 2 files changed, 3 insertions(+) create mode 100644 Resources/Textures/ADT/Objects/Fun/sharkplushie.rsi/mopbucket_shark_black.png diff --git a/Resources/Textures/ADT/Objects/Fun/sharkplushie.rsi/meta.json b/Resources/Textures/ADT/Objects/Fun/sharkplushie.rsi/meta.json index 71392398528..9cdd05f97d1 100644 --- a/Resources/Textures/ADT/Objects/Fun/sharkplushie.rsi/meta.json +++ b/Resources/Textures/ADT/Objects/Fun/sharkplushie.rsi/meta.json @@ -17,6 +17,9 @@ { "name": "black-inhand-right", "directions": 4 + }, + { + "name": "mopbucket_shark_black" } ] } diff --git a/Resources/Textures/ADT/Objects/Fun/sharkplushie.rsi/mopbucket_shark_black.png b/Resources/Textures/ADT/Objects/Fun/sharkplushie.rsi/mopbucket_shark_black.png new file mode 100644 index 0000000000000000000000000000000000000000..06ee27944b187a9392c2b9a11c0768fd44857b86 GIT binary patch literal 281 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|)B}7%T%{!? z9UUDF4GlFkGy)kJ&#h(q|NsA(_#WBR9_vs{Wp(6?$E(@y{r9S$5UfN`~pxR-psrNGN?V5^ICb2UKG1)Ab z$I+nvNAN$R;yRI{m*xwey%14hxZvvM;Zwk0^Lu_`GxvsGrUNBDOQ+nLE~nFY)PeKT zol8;nG7e|bH(k4RYhSrJ`=rI(9Y61um}~6PHjhxa$r`K>UH&a`Q5@48)*GrNleP$a Q06K}m)78&qol`;+093DRkpKVy literal 0 HcmV?d00001 From 9e47d748ccf6331bb2d075057d838baf01468755 Mon Sep 17 00:00:00 2001 From: Eugeny Date: Sun, 15 Dec 2024 03:21:50 +0400 Subject: [PATCH 36/46] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=20=D1=80=D1=81?= =?UTF-8?q?=D0=B8=202?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Resources/Prototypes/Entities/Objects/Fun/immovable_rod.yml | 2 +- Resources/Prototypes/Entities/Objects/Fun/toys.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Resources/Prototypes/Entities/Objects/Fun/immovable_rod.yml b/Resources/Prototypes/Entities/Objects/Fun/immovable_rod.yml index 0bee05aa6ad..dad1402ab53 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/immovable_rod.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/immovable_rod.yml @@ -114,7 +114,7 @@ description: SHARK TORNADO! components: - type: Sprite - sprite: Objects/Fun/sharkplush.rsi + sprite: Objects/Fun/sharkplushie.rsi state: blue rotation: 90 noRot: false diff --git a/Resources/Prototypes/Entities/Objects/Fun/toys.yml b/Resources/Prototypes/Entities/Objects/Fun/toys.yml index 4532e8ac8dc..ff5b084bb6e 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/toys.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/toys.yml @@ -496,7 +496,7 @@ description: Big and safe to have by your side if you want to discover the world below the surface of the ocean. components: - type: Sprite - sprite: Objects/Fun/sharkplush.rsi + sprite: Objects/Fun/sharkplushie.rsi state: blue - type: EmitSoundOnUse sound: @@ -519,7 +519,7 @@ description: Hehe shonk :) components: - type: Sprite - sprite: Objects/Fun/sharkplush.rsi + sprite: Objects/Fun/sharkplushie.rsi state: pink - type: Item heldPrefix: pink @@ -535,7 +535,7 @@ description: A quiet, reserved kind of shonk. Loves to ride the grey tide. components: - type: Sprite - sprite: Objects/Fun/sharkplush.rsi + sprite: Objects/Fun/sharkplushie.rsi state: grey - type: Item heldPrefix: grey From 063692380c9b52e8c44d9f1b3db478b11b79b86c Mon Sep 17 00:00:00 2001 From: Jungar <145219878+jungarikjan@users.noreply.github.com> Date: Sun, 15 Dec 2024 02:26:03 +0300 Subject: [PATCH 37/46] fix locale 2 --- .../Locale/ru-RU/ADT/attachments/attachable/attachable.ftl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Resources/Locale/ru-RU/ADT/attachments/attachable/attachable.ftl b/Resources/Locale/ru-RU/ADT/attachments/attachable/attachable.ftl index ab36271657b..83c89b47e8b 100644 --- a/Resources/Locale/ru-RU/ADT/attachments/attachable/attachable.ftl +++ b/Resources/Locale/ru-RU/ADT/attachments/attachable/attachable.ftl @@ -8,7 +8,7 @@ rmc-aslot-rail = Верхняя планка rmc-aslot-stock = Приклад rmc-aslot-underbarrel = Подствольное -rmc-attachable-activation-fail-not-wielded = {CAPITALIZE($holder)} должен быть экипирован, чтобы активировать {$attachable}! +rmc-attachable-activation-fail-not-wielded = {CAPITALIZE($holder)} должен быть в обеих руках, чтобы активировать {$attachable}! rmc-attachable-activation-fail-not-held = {CAPITALIZE($holder)} должен быть в руках, чтобы активировать {$attachable}! rmc-attachable-activation-fail-not-owned = {CAPITALIZE($holder)} должен быть в ваших руках или экипирован, чтобы активировать {$attachable}! @@ -47,7 +47,7 @@ rmc-attachable-examine-condition-whitelist-sizes = предмет [bold]имее rmc-attachable-examine-condition-whitelist-tags = предмет [bold]имеет {$tagNumber}[/bold] из следующих тегов = [bold]{$tags}[/bold] rmc-attachable-examine-condition-blacklist-comps = предмет [bold]не имеет {$compNumber}[/bold] из следующих компонентов = [bold]{$comps}[/bold] -rmc-attachable-examine-condition-blacklist-sizes = предмет [bold]не имеет один из следующих размеров =[/bold] [bold]{$sizes}[/bold] +rmc-attachable-examine-condition-blacklist-sizes = предмет [bold]не имеет один из следующих размеров = [/bold][bold]{$sizes}[/bold] rmc-attachable-examine-condition-blacklist-tags = предмет [bold]не имеет {$tagNumber}[/bold] из следующих тегов = [bold]{$tags}[/bold] rmc-attachable-examine-ranged-scatter = [color={$colour}]{$sign}{$scatter}[/color] градусов разброса. From ce8f5f83d0670a117db5669789c71829952113f4 Mon Sep 17 00:00:00 2001 From: Eugeny Date: Sun, 15 Dec 2024 03:28:00 +0400 Subject: [PATCH 38/46] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=20=D1=80=D1=81?= =?UTF-8?q?=D0=B8=203?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Entities/Objects/Fun/immovable_rod.yml | 2 +- .../Prototypes/Entities/Objects/Fun/toys.yml | 6 +- .../Objects/Fun/sharkplush.rsi/meta.json | 73 ++++++++++--------- 3 files changed, 42 insertions(+), 39 deletions(-) diff --git a/Resources/Prototypes/Entities/Objects/Fun/immovable_rod.yml b/Resources/Prototypes/Entities/Objects/Fun/immovable_rod.yml index dad1402ab53..0bee05aa6ad 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/immovable_rod.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/immovable_rod.yml @@ -114,7 +114,7 @@ description: SHARK TORNADO! components: - type: Sprite - sprite: Objects/Fun/sharkplushie.rsi + sprite: Objects/Fun/sharkplush.rsi state: blue rotation: 90 noRot: false diff --git a/Resources/Prototypes/Entities/Objects/Fun/toys.yml b/Resources/Prototypes/Entities/Objects/Fun/toys.yml index ff5b084bb6e..4532e8ac8dc 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/toys.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/toys.yml @@ -496,7 +496,7 @@ description: Big and safe to have by your side if you want to discover the world below the surface of the ocean. components: - type: Sprite - sprite: Objects/Fun/sharkplushie.rsi + sprite: Objects/Fun/sharkplush.rsi state: blue - type: EmitSoundOnUse sound: @@ -519,7 +519,7 @@ description: Hehe shonk :) components: - type: Sprite - sprite: Objects/Fun/sharkplushie.rsi + sprite: Objects/Fun/sharkplush.rsi state: pink - type: Item heldPrefix: pink @@ -535,7 +535,7 @@ description: A quiet, reserved kind of shonk. Loves to ride the grey tide. components: - type: Sprite - sprite: Objects/Fun/sharkplushie.rsi + sprite: Objects/Fun/sharkplush.rsi state: grey - type: Item heldPrefix: grey diff --git a/Resources/Textures/Objects/Fun/sharkplush.rsi/meta.json b/Resources/Textures/Objects/Fun/sharkplush.rsi/meta.json index 33604c15fd1..22ee5fd89ff 100644 --- a/Resources/Textures/Objects/Fun/sharkplush.rsi/meta.json +++ b/Resources/Textures/Objects/Fun/sharkplush.rsi/meta.json @@ -6,39 +6,42 @@ "x": 32, "y": 32 }, - "states": [ - { - "name": "blue" - }, - { - "name": "blue-inhand-left", - "directions": 4 - }, - { - "name": "blue-inhand-right", - "directions": 4 - }, - { - "name": "pink" - }, - { - "name": "pink-inhand-left", - "directions": 4 - }, - { - "name": "pink-inhand-right", - "directions": 4 - }, - { - "name": "grey" - }, - { - "name": "grey-inhand-left", - "directions": 4 - }, - { - "name": "grey-inhand-right", - "directions": 4 - } - ] + "states": [ + { + "name": "blue" + }, + { + "name": "blue-inhand-left", + "directions": 4 + }, + { + "name": "blue-inhand-right", + "directions": 4 + }, + { + "name": "pink" + }, + { + "name": "pink-inhand-left", + "directions": 4 + }, + { + "name": "pink-inhand-right", + "directions": 4 + }, + { + "name": "grey" + }, + { + "name": "grey-inhand-left", + "directions": 4 + }, + { + "name": "grey-inhand-right", + "directions": 4 + }, + { + "name": "mopbucket_shark_black" + } + ] } From 351b7a2cae227cc662a96ce07aa3a370185c560d Mon Sep 17 00:00:00 2001 From: Jungar <145219878+jungarikjan@users.noreply.github.com> Date: Sun, 15 Dec 2024 02:33:59 +0300 Subject: [PATCH 39/46] locale fix 3 --- .../ru-RU/ADT/prototypes/Catalog/store/bobr.ftl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/bobr.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/bobr.ftl index 1caed113595..54f4100f12c 100644 --- a/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/bobr.ftl +++ b/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/bobr.ftl @@ -11,19 +11,19 @@ boobr-ar12-name = Набор "АR-12" boobr-ar12-desc = Продвинутая штурмовая винтовка. Использует патроны калибра 6.5 мм ТСФ, входящие в набор. boobr-pulse-name = Импульсный карабин -boobr-pulse-desc = Высокотехнологичный энергетический карабин, который предпочитают оперативники ОБР NT. +boobr-pulse-desc = Высокотехнологичный энергетический карабин, который предпочитают оперативники ОБР NanoTrasen. boobr-mateba-name = Набор "Матеба" boobr-mateba-desc = Чертовски стильный и шумный револьвер, использующий патроны .44 магнум. boobr-ap-name = Набор бронебойщика -boobr-ap-desc = Набор из 10-ти бронебойных патронов .44 магнум, идеально подходящих для Матебы и Десерт Игла. +boobr-ap-desc = Набор из 10-ти бронебойных патронов .44 магнум, идеально подходящих для Матебы и Дезерт Игла. boobr-deagle-name = Дезерт Игл boobr-deagle-desc = Дезерт Игл, также известный как "Пустынный Орёл", - это мощный пистолет калибра .44, который выглядит металлическим и блестящим. boobr-disabler-name = Набор станнеров -boobr-disabler-desc = NT не смогли выбрать, что лучше - станнер-пулемет или просто станнер. Потому они добавили в набор оба. +boobr-disabler-desc = NanoTrasen не смогли выбрать, что лучше - станнер-пулемет или просто станнер. Потому они добавили в набор оба. boobr-ion-name = Ионная винтовка boobr-ion-desc = Ионно-электрическая винтовка, специально разработана против мехов и боргов. @@ -56,10 +56,10 @@ boobr-grappling-gun-name = Крюк-кошка boobr-grappling-gun-desc = Для лёгкого перемещения вне станции. Меч со сменным лезвием не в комплекте. boobr-medikit-name = Продвинутая аптечка -boobr-medikit-desc = Продвинутый набор для оказания помощи при продвинутых ранах. +boobr-medikit-desc = Продвинутый набор для оказания помощи при сильных ранах. boobr-portable-recharger-name = Переносной зарядник -boobr-portable-recharger-desc = Переносной зарядник выделенный для своевременной зарядки энергооружия в условиях боевых действий. +boobr-portable-recharger-desc = Переносной зарядник, выделенный для своевременной зарядки энергооружия в условиях боевых действий. boobr-holo-projector-name = Продвинутый голопроектор boobr-holo-projector-desc = Продвинутая версия обычного голопроектора, используемая для сдерживания угрозы или создания укреплений. @@ -68,7 +68,7 @@ boobr-m90-grenadelauncher-name = Подствольный гранатомёт G boobr-m90-grenadelauncher-desc = Один из наиболее распространенных подствольных гранатомётов, изначально разработанный для карабина M-90gl. Заряжается 40-мм выстрелами. boobr-m90-shotgun-name = Подствольный дробовик US90 -boobr-m90-shotgun-desc = Трехзарядный подствольный дробовик, сделанный изначально для карабина М-90gl. Прекрасно подходит для вышибания дверей или мозгов зомби. +boobr-m90-shotgun-desc = Трехзарядный подствольный дробовик, изначально сделанный для карабина М-90gl. Прекрасно подходит для вышибания дверей или мозгов зомби. boobr-weapon-attachments-name = Набор оружейных модулей boobr-weapon-attachments-desc = Кейс, в котором лежит лазерный целеуказатель, вертикальная рукоять, коллиматорный и оптический прицелы. From 0e38e74da9a0797b42953ac4f111b6371872388f Mon Sep 17 00:00:00 2001 From: Jungar <145219878+jungarikjan@users.noreply.github.com> Date: Sun, 15 Dec 2024 02:37:09 +0300 Subject: [PATCH 40/46] =?UTF-8?q?=D1=83=D0=BD=D0=B3=D0=B0=20=D0=B1=D1=83?= =?UTF-8?q?=D0=BD=D0=B3=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru-RU/ADT/prototypes/Catalog/store/uplink-catalog.ftl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/uplink-catalog.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/uplink-catalog.ftl index a7b46197ca7..23605f1740c 100644 --- a/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/uplink-catalog.ftl +++ b/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/uplink-catalog.ftl @@ -14,7 +14,7 @@ uplink-nukeopscloak-name = плащ Ядерных Оперативников uplink-nukeopscloak-desc = Защитит тебя от холода на базе. uplink-advanced-magboots = продвинутые магнитные ботинки синдиката -uplink-advanced-magboots-desc = Улучшенные магнитные ботинки синдиката. Собственность мародёров горлакса. +uplink-advanced-magboots-desc = Улучшенные магнитные ботинки синдиката. Собственность мародёров Горлакса. uplink-ADTHandDefibrillator-name = переносной дефибриллятор синдиката uplink-ADTHandDefibrillator-desc = Облегченная версия обычного дефибриллятора, более эффективен в лечении, но имеет больше сильный разряд. Можно надеть на шею. @@ -46,7 +46,7 @@ uplink-LightRifle-magazine-desc = Магазин с патронами кали # Bundles uplink-smokegrenade-bundle-name = набор дымовых гранат -uplink-smokegrenade-bundle-desc = Набор из 6 дымовых граната синдиката. Идеально подходят для кальянной вечеринки. +uplink-smokegrenade-bundle-desc = Набор из 6 дымовых граната Синдиката. Идеально подходят для кальянной вечеринки. uplink-C20-ammo-bundle-name = набор магазинов для С-20r uplink-C20-ammo-bundle-desc = Набор, содержащий 4 запасных магазина по цене 3. @@ -94,7 +94,7 @@ uplink-syndicate-helmet-name = шлем спецназа uplink-syndicate-helmet-desc = Очень прочный шлем, широко используемый военизированными организациями. Его украшает ужасный узор из красных и чёрных полос. Да пребудет с вами робаст. ADTuplink-grenade-launcher-bundle-name = РПГ-7 -ADTuplink-grenade-launcher-bundle-desc = Набор,содержащий в себе Ручной Противотанковый Гранатомет и 8 ракет для него! +ADTuplink-grenade-launcher-bundle-desc = Набор, содержащий в себе Ручной Противотанковый Гранатомет и 8 ракет для него! uplink-mask-name = Балаклава uplink-mask-desc = Идеально, если вы террорист. @@ -103,7 +103,7 @@ uplink-nukiesShield-name = двуручный штурмовой щит uplink-nukiesShield-desc = Массивный и опасный, двуручный щит из элитных материалов для лучшей защиты, имеет несколько рядов пластин, а также несколько шипов на основе щита. uplink-omnizinpizza-name = коробка с пиццей Синдиката -uplink-omnizinpizza-desc = Это коробка, с самой обычной пиццей внутри, это именно то, что используют элитные агенты для перекуса между стрельбой с капитаном, и кражей Иана. +uplink-omnizinpizza-desc = Это коробка с самой обычной пиццей внутри. Именно то, что используют элитные агенты для перекуса между перестрелками с Капитаном и кражей Иана. uplink-attachmentsbundle-name = Набор оружейных модулей uplink-attachmentsbundle-description = Комплект из вертикальной рукояти, лазерного целеуказателя, коллиматорного и оптического прицелов. From 4e2949fb64443b61fda62ef732a3b2851615df37 Mon Sep 17 00:00:00 2001 From: Jungar <145219878+jungarikjan@users.noreply.github.com> Date: Sun, 15 Dec 2024 02:38:40 +0300 Subject: [PATCH 41/46] =?UTF-8?q?=D0=BB=D0=BE=D0=BA=D0=B0=D0=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru-RU/ADT/prototypes/Entities/Objects/Device/binocular.ftl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Device/binocular.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Device/binocular.ftl index 028f5985262..a1756d5e911 100644 --- a/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Device/binocular.ftl +++ b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Device/binocular.ftl @@ -1,3 +1,3 @@ ent-ADTBinoculars = бинокль -.desc = Позволяет разглядеть получше противника вдали. Или ту пару вульп в соседнем здании. +.desc = Позволяет получше разглядеть противника, находящегося вдали. Или ту пару вульп в соседнем здании. .suffix = { "ОСЩ" } From 1d4b72ca5ac7604d8be1fffcb5db144023d0829e Mon Sep 17 00:00:00 2001 From: Jungar <145219878+jungarikjan@users.noreply.github.com> Date: Sun, 15 Dec 2024 02:42:15 +0300 Subject: [PATCH 42/46] =?UTF-8?q?=D1=80=D0=B0=D0=BD=D1=8B=20=D0=B7=D0=B0?= =?UTF-8?q?=D1=88=D0=B8=D0=B2=D0=B0=D1=8E=D1=82*=20=D1=8B=D1=8B=D1=8B?= =?UTF-8?q?=D1=8B=D1=8B=D1=8B=D1=8B=D1=8B=D1=8B=D1=8B=D1=8B=D1=8B=D1=8B?= =?UTF-8?q?=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ADT/prototypes/Entities/Objects/Weapons/Melee/melee.ftl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Melee/melee.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Melee/melee.ftl index 1b5d06e10a4..087f0d3319f 100644 --- a/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Melee/melee.ftl +++ b/Resources/Locale/ru-RU/ADT/prototypes/Entities/Objects/Weapons/Melee/melee.ftl @@ -31,7 +31,7 @@ ent-ADTJasonMachette = мачете Джейсона .desc = Мачете одного из самых ужасающих маньяков. Сбоку маленькая надпись "полиуретан". ent-ADTMosinBayonet = штык от винтовки Мосина - .desc = Потому что раны от игольчатого штыка невозможно сшить... + .desc = Потому что раны от игольчатого штыка невозможно зашить... ent-SpearReinforcedUran = копьё из закалённого урана .desc = Копьё, созданное из осколка закалённого урана, для более удобного убийства ваших оппонентов. From 72222247be5858642621b766f24e4b5f13190511 Mon Sep 17 00:00:00 2001 From: Eugeny Date: Sun, 15 Dec 2024 04:09:29 +0400 Subject: [PATCH 43/46] =?UTF-8?q?=D0=BA=D0=B0=D1=82=D0=B5=D0=B3=D0=BE?= =?UTF-8?q?=D1=80=D0=B8=D1=8F=20=D0=BC=D0=BE=D0=B4=D1=83=D0=BB=D0=B5=D0=B9?= =?UTF-8?q?=20=D0=B2=20=D0=B0=D0=BF=D0=BB=D0=B8=D0=BD=D0=BA=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Resources/Locale/en-US/store/categories.ftl | 1 + .../ADT/prototypes/Catalog/store/bobr.ftl | 5 +++- .../Catalog/store/uplink-catalog.ftl | 3 ++ .../weapons/guns/ammunition/explosives.ftl | 12 ++++---- .../guns/ammunition/magazines/grenade.ftl | 14 +++++----- .../weapons/guns/projectiles/projectiles.ftl | 8 +++--- .../entities/structures/shuttles/cannons.ftl | 4 +-- Resources/Locale/ru-RU/store/categories.ftl | 1 + .../Prototypes/ADT/Catalog/boobr_catalog.yml | 11 ++++++++ .../Prototypes/ADT/Catalog/uplink_catalog.yml | 28 ++++++++++++++++--- .../Entities/Objects/Specific/syndicate.yml | 1 + Resources/Prototypes/Store/categories.yml | 25 +++++++++++------ Resources/Prototypes/Store/presets.yml | 1 + 13 files changed, 81 insertions(+), 33 deletions(-) diff --git a/Resources/Locale/en-US/store/categories.ftl b/Resources/Locale/en-US/store/categories.ftl index 64ed0b5c637..9e51128cffd 100644 --- a/Resources/Locale/en-US/store/categories.ftl +++ b/Resources/Locale/en-US/store/categories.ftl @@ -3,6 +3,7 @@ store-category-debug = debug category store-category-debug2 = debug category 2 store-category-weapons = Weaponry store-category-ammo = Ammo +store-category-attachments = Attachments store-category-explosives = Explosives store-category-chemicals = Chemicals store-category-deception = Deception diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/bobr.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/bobr.ftl index 1caed113595..f0438e9cfa3 100644 --- a/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/bobr.ftl +++ b/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/bobr.ftl @@ -46,7 +46,7 @@ boobr-JawsOfLife-desc = Приспособление для быстрого в boobr-c4-name = C-4 boobr-c4-desc = Используйте её, чтобы разрушать стены, шлюзы. Её можно прикрепить практически к любому объекту, а таймер можно изменять, минимальное значение - 10 секунд. -boobr-grenade-name = Гапнельная граната +boobr-grenade-name = Шрапнельная граната boobr-grenade-desc = Разбрасывает вокруг себя облако шрапнели, вызывающей множественные раны и кровотечения. boobr-jetpack-name = Джетпак @@ -78,3 +78,6 @@ boobr-weapon-attachments-antilying-desc = Особо продвинутый мо boobr-weapon-attachments-suppressor-name = Глушитель boobr-weapon-attachments-suppressor-desc = Устанавлаемый на ствол универсальный мультикалиберный глушитель. Существенно снижает звук от стрельбы и скрывает дульную вспышку. + +boobr-weapon-attachments-magneticharness-name = Магнитный ремень +boobr-weapon-attachments-magneticharness-description = Комплект из ремня и магнитных креплений, которые крепятся к верхней планке. В случае потери бойцом равновесия - оружие не падает на землю и остается с владельцем. diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/uplink-catalog.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/uplink-catalog.ftl index a7b46197ca7..639dfd85476 100644 --- a/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/uplink-catalog.ftl +++ b/Resources/Locale/ru-RU/ADT/prototypes/Catalog/store/uplink-catalog.ftl @@ -116,3 +116,6 @@ uplink-attachments-antilying-description = Особо продвинутый м uplink-suppressor-name = Глушитель uplink-suppressor-description = Устанавлаемый на ствол универсальный мультикалиберный глушитель. Существенно снижает звук от стрельбы и скрывает дульную вспышку. + +uplink-attachments-magneticharness-name = Магнитный ремень +uplink-attachments-magneticharness-description = Комплект из ремня и магнитных креплений, которые крепятся к верхней планке. В случае потери бойцом равновесия - оружие не падает на землю и остается с владельцем. diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/weapons/guns/ammunition/explosives.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/weapons/guns/ammunition/explosives.ftl index d7a6bc38422..9c1a20540ab 100644 --- a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/weapons/guns/ammunition/explosives.ftl +++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/weapons/guns/ammunition/explosives.ftl @@ -2,17 +2,17 @@ ent-CartridgeRocket = выстрел ПГ-7ВЛ .desc = Выстрел для гранатомёта РПГ-7. Имеет форму трубы. ent-CartridgeRocketSlow = выстрел ПГ-7ВЛ "Улитка" .desc = Выстрел для гранатомёта РПГ-7. Необычайно медленная. -ent-BaseGrenade = базовая граната +ent-BaseGrenade = базовый снаряд .desc = { ent-BaseItem.desc } -ent-GrenadeBaton = шоковая граната +ent-GrenadeBaton = шоковый снаряд .desc = { ent-BaseGrenade.desc } -ent-GrenadeBlast = фугасная граната +ent-GrenadeBlast = фугасный снаряд .desc = { ent-BaseGrenade.desc } -ent-GrenadeFlash = светошумовая граната +ent-GrenadeFlash = светошумовой снаряд .desc = { ent-BaseGrenade.desc } -ent-GrenadeFrag = осколочная граната +ent-GrenadeFrag = осколочный снаряд .desc = { ent-BaseGrenade.desc } -ent-GrenadeEMP = ЭМИ граната +ent-GrenadeEMP = ЭМИ снаряд .desc = { ent-BaseGrenade.desc } ent-BaseCannonBall = базовое пушечное ядро .desc = { ent-BaseItem.desc } diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/weapons/guns/ammunition/magazines/grenade.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/weapons/guns/ammunition/magazines/grenade.ftl index 79fe130a3a0..942de050093 100644 --- a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/weapons/guns/ammunition/magazines/grenade.ftl +++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/weapons/guns/ammunition/magazines/grenade.ftl @@ -1,14 +1,14 @@ -ent-BaseMagazineGrenade = картридж гранат +ent-BaseMagazineGrenade = картридж снарядов .desc = { ent-BaseItem.desc } -ent-MagazineGrenadeEmpty = картридж гранат +ent-MagazineGrenadeEmpty = картридж снарядов .desc = { ent-BaseMagazineGrenade.desc } -ent-MagazineGrenadeFrag = картридж осколочных гранат +ent-MagazineGrenadeFrag = картридж осколочных снарядов .desc = { ent-BaseMagazineGrenade.desc } -ent-MagazineGrenadeEMP = картридж ЭМИ гранат +ent-MagazineGrenadeEMP = картридж ЭМИ снарядов .desc = { ent-BaseMagazineGrenade.desc } -ent-MagazineGrenadeFlash = картридж светошумовых гранат +ent-MagazineGrenadeFlash = картридж светошумовых снарядов .desc = { ent-BaseMagazineGrenade.desc } -ent-MagazineGrenadeBlast = картридж фугасных гранат +ent-MagazineGrenadeBlast = картридж фугасных снарядов .desc = { ent-BaseMagazineGrenade.desc } -ent-MagazineGrenadeBaton = картридж шоковых гранат +ent-MagazineGrenadeBaton = картридж шоковых снарядов .desc = { ent-BaseMagazineGrenade.desc } diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/weapons/guns/projectiles/projectiles.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/weapons/guns/projectiles/projectiles.ftl index 6432f0e2ed7..0a59c0ae766 100644 --- a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/weapons/guns/projectiles/projectiles.ftl +++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/weapons/guns/projectiles/projectiles.ftl @@ -52,13 +52,13 @@ ent-BulletRocket = ракета .desc = { ent-BaseBulletTrigger.desc } ent-BulletWeakRocket = слабая ракета .desc = { ent-BaseBulletTrigger.desc } -ent-BulletGrenadeBaton = шоковая граната +ent-BulletGrenadeBaton = шоковый снаряд .desc = { ent-BaseBullet.desc } -ent-BulletGrenadeBlast = фугасная граната +ent-BulletGrenadeBlast = фугасный снаряд .desc = { ent-BaseBulletTrigger.desc } -ent-BulletGrenadeFlash = светошумовая граната +ent-BulletGrenadeFlash = светошумовой снаряд .desc = { ent-BaseBulletTrigger.desc } -ent-BulletGrenadeFrag = осколочная граната +ent-BulletGrenadeFrag = осколочный снаряд .desc = { ent-BaseBulletTrigger.desc } ent-BulletGrenadeEMP = ЭМИ ракета .desc = { ent-BaseBulletTrigger.desc } diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/shuttles/cannons.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/shuttles/cannons.ftl index 1e08968401f..12d1fb74647 100644 --- a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/shuttles/cannons.ftl +++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/shuttles/cannons.ftl @@ -7,10 +7,10 @@ ent-ShuttleGunPerforator = LSE-1200c "Перфоратор" .desc = Продвинутая стационарная лазерная установка. Уничтожает электроприборы и чрезвычайно опасна для здоровья! Для стрельбы использует энергоячейки. .suffix = НЕ МАППИТЬ ent-ShuttleGunFriendship = EXP-320g "Дружба" - .desc = Небольшой стационарный гранатомёт, вмещающий 2 гранаты. + .desc = Небольшое стационарное орудие, вмещающее два снаряда. .suffix = НЕ МАППИТЬ ent-ShuttleGunDuster = EXP-2100g "Дастер" - .desc = Мощный стационарный гранатомёт. Для стрельбы необходим картридж. + .desc = Мощное стационарное орудие. Для стрельбы необходим картридж. .suffix = НЕ МАППИТЬ ent-ShuttleGunPirateCannon = пушка пиратского корабля .desc = Кабум! diff --git a/Resources/Locale/ru-RU/store/categories.ftl b/Resources/Locale/ru-RU/store/categories.ftl index b18e8dd1ddc..e71f9441437 100644 --- a/Resources/Locale/ru-RU/store/categories.ftl +++ b/Resources/Locale/ru-RU/store/categories.ftl @@ -3,6 +3,7 @@ store-category-debug = debug category store-category-debug2 = debug category 2 store-category-weapons = Вооружение store-category-ammo = Боеприпасы +store-category-attachments = Оруж. модули store-category-explosives = Взрывчатка store-category-chemicals = Химикаты store-category-deception = Обман diff --git a/Resources/Prototypes/ADT/Catalog/boobr_catalog.yml b/Resources/Prototypes/ADT/Catalog/boobr_catalog.yml index 51b8047a3c6..e8a3db6e241 100644 --- a/Resources/Prototypes/ADT/Catalog/boobr_catalog.yml +++ b/Resources/Prototypes/ADT/Catalog/boobr_catalog.yml @@ -64,6 +64,17 @@ categories: - ADTUplinkERTAttachments +- type: listing + id: ADTBoberMagneticHarnessAttachment + name: boobr-weapon-attachments-magneticharness-name + description: boobr-weapon-attachments-magneticharness-description + icon: { sprite: /Textures/ADT/Objects/Weapons/Guns/Attachments/rail.rsi, state: magnetic } + productEntity: ADTAttachmentMagneticHarness + cost: + Productunit: 4 + categories: + - ADTUplinkERTAttachments + - type: listing id: ADTBoberLecter name: boobr-lecter-name diff --git a/Resources/Prototypes/ADT/Catalog/uplink_catalog.yml b/Resources/Prototypes/ADT/Catalog/uplink_catalog.yml index 9f6e6c7a942..92f87a30486 100644 --- a/Resources/Prototypes/ADT/Catalog/uplink_catalog.yml +++ b/Resources/Prototypes/ADT/Catalog/uplink_catalog.yml @@ -55,6 +55,7 @@ tags: - NukeOpsUplink +#UplinkAttachments - type: listing id: ADTUplinkWeaponAttachmentsBundle name: uplink-attachmentsbundle-name @@ -67,7 +68,7 @@ cost: Telecrystal: 4 categories: - - UplinkWeaponry + - UplinkAttachments #ADT_Tweak - type: listing id: ADTUplinkLaserSightAttachment @@ -78,7 +79,7 @@ cost: Telecrystal: 1 categories: - - UplinkWeaponry + - UplinkAttachments #ADT_Tweak - type: listing id: ADTUplinkSuppressorAttachment @@ -89,7 +90,7 @@ cost: Telecrystal: 2 categories: - - UplinkWeaponry + - UplinkAttachments #ADT_Tweak - type: listing id: ADTUplinkAntilyingAttachment @@ -103,7 +104,26 @@ cost: Telecrystal: 8 categories: - - UplinkWeaponry + - UplinkAttachments #ADT_Tweak + conditions: + - !type:StoreWhitelistCondition + whitelist: + tags: + - NukeOpsUplink + +- type: listing + id: ADTUplinkMagneticHarnessAttachment + name: uplink-attachments-magneticharness-name + description: uplink-attachments-magneticharness-description + icon: { sprite: /Textures/ADT/Objects/Weapons/Guns/Attachments/rail.rsi, state: magnetic } + productEntity: ADTAttachmentMagneticHarness + discountCategory: usualDiscounts + discountDownTo: + Telecrystal: 4 + cost: + Telecrystal: 6 + categories: + - UplinkAttachments #ADT_Tweak conditions: - !type:StoreWhitelistCondition whitelist: diff --git a/Resources/Prototypes/Entities/Objects/Specific/syndicate.yml b/Resources/Prototypes/Entities/Objects/Specific/syndicate.yml index ac02eeef9bc..f7cd0fdff1f 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/syndicate.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/syndicate.yml @@ -132,6 +132,7 @@ categories: - UplinkWeaponry - UplinkAmmo + - UplinkAttachments #ADT_Tweak - UplinkExplosives - UplinkChemicals - UplinkDeception diff --git a/Resources/Prototypes/Store/categories.yml b/Resources/Prototypes/Store/categories.yml index 53457b252ad..37b3d0f58b6 100644 --- a/Resources/Prototypes/Store/categories.yml +++ b/Resources/Prototypes/Store/categories.yml @@ -44,50 +44,57 @@ name: store-category-ammo priority: 1 +#ADT_Tweak-Start +- type: storeCategory + id: UplinkAttachments #ADT_Tweak + name: store-category-attachments + priority: 2 +#ADT_Tweak-END + - type: storeCategory id: UplinkExplosives name: store-category-explosives - priority: 2 + priority: 3 #ADT_Tweak - type: storeCategory id: UplinkWearables name: store-category-wearables - priority: 3 + priority: 4 #ADT_Tweak - type: storeCategory id: UplinkChemicals name: store-category-chemicals - priority: 4 + priority: 5 #ADT_Tweak - type: storeCategory id: UplinkDeception name: store-category-deception - priority: 5 + priority: 6 #ADT_Tweak - type: storeCategory id: UplinkDisruption name: store-category-disruption - priority: 6 + priority: 7 #ADT_Tweak - type: storeCategory id: UplinkImplants name: store-category-implants - priority: 7 + priority: 8 #ADT_Tweak - type: storeCategory id: UplinkAllies name: store-category-allies - priority: 8 + priority: 9 #ADT_Tweak - type: storeCategory id: UplinkJob name: store-category-job - priority: 9 + priority: 10 #ADT_Tweak - type: storeCategory id: UplinkPointless name: store-category-pointless - priority: 10 + priority: 11 #ADT_Tweak #revenant - type: storeCategory diff --git a/Resources/Prototypes/Store/presets.yml b/Resources/Prototypes/Store/presets.yml index 762ed68921a..810a52808ef 100644 --- a/Resources/Prototypes/Store/presets.yml +++ b/Resources/Prototypes/Store/presets.yml @@ -7,6 +7,7 @@ categories: - UplinkWeaponry - UplinkAmmo + - UplinkAttachments #ADT_Tweak - UplinkExplosives - UplinkChemicals - UplinkDeception From 5c55eb325028cbd9f9d292e85333704803e26c1b Mon Sep 17 00:00:00 2001 From: FaDeOkno Date: Sat, 14 Dec 2024 23:17:03 +0400 Subject: [PATCH 44/46] =?UTF-8?q?=D0=B0=20=D0=BA=D1=82=D0=BE=20=D1=82?= =?UTF-8?q?=D0=B0=D0=BA=D0=B8=D0=B5=20=D1=84=D0=B8=D0=BA=D1=81=D0=B8=D0=BA?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ADT/_RMC14/Attachable/Systems/AttachableHolderSystem.cs | 2 ++ .../Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableHolderSystem.cs b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableHolderSystem.cs index ef0d19e6864..f3e31709adb 100644 --- a/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableHolderSystem.cs +++ b/Content.Shared/ADT/_RMC14/Attachable/Systems/AttachableHolderSystem.cs @@ -382,6 +382,7 @@ public bool Attach(Entity holder, Dirty(holder); + _gun.RefreshModifiers(holder.Owner); _audio.PlayPredicted(Comp(attachableUid).AttachSound, holder, userUid); @@ -480,6 +481,7 @@ public bool Detach(Entity holder, userUid); Dirty(holder); + _gun.RefreshModifiers(holder.Owner); _hands.TryPickupAnyHand(userUid, attachable); return true; } diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml index ccca1079be2..f4043820d0c 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml @@ -407,7 +407,7 @@ Structural: 30 # Short lifespan - type: TimedDespawn - lifetime: 0.4 + lifetime: 0.1 - type: GatheringProjectile - type: entity From 5e0b2882094eee4ab3590ec0d51dee83ceaea1dc Mon Sep 17 00:00:00 2001 From: PyotrIgn Date: Wed, 18 Dec 2024 17:07:34 +0400 Subject: [PATCH 45/46] =?UTF-8?q?=D0=B2=D1=80=D0=B5=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=BD=D1=8B=D0=B9=20=D0=BA=D0=BE=D1=81=D1=82=D1=8B=D0=BB=D1=8C?= =?UTF-8?q?=20=D0=BF=D1=80=D0=B8=D1=86=D0=B5=D0=BB=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Guns/Attachments/Attachments/rail_attachment.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/rail_attachment.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/rail_attachment.yml index f576b3e9068..2c7a781f3bd 100644 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/rail_attachment.yml +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Guns/Attachments/Attachments/rail_attachment.yml @@ -80,8 +80,8 @@ - type: AttachableToggleableSimpleActivate - type: Scope zoomLevels: - - zoom: 1.6 - offset: 14 + - zoom: 1.8 + offset: 0 allowMovement: false doAfter: 0 - type: AttachableSpeedMods @@ -132,8 +132,8 @@ - type: AttachableToggleableSimpleActivate - type: Scope zoomLevels: - - zoom: 1.2 - offset: 12 + - zoom: 1.4 + offset: 0 allowMovement: true doAfter: 0 requireWielding: false From 3da06038f494513b626d6b1911531b5741cbae5c Mon Sep 17 00:00:00 2001 From: PyotrIgn Date: Wed, 18 Dec 2024 17:21:24 +0400 Subject: [PATCH 46/46] =?UTF-8?q?=D1=84=D1=83=D0=BB=D0=BB=20=D0=B0=D0=B2?= =?UTF-8?q?=D1=82=D0=BE=20=D1=83=20=D0=B4=D1=80=D0=BE=D0=B7=D0=B4=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml index 9337ac00420..8f380d0202d 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml @@ -163,11 +163,12 @@ maxAngle: 32 fireRate: 12 burstFireRate: 12 - selectedMode: Burst + selectedMode: FullAuto soundGunshot: path: /Audio/Weapons/Guns/Gunshots/atreides.ogg availableModes: - Burst + - FullAuto shotsPerBurst: 3 burstCooldown: 0.25 - type: ItemSlots