Skip to content

Commit

Permalink
Добавил возможность вешать значки на броню (#608)
Browse files Browse the repository at this point in the history
## Описание 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 в скобках, например [X]):
-->
- [x] Я прочитал(а) и следую [Руководство по созданию пулл
реквестов](https://docs.spacestation14.com/en/general-development/codebase-info/pull-request-guidelines.html).
Я понимаю, что в противном случае мой ПР может быть закрыт по усмотрению
мейнтейнера.
- [x] Я добавил скриншоты/видео к этому пулл реквесту, демонстрирующие
его изменения в игре, **или** этот пулл реквест не требует демонстрации
в игре

## Критические изменения
<!--
Перечислите все критические изменения, включая изменения пространства
имён, публичных классов/методов/полей, переименования прототипов, и
предоставьте инструкции по их исправлению.
-->

**Чейнджлог**
<!--
Здесь Вы можете заполнить журнал изменений, который будет автоматически
добавлен в игру при мердже Вашего пулл реквест.

Чтобы игроки узнали о новых возможностях и изменениях, которые могут
повлиять на их игру, добавьте запись в журнал изменений.

Не считайте суффикс типа записи (например, add) "частью" предложения:
плохо: - add: новый инструмент для инженеров
хорошо: - add: добавлен новый инструмент для инженеров

Помещение имени после символа 🆑 изменит имя, которое будет
отображаться в журнале изменений (в противном случае будет
использоваться ваше имя пользователя GitHub).
Например: 🆑 AruMoon
-->

🆑
- add: Добавлена возможность закреплять значок на броне СБ

---------

Co-authored-by: Tymur Valiiev <[email protected]>
Co-authored-by: bananchiki <[email protected]>
Co-authored-by: PyotrIgn <[email protected]>
Co-authored-by: Schrödinger <[email protected]>
  • Loading branch information
5 people authored Oct 30, 2024
1 parent 423e11c commit b59c69f
Show file tree
Hide file tree
Showing 13 changed files with 288 additions and 11 deletions.
15 changes: 15 additions & 0 deletions Content.Shared/ADT/Clothing/Badge/BadgeComponent.cs
Original file line number Diff line number Diff line change
@@ -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";
}
60 changes: 60 additions & 0 deletions Content.Shared/ADT/Clothing/Badge/BadgeSystem.cs
Original file line number Diff line number Diff line change
@@ -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<BadgeComponent, ExaminedEvent>(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);
}
}
10 changes: 10 additions & 0 deletions Content.Shared/ADT/Clothing/Badge/BadgeableComponent.cs
Original file line number Diff line number Diff line change
@@ -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";
}
81 changes: 81 additions & 0 deletions Content.Shared/ADT/Clothing/Badge/BadgeableSystem.cs
Original file line number Diff line number Diff line change
@@ -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<BadgeableComponent, ExaminedEvent>(HandleExaminedEvent);
SubscribeLocalEvent<InventoryComponent, ExaminedEvent>(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<BadgeableComponent>(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);
}

}
}
}
8 changes: 8 additions & 0 deletions Resources/Locale/ru-RU/ADT/clothing/vest.ftl
Original file line number Diff line number Diff line change
@@ -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}
4 changes: 4 additions & 0 deletions Resources/Prototypes/ADT/Entities/Clothing/Neck/specific.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
components:
- type: Sprite
sprite: ADT/Clothing/Neck/Specific/secbadge.rsi
- type: Badge
- type: Tag
tags:
- ADTBadge

- type: entity
parent: ClothingNeckBase
Expand Down
48 changes: 48 additions & 0 deletions Resources/Prototypes/ADT/Entities/Clothing/OuterClothing/armor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions Resources/Prototypes/ADT/tags.yml
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@
- type: Tag
id: JanicartKeys

- type: Tag
id: ADTBadge

- type: Tag
id: ADTMagazineRifleExtended

Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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.
Expand All @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
32 changes: 28 additions & 4 deletions Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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.
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit b59c69f

Please sign in to comment.