diff --git a/Content.Server/Medical/DefibrillatorSystem.cs b/Content.Server/Medical/DefibrillatorSystem.cs
index 94d62641ce..7331d8dcc7 100644
--- a/Content.Server/Medical/DefibrillatorSystem.cs
+++ b/Content.Server/Medical/DefibrillatorSystem.cs
@@ -23,6 +23,12 @@ using Content.Shared.Timing;
using Content.Shared.Toggleable;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Player;
+// Sunrise-Start
+using Content.Shared.FixedPoint;
+using Content.Shared.Body.Components;
+using Content.Shared.Chemistry.EntitySystems;
+using Content.Shared.Chemistry.Components;
+// Sunrise-End
namespace Content.Server.Medical;
@@ -46,6 +52,7 @@ public sealed class DefibrillatorSystem : EntitySystem
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedMindSystem _mind = default!;
[Dependency] private readonly UseDelaySystem _useDelay = default!;
+ [Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!; // Sunrise-Edit
///
public override void Initialize()
@@ -70,7 +77,7 @@ public sealed class DefibrillatorSystem : EntitySystem
if (args.Target is not { } target)
return;
- if (!CanZap(uid, target, args.User, component))
+ if (!CanZap(uid, target, args.User, component, component.AllowUseOnAlive)) // Sunrise-Edit
return;
args.Handled = true;
@@ -111,6 +118,13 @@ public sealed class DefibrillatorSystem : EntitySystem
if (!_powerCell.HasActivatableCharge(uid, user: user))
return false;
+ // Sunrise-Start
+ var canZapEvent = new SunriseCanZapEvent(uid, target, user);
+ RaiseLocalEvent(uid, ref canZapEvent);
+ if (canZapEvent.Cancelled)
+ return false;
+ // Sunrise-End
+
if (!targetCanBeAlive && _mobState.IsAlive(target, mobState))
return false;
@@ -135,7 +149,7 @@ public sealed class DefibrillatorSystem : EntitySystem
if (!Resolve(uid, ref component))
return false;
- if (!CanZap(uid, target, user, component))
+ if (!CanZap(uid, target, user, component, component.AllowUseOnAlive)) // Sunrise-Edit
return false;
_audio.PlayPvs(component.ChargeSound, uid);
@@ -164,7 +178,7 @@ public sealed class DefibrillatorSystem : EntitySystem
target = selfEvent.DefibTarget;
// Ensure thet new target is still valid.
- if (selfEvent.Cancelled || !CanZap(uid, target, user, component, true))
+ if (selfEvent.Cancelled || !CanZap(uid, target, user, component, component.AllowUseOnAlive)) // Sunrise-Edit
return;
var targetEvent = new TargetBeforeDefibrillatorZapsEvent(user, uid, target);
@@ -172,7 +186,7 @@ public sealed class DefibrillatorSystem : EntitySystem
target = targetEvent.DefibTarget;
- if (targetEvent.Cancelled || !CanZap(uid, target, user, component, true))
+ if (targetEvent.Cancelled || !CanZap(uid, target, user, component, component.AllowUseOnAlive)) // Sunrise-Edit
return;
if (!TryComp(target, out var mob) ||
@@ -229,6 +243,18 @@ public sealed class DefibrillatorSystem : EntitySystem
}
}
+ // Sunrise-Start
+ // Inject reagents if any are specified
+ if (component.Reagents.Count > 0 && TryComp(target, out var bloodstream))
+ {
+ if (_solutionContainer.TryGetSolution(target, bloodstream.ChemicalSolutionName, out var solution))
+ {
+ foreach (var (reagent, amount) in component.Reagents)
+ _solutionContainer.TryAddReagent(solution.Value, reagent, FixedPoint2.New(amount), out _);
+ }
+ }
+ // Sunrise-End
+
var sound = dead || session == null
? component.FailureSound
: component.SuccessSound;
diff --git a/Content.Server/_Sunrise/Biocode/Systems/BiocodeDefibrillatorSystem.cs b/Content.Server/_Sunrise/Biocode/Systems/BiocodeDefibrillatorSystem.cs
new file mode 100644
index 0000000000..9f2f21ec0f
--- /dev/null
+++ b/Content.Server/_Sunrise/Biocode/Systems/BiocodeDefibrillatorSystem.cs
@@ -0,0 +1,36 @@
+using Content.Server.Popups;
+using Content.Shared._Sunrise.Biocode;
+using Content.Shared.Medical;
+
+namespace Content.Server._Sunrise.Biocode.Systems;
+
+///
+/// System that handles biocode checks for defibrillators.
+///
+public sealed class BiocodeDefibrillatorSystem : EntitySystem
+{
+ [Dependency] private readonly BiocodeSystem _biocode = default!;
+ [Dependency] private readonly PopupSystem _popup = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent(OnCanZap);
+ }
+
+ private void OnCanZap(EntityUid uid, BiocodeComponent component, ref SunriseCanZapEvent args)
+ {
+ if (args.User == null)
+ return;
+
+ if (_biocode.CanUse(args.User.Value, component.Factions))
+ return;
+
+ // User is not authorized, cancel the zap
+ if (!string.IsNullOrEmpty(component.AlertText))
+ _popup.PopupEntity(component.AlertText, uid, args.User.Value);
+
+ args.Cancelled = true;
+ }
+}
+
diff --git a/Content.Server/_Sunrise/Weapons/Melee/Components/PowerDrainOnMeleeHitComponent.cs b/Content.Server/_Sunrise/Weapons/Melee/Components/PowerDrainOnMeleeHitComponent.cs
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/Content.Server/_Sunrise/Weapons/Melee/Systems/PowerDrainOnMeleeHitSystem.cs b/Content.Server/_Sunrise/Weapons/Melee/Systems/PowerDrainOnMeleeHitSystem.cs
new file mode 100644
index 0000000000..966277f0a3
--- /dev/null
+++ b/Content.Server/_Sunrise/Weapons/Melee/Systems/PowerDrainOnMeleeHitSystem.cs
@@ -0,0 +1,71 @@
+using Content.Server.Power.EntitySystems;
+using Content.Server.PowerCell;
+using Content.Shared.Item.ItemToggle;
+using Content.Shared.Item.ItemToggle.Components;
+using Content.Shared.Power.Components;
+using Content.Shared.PowerCell.Components;
+using Content.Shared.Weapons.Melee.Events;
+using Content.Shared._Sunrise.Weapons.Melee.Components;
+
+namespace Content.Server._Sunrise.Weapons.Melee.Systems;
+
+public sealed class PowerDrainOnMeleeHitSystem : EntitySystem
+{
+ [Dependency] private readonly ItemToggleSystem _itemToggle = default!;
+ [Dependency] private readonly PowerCellSystem _powerCell = default!;
+ [Dependency] private readonly BatterySystem _battery = default!;
+
+ public override void Initialize()
+ {
+ SubscribeLocalEvent(OnMeleeHit);
+ }
+
+ private void OnMeleeHit(EntityUid uid, PowerDrainOnMeleeHitComponent comp, ref MeleeHitEvent args)
+ {
+ if (comp.ChargePerHit <= 0)
+ return;
+
+ if (!args.IsHit)
+ return;
+
+ if (comp.RequireActualHit && (args.HitEntities == null || args.HitEntities.Count == 0))
+ return;
+
+ // Check if item is toggled on (if it has ItemToggleComponent)
+ if (TryComp(uid, out var toggle) && !_itemToggle.IsActivated((uid, toggle)))
+ return;
+
+ // Prefer slotted power cell if present
+ if (HasComp(uid))
+ {
+ if (!_powerCell.HasCharge(uid, comp.ChargePerHit, null, args.User))
+ {
+ args.Handled = true;
+ return;
+ }
+
+ if (!_powerCell.TryUseCharge(uid, comp.ChargePerHit, null, args.User))
+ {
+ args.Handled = true;
+ return;
+ }
+ return;
+ }
+
+ // Fall back to direct BatteryComponent on the same entity
+ if (TryComp(uid, out var directBattery))
+ {
+ if (directBattery.CurrentCharge < comp.ChargePerHit)
+ {
+ args.Handled = true;
+ return;
+ }
+
+ if (!_battery.TryUseCharge(uid, comp.ChargePerHit, directBattery))
+ {
+ args.Handled = true;
+ return;
+ }
+ }
+ }
+}
diff --git a/Content.Shared/Medical/DefibrillatorComponent.cs b/Content.Shared/Medical/DefibrillatorComponent.cs
index f54348d771..94f9587359 100644
--- a/Content.Shared/Medical/DefibrillatorComponent.cs
+++ b/Content.Shared/Medical/DefibrillatorComponent.cs
@@ -77,6 +77,20 @@ public sealed partial class DefibrillatorComponent : Component
[ViewVariables(VVAccess.ReadWrite), DataField("readySound")]
public SoundSpecifier? ReadySound = new SoundPathSpecifier("/Audio/Items/Defib/defib_ready.ogg");
+
+ // Sunrise-Start
+ ///
+ /// Whether the defibrillator can be used on alive targets
+ ///
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
+ public bool AllowUseOnAlive = false;
+
+ ///
+ /// The reagents to inject when defibrillation is completed
+ ///
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
+ public Dictionary Reagents = new();
+ // Sunrise-End
}
[Serializable, NetSerializable]
diff --git a/Content.Shared/Medical/DefibrillatorEvents.cs b/Content.Shared/Medical/DefibrillatorEvents.cs
index 54a21a40d4..1f0d531689 100644
--- a/Content.Shared/Medical/DefibrillatorEvents.cs
+++ b/Content.Shared/Medical/DefibrillatorEvents.cs
@@ -37,3 +37,15 @@ public sealed class TargetBeforeDefibrillatorZapsEvent : BeforeDefibrillatorZaps
{
public TargetBeforeDefibrillatorZapsEvent(EntityUid entityUsingDefib, EntityUid defib, EntityUid defibtarget) : base(entityUsingDefib, defib, defibtarget) { }
}
+
+// Sunrise-Start
+///
+/// This event is raised to check if the defibrillator can be used.
+/// Systems can cancel this event to prevent defibrillation.
+///
+[ByRefEvent]
+public record struct SunriseCanZapEvent(EntityUid Defibrillator, EntityUid Target, EntityUid? User)
+{
+ public bool Cancelled = false;
+}
+// Sunrise-End
diff --git a/Content.Shared/_Sunrise/Weapons/Melee/Components/PowerDrainOnMeleeHitComponent.cs b/Content.Shared/_Sunrise/Weapons/Melee/Components/PowerDrainOnMeleeHitComponent.cs
new file mode 100644
index 0000000000..b37061d640
--- /dev/null
+++ b/Content.Shared/_Sunrise/Weapons/Melee/Components/PowerDrainOnMeleeHitComponent.cs
@@ -0,0 +1,23 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared._Sunrise.Weapons.Melee.Components;
+
+///
+/// When attached to a melee weapon, drains power on successful melee hit.
+/// Drains from a slotted power cell if present, otherwise from a direct BatteryComponent.
+///
+[RegisterComponent, NetworkedComponent]
+public sealed partial class PowerDrainOnMeleeHitComponent : Component
+{
+ ///
+ /// Amount of charge to drain per successful hit (in joules).
+ ///
+ [ViewVariables(VVAccess.ReadWrite), DataField]
+ public float ChargePerHit = 0f;
+
+ ///
+ /// If true, only drain when there is at least one entity hit.
+ ///
+ [ViewVariables(VVAccess.ReadWrite), DataField]
+ public bool RequireActualHit = true;
+}
diff --git a/Resources/Locale/ru-RU/_prototypes/catalog/fills/backpacks/duffelbag.ftl b/Resources/Locale/ru-RU/_prototypes/catalog/fills/backpacks/duffelbag.ftl
index d1f390a398..d540b9a6cc 100644
--- a/Resources/Locale/ru-RU/_prototypes/catalog/fills/backpacks/duffelbag.ftl
+++ b/Resources/Locale/ru-RU/_prototypes/catalog/fills/backpacks/duffelbag.ftl
@@ -41,7 +41,7 @@ ent-ClothingBackpackDuffelSyndicateHardsuitExtrasBundle = набор допол
ent-ClothingBackpackDuffelZombieBundle = зомби набор Синдиката
.desc = Универсальный набор для создания зомби на станции.
ent-ClothingBackpackDuffelSyndicateMedicalBundleFilled = набор медикаментов
- .desc = Все, что нужно для возвращения в строй ваших товарищей: главным образом, боевая аптечка, дефибриллятор и три боевых медипена.
+ .desc = Все, что нужно для возвращения в строй ваших товарищей: главным образом, боевая аптечка и три боевых медипена.
ent-ClothingBackpackDuffelSyndicateDecoyKitFilled = набор обманок
.desc = Содержит отвлекающие устройства, как звуковые, так и визуальные. Скоро появятся и обонятельные.
ent-ClothingBackpackDuffelAcolyteBundle = набор брони послушника
diff --git a/Resources/Locale/ru-RU/_prototypes/entities/objects/devices/syndicate_gadgets/syndicate_teleporter.ftl b/Resources/Locale/ru-RU/_prototypes/entities/objects/devices/syndicate_gadgets/syndicate_teleporter.ftl
index 76919e76e9..55db47d9e1 100644
--- a/Resources/Locale/ru-RU/_prototypes/entities/objects/devices/syndicate_gadgets/syndicate_teleporter.ftl
+++ b/Resources/Locale/ru-RU/_prototypes/entities/objects/devices/syndicate_gadgets/syndicate_teleporter.ftl
@@ -3,3 +3,6 @@ ent-SyndicateTeleporter = телепортер синдиката
ent-SyndicateTeleporterBiocode = { ent-SyndicateTeleporter }
.desc = { ent-SyndicateTeleporter.desc }
+
+ent-DefibrillatorSyndicateBiocode = { ent-DefibrillatorSyndicate }
+ .desc = { ent-DefibrillatorSyndicate.desc }
diff --git a/Resources/Locale/ru-RU/_prototypes/entities/objects/specific/medical/defib.ftl b/Resources/Locale/ru-RU/_prototypes/entities/objects/specific/medical/defib.ftl
index 3439d47f52..b5a3197e17 100644
--- a/Resources/Locale/ru-RU/_prototypes/entities/objects/specific/medical/defib.ftl
+++ b/Resources/Locale/ru-RU/_prototypes/entities/objects/specific/medical/defib.ftl
@@ -11,4 +11,4 @@ ent-DefibrillatorOneHandedUnpowered = { ent-BaseDefibrillator }
ent-DefibrillatorCompact = компактный дефибриллятор
.desc = Теперь в забавном размере!
ent-DefibrillatorSyndicate = дефибриллятор Interdyne
- .desc = Двойное оружие самообороны против склонных к военным преступлениям тайдеров.
+ .desc = Особый дефибриллятор фирмы Interdyne. Для настоящих медиков Синдиката!
diff --git a/Resources/Locale/ru-RU/_strings/store/uplink-catalog.ftl b/Resources/Locale/ru-RU/_strings/store/uplink-catalog.ftl
index 1b0fc742e1..61ac70936c 100644
--- a/Resources/Locale/ru-RU/_strings/store/uplink-catalog.ftl
+++ b/Resources/Locale/ru-RU/_strings/store/uplink-catalog.ftl
@@ -371,3 +371,5 @@ uplink-fake-mindshield-name = Имитатор защиты разума
uplink-fake-mindshield-desc = Переключаемый имплант, воспроизводящий сигнатуры настоящего щита. Обманывает сканеры командования, создавая ложное присутствие защиты. (Имплантер NT не включён в поставку.)
uplink-handcuffs-name = Наручники
uplink-handcuffs-desc = Используется для удержания жертв.
+uplink-interdyne-defibrillator-name = Дефибриллятор Interdyne
+uplink-interdyne-defibrillator-desc = Превосходный дефибриллятор, предназначенный для помощи и самообороны. Для настоящих медиков Синдиката.
diff --git a/Resources/Prototypes/Catalog/Fills/Backpacks/duffelbag.yml b/Resources/Prototypes/Catalog/Fills/Backpacks/duffelbag.yml
index b3c19bdb48..d147380b69 100644
--- a/Resources/Prototypes/Catalog/Fills/Backpacks/duffelbag.yml
+++ b/Resources/Prototypes/Catalog/Fills/Backpacks/duffelbag.yml
@@ -387,7 +387,7 @@
components:
- type: StorageFill
contents:
- - id: DefibrillatorSyndicate
+ #- id: DefibrillatorSyndicate
- id: MedkitCombatFilled
amount: 4
- id: Tourniquet
diff --git a/Resources/Prototypes/Catalog/uplink_catalog.yml b/Resources/Prototypes/Catalog/uplink_catalog.yml
index 897461b6ed..3d04fd783f 100644
--- a/Resources/Prototypes/Catalog/uplink_catalog.yml
+++ b/Resources/Prototypes/Catalog/uplink_catalog.yml
@@ -899,9 +899,9 @@
productEntity: ClothingBackpackDuffelSyndicateMedicalBundleFilled
discountCategory: rareDiscounts
discountDownTo:
- Telecrystal: 16
+ Telecrystal: 12
cost:
- Telecrystal: 24
+ Telecrystal: 16
categories:
- UplinkChemicals
conditions:
diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/defib.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/defib.yml
index 894454b05c..5e7f817d95 100644
--- a/Resources/Prototypes/Entities/Objects/Specific/Medical/defib.yml
+++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/defib.yml
@@ -112,6 +112,24 @@
- state: ready
map: ["enum.PowerDeviceVisualLayers.Powered"]
shader: unshaded
+ # Sunrise-Start
+ - type: Defibrillator
+ allowUseOnAlive: true
+ reagents:
+ Omnizine: 10
+ Epinephrine: 5
+ - type: ItemSlots
+ slots:
+ cell_slot:
+ name: power-cell-slot-component-slot-name-default
+ startingItem: PowerCellDefibrillatorSyndicate
+ disableEject: true
+ locked: true
+ - type: PowerCellDraw
+ useRate: 85
+ - type: PowerDrainOnMeleeHit
+ chargePerHit: 30
+ # Sunrise-End
- type: MeleeWeapon
damage:
types:
diff --git a/Resources/Prototypes/_Sunrise/Catalog/uplink_catalog.yml b/Resources/Prototypes/_Sunrise/Catalog/uplink_catalog.yml
index cbb430b86a..fcf062e583 100644
--- a/Resources/Prototypes/_Sunrise/Catalog/uplink_catalog.yml
+++ b/Resources/Prototypes/_Sunrise/Catalog/uplink_catalog.yml
@@ -2252,7 +2252,7 @@
sprite: /Textures/_Starlight/Objects/Weapons/Melee/cybermantisblade.rsi,
state: cybermantisblade,
}
- productEntity: MantisBladeArmsKit #ClothingBackpackDufelSyndicateFilledMantisBladeArms #Скучно и не практично в сумке ради 4 слота
+ productEntity: MantisBladeArmsKit
discountCategory: rareDiscounts
discountDownTo:
Telecrystal: 8
@@ -2443,6 +2443,29 @@
categories:
- UplinkDeception
conditions:
+ - !type:StoreWhitelistCondition
+ whitelist:
+ - Science
+ tags:
+ - NukeOpsUplink
+ - LoneOpsUplink
+ - AssaultOpsUplink
+
+- type: listing
+ id: UplinkDefibrillatorSyndicate
+ name: uplink-interdyne-defibrillator-name
+ description: uplink-interdyne-defibrillator-desc
+ productEntity: DefibrillatorSyndicateBiocode
+ discountCategory: rareDiscounts
+ discountDownTo:
+ Telecrystal: 4
+ cost:
+ Telecrystal: 8
+ categories:
+ - UplinkChemicals
+ conditions:
+ - !type:ListingLimitedStockCondition
+ stock: 1
- !type:StoreWhitelistCondition
whitelist:
tags:
diff --git a/Resources/Prototypes/_Sunrise/Entities/Objects/Devices/Syndicate_Gadgets/biocode.yml b/Resources/Prototypes/_Sunrise/Entities/Objects/Devices/Syndicate_Gadgets/biocode.yml
index c41756ed33..f4f4e5150b 100644
--- a/Resources/Prototypes/_Sunrise/Entities/Objects/Devices/Syndicate_Gadgets/biocode.yml
+++ b/Resources/Prototypes/_Sunrise/Entities/Objects/Devices/Syndicate_Gadgets/biocode.yml
@@ -8,3 +8,17 @@
- Syndicate
- Thief
alertText: Данный предмет биокодирован. Вы не можете его использовать.
+
+- type: entity
+ parent: DefibrillatorSyndicate
+ id: DefibrillatorSyndicateBiocode
+ suffix: BIOCODE
+ components:
+ - type: Biocode
+ factions:
+ - Syndicate
+ alertText: Данный предмет биокодирован. Вы не можете его использовать.
+ - type: FactionWeaponBlocker
+ factions:
+ - Syndicate
+ alertText: Данное оружие биокодировано. Вы не можете его использовать.
diff --git a/Resources/Prototypes/_Sunrise/Entities/Objects/Power/powercells.yml b/Resources/Prototypes/_Sunrise/Entities/Objects/Power/powercells.yml
index d616c83dd7..0f659c187b 100644
--- a/Resources/Prototypes/_Sunrise/Entities/Objects/Power/powercells.yml
+++ b/Resources/Prototypes/_Sunrise/Entities/Objects/Power/powercells.yml
@@ -59,3 +59,35 @@
graph: MakeshiftPowerCage
node: makeshiftcage
+- type: entity
+ name: powercell defibrillator syndicate
+ id: PowerCellDefibrillatorSyndicate
+ suffix: Full
+ parent: SyndicateDefibrillatorPowercell
+ components:
+ - type: Battery
+ maxCharge: 300
+ startingCharge: 300
+ - type: BatterySelfRecharger
+ autoRechargeRate: 4.5
+ autoRecharge: true
+ autoRechargePause: true
+ autoRechargePauseTime: 25
+
+- type: entity
+ name: syndicate defibrillator power cell
+ description: A rechargeable standardized power cell. This one looks like a rare and powerful Syndicate combat variant.
+ id: SyndicateDefibrillatorPowercell
+ suffix: Full
+ parent: BasePowerCell
+ components:
+ - type: Sprite
+ layers:
+ - map: [ "enum.PowerCellVisualLayers.Base" ]
+ state: syndicate
+ - map: [ "enum.PowerCellVisualLayers.Unshaded" ]
+ state: o2
+ shader: unshaded
+ - type: Battery
+ maxCharge: 1800
+ startingCharge: 1800