Skip to content

Добавление нового объекта 933. Его механики#954

Open
helper342 wants to merge 32 commits intospace-sunrise:masterfrom
helper342:933-tape-test
Open

Добавление нового объекта 933. Его механики#954
helper342 wants to merge 32 commits intospace-sunrise:masterfrom
helper342:933-tape-test

Conversation

@helper342
Copy link
Copy Markdown

@helper342 helper342 commented Apr 13, 2026

Краткое описание | Short description

О великий 933 был добавлен, наконец я смогу заклеить дыру в 173.
Объект 933 — это клейкая лента, создающая сущности, которые подчиняются первому заражённому и пытаются наклеить ленту на всех, срывая при этом лицо.

Ссылка на багрепорт/Предложение | Related Issue/Bug Report

Медиа (Видео/Скриншоты) | Media (Video/Screenshots)

Changelog

Добавлен SCP-933, включая: сам объект 933, 933-1, 933-2 (Хост) и 933-2 (Миньон). Механика: Наклеивания ленты, отклеивания, порабощение персонала в ряды SCP-933.
🆑 Fire Helper/Helper_Never_Dies

  • add: Добавлен SCP-933

Summary by CodeRabbit

Новые функции

  • Добавлена поддержка SCP-933 (специальная изолента) с полным игровым циклом применения и удаления.
  • Реализована система взаимодействия с маской из изоленты: её можно применить к персонажу и снять.
  • Добавлены звуковые эффекты и визуальные элементы для всех действий с изолентой.
  • Поддержана локализация контента на русский язык.

helper342 and others added 17 commits April 12, 2026 16:38
Refactor code structure for improved readability and maintainability
…ocalization; remove unused server-side code and enhance face erasure logic for victims.
Refactor SCP-933 master system to improve interaction mechanics and l…
Rename controlled component to Scp933FaceTornComponent; trim master component; update en-US strings. Includes staged RSI meta change.

Made-with: Cursor
Deletes Content.Server._Scp/Scp9332 orphan file; real 933 is Content.Server/_Scp/Scp933 only.

Made-with: Cursor
…ity with do-after events. Added sound effects for applying and removing tape, and updated dependencies for interaction and audio systems. Removed outdated update logic and improved event handling for tape application and removal.
Refactor Scp933MasterSystem to implement full SCP-933 tape functional…
@helper342 helper342 requested a review from ThereDrD0 as a code owner April 13, 2026 19:01
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 13, 2026

Warning

Rate limit exceeded

@helper342 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 15 minutes and 10 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 15 minutes and 10 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 26e42e54-6cbe-4ed0-92bc-12195dbe8603

📥 Commits

Reviewing files that changed from the base of the PR and between 442f10b and ba0fa81.

📒 Files selected for processing (3)
  • Content.Server/_Scp/Scp933/Scp933TapeSystem.cs
  • Content.Shared/_Scp/Scp933/Scp933MasterSystem.cs
  • Resources/Locale/en-US/_prototypes/_scp/entities/clothing/masks/masks.ftl
📝 Walkthrough

Walkthrough

Добавлена новая система игровой механики SCP-933, основанная на изоленте. Реализованы компоненты для отслеживания состояния ленты, её применения и удаления. Добавлены серверные системы для управления взаимодействиями и состояниями жертв. Включены прототипы сущностей, спрайты и локализация на английском и русском языках.

Changes

Cohort / File(s) Summary
Shared Components
Content.Shared/_Scp/Scp933/DuctTapeComponent.cs, Content.Shared/_Scp/Scp933/Scp933TapeMaskComponent.cs, Content.Shared/_Scp/Scp933/TapedFaceComponent.cs, Content.Shared/_Scp/Scp933/Scp933FaceTornComponent.cs, Content.Shared/_Scp/Scp933/Scp933MasterComponent.cs, Content.Shared/_Scp/Scp933/Scp933PendingHostComponent.cs
Новые сетевые ECS компоненты для отслеживания состояния изоленты, маски, повреждённых лиц и мастера-носителя с настраиваемыми параметрами задержек, звуков и пороговых значений.
Shared Systems
Content.Shared/_Scp/Scp933/SharedScp933MasterSystem.cs, Content.Shared/_Scp/Scp933/TapedFaceSystem.cs
Системы управления жизненным циклом компонентов: скрытие слоёв лица, применение ленты, управление мутированием и обработка do-after событий.
Server Systems
Content.Server/_Scp/Scp933/Scp933TapeSystem.cs, Content.Server/_Scp/Scp933/Scp933MasterSystem.cs
Серверные системы для обработки взаимодействий с изолентой (снятие, применение, снятие ленты) через do-after механику и управления бонусами хозяина.
Entity Prototypes
Resources/Prototypes/_Scp/Entities/Objects/Scp/scp933.yml, Resources/Prototypes/_Scp/Entities/Clothing/Masks/masks.yml
Определения прототипов сущностей для изоленты и маски с компонентами sprite, item, melee weapon, а также специфичные конфигурации звуков и задержек.
Localization Files
Resources/Locale/en-US/_Scp/scp933.ftl, Resources/Locale/en-US/_prototypes/_scp/entities/objects/scp/scp933.ftl, Resources/Locale/en-US/_prototypes/_scp/entities/clothing/masks/masks.ftl, Resources/Locale/ru-RU/_prototypes/_scp/entities/objects/scp/scp933.ftl, Resources/Locale/ru-RU/_strings/_scp/scp/scp933.ftl, Resources/Locale/ru-RU/_prototypes/_scp/entities/clothing/masks/masks.ftl
Локализационные строки для игровых сообщений, описаний сущностей и статусов взаимодействий на английском и русском языках.
Texture Metadata
Resources/Textures/_Scp/Objects/Scp/scp-933.rsi/meta.json, Resources/Textures/_Scp/Structures/Wallmounts/scp-posters.rsi/meta.json, Resources/Textures/_Scp/Structures/Wallmounts/signs-directional.rsi/meta.json
Добавление описаний состояний текстур (спрайтов) для изоленты, плакатов и указателей с определением направлений и размеров.

Sequence Diagram(s)

