Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 149 additions & 0 deletions Content.Server/_LP/Power/Systems/InducerSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
using System.Linq;
using Content.Server.Power.Components;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.DoAfter;
using Content.Shared.Interaction;
using Content.Shared.Popups;
using Content.Shared.Power.Components;
using Content.Shared.Verbs;
using Robust.Shared.Utility;

namespace Content.Server.Power.EntitySystems;

public sealed class InducerSystem : EntitySystem
{
[Dependency] private readonly BatterySystem _battery = default!;
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
[Dependency] private readonly ItemSlotsSystem _itemSlots = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;

public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<InducerComponent, AfterInteractEvent>(OnAfterInteract);
SubscribeLocalEvent<InducerComponent, InducerDoAfterEvent>(OnDoAfter);
SubscribeLocalEvent<InducerComponent, GetVerbsEvent<AlternativeVerb>>(OnGetVerbs);
}

private void OnAfterInteract(EntityUid uid, InducerComponent component, AfterInteractEvent args)
{
if (args.Handled || args.Target == null || !args.CanReach)
return;

var target = args.Target.Value;

if (!TryComp<BatteryComponent>(target, out var targetBattery))
{
_popup.PopupEntity(Loc.GetString("inducer-no-battery"), uid, args.User);
return;
}

if (!_itemSlots.TryGetSlot(uid, component.PowerCellSlotId, out var slot) || slot.Item == null ||
!TryComp<BatteryComponent>(slot.Item.Value, out var sourceBattery))
{
_popup.PopupEntity(Loc.GetString("inducer-no-power-cell"), uid, args.User);
return;
}

if (sourceBattery.CurrentCharge <= 0)
{
_popup.PopupEntity(Loc.GetString("inducer-empty"), uid, args.User);
return;
}

if (_battery.IsFull(target, targetBattery))
{
_popup.PopupEntity(Loc.GetString("inducer-target-full"), uid, args.User);
return;
}

var doAfterArgs = new DoAfterArgs(EntityManager, args.User, component.TransferDelay, new InducerDoAfterEvent(), uid, target: target, used: uid)
{
BreakOnMove = true,
BreakOnDamage = true,
RequireCanInteract = true,
DistanceThreshold = component.MaxDistance,
CancelDuplicate = false,
};

_doAfter.TryStartDoAfter(doAfterArgs);
args.Handled = true;
}

private void OnDoAfter(EntityUid uid, InducerComponent component, DoAfterEvent args)
{
if (args.Cancelled || args.Handled || args.Target == null)
return;

var target = args.Target.Value;

if (!TryComp<BatteryComponent>(target, out var targetBattery))
return;

if (!_itemSlots.TryGetSlot(uid, component.PowerCellSlotId, out var slot) || slot.Item == null)
return;

if (!TryComp<BatteryComponent>(slot.Item.Value, out var sourceBattery))
return;

var energyToTransfer = component.TransferRate;
energyToTransfer = Math.Min(energyToTransfer, sourceBattery.CurrentCharge);

var freeSpace = targetBattery.MaxCharge - targetBattery.CurrentCharge;
energyToTransfer = Math.Min(energyToTransfer, freeSpace);

if (energyToTransfer <= 0)
return;

if (_battery.TryUseCharge(slot.Item.Value, energyToTransfer, sourceBattery))
{
_battery.AddCharge(target, energyToTransfer, targetBattery);
var percent = (int)(targetBattery.CurrentCharge / targetBattery.MaxCharge * 100);
_popup.PopupEntity(Loc.GetString("inducer-success", ("percent", percent)), uid, args.User);

if (targetBattery.CurrentCharge < targetBattery.MaxCharge * 0.95f)
{
args.Repeat = true;
}
else
{
args.Repeat = false;
}
Comment on lines +105 to +112

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.

medium

Этот блок if/else можно упростить до одной строки для улучшения читаемости и краткости кода.

                args.Repeat = targetBattery.CurrentCharge < targetBattery.MaxCharge * 0.95f;

}
else
{
_battery.SetCharge(target, targetBattery.CurrentCharge + energyToTransfer, targetBattery);
_battery.SetCharge(slot.Item.Value, sourceBattery.CurrentCharge - energyToTransfer, sourceBattery);
args.Repeat = false;
}
Comment on lines +114 to +119

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.

high

Блок else здесь выглядит подозрительно и потенциально может привести к ошибкам. Метод _battery.TryUseCharge не должен возвращать false, так как energyToTransfer уже ограничен текущим зарядом sourceBattery. Если TryUseCharge все же вернет false (например, из-за состояния гонки), то ручное изменение заряда в обход API BatterySystem является некорректным. Это может привести к рассинхронизации состояния. Рекомендуется убрать манипуляции с зарядом из этого блока.

        else
        {
            args.Repeat = false;
        }

}

