Skip to content

Pullable Helmet. Ивентовый Контент. Механика Забрала. H/M#566

Open
Maggotson wants to merge 2 commits intoimperial-space:developfrom
Maggotson:ninja
Open

Pullable Helmet. Ивентовый Контент. Механика Забрала. H/M#566
Maggotson wants to merge 2 commits intoimperial-space:developfrom
Maggotson:ninja

Conversation

@Maggotson
Copy link
Contributor

@Maggotson Maggotson commented Feb 14, 2026

О ПР`е

Тип: feat

Изменения: Ивентовый контент

Технические детали

Добавлен компонент (и его системая) PullableHelmet, позволяющий переключать шлем через действие/контекстное меню.

Изменения кода официальных разработчиков

Нет

Summary by CodeRabbit

  • Новые функции
    • Добавлена механика переключения забрала шлема K6.3 с задержкой, звуками и действиями; варианты шлема можно поднимать/опускать.
  • Графика
    • Обновлены и добавлены визуальные спрайты/состояния для новых вариантов K6.3.
  • Локализация
    • Добавлены русские строки для действий «Опустить забрало» / «Поднять забрало» и новых сущностей.

@github-actions github-actions bot added size/Small Насколько сложно будет апстримить Resprite Изменения заменяют оригинальные текстуры визардов Change Wiz Code Изменения вмешиваются в код визардов Prototypes Изменения добавляет новые прототипы C# Изменения добавляют новый C# код Change WIz Prototypes Изменения вмешиваются в код прототипов визардов Sprite Изменения добавляют спрайты Audio Изменения добавляют ogg and removed size/Small Насколько сложно будет апстримить labels Feb 14, 2026
@Maggotson Maggotson changed the title Pullable Helmet Pullable Helmet. Ивентовый Контент. Механика Забрала. H/M Feb 14, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 14, 2026

Walkthrough

Добавлены механика и данные для съёмного/опускаемого забрала шлема K6-3: новый серверный компонент PullableHelmetComponent с настраиваемыми полями (прототипы, тексты, задержка, звуки, действие и т.д.), система PullableHelmetSystem, управляющая глаголами, DoAfter-процессом, переключением прототипов и звуком, сетевые/общие типы событий PullHelmetActionEvent и PullHelmetDoAfterEvent, обновлены прототипы (варианты поднятого/опущенного шлема), локализации и текстуры.

Sequence Diagram

sequenceDiagram
    actor Player
    participant VerbSystem as "Verb System"
    participant DoAfterSystem as "DoAfter System"
    participant PullSystem as "PullableHelmetSystem"
    participant InventorySystem as "Inventory System"
    participant AudioSystem as "Audio System"

    Player->>VerbSystem: Использует глагол "Поднять/Опустить"
    VerbSystem->>DoAfterSystem: TryStartDoAfter (delay из компонента)
    DoAfterSystem->>DoAfterSystem: Ожидание (Delay)
    DoAfterSystem->>PullSystem: PullHelmetDoAfterEvent
    PullSystem->>InventorySystem: Проверяет RequiredFlags/слот
    alt Флаги валидны
        PullSystem->>PullSystem: Спавнит прототип (toggled/untoggled)
        PullSystem->>InventorySystem: Ставит/убирает одежду в слот
        PullSystem->>AudioSystem: Проигрывает PullUp/PullDown звук
        PullSystem->>PullSystem: Удаляет старую сущность
    else Флаги не валидны
        PullSystem->>Player: Выдаёт попап/ошибку
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Merge Conflict Detection ⚠️ Warning ❌ Merge conflicts detected (42 files):

⚔️ Content.Client/Imperial/MiningWeapons/Smasher/SmasherSystem.cs (content)
⚔️ Content.Server/Imperial/Atmos/Reactions/DeuteriumProductionReaction.cs (content)
⚔️ Content.Server/Imperial/MiningWeapons/Smasher/SmasherSystem.Activation.cs (content)
⚔️ Content.Server/Imperial/MiningWeapons/Smasher/SmasherSystem.Deactivation.cs (content)
⚔️ Content.Server/Imperial/MiningWeapons/Smasher/SmasherSystem.cs (content)
⚔️ Content.Server/Imperial/Seriozha/Fredik21/callmtf/MTFCallCommand.cs (content)
⚔️ Content.Shared/Atmos/Atmospherics.cs (content)
⚔️ Content.Shared/Imperial/MiningWeapons/Smasher/Components/SmasherComponent.cs (content)
⚔️ Content.Shared/Imperial/MiningWeapons/Smasher/SharedSmasherSystem.cs (content)
⚔️ Resources/Audio/Imperial/Seriozha/SCP/event/attributions.yml (content)
⚔️ Resources/Locale/ru-RU/Imperial/DeadSector/helmets.ftl (content)
⚔️ Resources/Locale/ru-RU/Imperial/Seriozha/SCP/Fredik21/locale.ftl (content)
⚔️ Resources/Locale/ru-RU/Imperial/Seriozha/SCP/locale.ftl (content)
⚔️ Resources/Locale/ru-RU/Imperial/Unsorted/entities.ftl (content)
⚔️ Resources/Locale/ru-RU/kitchen/components/kitchen-spike-component.ftl (content)
⚔️ Resources/Locale/ru-RU/prototypes/catalog/fills/backpacks/duffelbag.ftl (content)
⚔️ Resources/Locale/ru-RU/store/uplink-catalog.ftl (content)
⚔️ Resources/Prototypes/Catalog/Fills/Backpacks/duffelbag.yml (content)
⚔️ Resources/Prototypes/Catalog/Imperial/uplink_catalog.yml (content)
⚔️ Resources/Prototypes/Catalog/uplink_catalog.yml (content)
⚔️ Resources/Prototypes/Imperial/Atmospherics/Thermonium/thermonium_reagent.yml (content)
⚔️ Resources/Prototypes/Imperial/Catalog/Fills/syndicate_upling_catalog_imperial.yml (content)
⚔️ Resources/Prototypes/Imperial/Clothing/Helmets/k6_3.yml (content)
⚔️ Resources/Prototypes/Imperial/Crook/misc.yml (content)
⚔️ Resources/Prototypes/Imperial/Felix/objects.yml (content)
⚔️ Resources/Prototypes/Imperial/HamMaggotson/Entities/clothing.yml (content)
⚔️ Resources/Prototypes/Imperial/MiningWeapons/Smasher/smasher.yml (content)
⚔️ Resources/Prototypes/Imperial/Other/BundleAKMS/uplink_catalog.yml (content)
⚔️ Resources/Prototypes/Imperial/Other/ElysiumPrime/entities.yml (content)
⚔️ Resources/Prototypes/Imperial/Seriozha/SCP/Fredik21/scp.yml (content)
⚔️ Resources/Prototypes/Imperial/Seriozha/SCP/SCP.yml (content)
⚔️ Resources/Prototypes/Imperial/Seriozha/SCP/id.yml (content)
⚔️ Resources/Prototypes/Imperial/Seriozha/SCP/names.yml (content)
⚔️ Resources/Prototypes/Imperial/Seriozha/SCP/presets.yml (content)
⚔️ Resources/ServerInfo/Guidebook/Engineering/Gasses.xml (content)
⚔️ Resources/Textures/Imperial/Crook/Misc/headcoat.rsi/icon-flash.png (content)
⚔️ Resources/Textures/Imperial/Crook/Misc/headcoat.rsi/icon.png (content)
⚔️ Resources/Textures/Imperial/Crook/Misc/headcoat.rsi/off-equipped-HELMET.png (content)
⚔️ Resources/Textures/Imperial/Crook/Misc/headcoat.rsi/on-equipped-HELMET.png (content)
⚔️ Resources/Textures/Imperial/MiningWeapons/Smasher/smasher_item.rsi/meta.json (content)
⚔️ Resources/Textures/Imperial/Seriozha/Fredik21/poster.rsi/meta.json (content)
⚔️ Resources/Textures/Imperial/Seriozha/Fredik21/uplink/all.rsi/meta.json (content)

These conflicts must be resolved before merging into develop.
Resolve conflicts locally and push changes to this branch.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: implementation of a pullable helmet mechanic with visor toggle functionality, which aligns with the substantial code additions for the PullableHelmetComponent and PullableHelmetSystem.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🤖 Fix all issues with AI agents
In
`@Content.Server/Imperial/HamMaggotson/PullableHelmet/Components/PullableHelmetComponent.cs`:
- Around line 1-8: Remove the duplicate and unused using directives in
PullableHelmetComponent: delete the repeated "using Robust.Shared.Prototypes;"
and remove the unused "using Content.Shared.Storage;". Keep any other necessary
usings (e.g., Robust.Shared.Audio, Robust.Shared.GameStates,
Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype,
Content.Shared.Inventory) and then rebuild to ensure no missing references; if
the compiler complains, re-add only the specific using required for the missing
symbol.
- Around line 34-37: PullUpSound and PullDownSound are declared as
auto-properties but should be plain fields like other component data; change the
declarations in PullableHelmetComponent so that PullUpSound and PullDownSound
are public fields (retain the [DataField] attribute and the default
SoundPathSpecifier initializers) instead of properties with { get; set; }, e.g.,
update the members on the PullableHelmetComponent class to be public
SoundSpecifier PullUpSound = ... and public SoundSpecifier PullDownSound = ....

In
`@Content.Server/Imperial/HamMaggotson/PullableHelmet/Systems/PullableHelmetSystem.cs`:
- Around line 66-77: Two TryStartDoAfter overloads duplicate building the same
DoAfterArgs; refactor by consolidating the shared DoAfterArgs construction into
a single helper or have one overload call the other. Specifically, centralize
creation of the DoAfterArgs (using EntityManager, args.Performer,
ent.Comp.Delay, new PullHelmetDoAfterEvent(), ent as both target and used, and
NeedHand = true) and then call _doAfter.TryStartDoAfter(...) from that helper so
both TryStartDoAfter(Entity<PullableHelmetComponent>, ref PullHelmetActionEvent)
and the other overload reuse the same logic.
- Around line 79-101: TryToggleHelmet should first check DoAfter results
(args.Cancelled or args.Handled) and return immediately if cancelled/handled,
and then be made private to match other handlers; move the cancelled check to
the top of TryToggleHelmet(PullableHelmetComponent component, ref
PullHelmetDoAfterEvent args). Avoid leaking the spawned entity: only
Spawn(newPrototype, ...) after confirming the DoAfter succeeded or, if you must
spawn earlier, ensure you QueueDel(newEntity) when TryGetContainingSlot returns
false. Also check the boolean results of _inventory.TryUnequip and
_inventory.TryEquip and only call QueueDel(uid) and _audio.PlayPvs(sound, user)
when both succeed; on failure rollback by QueueDel(newEntity) (and do not delete
the original uid). Use the existing symbols: TryToggleHelmet,
PullableHelmetComponent, args.Cancelled/args.Handled, TryGetContainingSlot,
TryUnequip, TryEquip, Spawn, QueueDel, and _audio.PlayPvs.

In `@Resources/Prototypes/Imperial/Clothing/Helmets/k6_3.yml`:
- Around line 109-113: В текущем блоке конфигурации типа PullableHelmet
(свойства PullableHelmet, untoggledPrototype: ClothingHeadHelmetK63Alternate,
toggledPrototype: ClothingHeadHelmetK63AlternateLowered, pullAction:
ToggleK63Helmet) отсутствует пустая строка-разделитель перед следующим
определением entity; исправьте это, добавив одну пустую строку сразу после блока
PullableHelmet (после строки с pullAction: ToggleK63Helmet) чтобы отделить
определение ClothingHeadHelmetK63Alternate/ClothingHeadHelmetK63AlternateLowered
от следующей сущности.
- Around line 69-78: The YAML entity ToggleK63Helmet has wrong English fallback
strings copied from ninja gloves; update the name and description fields (the
"name" and "description" entries under the ToggleK63Helmet entity) to
helmet-appropriate text (e.g., "Toggle K6-3 Helmet" and a description like
"Toggles helmet functions on left click: doorjack, power drain, stun and certain
hacks") so the English fallback matches the entity behavior triggered by the
InstantAction !type:PullHelmetActionEvent and Action entries; keep the rest of
the component definitions unchanged.
- Around line 35-67: ClothingHeadHelmetK63Lowered duplicates parent
ClothingHeadHelmetK63's Sprite, Item and HideLayerClothing components; remove
those duplicated component entries and only declare the components that differ
(keep Clothing with its altered clothingVisuals/head state on-equipped-HELMET,
plus Armor, ExplosionResistance and IngestionBlocker). Ensure the entity still
references parent ClothingHeadHelmetK63 so Sprite, Item (size: Normal) and
HideLayerClothing (Hair, HeadTop) are inherited, and only override Clothing
(clothingVisuals head state) and add the Armor and ExplosionResistance modifiers
as needed.

In
`@Resources/Textures/Imperial/Clothing/Head/Helmets/k6_3_new_alt.rsi/meta.json`:
- Line 4: The copyright field value contains a grammatical mistake: change the
string value of the "copyright" property from "Create by `@lune_felix`" to
"Created by `@lune_felix`" so the metadata uses correct English; update the
literal in the meta.json where the "copyright" key is defined.

In `@Resources/Textures/Imperial/Clothing/Head/Helmets/k6_3_new.rsi/meta.json`:
- Line 4: Update the value of the "copyright" field in the meta.json entry that
currently reads "Create by `@lune_felix`" to the grammatically correct "Created by
`@lune_felix`"; locate the "copyright" key in the meta.json for k6_3_new.rsi and
replace the string accordingly.

Comment on lines +1 to +8
using Content.Shared.Storage;
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
using Content.Shared.Inventory;
namespace Content.Server.Imperial.HamMaggotson.PullableHelmet.Components;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Дублированный using и потенциально неиспользуемый импорт.

Строка 3 и строка 5 — дублирование using Robust.Shared.Prototypes;. Также using Content.Shared.Storage; (строка 1) не используется в файле — нет ссылок на типы из этого пространства имён.

Исправление
-using Content.Shared.Storage;
 using Robust.Shared.Audio;
 using Robust.Shared.Prototypes;
 using Robust.Shared.GameStates;
-using Robust.Shared.Prototypes;
 using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
 using Content.Shared.Inventory;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
using Content.Shared.Storage;
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
using Content.Shared.Inventory;
namespace Content.Server.Imperial.HamMaggotson.PullableHelmet.Components;
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
using Content.Shared.Inventory;
namespace Content.Server.Imperial.HamMaggotson.PullableHelmet.Components;
🤖 Prompt for AI Agents
In
`@Content.Server/Imperial/HamMaggotson/PullableHelmet/Components/PullableHelmetComponent.cs`
around lines 1 - 8, Remove the duplicate and unused using directives in
PullableHelmetComponent: delete the repeated "using Robust.Shared.Prototypes;"
and remove the unused "using Content.Shared.Storage;". Keep any other necessary
usings (e.g., Robust.Shared.Audio, Robust.Shared.GameStates,
Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype,
Content.Shared.Inventory) and then rebuild to ensure no missing references; if
the compiler complains, re-add only the specific using required for the missing
symbol.

Comment on lines +34 to +37
[DataField]
public SoundSpecifier PullUpSound { get; set; } = new SoundPathSpecifier("/Audio/Imperial/HamMaggotson/helmet_pullup.ogg");
[DataField]
public SoundSpecifier PullDownSound { get; set; } = new SoundPathSpecifier("/Audio/Imperial/HamMaggotson/helmet_pulldown.ogg");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Несогласованность: свойства с { get; set; } вместо полей.

PullUpSound и PullDownSound объявлены как auto-properties ({ get; set; }), тогда как все остальные поля компонента — обычные поля. В SS14 компонентах обычно используются поля. Рекомендуется привести к единому стилю.

Исправление
     [DataField]
-    public SoundSpecifier PullUpSound { get; set; } = new SoundPathSpecifier("/Audio/Imperial/HamMaggotson/helmet_pullup.ogg");
+    public SoundSpecifier PullUpSound = new SoundPathSpecifier("/Audio/Imperial/HamMaggotson/helmet_pullup.ogg");
     [DataField]
-    public SoundSpecifier PullDownSound { get; set; } = new SoundPathSpecifier("/Audio/Imperial/HamMaggotson/helmet_pulldown.ogg");
+    public SoundSpecifier PullDownSound = new SoundPathSpecifier("/Audio/Imperial/HamMaggotson/helmet_pulldown.ogg");
🤖 Prompt for AI Agents
In
`@Content.Server/Imperial/HamMaggotson/PullableHelmet/Components/PullableHelmetComponent.cs`
around lines 34 - 37, PullUpSound and PullDownSound are declared as
auto-properties but should be plain fields like other component data; change the
declarations in PullableHelmetComponent so that PullUpSound and PullDownSound
are public fields (retain the [DataField] attribute and the default
SoundPathSpecifier initializers) instead of properties with { get; set; }, e.g.,
update the members on the PullableHelmetComponent class to be public
SoundSpecifier PullUpSound = ... and public SoundSpecifier PullDownSound = ....

Comment on lines +66 to +77
private void TryStartDoAfter(Entity<PullableHelmetComponent> ent, ref PullHelmetActionEvent args)
{
_doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager,
args.Performer,
ent.Comp.Delay,
new PullHelmetDoAfterEvent(),
ent,
ent)
{
NeedHand = true,
});
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Дублирование логики DoAfter между двумя перегрузками TryStartDoAfter.

Строки 53-64 и 66-77 содержат практически идентичную логику создания DoAfterArgs. Можно устранить дублирование, вызвав общую перегрузку из обработчика действия.

Рефакторинг
     private void TryStartDoAfter(Entity<PullableHelmetComponent> ent, ref PullHelmetActionEvent args)
     {
-        _doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager,
-            args.Performer,
-            ent.Comp.Delay,
-            new PullHelmetDoAfterEvent(),
-            ent,
-            ent)
-        {
-            NeedHand = true,
-        });
+        TryStartDoAfter(args.Performer, ent);
     }
🤖 Prompt for AI Agents
In
`@Content.Server/Imperial/HamMaggotson/PullableHelmet/Systems/PullableHelmetSystem.cs`
around lines 66 - 77, Two TryStartDoAfter overloads duplicate building the same
DoAfterArgs; refactor by consolidating the shared DoAfterArgs construction into
a single helper or have one overload call the other. Specifically, centralize
creation of the DoAfterArgs (using EntityManager, args.Performer,
ent.Comp.Delay, new PullHelmetDoAfterEvent(), ent as both target and used, and
NeedHand = true) and then call _doAfter.TryStartDoAfter(...) from that helper so
both TryStartDoAfter(Entity<PullableHelmetComponent>, ref PullHelmetActionEvent)
and the other overload reuse the same logic.

Comment on lines +79 to +101
public void TryToggleHelmet(EntityUid uid, PullableHelmetComponent component, ref PullHelmetDoAfterEvent args)
{
var user = args.User;
if (!_inventory.InSlotWithFlags(uid, component.RequiredFlags))
return;
component.Toggled = !component.Toggled;
var newPrototype = component.Toggled ? component.ToggledPrototype : component.UntoggledPrototype;
var sound = component.Toggled ? component.PullDownSound : component.PullUpSound;
var newEntity = Spawn(newPrototype, Transform(uid).Coordinates);
if (!TryComp<PullableHelmetComponent>(newEntity, out var hlm))
{
QueueDel(newEntity);
return;
}
hlm.Toggled = component.Toggled;
if (_inventory.TryGetContainingSlot(uid, out var slot))
{
_inventory.TryUnequip(user, slot.Name);
_inventory.TryEquip(user, newEntity, slot.Name);
QueueDel(uid);
_audio.PlayPvs(sound, user);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Критично: отсутствует проверка args.Cancelled / args.Handled в обработчике DoAfter.

TryToggleHelmet не проверяет, был ли DoAfter отменён (например, игрок пошевелился). Стандартный паттерн SS14 для обработки DoAfter-событий требует проверки в начале метода. Без этого шлем будет переключаться даже при отмене действия.

Кроме того, если TryGetContainingSlot вернёт false (строка 94), уже заспавненная сущность newEntity не удаляется — утечка сущности. Аналогично, результаты TryUnequip / TryEquip не проверяются — при неудаче возможна потеря или дублирование предмета.

Также метод public — должен быть private для единообразия с остальными обработчиками.

Предлагаемое исправление
-    public void TryToggleHelmet(EntityUid uid, PullableHelmetComponent component, ref PullHelmetDoAfterEvent args)
+    private void TryToggleHelmet(EntityUid uid, PullableHelmetComponent component, ref PullHelmetDoAfterEvent args)
     {
+        if (args.Cancelled || args.Handled)
+            return;
+
+        args.Handled = true;
+
         var user = args.User;
         if (!_inventory.InSlotWithFlags(uid, component.RequiredFlags))
             return;
         component.Toggled = !component.Toggled;
         var newPrototype = component.Toggled ? component.ToggledPrototype : component.UntoggledPrototype;
         var sound = component.Toggled ? component.PullDownSound : component.PullUpSound;
         var newEntity = Spawn(newPrototype, Transform(uid).Coordinates);
         if (!TryComp<PullableHelmetComponent>(newEntity, out var hlm))
         {
             QueueDel(newEntity);
             return;
         }
         hlm.Toggled = component.Toggled;
         if (_inventory.TryGetContainingSlot(uid, out var slot))
         {
-            _inventory.TryUnequip(user, slot.Name);
-            _inventory.TryEquip(user, newEntity, slot.Name);
-            QueueDel(uid);
-            _audio.PlayPvs(sound, user);
+            if (_inventory.TryUnequip(user, slot.Name) &&
+                _inventory.TryEquip(user, newEntity, slot.Name))
+            {
+                QueueDel(uid);
+                _audio.PlayPvs(sound, user);
+            }
+            else
+            {
+                QueueDel(newEntity);
+            }
+        }
+        else
+        {
+            QueueDel(newEntity);
         }
     }
🤖 Prompt for AI Agents
In
`@Content.Server/Imperial/HamMaggotson/PullableHelmet/Systems/PullableHelmetSystem.cs`
around lines 79 - 101, TryToggleHelmet should first check DoAfter results
(args.Cancelled or args.Handled) and return immediately if cancelled/handled,
and then be made private to match other handlers; move the cancelled check to
the top of TryToggleHelmet(PullableHelmetComponent component, ref
PullHelmetDoAfterEvent args). Avoid leaking the spawned entity: only
Spawn(newPrototype, ...) after confirming the DoAfter succeeded or, if you must
spawn earlier, ensure you QueueDel(newEntity) when TryGetContainingSlot returns
false. Also check the boolean results of _inventory.TryUnequip and
_inventory.TryEquip and only call QueueDel(uid) and _audio.PlayPvs(sound, user)
when both succeed; on failure rollback by QueueDel(newEntity) (and do not delete
the original uid). Use the existing symbols: TryToggleHelmet,
PullableHelmetComponent, args.Cancelled/args.Handled, TryGetContainingSlot,
TryUnequip, TryEquip, Spawn, QueueDel, and _audio.PlayPvs.

Comment on lines +35 to +67
- type: entity
id: ClothingHeadHelmetK63Lowered
parent: ClothingHeadHelmetK63
name: fire helmet
categories: [ HideSpawnMenu ]
description: An atmos tech's best friend. Provides some heat resistance and looks cool.
suffix: DeadSector
components:
- type: Sprite
sprite: Imperial/Clothing/Head/Helmets/k6_3_new.rsi
- type: Clothing
sprite: Imperial/Clothing/Head/Helmets/k6_3_new.rsi
quickEquip: true
clothingVisuals:
head:
- state: on-equipped-HELMET
- type: Item
size: Normal
- type: Armor
modifiers:
coefficients:
Blunt: 0.7
Slash: 0.7
Piercing: 0.75
Heat: 0.75
Shock: 0.75
- type: ExplosionResistance
damageCoefficient: 0.5
- type: HideLayerClothing
slots:
- Hair
- HeadTop
- type: IngestionBlocker
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Избыточное дублирование компонентов в ClothingHeadHelmetK63Lowered.

ClothingHeadHelmetK63Lowered наследует от ClothingHeadHelmetK63, но полностью переопределяет Sprite, Clothing, Item, HideLayerClothing с теми же значениями (тот же .rsi, тот же size: Normal, те же скрытые слои). Достаточно указать только отличающиеся компоненты: Clothing (другой state), Armor, ExplosionResistance и IngestionBlocker. Это уменьшит дублирование и упростит поддержку.

Пример минимального определения
 - type: entity
   id: ClothingHeadHelmetK63Lowered
   parent: ClothingHeadHelmetK63
   name: fire helmet
   categories: [ HideSpawnMenu ]
   description: An atmos tech's best friend. Provides some heat resistance and looks cool.
   suffix: DeadSector
   components:
-  - type: Sprite
-    sprite: Imperial/Clothing/Head/Helmets/k6_3_new.rsi
   - type: Clothing
     sprite: Imperial/Clothing/Head/Helmets/k6_3_new.rsi
     quickEquip: true
     clothingVisuals:
       head:
       - state: on-equipped-HELMET
-  - type: Item
-    size: Normal
   - type: Armor
     modifiers:
       coefficients:
         Blunt: 0.7
         Slash: 0.7
         Piercing: 0.75
         Heat: 0.75
         Shock: 0.75
   - type: ExplosionResistance
     damageCoefficient: 0.5
-  - type: HideLayerClothing
-    slots:
-    - Hair
-    - HeadTop
   - type: IngestionBlocker
🤖 Prompt for AI Agents
In `@Resources/Prototypes/Imperial/Clothing/Helmets/k6_3.yml` around lines 35 -
67, ClothingHeadHelmetK63Lowered duplicates parent ClothingHeadHelmetK63's
Sprite, Item and HideLayerClothing components; remove those duplicated component
entries and only declare the components that differ (keep Clothing with its
altered clothingVisuals/head state on-equipped-HELMET, plus Armor,
ExplosionResistance and IngestionBlocker). Ensure the entity still references
parent ClothingHeadHelmetK63 so Sprite, Item (size: Normal) and
HideLayerClothing (Hair, HeadTop) are inherited, and only override Clothing
(clothingVisuals head state) and add the Armor and ExplosionResistance modifiers
as needed.

Comment on lines 69 to +78
- type: entity
id: ToggleK63Helmet
name: Toggle ninja gloves
description: Toggles all glove actions on left click. Includes your doorjack, draining power, stunning enemies and hacking certain computers.
components:
- type: InstantAction
event: !type:ToggleActionEvent {}
event: !type:PullHelmetActionEvent
- type: Action
itemIconStyle: BigItem
useDelay: 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Копипаста из ниндзя-перчаток — некорректные name и description.

name: Toggle ninja gloves и description описывают перчатки ниндзя, а не забрало шлема. Хотя русская локализация (ent-ToggleK63Helmet) перекроет эти значения, англоязычный фоллбэк остаётся абсолютно неправильным. Это будет видно в логах, дебаге и у игроков без RU-локали.

Предлагаемое исправление
 - type: entity
   id: ToggleK63Helmet
-  name: Toggle ninja gloves
-  description: Toggles all glove actions on left click. Includes your doorjack, draining power, stunning enemies and hacking certain computers.
+  name: Toggle helmet visor
+  description: Pull the helmet visor up or down.
   components:
🤖 Prompt for AI Agents
In `@Resources/Prototypes/Imperial/Clothing/Helmets/k6_3.yml` around lines 69 -
78, The YAML entity ToggleK63Helmet has wrong English fallback strings copied
from ninja gloves; update the name and description fields (the "name" and
"description" entries under the ToggleK63Helmet entity) to helmet-appropriate
text (e.g., "Toggle K6-3 Helmet" and a description like "Toggles helmet
functions on left click: doorjack, power drain, stun and certain hacks") so the
English fallback matches the entity behavior triggered by the InstantAction
!type:PullHelmetActionEvent and Action entries; keep the rest of the component
definitions unchanged.

{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "Create by @lune_felix",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Исправьте грамматическую ошибку в поле copyright.

В строке copyright указано "Create by", но должно быть "Created by" для правильной грамматики английского языка.

📝 Предлагаемое исправление
-    "copyright": "Create by `@lune_felix`",
+    "copyright": "Created by `@lune_felix`",
🤖 Prompt for AI Agents
In `@Resources/Textures/Imperial/Clothing/Head/Helmets/k6_3_new_alt.rsi/meta.json`
at line 4, The copyright field value contains a grammatical mistake: change the
string value of the "copyright" property from "Create by `@lune_felix`" to
"Created by `@lune_felix`" so the metadata uses correct English; update the
literal in the meta.json where the "copyright" key is defined.

{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "Create by @lune_felix",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Исправьте грамматическую ошибку в поле copyright.

В строке copyright указано "Create by", но должно быть "Created by" для правильной грамматики английского языка.

📝 Предлагаемое исправление
-    "copyright": "Create by `@lune_felix`",
+    "copyright": "Created by `@lune_felix`",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"copyright": "Create by @lune_felix",
"copyright": "Created by `@lune_felix`",
🤖 Prompt for AI Agents
In `@Resources/Textures/Imperial/Clothing/Head/Helmets/k6_3_new.rsi/meta.json` at
line 4, Update the value of the "copyright" field in the meta.json entry that
currently reads "Create by `@lune_felix`" to the grammatically correct "Created by
`@lune_felix`"; locate the "copyright" key in the meta.json for k6_3_new.rsi and
replace the string accordingly.

@github-actions github-actions bot added the size/Small Насколько сложно будет апстримить label Feb 14, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@Resources/Prototypes/Imperial/Clothing/Helmets/k6_3.yml`:
- Around line 81-113: ClothingHeadHelmetK63Alternate has a different
ExplosionResistance damageCoefficient (0.7) than the base ClothingHeadHelmetK63
(0.75); if both variants should provide the same raised-state protection, update
the ExplosionResistance.damageCoefficient on ClothingHeadHelmetK63Alternate to
match the base (0.75) so the pulled/toggled prototypes are consistent, or adjust
ClothingHeadHelmetK63 instead if the base is wrong—verify and unify the value
for the prototypes referenced by PullableHelmet (ClothingHeadHelmetK63Alternate
and ClothingHeadHelmetK63).
- Around line 115-148: Удалите из определения
ClothingHeadHelmetK63AlternateLowered все компоненты, которые дублируют значения
родителя ClothingHeadHelmetK63Alternate (включая Sprite/Item/HideLayerClothing
если они идентичны родителю), оставив только отличающиеся компоненты: Clothing
(с состоянием on-equipped-HELMET), Armor, ExplosionResistance и
IngestionBlocker; если Sprite действительно отличается только по state (state:
icon-off) — вместо полного удаления оставьте только этот Sprite с state:
icon-off и уберите остальные дубликаты.

