Skip to content

[ADD] One psionic ability - #1109

Closed
kekoven1 wants to merge 12 commits into
WWhiteDreamProject:masterfrom
kekoven1:Tentacle-Psionic-Shooterok
Closed

[ADD] One psionic ability#1109
kekoven1 wants to merge 12 commits into
WWhiteDreamProject:masterfrom
kekoven1:Tentacle-Psionic-Shooterok

Conversation

@kekoven1

@kekoven1 kekoven1 commented Apr 7, 2026

Copy link
Copy Markdown
Contributor

Описание.
описание1
описание2
хук
или скорпион
сила зависит от силы псионика
мог где-то накосячить в коде

Медиа

https://youtu.be/8xUnMcWJQlU

Изменения

🆑

  • add: Псионическая способность на хук

@github-actions

github-actions Bot commented Apr 7, 2026

Copy link
Copy Markdown
Contributor

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

Resources/Textures/_White/Interface/Actions/psionic_hook.rsi

State Old New Status
icon Added

Resources/Textures/_White/Objects/Weapons/Guns/Launchers/psionic_hook_launcher.rsi

State Old New Status
icon Added
inhand-left Added
inhand-right Added
projectile Added
rope Added

Edit: diff updated after bae8512

@coderabbitai

coderabbitai Bot commented Apr 7, 2026

Copy link
Copy Markdown
Contributor

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

Добавлена псионическая способность «Крюк»: новые action-события и do-after, сетевые компоненты для крюка и снаряда, системы управления спавном/деспауном и поведением снаряда (выстрел, попадание, возврат), прототипы оружия/снаряда, локализация и метаданные текстур.

Changes

Cohort / File(s) Summary
Action Events
Content.Shared/_White/Actions/Events/PsionicHookActionEvent.cs
Добавлены PsionicHookPowerActionEvent и сериализуемый PsionicUncuffDoAfterEvent.
Hook components
Content.Shared/_White/Psionics/Hook/PsionicHookComponent.cs
Добавлены PsionicHookComponent и ProjectilePsionicHookComponent с сетевыми/автоген-полями (Projectile, IsReturning, Gun, ReturnSpeed, визуал для соединения).
Power component
Content.Shared/_White/Psionics/Hook/PsionicHookPowerComponent.cs
Добавлен PsionicHookPowerComponent с полями: HookPrototype, SoundOnSpawn, SoundOnDespawn, BreakoutTime, UncuffPopup, Hook.
Systems — применение и поведение
Content.Shared/_White/Psionics/Hook/HookPowerSystem.cs, Content.Shared/_White/Psionics/Hook/HookSystem.cs
Добавлены системы для обработки использования силы (спавн/деспаун крюка, запуск do-after для расковывания, завершение uncuff) и управления снарядом (привязка к оружию, обработка попадания, логика броска/возврата, пополнение патрона).
Action & Power prototypes
Resources/Prototypes/_White/Actions/psionics.yml, Resources/Prototypes/_White/Psionics/psionics.yml
Добавлены действие ActionSummonPsionicHook и определение силы PsionicHookPower с init/removal функциями (регистрация действия/компонента, фидбек).
Weapon & projectile prototypes
Resources/Prototypes/_White/Entities/Objects/Weapons/Guns/Launchers/launchers.yml, Resources/Prototypes/_White/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml
Добавлены прототипы WeaponPsionicHook и PsionicHookProjectile (Gun, ammo provider, sprite, физика, TimedDespawn, параметры возврата).
Localization
Resources/Locale/en-US/_white/abilities/psionic.ftl, Resources/Locale/ru-RU/_white/abilities/psionic.ftl, Resources/Locale/ru-RU/_white/weapons/ranged/launchers.ftl
Добавлены строки имени/описания действия, многострочный feedback при инициализации, popup для расковывания; RU: описание оружия.
Textures / meta
Resources/Textures/_White/Interface/Actions/psionic_hook.rsi/meta.json, Resources/Textures/_White/Objects/Weapons/Guns/Launchers/psionic_hook_launcher.rsi/meta.json
Добавлены meta.json для иконки действия и спрайтов крюка (состояния: icon, projectile, rope, inhand-* и др.).
Power pools
Resources/Prototypes/Psionics/PsionicPowerPool.yml, Resources/Prototypes/_White/Psionics/psionic_power_pool.yml
Добавлен вес PsionicHookPower: 1 в несколько пулов (RandomPsionicPowerPool, ElementalistPowerPool, PriestPowerPool).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested labels

Status: Needs Review

Suggested reviewers

  • Remuchi
  • Spatison
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title '[ADD] One psionic ability' is directly related to the changeset, which adds a new psionic hook ability with components, systems, localization, prototypes, and assets.
Description check ✅ Passed The description is related to the changeset, mentioning the hook/scorpion psionic ability with strength scaling and noting potential code issues.

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

✨ 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (3)
Resources/Textures/_White/Objects/Weapons/Guns/Launchers/psionic_hook_launcher.rsi/meta.json (1)

5-27: Непоследовательное форматирование JSON.

Отступы в массиве states (строки 9-27) отличаются от остальной части файла (строки 2-8). Рекомендуется использовать единообразное форматирование.

♻️ Предлагаемое исправление
 {
   "version": 1,
   "license": "CC-BY-SA-3.0",
   "copyright": "by kekoven1 (github)",
   "size": {
     "x": 32,
     "y": 32
   },
-    "states": [
-        {
-            "name": "icon"
-        },
-        {
-            "name": "projectile"
-        },
-        {
-            "name": "rope"
-        },
-        {
-            "name": "inhand-right",
-            "directions": 4
-        },
-        {
-            "name": "inhand-left",
-            "directions": 4
-        }
-    ]
+  "states": [
+    {
+      "name": "icon"
+    },
+    {
+      "name": "projectile"
+    },
+    {
+      "name": "rope"
+    },
+    {
+      "name": "inhand-right",
+      "directions": 4
+    },
+    {
+      "name": "inhand-left",
+      "directions": 4
+    }
+  ]
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@Resources/Textures/_White/Objects/Weapons/Guns/Launchers/psionic_hook_launcher.rsi/meta.json`
around lines 5 - 27, Массив "states" имеет несоответствующие отступы; приведи
форматирование блока "states" и его элементов ("icon", "projectile", "rope",
"inhand-right", "inhand-left") в соответствие с остальной частью файла (тот же
уровень отступов как у поля "size"), исправив лишние пробелы/отступы перед "[" и
каждой записи объекта, сохранив существующую JSON-структуру и порядок полей.
Content.Shared/_White/Psionics/Hook/PsionicHookPowerComponent.cs (1)

1-2: Неиспользуемые импорты.

Импорты Content.Shared.Humanoid и Content.Shared.Preferences не используются в данном компоненте и могут быть удалены.

♻️ Предлагаемое исправление
-using Content.Shared.Humanoid;
-using Content.Shared.Preferences;
 using Robust.Shared.Audio;
 using Robust.Shared.GameStates;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Utility;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Content.Shared/_White/Psionics/Hook/PsionicHookPowerComponent.cs` around
lines 1 - 2, В файле PsionicHookPowerComponent.cs в компоненте
PsionicHookPowerComponent обнаружены неиспользуемые импорты
Content.Shared.Humanoid и Content.Shared.Preferences — удалите эти
using-директивы из верхней части файла (уберите упоминания
Content.Shared.Humanoid и Content.Shared.Preferences), затем
пересоберите/прогоните анализатор, чтобы убедиться, что больше нет
неиспользуемых зависимостей.
Content.Shared/_White/Psionics/Hook/PsionicHookComponent.cs (1)

12-14: Исправьте опечатку в сериализуемом имени поля, пока оно новое.

HookJointSpite выглядит как typo и одновременно задаёт имя для [DataField]. Пока на это поле ещё не завязались прототипы и внешний код, безопаснее переименовать его в HookJointSprite.

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

In `@Content.Shared/_White/Psionics/Hook/PsionicHookComponent.cs` around lines 12
- 14, Rename the serializable field HookJointSpite in PsionicHookComponent to
HookJointSprite (update the field name and any references) so the [DataField]
uses the corrected name; ensure the SpriteSpecifier initialization and
ViewVariables attribute remain unchanged and update any usages of HookJointSpite
elsewhere in the codebase to the new identifier HookJointSprite.
🤖 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/_White/Psionics/Hook/HookPowerSystem.cs`:
- Around line 23-27: The component currently only removes component.Hook during
repeated use (OnPowerUse) so if PsionicHookPowerComponent is removed another way
the WeaponPsionicHook entity can remain; add cleanup by subscribing to the
component shutdown/removal event in Initialize (e.g.
SubscribeLocalEvent<PsionicHookPowerComponent,
ComponentShutdown>(OnHookComponentShutdown)) and implement
OnHookComponentShutdown(PsionicHookPowerComponent component, ComponentShutdown
args) to check component.Hook, forcibly delete that entity (ensure you handle
entity validity and Unremoveable state using the entity manager
delete/force-delete API), and then set component.Hook = null to avoid dangling
references; keep existing OnPowerUse and OnUncuff intact.
- Around line 91-95: Проблема: код читает CuffableComponent.LastAddedCuffs без
проверки наличия наручников, что может привести к выходу за границы если цель
уже раскована; исправьте в методе где используется
TryComp<CuffableComponent>(uid, out var cuffs) — после успешного получения cuffs
убедитесь, что контейнер наручников не пуст (например проверкой Count/IsEmpty
или наличия LastAddedCuffs безопасным способом) перед обращением к
LastAddedCuffs и вызовом _cuffs.Uncuff(uid, uid, lastAddedCuffs); если пустой —
просто вернуть/пропустить операцию do-after.
- Around line 12-14: The SpawnImplantSystem is performing world-changing actions
in shared code; move it into the server assembly and mark it server-only:
relocate the class SpawnImplantSystem from Content.Shared to Content.Server,
change its namespace to Content.Server._White.Psionics.Abilities, update any
using directives, and ensure it is compiled only in the server project; keep
logic that calls SpawnEntity, Del, TryPickupAnyHand and PlayPvs (and which
mutates component.Hook or spawns entities) on the server side and remove/replace
any client-side hooks or event handlers that could run on clients to avoid
prediction/duplication of sound and state. Ensure any registrations/DI that
referenced the old shared system are updated to the new server namespace so the
system runs only on the server.

In `@Content.Shared/_White/Psionics/Hook/HookSystem.cs`:
- Around line 94-105: The current branch only treats entities with the "Wall"
tag as surfaces to pull the shooter toward, causing hits on other stationary
things (doors, windows, vehicles) to fall through to the _throw branch; update
the condition in HookSystem (around Transform(args.Target), the
_tags.HasTag(args.Target, "Wall") check and the consequent branches) to detect
stationary/anchored/solid surfaces instead of only the "Wall" tag—for example
check the target's physics/rigidbody/anchored state or existence of a
Static/Immovable body (or a dedicated "Stationary" tag) and, when that test
passes, perform the pull (use shooterPos/targetPos direction * power * 2 and
_throw.TryThrow(shooter,..., hookComp.BasePower, shooter)); otherwise keep the
current fallback behavior that calls _layingDown.TryLieDown(args.Target) and
_throw.TryThrow(args.Target,...). Ensure you reference Transform(args.Target),
_tags.HasTag, _layingDown.TryLieDown, _throw.TryThrow, hookComp.BasePower,
args.Target and shooter when making the change.

---

Nitpick comments:
In `@Content.Shared/_White/Psionics/Hook/PsionicHookComponent.cs`:
- Around line 12-14: Rename the serializable field HookJointSpite in
PsionicHookComponent to HookJointSprite (update the field name and any
references) so the [DataField] uses the corrected name; ensure the
SpriteSpecifier initialization and ViewVariables attribute remain unchanged and
update any usages of HookJointSpite elsewhere in the codebase to the new
identifier HookJointSprite.

In `@Content.Shared/_White/Psionics/Hook/PsionicHookPowerComponent.cs`:
- Around line 1-2: В файле PsionicHookPowerComponent.cs в компоненте
PsionicHookPowerComponent обнаружены неиспользуемые импорты
Content.Shared.Humanoid и Content.Shared.Preferences — удалите эти
using-директивы из верхней части файла (уберите упоминания
Content.Shared.Humanoid и Content.Shared.Preferences), затем
пересоберите/прогоните анализатор, чтобы убедиться, что больше нет
неиспользуемых зависимостей.

In
`@Resources/Textures/_White/Objects/Weapons/Guns/Launchers/psionic_hook_launcher.rsi/meta.json`:
- Around line 5-27: Массив "states" имеет несоответствующие отступы; приведи
форматирование блока "states" и его элементов ("icon", "projectile", "rope",
"inhand-right", "inhand-left") в соответствие с остальной частью файла (тот же
уровень отступов как у поля "size"), исправив лишние пробелы/отступы перед "[" и
каждой записи объекта, сохранив существующую JSON-структуру и порядок полей.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: fe4a2475-bf26-4ff5-837a-49e801e47bbd

📥 Commits

Reviewing files that changed from the base of the PR and between d4077c4 and 37e9a4a.

⛔ Files ignored due to path filters (6)
  • Resources/Textures/_White/Interface/Actions/psionic_hook.rsi/icon.png is excluded by !**/*.png
  • Resources/Textures/_White/Objects/Weapons/Guns/Launchers/psionic_hook_launcher.rsi/icon.png is excluded by !**/*.png
  • Resources/Textures/_White/Objects/Weapons/Guns/Launchers/psionic_hook_launcher.rsi/inhand-left.png is excluded by !**/*.png
  • Resources/Textures/_White/Objects/Weapons/Guns/Launchers/psionic_hook_launcher.rsi/inhand-right.png is excluded by !**/*.png
  • Resources/Textures/_White/Objects/Weapons/Guns/Launchers/psionic_hook_launcher.rsi/projectile.png is excluded by !**/*.png
  • Resources/Textures/_White/Objects/Weapons/Guns/Launchers/psionic_hook_launcher.rsi/rope.png is excluded by !**/*.png
📒 Files selected for processing (13)
  • Content.Shared/_White/Actions/Events/PsionicHookActionEvent.cs
  • Content.Shared/_White/Psionics/Hook/HookPowerSystem.cs
  • Content.Shared/_White/Psionics/Hook/HookSystem.cs
  • Content.Shared/_White/Psionics/Hook/PsionicHookComponent.cs
  • Content.Shared/_White/Psionics/Hook/PsionicHookPowerComponent.cs
  • Resources/Locale/ru-RU/_white/abilities/psionic.ftl
  • Resources/Locale/ru-RU/_white/weapons/ranged/launchers.ftl
  • Resources/Prototypes/_White/Actions/psionics.yml
  • Resources/Prototypes/_White/Entities/Objects/Weapons/Guns/Launchers/launchers.yml
  • Resources/Prototypes/_White/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml
  • Resources/Prototypes/_White/Psionics/psionics.yml
  • Resources/Textures/_White/Interface/Actions/psionic_hook.rsi/meta.json
  • Resources/Textures/_White/Objects/Weapons/Guns/Launchers/psionic_hook_launcher.rsi/meta.json

Comment thread Content.Shared/_White/Psionics/Hook/HookPowerSystem.cs Outdated
Comment on lines +23 to +27
public override void Initialize()
{
SubscribeLocalEvent<PsionicHookPowerComponent, PsionicHookPowerActionEvent>(OnPowerUse);
SubscribeLocalEvent<CuffableComponent, PsionicUncuffDoAfterEvent>(OnUncuff);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Добавьте очистку уже призванного хука при снятии способности.

Сейчас component.Hook удаляется только при повторном использовании action. Если PsionicHookPowerComponent снимут другим путём, ссылка потеряется, а WeaponPsionicHook останется в мире или в руке; с учётом Unremoveable это может навсегда занять слот руки.

Возможный вариант
 public override void Initialize()
 {
     SubscribeLocalEvent<PsionicHookPowerComponent, PsionicHookPowerActionEvent>(OnPowerUse);
     SubscribeLocalEvent<CuffableComponent, PsionicUncuffDoAfterEvent>(OnUncuff);
+    SubscribeLocalEvent<PsionicHookPowerComponent, ComponentShutdown>(OnHookPowerShutdown);
 }
 
+private void OnHookPowerShutdown(EntityUid uid, PsionicHookPowerComponent component, ComponentShutdown args)
+{
+    if (component.Hook is not { } hook || Deleted(hook))
+        return;
+
+    QueueDel(hook);
+    component.Hook = null;
+}
📝 Committable suggestion

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

Suggested change
public override void Initialize()
{
SubscribeLocalEvent<PsionicHookPowerComponent, PsionicHookPowerActionEvent>(OnPowerUse);
SubscribeLocalEvent<CuffableComponent, PsionicUncuffDoAfterEvent>(OnUncuff);
}
public override void Initialize()
{
SubscribeLocalEvent<PsionicHookPowerComponent, PsionicHookPowerActionEvent>(OnPowerUse);
SubscribeLocalEvent<CuffableComponent, PsionicUncuffDoAfterEvent>(OnUncuff);
SubscribeLocalEvent<PsionicHookPowerComponent, ComponentShutdown>(OnHookPowerShutdown);
}
private void OnHookPowerShutdown(EntityUid uid, PsionicHookPowerComponent component, ComponentShutdown args)
{
if (component.Hook is not { } hook || Deleted(hook))
return;
QueueDel(hook);
component.Hook = null;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Content.Shared/_White/Psionics/Hook/HookPowerSystem.cs` around lines 23 - 27,
The component currently only removes component.Hook during repeated use
(OnPowerUse) so if PsionicHookPowerComponent is removed another way the
WeaponPsionicHook entity can remain; add cleanup by subscribing to the component
shutdown/removal event in Initialize (e.g.
SubscribeLocalEvent<PsionicHookPowerComponent,
ComponentShutdown>(OnHookComponentShutdown)) and implement
OnHookComponentShutdown(PsionicHookPowerComponent component, ComponentShutdown
args) to check component.Hook, forcibly delete that entity (ensure you handle
entity validity and Unremoveable state using the entity manager
delete/force-delete API), and then set component.Hook = null to avoid dangling
references; keep existing OnPowerUse and OnUncuff intact.

Comment thread Content.Shared/_White/Psionics/PsionicHook/HookSystem.cs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
Content.Shared/_White/Psionics/Hook/HookSystem.cs (1)

96-96: ⚠️ Potential issue | 🔴 Critical

Критическая опечатка: AchornedAnchored.

Сборка падает из-за опечатки в названии свойства. TransformComponent не содержит Achorned, правильное название — Anchored.

🐛 Исправление
-        if (_tags.HasTag(args.Target, "Wall") || transform.Achorned)
+        if (_tags.HasTag(args.Target, "Wall") || transform.Anchored)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Content.Shared/_White/Psionics/Hook/HookSystem.cs` at line 96, The condition
in HookSystem.cs uses a misspelled property transform.Achorned which causes a
build error; change it to the correct TransformComponent property name
transform.Anchored (i.e., replace "Achorned" with "Anchored") in the if
condition that checks _tags.HasTag(args.Target, "Wall") || transform.Achorned so
the code reads _tags.HasTag(args.Target, "Wall") || transform.Anchored; ensure
you import or reference the correct TransformComponent type if needed.
🧹 Nitpick comments (3)
Content.Shared/_White/Psionics/Hook/HookSystem.cs (3)

86-87: Избыточная проверка projectile.Shooter на null.

Эта проверка уже выполнена в методе OnProjectileHit (строка 66) перед вызовом HookThrow.

♻️ Предлагаемое исправление
     private void HookThrow(Entity<ProjectilePsionicHookComponent> ent, ProjectileHitEvent args,
         ProjectileComponent projectile, PsionicComponent psionic)
     {
         var power = MathF.Pow(psionic.CurrentAmplification, 1.3f);
         var hookComp = ent.Comp;
 
-        if (projectile.Shooter is null)
-            return;
-
         var shooter = projectile.Shooter.Value;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Content.Shared/_White/Psionics/Hook/HookSystem.cs` around lines 86 - 87, В
методе HookThrow удалите избыточную проверку на null для projectile.Shooter,
т.к. она уже проверяется в OnProjectileHit перед вызовом HookThrow; откройте
HookThrow и удалите блок "if (projectile.Shooter is null) return;" (или
эквивалентную проверку), оставив логику обработки попадания без дублируемой
проверки.

11-11: Неиспользуемый импорт MathNet.Numerics.Providers.LinearAlgebra.

В файле используется только MathF.Pow из System, а не функции из MathNet. Этот импорт можно удалить.

🧹 Предлагаемое исправление
-using MathNet.Numerics.Providers.LinearAlgebra;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Content.Shared/_White/Psionics/Hook/HookSystem.cs` at line 11, В файле
HookSystem.cs есть неиспользуемый импорт
MathNet.Numerics.Providers.LinearAlgebra — удалите строку using
MathNet.Numerics.Providers.LinearAlgebra; и оставьте только нужные пространства
имён (в коде используются MathF.Pow из System), чтобы убрать ненужную
зависимость и предупреждение компилятора.

50-59: Избыточный вызов Dirty(uid, component) после цикла.

Dirty уже вызывается внутри цикла на строке 50. Повторный вызов на строке 59 не нужен, если цикл выполнился хотя бы один раз.

♻️ Предлагаемое исправление
             Dirty(shotUid.Value, visuals);
         }
-
-        Dirty(uid, component);
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Content.Shared/_White/Psionics/Hook/HookSystem.cs` around lines 50 - 59, The
trailing redundant call to Dirty(uid, component) after the loop should be
removed because Dirty is already invoked inside the loop; locate the block that
sets up visuals using EnsureComp<JointVisualsComponent>(shotUid.Value), assigns
visuals.Sprite/OffsetA/Target and calls Dirty(shotUid.Value, visuals), and
simply delete the extra Dirty(uid, component) after that block (or, if you
intended to handle the case where the loop never executed, wrap that call in a
conditional that checks whether any iteration occurred), ensuring only the
necessary Dirty calls remain.
🤖 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/_White/Psionics/Hook/HookSystem.cs`:
- Around line 128-135: Переписать участок так, чтобы перед вызовом
_gun.ChangeBasicEntityAmmoCount(gun, 1) выполнялась проверка существования
сущности gun: убедиться, что component.Gun не равен null и сущность всё ещё
существует (например через EntityManager.EntityExists(gun) или соответствующий
метод в текущем контексте), и только после этого вызывать
ChangeBasicEntityAmmoCount; также сохранить текущую логику с
TryComp<PsionicHookComponent>(gun, out var hookComp) и Dirty(gun, hookComp) без
изменений.

---

Duplicate comments:
In `@Content.Shared/_White/Psionics/Hook/HookSystem.cs`:
- Line 96: The condition in HookSystem.cs uses a misspelled property
transform.Achorned which causes a build error; change it to the correct
TransformComponent property name transform.Anchored (i.e., replace "Achorned"
with "Anchored") in the if condition that checks _tags.HasTag(args.Target,
"Wall") || transform.Achorned so the code reads _tags.HasTag(args.Target,
"Wall") || transform.Anchored; ensure you import or reference the correct
TransformComponent type if needed.

---

Nitpick comments:
In `@Content.Shared/_White/Psionics/Hook/HookSystem.cs`:
- Around line 86-87: В методе HookThrow удалите избыточную проверку на null для
projectile.Shooter, т.к. она уже проверяется в OnProjectileHit перед вызовом
HookThrow; откройте HookThrow и удалите блок "if (projectile.Shooter is null)
return;" (или эквивалентную проверку), оставив логику обработки попадания без
дублируемой проверки.
- Line 11: В файле HookSystem.cs есть неиспользуемый импорт
MathNet.Numerics.Providers.LinearAlgebra — удалите строку using
MathNet.Numerics.Providers.LinearAlgebra; и оставьте только нужные пространства
имён (в коде используются MathF.Pow из System), чтобы убрать ненужную
зависимость и предупреждение компилятора.
- Around line 50-59: The trailing redundant call to Dirty(uid, component) after
the loop should be removed because Dirty is already invoked inside the loop;
locate the block that sets up visuals using
EnsureComp<JointVisualsComponent>(shotUid.Value), assigns
visuals.Sprite/OffsetA/Target and calls Dirty(shotUid.Value, visuals), and
simply delete the extra Dirty(uid, component) after that block (or, if you
intended to handle the case where the loop never executed, wrap that call in a
conditional that checks whether any iteration occurred), ensuring only the
necessary Dirty calls remain.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 1f8c69b6-b6b7-4a8e-bfb7-fb430d778765

📥 Commits

Reviewing files that changed from the base of the PR and between 37e9a4a and 5d9b752.

📒 Files selected for processing (2)
  • Content.Shared/_White/Psionics/Hook/HookPowerSystem.cs
  • Content.Shared/_White/Psionics/Hook/HookSystem.cs
🚧 Files skipped from review as they are similar to previous changes (1)
  • Content.Shared/_White/Psionics/Hook/HookPowerSystem.cs

Comment on lines +128 to +135
var gun = component.Gun;
if (TryComp<PsionicHookComponent>(gun, out var hookComp))
{
hookComp.Projectile = null;
Dirty(gun, hookComp);
}

_gun.ChangeBasicEntityAmmoCount(gun, 1);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Отсутствует проверка существования сущности gun перед изменением боеприпасов.

Если gun был удалён, но у него не было PsionicHookComponent, код всё равно попытается вызвать ChangeBasicEntityAmmoCount на несуществующей сущности.

🛡️ Предлагаемое исправление
         var gun = component.Gun;
+        if (Deleted(gun))
+        {
+            QueueDel(uid);
+            return;
+        }
+
         if (TryComp<PsionicHookComponent>(gun, out var hookComp))
         {
             hookComp.Projectile = null;
             Dirty(gun, hookComp);
         }
 
         _gun.ChangeBasicEntityAmmoCount(gun, 1);
📝 Committable suggestion

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

Suggested change
var gun = component.Gun;
if (TryComp<PsionicHookComponent>(gun, out var hookComp))
{
hookComp.Projectile = null;
Dirty(gun, hookComp);
}
_gun.ChangeBasicEntityAmmoCount(gun, 1);
var gun = component.Gun;
if (Deleted(gun))
{
QueueDel(uid);
return;
}
if (TryComp<PsionicHookComponent>(gun, out var hookComp))
{
hookComp.Projectile = null;
Dirty(gun, hookComp);
}
_gun.ChangeBasicEntityAmmoCount(gun, 1);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Content.Shared/_White/Psionics/Hook/HookSystem.cs` around lines 128 - 135,
Переписать участок так, чтобы перед вызовом _gun.ChangeBasicEntityAmmoCount(gun,
1) выполнялась проверка существования сущности gun: убедиться, что component.Gun
не равен null и сущность всё ещё существует (например через
EntityManager.EntityExists(gun) или соответствующий метод в текущем контексте),
и только после этого вызывать ChangeBasicEntityAmmoCount; также сохранить
текущую логику с TryComp<PsionicHookComponent>(gun, out var hookComp) и
Dirty(gun, hookComp) без изменений.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

Inline comments:
In `@Resources/Prototypes/Psionics/PsionicPowerPool.yml`:
- Line 21: Перенесите WWDP-специфичную запись PsionicHookPower из базового
PsionicPowerPool.yml в _White-слой: удалите добавление PsionicHookPower (тот
самый "PsionicHookPower: 1" в блоках weight) из основного
Resources/Prototypes/Psionics/PsionicPowerPool.yml и добавьте ту же запись с
комментарием и весом под соответствующие weightedRandom-блоки (например
RandomPsionicPowerPool и ElementalistPowerPool) в файл псевдо-слоя для
модификаций (файл с тем же структурным именем в _White), чтобы WWDP-специфичные
способности (PsionicHookPower и подобные ClonePower) хранились только в
_White-слое.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: d908563d-51fa-4177-b996-cb703a43564c

📥 Commits

Reviewing files that changed from the base of the PR and between 5d9b752 and fd91c11.

📒 Files selected for processing (1)
  • Resources/Prototypes/Psionics/PsionicPowerPool.yml

Comment thread Resources/Prototypes/Psionics/PsionicPowerPool.yml

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (2)
Content.Shared/_White/Psionics/Hook/HookPowerSystem.cs (2)

11-13: ⚠️ Potential issue | 🟠 Major

Эта система всё ещё не стала server-only.

Одного namespace Content.Server... здесь недостаточно: пока файл физически лежит в Content.Shared/..., он продолжит собираться вместе с shared-кодом. Для логики со SpawnEntity, Del, TryPickupAnyHand, PlayPvs и изменением component.Hook сам файл нужно переносить в Content.Server/..., а в shared оставлять только компоненты/ивенты.

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

In `@Content.Shared/_White/Psionics/Hook/HookPowerSystem.cs` around lines 11 - 13,
Файл с системой SpawnImplantSystem содержит серверную логику (вызовы
SpawnEntity, Del, TryPickupAnyHand, PlayPvs и изменение component.Hook) и
поэтому должен быть перемещён из Content.Shared в Content.Server; оставьте в
Shared только компоненты/ивенты, а сам класс SpawnImplantSystem перенесите в
соответствующий namespace и директорию Content.Server; убедитесь, что все
using/референсы обновлены и что код больше не компилируется в сборку shared
после перемещения.

22-26: ⚠️ Potential issue | 🟠 Major

Добавьте cleanup хука при снятии PsionicHookPowerComponent.

Сейчас удаление есть только в ветке повторного использования action. Если компонент снимут другим путём, ссылка на хук потеряется, а сама сущность останется в мире или в руке.

Возможный вариант
 public override void Initialize()
 {
     SubscribeLocalEvent<PsionicHookPowerComponent, PsionicHookPowerActionEvent>(OnPowerUse);
     SubscribeLocalEvent<CuffableComponent, PsionicUncuffDoAfterEvent>(OnUncuff);
+    SubscribeLocalEvent<PsionicHookPowerComponent, ComponentShutdown>(OnHookPowerShutdown);
 }
+
+private void OnHookPowerShutdown(EntityUid uid, PsionicHookPowerComponent component, ComponentShutdown args)
+{
+    if (component.Hook is not { } hook || Deleted(hook))
+        return;
+
+    QueueDel(hook);
+    component.Hook = null;
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Content.Shared/_White/Psionics/Hook/HookPowerSystem.cs` around lines 22 - 26,
The component stores a spawned/attached hook that is only cleaned up in the
reuse/action branch, so if PsionicHookPowerComponent is removed by any other
path the hook reference and entity remain; add a removal handler that cleans up
the hook when the component is removed: implement a component removal callback
(e.g., OnRemove/OnComponentRemove or subscribe to ComponentRemoveEvent for
PsionicHookPowerComponent) that checks the component's stored hook reference
(the hook entity/field on PsionicHookPowerComponent) and deletes/detaches it and
clears the reference, and ensure any related state (cooldowns/flags) is also
reset; keep the existing handlers OnPowerUse and OnUncuff untouched but ensure
the new removal handler runs for all non-action removals.
🤖 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/_White/Psionics/Hook/HookSystem.cs`:
- Around line 159-168: В блоке обработки возврата крюка предотвратите «перелёт»
через sourcePos: вычисляйте шаг как min(hookComp.ReturnSpeed * frameTime,
distance) и перемещайте снаряд на direction.Normalized() * step вместо прямого
hookComp.ReturnSpeed * frameTime; при достижении нулевой/малой оставшейся
дистанции вызывать GimmeHookBack(uid, hookComp) (как сейчас) и не делать
дальнейшего SetWorldPosition. Ссылки: hookComp.ReturnSpeed, frameTime, distance,
projectilePos, direction.Normalized(), GimmeHookBack и
_transform.SetWorldPosition.
- Around line 79-80: Перед вызовом MathF.Pow при вычислении переменной power в
HookSystem замените прямое использование psionic.CurrentAmplification на
безопасную валидацию: убедитесь, что значение является конечным (не
Infinity/NaN) и неотрицательным (например, с помощью float.IsFinite(...) и
проверки >= 0), при некорректном значении подставьте безопасный дефолт/клиппинг
(0 или минимально допустимое), и только затем вычисляйте power =
MathF.Pow(validAmplification, 1.3f); также добавьте защиту на случай, если
результат MathF.Pow окажется NaN — в таком случае присвойте power = 0 и
логируйте/отлавливайте аномалию; ориентируйтесь на символы
psionic.CurrentAmplification, переменную power и использование MathF.Pow в
HookSystem.

---

Duplicate comments:
In `@Content.Shared/_White/Psionics/Hook/HookPowerSystem.cs`:
- Around line 11-13: Файл с системой SpawnImplantSystem содержит серверную
логику (вызовы SpawnEntity, Del, TryPickupAnyHand, PlayPvs и изменение
component.Hook) и поэтому должен быть перемещён из Content.Shared в
Content.Server; оставьте в Shared только компоненты/ивенты, а сам класс
SpawnImplantSystem перенесите в соответствующий namespace и директорию
Content.Server; убедитесь, что все using/референсы обновлены и что код больше не
компилируется в сборку shared после перемещения.
- Around line 22-26: The component stores a spawned/attached hook that is only
cleaned up in the reuse/action branch, so if PsionicHookPowerComponent is
removed by any other path the hook reference and entity remain; add a removal
handler that cleans up the hook when the component is removed: implement a
component removal callback (e.g., OnRemove/OnComponentRemove or subscribe to
ComponentRemoveEvent for PsionicHookPowerComponent) that checks the component's
stored hook reference (the hook entity/field on PsionicHookPowerComponent) and
deletes/detaches it and clears the reference, and ensure any related state
(cooldowns/flags) is also reset; keep the existing handlers OnPowerUse and
OnUncuff untouched but ensure the new removal handler runs for all non-action
removals.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0b89b5b2-132b-4419-b9ce-0bdf8568d4a4

📥 Commits

Reviewing files that changed from the base of the PR and between fd91c11 and 8a780db.

📒 Files selected for processing (3)
  • Content.Shared/_White/Psionics/Hook/HookPowerSystem.cs
  • Content.Shared/_White/Psionics/Hook/HookSystem.cs
  • Resources/Locale/en-US/_white/abilities/psionic.ftl
✅ Files skipped from review due to trivial changes (1)
  • Resources/Locale/en-US/_white/abilities/psionic.ftl

Comment on lines +79 to +80
var power = MathF.Pow(psionic.CurrentAmplification, 1.3f);
var hookComp = ent.Comp;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In .NET/C#, what does MathF.Powreturn for a negative base with a fractional exponent such asMathF.Pow(-1f, 1.3f)?

💡 Result:

MathF.Pow(-1f, 1.3f) returns Single.NaN (a floating-point “not a number”), because the base is negative and the exponent is a finite non-integer (fractional) value. [1]

Source(s)
[1] Microsoft Learn — MathF.Pow(Single, Single) Method (remarks table: “x < 0 …, y finite non-integer → NaN”). (learn.microsoft.com)

Citations:


🏁 Script executed:

# First, locate the exact file and examine the context around lines 79-80
fd -t f "HookSystem.cs" --exec wc -l {} \;

Repository: WWhiteDreamProject/wwdpublic

Length of output: 127


🏁 Script executed:

# Read the HookSystem.cs file to see the context
cat -n "Content.Shared/_White/Psionics/Hook/HookSystem.cs" | sed -n '70,90p'

Repository: WWhiteDreamProject/wwdpublic

Length of output: 903


🏁 Script executed:

# Check PsionicComponent.cs for CurrentAmplification definition
fd -t f "PsionicComponent.cs" | xargs cat -n | sed -n '150,180p'

Repository: WWhiteDreamProject/wwdpublic

Length of output: 1610


🏁 Script executed:

# Search for any validation or bounds on CurrentAmplification
rg "CurrentAmplification" -A 3 -B 3

Repository: WWhiteDreamProject/wwdpublic

Length of output: 31194


Добавьте валидацию CurrentAmplification перед передачей в MathF.Pow.

Сейчас значение приходит без проверок, и для отрицательной или невалидной амплификации MathF.Pow(..., 1.3f) вернёт NaN. Это сломает физику возврата/притягивания крюка.

Рекомендуемый вариант
-        var power = MathF.Pow(psionic.CurrentAmplification, 1.3f);
+        var amplification = float.IsFinite(psionic.CurrentAmplification)
+            ? MathF.Max(psionic.CurrentAmplification, 0f)
+            : 0f;
+        var power = MathF.Pow(amplification, 1.3f);
📝 Committable suggestion

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

Suggested change
var power = MathF.Pow(psionic.CurrentAmplification, 1.3f);
var hookComp = ent.Comp;
var amplification = float.IsFinite(psionic.CurrentAmplification)
? MathF.Max(psionic.CurrentAmplification, 0f)
: 0f;
var power = MathF.Pow(amplification, 1.3f);
var hookComp = ent.Comp;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Content.Shared/_White/Psionics/Hook/HookSystem.cs` around lines 79 - 80,
Перед вызовом MathF.Pow при вычислении переменной power в HookSystem замените
прямое использование psionic.CurrentAmplification на безопасную валидацию:
убедитесь, что значение является конечным (не Infinity/NaN) и неотрицательным
(например, с помощью float.IsFinite(...) и проверки >= 0), при некорректном
значении подставьте безопасный дефолт/клиппинг (0 или минимально допустимое), и
только затем вычисляйте power = MathF.Pow(validAmplification, 1.3f); также
добавьте защиту на случай, если результат MathF.Pow окажется NaN — в таком
случае присвойте power = 0 и логируйте/отлавливайте аномалию; ориентируйтесь на
символы psionic.CurrentAmplification, переменную power и использование MathF.Pow
в HookSystem.

Comment on lines +159 to +168
if (distance < 0.7f)
{
if (_netManager.IsServer)
GimmeHookBack(uid, hookComp);

continue;
}

var movement = direction.Normalized() * hookComp.ReturnSpeed * frameTime;
_transform.SetWorldPosition(uid, projectilePos + movement);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Зажмите шаг возврата по оставшейся дистанции.

Если hookComp.ReturnSpeed * frameTime окажется больше distance, снаряд перелетит sourcePos, на следующем кадре развернётся и может зациклиться вокруг оружия, так и не попав в ветку возврата боеприпаса.

Возможный вариант
-            var movement = direction.Normalized() * hookComp.ReturnSpeed * frameTime;
-            _transform.SetWorldPosition(uid, projectilePos + movement);
+            var step = hookComp.ReturnSpeed * frameTime;
+            if (step >= distance)
+            {
+                _transform.SetWorldPosition(uid, sourcePos);
+                if (_netManager.IsServer)
+                    GimmeHookBack(uid, hookComp);
+                continue;
+            }
+
+            var movement = direction / distance * step;
+            _transform.SetWorldPosition(uid, projectilePos + movement);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Content.Shared/_White/Psionics/Hook/HookSystem.cs` around lines 159 - 168, В
блоке обработки возврата крюка предотвратите «перелёт» через sourcePos:
вычисляйте шаг как min(hookComp.ReturnSpeed * frameTime, distance) и перемещайте
снаряд на direction.Normalized() * step вместо прямого hookComp.ReturnSpeed *
frameTime; при достижении нулевой/малой оставшейся дистанции вызывать
GimmeHookBack(uid, hookComp) (как сейчас) и не делать дальнейшего
SetWorldPosition. Ссылки: hookComp.ReturnSpeed, frameTime, distance,
projectilePos, direction.Normalized(), GimmeHookBack и
_transform.SetWorldPosition.

@kekoven1

Copy link
Copy Markdown
Contributor Author

я не знаю почему он ругается всё есть всё работает

@kekoven1

kekoven1 commented Jun 6, 2026

Copy link
Copy Markdown
Contributor Author

это делает меня мёртвым капец

@kekoven1

Copy link
Copy Markdown
Contributor Author

портреты кровью рисую

@DVOniksWyvern

Copy link
Copy Markdown
Member

@Remuchi Проверь код, пожалуйста, быстренько. Псионика потом все равно уйдет на переработку, но в принципе идейно - нормально.

@kekoven1 kekoven1 closed this Aug 5, 2026
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