sequenceDiagram
    participant User as Пользователь
    participant TapeSystem as Scp933TapeSystem
    participant Target as Цель (Humanoid)
    participant MasterSystem as SharedScp933MasterSystem
    participant Components as Компоненты

    User->>TapeSystem: Использует DuctTape
    TapeSystem->>TapeSystem: TryPeelTape()
    TapeSystem->>Components: Создаёт Scp933PeelTapeDoAfterEvent
    TapeSystem->>User: Показывает PopUp (начало снятия)
    Note over TapeSystem: Ожидание завершения DoAfter
    TapeSystem->>TapeSystem: OnPeelTapeDoAfter (завершение)
    TapeSystem->>Components: Спавнит TapeMask прототип
    TapeSystem->>Components: Уменьшает UseCount
    TapeSystem->>User: Воспроизводит PullFromRollSound

    User->>TapeSystem: Взаимодействует с Target (с маской)
    TapeSystem->>TapeSystem: TryApplyTape()
    TapeSystem->>Components: Создаёт Scp933ApplyTapeDoAfterEvent
    TapeSystem->>User: Показывает PopUp (начало применения)
    Note over TapeSystem: Ожидание завершения DoAfter
    TapeSystem->>Target: Экипирует маску в слот "mask"
    TapeSystem->>Components: Добавляет TapedFaceComponent
    TapeSystem->>Components: Скрывает слои лица (Eyes, Snout)
    TapeSystem->>Components: Добавляет MutedComponent
    TapeSystem->>Target: Воспроизводит ApplyToFaceSound

    User->>TapeSystem: Взаимодействует RipTape с Target
    TapeSystem->>TapeSystem: TryRipTape()
    TapeSystem->>Components: Создаёт Scp933RipTapeDoAfterEvent
    TapeSystem->>User: Показывает PopUp (начало снятия)
    Note over TapeSystem: Ожидание завершения DoAfter
    TapeSystem->>TapeSystem: OnRipTapeDoAfter (завершение)
    alt Режим Emergency
        TapeSystem->>MasterSystem: ConvertToMaster()
        MasterSystem->>Components: Добавляет Scp933MasterComponent
        MasterSystem->>MasterSystem: EraseFaceFor933()
        TapeSystem->>MasterSystem: ApplyHostBuffs()
    else Обычный режим
        TapeSystem->>MasterSystem: ApplyFaceTornAfterRip()
        MasterSystem->>Components: Добавляет Scp933FaceTornComponent
        MasterSystem->>MasterSystem: Скрывает лицо жертвы
    end
    TapeSystem->>Components: Удаляет маску (unequip)
    TapeSystem->>Target: Показывает успех PopUp
Loading
sequenceDiagram
    participant MasterSystem as SharedScp933MasterSystem
    participant Master as Сущность-Master
    participant Victim as Жертва (Face Torn)
    participant Components as Компоненты

    Note over MasterSystem: ComponentStartup: Scp933MasterComponent
    MasterSystem->>MasterSystem: EraseFaceFor933()
    MasterSystem->>Components: Скрывает слои лица Master
    MasterSystem->>Master: Показывает PopUp (хозяин появился)

    loop Каждая жертва в FaceTornVictims
        Note over MasterSystem: ComponentShutdown: Scp933FaceTornComponent
        MasterSystem->>Victim: Проверяет MutedComponent
        MasterSystem->>Victim: Удаляет MutedComponent (если применена)
        MasterSystem->>Master: Удаляет жертву из FaceTornVictims
    end

    Note over MasterSystem: MobStateChangedEvent (Victim → Dead)
    MasterSystem->>Victim: Удаляет Scp933FaceTornComponent
    MasterSystem->>Components: Вызывает ComponentShutdown цепь
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 Хвост прыгает в углу...
Лента липкая летит, маски быстро на беду!
Мастер вышел из когда-то, лиц порвал уже с тобой,
Do-after отчитал срок, звуки радостно поют!
🎀 Вот творенье создано — SCP волшебен в всё!


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (3 errors, 1 warning)

Check name Status Explanation Resolution
Ss14 C# Rules ❌ Error Missing Dirty() call after modifying AutoNetworkedField components in ApplyFaceTornAfterRip method at lines 126-127. Add Dirty(victim, torn) after modifying torn.TornBy and torn.MutedByScp933 to ensure network synchronization of component changes.
Ss14 Yaml/Ftl Rules ❌ Error Entity display name 'ent-ClothingMaskScp933Tape' начинается с прописной буквы вместо строчной и содержит грамматическую ошибку в описании. Измените 'SCP-933 face tape' на 'scp-933 face tape' и 'It does not breathe with you' на 'It does not let you breathe'.
Ss14 Prediction Safety ❌ Error Метод ApplyFaceTornAfterRip() не вызывает Dirty() после установки сетевых полей TornBy и MutedByScp933, вызывая рассинхронизацию состояния. Добавить вызов Dirty(victim, torn) после установки полей для синхронизации с клиентами в предсказывающей архитектуре SS14.
Docstring Coverage ⚠️ Warning Docstring coverage is 13.64% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Заголовок PR четко описывает добавление нового объекта SCP-933 и его механик, что полностью соответствует содержимому PR с реализацией системы ленты, компонентов и игровых механик.
Ss14 Bridge Sync ✅ Passed PR добавляет контент SCP-933, но не изменяет канонические файлы в .agent/rules/ или .agent/skills/, поэтому синхронизация мостов не требуется.
Ss14 Prototype ↔ Ftl Parity ✅ Passed Оба прототипа (ClothingMaskScp933Tape и Scp933DuctTape) имеют полное соответствие локализационным ключам в EN-US и RU-RU.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@helper342
Copy link
Copy Markdown
Author

Всё заяц, сиди ещё час

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 13, 2026

RSI Diff Bot; head commit ba0fa81 merging into d6987a7
This PR makes changes to 1 or more RSIs. Here is a summary of all changes:

Resources/Textures/_Scp/Objects/Scp/scp-933.rsi

State Old New Status
equipped Added
peel Added
tape Added

Resources/Textures/_Scp/Structures/Wallmounts/scp-posters.rsi

State Old New Status
scp933 Added

Resources/Textures/_Scp/Structures/Wallmounts/signs-directional.rsi

State Old New Status
933 Added

Edit: diff updated after ba0fa81

@helper342
Copy link
Copy Markdown
Author

Ух еба, даже заяц не ноет

@helper342
Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 13, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
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: 10