Comment on lines +81 to +113
- type: entity
id: ClothingHeadHelmetK63Alternate
parent: ClothingHeadHelmetBase
name: fire helmet
description: An atmos tech's best friend. Provides some heat resistance and looks cool.
suffix: DeadSector
components:
- type: Sprite
sprite: Imperial/Clothing/Head/Helmets/k6_3_new_alt.rsi
- type: Clothing
sprite: Imperial/Clothing/Head/Helmets/k6_3_new_alt.rsi
quickEquip: true
clothingVisuals:
head:
- state: off-equipped-HELMET
- type: Item
size: Normal
- type: Armor
modifiers:
coefficients:
Blunt: 0.7
Slash: 0.7
Piercing: 0.93
- type: ExplosionResistance
damageCoefficient: 0.7
- type: HideLayerClothing
slots:
- Hair
- HeadTop
- type: PullableHelmet
untoggledPrototype: ClothingHeadHelmetK63Alternate
toggledPrototype: ClothingHeadHelmetK63AlternateLowered
pullAction: ToggleK63Helmet
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Альтернативный шлем — структура корректна, но проверьте коэффициент взрывоустойчивости.

У ClothingHeadHelmetK63Alternate damageCoefficient: 0.7 (строка 105), тогда как у базового ClothingHeadHelmetK630.75 (строка 25). Если оба варианта должны быть одинаковыми по защите в поднятом состоянии, значение стоит унифицировать.

