From b59c69ffe65411c07ed402d394728ccf2b7bb998 Mon Sep 17 00:00:00 2001 From: Mirokko Date: Wed, 30 Oct 2024 20:19:32 +0200 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20?= =?UTF-8?q?=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D1=8C=20=D0=B2=D0=B5=D1=88=D0=B0=D1=82=D1=8C=20=D0=B7=D0=BD?= =?UTF-8?q?=D0=B0=D1=87=D0=BA=D0=B8=20=D0=BD=D0=B0=20=D0=B1=D1=80=D0=BE?= =?UTF-8?q?=D0=BD=D1=8E=20(#608)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Описание PR Название ## Почему / Баланс **Ссылка на публикацию в Discord** - [Баги](https://discord.com/channels/901772674865455115/1284125054375825439) ## Техническая информация ## Медиа ![изображение](https://github.com/user-attachments/assets/7e688ad2-3527-4af3-93f7-56d9c9ebc01f) ![изображение](https://github.com/user-attachments/assets/33454da1-06b9-47ea-b9ee-c023f8daaf1f) ![изображение](https://github.com/user-attachments/assets/2a707438-945b-4b3d-9f57-01eeab520810) ![изображение](https://github.com/user-attachments/assets/affd712b-b2d0-4654-8c98-d8e99910d828) ![изображение](https://github.com/user-attachments/assets/e26a5bf1-3d73-46e9-b32d-8d6b6d4825af) ![изображение](https://github.com/user-attachments/assets/109fd75f-4161-4aa2-ab47-888a7fd76b9b) ## Требования - [x] Я прочитал(а) и следую [Руководство по созданию пулл реквестов](https://docs.spacestation14.com/en/general-development/codebase-info/pull-request-guidelines.html). Я понимаю, что в противном случае мой ПР может быть закрыт по усмотрению мейнтейнера. - [x] Я добавил скриншоты/видео к этому пулл реквесту, демонстрирующие его изменения в игре, **или** этот пулл реквест не требует демонстрации в игре ## Критические изменения **Чейнджлог** :cl: - add: Добавлена возможность закреплять значок на броне СБ --------- Co-authored-by: Tymur Valiiev Co-authored-by: bananchiki <87230164+Darkiich@users.noreply.github.com> Co-authored-by: PyotrIgn <131798882+PyotrIgn@users.noreply.github.com> Co-authored-by: Schrödinger <132720404+Schrodinger71@users.noreply.github.com> --- .../ADT/Clothing/Badge/BadgeComponent.cs | 15 ++++ .../ADT/Clothing/Badge/BadgeSystem.cs | 60 ++++++++++++++ .../ADT/Clothing/Badge/BadgeableComponent.cs | 10 +++ .../ADT/Clothing/Badge/BadgeableSystem.cs | 81 +++++++++++++++++++ Resources/Locale/ru-RU/ADT/clothing/vest.ftl | 8 ++ .../ADT/Entities/Clothing/Neck/specific.yml | 4 + .../Entities/Clothing/OuterClothing/armor.yml | 48 +++++++++++ Resources/Prototypes/ADT/tags.yml | 3 + .../Entities/Clothing/OuterClothing/coats.yml | 28 ++++++- .../Entities/Clothing/OuterClothing/vests.yml | 6 +- .../Entities/Clothing/OuterClothing/armor.yml | 2 +- .../Entities/Clothing/OuterClothing/coats.yml | 32 +++++++- .../Entities/Clothing/OuterClothing/vests.yml | 2 +- 13 files changed, 288 insertions(+), 11 deletions(-) create mode 100644 Content.Shared/ADT/Clothing/Badge/BadgeComponent.cs create mode 100644 Content.Shared/ADT/Clothing/Badge/BadgeSystem.cs create mode 100644 Content.Shared/ADT/Clothing/Badge/BadgeableComponent.cs create mode 100644 Content.Shared/ADT/Clothing/Badge/BadgeableSystem.cs create mode 100644 Resources/Locale/ru-RU/ADT/clothing/vest.ftl diff --git a/Content.Shared/ADT/Clothing/Badge/BadgeComponent.cs b/Content.Shared/ADT/Clothing/Badge/BadgeComponent.cs new file mode 100644 index 00000000000..bff6f12e719 --- /dev/null +++ b/Content.Shared/ADT/Clothing/Badge/BadgeComponent.cs @@ -0,0 +1,15 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.ADT.Clothing.Badge; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class BadgeComponent : Component +{ + [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] + public string BadgeNumber = String.Empty; + + [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] + public string NotInDetailsText = "badge-cannot-be-seen-text"; + [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] + public string InDetailsText = "badge-can-be-seen-text"; +} diff --git a/Content.Shared/ADT/Clothing/Badge/BadgeSystem.cs b/Content.Shared/ADT/Clothing/Badge/BadgeSystem.cs new file mode 100644 index 00000000000..980fa2bb2ea --- /dev/null +++ b/Content.Shared/ADT/Clothing/Badge/BadgeSystem.cs @@ -0,0 +1,60 @@ +using System.Diagnostics.CodeAnalysis; +using Content.Shared.Examine; +using Robust.Shared.Network; +using Robust.Shared.Random; + +namespace Content.Shared.ADT.Clothing.Badge; + +public sealed class BadgeSystem : EntitySystem +{ + [Dependency] protected readonly ExamineSystemShared ExamineSystem = default!; + [Dependency] protected readonly IRobustRandom Random = default!; + [Dependency] private readonly INetManager _net = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnExamined); + } + + private void OnExamined(EntityUid uid, BadgeComponent component, ExaminedEvent args) + { + if (!GetBadgeNumber(uid, out var badgeNumber, component)) + return; + + if (!ExamineSystem.IsInDetailsRange(args.Examiner, uid)) + { + if (component.NotInDetailsText != String.Empty) + args.PushMarkup(Loc.GetString(component.NotInDetailsText, ("badgeNumber", badgeNumber))); + + return; + } + + if (component.InDetailsText != String.Empty) + args.PushMarkup(Loc.GetString(component.InDetailsText, ("badgeNumber", badgeNumber))); + } + + public bool GetBadgeNumber(EntityUid badge, [NotNullWhen(true)] out string? badgeNumber, BadgeComponent? component = null) + { + badgeNumber = null; + if (!Resolve(badge, ref component)) + return false; + + if (component.BadgeNumber == String.Empty) + { + if (_net.IsClient) + return false; + component.BadgeNumber = GenerateBadgeNumber(badge, component); + Dirty(badge, component); + } + + badgeNumber = component.BadgeNumber; + return true; + } + + private string GenerateBadgeNumber(EntityUid badge, BadgeComponent component) + { + return badge.Id + "-" + Random.Next(100, 99999) + "/" + Random.Next(1, 50); + } +} diff --git a/Content.Shared/ADT/Clothing/Badge/BadgeableComponent.cs b/Content.Shared/ADT/Clothing/Badge/BadgeableComponent.cs new file mode 100644 index 00000000000..d78ed547922 --- /dev/null +++ b/Content.Shared/ADT/Clothing/Badge/BadgeableComponent.cs @@ -0,0 +1,10 @@ + +namespace Content.Shared.ADT.Clothing.Badge; + +[RegisterComponent] +public sealed partial class BadgeableComponent : Component +{ + public string Slot = "badge"; + public string NotInDetailsText = "badgeable-badge-cannot-be-seen-text"; + public string InDetailsText = "badgeable-badge-can-be-seen-text"; +} diff --git a/Content.Shared/ADT/Clothing/Badge/BadgeableSystem.cs b/Content.Shared/ADT/Clothing/Badge/BadgeableSystem.cs new file mode 100644 index 00000000000..973888d0bb0 --- /dev/null +++ b/Content.Shared/ADT/Clothing/Badge/BadgeableSystem.cs @@ -0,0 +1,81 @@ +using System.Diagnostics.CodeAnalysis; +using Content.Shared.ADT.Clothing.Badge; +using Content.Shared.Clothing; +using Content.Shared.Clothing.Components; +using Content.Shared.Containers.ItemSlots; +using Content.Shared.Examine; +using Content.Shared.Humanoid; +using Content.Shared.Inventory; + +namespace Content.Shared.ADT.Clothing.Badge; + +[Virtual] +public class BadgeableSystem : EntitySystem +{ + [Dependency] protected readonly ItemSlotsSystem ItemSlotsSystem = default!; + [Dependency] protected readonly BadgeSystem BadgeSystem = default!; + [Dependency] protected readonly InventorySystem InventorySystem = default!; + [Dependency] protected readonly ExamineSystemShared ExamineSystem = default!; + + override public void Initialize() + { + base.Initialize(); + + + SubscribeLocalEvent(HandleExaminedEvent); + SubscribeLocalEvent(HandleEntityExaminedEvent); + } + + public bool GetBadgeNumber(EntityUid entity, [NotNullWhen(true)] out string? badgeNumber, BadgeableComponent? component = null) + { + badgeNumber = null; + + if (!Resolve(entity, ref component)) + return false; + + var badge = ItemSlotsSystem.GetItemOrNull(entity, component.Slot); + if (badge is null) + return false; + + return BadgeSystem.GetBadgeNumber(badge.Value, out badgeNumber); + } + + protected void HandleExaminedEvent(EntityUid entity, BadgeableComponent component, ExaminedEvent ev) + { + if (!GetBadgeNumber(entity, out var badgeNumber, component)) + return; + + if (!ExamineSystem.IsInDetailsRange(ev.Examiner, entity)) + { + if (component.NotInDetailsText != String.Empty) + ev.PushMarkup(Loc.GetString(component.NotInDetailsText, ("badgeNumber", badgeNumber)), -5); + + return; + } + + if (component.InDetailsText != String.Empty) + ev.PushMarkup(Loc.GetString(component.InDetailsText, ("badgeNumber", badgeNumber)), -5); + } + + protected void HandleEntityExaminedEvent(EntityUid entity, InventoryComponent _, ExaminedEvent ev) + { + var enumerator = InventorySystem.GetSlotEnumerator(entity, SlotFlags.OUTERCLOTHING); + while (enumerator.MoveNext(out var container)) + { + if (!container.ContainedEntity.HasValue || container.ContainedEntity == null) + continue; + + if (!TryComp(container.ContainedEntity, out var vest)) + continue; + + if (GetBadgeNumber(container.ContainedEntity.Value, out var badgeNumber)) + { + if (ExamineSystem.IsInDetailsRange(ev.Examiner, entity)) + ev.PushMarkup(Loc.GetString(vest.InDetailsText, ("badgeNumber", badgeNumber)), -5); + else + ev.PushMarkup(Loc.GetString(vest.NotInDetailsText, ("badgeNumber", badgeNumber)), -5); + } + + } + } +} diff --git a/Resources/Locale/ru-RU/ADT/clothing/vest.ftl b/Resources/Locale/ru-RU/ADT/clothing/vest.ftl new file mode 100644 index 00000000000..b6f9b4d067d --- /dev/null +++ b/Resources/Locale/ru-RU/ADT/clothing/vest.ftl @@ -0,0 +1,8 @@ +attach-to-armor = Нацепить на броню +unattach-to-armor = Отцепить от брони + +badgeable-badge-cannot-be-seen-text = На броне закреплён какой-то значок +badgeable-badge-can-be-seen-text = На броне закреплён значок №{$badgeNumber} + +badge-cannot-be-seen-text = Номер значка не видно +badge-can-be-seen-text = Значок №{$badgeNumber} diff --git a/Resources/Prototypes/ADT/Entities/Clothing/Neck/specific.yml b/Resources/Prototypes/ADT/Entities/Clothing/Neck/specific.yml index 83b8fe97a3f..a62b800c386 100644 --- a/Resources/Prototypes/ADT/Entities/Clothing/Neck/specific.yml +++ b/Resources/Prototypes/ADT/Entities/Clothing/Neck/specific.yml @@ -6,6 +6,10 @@ components: - type: Sprite sprite: ADT/Clothing/Neck/Specific/secbadge.rsi + - type: Badge + - type: Tag + tags: + - ADTBadge - type: entity parent: ClothingNeckBase diff --git a/Resources/Prototypes/ADT/Entities/Clothing/OuterClothing/armor.yml b/Resources/Prototypes/ADT/Entities/Clothing/OuterClothing/armor.yml index c507d98580c..d36ea876903 100644 --- a/Resources/Prototypes/ADT/Entities/Clothing/OuterClothing/armor.yml +++ b/Resources/Prototypes/ADT/Entities/Clothing/OuterClothing/armor.yml @@ -18,6 +18,54 @@ - type: ExplosionResistance damageCoefficient: 0.80 +#ADT-Tweak-Start +- type: entity + abstract: true + id: BadgeOnClothing + components: + - type: Badgeable + - type: ContainerContainer + containers: + badge: !type:ContainerSlot + showEnts: False + occludes: True + ent: null + - type: ItemSlots + slots: + badge: + name: Badge + insertVerbText: attach-to-armor + ejectVerbText: unattach-to-armor + whitelist: + tags: + - ADTBadge + +- type: entity + abstract: true + id: BadgeOnClothingWithContainer + components: + - type: Badgeable + - type: ContainerContainer + containers: + storagebase: !type:Container + showEnts: False + occludes: True + ents: [] + badge: !type:ContainerSlot + showEnts: False + occludes: True + ent: null + - type: ItemSlots + slots: + badge: + name: Badge + insertVerbText: attach-to-armor + ejectVerbText: unattach-to-armor + whitelist: + tags: + - ADTBadge +#ADT-Tweak-End + - type: entity parent: [ClothingOuterBaseLarge, AllowSuitStorageClothing, BaseRestrictedContraband] id: ClothingOuterArmorAirsoftBlue diff --git a/Resources/Prototypes/ADT/tags.yml b/Resources/Prototypes/ADT/tags.yml index 5bcb8fc31f9..00aff4d367d 100644 --- a/Resources/Prototypes/ADT/tags.yml +++ b/Resources/Prototypes/ADT/tags.yml @@ -127,6 +127,9 @@ - type: Tag id: JanicartKeys +- type: Tag + id: ADTBadge + - type: Tag id: ADTMagazineRifleExtended diff --git a/Resources/Prototypes/Corvax/Entities/Clothing/OuterClothing/coats.yml b/Resources/Prototypes/Corvax/Entities/Clothing/OuterClothing/coats.yml index 126847d5938..5cb3271eb7c 100644 --- a/Resources/Prototypes/Corvax/Entities/Clothing/OuterClothing/coats.yml +++ b/Resources/Prototypes/Corvax/Entities/Clothing/OuterClothing/coats.yml @@ -1,5 +1,5 @@ - type: entity - parent: ClothingOuterCoatHoSTrench + parent: [ClothingOuterCoatHoSTrench, BadgeOnClothingWithContainer] #ADT-Tweak id: ClothingOuterCoatHoSGreatcoat name: armored greatcoat description: A greatcoat enhanced with a special alloy for some extra protection and style for those with a commanding presence. @@ -15,6 +15,18 @@ Slash: 0.7 Piercing: 0.4 Heat: 0.7 + #ADT-Tweak-Start + - type: ContainerContainer + containers: + storagebase: !type:Container + showEnts: False + occludes: True + ents: [] + badge: !type:ContainerSlot + showEnts: False + occludes: True + ent: null + #ADT-Tweak-End - type: entity parent: ClothingOuterCoatDetectiveLoadout @@ -53,7 +65,7 @@ Heat: 0.8 - type: entity - parent: ClothingOuterStorageBase + parent: [ClothingOuterStorageBase, BadgeOnClothingWithContainer] #ADT-Tweak id: ClothingOuterCoatSecurityOvercoat name: security overcoat description: Lightly armored leather overcoat meant as casual wear for high-ranking officers. Bears the crest of Nanotrasen Security. @@ -69,6 +81,18 @@ Slash: 0.8 Piercing: 0.6 Heat: 0.9 + #ADT-Tweak-Start + - type: ContainerContainer + containers: + storagebase: !type:Container + showEnts: False + occludes: True + ents: [] + badge: !type:ContainerSlot + showEnts: False + occludes: True + ent: null + #ADT-Tweak-End - type: entity parent: ClothingOuterStorageBase diff --git a/Resources/Prototypes/Corvax/Entities/Clothing/OuterClothing/vests.yml b/Resources/Prototypes/Corvax/Entities/Clothing/OuterClothing/vests.yml index 42b00999ebf..508c31a8a35 100644 --- a/Resources/Prototypes/Corvax/Entities/Clothing/OuterClothing/vests.yml +++ b/Resources/Prototypes/Corvax/Entities/Clothing/OuterClothing/vests.yml @@ -1,5 +1,5 @@ - type: entity - parent: ClothingOuterArmorBasic + parent: [ClothingOuterArmorBasic, BadgeOnClothing] #ADT-Tweak id: ClothingOuterVestArmorSec name: armor vest description: A slim Type I armored vest that provides decent protection against most types of damage. @@ -10,7 +10,7 @@ sprite: Corvax/Clothing/OuterClothing/Vests/armor_sec.rsi - type: entity - parent: ClothingOuterArmorBasic + parent: [ClothingOuterArmorBasic, BadgeOnClothing] #ADT-Tweak id: ClothingOuterVestArmorMedSec name: security medic armor vest description: A security medic's armor vest, with little pockets for little things. @@ -21,7 +21,7 @@ sprite: Corvax/Clothing/OuterClothing/Vests/armor_sec_med.rsi - type: entity - parent: ClothingOuterBase + parent: [ClothingOuterBase, BadgeOnClothing] #ADT-Tweak id: ClothingOuterVestSecurityMedic name: security medic vest description: A lightweight vest worn by the Security Medic. diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/armor.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/armor.yml index 392e129b0ef..8c83baa4fec 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/armor.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/armor.yml @@ -3,7 +3,7 @@ #Basic armor vest - type: entity - parent: [ClothingOuterBaseMedium, AllowSuitStorageClothing, BaseRestrictedContraband] + parent: [ClothingOuterBaseMedium, AllowSuitStorageClothing, BaseRestrictedContraband, BadgeOnClothing] #ADT-Tweak id: ClothingOuterArmorBasic name: armor vest description: A standard Type I armored vest that provides decent protection against most types of damage. diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml index 973af522216..6540b0c8993 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml @@ -10,7 +10,7 @@ sprite: Clothing/OuterClothing/Coats/bomber.rsi - type: entity - parent: [ClothingOuterStorageBase, AllowSuitStorageClothing, ClothingOuterArmorBasic] + parent: [ClothingOuterStorageBase, AllowSuitStorageClothing, ClothingOuterArmorBasic, BadgeOnClothingWithContainer] #ADT-Tweak id: ClothingOuterCoatDetective name: detective trenchcoat description: An 18th-century multi-purpose trenchcoat. Someone who wears this means serious business. @@ -25,9 +25,21 @@ - id: FlippoEngravedLighter - type: ExplosionResistance damageCoefficient: 1 #its a coat. it doesnt do shit - -- type: entity - parent: [ClothingOuterCoatDetectiveLoadout] + #ADT-Tweak-Start + - type: ContainerContainer + containers: + storagebase: !type:Container + showEnts: False + occludes: True + ents: [] + badge: !type:ContainerSlot + showEnts: False + occludes: True + ent: null + #ADT-Tweak-End + +- type: entity + parent: ClothingOuterCoatDetectiveLoadout id: ClothingOuterCoatDetectiveLoadoutGrey name: noir trenchcoat description: Ah, your trusty coat. There's a few tears here and there, giving it a more timely look. Or at least, that's what you told yourself when you found out gettin' it repaired would set you back 200 speos. @@ -99,6 +111,18 @@ sprite: Clothing/OuterClothing/Coats/hos_trenchcoat.rsi - type: Clothing sprite: Clothing/OuterClothing/Coats/hos_trenchcoat.rsi + #ADT-Tweak-Start + - type: ContainerContainer + containers: + storagebase: !type:Container + showEnts: False + occludes: True + ents: [] + badge: !type:ContainerSlot + showEnts: False + occludes: True + ent: null + #ADT-Tweak-End - type: entity parent: ClothingOuterStorageToggleableBase diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/vests.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/vests.yml index 545f46cc8cb..8b964f0a423 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/vests.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/vests.yml @@ -42,7 +42,7 @@ #Detective's vest - type: entity - parent: [ClothingOuterArmorBasic, BaseRestrictedContraband] + parent: [ClothingOuterArmorBasic, BaseRestrictedContraband, BadgeOnClothing] #ADT-Tweak id: ClothingOuterVestDetective name: detective's vest description: A hard-boiled private investigator's armored vest.