🤖 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/_Scp/Scp933/Scp933MasterSystem.cs`:
- Around line 319-323: Здесь мы модифицируем tapeMask.EmergencyRipAvailable
после того, как та же сущность помечена на удаление (removed -> QueueDel),
поэтому изменение не сохранится; переместите присвоение
tapeMask.EmergencyRipAvailable = false так, чтобы оно выполнялось до вызова
QueueDel(removed.Value) (или, если флаг должен быть глобальным, вместо изменения
tapeMask установите/сбросьте соответствующий системный флаг в
Scp933MasterSystem), и убедитесь, что вы используете тот же объект tapeMask (и
проверяете args.EmergencyMode) перед удалением, чтобы изменение вступило в силу.
- Around line 65-66: Remove the redundant TryComp<DuctTapeComponent> call since
`tape` is already an Entity<DuctTapeComponent> and its component is accessible
via `tape.Comp`; replace the TryComp usage with a null-check (or guard) on
`tape.Comp` and return if it is null, ensuring any subsequent uses reference
`tape.Comp` directly (refer to the variable `tape`, the component type
`DuctTapeComponent`, and the existing TryComp<DuctTapeComponent> call to locate
the code).
- Around line 99-100: В методе OnPeelTapeDoAfter есть лишний вызов
TryComp<DuctTapeComponent> для переменной tape; удалите этот дублирующий TryComp
и вместо него используйте уже полученный компонент (ductTape) из предыдущей
проверки/контекста или выполните единственный TryComp в согласованном месте,
чтобы избежать повторного запроса компонента DuctTapeComponent для сущности
tape.
- Around line 172-173: Remove the redundant TryComp check: the variable tapeMask
is an Entity<Scp933TapeMaskComponent> and always has the component, so delete
the if (!TryComp<Scp933TapeMaskComponent>(tapeMask, out _)) return; guard in
Scp933MasterSystem (remove the TryComp call and early return) and use the
component directly where needed (e.g., access via the entity/typed variable or
Comp/GetComponent calls that assume presence).

In `@Content.Shared/_Scp/Scp933/Scp933MasterSystem.cs`:
- Around line 76-90: EraseFaceFor933 currently calls
_humanoid.SetLayerVisibility eight times which can trigger Dirty() repeatedly;
change to use a batched update by using the SetLayerVisibility overload that
accepts a ref bool dirty (or otherwise accumulate a dirty flag) — e.g. create a
local bool dirty = false, call _humanoid.SetLayerVisibility(humanoidEnt,
HumanoidVisualLayers.Eyes, false, ref dirty) for each layer (Eyes, Snout, Head,
Hair, FacialHair, HeadTop, HeadSide, SnoutCover), then after the loop call the
single dirty commit method (e.g. _humanoid.Dirty(humanoidEnt) or the API's
equivalent) if dirty is true so only one Dirty() is emitted; keep references to
EraseFaceFor933, _humanoid.SetLayerVisibility, HumanoidVisualLayers and the
Entity<HumanoidAppearanceComponent?> usage to locate the code.
- Around line 162-165: Метод Clone() в Scp933RipTapeDoAfterEvent не должен
возвращать this — нужно вернуть новый экземпляр с копией состояния; измените
реализацию метода Clone() (в классе Scp933RipTapeDoAfterEvent / метод Clone)
чтобы создавать и возвращать новый объект и скопировать все мутируемые поля
(минимум ExpectedMask и EmergencyMode) и при необходимости другие наследуемые
поля/идентификаторы, вместо возвращения this, чтобы избежать повреждения данных
при сериализации/параллельной обработке.

In `@Resources/Locale/ru-RU/_prototypes/_scp/entities/objects/scp/scp933.ftl`:
- Around line 1-22: This file uses general keys like scp933-duct-tape,
scp933-master-desc, scp933-apply-success-user, etc., but prototype files must
use the ent-{PrototypeID} schema and prototype attributes; rename these keys to
the prototype format (e.g., ent-scp933, ent-scp933.desc for the prototype
description and ent-scp933.suffix where applicable) and convert per-item
prototype attributes to .desc/.suffix forms (replace scp933-duct-tape ->
ent-scp933.duct-tape or ent-scp933.duct-tape.desc as appropriate); move shared
runtime strings (like tape/equip/fail/peel messages such as scp933-tape-already,
scp933-tape-equip-fail, scp933-peel-start, scp933-apply-success-target, etc.)
out of this _prototypes file into the common runtime locale (e.g.,
Resources/Locale/ru-RU/_Scp/ or equivalent) so only prototype-specific metadata
remains here.
- Around line 1-22: Fix Russian typos and clarify target-action wording while
keeping parser-safe, lowercase item names: change scp933-duct-tape and
scp933-tape-mask values to start with lowercase (e.g., "изолента", "ленточка
изоленты"); correct spelling in scp933-master-desc ("первая жертва" or
"первая/основная жертва" instead of "первинная"), scp933-tape-equip-fail ("Лента
тут не прикрепляется" or "Лента не прикрепляется здесь" instead of "Лента не
крепиться здесь"), scp933-peel-hand-fail ("скручивается" instead of
"скручиваеться") and any other misspellings; change scp933-apply-start from "Вы
начинаете заклеивать своё лицо." to a target-focused phrase like "Вы начинаете
заклеивать лицо цели." to avoid implying self-action; ensure all edited strings
remain grammatically correct, consistent in meaning with other keys
(scp933-apply-success-user, scp933-apply-success-target,
scp933-victim-face-torn) and contain no extra punctuation that could break the
parser.

In `@Resources/Prototypes/_Scp/Entities/Clothing/Masks/masks.yml`:
- Around line 40-45: Добавьте в файлы локализации ru-RU и en-US отсутствующие
ключи для прототипа ClothingMaskScp933Tape: как минимум
ent-ClothingMaskScp933Tape, ent-ClothingMaskScp933Tape.desc и, если требуется по
шаблону, ent-ClothingMaskScp933Tape.suffix; поместите в соответствующие .ftl
файлы переводы названия и описания (русский и английский) и убедитесь, что имена
ключей точно совпадают с id прототипа ClothingMaskScp933Tape и со схемой
локализации, используемой для других масок (например с префиксом ent- и
суффиксом .desc/.suffix).

In `@Resources/Prototypes/_Scp/Entities/Objects/Scp/scp933.yml`:
- Line 1: Remove the redundant fork marker "# Fire added" from scp933.yml in the
_Scp/Entities/Objects/Scp directory because this is a new fork-only file and
fork markers are only required when modifying upstream files; open scp933.yml,
delete the leading comment line containing "# Fire added" (ensure any intended
Russian description remains intact) and save the file so the file no longer
begins with the fork marker.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 05fa677f-13e2-435d-afa5-c430aafe67e1

📥 Commits

Reviewing files that changed from the base of the PR and between b873bec and c07a913.

⛔ Files ignored due to path filters (7)
  • Resources/Audio/_Scp/Scp933/ducttape.ogg is excluded by !**/*.ogg
  • Resources/Audio/_Scp/Scp933/peeloff.ogg is excluded by !**/*.ogg
  • Resources/Textures/_Scp/Objects/Scp/scp-933.rsi/equipped.png is excluded by !**/*.png
  • Resources/Textures/_Scp/Objects/Scp/scp-933.rsi/peel.png is excluded by !**/*.png
  • Resources/Textures/_Scp/Objects/Scp/scp-933.rsi/tape.png is excluded by !**/*.png
  • Resources/Textures/_Scp/Structures/Wallmounts/scp-posters.rsi/scp933.png is excluded by !**/*.png
  • Resources/Textures/_Scp/Structures/Wallmounts/signs-directional.rsi/933.png is excluded by !**/*.png
📒 Files selected for processing (16)
  • Content.Server/_Scp/Scp933/Scp933MasterSystem.cs
  • Content.Shared/_Scp/Scp933/DuctTapeComponent.cs
  • Content.Shared/_Scp/Scp933/Scp933FaceTornComponent.cs
  • Content.Shared/_Scp/Scp933/Scp933MasterComponent.cs
  • Content.Shared/_Scp/Scp933/Scp933MasterSystem.cs
  • Content.Shared/_Scp/Scp933/Scp933PendingHostComponent.cs
  • Content.Shared/_Scp/Scp933/Scp933TapeMaskComponent.cs
  • Content.Shared/_Scp/Scp933/TapedFaceComponent.cs
  • Content.Shared/_Scp/Scp933/TapedFaceSystem.cs
  • Resources/Locale/en-US/_Scp/scp933.ftl
  • Resources/Locale/ru-RU/_prototypes/_scp/entities/objects/scp/scp933.ftl
  • Resources/Prototypes/_Scp/Entities/Clothing/Masks/masks.yml
  • Resources/Prototypes/_Scp/Entities/Objects/Scp/scp933.yml
  • Resources/Textures/_Scp/Objects/Scp/scp-933.rsi/meta.json
  • Resources/Textures/_Scp/Structures/Wallmounts/scp-posters.rsi/meta.json
  • Resources/Textures/_Scp/Structures/Wallmounts/signs-directional.rsi/meta.json

Comment thread Content.Server/_Scp/Scp933/Scp933MasterSystem.cs Outdated
Comment thread Content.Server/_Scp/Scp933/Scp933MasterSystem.cs Outdated
Comment thread Content.Server/_Scp/Scp933/Scp933MasterSystem.cs Outdated
Comment thread Content.Server/_Scp/Scp933/Scp933MasterSystem.cs Outdated
Comment thread Content.Shared/_Scp/Scp933/Scp933MasterSystem.cs
Comment thread Content.Shared/_Scp/Scp933/Scp933MasterSystem.cs
Comment thread Resources/Locale/ru-RU/_prototypes/_scp/entities/objects/scp/scp933.ftl Outdated
Comment thread Resources/Prototypes/_Scp/Entities/Clothing/Masks/masks.yml
Comment thread Resources/Prototypes/_Scp/Entities/Objects/Scp/scp933.yml Outdated
Co-authored-by: ThereDrD <88589686+ThereDrD0@users.noreply.github.com>
@helper342 helper342 changed the title ДЦП 933 (Опять) Добавление нового объекта 933. Его механики Apr 14, 2026
@helper342
Copy link
Copy Markdown
Author

@ThereDrD0 Что там?

@helper342
Copy link
Copy Markdown
Author

@coderabbitai Что там с ПРом, всё чисто?

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 14, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Get review comments on the PR
gh pr view 954 --repo space-sunrise/project-fire --json reviews,reviewRequests,state,statusCheckRollup

echo "=== REVIEW COMMENTS ==="
gh api repos/space-sunrise/project-fire/pulls/954/comments --jq '.[].body' | head -200

echo "=== PR REVIEW THREADS ==="
gh api repos/space-sunrise/project-fire/pulls/954/reviews --jq '.[] | {state: .state, body: .body, user: .user.login}'

echo "=== ISSUE COMMENTS ==="
gh api repos/space-sunrise/project-fire/issues/954/comments --jq '.[] | {user: .user.login, body: .body[:300]}'

Length of output: 33440


@helper342, нет, не совсем чисто. Вот текущий статус:

Статус PR: 🔴 Запрошены изменения (@ThereDrD0: "Это + ревью кролика. И это ревью 100% не последнее будет")

CI-проверки: ✅ Label, ✅ Diff RSI — всё зелёное.


Из моих 10 комментариев 4 уже закрыты, но ~6 остаются открытыми:

# Файл Проблема
1 Content.Shared/.../Scp933MasterSystem.cs (строки ~76-90) EraseFaceFor933 делает 8 вызовов SetLayerVisibility подряд — каждый может триггерить Dirty(). Нужно батч-обновление.
2 Content.Shared/.../Scp933MasterSystem.cs (строки ~162-165) Clone() в Scp933RipTapeDoAfterEvent возвращает this — нужно возвращать новый экземпляр с копией полей (ExpectedMask, EmergencyMode).
3 Resources/Locale/ru-RU/_prototypes/.../scp933.ftl Ключи не соответствуют схеме прототипов — нужно ent-{PrototypeID} (например ent-Scp933DuctTape); runtime-строки перенести в ru-RU/_Scp/.
4 Resources/Locale/ru-RU/_prototypes/.../scp933.ftl Опечатки: первиннаяпервая жертва, крепитьсякрепится, скручиваетьсяскручивается; текст scp933-apply-start подразумевает self-action.
5 Resources/Prototypes/_Scp/Entities/Clothing/Masks/masks.yml Отсутствуют ключи локализации для ClothingMaskScp933Tape (ent-ClothingMaskScp933Tape, ent-ClothingMaskScp933Tape.desc) в обоих локалях.
6 Resources/Prototypes/_Scp/Entities/Objects/Scp/scp933.yml Лишний форк-маркер # Fire added — он нужен только при изменении апстрим-файлов, а это новый файл.

Пункт #2 (Clone возвращает this) — наиболее критичный, может вызвать баги при параллельной обработке событий.

@helper342
Copy link
Copy Markdown
Author

@coderabbitai Где ты тут нашёл лишний форк маркер

SCP-933 - Duct Tape System

SCP-933-01: The Duct Tape Item

  • type: entity
    parent: BaseItem
    id: Scp933DuctTape
    suffix: SCP-933-01
    name: scp933-duct-tape
    description: scp933-duct-tape-desc
    components:
    • type: Sprite
      sprite: _Scp/Objects/Scp/scp-933.rsi
      state: equipped
    • type: Item
      size: Small
      heldPrefix: equipped
    • type: DuctTape
    • type: MeleeWeapon
      range: 1.5
      damage:
      types:
      Blunt: 5
    • type: GuideHelp
      guides:
      • ScpResearch

SCP-933-02: The Tape Master (Faceless Entity)

  • type: entity
    parent: BaseMobHuman
    id: Scp933Master
    suffix: SCP-933-02
    name: SCP-933-02 "The Tape Master"
    description: scp933-master-desc
    components:
  • type: Sprite
    sprite: _Scp/Mobs/Scp933Master.rsi
    layers:
    • map: ["enum.HumanoidVisualLayers.Chest"]
      state: torso
      sprite: _Scp/Mobs/Scp933Master.rsi

    • map: ["enum.HumanoidVisualLayers.Ensnare"]
      sprite: _Scp/Objects/Scp/scp-933.rsi
      state: equipped
      visible: true

    • type: HumanoidAppearance
      sex: Male

      hairColor: "#FFFF00" # лучше убрать или сделать менее ярким

    • type: Scp933Master

    • type: TapedFace

    • type: MobThresholds
      thresholds:
      0: Alive
      500: Critical
      800: Dead

    • type: NpcFactionMember
      factions:

      • SimpleHostile
    • type: MeleeWeapon
      range: 1.5
      damage:
      types:
      Blunt: 25

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 14, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check for fork markers in the relevant files
rg -n "Fire added|fire added|# Fire|fork marker" Resources/Prototypes/_Scp/Entities/Objects/Scp/scp933.yml || echo "No match in scp933.yml"

# Also search broadly across the entire PR's new files
rg -n "Fire added|fire added" Resources/Prototypes/_Scp/

Length of output: 22


@helper342, ты прав — я ошибся. Никакого # Fire added маркера в файле нет, скрипт это подтвердил. Прошу прощения за неточность в предыдущем ответе — пункт #6 из моего списка был неверным и его следует игнорировать.

Актуальные открытые замечания — это пункты #1#5 из таблицы выше (батчинг в EraseFaceFor933, Clone() в Scp933RipTapeDoAfterEvent, структура ключей локализации и опечатки).

(。•́︿•̀。)

@helper342
Copy link
Copy Markdown
Author

@coderabbitai А ну читай опять. Я всё давным давно исправил

@helper342
Copy link
Copy Markdown
Author

Ебать бот, даже не видит новый коммит, нужно пальчиком указывать

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 14, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

Сейчас проверю текущее состояние файлов.


🏁 Script executed:

#!/bin/bash
echo "=== Clone() in DoAfterEvents ==="
rg -n "Clone" Content.Shared/_Scp/Scp933/Scp933MasterSystem.cs

echo "=== EraseFaceFor933 ==="
rg -n -A 20 "EraseFaceFor933" Content.Shared/_Scp/Scp933/Scp933MasterSystem.cs

echo "=== RU locale file ==="
cat Resources/Locale/ru-RU/_prototypes/_scp/entities/objects/scp/scp933.ftl 2>/dev/null || echo "File not found at that path"
fd -i "scp933.ftl" Resources/Locale/ru-RU/ --exec cat {}

echo "=== EN locale file ==="
fd -i "scp933.ftl" Resources/Locale/en-US/ --exec cat {}

echo "=== ClothingMaskScp933Tape localization keys ==="
rg -n "ClothingMaskScp933Tape\|ent-ClothingMaskScp933Tape" Resources/Locale/

echo "=== scp933.yml prototype ==="
cat Resources/Prototypes/_Scp/Entities/Objects/Scp/scp933.yml

Length of output: 6469


Проверяю полностью — одну секунду.


🏁 Script executed:

#!/bin/bash
echo "=== Full Clone() implementations for Apply and Rip events ==="
sed -n '148,185p' Content.Shared/_Scp/Scp933/Scp933MasterSystem.cs

echo ""
echo "=== All locale files for en-US scp933 ==="
fd -i "scp933.ftl" Resources/Locale/en-US/

echo ""
echo "=== ClothingMaskScp933Tape in any locale ==="
rg -rn "ClothingMaskScp933Tape" Resources/Locale/ || echo "NOT FOUND in locale files"

echo ""
echo "=== masks.yml ClothingMaskScp933Tape entry ==="
rg -n -A5 "ClothingMaskScp933Tape" Resources/Prototypes/_Scp/Entities/Clothing/Masks/masks.yml

Length of output: 1266


@helper342, ты прав — всё исправлено. Приношу извинения за то, что не проверил сразу. Вот итог:

# Проблема Статус
1 EraseFaceFor933 — батч-обновление ✅ Исправлено (SetLayersVisibility с массивом)
2 Clone() возвращал this ✅ Исправлено во всех трёх событиях (Peel, Apply, Rip — каждый возвращает новый экземпляр с копированием полей)
3 Структура ключей локализации ✅ Исправлено (ent-Scp933DuctTape присутствует в обоих локалях)
4 Опечатки в ru-RU ✅ Исправлено
5 Отсутствие ent-ClothingMaskScp933Tape ✅ Исправлено (ключи есть в masks.ftl для обоих языков)

Все замечания устранены.

Copy link
Copy Markdown
Collaborator

@ThereDrD0 ThereDrD0 left a comment

Choose a reason for hiding this comment

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

Плюс предыдущее ревью не было сделано до конца, доделывай

Comment thread Content.Server/_Scp/Scp933/Scp933MasterSystem.cs Outdated
Comment thread Content.Server/_Scp/Scp933/Scp933MasterSystem.cs Outdated
Comment thread Content.Server/_Scp/Scp933/Scp933MasterSystem.cs Outdated
Copy link
Copy Markdown
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: 7

🤖 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/_Scp/Scp933/Scp933TapeSystem.cs`:
- Around line 270-283: В текущем DoAfter-инициализаторе (DoAfterArgs с
Scp933ApplyTapeDoAfterEvent, передаваемый tapeMask и target: victim) отсутствует
прерывание при перемещении цели, поэтому действие завершается даже если жертва
уходит; добавьте в объект инициализации свойство BreakOnTargetMove = true. То же
самое исправьте в втором DoAfter (тот, что использует
Scp933RemoveTapeDoAfterEvent / связанный tapeMask и target: victim в блоке
~343-357): установить BreakOnTargetMove = true в инициализаторе DoAfterArgs
рядом с BreakOnMove/BreakOnDamage/и т.д.
- Around line 169-185: Сделайте так, чтобы SCP-933 снимал только собственный
mute: добавьте уникальный маркер-компонент (например Scp933MutedTagComponent) и
в OnTapeMaskGotEquipped (и в логике, где накладывается mute при порванном лице)
ставьте одновременно EnsureComp<MutedComponent>(...) и
EnsureComp<Scp933MutedTagComponent>(...). В OnTapeMaskGotUnequipped проверяйте
только наличие этого маркера (HasComp<Scp933MutedTagComponent>(args.Equipee)) и
при его наличии удаляйте RemComp<Scp933MutedTagComponent>(args.Equipee) и только
затем RemComp<MutedComponent>(args.Equipee); не выполняйте
RemComp<MutedComponent> если маркер отсутствует. Это гарантирует, что вы не
удалите чужой mute; примените тот же паттерн в ветке с Scp933FaceTornComponent.
- Around line 99-144: Extract all permission and emergency-mode logic and popup
decisions out of OnHumanoidInteractHand into two methods: CanRipTape and
TryRipTape. Implement CanRipTape(user, targetUid, out string popupMessage, out
bool emergencyMode) to encapsulate checks for HasComp<Scp933MasterComponent>,
_master.HasAnyScp933Host(), TryGetScp933TapeMask,
TryComp<Scp933TapeMaskComponent>, and EmergencyRipAvailable and return a clear
denial popupMessage when not allowed. Implement TryRipTape(user, targetUid, out
DoAfterEventArgs doAfter) to call CanRipTape, set emergencyMode accordingly,
create the doAfter if allowed, and return true/false. Finally simplify
OnHumanoidInteractHand to only check args.Handled, call TryRipTape(args.User,
target.Owner, out var doAfter), start _doAfter.TryStartDoAfter(doAfter), show
the "scp933-rip-start" popup and set args.Handled; remove all moved
checks/popups from the handler.

In `@Content.Shared/_Scp/Scp933/Scp933MasterSystem.cs`:
- Around line 65-70: The handler OnFaceTornMobStateChanged removes
Scp933FaceTornComponent on death but runs on clients too; guard the mutation by
checking the network role and only call RemComp<Scp933FaceTornComponent>(ent)
when _net.IsServer is true (e.g., early-return when !_net.IsServer or wrap the
RemComp call inside if (_net.IsServer) { ... }) so only the server mutates
component state.

In `@Resources/Locale/en-US/_prototypes/entities/clothing/masks/masks.ftl`:
- Around line 84-85: The new FTL entry ent-ClothingMaskScp933Tape (.desc) was
added without the required fork marker; update the masks.ftl block by adding the
Fire fork marker (e.g., add a line with "# Fire edit" or "# Fire added")
immediately above the ent-ClothingMaskScp933Tape entry so the
ent-ClothingMaskScp933Tape and its .desc are properly annotated per the
repository guideline.

In `@Resources/Locale/ru-RU/_prototypes/entities/clothing/masks/masks.ftl`:
- Around line 88-89: The new FTL key ent-ClothingMaskScp933Tape (and its .desc)
was added without the required Fire fork marker; update the ru-RU masks.ftl by
adding the appropriate "# Fire edit" marker at the top of this edit block (or
immediately above the ent-ClothingMaskScp933Tape entry) so the file uses the
mandated "# Fire edit" format for FTL changes, leaving the key name and .desc
text intact.

In `@Resources/Locale/ru-RU/_strings/_scp/scp/scp933.ftl`:
- Line 13: Строка локали с ключом scp933-rip-master-only содержит внеигровую
подсказку, добавьте префикс "OOC: " перед текстом значения (т.е. превратите
"Только текущая первая жертва может выполнить финальный ритуал срыва." в строку,
начинающуюся с "OOC: "), чтобы явно пометить её как OOC согласно правилам для
Resources/Locale/**/*.ftl.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 46bcc2a8-9d19-4f9c-8fca-d3fe8f4f234e

📥 Commits

Reviewing files that changed from the base of the PR and between c07a913 and 939d39e.

📒 Files selected for processing (14)
  • Content.Server/_Scp/Scp933/Scp933MasterSystem.cs
  • Content.Server/_Scp/Scp933/Scp933TapeSystem.cs
  • Content.Shared/_Scp/Scp933/DuctTapeComponent.cs
  • Content.Shared/_Scp/Scp933/Scp933MasterComponent.cs
  • Content.Shared/_Scp/Scp933/Scp933MasterSystem.cs
  • Content.Shared/_Scp/Scp933/Scp933TapeMaskComponent.cs
  • Content.Shared/_Scp/Scp933/TapedFaceSystem.cs
  • Resources/Locale/en-US/_prototypes/_scp/entities/objects/scp/scp933.ftl
  • Resources/Locale/en-US/_prototypes/entities/clothing/masks/masks.ftl
  • Resources/Locale/ru-RU/_prototypes/_scp/entities/objects/scp/scp933.ftl
  • Resources/Locale/ru-RU/_prototypes/entities/clothing/masks/masks.ftl
  • Resources/Locale/ru-RU/_strings/_scp/scp/scp933.ftl
  • Resources/Prototypes/_Scp/Entities/Clothing/Masks/masks.yml
  • Resources/Prototypes/_Scp/Entities/Objects/Scp/scp933.yml