🤖 Prompt for AI Agents
In `@Resources/Prototypes/Imperial/Clothing/Helmets/k6_3.yml` around lines 81 -
113, ClothingHeadHelmetK63Alternate has a different ExplosionResistance
damageCoefficient (0.7) than the base ClothingHeadHelmetK63 (0.75); if both
variants should provide the same raised-state protection, update the
ExplosionResistance.damageCoefficient on ClothingHeadHelmetK63Alternate to match
the base (0.75) so the pulled/toggled prototypes are consistent, or adjust
ClothingHeadHelmetK63 instead if the base is wrong—verify and unify the value
for the prototypes referenced by PullableHelmet (ClothingHeadHelmetK63Alternate
and ClothingHeadHelmetK63).

Comment on lines +115 to +148
- type: entity
id: ClothingHeadHelmetK63AlternateLowered
parent: ClothingHeadHelmetK63Alternate
name: fire helmet
categories: [ HideSpawnMenu ]
description: An atmos tech's best friend. Provides some heat resistance and looks cool.
suffix: DeadSector
components:
- type: Sprite
sprite: Imperial/Clothing/Head/Helmets/k6_3_new_alt.rsi
state: icon-off
- type: Clothing
sprite: Imperial/Clothing/Head/Helmets/k6_3_new_alt.rsi
quickEquip: true
clothingVisuals:
head:
- state: on-equipped-HELMET
- type: Item
size: Normal
- type: Armor
modifiers:
coefficients:
Blunt: 0.7
Slash: 0.7
Piercing: 0.75
Heat: 0.75
Shock: 0.75
- type: ExplosionResistance
damageCoefficient: 0.5
- type: HideLayerClothing
slots:
- Hair
- HeadTop
- type: IngestionBlocker
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Та же избыточная дупликация компонентов, что и в ClothingHeadHelmetK63Lowered.

