From 08f0c51ce0383081d0f5025ca0657dd06c7cfa47 Mon Sep 17 00:00:00 2001 From: withoutcode333 <66198468+withoutcode333@users.noreply.github.com> Date: Fri, 18 Apr 2025 08:26:02 +0500 Subject: [PATCH] Upstream core (#284) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [Feature] Holo Update (#948) * Это база, основа, фундамент. * update icons * based2 * zamena headcoder * протоНовые функции Обновлены окна персонажа для отображения статистики и навыков игрока. Добавлена система боевой музыки, которая активируется во время боя. Реализована функция широковещательной передачи сообщений в чате для нескольких получателей. Внедрены изменения на основе навыков и статистики для медицинских систем, включая дефибриллятор и лечение. Улучшена система ближнего боя с новыми действиями и сообщениями. Введена система предсказуемого рандома для продвинутой генерации случайных значений. Навыки и статистика теперь зависят от назначений на работу. * abilities * zvuk * tweaks & fixes * sprite fix * govno * govno2 * fix govna * GOVNOOOOOOOOOOOO * finally * цена (cherry picked from commit cf4a7d0a7ccb780905e0df7db80d60d2338c02d0) * Automatic changelog update (cherry picked from commit 32a1f13849b4593fa03eafff99179814278f5f11) --------- Co-authored-by: RavmorganButOnCocaine --- .../_White/Guardian/GuardianSelectorBUI.cs | 114 +++++++++ Content.Server/Guardian/GuardianComponent.cs | 52 ++++- .../Guardian/GuardianCreatorComponent.cs | 32 --- Content.Server/Guardian/GuardianSystem.cs | 210 ++++++++++++++++- .../_White/Commands/PoshelnahuiCommand.cs | 2 +- .../Systems/CultSystem.ConstructsAbilities.cs | 2 + .../IncorporealSystem/IncorporealComponent.cs | 5 +- .../IncorporealSystem/IncorporealSystem.cs | 8 +- .../_White/Wizard/Magic/WizardSpellsSystem.cs | 2 + .../Guardian/GuardianCreatorComponent.cs | 49 ++++ .../Guardian/GuardianCreatorDoAfterEvent.cs | 4 +- .../_White/Guardian/GuardianEvents.cs | 53 +++++ Resources/Audio/White/Guardian/charger.ogg | Bin 0 -> 11457 bytes Resources/Changelog/ChangelogWhite.yml | 54 ++++- .../Locale/ru-RU/_white/guardian/guardian.ftl | 4 + .../Prototypes/Catalog/uplink_catalog.yml | 2 +- .../Entities/Mobs/Player/guardian.yml | 221 ++++++++++++++++-- .../Syndicate_Gadgets/guardian_activators.yml | 9 + .../Prototypes/_White/Actions/guardian.yml | 36 +++ .../White/Interface/Guardian/power.png | Bin 0 -> 1446 bytes .../White/Interface/Guardian/powerOff.png | Bin 0 -> 1635 bytes .../guardianselector.rsi/assasin.png | Bin 0 -> 297 bytes .../guardianselector.rsi/charger.png | Bin 0 -> 276 bytes .../guardianselector.rsi/lighting.png | Bin 0 -> 252 bytes .../Interface/guardianselector.rsi/meta.json | 20 ++ .../guardianselector.rsi/standart.png | Bin 0 -> 268 bytes 26 files changed, 790 insertions(+), 89 deletions(-) create mode 100644 Content.Client/_White/Guardian/GuardianSelectorBUI.cs delete mode 100644 Content.Server/Guardian/GuardianCreatorComponent.cs create mode 100644 Content.Shared/Guardian/GuardianCreatorComponent.cs create mode 100644 Content.Shared/_White/Guardian/GuardianEvents.cs create mode 100644 Resources/Audio/White/Guardian/charger.ogg create mode 100644 Resources/Locale/ru-RU/_white/guardian/guardian.ftl create mode 100644 Resources/Prototypes/_White/Actions/guardian.yml create mode 100644 Resources/Textures/White/Interface/Guardian/power.png create mode 100644 Resources/Textures/White/Interface/Guardian/powerOff.png create mode 100644 Resources/Textures/White/Interface/guardianselector.rsi/assasin.png create mode 100644 Resources/Textures/White/Interface/guardianselector.rsi/charger.png create mode 100644 Resources/Textures/White/Interface/guardianselector.rsi/lighting.png create mode 100644 Resources/Textures/White/Interface/guardianselector.rsi/meta.json create mode 100644 Resources/Textures/White/Interface/guardianselector.rsi/standart.png diff --git a/Content.Client/_White/Guardian/GuardianSelectorBUI.cs b/Content.Client/_White/Guardian/GuardianSelectorBUI.cs new file mode 100644 index 0000000000..6b4799e56d --- /dev/null +++ b/Content.Client/_White/Guardian/GuardianSelectorBUI.cs @@ -0,0 +1,114 @@ +using Content.Client._White.UserInterface.Radial; +using Content.Shared._White.Guardian; + +namespace Content.Client._White.Guardian; + +public sealed class GuardianSelectorBUI : BoundUserInterface +{ + private readonly Dictionary _names = new() + { + { GuardianSelector.Assasin, Loc.GetString("guardian-assasin-name")}, + { GuardianSelector.Charger, Loc.GetString("guardian-charger-name")}, + { GuardianSelector.Lighting, Loc.GetString("guardian-lighting-name")}, + { GuardianSelector.Standart, Loc.GetString("guardian-standart-name")}, + }; + + private readonly Dictionary _icons = new() + { + { GuardianSelector.Assasin, "/Textures/White/Interface/guardianselector.rsi/assasin.png" }, + { GuardianSelector.Charger, "/Textures/White/Interface/guardianselector.rsi/charger.png" }, + { GuardianSelector.Lighting, "/Textures/White/Interface/guardianselector.rsi/lighting.png" }, + { GuardianSelector.Standart, "/Textures/White/Interface/guardianselector.rsi/standart.png" }, + }; + + private readonly Dictionary _guardianSelectors = new() + { + { "Assasin", GuardianSelector.Assasin }, + { "Charger", GuardianSelector.Charger }, + { "Lighting", GuardianSelector.Lighting }, + { "Standart", GuardianSelector.Standart }, + }; + + private RadialContainer? _radialContainer; + private bool _updated; + + public GuardianSelectorBUI(EntityUid owner, Enum uiKey) : base(owner, uiKey) + { + } + + protected override void Open() + { + base.Open(); + + if (_radialContainer != null) + UIReset(); + + _radialContainer = new RadialContainer(); + + _radialContainer.Closed += Close; + + if (State != null) + UpdateState(State); + } + + private void UIReset() + { + _radialContainer?.Close(); + _radialContainer = null; + _updated = false; + } + + private void PopulateRadial(IReadOnlyCollection ids, NetEntity target) + { + foreach (var id in ids) + { + if (_radialContainer == null) + continue; + + if(!_guardianSelectors.TryGetValue(id, out var guardianSelector)) + return; + + if(!_names.TryGetValue(guardianSelector, out var name) || !_icons.TryGetValue(guardianSelector, out var icon)) + return; + + var button = _radialContainer.AddButton(name, icon); + button.Controller.OnPressed += _ => + { + Select(guardianSelector, target); + }; + } + } + + private void Select(GuardianSelector type, NetEntity target) + { + SendMessage(new GuardianSelectorSelectedBuiMessage(type, target)); + UIReset(); + Close(); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + _radialContainer?.Close(); + } + + protected override void UpdateState(BoundUserInterfaceState state) + { + base.UpdateState(state); + + if (_updated) + return; + + if (state is GuardianSelectorBUIState newState) + { + PopulateRadial(newState.Ids, newState.Target); + } + + if (_radialContainer == null) + return; + + _radialContainer?.OpenAttachedLocalPlayer(); + _updated = true; + } +} + diff --git a/Content.Server/Guardian/GuardianComponent.cs b/Content.Server/Guardian/GuardianComponent.cs index a54d033756..f9958f08f7 100644 --- a/Content.Server/Guardian/GuardianComponent.cs +++ b/Content.Server/Guardian/GuardianComponent.cs @@ -1,3 +1,8 @@ +using Content.Shared._White.Guardian; +using Robust.Shared.Audio; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + namespace Content.Server.Guardian { /// @@ -15,20 +20,63 @@ namespace Content.Server.Guardian /// /// Percentage of damage reflected from the guardian to the host /// - [DataField] + [DataField("damageShare")] public float DamageShare { get; set; } = 0.65f; /// /// Maximum distance the guardian can travel before it's forced to recall, use YAML to set /// - [DataField] + [DataField("distance")] public float DistanceAllowed { get; set; } = 5f; + /// + /// Maximum default distance the guardian can travel before it's forced to recall, use YAML to set + /// + [DataField("distanceDefault")] + public float DistanceAllowedDefault { get; set; } = 10f; + + [DataField] + public float DistancePowerAssasin { get; set; } = 25f; + /// /// If the guardian is currently manifested /// [DataField] public bool GuardianLoose; + [DataField] + public GuardianSelector GuardianType = GuardianSelector.Standart; + + [DataField("powerToggleAction", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string PowerToggleAction = "ActionGuardianPowerToggle"; + + [DataField] + public EntityUid? PowerToggleActionEntity; + + [ViewVariables(VVAccess.ReadWrite), DataField] + public bool IsInPowerMode; + + [DataField("chargerPowerAction", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string ChargerPowerAction = "ActionChargerPower"; + + [DataField] + public EntityUid? ChargerPowerActionEntity; + + [ViewVariables(VVAccess.ReadWrite), DataField] + public bool IsCharged; + + [ViewVariables(VVAccess.ReadWrite), DataField("assasinDamageModifier")] + public float AssasinDamageModifier = 3F; + + [ViewVariables(VVAccess.ReadWrite), DataField] + public int LightingCount = 1; + + [ViewVariables(VVAccess.ReadWrite), DataField] + public SoundSpecifier? ChargerSound = new SoundPathSpecifier("/Audio/White/Guardian/charger.ogg"); + + [DataField] + public EntProtoId Action = "ActionToggleGuardian"; + + [DataField] public EntityUid? ActionEntity; } } diff --git a/Content.Server/Guardian/GuardianCreatorComponent.cs b/Content.Server/Guardian/GuardianCreatorComponent.cs deleted file mode 100644 index dfe801f290..0000000000 --- a/Content.Server/Guardian/GuardianCreatorComponent.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; - -namespace Content.Server.Guardian -{ - /// - /// Creates a GuardianComponent attached to the user's GuardianHost. - /// - [RegisterComponent] - public sealed partial class GuardianCreatorComponent : Component - { - /// - /// Counts as spent upon exhausting the injection - /// - /// - /// We don't mark as deleted as examine depends on this. - /// - public bool Used = false; - - /// - /// The prototype of the guardian entity which will be created - /// - [DataField("guardianProto", customTypeSerializer:typeof(PrototypeIdSerializer), required: true)] - public string GuardianProto { get; set; } = default!; - - /// - /// How long it takes to inject someone. - /// - [DataField("delay")] - public float InjectionDelay = 5f; - } -} diff --git a/Content.Server/Guardian/GuardianSystem.cs b/Content.Server/Guardian/GuardianSystem.cs index 203882ed9e..1622a45576 100644 --- a/Content.Server/Guardian/GuardianSystem.cs +++ b/Content.Server/Guardian/GuardianSystem.cs @@ -1,7 +1,9 @@ +using Content.Server._White.IncorporealSystem; using Content.Server.Body.Systems; +using Content.Server.Lightning; using Content.Server.Popups; +using Content.Shared._White.Guardian; using Content.Shared.Actions; -using Content.Shared.Audio; using Content.Shared.Damage; using Content.Shared.DoAfter; using Content.Shared.Examine; @@ -12,7 +14,7 @@ using Content.Shared.Interaction; using Content.Shared.Interaction.Events; using Content.Shared.Mobs; using Content.Shared.Popups; -using Robust.Server.GameObjects; +using Content.Shared.Weapons.Melee; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; @@ -35,6 +37,9 @@ namespace Content.Server.Guardian [Dependency] private readonly BodySystem _bodySystem = default!; [Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly SharedUserInterfaceSystem _ui = default!; + [Dependency] private readonly LightningSystem _lightningSystem = default!; + [Dependency] private readonly DamageableSystem _damageableSystem = default!; public override void Initialize() { @@ -58,8 +63,93 @@ namespace Content.Server.Guardian SubscribeLocalEvent(OnPerformAction); SubscribeLocalEvent(OnGuardianAttackAttempt); + + // PARSEC EDIT START + SubscribeLocalEvent(OnGuardianSelected); + SubscribeLocalEvent(OnPerformGuardianPowerAction); + SubscribeLocalEvent(OnPerformChargerPowerAction); + SubscribeLocalEvent(OnPerformGuardianAction); } + // PARSEC EDIT START + + private void OnGuardianSelected(EntityUid uid, + GuardianCreatorComponent component, + GuardianSelectorSelectedBuiMessage args) + { + var target = GetEntity(args.Target); + _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, args.Actor, component.InjectionDelay, new GuardianCreatorDoAfterEvent{SelectedType = args.GuardianType}, uid, target: target, used: uid){BreakOnMove = true}); + } + + private void OnPerformGuardianPowerAction(EntityUid uid, + GuardianComponent component, + ToggleGuardianPowerActionEvent args) + { + if(args.Handled) + return; + + args.Handled = true; + ToggleGuardianPower(uid, component, !component.IsInPowerMode); + } + + private void ToggleGuardianPower(EntityUid uid, GuardianComponent component, bool toggleValue) + { + if (component.IsInPowerMode == toggleValue) + return; + + if(component.PowerToggleActionEntity == null) + return; + + if (component is { IsInPowerMode: false, GuardianLoose: true }) + { + _popupSystem.PopupEntity("Вы должны находится в теле, чтобы активировать способность!", uid, uid, PopupType.MediumCaution); + return; + } + + component.IsInPowerMode = toggleValue; + + _actionSystem.SetToggled(component.PowerToggleActionEntity, component.IsInPowerMode); + SetupPower(uid, component, component.GuardianType); + } + + private void SetupPower(EntityUid uid, GuardianComponent component, GuardianSelector type) + { + if (type == GuardianSelector.Assasin) + SetupAssasin(uid, component); + } + + private void SetupAssasin(EntityUid uid, GuardianComponent component) + { + if (HasComp(uid)) + { + RemComp(uid); + _actionSystem.SetToggled(component.PowerToggleActionEntity, !component.IsInPowerMode); + component.IsInPowerMode = false; + component.DistanceAllowed = component.DistanceAllowedDefault; + return; + } + + var incorporealComp = EnsureComp(uid); + incorporealComp.Effect = false; + component.DistanceAllowed = component.DistancePowerAssasin; + } + + private void OnPerformChargerPowerAction(EntityUid uid, GuardianComponent component, ChargerPowerActionEvent args) + { + if(args.Handled) + return; + + args.Handled = true; + + if(component.IsCharged) + return; + + component.IsCharged = true; + _audio.PlayPvs(component.ChargerSound, uid); + } + + //Parsec edit end + private void OnGuardianShutdown(EntityUid uid, GuardianComponent component, ComponentShutdown args) { var host = component.Host; @@ -70,6 +160,10 @@ namespace Content.Server.Guardian _container.Remove(uid, hostComponent.GuardianContainer); hostComponent.HostedGuardian = null; + if(component.PowerToggleActionEntity != null) + _actionSystem.RemoveAction(uid, component.PowerToggleActionEntity); // Parsec + if(component.ChargerPowerActionEntity != null) + _actionSystem.RemoveAction(uid, component.ChargerPowerActionEntity); // parsec Dirty(host.Value, hostComponent); QueueDel(hostComponent.ActionEntity); hostComponent.ActionEntity = null; @@ -86,6 +180,24 @@ namespace Content.Server.Guardian args.Handled = true; } + private void OnPerformGuardianAction(EntityUid uid, GuardianComponent component, GuardianToggleActionEvent args) + { + if (args.Handled) + return; + + if(component.Host == null) + return; + + var host = (EntityUid) component.Host; + + if(!TryComp(host, out var guardianHostComponent)) + return; + + ToggleGuardian(host, guardianHostComponent); + + args.Handled = true; + } + private void OnGuardianPlayerDetached(EntityUid uid, GuardianComponent component, PlayerDetachedEvent args) { var host = component.Host; @@ -109,6 +221,19 @@ namespace Content.Server.Guardian } _popupSystem.PopupEntity(Loc.GetString("guardian-available"), host.Value, host.Value); + + _actionSystem.AddAction(uid, ref component.ActionEntity, component.Action); + + if (component.GuardianType is GuardianSelector.Standart or GuardianSelector.Lighting) + return; + + if (component.GuardianType == GuardianSelector.Charger) + { + _actionSystem.AddAction(uid, ref component.ChargerPowerActionEntity, component.ChargerPowerAction); + return; + } + + _actionSystem.AddAction(uid, ref component.PowerToggleActionEntity, component.PowerToggleAction); } private void OnHostInit(EntityUid uid, GuardianHostComponent component, ComponentInit args) @@ -133,12 +258,55 @@ namespace Content.Server.Guardian private void OnGuardianAttackAttempt(EntityUid uid, GuardianComponent component, AttackAttemptEvent args) { - if (args.Cancelled || args.Target != component.Host) + if (args.Cancelled) return; - // why is this server side code? This should be in shared - _popupSystem.PopupCursor(Loc.GetString("guardian-attack-host"), uid, PopupType.LargeCaution); - args.Cancel(); + if (args.Target == null) + return; + + if (args.Target == component.Host) + { + _popupSystem.PopupCursor(Loc.GetString("guardian-attack-host"), uid, PopupType.LargeCaution); + args.Cancel(); + return; + } + + var target = (EntityUid) args.Target; + + if (component.GuardianType == GuardianSelector.Lighting) + { + for (var i = 0; i < component.LightingCount; i++) + { + _lightningSystem.ShootLightning(uid, target); + } + } + + if (component.GuardianType == GuardianSelector.Assasin) + { + if (!component.IsInPowerMode) + return; + + if (!TryComp(args.Weapon, out var meleeWeaponComponent)) + return; + + _damageableSystem.TryChangeDamage(args.Target, + meleeWeaponComponent.Damage * component.AssasinDamageModifier, + true); + SetupAssasin(uid, component); + } + + if (component.GuardianType == GuardianSelector.Charger) + { + if(!component.IsCharged) + return; + + foreach (var hand in _handsSystem.EnumerateHands(target)) + { + _handsSystem.TryDrop(target, hand); + } + + component.IsCharged = false; + } } public void ToggleGuardian(EntityUid user, GuardianHostComponent hostComponent) @@ -172,6 +340,7 @@ namespace Content.Server.Guardian args.Handled = true; UseCreator(args.User, args.Target.Value, uid, component); } + private void UseCreator(EntityUid user, EntityUid target, EntityUid injector, GuardianCreatorComponent component) { if (component.Used) @@ -194,10 +363,11 @@ namespace Content.Server.Guardian return; } - _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, user, component.InjectionDelay, new GuardianCreatorDoAfterEvent(), injector, target: target, used: injector){BreakOnMove = true}); + _ui.SetUiState(injector, GuardianSelectorUiKey.Key, new GuardianSelectorBUIState(component.GuardiansAvaliable, GetNetEntity(target))); + _ui.OpenUi(injector, GuardianSelectorUiKey.Key, user); } - private void OnDoAfter(EntityUid uid, GuardianCreatorComponent component, DoAfterEvent args) + private void OnDoAfter(EntityUid uid, GuardianCreatorComponent component, GuardianCreatorDoAfterEvent args) { if (args.Handled || args.Args.Target == null) return; @@ -207,14 +377,16 @@ namespace Content.Server.Guardian var hostXform = Transform(args.Args.Target.Value); var host = EnsureComp(args.Args.Target.Value); + var guardianProto = component.GuardianSelectorToProto[args.SelectedType]; // Parsec // Use map position so it's not inadvertantly parented to the host + if it's in a container it spawns outside I guess. - var guardian = Spawn(component.GuardianProto, _transform.GetMapCoordinates(args.Args.Target.Value, xform: hostXform)); + var guardian = Spawn(guardianProto, _transform.GetMapCoordinates(args.Args.Target.Value, xform: hostXform)); // Parsec edit _container.Insert(guardian, host.GuardianContainer); host.HostedGuardian = guardian; if (TryComp(guardian, out var guardianComp)) { + guardianComp.GuardianType = args.SelectedType; guardianComp.Host = args.Args.Target.Value; _audio.PlayPvs("/Audio/Effects/guardian_inject.ogg", args.Args.Target.Value); _popupSystem.PopupEntity(Loc.GetString("guardian-created"), args.Args.Target.Value, args.Args.Target.Value); @@ -273,8 +445,8 @@ namespace Content.Server.Guardian /// private void OnCreatorExamine(EntityUid uid, GuardianCreatorComponent component, ExaminedEvent args) { - if (component.Used) - args.PushMarkup(Loc.GetString("guardian-activator-empty-examine")); + if (component.Used) + args.PushMarkup(Loc.GetString("guardian-activator-empty-examine")); } /// @@ -344,7 +516,7 @@ namespace Content.Server.Guardian guardianComponent.GuardianLoose = true; } - private void RetractGuardian(EntityUid host,GuardianHostComponent hostComponent, EntityUid guardian, GuardianComponent guardianComponent) + private void RetractGuardian(EntityUid host, GuardianHostComponent hostComponent, EntityUid guardian, GuardianComponent guardianComponent) { if (!guardianComponent.GuardianLoose) { @@ -355,6 +527,20 @@ namespace Content.Server.Guardian _container.Insert(guardian, hostComponent.GuardianContainer); DebugTools.Assert(hostComponent.GuardianContainer.Contains(guardian)); _popupSystem.PopupEntity(Loc.GetString("guardian-entity-recall"), host); + if (guardianComponent.IsInPowerMode) + { + if (guardianComponent.GuardianType == GuardianSelector.Assasin) + { + SetupPower(guardian, guardianComponent, guardianComponent.GuardianType); + return; + } + + guardianComponent.IsInPowerMode = false; + if (guardianComponent.PowerToggleActionEntity != null) + { + _actionSystem.SetToggled(guardianComponent.PowerToggleActionEntity, guardianComponent.IsInPowerMode); + } + } guardianComponent.GuardianLoose = false; } } diff --git a/Content.Server/_White/Commands/PoshelnahuiCommand.cs b/Content.Server/_White/Commands/PoshelnahuiCommand.cs index 722f3123b1..00152e2387 100644 --- a/Content.Server/_White/Commands/PoshelnahuiCommand.cs +++ b/Content.Server/_White/Commands/PoshelnahuiCommand.cs @@ -13,7 +13,7 @@ public sealed class PoshelnahuiCommand : IConsoleCommand public string Command => "poshelnahui"; public string Description => "Close client game lol"; public string Help => "poshelnahui "; - private readonly List _vip = ["Valtos", "SamsungS", "Dosharus", "BIG_Zi_348"]; + private readonly List _vip = ["Valtos", "SamsungS", "Dosharus", "CaypenNow"]; public void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length != 1 || string.IsNullOrEmpty(args[0])) diff --git a/Content.Server/_White/Cult/Runes/Systems/CultSystem.ConstructsAbilities.cs b/Content.Server/_White/Cult/Runes/Systems/CultSystem.ConstructsAbilities.cs index 93eff0bebc..ce78d38770 100644 --- a/Content.Server/_White/Cult/Runes/Systems/CultSystem.ConstructsAbilities.cs +++ b/Content.Server/_White/Cult/Runes/Systems/CultSystem.ConstructsAbilities.cs @@ -157,6 +157,8 @@ public partial class CultSystem _statusEffectsSystem.TryAddStatusEffect(ev.Performer, ev.StatusEffectId, TimeSpan.FromSeconds(ev.Duration), false); + Spawn("EffectEmpPulse", Transform(ev.Performer).Coordinates); + ev.Handled = true; } diff --git a/Content.Server/_White/IncorporealSystem/IncorporealComponent.cs b/Content.Server/_White/IncorporealSystem/IncorporealComponent.cs index aa2eba7a8e..98e52aad91 100644 --- a/Content.Server/_White/IncorporealSystem/IncorporealComponent.cs +++ b/Content.Server/_White/IncorporealSystem/IncorporealComponent.cs @@ -6,10 +6,11 @@ namespace Content.Server._White.IncorporealSystem; public sealed partial class IncorporealComponent : Component { [DataField] public float MovementSpeedBuff = 1.5f; + [DataField] public bool Effect = true; [DataField] public int CollisionMask = (int) CollisionGroup.GhostImpassable; [DataField] public int CollisionLayer = 0; - + public int StoredMask; public int StoredLayer; -} \ No newline at end of file +} diff --git a/Content.Server/_White/IncorporealSystem/IncorporealSystem.cs b/Content.Server/_White/IncorporealSystem/IncorporealSystem.cs index a3b658e2ca..1ca96ab675 100644 --- a/Content.Server/_White/IncorporealSystem/IncorporealSystem.cs +++ b/Content.Server/_White/IncorporealSystem/IncorporealSystem.cs @@ -53,7 +53,6 @@ public sealed class IncorporealSystem : EntitySystem _visibilitySystem.RefreshVisibility(uid); } - Spawn("EffectEmpPulse", Transform(uid).Coordinates); EnsureComp(uid); _stealth.SetVisibility(uid, -1); if (TryComp(uid, out PullableComponent? pullable)) @@ -79,7 +78,12 @@ public sealed class IncorporealSystem : EntitySystem } component.MovementSpeedBuff = 1; - Spawn("EffectEmpPulse", _transform.GetMapCoordinates(uid)); + + if (component.Effect) + { + Spawn("EffectEmpPulse", _transform.GetMapCoordinates(uid)); + } + _stealth.SetVisibility(uid, 1); RemComp(uid); _movement.RefreshMovementSpeedModifiers(uid); diff --git a/Content.Server/_White/Wizard/Magic/WizardSpellsSystem.cs b/Content.Server/_White/Wizard/Magic/WizardSpellsSystem.cs index 9119c482a1..5e95d43c0e 100644 --- a/Content.Server/_White/Wizard/Magic/WizardSpellsSystem.cs +++ b/Content.Server/_White/Wizard/Magic/WizardSpellsSystem.cs @@ -404,6 +404,8 @@ public sealed class WizardSpellsSystem : EntitySystem _statusEffectsSystem.TryAddStatusEffect(msg.Performer, "Incorporeal", TimeSpan.FromSeconds(10), false); + Spawn("EffectEmpPulse", Transform(msg.Performer).Coordinates); + Cast(msg); } diff --git a/Content.Shared/Guardian/GuardianCreatorComponent.cs b/Content.Shared/Guardian/GuardianCreatorComponent.cs new file mode 100644 index 0000000000..3cb04ba1c8 --- /dev/null +++ b/Content.Shared/Guardian/GuardianCreatorComponent.cs @@ -0,0 +1,49 @@ +using Content.Shared._White.Guardian; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Shared.Guardian +{ + /// + /// Creates a GuardianComponent attached to the user's GuardianHost. + /// + [RegisterComponent, NetworkedComponent] + public sealed partial class GuardianCreatorComponent : Component + { + /// + /// Counts as spent upon exhausting the injection + /// + /// + /// We don't mark as deleted as examine depends on this. + /// + [DataField] + public bool Used = false; + + /// + /// The prototype of the guardian entity which will be created + /// + [DataField("guardianProto", + customTypeSerializer: typeof(PrototypeIdSerializer), + required: true)] + public string GuardianProto; + + /// + /// How long it takes to inject someone. + /// + [DataField("delay")] + public float InjectionDelay = 5f; + + [DataField("guardiansAvaliable")] + public IReadOnlyCollection GuardiansAvaliable = ArraySegment.Empty; + + [DataField] + public Dictionary GuardianSelectorToProto = new() + { + { GuardianSelector.Assasin, "MobHoloparasiteGuardianAssasin" }, + { GuardianSelector.Standart, "MobHoloparasiteGuardianStandart" }, + { GuardianSelector.Charger, "MobHoloparasiteGuardianCharger" }, + { GuardianSelector.Lighting, "MobHoloparasiteGuardianLighting" } + }; + } +} diff --git a/Content.Shared/Guardian/GuardianCreatorDoAfterEvent.cs b/Content.Shared/Guardian/GuardianCreatorDoAfterEvent.cs index 8addfa2ed1..e9d85faddd 100644 --- a/Content.Shared/Guardian/GuardianCreatorDoAfterEvent.cs +++ b/Content.Shared/Guardian/GuardianCreatorDoAfterEvent.cs @@ -1,4 +1,5 @@ -using Content.Shared.DoAfter; +using Content.Shared._White.Guardian; +using Content.Shared.DoAfter; using Robust.Shared.Serialization; namespace Content.Shared.Guardian; @@ -6,4 +7,5 @@ namespace Content.Shared.Guardian; [Serializable, NetSerializable] public sealed partial class GuardianCreatorDoAfterEvent : SimpleDoAfterEvent { + public GuardianSelector SelectedType; // Parsec Edit } diff --git a/Content.Shared/_White/Guardian/GuardianEvents.cs b/Content.Shared/_White/Guardian/GuardianEvents.cs new file mode 100644 index 0000000000..a4a32809a6 --- /dev/null +++ b/Content.Shared/_White/Guardian/GuardianEvents.cs @@ -0,0 +1,53 @@ +using Content.Shared.Actions; +using Robust.Shared.Serialization; + +namespace Content.Shared._White.Guardian; + +public enum GuardianSelector : byte +{ + Assasin, + Standart, + Charger, + Lighting +} + +[Serializable, NetSerializable] +public enum GuardianSelectorUiKey : byte +{ + Key +} + +[Serializable, NetSerializable] +public sealed class GuardianSelectorBUIState : BoundUserInterfaceState +{ + public IReadOnlyCollection Ids { get; set; } + + public NetEntity Target { get; set; } + + public GuardianSelectorBUIState(IReadOnlyCollection ids, NetEntity target) + { + Ids = ids; + Target = target; + } +} + +[Serializable, NetSerializable] +public sealed class GuardianSelectorSelectedBuiMessage : BoundUserInterfaceMessage +{ + public GuardianSelector GuardianType; + public NetEntity Target; + + public GuardianSelectorSelectedBuiMessage(GuardianSelector guardianType, NetEntity target) + { + GuardianType = guardianType; + Target = target; + } +} + +public sealed partial class ToggleGuardianPowerActionEvent : InstantActionEvent +{ +} + +public sealed partial class ChargerPowerActionEvent : InstantActionEvent +{ +} diff --git a/Resources/Audio/White/Guardian/charger.ogg b/Resources/Audio/White/Guardian/charger.ogg new file mode 100644 index 0000000000000000000000000000000000000000..80211eeeaf0d708f83dbaba985f955dc65849e5f GIT binary patch literal 11457 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 PBi-m+xfqKKOwj%x7G+@Z literal 0 HcmV?d00001 diff --git a/Resources/Changelog/ChangelogWhite.yml b/Resources/Changelog/ChangelogWhite.yml index 60539d3ea5..3f327a32f5 100644 --- a/Resources/Changelog/ChangelogWhite.yml +++ b/Resources/Changelog/ChangelogWhite.yml @@ -1,16 +1,4 @@ Entries: -- author: Aviu - changes: - - message: "\u0411\u0417 \u0442\u0435\u043F\u0435\u0440\u044C \u0443\u0441\u044B\ - \u043F\u043B\u044F\u0435\u0442 \u0433\u0435\u043D\u043E\u043A\u0440\u0430\u0434\ - \u043E\u0432." - type: Add - - message: "\u041D\u0438\u0442\u0440\u0438\u0443\u043C \u0441\u043D\u043E\u0432\u0430\ - \ \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442." - type: Fix - id: 178 - time: '2024-03-03T08:09:04.0000000+00:00' - url: https://api.github.com/repos/frosty-dev/ss14-core/pulls/167 - author: ThereDrD changes: - message: "\u0424\u0438\u043A\u0441 \u043F\u0443\u0441\u0442\u044B\u0445 \u0441\ @@ -9078,3 +9066,45 @@ id: 677 time: '2025-04-13T16:14:06.0000000+00:00' url: https://api.github.com/repos/frosty-dev/ss14-core/pulls/947 +- author: CaypenNow + changes: + - message: "\u0413\u043E\u043B\u043E\u043F\u0430\u0440\u0430\u0437\u0438\u0442\u044B\ + \ \u043F\u043E\u043B\u0443\u0447\u0438\u043B\u0438 \u043F\u043E\u043B\u043D\u043E\ + \u0435 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435. \u0422\u0435\ + \u043F\u0435\u0440\u044C, \u043F\u0440\u0438 \u0438\u043C\u043F\u043B\u0430\u043D\ + \u0442\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u0438 \u0433\u043E\u043B\u043E\ + \u043F\u0430\u0440\u0430\u0437\u0438\u0442\u0430, \u0435\u0441\u0442\u044C \u0432\ + \u043E\u0437\u043C\u043E\u0436\u043D\u043E\u0441\u0442\u044C \u0432\u044B\u0431\ + \u0440\u0430\u0442\u044C \u043E\u0434\u0438\u043D \u0438\u0437 4 \u043A\u043B\ + \u0430\u0441\u0441\u043E\u0432. \u041A\u0430\u0436\u0434\u044B\u0439 \u043A\u043B\ + \u0430\u0441\u0441 \u0438\u043C\u0435\u0435\u0442 \u0440\u0430\u0437\u043B\u0438\ + \u0447\u0438\u044F, \u0430 \u043D\u0435\u043A\u043E\u0442\u043E\u0440\u044B\u0435\ + \ \u0438 \u0441\u043E\u0431\u0441\u0442\u0432\u0435\u043D\u043D\u044B\u0435\ + \ \u0441\u043F\u043E\u0441\u043E\u0431\u043D\u043E\u0441\u0442\u0438." + type: Add + - message: "\u0413\u043E\u043B\u043E\u043F\u0430\u0440\u0430\u0437\u0438\u0442 \u043F\ + \u043E\u043B\u0443\u0447\u0438\u043B \u043D\u043E\u0432\u044B\u0439 \u0441\u043F\ + \u0440\u0430\u0439\u0442" + type: Add + - message: "\u0422\u0435\u043F\u0435\u0440\u044C \u0433\u043E\u043B\u043E\u043F\u0430\ + \u0440\u0430\u0437\u0438\u0442 \u043C\u043E\u0436\u0435\u0442 \u0432\u044B\u0445\ + \u043E\u0434\u0438\u0442\u044C \u0438\u0437 \u0442\u0435\u043B\u0430 \u0441\u0430\ + \u043C" + type: Tweak + - message: "\u0422\u0435\u043F\u0435\u0440\u044C \u0433\u043E\u043B\u043E\u043F\u0430\ + \u0440\u0430\u0437\u0438\u0442 \u043C\u043E\u0436\u0435\u0442 \u0442\u0430\u0441\ + \u043A\u0430\u0442\u044C \u0432\u0435\u0449\u0438\u0442\u044C" + type: Tweak + - message: "\u0422\u0435\u043F\u0435\u0440\u044C \u0446\u0432\u0435\u0442 \u0433\ + \u043E\u043B\u043E\u043F\u0430\u0440\u0430\u0437\u0438\u0442\u0430 - \u0443\u043D\ + \u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0439 \u0434\u043B\u044F \u043A\u043B\ + \u0430\u0441\u0441\u0430, \u0430 \u043D\u0435 \u043F\u0440\u043E\u0441\u0442\ + \u043E \u0440\u0430\u043D\u0434\u043E\u043C\u043D\u044B\u0439." + type: Tweak + - message: "\u0426\u0435\u043D\u0430 \u0433\u043E\u043B\u043E\u043F\u0430\u0440\u0430\ + \u0437\u0438\u0442\u0430 \u043F\u043E\u0432\u044B\u0448\u0435\u043D\u0430. 12\ + \ \u0422\u041A --> 13 \u0422\u041A" + type: Tweak + id: 678 + time: '2025-04-18T03:18:09.0000000+00:00' + url: https://api.github.com/repos/frosty-dev/ss14-core/pulls/948 diff --git a/Resources/Locale/ru-RU/_white/guardian/guardian.ftl b/Resources/Locale/ru-RU/_white/guardian/guardian.ftl new file mode 100644 index 0000000000..2d654b9c2a --- /dev/null +++ b/Resources/Locale/ru-RU/_white/guardian/guardian.ftl @@ -0,0 +1,4 @@ +guardian-assasin-name = Ассасин +guardian-lighting-name = Молниеносный +guardian-charger-name = Быстрый +guardian-standart-name = Классический \ No newline at end of file diff --git a/Resources/Prototypes/Catalog/uplink_catalog.yml b/Resources/Prototypes/Catalog/uplink_catalog.yml index d5020e2829..8204558502 100644 --- a/Resources/Prototypes/Catalog/uplink_catalog.yml +++ b/Resources/Prototypes/Catalog/uplink_catalog.yml @@ -922,7 +922,7 @@ icon: { sprite: /Textures/Objects/Misc/guardian_info.rsi, state: icon } productEntity: BoxHoloparasite cost: - Telecrystal: 12 + Telecrystal: 13 categories: - UplinkAllies conditions: diff --git a/Resources/Prototypes/Entities/Mobs/Player/guardian.yml b/Resources/Prototypes/Entities/Mobs/Player/guardian.yml index c044105a7a..68192a5d50 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/guardian.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/guardian.yml @@ -20,6 +20,7 @@ context: "human" - type: MobMover - type: InputMover + - type: Puller - type: MovementSpeedModifier baseWalkSpeed: 4 baseSprintSpeed: 5.5 @@ -29,20 +30,6 @@ Blunt: 5 soundHit: collection: MetalThud - - type: RandomSprite - available: - - enum.DamageStateVisualLayers.Base: - magic_base: "" - enum.DamageStateVisualLayers.BaseUnshaded: - magic_flare: Sixteen - - enum.DamageStateVisualLayers.Base: - miner_base: "" - enum.DamageStateVisualLayers.BaseUnshaded: - miner_flare: Sixteen - - enum.DamageStateVisualLayers.Base: - tech_base: "" - enum.DamageStateVisualLayers.BaseUnshaded: - tech_flare: Sixteen - type: Sprite drawdepth: Mobs sprite: White/Mobs/Aliens/Guardians/guardians.rsi @@ -112,8 +99,8 @@ # From the uplink injector - type: entity - name: Holoparasite - id: MobHoloparasiteGuardian + name: HoloparasiteStandart + id: MobHoloparasiteGuardianStandart parent: MobGuardianBase description: A mesmerising whirl of hard-light patterns weaves a marvelous, yet oddly familiar visage. It stands proud, tuning into its owner's life to sustain itself. components: @@ -126,22 +113,208 @@ raffle: settings: default - type: GhostTakeoverAvailable + - type: Sprite + drawdepth: Mobs + sprite: White/Mobs/Aliens/Guardians/guardians.rsi + layers: + - state: tech_base + map: [ "enum.DamageStateVisualLayers.Base" ] + - state: tech_flare + map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ] + color: "#707070" + shader: unshaded + noRot: true + - type: Guardian + damageShare: 0.5 + distance: 6 + - type: MovementSpeedModifier + baseWalkSpeed: 4.5 + baseSprintSpeed: 6 + - type: DamageOnHighSpeedImpact + damage: + types: + Blunt: 5 + soundHit: + collection: MetalThud + - type: MeleeWeapon + hidden: false + altDisarm: false + animation: WeaponArcFist + attackRate: 2.2 + autoAttack: true + soundHit: + collection: Punch + damage: + types: + Blunt: 24 + Structural: 24 - type: NameIdentifier group: Holoparasite - type: TypingIndicator proto: holo - - type: Sprite - layers: - - state: tech_base - map: [ "enum.DamageStateVisualLayers.Base" ] - - state: tech_flare - map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ] - color: "#40a7d7" - shader: unshaded - type: HTN rootTask: task: SimpleHumanoidHostileCompound +- type: entity + name: HoloparasiteAssasin + id: MobHoloparasiteGuardianAssasin + parent: MobGuardianBase + description: A mesmerising whirl of hard-light patterns weaves a marvelous, yet oddly familiar visage. It stands proud, tuning into its owner's life to sustain itself. + components: + - type: GhostRole + allowMovement: true + allowSpeech: true + makeSentient: true + name: ghost-role-information-holoparasite-name + description: ghost-role-information-holoparasite-description + raffle: + settings: default + - type: GhostTakeoverAvailable + - type: Sprite + drawdepth: Mobs + sprite: White/Mobs/Aliens/Guardians/guardians.rsi + layers: + - state: tech_base + map: [ "enum.DamageStateVisualLayers.Base" ] + - state: tech_flare + map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ] + color: "#9d0016" + shader: unshaded + noRot: true + - type: Guardian + damageShare: 1 + distance: 10 + - type: MovementSpeedModifier + baseWalkSpeed: 4 + baseSprintSpeed: 5.5 + - type: DamageOnHighSpeedImpact + damage: + types: + Blunt: 5 + soundHit: + collection: MetalThud + - type: MeleeWeapon + hidden: false + altDisarm: false + animation: WeaponArcFist + attackRate: 2 + autoAttack: true + soundHit: + collection: Punch + damage: + types: + Blunt: 14 + Structural: 14 + - type: NameIdentifier + group: Holoparasite + - type: TypingIndicator + proto: holo + - type: HTN + rootTask: + task: SimpleHumanoidHostileCompound + +- type: entity + name: HoloparasiteCharger + id: MobHoloparasiteGuardianCharger + parent: MobGuardianBase + description: A mesmerising whirl of hard-light patterns weaves a marvelous, yet oddly familiar visage. It stands proud, tuning into its owner's life to sustain itself. + components: + - type: GhostRole + allowMovement: true + allowSpeech: true + makeSentient: true + name: ghost-role-information-holoparasite-name + description: ghost-role-information-holoparasite-description + raffle: + settings: default + - type: GhostTakeoverAvailable + - type: Sprite + drawdepth: Mobs + sprite: White/Mobs/Aliens/Guardians/guardians.rsi + layers: + - state: tech_base + map: [ "enum.DamageStateVisualLayers.Base" ] + - state: tech_flare + map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ] + color: "#54f3ff" + shader: unshaded + noRot: true + - type: MovementSpeedModifier + baseWalkSpeed: 6 + baseSprintSpeed: 7.5 + - type: DamageOnHighSpeedImpact + damage: + types: + Blunt: 5 + soundHit: + collection: MetalThud + - type: MeleeWeapon + hidden: false + altDisarm: false + animation: WeaponArcFist + attackRate: 2.5 + autoAttack: true + soundHit: + collection: Punch + damage: + types: + Blunt: 15 + Structural: 15 + - type: NameIdentifier + group: Holoparasite + - type: TypingIndicator + proto: holo + - type: HTN + rootTask: + task: SimpleHumanoidHostileCompound + +- type: entity + name: HoloparasiteLighting + id: MobHoloparasiteGuardianLighting + parent: MobGuardianBase + description: A mesmerising whirl of hard-light patterns weaves a marvelous, yet oddly familiar visage. It stands proud, tuning into its owner's life to sustain itself. + components: + - type: GhostRole + allowMovement: true + allowSpeech: true + makeSentient: true + name: ghost-role-information-holoparasite-name + description: ghost-role-information-holoparasite-description + raffle: + settings: default + - type: GhostTakeoverAvailable + - type: Sprite + drawdepth: Mobs + sprite: White/Mobs/Aliens/Guardians/guardians.rsi + layers: + - state: tech_base + map: [ "enum.DamageStateVisualLayers.Base" ] + - state: tech_flare + map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ] + color: "#2000c8" + shader: unshaded + noRot: true + - type: MeleeWeapon + hidden: false + altDisarm: false + animation: WeaponArcFist + attackRate: 1.8 + autoAttack: true + soundHit: + collection: Punch + damage: + types: + Blunt: 5 + Structural: 5 + - type: NameIdentifier + group: Holoparasite + - type: TypingIndicator + proto: holo + - type: HTN + rootTask: + task: SimpleHumanoidHostileCompound + # From Wizard deck of cards - type: entity name: Ifrit diff --git a/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/guardian_activators.yml b/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/guardian_activators.yml index 0b1769a3da..cdd3faee0e 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/guardian_activators.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/guardian_activators.yml @@ -9,6 +9,15 @@ state: combat_hypo - type: GuardianCreator guardianProto: MobHoloparasiteGuardian + guardiansAvaliable: + - Assasin + - Charger + - Standart + - Lighting + - type: UserInterface # PARSEC EDIT + interfaces: + enum.GuardianSelectorUiKey.Key: + type: GuardianSelectorBUI - type: entity name: holoclown injector diff --git a/Resources/Prototypes/_White/Actions/guardian.yml b/Resources/Prototypes/_White/Actions/guardian.yml new file mode 100644 index 0000000000..ed192777bd --- /dev/null +++ b/Resources/Prototypes/_White/Actions/guardian.yml @@ -0,0 +1,36 @@ +- type: entity + id: ActionGuardianPowerToggle + name: "[color=green]Сила голопаразита[/color]" + description: Уникальная способность голопаразита. + noSpawn: true + components: + - type: InstantAction + checkCanInteract: false + checkConsciousness: false + icon: White/Interface/Guardian/powerOff.png + iconOn: White/Interface/Guardian/power.png + event: !type:ToggleGuardianPowerActionEvent + +- type: entity + id: ActionGuardianPowerOff + parent: ActionCombatModeToggle + name: "[color=red]Сила голопаразита[/color]" + description: Уникальная способность голопаразита. + noSpawn: true + components: + - type: InstantAction + enabled: false + autoPopulate: false + +- type: entity + id: ActionChargerPower + name: "[color=green]Сила голопаразита[/color]" + description: Уникальная способность голопаразита, позволяет зарядить ваш кулак и одним ударом поразить цель. + noSpawn: true + components: + - type: InstantAction + useDelay: 4 + checkCanInteract: false + checkConsciousness: false + icon: White/Interface/Guardian/powerOff.png + event: !type:ChargerPowerActionEvent \ No newline at end of file diff --git a/Resources/Textures/White/Interface/Guardian/power.png b/Resources/Textures/White/Interface/Guardian/power.png new file mode 100644 index 0000000000000000000000000000000000000000..8fef8c374fcd18ad458f27569469f866867592f5 GIT binary patch literal 1446 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/White/Interface/guardianselector.rsi/assasin.png b/Resources/Textures/White/Interface/guardianselector.rsi/assasin.png new file mode 100644 index 0000000000000000000000000000000000000000..b83f25d08acce17800be669d5259b455b08a5c39 GIT binary patch literal 297 zcmV+^0oMMBP)Px#<4Ht8R9J=WR_zXhFbI@o55}YS&G5%Ohb>hoW@bq*F>2eu@p0&~OiVls@*FCq zG;7Q(#<|8GGoRXidkFL(^5sC}ilxCTLm=b$HUc^eKO=zpBYNDezPOzLoQTLCy?&08 z@D}i3R7A|$ch*mRxHF)mg%d=MJt8`s^B^ok?LPx#&PhZ;R9J=Wl~D@BFbG6vmOYq9_h$AhyV;s#e7${d==km4itvb3;~=U#q2;T0Ysg>LRF?=8o(9O6fUouE~G2ZYwYI)$)iu!u~3BTFG zdexNPFL5w+yEMDO;6OyC{L$A8VM{N%l`uwxuG;zS_*YAV*FR2(lrTqJx9NM9&9M09 z%1Vv{O_jQ=GoK|k=oBk_P<(m+|CK!Px##z{m$R9J=WRM8HDFbKqDAI7Km&)9>WyRptfb;*)(Nh2z~yFiObp-}jDETe?h z+8(Q_1@d=JRh_i;ZosgPzaiBCE$K%dY?7`az12;{o%|Q2^(OM(QU{e)dHS!BG1Xl70DuX2z#R#qO(;=O~Rgt z|L)$;PePO(2aXquVnN)uYubP}f#;_|q literal 0 HcmV?d00001