private void OnGetVerbs(EntityUid uid, InducerComponent component, GetVerbsEvent<AlternativeVerb> args)
{
if (!args.CanAccess || !args.CanInteract)
return;

var priority = 0;
foreach (var rate in component.AvailableTransferRates)
{
AlternativeVerb verb = new()
{
Text = Loc.GetString("inducer-set-transfer-rate", ("rate", rate)),
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/zap.svg.192dpi.png")),
Category = VerbCategory.SelectType,
Act = () =>
{
component.TransferRate = rate;
Dirty(uid, component);
_popup.PopupEntity(Loc.GetString("inducer-transfer-rate-set", ("rate", rate)), uid, args.User);
},
Priority = priority
};

priority--;

args.Verbs.Add(verb);
}
}
}
27 changes: 27 additions & 0 deletions Content.Shared/_LP/Power/Components/InducerComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
using Content.Shared.DoAfter;

namespace Content.Shared.Power.Components;

[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class InducerComponent : Component
{
[DataField]
public string PowerCellSlotId = "inducer_power_cell_slot";

[DataField, AutoNetworkedField]
public float TransferRate = default!;

[DataField]
public List<float> AvailableTransferRates = new();

[DataField]
public float TransferDelay = default!;

[DataField]
public float MaxDistance = default!;
}

[Serializable, NetSerializable]
public sealed partial class InducerDoAfterEvent : SimpleDoAfterEvent;
22 changes: 22 additions & 0 deletions Content.Shared/_LP/Power/Systems/SharedInducerSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Content.Shared.Examine;
using Content.Shared.Power.Components;

namespace Content.Shared.Power.EntitySystems;

public sealed class SharedInducerSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<InducerComponent, ExaminedEvent>(OnExamined);
}

private void OnExamined(EntityUid uid, InducerComponent component, ExaminedEvent args)
{
if (!args.IsInDetailsRange)
return;

args.PushMarkup(Loc.GetString("inducer-examine-rate", ("rate", component.TransferRate)));
}
}
3 changes: 3 additions & 0 deletions Resources/Locale/ru-RU/_ADT/research/technologies.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
research-technology-basemegacells = Мегабатареи

research-technology-advancedmegacells = Сверхэффективные мегабатареи
8 changes: 8 additions & 0 deletions Resources/Locale/ru-RU/_LP/power/inducer.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
inducer-no-battery = В цели нет батареи!
inducer-no-power-cell = В индукторе нет батареи!
inducer-empty = Батарея устройства разряжена!
inducer-target-full = Батарея цели уже полностью заряжена!
inducer-success = Энергия передана. Заряд цели: {$percent}%
inducer-set-transfer-rate = Установить {$rate} Дж/с
inducer-transfer-rate-set = Скорость передачи установлена на {$rate} Дж/с
inducer-examine-rate = Текущая скорость передачи: [color=yellow]{$rate} Дж/с[/color]
1 change: 1 addition & 0 deletions Resources/Locale/ru-RU/_LP/research/technologies.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
research-technology-inducer = Беспроводная передача энергии
Comment thread
KashRas2 marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ent-ADTMegaCellRechargerCircuitboard = зарядник мегабатарей (машинная плата)
.desc = Печатная плата зарядника мегабатарей.
Comment thread
KashRas2 marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
ent-ADTMegaCellSmall = мегабатарея малой ёмкости
.desc = Перезаряжаемый энергоэлемент высшего класса. Скромная по меркам серии, но на порядок превосходит устаревшие промышленные аккумуляторы. Из-за особенностей конструкции несовместима с обычными зарядниками.
.suffix = Полный
ent-ADTMegaCellSmallPrinted = { ent-ADTMegaCellSmall }
.suffix = Пустой
.desc = { ent-ADTMegaCellSmall.desc }
ent-ADTMegaCellMedium = мегабатарея средней ёмкости
.desc = Энергоэлемент продвинутой конструкции. Обладает выдающейся стабильностью и ёмкостью. Из-за особенностей конструкции несовместима с обычными зарядниками.
.suffix = Полный
ent-ADTMegaCellMediumPrinted = { ent-ADTMegaCellMedium }
.suffix = Пустой
.desc = { ent-ADTMegaCellMedium.desc }
ent-ADTMegaCellHigh = мегабатарея высокой ёмкости
.desc = Высокоёмкий источник энергии нового поколения. Обеспечивает длительное энергоснабжение без потери производительности. Из-за особенностей конструкции несовместима с обычными зарядниками.
.suffix = Полный
ent-ADTMegaCellHighPrinted = { ent-ADTMegaCellHigh }
.suffix = Пустой
.desc = { ent-ADTMegaCellHigh.desc }
ent-ADTMegaCellHyper = мегабатарея гипер ёмкости
.desc = Эталон инженерной мысли в сфере энергосистем. Способна вмещать в себя колоссальное количество энергии и сохранять её с безупречной стабильностью. Из-за особенностей конструкции несовместима с обычными зарядниками.
.suffix = Полный
ent-ADTMegaCellHyperPrinted = { ent-ADTMegaCellHyper }
.suffix = Пустой
.desc = { ent-ADTMegaCellHyper.desc }
ent-ADTMegaCellInfinite = квантовая мегабатарея
.desc = Абсолютная вершина энергетических технологий. Квантовая матрица внутри корпуса обеспечивает практически неисчерпаемый запас энергии, нарушая все известные законы термодинамики.
.suffix = Бесконечный

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.

medium

В конце файла отсутствует символ новой строки. Некоторые инструменты и системы контроля версий могут некорректно обрабатывать файлы без завершающей новой строки. Рекомендуется добавить ее.

Suggested change
.suffix = Бесконечный
.suffix = Бесконечный

Comment thread
KashRas2 marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ent-ADTMegaCellRecharger = зарядник мегабатарей
.desc = Модифицированный зарядник промышленного класса, предназначенный исключительно для зарядки мегабатарей. Оснащён контактным основанием и усиленными энергоканалами для безопасной и эффективной передачи электричества.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

В конце файла отсутствует символ новой строки. Некоторые инструменты и системы контроля версий могут некорректно обрабатывать файлы без завершающей новой строки. Рекомендуется добавить ее.

Suggested change
.desc = Модифицированный зарядник промышленного класса, предназначенный исключительно для зарядки мегабатарей. Оснащён контактным основанием и усиленными энергоканалами для безопасной и эффективной передачи электричества.
.desc = Модифицированный зарядник промышленного класса, предназначенный исключительно для зарядки мегабатарей. Оснащён контактным основанием и усиленными энергоканалами для безопасной и эффективной передачи электричества.

Comment thread
KashRas2 marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
ent-LPPEngiInducer = индуктор
.desc = Устройство для беспроводной передачи энергии от собственной батареи к батареям других устройств.
.suffix = Пустой, Инженерный
ent-LPPEngiInducerBattery = { ent-LPPEngiInducer }
.desc = { ent-LPPEngiInducer.desc }
.suffix = Батарея, Инженерный
ent-LPPRNDInducer = { ent-LPPEngiInducer }
.desc = { ent-LPPEngiInducer.desc }
.suffix = Пустой, РНД
ent-LPPRNDInducerBattery = { ent-LPPEngiInducer }
.desc = { ent-LPPEngiInducer.desc }
.suffix = Батарея, РНД
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,11 @@
slots:
cell_slot:
name: power-cell-slot-component-slot-name-default
# LP Edit Start
blacklist:
tags:
- ADTMegaCell
# LP Edit End
- type: Body
bodyType: Simple
- type: StatusEffects
Expand Down
6 changes: 6 additions & 0 deletions Resources/Prototypes/Entities/Structures/Power/chargers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,11 @@
tags:
- PowerCell
- PowerCellSmall
# ADT-tweak-start
blacklist:
tags:
- ADTMegaCell
# ADT-tweak-end

- type: entity
parent: [ BaseItemRecharger, ConstructibleMachine ]
Expand Down Expand Up @@ -280,6 +285,7 @@
blacklist:
tags:
- PotatoBattery
- ADTMegaCell # ADT-Tweak
- WizardWand # Goobstation
components: # Goobstation
- MaterialEnergy
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
- type: entity
id: ADTMegaCellRechargerCircuitboard
parent: BaseMachineCircuitboard
name: megacell recharger machine board
description: A machine printed circuit board for a megacell recharger.
components:
- type: Sprite
sprite: Objects/Misc/module.rsi
state: engineering
- type: MachineBoard
prototype: ADTMegaCellRecharger
stackRequirements:
Manipulator: 5
Gold: 20
Cable: 5
- type: PhysicalComposition
materialComposition:
Steel: 30
Plastic: 30
- type: StaticPrice
price: 15
Loading
Loading