ClothingHeadHelmetK63AlternateLowered наследует от ClothingHeadHelmetK63Alternate, но повторяет Sprite, Item, HideLayerClothing с идентичными значениями родителя. Оставьте только отличающиеся компоненты: Clothingon-equipped-HELMET), Armor, ExplosionResistance и IngestionBlocker.

Минимальное определение
 - type: entity
   id: ClothingHeadHelmetK63AlternateLowered
   parent: ClothingHeadHelmetK63Alternate
   name: fire helmet
   categories: [ HideSpawnMenu ]
   description: An atmos tech's best friend. Provides some heat resistance and looks cool.
   suffix: DeadSector
   components:
-  - type: Sprite
-    sprite: Imperial/Clothing/Head/Helmets/k6_3_new_alt.rsi
-    state: icon-off
   - type: Clothing
     sprite: Imperial/Clothing/Head/Helmets/k6_3_new_alt.rsi
     quickEquip: true
     clothingVisuals:
       head:
       - state: on-equipped-HELMET
-  - type: Item
-    size: Normal
   - type: Armor
     modifiers:
       coefficients:
         Blunt: 0.7
         Slash: 0.7
         Piercing: 0.75
         Heat: 0.75
         Shock: 0.75
   - type: ExplosionResistance
     damageCoefficient: 0.5
