Skip to content

Чудо-Юдо. Новый монстр Недр. H/M#613

Open
Maggotson wants to merge 6 commits into
imperial-space:developfrom
Maggotson:vending
Open

Чудо-Юдо. Новый монстр Недр. H/M#613
Maggotson wants to merge 6 commits into
imperial-space:developfrom
Maggotson:vending

Conversation

@Maggotson

@Maggotson Maggotson commented Apr 7, 2026

Copy link
Copy Markdown
Contributor

О ПР`е

Тип: feat

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

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

Нет

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

Нет

Summary by CodeRabbit

Изменения в релизе

  • Новые функции
    • Добавлено новое SCP существо "Nothing There" с системой фаз и способностями захвата тел
    • Реализованы боевые механики, включая музыку преследования и трансформации
    • Добавлены новые действия: вселение в тело, превращение в яйцо, упрощение и призыв проектилей
    • Введены новые косметические предметы: плащи Nedra для кастомизации персонажа

@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 Apr 7, 2026
@Maggotson Maggotson changed the title Чудо-Юдо. H/M Чудо-Юдо. Новый монстр Недр. H/M Apr 7, 2026
@coderabbitai

coderabbitai Bot commented Apr 7, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Добавлена новая серверная система для сущности SCP "NothingThere" с поддержкой множественных механик. Реализованы компоненты для управления телом, трансформации в яйцо и осадок (empower), включая отслеживание убийств и звукового сопровождения. Система включает обработку действий игроков (вход в тело, трансформация, боевые манипуляции), управление состоянием сущности через фазы, спаренную карту для временного захвата, и интеграцию с системой ума (mind transfer). Добавлены прототипы сущностей, действий, оружия и локализации на русском языке.

Sequence Diagram(s)

sequenceDiagram
    participant Player as Игрок/Исполнитель
    participant NothingThere as Система NothingThere
    participant Target as Цель (Мобиль)
    participant Mind as Система Ума
    participant PausedMap as Приостановленная Карта

    Player->>NothingThere: Активирует "Вход в Тело"
    NothingThere->>NothingThere: Проверяет валидность цели<br/>(не ротт, гуманоид, мёртв)
    NothingThere->>Player: Начало DoAfter (EnterBodyWindUp)
    Player-->>NothingThere: DoAfter завершён
    
    NothingThere->>Mind: Переносит ум игрока на цель
    NothingThere->>Target: Переводит в MobState.Alive
    NothingThere->>NothingThere: Обновляет пороги урона мобили
    NothingThere->>PausedMap: Переводит исходное тело на карту
    NothingThere->>NothingThere: Останавливает музыку преследования
Loading
sequenceDiagram
    participant NothingThere as Сущность NothingThere
    participant System as Система
    participant Audio as Аудиосистема
    participant Map as Система Карт

    Note over NothingThere: Phase 0: Инициализация
    NothingThere->>System: MapInitEvent
    System->>NothingThere: Регистрирует действия (Enter, Egg, Projectile)
    
    Note over NothingThere: Phase 1: Трансформация Яйца
    System->>System: Ждёт EggTransformEnd
    System->>NothingThere: Полиморфизм в TrueMorph
    System->>Audio: Воспроизводит HatchSound
    
    Note over NothingThere: Phase 2: Усиление (Empower)
    NothingThere->>System: Игрок активирует действие Goodbye
    System->>NothingThere: Выдаёт оружие (GoodbyeProto/HitProto)
    NothingThere->>Audio: Звук усиления при использовании
    System->>NothingThere: Переводит NeedItems = false
Loading
sequenceDiagram
    participant ControlledBody as Контролируемое Тело
    participant NothingThere as Система NothingThere
    participant Audio as Аудиосистема
    participant Destructible as Система Разрушения
    participant MindSystem as Система Ума

    ControlledBody->>ControlledBody: Переходит в Dead/Critical
    NothingThere->>MindSystem: Восстанавливает ум на OriginalBody
    NothingThere->>Audio: Воспроизводит ExitSound
    NothingThere->>Destructible: Вызывает Gib()
    Destructible->>Destructible: Удаляет сущность
    Destructible->>Audio: Звук гибели
    NothingThere->>NothingThere: Синхронизирует KillCount
    NothingThere->>Audio: Перезапускает музыку преследования
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Ивент контент #416: Модифицирует файл русской локализации Resources/Locale/ru-RU/Imperial/Seriozha/SCP/locale.ftl и добавляет новые записи для пользовательской одежды Seriozha, пересекаясь с локализацией в данном PR.
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

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.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Заголовок полностью соответствует основным изменениям в PR: добавлен новый монстр 'Nothing There' для контента Недр (Imperial SCP), что полностью отражает представленный набор изменений.

✏️ 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.

@github-actions github-actions Bot added the size/Small Насколько сложно будет апстримить label Apr 7, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 22

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@Content.Server/Imperial/SCP/NothingThere/Components/ImperialControlledNothingThereComponent.cs`:
- Around line 19-23: OriginalBody and KillCount are runtime-only state but are
currently marked with [DataField]; remove the [DataField] attributes and instead
annotate these fields with [ViewVariables] (e.g., [ViewVariables] or
[ViewVariables(VVAccess.ReadWrite)] as appropriate) in the
ImperialControlledNothingThereComponent so they are visible/editable in VV and
not treated as prototype-configured values; keep their runtime defaults
(OriginalBody = EntityUid.Invalid, KillCount = 0) and leave ExitSound as the
DataField-configured prototype value.

In
`@Content.Server/Imperial/SCP/NothingThere/Components/ImperialNothingThereComponent.cs`:
- Line 59: Поля runtime-состояния в компоненте ImperialNothingThereComponent
(`Empowered` и `NeedGoodbye`) не помечены атрибутом [ViewVariables]; добавьте
атрибут [ViewVariables] над определениями этих полей в классе
ImperialNothingThereComponent, чтобы они были видимы в отладке/инспекторах
(оставьте типы и имена полей без изменений).
- Line 43: Поля компонента ImperialNothingThereComponent — EggEntityProto,
TrueEntityProto, GoodbyeProto и HitProto — содержат идентификаторы прототипов,
но не помечены атрибутом [DataField], из‑за чего их нельзя переопределить через
YAML; откройте класс ImperialNothingThereComponent и добавить атрибут
[DataField] к каждому из этих полей (если их нужно конфигурировать из
прототипов), либо — если пропи́сно намеренно неизменяемо — пометить их
[ViewVariables] для отладки; убедитесь, что имена полей в [DataField("...")]
соответствуют ожидаемым YAML-ключам и что типы (EntProtoId?) остаются без
изменений.
- Around line 8-9: Файл содержит неиспользуемые директивы using: remove the
unused imports Content.Shared.Mobs.Systems and Content.Shared.Mobs from the top
of the ImperialNothingThereComponent file; locate the
ImperialNothingThereComponent class in the
Content.Server.Imperial.SCP.NothingThere.Components namespace and delete the two
using lines (using Content.Shared.Mobs.Systems; and using Content.Shared.Mobs;)
so only required namespaces remain.

In
`@Content.Server/Imperial/SCP/NothingThere/Components/ImperialNothingThereGoodbyeComponent.cs`:
- Around line 6-10: The field Used is a runtime-only flag and should not be a
prototype-configured DataField: remove the [DataField] attribute from Used and
mark it with [ViewVariables] instead; conversely ensure HitProto (EntProtoId
HitProto = "ImperialNothingThereHit") is marked with [DataField] (e.g.
[DataField("hitProto")]) so it’s serializable from YAML; leave EmpowerSound
as-is. Modify these attributes on the ImperialNothingThereGoodbyeComponent to
separate runtime state (Used) from prototype-configurable fields (HitProto,
EmpowerSound).

In
`@Content.Server/Imperial/SCP/NothingThere/Systems/ImperialNothingThere.ChaseMusic.cs`:
- Around line 27-33: The component currently sets comp.IsPlaying = true
unconditionally even if _audio.PlayPvs(...) returns null; change the logic so
you first call _audio.PlayPvs(comp.ChaseSound, uid,
AudioParams.Default.WithLoop(true)) and assign its ?.Entity to
comp.PlayingStream, then only set comp.IsPlaying = true if comp.PlayingStream is
not null (otherwise leave/set comp.IsPlaying = false) so failed PlayPvs attempts
don't mark the component as playing and prevent future retries.

In
`@Content.Server/Imperial/SCP/NothingThere/Systems/ImperialNothingThereSystem.Arsenal.cs`:
- Around line 96-104: The handler continues executing when
TryComp<HandsComponent>(args.User, out var hands) fails; after setting
args.Handled = true you must return to avoid using null/uninitialized hands in
_hands.GetActiveHand and the Timer callback. Modify the block around TryComp so
that when it returns false you set args.Handled = true and immediately return
from the method (ensuring the if has braces or an explicit return), leaving the
subsequent calls to _audio.PlayPvs, comp.Used, _hands.GetActiveHand, Timer.Spawn
and _hands.DoDrop only reachable when hands is present.
- Around line 60-65: Привяжите do-after к изначальному предмету и руке: при
создании DoAfterArgs (в месте с вызовом new DoAfterArgs(...)) установите
NeedHand = true и передайте туда текущий активный предмет/руку (например
сохраните var initItem = GetActiveItem() и передайте его в поле/параметр
DoAfterArgs, либо используйте доступное поле для Used/TargetEntity), затем в
обработчике OnGoodbyeDoAfter используйте переданный в args объект (а не повторно
вызывать GetActiveItem()) и добавьте безопасную проверку handd на null/valid
перед использова­нием/удалением предмета.
- Around line 34-49: The code clears comp.NeedGoodbye before attempting pickup
so a failed TryForcePickup causes the goodbye to be lost; move the mutation so
NeedGoodbye is only set to false after a successful pickup. In
ImperialNothingThereSystem.Arsenal (look for the spawn/try-pickup block using
Spawn, Transform(uid).Coordinates, _hands.TryForcePickup, hit, comp.NeedGoodbye
and comp.NeedItems), only set comp.NeedGoodbye = false inside the branch taken
when TryForcePickup returns true (and keep QueueDel/return behavior on failure),
and ensure comp.NeedItems is updated consistently after success.

In
`@Content.Server/Imperial/SCP/NothingThere/Systems/ImperialNothingThereSystem.BodyControl.cs`:
- Around line 112-118: The code currently drops all items via
TryComp<HandsComponent> and _hands.TryDrop(...) then calls
RemComp<HandsComponent>(target), which can break other systems expecting the
component; instead stop removing the component: in the block that finds
HandsComponent (via TryComp<HandsComponent>(target, out var hands)) drop each
held item using _hands.TryDrop((target, hands), hand) but do not call
RemComp<HandsComponent>(target); if you need to reset state, clear or reset the
hands collection on the found HandsComponent instance (e.g., empty or set a
disabled flag) rather than removing the component so other systems still see a
valid HandsComponent.
- Line 100: The code sets var target = args.Target ?? EntityUid.Invalid and then
proceeds to call TryComp/EnsureComp on that invalid ID; add an early
null/invalid check for args.Target to avoid operating on EntityUid.Invalid.
Inside the method in ImperialNothingThereSystem (BodyControl logic), if
args.Target is null or target == EntityUid.Invalid return immediately (or skip
the rest of the handling) before calling TryComp, EnsureComp, or any component
operations on target. Ensure the check references args.Target and the local
variable target so subsequent code is only executed for a valid EntityUid.
- Around line 165-189: The Gib method raises GibbedBeforeDeletionEvent but never
actually deletes the entity, which breaks subscribers that expect the entity to
be removed (e.g., TransferMindOnGibSystem, ForensicsSystem, ImplantedSystem).
Modify Gib (method name Gib, parameter ent) to raise BeingGibbedEvent and
GibbedBeforeDeletionEvent before performing the final deletion, then delete the
entity (e.g., call the project's delete method such as
EntityManager.DeleteEntity(ent) or the appropriate _destructible/_entityManager
delete method) after RaiseLocalEvent(ent, ref beforeDeletion) so subscribers run
with the entity still present but it is removed immediately afterwards.
- Line 123: The expression uses the null-coalescing operator with the wrong
precedence so `??` never triggers: change the assignment of nddde to either add
parentheses around the coalescing operation like var nddde = ddde +
(comp.Threshold ?? FixedPoint2.New(400.0f)); or, if the intent is that Threshold
be nullable, make comp.Threshold a nullable FixedPoint2? and then use the same
parenthesized expression (ddde + (comp.Threshold ?? FixedPoint2.New(400.0f))) to
ensure the default is applied when Threshold is null.
- Around line 143-164: OnControlledMobStateChanged uses comp.OriginalBody
without validating it; if OriginalBody is EntityUid.Invalid the calls to
Transform(newb) and subsequent ops will fail. Fix by early-returning (or
aborting the death/transfer logic) when comp.OriginalBody is invalid: check
ImperialControlledNothingThereComponent.OriginalBody at start of the death
branch in OnControlledMobStateChanged and only call Transform(newb),
_transform.SetParent/_transform.SetCoordinates, _mind.TransferTo,
_audio.PlayPvs, Gib, and TryComp(...) when OriginalBody is a valid EntityUid;
otherwise skip those steps (or queue cleanup) to avoid operating on an invalid
entity.

In
`@Content.Server/Imperial/SCP/NothingThere/Systems/ImperialNothingThereSystem.Egg.cs`:
- Around line 52-53: PolymorphEntity может вернуть EntityUid.Invalid, но код
всегда вызывает _audio.PlayPvs(egg.HatchSound, newb); — добавьте проверку на
валидность после вызова PolymorphEntity: var newb =
_polymorph.PolymorphEntity(entity, egg.TrueMorph) ?? EntityUid.Invalid; if (newb
== EntityUid.Invalid) return; // либо пропустить воспроизведение и дальнейшие
шаги; иначе вызовите _audio.PlayPvs(egg.HatchSound, newb). Это предотвратит
попытки проигрывать звук на невалидном uid и повторные срабатывания в апдейте.

In
`@Content.Server/Imperial/SCP/NothingThere/Systems/ImperialNothingThereSystem.PausedMap.cs`:
- Around line 14-20: В обработчике OnRoundRestart, после вызова
Del(PausedMap.Value) явно сбросьте свойство PausedMap в null, чтобы избежать
хранения удалённого EntityUid; то есть в методе OnRoundRestart (работающем с
PausedMap и проверяющем Exists) после удаления сущности вызвать присвоение
PausedMap = null, чтобы состояние было предсказуемым и EnsurePausedMap не
полагался только на Exists.

In
`@Content.Shared/Imperial/SCP/NothingThere/Events/ImperialNothingThereGoodbyeDoAfterEvent.cs`:
- Around line 8-13: Remove the redundant empty constructor and the unnecessary
override of Clone() in the ImperialNothingThereGoodbyeDoAfterEvent class: delete
the explicit parameterless constructor and the public override DoAfterEvent
Clone() => this; method so the class uses the compiler-generated constructor and
the base SimpleDoAfterEvent.Clone implementation.

In `@Resources/Locale/ru-RU/Imperial/SCP/dimensionenteraction.ftl`:
- Line 6: В строке ключа nothingthere-hammaggotson-haha исправьте незакрытые
форматирующие теги: корректно закройте вложенные теги в обратном порядке их
открытия (например добавьте недостающие [/bold], затем [/font], затем [/color]
или соответствующие закрывающие теги), чтобы все открытые [color=red], [font
size=14], [bold] были закрыты.

In `@Resources/Locale/ru-RU/Imperial/Seriozha/SCP/locale.ftl`:
- Line 198: В описании локали для ent-CloakNDAWhite (ключ .desc в locale.ftl)
исправьте опечатку и формулировку: заменить «Ауидо» на «аудио» и «Для удобности»
на «Для удобства», т.е. обновить значение .desc соответствующего объекта
(ent-CloakNDAWhite) на корректную фразу с этими правками.

In `@Resources/Prototypes/Imperial/SCP/Actions/nothingthere.yml`:
- Around line 1-12: The action ImperialNothingThereEnterBodyAction is missing
parent: BaseAction causing it to not inherit default components; add parent:
BaseAction to the ImperialNothingThereEnterBodyAction YAML entry so it matches
ImperialNothingThereGibBodyAction, ImperialNothingThereEggAction and
ImperialNothingThereHelloAction, then verify that any required base components
(e.g., Action, TargetAction, EntityTargetAction) are not duplicated or
contradicted after inheritance and adjust/remove explicit component declarations
if they conflict with BaseAction defaults.
- Around line 52-68: The entity ImperialNothingThereProjectileAction is missing
inheritance from BaseAction; update the entity definition for
ImperialNothingThereProjectileAction to include a parent: BaseAction entry
(matching other actions in the file) so it inherits base action behavior while
keeping its existing components (Action, TargetAction, WorldTargetAction)
intact.

In `@Resources/Prototypes/Imperial/Seriozha/misc/misc.yml`:
- Around line 50-68: Вынести общие поля для CloakNDADelexor и CloakNDAWhite в
общий абстрактный parent: создайте новый прототип (например CloakNDABase) с
parent: ClothingNeckBase и общими полями name, suffix, description и общим
components-секцией за исключением уникального sprite; затем обновите
CloakNDADelexor и CloakNDAWhite чтобы они наследовали от CloakNDABase и
оставляли только id и уникальный Sprite (sprite:
Imperial/Seriozha/misc/Customization/nda_cloak.rsi и sprite:
Imperial/Seriozha/misc/Customization/white_cloak.rsi соответственно).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 3d22ef9c-2d1e-416b-bf57-8c912e0e87d3

📥 Commits

Reviewing files that changed from the base of the PR and between 1e331b5 and f654429.

⛔ Files ignored due to path filters (32)
  • Resources/Audio/Imperial/SCP/nothingthere_empower.ogg is excluded by !**/*.ogg
  • Resources/Audio/Imperial/SCP/nothingthere_enter.ogg is excluded by !**/*.ogg
  • Resources/Audio/Imperial/SCP/nothingthere_gibbody.ogg is excluded by !**/*.ogg
  • Resources/Audio/Imperial/SCP/nothingthere_goodbyehit.ogg is excluded by !**/*.ogg
  • Resources/Audio/Imperial/SCP/nothingthere_hatch.ogg is excluded by !**/*.ogg
  • Resources/Audio/Imperial/SCP/nothingthere_heartbeat.ogg is excluded by !**/*.ogg
  • Resources/Audio/Imperial/SCP/nothingthere_hello.ogg is excluded by !**/*.ogg
  • Resources/Audio/Imperial/SCP/nothingthere_idle.ogg is excluded by !**/*.ogg
  • Resources/Audio/Imperial/SCP/nothingthere_idle_true.ogg is excluded by !**/*.ogg
  • Resources/Audio/Imperial/SCP/nothingthere_projectile.ogg is excluded by !**/*.ogg
  • Resources/Audio/Imperial/SCP/nothingthere_punch1.ogg is excluded by !**/*.ogg
  • Resources/Audio/Imperial/SCP/nothingthere_punch2.ogg is excluded by !**/*.ogg
  • Resources/Audio/Imperial/SCP/nothingthere_run1.ogg is excluded by !**/*.ogg
  • Resources/Audio/Imperial/SCP/nothingthere_run2.ogg is excluded by !**/*.ogg
  • Resources/Audio/Imperial/SCP/nothingthere_scream.ogg is excluded by !**/*.ogg
  • Resources/Textures/Imperial/SCP/nothingthere1.rsi/jared.png is excluded by !**/*.png
  • Resources/Textures/Imperial/SCP/nothingthere2.rsi/jared.png is excluded by !**/*.png
  • Resources/Textures/Imperial/SCP/nothingthere2.rsi/jared2.png is excluded by !**/*.png
  • Resources/Textures/Imperial/SCP/nothingthereegg.rsi/icon.png is excluded by !**/*.png
  • Resources/Textures/Imperial/SCP/nothingtherewpn1.rsi/icon.png is excluded by !**/*.png
  • Resources/Textures/Imperial/SCP/nothingtherewpn1.rsi/inhand-left.png is excluded by !**/*.png
  • Resources/Textures/Imperial/SCP/nothingtherewpn1.rsi/inhand-right.png is excluded by !**/*.png
  • Resources/Textures/Imperial/SCP/nothingtherewpn2.rsi/icon.png is excluded by !**/*.png
  • Resources/Textures/Imperial/SCP/nothingtherewpn2.rsi/inhand-left.png is excluded by !**/*.png
  • Resources/Textures/Imperial/SCP/nothingtherewpn2.rsi/inhand-right.png is excluded by !**/*.png
  • Resources/Textures/Imperial/SCP/nothingtherewpn2.rsi/jared.png is excluded by !**/*.png
  • Resources/Textures/Imperial/Seriozha/misc/Customization/nda_cloak.rsi/equipped-NECK.png is excluded by !**/*.png
  • Resources/Textures/Imperial/Seriozha/misc/Customization/nda_cloak.rsi/icon.png is excluded by !**/*.png
  • Resources/Textures/Imperial/Seriozha/misc/Customization/violet_cloak.rsi/equipped-NECK.png is excluded by !**/*.png
  • Resources/Textures/Imperial/Seriozha/misc/Customization/violet_cloak.rsi/icon.png is excluded by !**/*.png
  • Resources/Textures/Imperial/Seriozha/misc/Customization/white_cloak.rsi/equipped-NECK.png is excluded by !**/*.png
  • Resources/Textures/Imperial/Seriozha/misc/Customization/white_cloak.rsi/icon.png is excluded by !**/*.png
📒 Files selected for processing (31)
  • Content.Server/Imperial/SCP/NothingThere/Components/ImperialControlledNothingThereComponent.cs
  • Content.Server/Imperial/SCP/NothingThere/Components/ImperialNothingThereComponent.cs
  • Content.Server/Imperial/SCP/NothingThere/Components/ImperialNothingThereGoodbyeComponent.cs
  • Content.Server/Imperial/SCP/NothingThere/Systems/ImperialNothingThere.ChaseMusic.cs
  • Content.Server/Imperial/SCP/NothingThere/Systems/ImperialNothingThereSystem.Arsenal.cs
  • Content.Server/Imperial/SCP/NothingThere/Systems/ImperialNothingThereSystem.BodyControl.cs
  • Content.Server/Imperial/SCP/NothingThere/Systems/ImperialNothingThereSystem.Egg.cs
  • Content.Server/Imperial/SCP/NothingThere/Systems/ImperialNothingThereSystem.PausedMap.cs
  • Content.Server/Imperial/SCP/NothingThere/Systems/ImperialNothingThereSystem.cs
  • Content.Shared/Imperial/SCP/NothingThere/Events/ImperialNothingThereEggEvent.cs
  • Content.Shared/Imperial/SCP/NothingThere/Events/ImperialNothingThereEnterBodyEvent.cs
  • Content.Shared/Imperial/SCP/NothingThere/Events/ImperialNothingThereGibBodyEvent.cs
  • Content.Shared/Imperial/SCP/NothingThere/Events/ImperialNothingThereGoodbyeDoAfterEvent.cs
  • Resources/Locale/ru-RU/Imperial/SCP/actions.ftl
  • Resources/Locale/ru-RU/Imperial/SCP/dimensionenteraction.ftl
  • Resources/Locale/ru-RU/Imperial/SCP/entities.ftl
  • Resources/Locale/ru-RU/Imperial/SCP/popup.ftl
  • Resources/Locale/ru-RU/Imperial/Seriozha/SCP/locale.ftl
  • Resources/Prototypes/Imperial/SCP/Actions/nothingthere.yml
  • Resources/Prototypes/Imperial/SCP/Entities/nothingthere.yml
  • Resources/Prototypes/Imperial/SCP/Entities/weapon.yml
  • Resources/Prototypes/Imperial/SCP/Misc/nothingtherepolymorph.yml
  • Resources/Prototypes/Imperial/Seriozha/misc/misc.yml
  • Resources/Textures/Imperial/SCP/nothingthere1.rsi/meta.json
  • Resources/Textures/Imperial/SCP/nothingthere2.rsi/meta.json
  • Resources/Textures/Imperial/SCP/nothingthereegg.rsi/meta.json
  • Resources/Textures/Imperial/SCP/nothingtherewpn1.rsi/meta.json
  • Resources/Textures/Imperial/SCP/nothingtherewpn2.rsi/meta.json
  • Resources/Textures/Imperial/Seriozha/misc/Customization/nda_cloak.rsi/meta.json
  • Resources/Textures/Imperial/Seriozha/misc/Customization/violet_cloak.rsi/meta.json
  • Resources/Textures/Imperial/Seriozha/misc/Customization/white_cloak.rsi/meta.json

Comment on lines +19 to +23
public EntityUid OriginalBody = EntityUid.Invalid;
[DataField("exitSound")]
public SoundSpecifier ExitSound = new SoundPathSpecifier("/Audio/Imperial/SCP/nothingthere_gibbody.ogg");
[DataField("killCount")]
public int KillCount = 0;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Не храните runtime-состояние как prototype-конфиг.

По текущему использованию OriginalBody и KillCount меняются только в рантайме. Лучше пометить их как runtime-поля для VV, иначе KillCount можно случайно зашить в YAML, а OriginalBody вообще не видно при отладке.

Based on learnings: In the Imperial SS14 project, fields of components that are not configured via YAML prototypes (runtime state) should be marked with the [ViewVariables] attribute, while fields configured via prototypes should use [DataField].

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@Content.Server/Imperial/SCP/NothingThere/Components/ImperialControlledNothingThereComponent.cs`
around lines 19 - 23, OriginalBody and KillCount are runtime-only state but are
currently marked with [DataField]; remove the [DataField] attributes and instead
annotate these fields with [ViewVariables] (e.g., [ViewVariables] or
[ViewVariables(VVAccess.ReadWrite)] as appropriate) in the
ImperialControlledNothingThereComponent so they are visible/editable in VV and
not treated as prototype-configured values; keep their runtime defaults
(OriginalBody = EntityUid.Invalid, KillCount = 0) and leave ExitSound as the
DataField-configured prototype value.

Comment on lines +8 to +9
using Content.Shared.Mobs.Systems;
using Content.Shared.Mobs;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Неиспользуемые директивы using.

Content.Shared.Mobs.Systems и Content.Shared.Mobs импортированы, но типы из них не используются в этом файле компонента. Рекомендуется удалить неиспользуемые импорты.

♻️ Предлагаемое исправление
-using Content.Shared.Mobs.Systems;
-using Content.Shared.Mobs;
📝 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.Mobs.Systems;
using Content.Shared.Mobs;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@Content.Server/Imperial/SCP/NothingThere/Components/ImperialNothingThereComponent.cs`
around lines 8 - 9, Файл содержит неиспользуемые директивы using: remove the
unused imports Content.Shared.Mobs.Systems and Content.Shared.Mobs from the top
of the ImperialNothingThereComponent file; locate the
ImperialNothingThereComponent class in the
Content.Server.Imperial.SCP.NothingThere.Components namespace and delete the two
using lines (using Content.Shared.Mobs.Systems; and using Content.Shared.Mobs;)
so only required namespaces remain.


[DataField("phase")]
public int Phase = 0;
public EntProtoId? EggEntityProto = "ImperialSCPNothingThereEgg";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Отсутствуют атрибуты [DataField] для полей с прототипами.

Поля EggEntityProto, TrueEntityProto, GoodbyeProto и HitProto содержат идентификаторы прототипов, но не имеют атрибута [DataField]. Это означает, что их нельзя переопределить через YAML конфигурацию. Если это намеренно — добавьте [ViewVariables] для отладки, иначе добавьте [DataField].

Based on learnings: "fields configured via prototypes should use [DataField]".

♻️ Предлагаемое исправление
-public EntProtoId? EggEntityProto = "ImperialSCPNothingThereEgg";
+[DataField("eggEntityProto")]
+public EntProtoId? EggEntityProto = "ImperialSCPNothingThereEgg";
-public EntProtoId? TrueEntityProto = "ImperialSCPNothingThereTrue";
+[DataField("trueEntityProto")]
+public EntProtoId? TrueEntityProto = "ImperialSCPNothingThereTrue";
-public EntProtoId GoodbyeProto = "ImperialNothingThereEmpowerHit";
+[DataField("goodbyeProto")]
+public EntProtoId GoodbyeProto = "ImperialNothingThereEmpowerHit";
-public EntProtoId HitProto = "ImperialNothingThereHit";
+[DataField("hitProto")]
+public EntProtoId HitProto = "ImperialNothingThereHit";

Also applies to: 55-55, 74-75

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@Content.Server/Imperial/SCP/NothingThere/Components/ImperialNothingThereComponent.cs`
at line 43, Поля компонента ImperialNothingThereComponent — EggEntityProto,
TrueEntityProto, GoodbyeProto и HitProto — содержат идентификаторы прототипов,
но не помечены атрибутом [DataField], из‑за чего их нельзя переопределить через
YAML; откройте класс ImperialNothingThereComponent и добавить атрибут
[DataField] к каждому из этих полей (если их нужно конфигурировать из
прототипов), либо — если пропи́сно намеренно неизменяемо — пометить их
[ViewVariables] для отладки; убедитесь, что имена полей в [DataField("...")]
соответствуют ожидаемым YAML-ключам и что типы (EntProtoId?) остаются без
изменений.

[DataField("hatchSound")]
public SoundSpecifier HatchSound = new SoundPathSpecifier("/Audio/Imperial/SCP/nothingthere_hatch.ogg");

public bool Empowered = false;

@coderabbitai coderabbitai Bot Apr 7, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Отсутствуют атрибуты [ViewVariables] для runtime-состояния.

Поля Empowered и NeedGoodbye являются runtime-состоянием (не конфигурируются через YAML), но не имеют атрибута [ViewVariables]. Согласно практикам проекта, runtime state должен быть помечен [ViewVariables] для удобства отладки.

Based on learnings: "fields of components that are not configured via YAML prototypes (runtime state) should be marked with the [ViewVariables] attribute".

♻️ Предлагаемое исправление
-public bool Empowered = false;
+[ViewVariables]
+public bool Empowered = false;
-public bool NeedGoodbye = false;
+[ViewVariables]
+public bool NeedGoodbye = false;

Also applies to: 78-78

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@Content.Server/Imperial/SCP/NothingThere/Components/ImperialNothingThereComponent.cs`
at line 59, Поля runtime-состояния в компоненте ImperialNothingThereComponent
(`Empowered` и `NeedGoodbye`) не помечены атрибутом [ViewVariables]; добавьте
атрибут [ViewVariables] над определениями этих полей в классе
ImperialNothingThereComponent, чтобы они были видимы в отладке/инспекторах
(оставьте типы и имена полей без изменений).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Добавьте либо атрибут ViewVariables, либо DataField

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "=== Snippet (1..200) with line numbers ==="
nl -ba Content.Server/Imperial/SCP/NothingThere/Components/ImperialNothingThereComponent.cs | sed -n '1,200p'

echo
echo "=== Grep for target fields (with context) ==="
rg -n -C2 $'\\b(Empowered|NeedGoodbye)\\b' -- Content.Server/Imperial/SCP/NothingThere/Components/ImperialNothingThereComponent.cs || true

Length of output: 84


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

file='Content.Server/Imperial/SCP/NothingThere/Components/ImperialNothingThereComponent.cs'

echo "=== File exists? ==="
if [[ -f "$file" ]]; then
  echo "yes: $file"
else
  echo "no: $file"
  exit 0
fi

echo
echo "=== Content with line numbers (1..240) ==="
# Use awk to add line numbers (nl may not be available)
awk '{printf "%6d  %s\n", NR, $0}' "$file" | sed -n '1,240p'

echo
echo "=== Locate Empowered / NeedGoodbye declarations (with 3 lines context) ==="
if command -v rg >/dev/null 2>&1; then
  rg -n -C3 $'\\b(Empowered|NeedGoodbye)\\b' -- "$file" || true
else
  grep -nE -C3 '\b(Empowered|NeedGoodbye)\b' "$file" || true
fi

echo
echo "=== Search prototypes for empowered/needgoodbye keys to detect YAML-configurability ==="
if command -v rg >/dev/null 2>&1; then
  rg -n -i --glob 'Resources/Prototypes/**' -- $'\\b(empowered|needgoodbye)\\b' || true
else
  grep -RInEi '\b(empowered|needgoodbye)\b' Resources/Prototypes || true
fi

Length of output: 5538


@The-Fiafi спасибо! Подтвердил по коду и прототипам:

  • Line 59: Empowered — без атрибута.
  • Line 78: NeedGoodbye — без атрибута.
  • В Resources/Prototypes/** нет ключей empowered/needgoodbye для этого компонента (нашлись только «empowered burger», не относящиеся к SCP).

С учётом ранее зафиксированного правила проекта (runtime поля помечаем [ViewVariables]), предлагаю добавить [ViewVariables] к обоим полям.

Минимальное исправление: отметить runtime‑поля [ViewVariables].

Если хотите сделать их настраиваемыми из YAML, скажите — заменю на [DataField("empowered")] и [DataField("needGoodbye")] (или добавлю их вдобавок к [ViewVariables], как уже сделано для EmpowerDamage).


🧠 Learnings used
Learnt from: The-Fiafi
Repo: imperial-space/SS14-public PR: 531
File: Content.Server/Imperial/SCP/ChaseMusic/Components/ImperialSCPChaseMusicComponent.cs:14-16
Timestamp: 2026-01-24T12:55:23.032Z
Learning: In the Imperial SS14 project, fields of components that are not configured via YAML prototypes (runtime state) should be marked with the [ViewVariables] attribute, while fields configured via prototypes should use [DataField]. This guideline applies to all C# component files under Content.Server; review each field to determine whether it’s prototype-configured and assign the appropriate attribute accordingly.

Learnt from: The-Fiafi
Repo: imperial-space/SS14-public PR: 545
File: Content.Server/Imperial/XxRaay/Systems/AnimatronicTargetSystem.cs:21-21
Timestamp: 2026-02-01T14:57:29.328Z
Learning: Enforce C# private field naming: all private fields must start with an underscore and use camelCase (e.g., _transformSystem). This rule applies across the repository (imperial-space/SS14-public) to maintain consistency in all C# files.

Learnt from: The-Fiafi
Repo: imperial-space/SS14-public PR: 565
File: Content.Server/Imperial/XenoGenetcs/ServerXenoGeneticsSystem.cs:16-16
Timestamp: 2026-02-19T18:00:42.014Z
Learning: In C# files across the repository, mark classes as sealed when there is no explicit need for inheritance. This project-wide coding standard (confirmed by The-Fiafi) helps prevent unintended inheritance and encourages explicit design. Exceptions should be made only where inheritance is actually required (e.g., for extensibility, mockable abstraction, or framework constraints). Ensure consistency by auditing classes in Content.Server/Imperial/XenoGenetcs/ServerXenoGeneticsSystem.cs and related files, applying sealed where inheritance is not needed.

Failed to handle agent chat message. Please try again.

Comment on lines +6 to +10
[DataField]
public bool Used = false;
public EntProtoId HitProto = "ImperialNothingThereHit";
[DataField("empowerSound")]
public SoundSpecifier EmpowerSound = new SoundPathSpecifier("/Audio/Imperial/SCP/nothingthere_empower.ogg");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Разделите prototype-конфиг и runtime-состояние по атрибутам.

Used выглядит как чистый runtime-флаг, а HitProto, если его нужно переопределять из YAML, сейчас вообще не сериализуется. В текущем виде состояние хуже дебажится, а конфиг поля легко потерять молча.

Based on learnings: In the Imperial SS14 project, fields of components that are not configured via YAML prototypes (runtime state) should be marked with the [ViewVariables] attribute, while fields configured via prototypes should use [DataField].

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@Content.Server/Imperial/SCP/NothingThere/Components/ImperialNothingThereGoodbyeComponent.cs`
around lines 6 - 10, The field Used is a runtime-only flag and should not be a
prototype-configured DataField: remove the [DataField] attribute from Used and
mark it with [ViewVariables] instead; conversely ensure HitProto (EntProtoId
HitProto = "ImperialNothingThereHit") is marked with [DataField] (e.g.
[DataField("hitProto")]) so it’s serializable from YAML; leave EmpowerSound
as-is. Modify these attributes on the ImperialNothingThereGoodbyeComponent to
separate runtime state (Used) from prototype-configurable fields (HitProto,
EmpowerSound).

{$name} попал в ваше измерение! Удачной охоты ^_^ No newline at end of file
{$name} попал в ваше измерение! Удачной охоты ^_^

nothingthere-hammaggotson-haha = [color=red][font size=14][bold]Вы чувствуете, что вы нашли то, чего искали. Ваше истинное "Я".[/font]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Незакрытый тег [/font] в строке локализации.

В строке nothingthere-hammaggotson-haha открыт тег [font size=14], но отсутствует закрывающий [/font]. Это может вызвать проблемы с форматированием текста в игре.

🐛 Предлагаемое исправление
-nothingthere-hammaggotson-haha = [color=red][font size=14][bold]Вы чувствуете, что вы нашли то, чего искали. Ваше истинное "Я".[/font]
+nothingthere-hammaggotson-haha = [color=red][font size=14][bold]Вы чувствуете, что вы нашли то, чего искали. Ваше истинное "Я".[/bold][/font][/color]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Resources/Locale/ru-RU/Imperial/SCP/dimensionenteraction.ftl` at line 6, В
строке ключа nothingthere-hammaggotson-haha исправьте незакрытые форматирующие
теги: корректно закройте вложенные теги в обратном порядке их открытия (например
добавьте недостающие [/bold], затем [/font], затем [/color] или соответствующие
закрывающие теги), чтобы все открытые [color=red], [font size=14], [bold] были
закрыты.

ent-CloakNDADelexor = Плащ командования Недр
.desc = Выдается только самым значимым сотрудникам Недр.
ent-CloakNDAWhite = Подозрительный плащ Недр
.desc = Помните, Совет всегда видит и слышит вас. Для удобности и компактности в плаще уже вшиты диктофон и записывающее Ауидо устройство. Выдаётся всем, кому не лень.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Исправьте опечатку в описании ent-CloakNDAWhite.

На Line 198, вероятно, опечатка: Ауидоаудио (и лучше Для удобства, а не Для удобности).

Предлагаемая правка
-    .desc = Помните, Совет всегда видит и слышит вас. Для удобности и компактности в плаще уже вшиты диктофон и записывающее Ауидо устройство. Выдаётся всем, кому не лень.
+    .desc = Помните, Совет всегда видит и слышит вас. Для удобства и компактности в плаще уже вшиты диктофон и записывающее аудио-устройство. Выдаётся всем, кому не лень.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Resources/Locale/ru-RU/Imperial/Seriozha/SCP/locale.ftl` at line 198, В
описании локали для ent-CloakNDAWhite (ключ .desc в locale.ftl) исправьте
опечатку и формулировку: заменить «Ауидо» на «аудио» и «Для удобности» на «Для
удобства», т.е. обновить значение .desc соответствующего объекта
(ent-CloakNDAWhite) на корректную фразу с этими правками.

Comment on lines +1 to +12
- type: entity
id: ImperialNothingThereEnterBodyAction
name: Control body
description: cubism
components:
- type: Action
icon: { sprite : Mobs/Species/Human/organs.rsi, state: "brain" }
iconOn: { sprite : Mobs/Species/Human/organs.rsi, state: "brain" }
priority: 1
- type: TargetAction
- type: EntityTargetAction
event: !type:ImperialNothingThereEnterBodyEvent

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Отсутствует parent: BaseAction для согласованности с другими действиями.

Действия ImperialNothingThereGibBodyAction, ImperialNothingThereEggAction и ImperialNothingThereHelloAction наследуются от BaseAction, но ImperialNothingThereEnterBodyAction — нет. Это может привести к отсутствию базовых компонентов или настроек по умолчанию.

♻️ Предлагаемое исправление
 - type: entity
+  parent: BaseAction
   id: ImperialNothingThereEnterBodyAction
   name: Control body
   description: cubism
📝 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
- type: entity
id: ImperialNothingThereEnterBodyAction
name: Control body
description: cubism
components:
- type: Action
icon: { sprite : Mobs/Species/Human/organs.rsi, state: "brain" }
iconOn: { sprite : Mobs/Species/Human/organs.rsi, state: "brain" }
priority: 1
- type: TargetAction
- type: EntityTargetAction
event: !type:ImperialNothingThereEnterBodyEvent
- type: entity
parent: BaseAction
id: ImperialNothingThereEnterBodyAction
name: Control body
description: cubism
components:
- type: Action
icon: { sprite : Mobs/Species/Human/organs.rsi, state: "brain" }
iconOn: { sprite : Mobs/Species/Human/organs.rsi, state: "brain" }
priority: 1
- type: TargetAction
- type: EntityTargetAction
event: !type:ImperialNothingThereEnterBodyEvent
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Resources/Prototypes/Imperial/SCP/Actions/nothingthere.yml` around lines 1 -
12, The action ImperialNothingThereEnterBodyAction is missing parent: BaseAction
causing it to not inherit default components; add parent: BaseAction to the
ImperialNothingThereEnterBodyAction YAML entry so it matches
ImperialNothingThereGibBodyAction, ImperialNothingThereEggAction and
ImperialNothingThereHelloAction, then verify that any required base components
(e.g., Action, TargetAction, EntityTargetAction) are not duplicated or
contradicted after inheritance and adjust/remove explicit component declarations
if they conflict with BaseAction defaults.

Comment on lines +52 to +68
- type: entity
id: ImperialNothingThereProjectileAction
name: Throw bone shard
description: yeah.
components:
- type: Action
useDelay: 5
itemIconStyle: BigAction
sound: !type:SoundPathSpecifier
path: /Audio/Imperial/SCP/nothingthere_hello.ogg
icon: { sprite : Objects/Materials/materials.rsi, state: "bones" }
- type: TargetAction
checkCanAccess: false
range: 60
- type: WorldTargetAction
event: !type:ProjectileSpellEvent
prototype: ImperialProjectileBoneShard

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Отсутствует parent: BaseAction для ImperialNothingThereProjectileAction.

По аналогии с другими действиями в этом файле, рекомендуется добавить наследование от BaseAction для согласованности.

♻️ Предлагаемое исправление
 - type: entity
+  parent: BaseAction
   id: ImperialNothingThereProjectileAction
   name: Throw bone shard
   description: yeah.
📝 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
- type: entity
id: ImperialNothingThereProjectileAction
name: Throw bone shard
description: yeah.
components:
- type: Action
useDelay: 5
itemIconStyle: BigAction
sound: !type:SoundPathSpecifier
path: /Audio/Imperial/SCP/nothingthere_hello.ogg
icon: { sprite : Objects/Materials/materials.rsi, state: "bones" }
- type: TargetAction
checkCanAccess: false
range: 60
- type: WorldTargetAction
event: !type:ProjectileSpellEvent
prototype: ImperialProjectileBoneShard
- type: entity
parent: BaseAction
id: ImperialNothingThereProjectileAction
name: Throw bone shard
description: yeah.
components:
- type: Action
useDelay: 5
itemIconStyle: BigAction
sound: !type:SoundPathSpecifier
path: /Audio/Imperial/SCP/nothingthere_hello.ogg
icon: { sprite : Objects/Materials/materials.rsi, state: "bones" }
- type: TargetAction
checkCanAccess: false
range: 60
- type: WorldTargetAction
event: !type:ProjectileSpellEvent
prototype: ImperialProjectileBoneShard
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Resources/Prototypes/Imperial/SCP/Actions/nothingthere.yml` around lines 52 -
68, The entity ImperialNothingThereProjectileAction is missing inheritance from
BaseAction; update the entity definition for
ImperialNothingThereProjectileAction to include a parent: BaseAction entry
(matching other actions in the file) so it inherits base action behavior while
keeping its existing components (Action, TargetAction, WorldTargetAction)
intact.

Comment on lines +50 to +68
- type: entity
parent: ClothingNeckBase
id: CloakNDADelexor
name: vampire cloak
suffix: Seriozha, Кастомизация, Недра
description: Worn by high ranking vampires of the transylvanian society of vampires.
components:
- type: Sprite
sprite: Imperial/Seriozha/misc/Customization/nda_cloak.rsi

- type: entity
parent: ClothingNeckBase
id: CloakNDAWhite
name: vampire cloak
suffix: Seriozha, Кастомизация, Недра
description: Worn by high ranking vampires of the transylvanian society of vampires.
components:
- type: Sprite
sprite: Imperial/Seriozha/misc/Customization/white_cloak.rsi

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Снизьте дублирование в новых прототипах плащей.

CloakNDADelexor и CloakNDAWhite повторяют одни и те же поля; лучше вынести их в общий абстрактный parent.

Вариант рефактора
+- type: entity
+  abstract: true
+  parent: ClothingNeckBase
+  id: CloakNDABase
+  name: vampire cloak
+  suffix: Seriozha, Кастомизация, Недра
+  description: Worn by high ranking vampires of the transylvanian society of vampires.
+  components:
+  - type: Sprite
+
 - type: entity
-  parent: ClothingNeckBase
+  parent: CloakNDABase
   id: CloakNDADelexor
-  name: vampire cloak
-  suffix: Seriozha, Кастомизация, Недра
-  description: Worn by high ranking vampires of the transylvanian society of vampires.
   components:
   - type: Sprite
     sprite: Imperial/Seriozha/misc/Customization/nda_cloak.rsi

 - type: entity
-  parent: ClothingNeckBase
+  parent: CloakNDABase
   id: CloakNDAWhite
-  name: vampire cloak
-  suffix: Seriozha, Кастомизация, Недра
-  description: Worn by high ranking vampires of the transylvanian society of vampires.
   components:
   - type: Sprite
     sprite: Imperial/Seriozha/misc/Customization/white_cloak.rsi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Resources/Prototypes/Imperial/Seriozha/misc/misc.yml` around lines 50 - 68,
Вынести общие поля для CloakNDADelexor и CloakNDAWhite в общий абстрактный
parent: создайте новый прототип (например CloakNDABase) с parent:
ClothingNeckBase и общими полями name, suffix, description и общим
components-секцией за исключением уникального sprite; затем обновите
CloakNDADelexor и CloakNDAWhite чтобы они наследовали от CloakNDABase и
оставляли только id и уникальный Sprite (sprite:
Imperial/Seriozha/misc/Customization/nda_cloak.rsi и sprite:
Imperial/Seriozha/misc/Customization/white_cloak.rsi соответственно).

@The-Fiafi The-Fiafi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Апстрините ветку

{
[DataField("gibBodyAction")]
public EntProtoId GibBodyAction = "ImperialNothingThereGibBodyAction";
[AutoNetworkedField, DataField("gibBodyEntity")]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ваш компонент не помечен сетевым

[RegisterComponent]
public sealed partial class ImperialControlledNothingThereComponent : Component
{
[DataField("gibBodyAction")]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Передача строки излишне

public EntityUid? GibBodyEntity;

public EntityUid OriginalBody = EntityUid.Invalid;
[DataField("exitSound")]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Передача строки излишне

public EntityUid OriginalBody = EntityUid.Invalid;
[DataField("exitSound")]
public SoundSpecifier ExitSound = new SoundPathSpecifier("/Audio/Imperial/SCP/nothingthere_gibbody.ogg");
[DataField("killCount")]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Это не должно быть датафилдом

[RegisterComponent]
public sealed partial class ImperialNothingThereComponent : Component
{
[DataField("chaseSound")]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Передача строки излишне

if (_mobStateSystem.IsDead(uid) || _mobStateSystem.IsCritical(uid))
{
var transformB = Transform(uid);
var coords = transformB.Coordinates;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Зачем?

return gibbed;
}

private const float GibletLaunchImpulse = 150;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Вынети в компонент

}

private const float GibletLaunchImpulse = 150;
private const float GibletLaunchImpulseVariance = 3;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Вынети в компонент

var hands = EnsureComp<HandsComponent>(uid);
if (_hands.TryGetEmptyHand((uid, hands), out var emptyHand))
{
var hit = EntityUid.Invalid;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Никогда не используйте таким образом EntityUid.Invalid. Для этого есть null-able типы

public bool NeedGoodbye = false;
[DataField("projectileAction")]
public EntProtoId ProjectileAction = "ImperialNothingThereProjectileAction";
[AutoNetworkedField, DataField("projectileEntity")]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ваш компонент не помечен сетевым

@The-Fiafi The-Fiafi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Уберите у датафилдов передачу строки.

[DataField("hatchSound")]
public SoundSpecifier HatchSound = new SoundPathSpecifier("/Audio/Imperial/SCP/nothingthere_hatch.ogg");

public bool Empowered = false;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Добавьте либо атрибут ViewVariables, либо DataField

public EntProtoId HitProto = "ImperialNothingThereHit";
[DataField]
public bool NeedItems = false;
public bool NeedGoodbye = false;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Добавьте либо атрибут ViewVariables, либо DataField

[AutoNetworkedField, DataField("gibBodyEntity")]
public EntityUid? GibBodyEntity;

public EntityUid OriginalBody = EntityUid.Invalid;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Добавьте либо атрибут ViewVariables, либо DataField

@The-Fiafi

Copy link
Copy Markdown
Contributor

Апстримните ветку

@Maggotson Maggotson requested a review from a team June 22, 2026 14:16
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.

2 participants