Comment thread Content.Server/_Scp/Scp933/Scp933TapeSystem.cs
Comment thread Content.Server/_Scp/Scp933/Scp933TapeSystem.cs Outdated
Comment thread Content.Server/_Scp/Scp933/Scp933TapeSystem.cs
Comment thread Content.Shared/_Scp/Scp933/Scp933MasterSystem.cs
Comment thread Resources/Locale/en-US/_prototypes/entities/clothing/masks/masks.ftl Outdated
Comment thread Resources/Locale/ru-RU/_prototypes/entities/clothing/masks/masks.ftl Outdated
Comment thread Resources/Locale/ru-RU/_strings/_scp/scp/scp933.ftl
@NotSoWizard
Copy link
Copy Markdown
Contributor

Почему ClothingMaskScp933Tape находится по пути
Resources/Locale/ru-RU/_prototypes/entities/clothing/masks/masks.ftl
вместо
Resources/Locale/ru-RU/_prototypes/_scp/entities/clothing/masks/masks.ftl
???

Copy link
Copy Markdown
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

♻️ Duplicate comments (1)
Content.Server/_Scp/Scp933/Scp933TapeSystem.cs (1)

142-159: ⚠️ Potential issue | 🟠 Major

Не снимайте MutedComponent без собственного маркера SCP-933.

Если цель уже была заглушена другой механикой, вы всё равно ставите MutedByScp933 = true, а на снятии маски безусловно делаете RemComp<MutedComponent>. Это удалит чужой mute. Здесь нужен отдельный маркер/учёт причины, и тот же паттерн надо применить в ветке ApplyFaceTornAfterRip / OnFaceTornShutdown.

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

In `@Content.Server/_Scp/Scp933/Scp933TapeSystem.cs` around lines 142 - 159, You
currently add/remove MutedComponent unconditionally which can remove mutes
applied by other systems; instead add a dedicated marker component (e.g.,
Scp933MutedComponent) when you mute in ApplyTapeMask/OnTapeMaskGotEquipped and
only remove the shared MutedComponent if that marker is present on the target.
Concretely: when muting (EnsureComp<MutedComponent>(...),
tapeMask.Comp.MutedByScp933 = true) also
AddComp<Scp933MutedComponent>(args.Equipee) (do not skip adding the marker even
if MutedComponent already existed); when unmuting (OnTapeMaskGotUnequipped and
in ApplyFaceTornAfterRip / OnFaceTornShutdown) check
HasComp<Scp933MutedComponent>(args.Equipee) before calling
RemComp<MutedComponent>, then Remove the marker and clear
tapeMask.Comp.MutedByScp933/Dirty as before; apply the same marker-check pattern
in both face-torn methods.
🤖 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.Shared/_Scp/Scp933/Scp933MasterSystem.cs`:
- Around line 62-63: После удаления элемента из коллекции FaceTornVictims в
Scp933MasterComponent пометьте компонент как изменённый для сетевой
синхронизации: в блоке где проверяется TryComp<Scp933MasterComponent>(bearer,
out var master) и выполняется master.FaceTornVictims.Remove(ent) вызовите
Dirty(bearer, master) (или Dirty(ent) если уместно) сразу после Remove, чтобы
изменения коллекции были отправлены клиентам.

---

Duplicate comments:
In `@Content.Server/_Scp/Scp933/Scp933TapeSystem.cs`:
- Around line 142-159: You currently add/remove MutedComponent unconditionally
which can remove mutes applied by other systems; instead add a dedicated marker
component (e.g., Scp933MutedComponent) when you mute in
ApplyTapeMask/OnTapeMaskGotEquipped and only remove the shared MutedComponent if
that marker is present on the target. Concretely: when muting
(EnsureComp<MutedComponent>(...), tapeMask.Comp.MutedByScp933 = true) also
AddComp<Scp933MutedComponent>(args.Equipee) (do not skip adding the marker even
if MutedComponent already existed); when unmuting (OnTapeMaskGotUnequipped and
in ApplyFaceTornAfterRip / OnFaceTornShutdown) check
HasComp<Scp933MutedComponent>(args.Equipee) before calling
RemComp<MutedComponent>, then Remove the marker and clear
tapeMask.Comp.MutedByScp933/Dirty as before; apply the same marker-check pattern
in both face-torn methods.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 75e9773c-c31b-4d70-b886-f86725f9d6b1

📥 Commits

Reviewing files that changed from the base of the PR and between 939d39e and a6cb491.

📒 Files selected for processing (7)
  • Content.Server/_Scp/Scp933/Scp933MasterSystem.cs
  • Content.Server/_Scp/Scp933/Scp933TapeSystem.cs
  • Content.Shared/_Scp/Scp933/Scp933FaceTornComponent.cs
  • Content.Shared/_Scp/Scp933/Scp933MasterComponent.cs
  • Content.Shared/_Scp/Scp933/Scp933MasterSystem.cs
  • Content.Shared/_Scp/Scp933/Scp933MutedTagComponent.cs
  • Content.Shared/_Scp/Scp933/Scp933TapeMaskComponent.cs

Comment thread Content.Server/_Scp/Scp933/Scp933TapeSystem.cs
Comment thread Content.Shared/_Scp/Scp933/Scp933MasterSystem.cs Outdated
@helper342
Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 15, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
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: 3

♻️ Duplicate comments (2)
Content.Shared/_Scp/Scp933/Scp933MasterSystem.cs (1)

145-161: 🧹 Nitpick | 🔵 Trivial

Рассмотрите использование SimpleDoAfterEvent без ручного Clone().

Для событий без состояния (Scp933PeelTapeDoAfterEvent, Scp933ApplyTapeDoAfterEvent) можно использовать базовый SimpleDoAfterEvent без переопределения Clone(), если он корректно обрабатывает клонирование.

Предлагаемый рефакторинг (если SimpleDoAfterEvent поддерживает автоклонирование)
 [Serializable, NetSerializable]
-public sealed partial class Scp933PeelTapeDoAfterEvent : SimpleDoAfterEvent
-{
-    public override DoAfterEvent Clone()
-    {
-        return new Scp933PeelTapeDoAfterEvent();
-    }
-}
+public sealed partial class Scp933PeelTapeDoAfterEvent : SimpleDoAfterEvent;
 
 [Serializable, NetSerializable]
-public sealed partial class Scp933ApplyTapeDoAfterEvent : DoAfterEvent
-{
-    public override DoAfterEvent Clone()
-    {
-        return new Scp933ApplyTapeDoAfterEvent();
-    }
-}
+public sealed partial class Scp933ApplyTapeDoAfterEvent : SimpleDoAfterEvent;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Content.Shared/_Scp/Scp933/Scp933MasterSystem.cs` around lines 145 - 161, Эти
два пустых события (Scp933PeelTapeDoAfterEvent и Scp933ApplyTapeDoAfterEvent)
лишь повторяют поведение SimpleDoAfterEvent, поэтому уберите их кастомные
классы/переопределения Clone() и используйте SimpleDoAfterEvent напрямую (или
замените их типы/создания на SimpleDoAfterEvent) — проверьте все места, где
упоминаются Scp933PeelTapeDoAfterEvent и Scp933ApplyTapeDoAfterEvent, и замените
их на SimpleDoAfterEvent, удалив ненужные определения Clone() в
Scp933PeelTapeDoAfterEvent и Scp933ApplyTapeDoAfterEvent если SimpleDoAfterEvent
самостоятельно корректно клонируется.
Content.Server/_Scp/Scp933/Scp933TapeSystem.cs (1)