-  - type: HideLayerClothing
-    slots:
-    - Hair
-    - HeadTop
   - type: IngestionBlocker

Примечание: Sprite с state: icon-off может отличаться от родителя (у родителя нет явного state). Если это так, оставьте только Sprite с state: icon-off, убрав остальные дублирующиеся компоненты.

🤖 Prompt for AI Agents
In `@Resources/Prototypes/Imperial/Clothing/Helmets/k6_3.yml` around lines 115 -
148, Удалите из определения ClothingHeadHelmetK63AlternateLowered все
компоненты, которые дублируют значения родителя ClothingHeadHelmetK63Alternate
(включая Sprite/Item/HideLayerClothing если они идентичны родителю), оставив
только отличающиеся компоненты: Clothing (с состоянием on-equipped-HELMET),
Armor, ExplosionResistance и IngestionBlocker; если Sprite действительно
отличается только по state (state: icon-off) — вместо полного удаления оставьте
только этот Sprite с state: icon-off и уберите остальные дубликаты.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Audio Изменения добавляют ogg C# Изменения добавляют новый C# код Change Wiz Code Изменения вмешиваются в код визардов Change WIz Prototypes Изменения вмешиваются в код прототипов визардов Prototypes Изменения добавляет новые прототипы Resprite Изменения заменяют оригинальные текстуры визардов size/Small Насколько сложно будет апстримить Sprite Изменения добавляют спрайты

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant