Skip to content

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

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

Добавление нового объекта 933. Его механики#954
helper342 wants to merge 47 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: рулон изоленты с циклом (пилинг, наложение, отрыв) и связанные визуальные/аудио эффекты.
    • Маска/ленты можно надевать/снимать, есть ритуал финального отрыва, последствия для носителя и пострадавших (включая состояние «лицо разорвано» и превращение в хозяина).
    • Новые предметы и прототипы (рулон, маска), слои спрайтов и HUD-попапы.
  • Локализация

    • Добавлены строки на английском и русском для всех взаимодействий и сообщений.

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

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 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
Новая Shared система для управления мастером/жертвами (стартап/шутдаун, EraseFaceFor933, ConvertToMaster, ApplyFaceTornAfterRip) и система для скрытия/восстановления слоёв лица при TapedFaceComponent.
Server Systems
Content.Server/_Scp/Scp933/Scp933TapeSystem.cs, Content.Server/_Scp/Scp933/Scp933MasterSystem.cs
Серверные системы DoAfter для снятия рулона, применения маски и рвания ленты; логика создания хозяина, применения баффов хоста и управления списком жертв.
Entity Prototypes
Resources/Prototypes/_Scp/Entities/Objects/Scp/scp933.yml, Resources/Prototypes/_Scp/Entities/Clothing/Masks/masks.yml
Добавлены прототипы: Scp933DuctTape (item, melee) и ClothingMaskScp933Tape (pullable mask) с конфигурацией звуков, задержек и скрытием слоя носа.
Localization
Resources/Locale/en-US/_Scp/scp933.ftl, Resources/Locale/en-US/_prototypes/.../scp933.ftl, Resources/Locale/en-US/.../masks.ftl, Resources/Locale/ru-RU/.../scp933.ftl, Resources/Locale/ru-RU/.../masks.ftl
Добавлены/обновлены англо- и русскоязычные строки для предметов и всех этапов взаимодействия (peel/apply/rip, состояния, ошибки, подсказки).
Textures / Meta
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
Добавлены/обновлены метаданные RSI‑состояний для спрайтов SCP‑933 и указателей.

Sequence Diagram(s)

sequenceDiagram
    participant Игрок as Игрок
    participant TapeSystem as Scp933TapeSystem
    participant Цель as Цель (Humanoid)
    participant MasterSys as SharedScp933MasterSystem
    participant Компоненты as Компоненты/Сервер

    Игрок->>TapeSystem: Использует DuctTape (TryPeelTape)
    TapeSystem->>Компоненты: Создаёт DoAfter (peel)
    Note over TapeSystem: Ожидание DoAfter завершения
    TapeSystem->>Компоненты: Спавнит TapeMask, уменьшает UseCount, воспроизводит звук

    Игрок->>TapeSystem: Применяет маску к Цели (TryApplyTape)
    TapeSystem->>Компоненты: Создаёт DoAfter (apply)
    Note over TapeSystem: Ожидание DoAfter завершения
    TapeSystem->>Цель: Экипирует mask, добавляет TapedFaceComponent, применяет MutedComponent

    Игрок->>TapeSystem: Рвёт ленту у Цели (TryRipTape)
    TapeSystem->>Компоненты: Создаёт DoAfter (rip)
    Note over TapeSystem: Ожидание DoAfter завершения
    alt Результат → превращение в хозяина
        TapeSystem->>MasterSys: ConvertToMaster / ApplyHostBuffs
        MasterSys->>Компоненты: Добавляет Scp933MasterComponent, EraseFaceFor933, настраивает пороги/баффы
    else Результат → лицо порвано
        TapeSystem->>MasterSys: ApplyFaceTornAfterRip
        MasterSys->>Цель: Добавляет Scp933FaceTornComponent, мутит, скрывает лицо
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 Я прыгаю тихо в тени,
Лента шуршит — вот новый день.
Лицо скрыто, ритуал готов,
Хозяин встал — и мир реков.
✨ Пусть код цветёт, как в поле лён.


Important

Pre-merge checks failed

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

❌ Failed checks (2 errors, 1 warning)

Check name Status Explanation Resolution
Ss14 Yaml/Ftl Rules ❌ Error Прототип ClothingMaskScp933Tape нарушает правило ss14-naming-conventions: fork-specific контент должен иметь префикс в начале ID согласно fresh-pattern-catalog. Переименуйте ClothingMaskScp933Tape на Scp933ClothingMaskTape и обновите все FTL и конфигурационные файлы для соответствия актуальному стандарту.
Ss14 Prediction Safety ❌ Error Shared код SCP-933 содержит непредсказываемые побочные эффекты (PopupEntity, SetLayerVisibility) в обработчиках ComponentStartup/ComponentShutdown без защиты от predicted контекста. Добавить IsFirstTimePredicted или ApplyingState защиту для PopupEntity и SetLayerVisibility в shared коде; переместить логику в серверный контекст или использовать predicted-safe варианты.
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 (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Заголовок PR точно описывает основное изменение: добавление нового объекта SCP-933 и его механик, что соответствует содержимому changeset'а.
Ss14 Bridge Sync ✅ Passed PR не изменяет канонические файлы правил или навыков в .agent/. Все измененные файлы относятся только к игровому контенту SCP-933.
Ss14 C# Rules ✅ Passed Все C# файлы соответствуют SS14 соглашениям об именовании и архитектурным требованиям.
Ss14 Prototype ↔ Ftl Parity ✅ Passed Оба player-facing прототипа SCP-933 имеют полное локализационное покрытие в обоих языках с правильной структурой.
✨ 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 6deafb0 merging into 4fc185b
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 6deafb0

@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 Outdated
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
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 Outdated
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.

@helper342
Copy link
Copy Markdown
Author

@coderabbitai Что там по ревью, отчёт

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 16, 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,statusCheckRollup

echo ""
echo "=== All open/unresolved review threads ==="
gh api graphql -f query='
{
  repository(owner: "space-sunrise", name: "project-fire") {
    pullRequest(number: 954) {
      reviewThreads(first: 100) {
        nodes {
          isResolved
          comments(first: 1) {
            nodes {
              author { login }
              body
              path
              createdAt
            }
          }
        }
      }
    }
  }
}' --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[:300], createdAt: .comments.nodes[0].createdAt}'

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

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

echo ""
echo "=== CI status checks ==="
gh pr view 954 --repo space-sunrise/project-fire --json statusCheckRollup --jq '.statusCheckRollup[] | {name: .name, status: .status, conclusion: .conclusion}'

Length of output: 43412


@helper342, вот актуальный отчёт по последнему ревью:

CI: ✅ Diff RSI — пройдено | ⏳ Label — в процессе
Решение: 🔴 CHANGES_REQUESTED


🔴 Открытые треды от @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 Слои для EraseFaceFor933 сделать списком в компоненте с циклом вместо хардкода

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

Файл Замечание Приоритет
Content.Server/.../Scp933TapeSystem.cs (~431) Повторно вычислять emergencyMode внутри TryCompleteRipTape перед созданием мастера, а не использовать устаревший флаг 🟠 Major
Content.Shared/.../Scp933MasterSystem.cs (~131) Вызвать Dirty(victim, torn) после установки TornBy/MutedByScp933 для сетевой синхронизации 🟠 Major
Content.Server/.../Scp933TapeSystem.cs (~150) MutedComponent может удалить чужой мут — нужна проверка: добавлять MutedByScp933 = true только если компонент не существовал до этого 🟠 Major
Content.Shared/.../Scp933MasterSystem.cs (~145) Scp933PeelTapeDoAfterEvent / Scp933ApplyTapeDoAfterEvent можно заменить напрямую на SimpleDoAfterEvent 🔵 Nitpick

Итого: Есть 8 нерезолвнутых тредов от @ThereDrD0 + 3 actionable замечания от меня. До мержа нужно разобраться как минимум с замечаниями ThereDrD0 (они блокируют аппрув).

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.

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

150-174: ⚠️ Potential issue | 🟠 Major

Некорректное отслеживание MutedComponent — чужой mute может быть удалён.

Текущая логика:

  1. При надевании EnsureComp<MutedComponent> ничего не делает, если компонент уже был
  2. Но MutedByScp933 = true устанавливается всегда
  3. При снятии маски удаляется MutedComponent, даже если он был добавлен другой механикой

Нужно проверять, был ли MutedComponent до надевания маски.

🛡️ Предлагаемое исправление
     private void OnTapeMaskGotEquipped(Entity<Scp933TapeMaskComponent> tapeMask, ref GotEquippedEvent args)
     {
         if (args.Slot != "mask")
             return;

+        // Не перезаписывать чужой mute
+        if (HasComp<MutedComponent>(args.Equipee))
+        {
+            tapeMask.Comp.MutedByScp933 = false;
+            Dirty(tapeMask);
+            return;
+        }
+
         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 - 174, The
code currently always sets tapeMask.Comp.MutedByScp933 = true on equip which can
remove someone else's mute on unequip; change OnTapeMaskGotEquipped to first
check bool hadMuted = HasComp<MutedComponent>(args.Equipee) and only call
EnsureComp<MutedComponent>(args.Equipee) if needed, then set
tapeMask.Comp.MutedByScp933 = !hadMuted (true only if we added the component),
and call Dirty(tapeMask) only when MutedByScp933 was set; leave
OnTapeMaskGotUnequipped as-is because it already only removes the MutedComponent
when tapeMask.Comp.MutedByScp933 is true (so this will now correctly only remove
mutes we added). Ensure you reference OnTapeMaskGotEquipped,
OnTapeMaskGotUnequipped, MutedByScp933, EnsureComp<MutedComponent>,
HasComp<MutedComponent>, RemComp<MutedComponent>, and Dirty(tapeMask) when
making the change.
Content.Shared/_Scp/Scp933/Scp933MasterSystem.cs (2)

146-162: 🧹 Nitpick | 🔵 Trivial

Избыточное переопределение Clone() для событий без состояния.

Scp933PeelTapeDoAfterEvent наследует SimpleDoAfterEvent, который уже предоставляет корректный Clone(). Аналогично, Scp933ApplyTapeDoAfterEvent не имеет полей состояния и может наследовать SimpleDoAfterEvent.

♻️ Упрощённый вариант
 [Serializable, NetSerializable]
 public sealed partial class Scp933PeelTapeDoAfterEvent : SimpleDoAfterEvent
 {
-    public override DoAfterEvent Clone()
-    {
-        return new Scp933PeelTapeDoAfterEvent();
-    }
 }

 [Serializable, NetSerializable]
-public sealed partial class Scp933ApplyTapeDoAfterEvent : DoAfterEvent
+public sealed partial class Scp933ApplyTapeDoAfterEvent : SimpleDoAfterEvent
 {
-    public override DoAfterEvent Clone()
-    {
-        return new Scp933ApplyTapeDoAfterEvent();
-    }
 }

Как указал ThereDrD0 в прошлом ревью: SimpleDoAfterEvent не требует ручного переопределения Clone().

🤖 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 146 - 162,
Переопределения Clone() избыточны: удалите метод Clone() в классах
Scp933PeelTapeDoAfterEvent и Scp933ApplyTapeDoAfterEvent, и сделайте
Scp933ApplyTapeDoAfterEvent наследником SimpleDoAfterEvent (как уже сделано для
Scp933PeelTapeDoAfterEvent), чтобы оба события использовали стандартную
реализацию SimpleDoAfterEvent без собственных Clone().

108-111: 🧹 Nitpick | 🔵 Trivial

Избыточная проверка HasComp перед EnsureComp.

EnsureComp<T> уже возвращает существующий компонент, если он есть — дополнительная проверка HasComp не нужна.

♻️ Упрощённый вариант
-        if (HasComp<Scp933MasterComponent>(victim))
-            return;
-
         EnsureComp<Scp933MasterComponent>(victim);
🤖 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 108 - 111, The
upfront HasComp<Scp933MasterComponent>(victim) check is redundant because
EnsureComp<Scp933MasterComponent>(victim) will return the existing component;
remove the if-check and simply call EnsureComp<Scp933MasterComponent>(victim)
(or assign its return to a variable if you need to use the component), keeping
references to Scp933MasterComponent and victim to locate the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@Content.Server/_Scp/Scp933/Scp933TapeSystem.cs`:
- Around line 150-174: The code currently always sets
tapeMask.Comp.MutedByScp933 = true on equip which can remove someone else's mute
on unequip; change OnTapeMaskGotEquipped to first check bool hadMuted =
HasComp<MutedComponent>(args.Equipee) and only call
EnsureComp<MutedComponent>(args.Equipee) if needed, then set
tapeMask.Comp.MutedByScp933 = !hadMuted (true only if we added the component),
and call Dirty(tapeMask) only when MutedByScp933 was set; leave
OnTapeMaskGotUnequipped as-is because it already only removes the MutedComponent
when tapeMask.Comp.MutedByScp933 is true (so this will now correctly only remove
mutes we added). Ensure you reference OnTapeMaskGotEquipped,
OnTapeMaskGotUnequipped, MutedByScp933, EnsureComp<MutedComponent>,
HasComp<MutedComponent>, RemComp<MutedComponent>, and Dirty(tapeMask) when
making the change.

In `@Content.Shared/_Scp/Scp933/Scp933MasterSystem.cs`:
- Around line 146-162: Переопределения Clone() избыточны: удалите метод Clone()
в классах Scp933PeelTapeDoAfterEvent и Scp933ApplyTapeDoAfterEvent, и сделайте
Scp933ApplyTapeDoAfterEvent наследником SimpleDoAfterEvent (как уже сделано для
Scp933PeelTapeDoAfterEvent), чтобы оба события использовали стандартную
реализацию SimpleDoAfterEvent без собственных Clone().
- Around line 108-111: The upfront HasComp<Scp933MasterComponent>(victim) check
is redundant because EnsureComp<Scp933MasterComponent>(victim) will return the
existing component; remove the if-check and simply call
EnsureComp<Scp933MasterComponent>(victim) (or assign its return to a variable if
you need to use the component), keeping references to Scp933MasterComponent and
victim to locate the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4b0e57eb-5769-4542-9c07-57e03623b26a

📥 Commits

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

📒 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

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 on lines +15 to +21
[Dependency] private readonly DamageableSystem _damageable = default!;
[Dependency] private readonly MobThresholdSystem _mobThresholds = default!;
public bool HasAnyScp933Host()
{
var query = EntityQueryEnumerator<Scp933MasterComponent>();
return query.MoveNext(out _, out _);
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
[Dependency] private readonly DamageableSystem _damageable = default!;
[Dependency] private readonly MobThresholdSystem _mobThresholds = default!;
public bool HasAnyScp933Host()
{
var query = EntityQueryEnumerator<Scp933MasterComponent>();
return query.MoveNext(out _, out _);
}
[Dependency] private readonly DamageableSystem _damageable = default!;
[Dependency] private readonly MobThresholdSystem _mobThresholds = default!;
public bool HasAnyScp933Host()
{
var query = EntityQueryEnumerator<Scp933MasterComponent>();
return query.MoveNext(out _, out _);
}

Comment on lines +50 to +54
if (TryComp<MeleeWeaponComponent>(uid, out var melee))
{
melee.Damage = new DamageSpecifier { DamageDict = { ["Blunt"] = master.HostBluntDamage } };
Dirty(uid, melee);
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Сразу храни в компоненте DamageSpecifier, тогда будет ещё меньше хардкода и код лучше

Comment on lines +152 to +153
if (args.Slot != "mask")
return;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Слот должен храниться в компоненте, желательно списком возможных слотов

Comment on lines +189 to +200
private void OnTargetMove(Entity<HumanoidAppearanceComponent> target, ref MoveEvent args)
{
if (!_targetToActiveDoAfters.TryGetValue(target.Owner, out var activeDoAfters))
return;

foreach (var doAfterId in activeDoAfters)
{
_doAfter.Cancel(doAfterId);
}

_targetToActiveDoAfters.Remove(target.Owner);
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

  1. Ультралаг едишен
  2. Зачем ты переизобретаешь существующую логику работу дуафтеров

Оно и так автоматически должно работать если ты правильно делаешь

Comment on lines +269 to +278
{
tape.Comp.UseCount--;
if (tape.Comp.UseCount <= 0)
{
QueueDel(tape);
return;
}

Dirty(tape);
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Ты так и не использовал логику стаков уже готовую, делай по аналогии с материалами

TryCompletePeelTape(tape, args.User);
}

private void OnHumanoidInteractUsing(Entity<HumanoidAppearanceComponent> target, ref InteractUsingEvent args)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Опять же не использован отдельный компонент для этого

@helper342 helper342 requested a review from ThereDrD0 April 17, 2026 12:49
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