150-158: ⚠️ Potential issue | 🟠 Major

Риск перезаписи чужого MutedComponent.

Если у сущности уже есть MutedComponent от другой механики, текущий код установит MutedByScp933 = true, и при снятии маски удалит чужой мут.

Предлагаемое исправление
     private void OnTapeMaskGotEquipped(Entity<Scp933TapeMaskComponent> tapeMask, ref GotEquippedEvent args)
     {
         if (args.Slot != "mask")
             return;
 
-        EnsureComp<MutedComponent>(args.Equipee);
-        tapeMask.Comp.MutedByScp933 = true;
+        if (!HasComp<MutedComponent>(args.Equipee))
+        {
+            EnsureComp<MutedComponent>(args.Equipee);
+            tapeMask.Comp.MutedByScp933 = true;
+        }
         Dirty(tapeMask);
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Content.Server/_Scp/Scp933/Scp933TapeSystem.cs` around lines 150 - 158, В
текущем OnTapeMaskGotEquipped вы можете перезаписать чужой MutedComponent —
измените логику: вместо безусловного EnsureComp+перезаписи, сначала попытайтесь
получить существующий компонент через TryGetComp(args.Equipee, out
MutedComponent comp); если не найден — создайте его через EnsureComp; в обоих
случаях выставьте только флаг comp.MutedByScp933 = true и вызовите Dirty(comp)
(не затирая другие флаги). Также откройте обработчик снятия
(OnTapeMaskGotUnequipped) и измените его так, чтобы он только очищал
comp.MutedByScp933 и удалял сам MutedComponent только если ни один из флагов
(например MutedByScp933 и другие) не установлен; используйте RemComp только в
этом безопасном случае.
🤖 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/_Scp/Scp933/Scp933TapeSystem.cs`:
- Around line 431-438: Re-evaluate the emergency rip condition at completion:
inside TryCompleteRipTape (before calling DoRipTape/ConvertToMaster) call
CanRipTape(target, expectedMask, out var tapeMask) again and recompute
emergencyMode (or bail out) so you don't proceed with a stale emergencyMode
computed in TryRipTape; ensure DoRipTape/ConvertToMaster only run when the
rechecked emergencyMode is still valid (or update the flag passed to DoRipTape)
to prevent multiple masters being created.

In `@Content.Shared/_Scp/Scp933/Scp933MasterSystem.cs`:
- Around line 131-134: After modifying the Scp933FaceTornComponent instance
(obtained via EnsureComp<Scp933FaceTornComponent>(victim)) — setting TornBy and
MutedByScp933 — mark the component dirty so the AutoNetworkedField changes are
synchronized by calling Dirty for the entity/component (e.g., Dirty(victim,
torn) or Dirty(victim)) immediately after those assignments.

In `@Resources/Locale/en-US/_prototypes/_scp/entities/clothing/masks/masks.ftl`:
- Around line 5-6: Lowercase the entity key ent-ClothingMaskScp933Tape to
ent-clothingmaskscp933tape and update its .desc to a more natural phrasing with
a capitalized sentence start (e.g., change ".desc = Silver strips pressed over
the eyes. It does not breathe with you." to ".desc = Silver strips pressed over
the eyes. They do not move with your breathing."). Ensure you modify the entry
with the exact identifiers ent-ClothingMaskScp933Tape ->
ent-clothingmaskscp933tape and the corresponding .desc line.

---

Duplicate comments:
In `@Content.Server/_Scp/Scp933/Scp933TapeSystem.cs`:
- Around line 150-158: В текущем OnTapeMaskGotEquipped вы можете перезаписать
чужой MutedComponent — измените логику: вместо безусловного
EnsureComp+перезаписи, сначала попытайтесь получить существующий компонент через
TryGetComp(args.Equipee, out MutedComponent comp); если не найден — создайте его
через EnsureComp; в обоих случаях выставьте только флаг comp.MutedByScp933 =
true и вызовите Dirty(comp) (не затирая другие флаги). Также откройте обработчик
снятия (OnTapeMaskGotUnequipped) и измените его так, чтобы он только очищал
comp.MutedByScp933 и удалял сам MutedComponent только если ни один из флагов
(например MutedByScp933 и другие) не установлен; используйте RemComp только в
этом безопасном случае.

In `@Content.Shared/_Scp/Scp933/Scp933MasterSystem.cs`:
- Around line 145-161: Эти два пустых события (Scp933PeelTapeDoAfterEvent и
Scp933ApplyTapeDoAfterEvent) лишь повторяют поведение SimpleDoAfterEvent,
поэтому уберите их кастомные классы/переопределения Clone() и используйте
SimpleDoAfterEvent напрямую (или замените их типы/создания на
SimpleDoAfterEvent) — проверьте все места, где упоминаются
Scp933PeelTapeDoAfterEvent и Scp933ApplyTapeDoAfterEvent, и замените их на
SimpleDoAfterEvent, удалив ненужные определения Clone() в
Scp933PeelTapeDoAfterEvent и Scp933ApplyTapeDoAfterEvent если SimpleDoAfterEvent
самостоятельно корректно клонируется.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ec8ce2ad-8394-43ca-8eb5-9f72616d342d

📥 Commits

Reviewing files that changed from the base of the PR and between a6cb491 and 442f10b.

📒 Files selected for processing (4)
  • Content.Server/_Scp/Scp933/Scp933TapeSystem.cs
  • Content.Shared/_Scp/Scp933/Scp933MasterSystem.cs
  • Resources/Locale/en-US/_prototypes/_scp/entities/clothing/masks/masks.ftl
  • Resources/Locale/ru-RU/_prototypes/_scp/entities/clothing/masks/masks.ftl

Comment thread Content.Server/_Scp/Scp933/Scp933TapeSystem.cs
Comment thread Content.Shared/_Scp/Scp933/Scp933MasterSystem.cs
Comment thread Resources/Locale/en-US/_prototypes/_scp/entities/clothing/masks/masks.ftl Outdated
@helper342
Copy link
Copy Markdown
Author

@coderabbitai Проверь опять

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 15, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
echo "=== All masks.ftl paths in ru-RU ==="
fd -i "masks.ftl" Resources/Locale/ru-RU/

echo ""
echo "=== All masks.ftl paths in en-US ==="
fd -i "masks.ftl" Resources/Locale/en-US/

echo ""
echo "=== Contents of ALL masks.ftl files ==="
fd -i "masks.ftl" Resources/Locale/ --exec echo "--- {} ---" \; --exec cat {} \;

echo ""
echo "=== All scp933 locale files ==="
fd -i "scp933.ftl" Resources/Locale/ 

echo ""
echo "=== Full directory structure of ru-RU _prototypes ==="
tree Resources/Locale/ru-RU/_prototypes/ 2>/dev/null || find Resources/Locale/ru-RU/_prototypes/ -type f | sort

Length of output: 103554


@helper342, всё чисто. Проверил файлы напрямую:

Проверка Статус
ent-ClothingMaskScp933Tape в ru-RU ✅ находится по правильному пути: _prototypes/_scp/entities/clothing/masks/masks.ftl
ent-ClothingMaskScp933Tape в en-US ✅ находится по правильному пути: _prototypes/_scp/entities/clothing/masks/masks.ftl
Все 5 ранее выявленных проблем ✅ исправлены

По поводу вопроса @NotSoWizard — ключ находится именно в _prototypes/_scp/..., а не в _prototypes/entities/.... Путь корректный, ключ в нужном месте.

С моей стороны замечаний нет. 🎉

@helper342
Copy link
Copy Markdown
Author

@coderabbitai Ещё жалобы от @ThereDrD0 ожидаются или всё уже оптимизировано и готово к merge?

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 15, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
echo "=== Current PR review state ==="
gh pr view 954 --repo space-sunrise/project-fire --json reviewDecision,reviews,state

echo ""
echo "=== Reviews detail ==="
gh api repos/space-sunrise/project-fire/pulls/954/reviews --jq '.[] | {user: .user.login, state: .state, body: .body, submitted_at: .submitted_at}'

echo ""
echo "=== All PR review comments (inline) from ThereDrD0 ==="
gh api repos/space-sunrise/project-fire/pulls/954/comments --jq '.[] | select(.user.login == "ThereDrD0") | {path: .path, body: .body, line: .line, position: .position}'

echo ""
echo "=== All issue comments from ThereDrD0 ==="
gh api repos/space-sunrise/project-fire/issues/954/comments --jq '.[] | select(.user.login == "ThereDrD0") | {body: .body, created_at: .created_at}'

echo ""
echo "=== Open/unresolved review threads ==="
gh api graphql -f query='
{
  repository(owner: "space-sunrise", name: "project-fire") {
    pullRequest(number: 954) {
      reviewThreads(first: 50) {
        nodes {
          isResolved
          comments(first: 1) {
            nodes {
              author { login }
              body
              path
            }
          }
        }
      }
    }
  }
}' --jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false) | {resolved: .isResolved, author: .comments.nodes[0].author.login, path: .comments.nodes[0].path, body: .comments.nodes[0].body[:200]}'

Length of output: 78326


@helper342, нет, к мержу ещё не готово. Есть открытые замечания сразу от двух источников:


🔴 Открытые треды от @ThereDrD0 (8 штук, нерезолвнуто):

Файл Замечание
Content.Server/.../Scp933MasterSystem.cs Использовать отдельный компонент для возможных целей SCP-933 вместо HumanoidAppearanceComponent
Content.Server/.../Scp933MasterSystem.cs Слоты вынести в компонент как список (настраиваемый через YAML)
Content.Server/.../Scp933MasterSystem.cs Валидацию делать внутри поля компонента через get/set, а не в системе
Content.Server/.../Scp933MasterSystem.cs Хардкод — должно настраиваться через компоненты
Content.Shared/.../DuctTapeComponent.cs Почему не Stack-компонент вместо своего счётчика UseCount?
Content.Shared/.../Scp933MasterComponent.cs [ViewVariables(VVAccess.ReadOnly)] → достаточно просто [ViewVariables]
Content.Shared/.../Scp933MasterSystem.cs Серверный код перенести на сервер
Content.Shared/.../Scp933MasterSystem.cs Слои для скрытия лица сделать списком в компоненте и проходить циклом, а не хардкодить

🟡 Мои открытые замечания (из последнего ревью, актуальные):

Файл Замечание
Content.Server/.../Scp933TapeSystem.cs (строка ~431) Повторно проверять emergencyMode при завершении DoAfter, чтобы не создавать лишних мастеров
Content.Shared/.../Scp933MasterSystem.cs (строка ~131) Вызывать Dirty(victim, torn) после установки TornBy/MutedByScp933 для сетевой синхронизации
Content.Server/.../Scp933TapeSystem.cs (строка ~150) MutedComponent может удалить чужой мут — нужен маркер-компонент Scp933MutedTagComponent

Итого: PR ещё требует доработки. Основные блокеры — замечания @ThereDrD0.

@helper342
Copy link
Copy Markdown
Author

А ну пересмотрит коммиты
@coderabbitai

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 15, 2026

@helper342, запускаю пересмотр коммитов прямо сейчас!

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants