From 599f047fc95f8821443b6500a8d3dfae2e943131 Mon Sep 17 00:00:00 2001
From: A-Mironov <65418470+Alexnov33X@users.noreply.github.com>
Date: Sat, 27 Sep 2025 00:59:57 +0300
Subject: [PATCH] =?UTF-8?q?QOL=20=D0=B4=D0=BB=D1=8F=20=D0=BA=D1=83=D0=BB?=
=?UTF-8?q?=D1=8C=D1=82=D0=B0=20=D0=BA=D1=80=D0=BE=D0=B2=D0=B8=20(#3261)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Systems/BiocodeDeactivationSystem.cs | 46 ++++++
.../BloodCult/BloodCultTargetComponent.cs | 6 -
.../Commands/AddCultTargetCommand.cs | 61 ++++++++
.../Commands/ListCultTargetsCommand.cs | 42 ++++++
.../Commands/RemoveCultTargetCommand.cs | 61 ++++++++
.../BloodCult/GameRule/BloodCultRuleSystem.cs | 39 +++++
.../Pinpointer/SharedPinpointerSystem.cs | 2 +-
.../BiocodeDeactivationComponent.cs | 29 ++++
.../Systems/BiocodeDeactivationSystem.cs | 136 +++++++++++++++++
.../Components/BloodCultTargetComponent.cs | 11 ++
.../objects/devices/blood_cult_pinpointer.ftl | 2 +
.../_strings/_sunrise/bloodcult/commands.ftl | 36 +++++
.../_sunrise/bloodcult/pinpointer.ftl | 11 ++
.../objects/devices/blood_cult_pinpointer.ftl | 2 +
.../_strings/_sunrise/bloodcult/commands.ftl | 40 +++++
.../_sunrise/bloodcult/pinpointer.ftl | 9 ++
.../Objects/Devices/blood_cult_pinpointer.yml | 45 ++++++
.../_Sunrise/BloodCult/cult_types.yml | 3 +
.../BloodCult/pinpointer.rsi/meta.json | 142 ++++++++++++++++++
.../BloodCult/pinpointer.rsi/pinonalert.png | Bin 0 -> 577 bytes
.../pinpointer.rsi/pinonalertdirect.png | Bin 0 -> 196 bytes
.../pinpointer.rsi/pinonalertnull.png | Bin 0 -> 212 bytes
.../BloodCult/pinpointer.rsi/pinonclose.png | Bin 0 -> 4979 bytes
.../BloodCult/pinpointer.rsi/pinondirect.png | Bin 0 -> 166 bytes
.../pinpointer.rsi/pinondirectlarge.png | Bin 0 -> 173 bytes
.../pinpointer.rsi/pinondirectsmall.png | Bin 0 -> 152 bytes
.../pinpointer.rsi/pinondirectxtrlarge.png | Bin 0 -> 159 bytes
.../BloodCult/pinpointer.rsi/pinonfar.png | Bin 0 -> 230 bytes
.../BloodCult/pinpointer.rsi/pinonmedium.png | Bin 0 -> 4978 bytes
.../BloodCult/pinpointer.rsi/pinonnull.png | Bin 0 -> 182 bytes
.../pinpointer.rsi/pinpointer_bloodcult.png | Bin 0 -> 857 bytes
31 files changed, 716 insertions(+), 7 deletions(-)
create mode 100644 Content.Server/_Sunrise/Biocode/Systems/BiocodeDeactivationSystem.cs
delete mode 100644 Content.Server/_Sunrise/BloodCult/BloodCultTargetComponent.cs
create mode 100644 Content.Server/_Sunrise/BloodCult/Commands/AddCultTargetCommand.cs
create mode 100644 Content.Server/_Sunrise/BloodCult/Commands/ListCultTargetsCommand.cs
create mode 100644 Content.Server/_Sunrise/BloodCult/Commands/RemoveCultTargetCommand.cs
create mode 100644 Content.Shared/_Sunrise/Biocode/Components/BiocodeDeactivationComponent.cs
create mode 100644 Content.Shared/_Sunrise/Biocode/Systems/BiocodeDeactivationSystem.cs
create mode 100644 Content.Shared/_Sunrise/BloodCult/Components/BloodCultTargetComponent.cs
create mode 100644 Resources/Locale/en-US/_prototypes/_sunrise/entities/objects/devices/blood_cult_pinpointer.ftl
create mode 100644 Resources/Locale/en-US/_strings/_sunrise/bloodcult/commands.ftl
create mode 100644 Resources/Locale/en-US/_strings/_sunrise/bloodcult/pinpointer.ftl
create mode 100644 Resources/Locale/ru-RU/_prototypes/_sunrise/entities/objects/devices/blood_cult_pinpointer.ftl
create mode 100644 Resources/Locale/ru-RU/_strings/_sunrise/bloodcult/commands.ftl
create mode 100644 Resources/Locale/ru-RU/_strings/_sunrise/bloodcult/pinpointer.ftl
create mode 100644 Resources/Prototypes/_Sunrise/BloodCult/Entities/Objects/Devices/blood_cult_pinpointer.yml
create mode 100644 Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/meta.json
create mode 100644 Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinonalert.png
create mode 100644 Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinonalertdirect.png
create mode 100644 Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinonalertnull.png
create mode 100644 Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinonclose.png
create mode 100644 Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinondirect.png
create mode 100644 Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinondirectlarge.png
create mode 100644 Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinondirectsmall.png
create mode 100644 Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinondirectxtrlarge.png
create mode 100644 Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinonfar.png
create mode 100644 Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinonmedium.png
create mode 100644 Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinonnull.png
create mode 100644 Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinpointer_bloodcult.png
diff --git a/Content.Server/_Sunrise/Biocode/Systems/BiocodeDeactivationSystem.cs b/Content.Server/_Sunrise/Biocode/Systems/BiocodeDeactivationSystem.cs
new file mode 100644
index 0000000000..056ad731ef
--- /dev/null
+++ b/Content.Server/_Sunrise/Biocode/Systems/BiocodeDeactivationSystem.cs
@@ -0,0 +1,46 @@
+using Content.Shared._Sunrise.Biocode.Systems;
+using Content.Shared.Pinpointer;
+using Content.Server.Popups;
+using Content.Server.Pinpointer;
+
+namespace Content.Server._Sunrise.Biocode.Systems;
+
+///
+/// Server-side implementation of biocode deactivation system.
+///
+public sealed class ServerBiocodeDeactivationSystem : BiocodeDeactivationSystem
+{
+ [Dependency] private readonly PopupSystem _popup = default!;
+ [Dependency] private readonly PinpointerSystem _pinpointerSystem = default!;
+ [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
+
+ private static readonly ISawmill Sawmill = Logger.GetSawmill("biocode.deactivation");
+
+ protected override void ShowAlert(EntityUid user, string alertText)
+ {
+ _popup.PopupEntity(Loc.GetString(alertText), user, user);
+ }
+
+ protected override void DeactivateItem(EntityUid uid)
+ {
+ // Handle pinpointer deactivation using the proper system method
+ if (TryComp(uid, out var pinpointer))
+ {
+ // Always ensure the pinpointer is deactivated
+ _pinpointerSystem.SetActive(uid, false, pinpointer);
+
+ // Force update appearance to ensure visual state is correct
+ if (TryComp(uid, out var appearance))
+ {
+ _appearance.SetData(uid, PinpointerVisuals.IsActive, false, appearance);
+ _appearance.SetData(uid, PinpointerVisuals.TargetDistance, Distance.Unknown, appearance);
+ }
+ }
+
+ // Add other item types here as needed
+ // Example: if (TryComp(uid, out var otherComponent))
+ // {
+ // _someOtherSystem.Deactivate(uid, otherComponent);
+ // }
+ }
+}
diff --git a/Content.Server/_Sunrise/BloodCult/BloodCultTargetComponent.cs b/Content.Server/_Sunrise/BloodCult/BloodCultTargetComponent.cs
deleted file mode 100644
index 024df13779..0000000000
--- a/Content.Server/_Sunrise/BloodCult/BloodCultTargetComponent.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace Content.Server._Sunrise.BloodCult;
-
-[RegisterComponent]
-public sealed partial class BloodCultTargetComponent : Component
-{
-}
diff --git a/Content.Server/_Sunrise/BloodCult/Commands/AddCultTargetCommand.cs b/Content.Server/_Sunrise/BloodCult/Commands/AddCultTargetCommand.cs
new file mode 100644
index 0000000000..82990b0acd
--- /dev/null
+++ b/Content.Server/_Sunrise/BloodCult/Commands/AddCultTargetCommand.cs
@@ -0,0 +1,61 @@
+using Content.Server._Sunrise.BloodCult.GameRule;
+using Content.Server.Administration;
+using Content.Shared.Administration;
+using Robust.Shared.Console;
+using Robust.Server.Player;
+
+namespace Content.Server._Sunrise.BloodCult.Commands;
+
+[AdminCommand(AdminFlags.Admin)]
+public sealed class AddCultTargetCommand : IConsoleCommand
+{
+ [Dependency] private readonly IEntityManager _entManager = default!;
+ [Dependency] private readonly IPlayerManager _playerManager = default!;
+
+ public string Command => "bloodcult_addtarget";
+ public string Description => Loc.GetString("bloodcult-addtarget-description");
+ public string Help => Loc.GetString("bloodcult-addtarget-help");
+
+ public void Execute(IConsoleShell shell, string argStr, string[] args)
+ {
+ if (args.Length != 1)
+ {
+ shell.WriteError(Loc.GetString("bloodcult-addtarget-usage"));
+ return;
+ }
+
+ var ckey = args[0];
+ if (!_playerManager.TryGetSessionByUsername(ckey, out var session) || session.AttachedEntity == null)
+ {
+ shell.WriteError(Loc.GetString("bloodcult-addtarget-player-not-found", ("ckey", ckey)));
+ return;
+ }
+
+ var entityUid = session.AttachedEntity.Value;
+
+ if (!_entManager.EntitySysManager.TryGetEntitySystem(out var cultRuleSystem))
+ {
+ shell.WriteError(Loc.GetString("bloodcult-addtarget-system-not-found"));
+ return;
+ }
+
+ var rule = cultRuleSystem.GetRule();
+ if (rule == null)
+ {
+ shell.WriteError(Loc.GetString("bloodcult-addtarget-rule-not-found"));
+ return;
+ }
+
+ // Use the system method to add target properly
+ if (!cultRuleSystem.AddSpecificCultTarget(entityUid, rule))
+ {
+ shell.WriteError(Loc.GetString("bloodcult-addtarget-already-target"));
+ return;
+ }
+
+ var targetName = _entManager.TryGetComponent(entityUid, out var meta)
+ ? meta.EntityName
+ : Loc.GetString("bloodcult-unknown-entity");
+ shell.WriteLine(Loc.GetString("bloodcult-addtarget-success", ("name", targetName)));
+ }
+}
diff --git a/Content.Server/_Sunrise/BloodCult/Commands/ListCultTargetsCommand.cs b/Content.Server/_Sunrise/BloodCult/Commands/ListCultTargetsCommand.cs
new file mode 100644
index 0000000000..388e910086
--- /dev/null
+++ b/Content.Server/_Sunrise/BloodCult/Commands/ListCultTargetsCommand.cs
@@ -0,0 +1,42 @@
+using Content.Server._Sunrise.BloodCult.GameRule;
+using Content.Server.Administration;
+using Content.Shared.Administration;
+using Robust.Shared.Console;
+
+namespace Content.Server._Sunrise.BloodCult.Commands;
+
+[AdminCommand(AdminFlags.Admin)]
+public sealed class ListCultTargetsCommand : IConsoleCommand
+{
+ [Dependency] private readonly IEntityManager _entManager = default!;
+
+ public string Command => "bloodcult_listtargets";
+ public string Description => Loc.GetString("bloodcult-listtargets-description");
+ public string Help => Loc.GetString("bloodcult-listtargets-help");
+
+ public void Execute(IConsoleShell shell, string argStr, string[] args)
+ {
+ if (!_entManager.EntitySysManager.TryGetEntitySystem(out var cultRuleSystem))
+ {
+ shell.WriteError(Loc.GetString("bloodcult-listtargets-system-not-found"));
+ return;
+ }
+
+ var rule = cultRuleSystem.GetRule();
+ if (rule?.CultTargets == null || rule.CultTargets.Count == 0)
+ {
+ shell.WriteLine(Loc.GetString("bloodcult-listtargets-no-targets"));
+ return;
+ }
+
+ shell.WriteLine(Loc.GetString("bloodcult-listtargets-header", ("count", rule.CultTargets.Count)));
+ foreach (var (target, isSacrificed) in rule.CultTargets)
+ {
+ var targetName = _entManager.TryGetComponent(target, out var meta)
+ ? meta.EntityName
+ : Loc.GetString("bloodcult-unknown-entity");
+ var status = isSacrificed ? Loc.GetString("bloodcult-listtargets-sacrificed") : Loc.GetString("bloodcult-listtargets-alive");
+ shell.WriteLine(Loc.GetString("bloodcult-listtargets-target", ("name", targetName), ("uid", target), ("status", status)));
+ }
+ }
+}
diff --git a/Content.Server/_Sunrise/BloodCult/Commands/RemoveCultTargetCommand.cs b/Content.Server/_Sunrise/BloodCult/Commands/RemoveCultTargetCommand.cs
new file mode 100644
index 0000000000..03ab1bdaf1
--- /dev/null
+++ b/Content.Server/_Sunrise/BloodCult/Commands/RemoveCultTargetCommand.cs
@@ -0,0 +1,61 @@
+using Content.Server._Sunrise.BloodCult.GameRule;
+using Content.Server.Administration;
+using Content.Shared.Administration;
+using Robust.Shared.Console;
+using Robust.Server.Player;
+
+namespace Content.Server._Sunrise.BloodCult.Commands;
+
+[AdminCommand(AdminFlags.Admin)]
+public sealed class RemoveCultTargetCommand : IConsoleCommand
+{
+ [Dependency] private readonly IEntityManager _entManager = default!;
+ [Dependency] private readonly IPlayerManager _playerManager = default!;
+
+ public string Command => "bloodcult_removetarget";
+ public string Description => Loc.GetString("bloodcult-removetarget-description");
+ public string Help => Loc.GetString("bloodcult-removetarget-help");
+
+ public void Execute(IConsoleShell shell, string argStr, string[] args)
+ {
+ if (args.Length != 1)
+ {
+ shell.WriteError(Loc.GetString("bloodcult-removetarget-usage"));
+ return;
+ }
+
+ var ckey = args[0];
+ if (!_playerManager.TryGetSessionByUsername(ckey, out var session) || session.AttachedEntity == null)
+ {
+ shell.WriteError(Loc.GetString("bloodcult-removetarget-player-not-found", ("ckey", ckey)));
+ return;
+ }
+
+ var entityUid = session.AttachedEntity.Value;
+
+ if (!_entManager.EntitySysManager.TryGetEntitySystem(out var cultRuleSystem))
+ {
+ shell.WriteError(Loc.GetString("bloodcult-removetarget-system-not-found"));
+ return;
+ }
+
+ var rule = cultRuleSystem.GetRule();
+ if (rule == null)
+ {
+ shell.WriteError(Loc.GetString("bloodcult-removetarget-rule-not-found"));
+ return;
+ }
+
+ // Use the system method to remove target properly
+ if (!cultRuleSystem.RemoveSpecificCultTarget(entityUid, rule))
+ {
+ shell.WriteError(Loc.GetString("bloodcult-removetarget-not-target"));
+ return;
+ }
+
+ var targetName = _entManager.TryGetComponent(entityUid, out var meta)
+ ? meta.EntityName
+ : Loc.GetString("bloodcult-unknown-entity");
+ shell.WriteLine(Loc.GetString("bloodcult-removetarget-success", ("name", targetName)));
+ }
+}
diff --git a/Content.Server/_Sunrise/BloodCult/GameRule/BloodCultRuleSystem.cs b/Content.Server/_Sunrise/BloodCult/GameRule/BloodCultRuleSystem.cs
index fbd43e9aa3..835d1c9236 100644
--- a/Content.Server/_Sunrise/BloodCult/GameRule/BloodCultRuleSystem.cs
+++ b/Content.Server/_Sunrise/BloodCult/GameRule/BloodCultRuleSystem.cs
@@ -142,6 +142,45 @@ public sealed class BloodCultRuleSystem : GameRuleSystem
}
}
+ ///
+ /// Manually add a specific entity as a cult target.
+ ///
+ public bool AddSpecificCultTarget(EntityUid target, BloodCultRuleComponent rule)
+ {
+ if (!Exists(target) || rule.CultTargets.ContainsKey(target))
+ return false;
+
+ rule.CultTargets.Add(target, false);
+ EnsureComp(target);
+
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var uid, out var killCultistTargetsComponent))
+ {
+ _cultistTargetsConditionSystem.RefresTitle(uid, rule.CultTargets, killCultistTargetsComponent);
+ }
+ return true;
+ }
+
+ ///
+ /// Manually remove a specific entity as a cult target.
+ ///
+ public bool RemoveSpecificCultTarget(EntityUid target, BloodCultRuleComponent rule)
+ {
+ if (!rule.CultTargets.ContainsKey(target))
+ return false;
+
+ rule.CultTargets.Remove(target);
+ if (Exists(target))
+ RemComp(target);
+
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var uid, out var killCultistTargetsComponent))
+ {
+ _cultistTargetsConditionSystem.RefresTitle(uid, rule.CultTargets, killCultistTargetsComponent);
+ }
+ return true;
+ }
+
protected override void Added(EntityUid uid,
BloodCultRuleComponent component,
GameRuleComponent gameRule,
diff --git a/Content.Shared/Pinpointer/SharedPinpointerSystem.cs b/Content.Shared/Pinpointer/SharedPinpointerSystem.cs
index 4710960183..2f62c5d9fc 100644
--- a/Content.Shared/Pinpointer/SharedPinpointerSystem.cs
+++ b/Content.Shared/Pinpointer/SharedPinpointerSystem.cs
@@ -67,7 +67,7 @@ public abstract class SharedPinpointerSystem : EntitySystem
private void OnExamined(EntityUid uid, PinpointerComponent component, ExaminedEvent args)
{
- if (!args.IsInDetailsRange || component.TargetName == null)
+ if (!args.IsInDetailsRange || component.TargetName == null || !component.IsActive)
return;
args.PushMarkup(Loc.GetString("examine-pinpointer-linked", ("target", component.TargetName)));
diff --git a/Content.Shared/_Sunrise/Biocode/Components/BiocodeDeactivationComponent.cs b/Content.Shared/_Sunrise/Biocode/Components/BiocodeDeactivationComponent.cs
new file mode 100644
index 0000000000..22dd415fef
--- /dev/null
+++ b/Content.Shared/_Sunrise/Biocode/Components/BiocodeDeactivationComponent.cs
@@ -0,0 +1,29 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared._Sunrise.Biocode.Components;
+
+///
+/// Component that automatically deactivates items when they're not in the possession of authorized users.
+///
+[RegisterComponent, NetworkedComponent]
+public sealed partial class BiocodeDeactivationComponent : Component
+{
+ ///
+ /// Whether the item should be deactivated when removed from authorized user's possession.
+ ///
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
+ public bool DeactivateOnRemoval = true;
+
+ ///
+ /// Whether the item should be deactivated when placed in unauthorized user's possession.
+ ///
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
+ public bool DeactivateOnUnauthorized = true;
+
+ ///
+ /// Alert text to show when unauthorized user tries to use the item.
+ /// If null, uses the BiocodeComponent's alert text.
+ ///
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
+ public string? AlertText;
+}
diff --git a/Content.Shared/_Sunrise/Biocode/Systems/BiocodeDeactivationSystem.cs b/Content.Shared/_Sunrise/Biocode/Systems/BiocodeDeactivationSystem.cs
new file mode 100644
index 0000000000..c44d181637
--- /dev/null
+++ b/Content.Shared/_Sunrise/Biocode/Systems/BiocodeDeactivationSystem.cs
@@ -0,0 +1,136 @@
+using Content.Shared._Sunrise.Biocode.Components;
+using Content.Shared.Containers;
+using Content.Shared.Hands.Components;
+using Content.Shared.Inventory;
+using Content.Shared.Storage.Components;
+using Content.Shared.Interaction;
+using Content.Shared.Interaction.Events;
+using Content.Shared.Storage;
+using Content.Shared.Hands;
+using Content.Shared.Inventory.Events;
+using Robust.Shared.Containers;
+
+namespace Content.Shared._Sunrise.Biocode.Systems;
+
+///
+/// System that handles automatic deactivation of biocoded items when they're not in authorized user's possession.
+///
+public abstract class BiocodeDeactivationSystem : EntitySystem
+{
+ [Dependency] private readonly BiocodeSystem _biocodeSystem = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent(OnActivate);
+ SubscribeLocalEvent(OnUseInHand);
+ SubscribeLocalEvent(OnItemDropped);
+ SubscribeLocalEvent(OnItemPickedUp);
+ }
+
+ private void OnItemDropped(EntityUid uid, BiocodeDeactivationComponent component, DroppedEvent args)
+ {
+ if (!component.DeactivateOnRemoval)
+ return;
+
+ // Check if this item has biocode
+ if (!TryComp(uid, out var biocodeComponent))
+ return;
+
+ // Item was dropped, deactivate it
+ DeactivateItem(uid);
+ }
+
+ private void OnItemPickedUp(EntityUid uid, BiocodeDeactivationComponent component, GotEquippedEvent args)
+ {
+ if (!component.DeactivateOnUnauthorized)
+ return;
+
+ // Check if this item has biocode
+ if (!TryComp(uid, out var biocodeComponent))
+ return;
+
+ // Check if the picker is authorized
+ if (_biocodeSystem.CanUse(args.Equipee, biocodeComponent.Factions))
+ return;
+
+ // Picker is not authorized, deactivate the item
+ DeactivateItem(uid);
+ }
+
+ private void OnActivate(EntityUid uid, BiocodeDeactivationComponent component, ActivateInWorldEvent args)
+ {
+ if (args.Handled || !args.Complex)
+ return;
+
+ // Check if this item has biocode
+ if (!TryComp(uid, out var biocodeComponent))
+ return;
+
+ // Check if user is authorized
+ if (_biocodeSystem.CanUse(args.User, biocodeComponent.Factions))
+ return;
+
+ // User is not authorized, show alert and prevent activation
+ var alertText = component.AlertText ?? biocodeComponent.AlertText;
+ ShowAlert(args.User, alertText);
+ args.Handled = true;
+ }
+
+ private void OnUseInHand(EntityUid uid, BiocodeDeactivationComponent component, UseInHandEvent args)
+ {
+ if (args.Handled)
+ return;
+
+ // Check if this item has biocode
+ if (!TryComp(uid, out var biocodeComponent))
+ return;
+
+ // Check if user is authorized
+ if (_biocodeSystem.CanUse(args.User, biocodeComponent.Factions))
+ return;
+
+ // User is not authorized, show alert and prevent use
+ var alertText = component.AlertText ?? biocodeComponent.AlertText;
+ ShowAlert(args.User, alertText);
+ args.Handled = true;
+ }
+
+ ///
+ /// Shows an alert to the user. Override this method to implement specific alert display logic.
+ ///
+ protected abstract void ShowAlert(EntityUid user, string alertText);
+
+ ///
+ /// Deactivates the item. Override this method in the shared system to implement specific deactivation logic.
+ ///
+ protected abstract void DeactivateItem(EntityUid uid);
+
+ private EntityUid? GetContainerOwner(EntityUid container)
+ {
+ // Try to find the owner through various container types
+ if (TryComp(container, out _))
+ {
+ return container;
+ }
+
+ if (TryComp(container, out _))
+ {
+ return container;
+ }
+
+ if (TryComp(container, out _))
+ {
+ return container;
+ }
+
+ // Check if this container is inside another entity
+ var parent = Transform(container).ParentUid;
+ if (parent != EntityUid.Invalid)
+ {
+ return GetContainerOwner(parent);
+ }
+
+ return null;
+ }
+}
diff --git a/Content.Shared/_Sunrise/BloodCult/Components/BloodCultTargetComponent.cs b/Content.Shared/_Sunrise/BloodCult/Components/BloodCultTargetComponent.cs
new file mode 100644
index 0000000000..6ff7e43fc7
--- /dev/null
+++ b/Content.Shared/_Sunrise/BloodCult/Components/BloodCultTargetComponent.cs
@@ -0,0 +1,11 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared._Sunrise.BloodCult.Components;
+
+///
+/// Component that marks an entity as a target for the Blood cult.
+///
+[RegisterComponent, NetworkedComponent]
+public sealed partial class BloodCultTargetComponent : Component
+{
+}
diff --git a/Resources/Locale/en-US/_prototypes/_sunrise/entities/objects/devices/blood_cult_pinpointer.ftl b/Resources/Locale/en-US/_prototypes/_sunrise/entities/objects/devices/blood_cult_pinpointer.ftl
new file mode 100644
index 0000000000..a34c2e3625
--- /dev/null
+++ b/Resources/Locale/en-US/_prototypes/_sunrise/entities/objects/devices/blood_cult_pinpointer.ftl
@@ -0,0 +1,2 @@
+ent-BloodCultPinpointer = Blood Locator
+ .desc = A sinister looking pinpointer with a strange crystal lodged into it. It points towards cult targets. Only cultists know about this device and how to use it, for others it's a strange piece of junk.
diff --git a/Resources/Locale/en-US/_strings/_sunrise/bloodcult/commands.ftl b/Resources/Locale/en-US/_strings/_sunrise/bloodcult/commands.ftl
new file mode 100644
index 0000000000..f9608b089b
--- /dev/null
+++ b/Resources/Locale/en-US/_strings/_sunrise/bloodcult/commands.ftl
@@ -0,0 +1,36 @@
+# Blood Cult Console Commands
+
+# Add Target Command
+bloodcult-addtarget-description = Add target for Blood Cult
+bloodcult-addtarget-help = Adds a specific player as a target for the Blood Cult. The player will be marked for tracking and potential sacrifice.
+bloodcult-addtarget-usage = Usage: bloodcult_addtarget
+bloodcult-addtarget-player-not-found = Player with ckey '{ $ckey }' not found or not in game.
+bloodcult-addtarget-system-not-found = Blood Cult system not found.
+bloodcult-addtarget-rule-not-found = No active Blood Cult rule found.
+bloodcult-addtarget-already-target = Entity is already a cult target.
+bloodcult-addtarget-success = Successfully added { $name } as a cult target.
+
+# Remove Target Command
+bloodcult-removetarget-description = Remove target for Blood Cult
+bloodcult-removetarget-help = Removes a specific player from the Blood Cult target list. The player will no longer be tracked or marked for sacrifice.
+bloodcult-removetarget-usage = Usage: bloodcult_removetarget
+bloodcult-removetarget-player-not-found = Player with ckey '{ $ckey }' not found or not in game.
+bloodcult-removetarget-system-not-found = Blood Cult system not found.
+bloodcult-removetarget-rule-not-found = No active Blood Cult rule found.
+bloodcult-removetarget-not-target = Entity is not a cult target.
+bloodcult-removetarget-success = Successfully removed { $name } as a cult target.
+
+# List Targets Command
+bloodcult-listtargets-description = Show all current Blood Cult targets
+bloodcult-listtargets-help = Displays all current Blood Cult targets with their status (alive or sacrificed) and entity information.
+bloodcult-listtargets-usage = Usage: bloodcult_listtargets
+bloodcult-listtargets-system-not-found = Blood Cult system not found.
+bloodcult-listtargets-no-targets = No cult targets found.
+bloodcult-listtargets-header = Current cult targets ({ $count }):
+bloodcult-listtargets-sacrificed = Sacrificed
+bloodcult-listtargets-alive = Alive
+bloodcult-listtargets-target = { $name } ({ $uid }) - { $status }
+bloodcult-unknown-entity = Unknown Entity
+
+# Cult Device Alert
+bloodcult-biocode-alert = The device pulses with dark energy, rejecting your touch. Only those bound by blood may wield its power.
diff --git a/Resources/Locale/en-US/_strings/_sunrise/bloodcult/pinpointer.ftl b/Resources/Locale/en-US/_strings/_sunrise/bloodcult/pinpointer.ftl
new file mode 100644
index 0000000000..6ec7defb6d
--- /dev/null
+++ b/Resources/Locale/en-US/_strings/_sunrise/bloodcult/pinpointer.ftl
@@ -0,0 +1,11 @@
+#Sunrise-start
+pinpointer-cult-target = cult target
+pinpointer-cult-no-target = No cult targets found
+pinpointer-cult-target-name = { $name } ({ $status })
+pinpointer-cult-target-alive = Alive
+pinpointer-cult-target-sacrificed = Sacrificed
+
+# Blood Locator
+blood-locator-name = Blood Locator
+blood-locator-description = A sinister looking pinpointer with a strange crystal lodged into it. It points towards cult targets. Only cultists know about this device and how to use it, for others it's a strange piece of junk.
+#Sunrise-End
diff --git a/Resources/Locale/ru-RU/_prototypes/_sunrise/entities/objects/devices/blood_cult_pinpointer.ftl b/Resources/Locale/ru-RU/_prototypes/_sunrise/entities/objects/devices/blood_cult_pinpointer.ftl
new file mode 100644
index 0000000000..afbdd54548
--- /dev/null
+++ b/Resources/Locale/ru-RU/_prototypes/_sunrise/entities/objects/devices/blood_cult_pinpointer.ftl
@@ -0,0 +1,2 @@
+ent-BloodCultPinpointer = Кровеуказатель
+ .desc = Зловещий указатель со странным кристаллом, встроенным в него. Он указывает на цели культа. Только культисты знают об этом устройстве и как его использовать, для остальных это странный хлам.
diff --git a/Resources/Locale/ru-RU/_strings/_sunrise/bloodcult/commands.ftl b/Resources/Locale/ru-RU/_strings/_sunrise/bloodcult/commands.ftl
new file mode 100644
index 0000000000..c1cc1d6a0f
--- /dev/null
+++ b/Resources/Locale/ru-RU/_strings/_sunrise/bloodcult/commands.ftl
@@ -0,0 +1,40 @@
+# Blood Cult Console Commands
+
+# Add Target Command
+bloodcult-addtarget-description = Добавить цель для Культа Крови
+bloodcult-addtarget-help = Добавляет конкретного игрока как цель Культа Крови для отслеживания и потенциального жертвоприношения.
+bloodcult-addtarget-usage = Использование: bloodcult_addtarget
+bloodcult-addtarget-player-not-found = Игрок с ckey '{ $ckey }' не найден или не в игре.
+bloodcult-addtarget-system-not-found = Система Культа Крови не найдена.
+bloodcult-addtarget-rule-not-found = Активное правило Культа Крови не найдено.
+bloodcult-addtarget-already-target = Сущность уже является целью культа.
+bloodcult-addtarget-success = Цель культа { $name } успешно добавлена.
+
+# Remove Target Command
+bloodcult-removetarget-description = Удалить цель для Культа Крови
+bloodcult-removetarget-help = Удаляет конкретного игрока из списка целей Культа Крови, прекращая отслеживание и отметку для жертвоприношения.
+bloodcult-removetarget-usage = Использование: bloodcult_removetarget
+bloodcult-removetarget-player-not-found = Игрок с ckey '{ $ckey }' не найден или не в игре.
+bloodcult-removetarget-system-not-found = Система Культа Крови не найдена.
+bloodcult-removetarget-rule-not-found = Активное правило Культа Крови не найдено.
+bloodcult-removetarget-not-target = Сущность не является целью культа.
+bloodcult-removetarget-success = Цель культа { $name } успешно удалена.
+
+# List Targets Command
+bloodcult-listtargets-description = Показать все текущие цели Культа Крови
+bloodcult-listtargets-help = Отображает все текущие цели Культа Крови с их статусом (жив или принесен в жертву) и информацией о сущности.
+bloodcult-listtargets-usage = Использование: bloodcult_listtargets
+bloodcult-listtargets-system-not-found = Система Культа Крови не найдена.
+bloodcult-listtargets-no-targets = Цели культа не найдены.
+bloodcult-listtargets-header = { $count ->
+ [1] Текущая цель культа ({ $count }):
+ [few] Текущие цели культа ({ $count }):
+ *[other] Текущие цели культа ({ $count }):
+}
+bloodcult-listtargets-sacrificed = Принесен в жертву
+bloodcult-listtargets-alive = Жив
+bloodcult-listtargets-target = { $name } ({ $uid }) - { $status }
+bloodcult-unknown-entity = Неизвестная сущность
+
+# Cult Device Alert
+bloodcult-biocode-alert = Устройство пульсирует тёмной энергией, отвергая ваше прикосновение. Только те, кто связан кровью, могут владеть его силой.
diff --git a/Resources/Locale/ru-RU/_strings/_sunrise/bloodcult/pinpointer.ftl b/Resources/Locale/ru-RU/_strings/_sunrise/bloodcult/pinpointer.ftl
new file mode 100644
index 0000000000..53fb4ac537
--- /dev/null
+++ b/Resources/Locale/ru-RU/_strings/_sunrise/bloodcult/pinpointer.ftl
@@ -0,0 +1,9 @@
+pinpointer-cult-target = цель культа
+pinpointer-cult-no-target = Цели культа не найдены
+pinpointer-cult-target-name = { $name } ({ $status })
+pinpointer-cult-target-alive = Жив
+pinpointer-cult-target-sacrificed = Принесен в жертву
+
+# Blood Locator
+blood-locator-name = Кровеуказатель
+blood-locator-description = Зловещий указатель со странным кристаллом, встроенным в него. Он указывает на цели культа. Только культисты знают об этом устройстве и как его использовать, для остальных это странный хлам.
diff --git a/Resources/Prototypes/_Sunrise/BloodCult/Entities/Objects/Devices/blood_cult_pinpointer.yml b/Resources/Prototypes/_Sunrise/BloodCult/Entities/Objects/Devices/blood_cult_pinpointer.yml
new file mode 100644
index 0000000000..0c5584b4fd
--- /dev/null
+++ b/Resources/Prototypes/_Sunrise/BloodCult/Entities/Objects/Devices/blood_cult_pinpointer.yml
@@ -0,0 +1,45 @@
+- type: entity
+ name: ent-BloodCultPinpointer
+ description: ent-BloodCultPinpointer-desc
+ id: BloodCultPinpointer
+ parent: PinpointerBase
+ components:
+ - type: Sprite
+ sprite: _Sunrise/BloodCult/pinpointer.rsi
+ layers:
+ - state: pinpointer_bloodcult
+ map: ["enum.PinpointerLayers.Base"]
+ - state: pinonnull
+ map: ["enum.PinpointerLayers.Screen"]
+ shader: unshaded
+ visible: false
+ - type: Item
+ inhandVisuals:
+ left:
+ - state: inhand-left-base
+ color: "#8b0000"
+ - state: inhand-left-stripe
+ color: "#8b0000"
+ - state: inhand-left-top
+ right:
+ - state: inhand-right-base
+ color: "#8b0000"
+ - state: inhand-right-stripe
+ color: "#8b0000"
+ - state: inhand-right-top
+ - type: Icon
+ sprite: _Sunrise/BloodCult/pinpointer.rsi
+ state: pinpointer_bloodcult
+ - type: Pinpointer
+ component: BloodCultTarget
+ targetName: cult target
+ updateTargetName: true
+ canRetarget: false
+ - type: Biocode
+ factions:
+ - BloodCult
+ alertText: bloodcult-biocode-alert
+ - type: BiocodeDeactivation
+ deactivateOnRemoval: true
+ deactivateOnUnauthorized: true
+ alertText: bloodcult-biocode-alert
diff --git a/Resources/Prototypes/_Sunrise/BloodCult/cult_types.yml b/Resources/Prototypes/_Sunrise/BloodCult/cult_types.yml
index 6b70ae4a73..c9da9524dc 100644
--- a/Resources/Prototypes/_Sunrise/BloodCult/cult_types.yml
+++ b/Resources/Prototypes/_Sunrise/BloodCult/cult_types.yml
@@ -8,6 +8,7 @@
startingItems:
- NarsieRitualDagger
- CultRunicMetal10
+ - BloodCultPinpointer
- type: bloodCult
id: NarbeeCult
@@ -19,6 +20,7 @@
startingItems:
- NarbeeRitualDagger
- CultRunicMetal10
+ - BloodCultPinpointer
- type: bloodCult
id: ReaperCult
@@ -30,3 +32,4 @@
startingItems:
- ReaperRitualDagger
- CultRunicMetal10
+ - BloodCultPinpointer
diff --git a/Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/meta.json b/Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/meta.json
new file mode 100644
index 0000000000..7400b8a2a0
--- /dev/null
+++ b/Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/meta.json
@@ -0,0 +1,142 @@
+{
+ "version": 1,
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "license": "CC-BY-SA-3.0",
+ "copyright": "© 2025 Alexnov33x",
+ "states": [
+ {
+ "name": "pinonalert",
+ "directions": 8,
+ "delays": [
+ [
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "pinonalertdirect",
+ "delays": [
+ [
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "pinonalertnull",
+ "delays": [
+ [
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "pinonclose",
+ "delays": [
+ [
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "pinondirect",
+ "delays": [
+ [
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "pinondirectlarge",
+ "delays": [
+ [
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "pinondirectsmall",
+ "delays": [
+ [
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "pinondirectxtrlarge",
+ "delays": [
+ [
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "pinonfar",
+ "delays": [
+ [
+ 0.6,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "pinonmedium",
+ "delays": [
+ [
+ 0.4,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "pinonnull",
+ "delays": [
+ [
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "pinpointer_bloodcult"
+ }
+ ]
+}
diff --git a/Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinonalert.png b/Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinonalert.png
new file mode 100644
index 0000000000000000000000000000000000000000..39e73ee2664ae4d38ea4bf7fd9aa9a5a871fb265
GIT binary patch
literal 577
zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7xzrVB+v}aSW-L^Y-q=+`|e23<29;
ziF}l}t9&@EzwhCii*<@iPh@o+jNyJ?8@-V~o}vEEMjfDD1_qvYOP@T-y=^x?cJsRI
zi}}-j#N3;I?|(2Ju+q0{V)!)xMow~Pf_cD`z*V)dSE;ae^llz6L
zYTUerr78y)e|o>4%ktBEy=T+*TkSIgr9SLcUC=(IpxWDECFbu;U=a59TlI
z8U{&!vY6Gct1vEFUA)Nqa#glu{$|O9C5}H&W)z0KW&FnW_>5`AdUwBd-=*$scE4~>
zPGyVxh1%V3r)7OFid?^Y>8tdU$-OaEpKkPLZDZ-Vp!3k&t$VX4Q;(U(`5uw==N*vk
z+Yhmi%UMmG5ro30GAuUr)-ZMYbM-G{)wSo(^C~K2+Z3iR5@E^geeluU07aOhg>&?9vo4e0j?B2P{
zKxLPM;wp#aDLbaN`L6TKj5y+X%TvqmZDmDCiepaK)~gla-`P8C?Dmyc{*rupQ}vvN
u|N3|Q0-4{K&We4!&FtgH1Vj)!c;0XaJm-mwJaOoQjXlq^8|btUBnUue=?p?7Wm2?
s<=VU8wa}caHKK-9r|p}8CNo_7!eo@HD#Y=5$xjg1)78&qol`;+051edSO5S3
literal 0
HcmV?d00001
diff --git a/Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinonalertnull.png b/Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinonalertnull.png
new file mode 100644
index 0000000000000000000000000000000000000000..1556d82c76d9140d150dbab6ef0b5e29fbb2f42e
GIT binary patch
literal 212
zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQnNi>978JRyuEUkw?ToYA<)!M
zF?k33;Z5zy52UJ^OkDVNR|M`aXIk{leZgy>@`m_Vru@exwwuh`bN+QUN9CJ2!L`B3
zv!BbvADgoC%jrd3_7Or88T+4wPd+Mt*3^eLLvTl{Sg*XUe(k~!N3Jv&b*f7hm9b}p
z$~GEJRKN0$?K59R^~26ecAtCq>wbG@bNJRdeH8@S!_Z)Ui?QELN5ZF2XA_9;>FVdQ
I&MBb@0PM3)^Z)<=
literal 0
HcmV?d00001
diff --git a/Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinonclose.png b/Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinonclose.png
new file mode 100644
index 0000000000000000000000000000000000000000..d652e4cd02a15fd1ae265b6af6038803243d74d2
GIT binary patch
literal 4979
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
CNrOZH
literal 0
HcmV?d00001
diff --git a/Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinondirect.png b/Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinondirect.png
new file mode 100644
index 0000000000000000000000000000000000000000..c2ac6e44e2720d0b2477e1a345005e6df91d4c0b
GIT binary patch
literal 166
zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQn{Wkjv*Cu-d=U&I-nrnd~wV5
z8NcOqpJ#;U?aCNjzIkkvv)CG%@-H4)#vX4
OaXnrAT-G@yGywq0o<45?
literal 0
HcmV?d00001
diff --git a/Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinondirectlarge.png b/Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinondirectlarge.png
new file mode 100644
index 0000000000000000000000000000000000000000..c8b1fa4875244eb86bcb5bf3ef87c72bbcb733c8
GIT binary patch
literal 173
zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQYD@)jv*Cu-d;J#+n~VH`Y`Lx
zqqp`^&o2ZE>mL#6iTb%;xSdH?FVdQ&MBb@0PE90Y5)KL
literal 0
HcmV?d00001
diff --git a/Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinondirectsmall.png b/Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinondirectsmall.png
new file mode 100644
index 0000000000000000000000000000000000000000..ab7940efd992708c0fd020969b51f7d50b2d7e9a
GIT binary patch
literal 152
zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQt_THjv*Cu-d-`}Yf#`}z3|Gk
z>i^=eGFFxrk_V0`yw}xXy*1x~g@HjQGh1`rs>dtUjAx(w^XuQ<{d4OD4xD&)re<~j
z`4aX5Ui)f}yNn@MbLU>YAUvb?2gm#cK*JkM=O*nJ6skU=A_n9!c)I$ztaD0e0szd<
BH)8+*
literal 0
HcmV?d00001
diff --git a/Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinondirectxtrlarge.png b/Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinondirectxtrlarge.png
new file mode 100644
index 0000000000000000000000000000000000000000..5db693402ca49f731e6bc1701c19f6865e16bc8f
GIT binary patch
literal 159
zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQfZzpjv*Cu-d;5nYB1n%x%i@@
zd++~?-(;d9B}*45Ui|OHHpxLSiW#V~F0)hR_PzT>Dy`?%?5jU*<8nzg&AK>br)kuM
z?0=eeyFM`NYhw(tUm(TYA$I5Qx6OHtSES}_jRfjsu#lahBYaeU&w(!>o~Nsy%Q~lo
FCIC~xIo|*P
literal 0
HcmV?d00001
diff --git a/Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinonfar.png b/Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinonfar.png
new file mode 100644
index 0000000000000000000000000000000000000000..fd0fbf51ac65ccbdeb482f6c119788c62dc22d05
GIT binary patch
literal 230
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
literal 0
HcmV?d00001
diff --git a/Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinonnull.png b/Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinonnull.png
new file mode 100644
index 0000000000000000000000000000000000000000..a309d053e59380119831bb4d0cc1aec835b68b95
GIT binary patch
literal 182
zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQnj8gjv*Cu-d@=&*r34E_R#;l
zW`cTKs(Os`>H@JKfmJVlha6y3{No8!dO$zdcy4s|^r^v`d;hN4I=%Q@aBNL8I|}bNgm}HUe_zL*
e5ojDk#|yU2KcpnC-}!JE#PxLbb6Mw<&;$UGNk-rR
literal 0
HcmV?d00001
diff --git a/Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinpointer_bloodcult.png b/Resources/Textures/_Sunrise/BloodCult/pinpointer.rsi/pinpointer_bloodcult.png
new file mode 100644
index 0000000000000000000000000000000000000000..5d9c8e05c528ef3d664cc48841b94482ad42c126
GIT binary patch
literal 857
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}Ea{HEjtmSN
z`?>!lvI6;>1s;*b3=G_YAk0{w5#8IXksPAt^OIGtXB2{qFth3YjUk>fxro2EGN(sTr9bRYj@6RemAKRoTgwDeCri
zyj(UFRzMSSQ%e#RDspr3imfVamB0pD0ofp7eI+}aqLehNAQv~N3Lwu`DWjyMz)D}g
zyu4hm+*mKaC|%#s($Z4jz)0W7NEfI=x41H|B(Xv_uUHvsfJi^MBT&`V?*5(W8)NaQ$q`*G{Yn%sP!e8
zX$brCilM;(3=n;gjJ~0s0m#W9wv~TTW-8DXAS>+*ZNTy+W}wRQ8OZwuTEc-r)e
zXJYNF^E-d@_rH&y``*YqAXJn`a6!nT>n|U(d|;7EoyNehuiSc1j+uc=yYPo?bq}JW
z^wzCwY-H-&>Fn&yC)U6Ah5}>q0xpiy4Q;=9`CjUTGSuy!zMJjwGxzx&3mTjic{g5U
z`QckpR(`+pXOEh~G)Ja8w$nd6t`p9i-hJ)a7e4lO#Z9Z1IR=Vc{4QnNyuz>eW1&7=&I10Aa_om6OUn}cW%`PDH-~qGC
suFEnn_y6u-