Skip to content

bugfix - #76

Merged
RavenAzala merged 1 commit into
masterfrom
RavenUpstreamNewII
Aug 11, 2026
Merged

bugfix#76
RavenAzala merged 1 commit into
masterfrom
RavenUpstreamNewII

Conversation

@RavenAzala

@RavenAzala RavenAzala commented Aug 11, 2026

Copy link
Copy Markdown

Багфикс
🆑 Ravenreaper

  • add: Добавлен экспериментальный тип боеприпасов.
  • fix: Пофикшен баг Санника, а так же куча других багов.

Summary by CodeRabbit

  • Новые возможности

    • Добавлена поддержка гибридных боеприпасов: оружие может использовать баллистические патроны и энергию.
    • Добавлен новый вариант гауссова оружия с отображением боезапаса и расходом энергии.
    • Для гауссовых снарядов добавлены визуальные эффекты выстрела и попадания.
    • Обновлены параметры и защита различных комплектов силовой брони.
    • Для некоторых дробовиков увеличен пробивающий урон.
  • Изменения

    • Обновлены магазины 2mmEC и связанные боеприпасы.
    • Скорректирована экипировка тяжёлого NCR-бойца.
    • Удалён бронзовый контрактный жетон с карты.

@github-actions

Copy link
Copy Markdown

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

Resources/Textures/Objects/Weapons/Guns/Projectiles/projectiles.rsi

State Old New Status
muzzle_gauss Modified

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

PR добавляет гибридную систему боеприпасов для оружия. Она поддерживает магазин, баллистические патроны, заряд батареи и счётчик боеприпасов. Также обновлены прототипы гауссового оружия, снарядов, дробовиков и силовой брони.

Changes

Гибридная система оружия

Layer / File(s) Summary
Контракт и подключение гибридных боеприпасов
Content.Shared/Weapons/Ranged/Components/HybridAmmoProviderComponent.cs, Content.Server/Weapons/Ranged/Systems/GunSystem.cs, Content.Client/Weapons/Ranged/Systems/GunSystem.cs, Content.Client/Weapons/Ranged/Systems/GunSystem.Hybrid.cs
Добавлен HybridAmmoProviderComponent с сетевыми полями прототипа, вместимости, количества, стоимости выстрела, батареи и слота магазина. Сервер и клиент подключают обработчики гибридных боеприпасов.
Расход ресурсов и запуск снаряда
Content.Server/Weapons/Ranged/Systems/GunSystem.Hybrid.cs, Content.Server/Weapons/Ranged/Systems/GunSystem.cs, Content.Shared/Weapons/Ranged/Components/AmmoComponent.cs, Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Shotguns/shotguns.yml
Система проверяет магазин, патроны и заряд батареи. После успешной проверки она расходует ресурсы, создаёт снаряд и обновляет счётчик. Запуск картриджей и AmmoComponent использует общий путь CreateAndFireProjectiles.
Прототипы гауссового оружия и боеприпасов
Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Ammunition/Magazines/2mmEC.yml, Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Snipers/snipers.yml, Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/2mmEC.yml, Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Projectiles/impacts.yml, Resources/Prototypes/_Nuclear14/tags.yml
Добавлены энергетическая ячейка-магазин, гибридная конфигурация M72 Gauss rifle, визуальные эффекты снаряда и эффект попадания BulletGaussImpactEffect. Добавлены теги MisfitsPipBoy и N14GaussCell.

Параметры силовой брони

Layer / File(s) Summary
Обновление защиты силовой брони
Resources/Prototypes/_Nuclear14/Entities/Clothing/OuterClothing/powerarmor.yml, Resources/Prototypes/Corvax/Entities/Clothing/OuterClothing/powerarmor.yml
Для вариантов силовой брони удалены компоненты целостности. Обновлены коэффициенты защиты, плоские снижения урона, отражение, взрывоустойчивость и параметры скорости.

Прочие изменения прототипов

Layer / File(s) Summary
Точечные изменения ресурсов и снаряжения
Resources/Maps/N14/SunnyvaleSurface.yml, Resources/Prototypes/_Misfits/Entities/Objects/Misc/campfire_fuel.yml, Resources/Prototypes/_Misfits/Roles/Jobs/NCR/ncr_heavy_trooper.yml, Resources/Prototypes/_Nuclear14/Loadouts/Fractions/NCRLoadout/loadouts_followers.yml
Удалён объект с карты. Исправлен путь к спрайту костра. Из стартового снаряжения NCR Heavy Trooper удалены миниган и дополнительный магазин. Изменена категория loadout.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant GunSystem
  participant HybridAmmoProviderComponent
  participant Magazine
  participant Battery
  participant Projectile
  GunSystem->>HybridAmmoProviderComponent: запрашивает магазин и количество боеприпасов
  HybridAmmoProviderComponent->>Magazine: проверяет баллистические патроны
  HybridAmmoProviderComponent->>Battery: проверяет и расходует заряд
  HybridAmmoProviderComponent->>Projectile: создаёт снаряд
  HybridAmmoProviderComponent->>GunSystem: обновляет состояние и счётчик
Loading

Possibly related PRs

Suggested reviewers: remuchi, sleepyyapril

Poem

Я兔ик вижу: гаусс стреляет,
Батарея заряд считает.
Магазин патрон хранит,
Броня удары отразит.
Прыг-скок — прототип готов,
В норе тихонько ждёт ревью.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

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.
Title check ❓ Inconclusive Заголовок «bugfix» связан с целью исправления ошибок, но не описывает основное изменение — добавление экспериментального типа боеприпасов. Укажите конкретное основное изменение, например: «Добавить поддержку гибридных боеприпасов для винтовки M72 Gauss».
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch RavenUpstreamNewII

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
Content.Server/Weapons/Ranged/Systems/GunSystem.cs (2)

183-197: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Dirty вызывается после удаления сущности.

Если cartridge.DeleteOnSpawn равно true, то на строке 184 сущность удаляется через Del(ent.Value). Затем строка 196 вызывает Dirty(ent!.Value, cartridge) для уже удалённой сущности. Это приводит к ошибке или к работе с невалидным EntityUid.

Вызывайте Dirty до удаления или пропускайте его для удалённых сущностей.

🐛 Предлагаемое исправление
                         SetCartridgeSpent(ent.Value, cartridge, true);
 
+                        Dirty(ent.Value, cartridge);
+
                         if (cartridge.DeleteOnSpawn)
                             Del(ent.Value);
                     }
                     else
                     {
                         userImpulse = false;
                         Audio.PlayPredicted(gun.SoundEmpty, gunUid, user);
                     }
 
+                    if (Deleted(ent!.Value))
+                        break;
+
                     // Something like ballistic might want to leave it in the container still
                     if (!cartridge.DeleteOnSpawn && !Containers.IsEntityInContainer(ent!.Value))
                         EjectCartridge(ent.Value, angle);
-
-                    Dirty(ent!.Value, cartridge);
                     break;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Content.Server/Weapons/Ranged/Systems/GunSystem.cs` around lines 183 - 197,
Update the cartridge handling flow around Del and Dirty so Dirty is not called
with an entity that has already been deleted. Move Dirty before Del(ent.Value),
or conditionally skip it when cartridge.DeleteOnSpawn is true, while preserving
the existing ejection behavior.

176-179: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Передавайте в событии на патрон только снаряды текущего патрона.

События на строках 176 и 339 поднимаются на разных сущностях. Первое обрабатывает ChemicalAmmoSystem, второе — подписчики оружия. Однако shotProjectiles содержит снаряды всех итераций. Поэтому ChemicalAmmoSystem может повторно обработать предыдущие снаряды и списать раствор текущего патрона некорректно. Используйте отдельный список для каждого патрона, а агрегированный список оставьте для события оружия.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Content.Server/Weapons/Ranged/Systems/GunSystem.cs` around lines 176 - 179, В
`GunSystem` разделите списки снарядов по назначению: перед событием
`AmmoShotEvent` на сущности текущего патрона передавайте только снаряды этой
итерации, создав или очищая отдельный список для каждого патрона. Сохраните
`shotProjectiles` как агрегированный список для последующего события оружия на
строке 339.
Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Ammunition/Magazines/2mmEC.yml (1)

42-49: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Замените обычный провайдер для всех оружий с N14MagazineRifle2mmEC.

N14WeaponGaussRifle использует MagazineAmmoProvider. N14WeaponSniperM72GaussRifleSirius67 наследует ChamberMagazineAmmoProvider через N14WeaponRifleBase и BaseWeaponRifle. Эти провайдеры не расходуют BatteryComponent, поэтому оружие стреляет при разряженном магазине.

Используйте HybridAmmoProvider с proto: N14Bullet2mmEC, fireCost и magazineSlot: gun_magazine. Удалите конфликтующий обычный провайдер.

N14MagazineRifle2mmECOld внешних ссылок не имеет. Удалите его, если legacy-прототип не нужен.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Ammunition/Magazines/2mmEC.yml`
around lines 42 - 49, Замените обычные провайдеры боеприпасов у
N14WeaponGaussRifle и унаследованного N14WeaponSniperM72GaussRifleSirius67 на
HybridAmmoProvider с proto N14Bullet2mmEC, fireCost и magazineSlot gun_magazine;
удалите конфликтующие MagazineAmmoProvider/ChamberMagazineAmmoProvider. Удалите
N14MagazineRifle2mmECOld, поскольку внешних ссылок на него нет.
🧹 Nitpick comments (3)
Resources/Prototypes/_Nuclear14/Entities/Clothing/OuterClothing/powerarmor.yml (1)

9-12: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Удалите или перепишите комментарий о PowerArmorIntegrity.

N14ClothingOuterPowerArmorT45 больше не содержит PowerArmorIntegrity. Комментарий описывает отдельный запас целостности, снятие ArmorComponent и ремонт этой механики. Эти утверждения больше не соответствуют прототипу. В тексте также есть опечатка rityinteg.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@Resources/Prototypes/_Nuclear14/Entities/Clothing/OuterClothing/powerarmor.yml`
around lines 9 - 12, Удалите устаревший комментарий о PowerArmorIntegrity над
N14ClothingOuterPowerArmorT45 либо перепишите его так, чтобы он описывал только
фактически поддерживаемую механику прототипа; уберите упоминания отдельного
запаса целостности, снятия ArmorComponent, поглощения урона и ремонта, а также
исправьте опечатку rityinteg.
Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Ammunition/Magazines/2mmEC.yml (1)

90-90: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Уберите рабочие заметки из прототипа.

Строка 90 содержит незавершённую заметку # или BaseMagazineRifle. Строка 108 содержит заметку # УДАЛЯЕМ ProjectileBatteryAmmoProvider. Эти комментарии описывают процесс разработки, а не итоговую конфигурацию.

Also applies to: 108-108

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Ammunition/Magazines/2mmEC.yml`
at line 90, Remove the unfinished development notes from the ammunition magazine
prototype: delete the inline “или BaseMagazineRifle” comment on the parent
declaration and the “УДАЛЯЕМ ProjectileBatteryAmmoProvider” comment near
ProjectileBatteryAmmoProvider, leaving the functional prototype configuration
unchanged.
Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Projectiles/impacts.yml (1)

57-73: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

BulletGaussImpactEffect полностью дублирует BulletPlasmaImpactEffect.

Обе сущности используют plasma.rsi со состоянием impact_plasma, одинаковое время жизни и одинаковые компоненты. Разница только в идентификаторе.

Есть два решения:

  • Задайте гауссовый спрайт, например состояние из projectiles.rsi, по аналогии с GaussMuzzleFlashEffect на строках 39-55.
  • Либо используйте BulletPlasmaImpactEffect в Projectiles/2mmEC.yml и удалите дубликат.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Projectiles/impacts.yml`
around lines 57 - 73, Устраните дублирование между BulletGaussImpactEffect и
BulletPlasmaImpactEffect: либо назначьте BulletGaussImpactEffect отдельный
гауссовый спрайт и состояние по аналогии с GaussMuzzleFlashEffect, либо замените
его использование в 2mmEC.yml на BulletPlasmaImpactEffect и удалите дубликат.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Content.Server/Weapons/Ranged/Systems/GunSystem.Hybrid.cs`:
- Around line 35-104: Update OnHybridTakeAmmo to process up to args.Shots
requests instead of always creating one projectile. Wrap the ammo, energy,
projectile creation, and args.Ammo addition flow in a loop, stopping when
ammunition or battery charge is insufficient; preserve the existing failure
reason and ensure each successful iteration consumes one round, spends FireCost,
and updates the ballistic state appropriately.
- Around line 60-70: Синхронизируйте проверку энергии в обработчике стрельбы с
контрактом HybridAmmoProviderComponent: используйте component.BatteryEntity, а
при его отсутствии — magazineEntity.Value как источник BatteryComponent.
Обновите получение батареи и связанные проверки в текущем участке, чтобы заряд и
списание обращались к выбранной сущности, сохранив существующие причины отказа.
- Around line 72-88: В блоке расходования боеприпаса в GunSystem удалите прямое
изменение ballistic.Entities: передайте последний патрон в Containers.Remove и
проверьте успешность операции. Учитывайте UnspawnedCount только если
контейнерных сущностей нет; при неуспешном удалении не изменяйте счётчики и
обработайте отсутствие боеприпаса через существующий gun-no-ammo путь.
- Line 41: Добавьте ключи локализации gun-no-magazine, gun-no-ammo,
gun-no-battery и gun-not-enough-energy во все необходимые .ftl-файлы, включая
сообщения для оружия и использования в SharedFlamerAmmoSystem.cs, с корректными
переводами и доступностью для Loc.GetString.

In `@Content.Shared/Weapons/Ranged/Components/HybridAmmoProviderComponent.cs`:
- Around line 13-28: Состояние боеприпасов HybridAmmoProviderComponent не
синхронизируется с клиентом. В
Content.Shared/Weapons/Ranged/Components/HybridAmmoProviderComponent.cs:13-28
сделайте Count, Capacity и BatteryEntity единственным источником состояния; в
Content.Client/Weapons/Ranged/Systems/GunSystem.Hybrid.cs:14-22 замените
локальное событие RaiseLocalEvent чтением сетевых полей компонента либо
перенесите GetAmmoCountEvent в общий код; в
Content.Server/Weapons/Ranged/Systems/GunSystem.Hybrid.cs:60-70 используйте
component.BatteryEntity для выбора источника заряда, обновляйте Count и Capacity
после выстрела и вызывайте Dirty.
- Around line 13-28: Remove the unused Capacity, Count, and BatteryEntity fields
from HybridAmmoProviderComponent, including their DataField and
AutoNetworkedField attributes. Keep MagazineSlot because it is used for
automatic magazine loading, and do not introduce runtime-only EntityUid state
unless it is actually required; if retained, remove its DataField attribute.

In
`@Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Ammunition/Magazines/2mmEC.yml`:
- Around line 92-100: В конфигурации спрайта удалите компонент PowerCellVisuals,
поскольку его unshadedLayer и baseLayer ссылаются на отсутствующие
PowerCellVisualLayers; сохраните существующие слои enum.GunVisualLayers.Base и
enum.GunVisualLayers.Mag без изменений.

In
`@Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/2mmEC.yml`:
- Around line 20-22: Update the Sprite definition for the projectile so its
comment accurately describes the configured `projectiles2.rsi` `buckshot` state,
or change the `sprite` and `state` values to the intended plasma-bolt asset.
Ensure the documentation and actual sprite configuration consistently identify
the projectile graphic.

In
`@Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Snipers/snipers.yml`:
- Around line 826-830: Remove the obsolete N14WeaponSniperM72GaussRifleSirius67
prototype if it is no longer needed; otherwise rename its id to a meaningful
identifier and add suffix: Old so it is clearly distinguished from the new M72
Gauss rifle in spawn menus.
- Around line 901-965: В сущности N14WeaponSniperM72GaussRifleSirius
восстановите настройки базовой винтовки: добавьте GunDamageBonus с бонусом
Piercing 38, а также унаследованные через BaseWeaponRifle компоненты
FollowDistance и GunRequiresWield. Не дублируйте уже явно заданные Sprite, Item,
ContainerContainer, MagazineVisuals и Appearance.

---

Outside diff comments:
In `@Content.Server/Weapons/Ranged/Systems/GunSystem.cs`:
- Around line 183-197: Update the cartridge handling flow around Del and Dirty
so Dirty is not called with an entity that has already been deleted. Move Dirty
before Del(ent.Value), or conditionally skip it when cartridge.DeleteOnSpawn is
true, while preserving the existing ejection behavior.
- Around line 176-179: В `GunSystem` разделите списки снарядов по назначению:
перед событием `AmmoShotEvent` на сущности текущего патрона передавайте только
снаряды этой итерации, создав или очищая отдельный список для каждого патрона.
Сохраните `shotProjectiles` как агрегированный список для последующего события
оружия на строке 339.

In
`@Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Ammunition/Magazines/2mmEC.yml`:
- Around line 42-49: Замените обычные провайдеры боеприпасов у
N14WeaponGaussRifle и унаследованного N14WeaponSniperM72GaussRifleSirius67 на
HybridAmmoProvider с proto N14Bullet2mmEC, fireCost и magazineSlot gun_magazine;
удалите конфликтующие MagazineAmmoProvider/ChamberMagazineAmmoProvider. Удалите
N14MagazineRifle2mmECOld, поскольку внешних ссылок на него нет.

---

Nitpick comments:
In
`@Resources/Prototypes/_Nuclear14/Entities/Clothing/OuterClothing/powerarmor.yml`:
- Around line 9-12: Удалите устаревший комментарий о PowerArmorIntegrity над
N14ClothingOuterPowerArmorT45 либо перепишите его так, чтобы он описывал только
фактически поддерживаемую механику прототипа; уберите упоминания отдельного
запаса целостности, снятия ArmorComponent, поглощения урона и ремонта, а также
исправьте опечатку rityinteg.

In
`@Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Ammunition/Magazines/2mmEC.yml`:
- Line 90: Remove the unfinished development notes from the ammunition magazine
prototype: delete the inline “или BaseMagazineRifle” comment on the parent
declaration and the “УДАЛЯЕМ ProjectileBatteryAmmoProvider” comment near
ProjectileBatteryAmmoProvider, leaving the functional prototype configuration
unchanged.

In
`@Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Projectiles/impacts.yml`:
- Around line 57-73: Устраните дублирование между BulletGaussImpactEffect и
BulletPlasmaImpactEffect: либо назначьте BulletGaussImpactEffect отдельный
гауссовый спрайт и состояние по аналогии с GaussMuzzleFlashEffect, либо замените
его использование в 2mmEC.yml на BulletPlasmaImpactEffect и удалите дубликат.
🪄 Autofix

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 Plus

Run ID: 04195ca6-5621-4d94-8acb-ce450f859725

📥 Commits

Reviewing files that changed from the base of the PR and between a3d441d and 40273fe.

⛔ Files ignored due to path filters (1)
  • Resources/Textures/Objects/Weapons/Guns/Projectiles/projectiles.rsi/muzzle_gauss.png is excluded by !**/*.png
📒 Files selected for processing (18)
  • Content.Client/Weapons/Ranged/Systems/GunSystem.Hybrid.cs
  • Content.Client/Weapons/Ranged/Systems/GunSystem.cs
  • Content.Server/Weapons/Ranged/Systems/GunSystem.Hybrid.cs
  • Content.Server/Weapons/Ranged/Systems/GunSystem.cs
  • Content.Shared/Weapons/Ranged/Components/AmmoComponent.cs
  • Content.Shared/Weapons/Ranged/Components/HybridAmmoProviderComponent.cs
  • Resources/Maps/N14/SunnyvaleSurface.yml
  • Resources/Prototypes/Corvax/Entities/Clothing/OuterClothing/powerarmor.yml
  • Resources/Prototypes/_Misfits/Entities/Objects/Misc/campfire_fuel.yml
  • Resources/Prototypes/_Misfits/Roles/Jobs/NCR/ncr_heavy_trooper.yml
  • Resources/Prototypes/_Nuclear14/Entities/Clothing/OuterClothing/powerarmor.yml
  • Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Ammunition/Magazines/2mmEC.yml
  • Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/2mmEC.yml
  • Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Projectiles/impacts.yml
  • Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Shotguns/shotguns.yml
  • Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Snipers/snipers.yml
  • Resources/Prototypes/_Nuclear14/Loadouts/Fractions/NCRLoadout/loadouts_followers.yml
  • Resources/Prototypes/_Nuclear14/tags.yml
💤 Files with no reviewable changes (2)
  • Resources/Prototypes/_Misfits/Roles/Jobs/NCR/ncr_heavy_trooper.yml
  • Resources/Maps/N14/SunnyvaleSurface.yml

Comment on lines +35 to +104
private void OnHybridTakeAmmo(EntityUid uid, HybridAmmoProviderComponent component, TakeAmmoEvent args)
{
// 1. Получаем магазин из слота
var magazineEntity = GetMagazineEntity(uid);
if (magazineEntity == null)
{
args.Reason = Loc.GetString("gun-no-magazine");
return;
}

// 2. Проверяем патроны (BallisticAmmoProvider)
if (!TryComp<BallisticAmmoProviderComponent>(magazineEntity.Value, out var ballistic))
{
args.Reason = Loc.GetString("gun-no-ammo");
return;
}

// Получаем текущее количество патронов
var currentCount = GetBallisticShots(ballistic);
if (currentCount <= 0)
{
args.Reason = Loc.GetString("gun-no-ammo");
return;
}

// 3. Проверяем энергию (BatteryComponent)
if (!TryComp<BatteryComponent>(magazineEntity.Value, out var battery))
{
args.Reason = Loc.GetString("gun-no-battery");
return;
}
if (battery.CurrentCharge < component.FireCost)
{
args.Reason = Loc.GetString("gun-not-enough-energy");
return;
}

// 4. Тратим патрон: удаляем последний патрон из контейнера или уменьшаем UnspawnedCount
if (ballistic.Entities.Count > 0)
{
var lastEntity = ballistic.Entities[^1];
ballistic.Entities.RemoveAt(ballistic.Entities.Count - 1);
Containers.Remove(lastEntity, ballistic.Container);
QueueDel(lastEntity); // Удаляем сущность патрона (гильза не нужна)
}
else if (ballistic.UnspawnedCount > 0)
{
ballistic.UnspawnedCount--;
}
else
{
args.Reason = Loc.GetString("gun-no-ammo");
return;
}

// 5. Тратим энергию
_battery.UseCharge(magazineEntity.Value, component.FireCost);

// 6. Создаём снаряд в координатах выстрела
var fromCoordinates = args.Coordinates;
var mapCoords = fromCoordinates.ToMap(EntityManager, TransformSystem);
var projectile = Spawn(component.Prototype, mapCoords);

// 7. Добавляем снаряд в список для выстрела (основной GunSystem обработает его)
args.Ammo.Add((projectile, EnsureShootable(projectile)));

// 8. Обновляем счётчик на клиенте
Dirty(magazineEntity.Value, ballistic);
UpdateAmmoCount(uid);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Обработчик игнорирует args.Shots.

TakeAmmoEvent.Shots задаёт количество запрошенных выстрелов. Другие провайдеры (например, BallisticAmmoProvider) выдают до Shots единиц боеприпасов за одно событие. Здесь всегда выдаётся ровно один снаряд. При FullAuto или высоком fireRate оружие будет стрелять медленнее ожидаемого.

Оберните шаги 2–7 в цикл по args.Shots и прерывайте его при нехватке патронов или энергии.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Content.Server/Weapons/Ranged/Systems/GunSystem.Hybrid.cs` around lines 35 -
104, Update OnHybridTakeAmmo to process up to args.Shots requests instead of
always creating one projectile. Wrap the ammo, energy, projectile creation, and
args.Ammo addition flow in a loop, stopping when ammunition or battery charge is
insufficient; preserve the existing failure reason and ensure each successful
iteration consumes one round, spends FireCost, and updates the ballistic state
appropriately.

var magazineEntity = GetMagazineEntity(uid);
if (magazineEntity == null)
{
args.Reason = Loc.GetString("gun-no-magazine");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Проверить наличие ключей локализации
for key in gun-no-magazine gun-no-ammo gun-no-battery gun-not-enough-energy; do
  echo "=== $key ==="
  rg -n "^${key}\s*=" --glob '*.ftl' || echo "НЕ НАЙДЕН"
done

Repository: Echo-DreamMaker/Sirius_Fallout

Length of output: 305


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- gun key usages ---'
rg -n --hidden --glob '!*.git/*' 'gun-(no-magazine|no-ammo|no-battery|not-enough-energy)' .

printf '%s\n' '--- localization files and nearby gun entries ---'
git ls-files '*.ftl' | head -80
rg -n -i --glob '*.ftl' 'gun|magazine|battery|enough.energy|no.ammo' . | head -200

printf '%s\n' '--- relevant source context ---'
sed -n '1,110p' Content.Server/Weapons/Ranged/Systems/GunSystem.Hybrid.cs

Repository: Echo-DreamMaker/Sirius_Fallout

Length of output: 37095


Добавьте ключи локализации для сообщений оружия.

Ключи gun-no-magazine, gun-no-ammo, gun-no-battery и gun-not-enough-energy отсутствуют во всех .ftl. Они также используются в SharedFlamerAmmoSystem.cs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Content.Server/Weapons/Ranged/Systems/GunSystem.Hybrid.cs` at line 41,
Добавьте ключи локализации gun-no-magazine, gun-no-ammo, gun-no-battery и
gun-not-enough-energy во все необходимые .ftl-файлы, включая сообщения для
оружия и использования в SharedFlamerAmmoSystem.cs, с корректными переводами и
доступностью для Loc.GetString.

Comment on lines +60 to +70
// 3. Проверяем энергию (BatteryComponent)
if (!TryComp<BatteryComponent>(magazineEntity.Value, out var battery))
{
args.Reason = Loc.GetString("gun-no-battery");
return;
}
if (battery.CurrentCharge < component.FireCost)
{
args.Reason = Loc.GetString("gun-not-enough-energy");
return;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Батарея берётся только из магазина.

component.BatteryEntity не используется. Заряд читается из BatteryComponent магазина. Комментарий в HybridAmmoProviderComponent описывает другое поведение: «если null, используем свой uid». Приведите код и комментарий к одному поведению.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Content.Server/Weapons/Ranged/Systems/GunSystem.Hybrid.cs` around lines 60 -
70, Синхронизируйте проверку энергии в обработчике стрельбы с контрактом
HybridAmmoProviderComponent: используйте component.BatteryEntity, а при его
отсутствии — magazineEntity.Value как источник BatteryComponent. Обновите
получение батареи и связанные проверки в текущем участке, чтобы заряд и списание
обращались к выбранной сущности, сохранив существующие причины отказа.

Comment on lines +72 to +88
// 4. Тратим патрон: удаляем последний патрон из контейнера или уменьшаем UnspawnedCount
if (ballistic.Entities.Count > 0)
{
var lastEntity = ballistic.Entities[^1];
ballistic.Entities.RemoveAt(ballistic.Entities.Count - 1);
Containers.Remove(lastEntity, ballistic.Container);
QueueDel(lastEntity); // Удаляем сущность патрона (гильза не нужна)
}
else if (ballistic.UnspawnedCount > 0)
{
ballistic.UnspawnedCount--;
}
else
{
args.Reason = Loc.GetString("gun-no-ammo");
return;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Не изменяйте ballistic.Entities напрямую.

Containers.Remove сам поднимает EntRemovedFromContainerMessage, а BallisticAmmoProviderComponent обрабатывает это сообщение и удаляет сущность из Entities. Здесь список изменяется вручную до вызова Containers.Remove. Если Containers.Remove вернёт false, патрон исчезнет из счётчика, но останется в контейнере. Это рассинхронизирует состояние магазина.

Удаляйте патрон только через контейнер и проверяйте результат.

🐛 Предлагаемое исправление
         if (ballistic.Entities.Count > 0)
         {
             var lastEntity = ballistic.Entities[^1];
-            ballistic.Entities.RemoveAt(ballistic.Entities.Count - 1);
-            Containers.Remove(lastEntity, ballistic.Container);
+            if (!Containers.Remove(lastEntity, ballistic.Container))
+            {
+                args.Reason = Loc.GetString("gun-no-ammo");
+                return;
+            }
             QueueDel(lastEntity); // Удаляем сущность патрона (гильза не нужна)
         }
📝 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
// 4. Тратим патрон: удаляем последний патрон из контейнера или уменьшаем UnspawnedCount
if (ballistic.Entities.Count > 0)
{
var lastEntity = ballistic.Entities[^1];
ballistic.Entities.RemoveAt(ballistic.Entities.Count - 1);
Containers.Remove(lastEntity, ballistic.Container);
QueueDel(lastEntity); // Удаляем сущность патрона (гильза не нужна)
}
else if (ballistic.UnspawnedCount > 0)
{
ballistic.UnspawnedCount--;
}
else
{
args.Reason = Loc.GetString("gun-no-ammo");
return;
}
// 4. Тратим патрон: удаляем последний патрон из контейнера или уменьшаем UnspawnedCount
if (ballistic.Entities.Count > 0)
{
var lastEntity = ballistic.Entities[^1];
if (!Containers.Remove(lastEntity, ballistic.Container))
{
args.Reason = Loc.GetString("gun-no-ammo");
return;
}
QueueDel(lastEntity); // Удаляем сущность патрона (гильза не нужна)
}
else if (ballistic.UnspawnedCount > 0)
{
ballistic.UnspawnedCount--;
}
else
{
args.Reason = Loc.GetString("gun-no-ammo");
return;
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Content.Server/Weapons/Ranged/Systems/GunSystem.Hybrid.cs` around lines 72 -
88, В блоке расходования боеприпаса в GunSystem удалите прямое изменение
ballistic.Entities: передайте последний патрон в Containers.Remove и проверьте
успешность операции. Учитывайте UnspawnedCount только если контейнерных
сущностей нет; при неуспешном удалении не изменяйте счётчики и обработайте
отсутствие боеприпаса через существующий gun-no-ammo путь.

Comment on lines +13 to +28
[DataField("capacity"), AutoNetworkedField]
public int Capacity = 10;

[DataField("count"), AutoNetworkedField]
public int Count = 10;

[DataField("fireCost")]
public float FireCost = 100f;

// Ссылка на батарею (если null, используем свой uid)
[DataField("battery")]
public EntityUid? BatteryEntity;

// Ссылка на слот магазина (для автоматической загрузки патронов)
[DataField("magazineSlot")]
public string? MagazineSlot;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Контракт HybridAmmoProviderComponent не реализован: состояние боеприпасов не доходит до клиента. Компонент объявляет сетевые поля Count, Capacity и поле BatteryEntity, но серверная логика их не заполняет и не читает. Из-за этого клиентский счётчик боеприпасов всегда показывает 0.

  • Content.Shared/Weapons/Ranged/Components/HybridAmmoProviderComponent.cs#L13-L28: либо удалите Capacity, Count и BatteryEntity, либо сделайте их единственным источником состояния для клиента.
  • Content.Client/Weapons/Ranged/Systems/GunSystem.Hybrid.cs#L14-L22: замените RaiseLocalEvent(uid, ref ev, false) на чтение сетевых полей компонента, либо перенесите обработчик GetAmmoCountEvent в общий код.
  • Content.Server/Weapons/Ranged/Systems/GunSystem.Hybrid.cs#L60-L70: используйте component.BatteryEntity при выборе источника заряда и обновляйте Count/Capacity с вызовом Dirty после каждого выстрела.
📍 Affects 3 files
  • Content.Shared/Weapons/Ranged/Components/HybridAmmoProviderComponent.cs#L13-L28 (this comment)
  • Content.Client/Weapons/Ranged/Systems/GunSystem.Hybrid.cs#L14-L22
  • Content.Server/Weapons/Ranged/Systems/GunSystem.Hybrid.cs#L60-L70
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Content.Shared/Weapons/Ranged/Components/HybridAmmoProviderComponent.cs`
around lines 13 - 28, Состояние боеприпасов HybridAmmoProviderComponent не
синхронизируется с клиентом. В
Content.Shared/Weapons/Ranged/Components/HybridAmmoProviderComponent.cs:13-28
сделайте Count, Capacity и BatteryEntity единственным источником состояния; в
Content.Client/Weapons/Ranged/Systems/GunSystem.Hybrid.cs:14-22 замените
локальное событие RaiseLocalEvent чтением сетевых полей компонента либо
перенесите GetAmmoCountEvent в общий код; в
Content.Server/Weapons/Ranged/Systems/GunSystem.Hybrid.cs:60-70 используйте
component.BatteryEntity для выбора источника заряда, обновляйте Count и Capacity
после выстрела и вызывайте Dirty.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Уберите неиспользуемые поля или начните их использовать.

Поля Capacity, Count и BatteryEntity не читаются ни серверным GunSystem.Hybrid.cs, ни клиентским. Счётчик боеприпасов берётся из BallisticAmmoProviderComponent магазина, а заряд — из BatteryComponent магазина. Сетевая синхронизация Capacity и Count создаёт мёртвое состояние: значения из прототипа (10/10) никогда не совпадут с реальным количеством патронов, и будущий код может прочитать их как истину.

Дополнительно: EntityUid в DataField не задаётся из YAML-прототипа. Если поле нужно только в рантайме, объявите его без DataField.

♻️ Предлагаемое изменение
-    [DataField("capacity"), AutoNetworkedField]
-    public int Capacity = 10;
-
-    [DataField("count"), AutoNetworkedField]
-    public int Count = 10;
-
     [DataField("fireCost")]
     public float FireCost = 100f;
 
-    // Ссылка на батарею (если null, используем свой uid)
-    [DataField("battery")]
-    public EntityUid? BatteryEntity;
+    // Ссылка на батарею (если null, используем магазин)
+    public EntityUid? BatteryEntity;
 
     // Ссылка на слот магазина (для автоматической загрузки патронов)
     [DataField("magazineSlot")]
     public string? MagazineSlot;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Content.Shared/Weapons/Ranged/Components/HybridAmmoProviderComponent.cs`
around lines 13 - 28, Remove the unused Capacity, Count, and BatteryEntity
fields from HybridAmmoProviderComponent, including their DataField and
AutoNetworkedField attributes. Keep MagazineSlot because it is used for
automatic magazine loading, and do not introduce runtime-only EntityUid state
unless it is actually required; if retained, remove its DataField attribute.

Comment on lines +92 to +100
- type: Sprite
netsync: false
sprite: _Nuclear14/Objects/Weapons/Guns/Ammunition/Magazines/2mmEC/2mmriflemag.rsi
layers:
- state: base
map: ["enum.GunVisualLayers.Base"]
- state: mag-1
map: ["enum.GunVisualLayers.Mag"]
scale: 0.60, 0.60

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

PowerCellVisuals ссылается на несуществующие слои спрайта.

Компонент PowerCellVisuals задаёт unshadedLayer: enum.PowerCellVisualLayers.Unshaded и baseLayer: enum.PowerCellVisualLayers.Base. Слои спрайта на строках 96-99 объявлены с ключами enum.GunVisualLayers.Base и enum.GunVisualLayers.Mag. Слои PowerCellVisualLayers отсутствуют. Система визуализации не найдёт эти слои и выдаст ошибку или проигнорирует отображение заряда.

Удалите PowerCellVisuals либо добавьте соответствующие слои в Sprite.

🐛 Предлагаемое исправление
   - type: Appearance
-  - type: PowerCellVisuals
-    unshadedLayer: enum.PowerCellVisualLayers.Unshaded
-    baseLayer: enum.PowerCellVisualLayers.Base
   - type: Riggable

Also applies to: 137-141

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Ammunition/Magazines/2mmEC.yml`
around lines 92 - 100, В конфигурации спрайта удалите компонент
PowerCellVisuals, поскольку его unshadedLayer и baseLayer ссылаются на
отсутствующие PowerCellVisualLayers; сохраните существующие слои
enum.GunVisualLayers.Base и enum.GunVisualLayers.Mag без изменений.

Comment on lines +20 to +22
- type: Sprite #Misfits Fix — was using stretched ballistic bullet sprite (projectiles2.rsi 'bullet' scale 1.2,0.5). Now uses the proper plasma bolt from plasma.rsi.
sprite: Objects/Weapons/Guns/Projectiles/projectiles2.rsi
state: buckshot

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Комментарий противоречит конфигурации спрайта.

Комментарий говорит: спрайт теперь берётся из plasma.rsi. Фактически задан sprite: Objects/Weapons/Guns/Projectiles/projectiles2.rsi и state: buckshot. Состояние buckshot — это дробь, а не гауссовая пуля.

Приведите комментарий в соответствие с кодом или укажите нужный спрайт.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/2mmEC.yml`
around lines 20 - 22, Update the Sprite definition for the projectile so its
comment accurately describes the configured `projectiles2.rsi` `buckshot` state,
or change the `sprite` and `state` values to the intended plasma-bolt asset.
Ensure the documentation and actual sprite configuration consistently identify
the projectile graphic.

Comment on lines 826 to 830
- type: entity
name: M72 Gauss rifle
parent: N14WeaponRifleBase
id: N14WeaponSniperM72GaussRifleSirius
id: N14WeaponSniperM72GaussRifleSirius67
description: "An anti-materiel rifle with an ergonomic, sleek, skeletonized design. Simply looking at it can you tell it'll rip some limbs apart. Uses .50 anti-material ammo."

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Идентификатор N14WeaponSniperM72GaussRifleSirius67 выглядит как временная заглушка.

Суффикс 67 не несёт смысла и не соответствует соглашению об именовании в файле. Старая сущность остаётся доступной в меню спавна и дублирует новую по имени «M72 Gauss rifle». Игроки и мапперы не смогут их различить.

Есть два решения:

  • Удалите старый прототип, если он больше не нужен.
  • Либо дайте ему понятный идентификатор и суффикс suffix: Old, чтобы отличать его в меню.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Snipers/snipers.yml`
around lines 826 - 830, Remove the obsolete N14WeaponSniperM72GaussRifleSirius67
prototype if it is no longer needed; otherwise rename its id to a meaningful
identifier and add suffix: Old so it is clearly distinguished from the new M72
Gauss rifle in spawn menus.

Comment on lines +901 to +965
- type: entity
name: M72 Gauss rifle
parent: BaseItem
id: N14WeaponSniperM72GaussRifleSirius
description: An advanced gauss rifle that consumes both energy and 2mmEC ammunition.
components:
- type: Clothing
sprite: _Nuclear14/Objects/Weapons/Guns/Snipers/gaussrifle.rsi
quickEquip: false
slots:
- Back
- suitStorage
- type: Sprite
sprite: _Nuclear14/Objects/Weapons/Guns/Snipers/gaussrifle.rsi
layers:
- state: base
map: ["enum.GunVisualLayers.Base"]
- state: mag-0
map: ["enum.GunVisualLayers.Mag"]
- type: Item
size: Huge
- type: Wieldable
wieldedSpeedModifier: 0.75
- type: GunWieldBonus
minAngle: -23
maxAngle: -104
- type: HybridAmmoProvider
proto: N14Bullet2mmEC
fireCost: 50
magazineSlot: gun_magazine
- type: Gun
minAngle: 24
maxAngle: 60
angleIncrease: 4
angleDecay: 16
fireRate: 1.5
soundGunshot:
path: /Audio/Weapons/Guns/Gunshots/GaussRifle_SingleShot_1.ogg
soundEmpty:
path: /Audio/Weapons/Guns/Empty/empty.ogg
selectedMode: SemiAuto
availableModes:
- SemiAuto
- type: ItemSlots
slots:
gun_magazine:
name: Magazine
startingItem: N14MagazineRifle2mmEC
insertSound: /Audio/Weapons/Guns/MagIn/batrifle_magin.ogg
ejectSound: /Audio/Weapons/Guns/MagOut/batrifle_magout.ogg
whitelist:
tags:
- N14MagazineRifle2mmEC
- type: ContainerContainer
containers:
gun_magazine: !type:ContainerSlot
- type: MagazineVisuals
magState: mag
steps: 1
zeroVisible: true
- type: Appearance
- type: AmmoCounter
- type: StaticPrice
price: 200
# - type: Craftable # #Misfits Remove: Stalker14 crafting system

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Показать состав базового прототипа оружия
rg -n -A 40 'id:\s*N14WeaponRifleBase' --glob '*.yml'

Repository: Echo-DreamMaker/Sirius_Fallout

Length of output: 168


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- matching prototypes and references ---'
rg -n -C 8 'N14WeaponRifleBase|N14WeaponSniperM72GaussRifleSirius|GunDamageBonus|FollowDistance|HybridAmmoProvider' \
  Resources/Prototypes --glob '*.yml' --glob '*.yaml' | head -n 400
printf '%s\n' '--- candidate base prototype files ---'
rg -l 'N14WeaponRifleBase|GunDamageBonus' Resources/Prototypes --glob '*.yml' --glob '*.yaml' | head -n 100
printf '%s\n' '--- target file context ---'
sed -n '870,980p' Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Snipers/snipers.yml

Repository: Echo-DreamMaker/Sirius_Fallout

Length of output: 45649


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- sniper prototypes around the target ---'
sed -n '1,140p' Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Snipers/snipers.yml
sed -n '760,930p' Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Snipers/snipers.yml
printf '%s\n' '--- all declarations and parent references for rifle bases ---'
rg -n '^[[:space:]-]*(id|parent):.*(N14WeaponRifleBase|N14Weapon.*Rifle.*Base|BaseItem)' \
  Resources/Prototypes --glob '*.yml' --glob '*.yaml'
printf '%s\n' '--- repository state and target diff summary ---'
git status --short
git diff --stat -- Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Snipers/snipers.yml

Repository: Echo-DreamMaker/Sirius_Fallout

Length of output: 50386


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- rifle base definition ---'
sed -n '1,38p' Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Rifles/rifles.yml
printf '%s\n' '--- relevant base definitions ---'
rg -n -C 12 '^(- type: entity|  id: BaseItem|  id: BaseWeaponRifle|  id: BaseWeaponSniper|  id: N14WeaponRifleBase)' \
  Resources/Prototypes --glob '*.yml' --glob '*.yaml' | rg -n -A 18 -B 2 \
  'BaseItem|BaseWeaponRifle|BaseWeaponSniper|N14WeaponRifleBase' | head -n 240
printf '%s\n' '--- 2mm projectile and damage declarations ---'
rg -n -C 15 'N14Bullet2mmEC|N14Cartridge2mmEC|Piercing: 38|GunDamageBonus' \
  Resources/Prototypes/_Nuclear14 Resources/Prototypes/_Misfits --glob '*.yml' --glob '*.yaml' | head -n 320

Repository: Echo-DreamMaker/Sirius_Fallout

Length of output: 50386


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- core weapon bases ---'
rg -n -B 3 -A 30 '^  id: (BaseItem|BaseWeaponRifle|BaseWeaponSniper)$' \
  Resources/Prototypes --glob '*.yml' --glob '*.yaml'
printf '%s\n' '--- exact 2mm ammunition prototypes ---'
rg -n -B 3 -A 35 '^  id: (N14Bullet2mmEC|N14Cartridge2mmEC)$' \
  Resources/Prototypes --glob '*.yml' --glob '*.yaml'
printf '%s\n' '--- all Gauss damage-related declarations ---'
rg -n -B 5 -A 12 'N14WeaponSniperM72GaussRifleSirius|Piercing: 38|N14Bullet2mmEC' \
  Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Snipers/snipers.yml \
  Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Ammunition --glob '*.yml' --glob '*.yaml'

Repository: Echo-DreamMaker/Sirius_Fallout

Length of output: 30646


🏁 Script executed:

#!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
import re

path = Path("Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Snipers/snipers.yml")
text = path.read_text()

def block_for(proto_id):
    starts = [m.start() for m in re.finditer(r"(?m)^- type: entity$", text)]
    for i, start in enumerate(starts):
        end = starts[i + 1] if i + 1 < len(starts) else len(text)
        block = text[start:end]
        if re.search(rf"(?m)^  id: {re.escape(proto_id)}$", block):
            return block
    raise SystemExit(f"prototype not found: {proto_id}")

def component_types(block):
    return re.findall(r"(?m)^  - type: ([^\s#]+)", block)

ids = [
    "N14WeaponRifleBase",
    "N14WeaponSniperM72GaussRifleSirius67",
    "N14WeaponSniperM72GaussRifleSirius",
]
for proto_id in ids:
    block = block_for(proto_id)
    parent = re.search(r"(?m)^  parent: (.+)$", block)
    print(f"{proto_id}: parent={parent.group(1) if parent else '<none>'}")
    print("  components:", ", ".join(component_types(block)))

old = set(component_types(block_for("N14WeaponSniperM72GaussRifleSirius67")))
new = set(component_types(block_for("N14WeaponSniperM72GaussRifleSirius")))
base = set(component_types(block_for("N14WeaponRifleBase")))
print("old-only components:", ", ".join(sorted(old - new)) or "<none>")
print("new-only components:", ", ".join(sorted(new - old)) or "<none>")
print("base components not declared by new:", ", ".join(sorted(base - new)) or "<none>")
print("new has GunDamageBonus:", "GunDamageBonus" in new)
PY

Repository: Echo-DreamMaker/Sirius_Fallout

Length of output: 208


🏁 Script executed:

#!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
import re

root = Path("Resources/Prototypes")

def find_block(proto_id):
    for path in root.rglob("*.yml"):
        text = path.read_text(errors="replace")
        starts = [m.start() for m in re.finditer(r"(?m)^- type: entity$", text)]
        for i, start in enumerate(starts):
            end = starts[i + 1] if i + 1 < len(starts) else len(text)
            block = text[start:end]
            if re.search(rf"(?m)^  id: {re.escape(proto_id)}$", block):
                return path, block
    raise SystemExit(f"prototype not found: {proto_id}")

def component_types(block):
    return re.findall(r"(?m)^  - type: ([^\s#]+)", block)

ids = [
    "N14WeaponRifleBase",
    "N14WeaponSniperM72GaussRifleSirius67",
    "N14WeaponSniperM72GaussRifleSirius",
]
blocks = {}
for proto_id in ids:
    path, block = find_block(proto_id)
    blocks[proto_id] = block
    parent = re.search(r"(?m)^  parent: (.+)$", block)
    print(f"{proto_id}: file={path}, parent={parent.group(1) if parent else '<none>'}")
    print("  components:", ", ".join(component_types(block)))

old = set(component_types(blocks["N14WeaponSniperM72GaussRifleSirius67"]))
new = set(component_types(blocks["N14WeaponSniperM72GaussRifleSirius"]))
base = set(component_types(blocks["N14WeaponRifleBase"]))
print("old-only components:", ", ".join(sorted(old - new)) or "<none>")
print("new-only components:", ", ".join(sorted(new - old)) or "<none>")
print("base components not declared by new:", ", ".join(sorted(base - new)) or "<none>")
print("new has GunDamageBonus:", "GunDamageBonus" in new)
PY

Repository: Echo-DreamMaker/Sirius_Fallout

Length of output: 1256


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- BaseWeaponRifle parent chain and wield requirement ---'
sed -n '1,55p' Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml
rg -n -B 5 -A 28 'id: BaseGunWieldable|type: GunRequiresWield' Resources/Prototypes --glob '*.yml' --glob '*.yaml'
printf '%s\n' '--- old and new Gauss component sections ---'
sed -n '826,979p' Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Snipers/snipers.yml

Repository: Echo-DreamMaker/Sirius_Fallout

Length of output: 50387


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- complete BaseWeaponRifle declaration ---'
sed -n '1,90p' Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml
printf '%s\n' '--- component declarations in the Gauss prototypes ---'
python3 - <<'PY'
from pathlib import Path
import re

paths = [
    Path("Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml"),
    Path("Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Rifles/rifles.yml"),
    Path("Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Snipers/snipers.yml"),
]
wanted = {
    "BaseWeaponRifle",
    "N14WeaponRifleBase",
    "N14WeaponSniperM72GaussRifleSirius67",
    "N14WeaponSniperM72GaussRifleSirius",
}
for path in paths:
    text = path.read_text()
    starts = [m.start() for m in re.finditer(r"(?m)^- type: entity$", text)]
    for i, start in enumerate(starts):
        block = text[start:starts[i + 1] if i + 1 < len(starts) else len(text)]
        m = re.search(r"(?m)^  id: ([^\s]+)$", block)
        if not m or m.group(1) not in wanted:
            continue
        print(f"{m.group(1)} ({path})")
        for component in re.findall(r"(?m)^  - type: ([^\s#]+)", block):
            print(f"  - {component}")
PY

Repository: Echo-DreamMaker/Sirius_Fallout

Length of output: 3761


Восстановите настройки базовой винтовки.

N14Bullet2mmEC наносит 32 Piercing. Без GunDamageBonus с Piercing: 38 новая сущность наносит 32 вместо 70. Добавьте этот компонент.

Новая сущность также не содержит FollowDistance и GunRequiresWield, который наследуется через BaseWeaponRifle. Sprite, Item, ContainerContainer, MagazineVisuals и Appearance уже заданы явно и не потеряны.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@Resources/Prototypes/_Nuclear14/Entities/Objects/Weapons/Guns/Snipers/snipers.yml`
around lines 901 - 965, В сущности N14WeaponSniperM72GaussRifleSirius
восстановите настройки базовой винтовки: добавьте GunDamageBonus с бонусом
Piercing 38, а также унаследованные через BaseWeaponRifle компоненты
FollowDistance и GunRequiresWield. Не дублируйте уже явно заданные Sprite, Item,
ContainerContainer, MagazineVisuals и Appearance.

@RavenAzala
RavenAzala merged commit 379e123 into master Aug 11, 2026
12 of 13 checks passed
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.

1 participant