From 775258be5226e879321be60458f6f94125e252d1 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Thu, 18 May 2023 11:36:06 +1000 Subject: [PATCH] Add tether gun (#16430) --- .../Weapons/Misc/TetherGunOverlay.cs | 52 ++++ .../Weapons/Misc/TetherGunSystem.cs | 103 +++++++ .../Weapons/Ranged/Systems/TetherGunSystem.cs | 142 ---------- Content.Server/PowerCell/PowerCellSystem.cs | 12 + .../Weapons/Misc/TetherGunSystem.cs | 46 +++ .../Weapons/Ranged/Systems/TetherGunSystem.cs | 199 ------------- Content.Server/Weapons/TetherGunCommand.cs | 25 -- .../Buckle/Components/BuckleComponent.cs | 2 +- .../Weapons/Misc/SharedTetherGunSystem.cs | 267 ++++++++++++++++++ .../Weapons/Misc/TetherGunComponent.cs | 58 ++++ .../Weapons/Misc/TetheredComponent.cs | 16 ++ .../Ranged/Systems/SharedTetherGunSystem.cs | 43 --- Resources/Audio/Weapons/attributions.yml | 2 +- Resources/Audio/Weapons/licenses.txt | 6 +- Resources/Audio/Weapons/weoweo.ogg | Bin 0 -> 34523 bytes .../Locale/en-US/research/technologies.ftl | 1 + .../Prototypes/Entities/Objects/Fun/pai.yml | 1 - .../Weapons/Guns/Launchers/launchers.yml | 74 +++++ .../Prototypes/Entities/Objects/base_item.yml | 15 + .../Prototypes/Entities/Virtual/tether.yml | 1 + .../Prototypes/Research/experimental.yml | 12 + .../tether_gun.rsi/base-unshaded.png | Bin 0 -> 6130 bytes .../Guns/Launchers/tether_gun.rsi/base.png | Bin 0 -> 6047 bytes .../tether_gun.rsi/inhand-left-unshaded.png | Bin 0 -> 5927 bytes .../Launchers/tether_gun.rsi/inhand-left.png | Bin 0 -> 6134 bytes .../tether_gun.rsi/inhand-right-unshaded.png | Bin 0 -> 5909 bytes .../Launchers/tether_gun.rsi/inhand-right.png | Bin 0 -> 6110 bytes .../Guns/Launchers/tether_gun.rsi/meta.json | 33 +++ 28 files changed, 697 insertions(+), 413 deletions(-) create mode 100644 Content.Client/Weapons/Misc/TetherGunOverlay.cs create mode 100644 Content.Client/Weapons/Misc/TetherGunSystem.cs delete mode 100644 Content.Client/Weapons/Ranged/Systems/TetherGunSystem.cs create mode 100644 Content.Server/Weapons/Misc/TetherGunSystem.cs delete mode 100644 Content.Server/Weapons/Ranged/Systems/TetherGunSystem.cs delete mode 100644 Content.Server/Weapons/TetherGunCommand.cs create mode 100644 Content.Shared/Weapons/Misc/SharedTetherGunSystem.cs create mode 100644 Content.Shared/Weapons/Misc/TetherGunComponent.cs create mode 100644 Content.Shared/Weapons/Misc/TetheredComponent.cs delete mode 100644 Content.Shared/Weapons/Ranged/Systems/SharedTetherGunSystem.cs create mode 100644 Resources/Audio/Weapons/weoweo.ogg create mode 100644 Resources/Textures/Objects/Weapons/Guns/Launchers/tether_gun.rsi/base-unshaded.png create mode 100644 Resources/Textures/Objects/Weapons/Guns/Launchers/tether_gun.rsi/base.png create mode 100644 Resources/Textures/Objects/Weapons/Guns/Launchers/tether_gun.rsi/inhand-left-unshaded.png create mode 100644 Resources/Textures/Objects/Weapons/Guns/Launchers/tether_gun.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Weapons/Guns/Launchers/tether_gun.rsi/inhand-right-unshaded.png create mode 100644 Resources/Textures/Objects/Weapons/Guns/Launchers/tether_gun.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Weapons/Guns/Launchers/tether_gun.rsi/meta.json diff --git a/Content.Client/Weapons/Misc/TetherGunOverlay.cs b/Content.Client/Weapons/Misc/TetherGunOverlay.cs new file mode 100644 index 0000000000..215589c38d --- /dev/null +++ b/Content.Client/Weapons/Misc/TetherGunOverlay.cs @@ -0,0 +1,52 @@ +using Content.Shared.Weapons.Misc; +using Robust.Client.Graphics; +using Robust.Shared.Enums; + +namespace Content.Client.Weapons.Misc; + +public sealed class TetherGunOverlay : Overlay +{ + public override OverlaySpace Space => OverlaySpace.WorldSpaceBelowFOV; + + private IEntityManager _entManager; + + public TetherGunOverlay(IEntityManager entManager) + { + _entManager = entManager; + } + + protected override void Draw(in OverlayDrawArgs args) + { + var query = _entManager.EntityQueryEnumerator(); + var xformQuery = _entManager.GetEntityQuery(); + var worldHandle = args.WorldHandle; + var xformSystem = _entManager.System(); + + while (query.MoveNext(out var uid, out var tethered)) + { + var gun = tethered.Tetherer; + + if (!xformQuery.TryGetComponent(gun, out var gunXform) || + !xformQuery.TryGetComponent(uid, out var xform)) + { + continue; + } + + if (xform.MapID != gunXform.MapID) + continue; + + var worldPos = xformSystem.GetWorldPosition(xform, xformQuery); + var gunWorldPos = xformSystem.GetWorldPosition(gunXform, xformQuery); + var diff = worldPos - gunWorldPos; + var angle = diff.ToWorldAngle(); + var length = diff.Length / 2f; + var midPoint = gunWorldPos + diff / 2; + const float Width = 0.05f; + + var box = new Box2(-Width, -length, Width, length); + var rotated = new Box2Rotated(box.Translated(midPoint), angle, midPoint); + + worldHandle.DrawRect(rotated, Color.Orange.WithAlpha(0.3f)); + } + } +} diff --git a/Content.Client/Weapons/Misc/TetherGunSystem.cs b/Content.Client/Weapons/Misc/TetherGunSystem.cs new file mode 100644 index 0000000000..1219fe1357 --- /dev/null +++ b/Content.Client/Weapons/Misc/TetherGunSystem.cs @@ -0,0 +1,103 @@ +using Content.Shared.Weapons.Misc; +using Robust.Client.GameObjects; +using Robust.Client.Graphics; +using Robust.Client.Input; +using Robust.Client.Player; +using Robust.Shared.Map; +using Robust.Shared.Timing; + +namespace Content.Client.Weapons.Misc; + +public sealed class TetherGunSystem : SharedTetherGunSystem +{ + [Dependency] private readonly IEyeManager _eyeManager = default!; + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly IInputManager _input = default!; + [Dependency] private readonly IMapManager _mapManager = default!; + [Dependency] private readonly IOverlayManager _overlay = default!; + [Dependency] private readonly IPlayerManager _player = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnTetheredStartup); + SubscribeLocalEvent(OnTetheredShutdown); + _overlay.AddOverlay(new TetherGunOverlay(EntityManager)); + } + + public override void Shutdown() + { + base.Shutdown(); + _overlay.RemoveOverlay(); + } + + protected override bool CanTether(EntityUid uid, TetherGunComponent component, EntityUid target, EntityUid? user) + { + // Need powercells predicted sadly :< + return false; + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + if (!_timing.IsFirstTimePredicted) + return; + + var player = _player.LocalPlayer?.ControlledEntity; + + if (player == null || + !TryGetTetherGun(player.Value, out var gunUid, out var gun) || + gun.TetherEntity == null) + { + return; + } + + var mousePos = _input.MouseScreenPosition; + var mouseWorldPos = _eyeManager.ScreenToMap(mousePos); + + if (mouseWorldPos.MapId == MapId.Nullspace) + return; + + EntityCoordinates coords; + + if (_mapManager.TryFindGridAt(mouseWorldPos, out var grid)) + { + coords = EntityCoordinates.FromMap(grid.Owner, mouseWorldPos, TransformSystem); + } + else + { + coords = EntityCoordinates.FromMap(_mapManager.GetMapEntityId(mouseWorldPos.MapId), mouseWorldPos, TransformSystem); + } + + const float BufferDistance = 0.1f; + + if (TryComp(gun.TetherEntity, out var tetherXform) && + tetherXform.Coordinates.TryDistance(EntityManager, TransformSystem, coords, out var distance) && + distance < BufferDistance) + { + return; + } + + RaisePredictiveEvent(new RequestTetherMoveEvent() + { + Coordinates = coords + }); + } + + private void OnTetheredStartup(EntityUid uid, TetheredComponent component, ComponentStartup args) + { + if (!TryComp(uid, out var sprite)) + return; + + sprite.Color = Color.Orange; + } + + private void OnTetheredShutdown(EntityUid uid, TetheredComponent component, ComponentShutdown args) + { + if (!TryComp(uid, out var sprite)) + return; + + sprite.Color = Color.White; + } +} diff --git a/Content.Client/Weapons/Ranged/Systems/TetherGunSystem.cs b/Content.Client/Weapons/Ranged/Systems/TetherGunSystem.cs deleted file mode 100644 index 3a66f07bc9..0000000000 --- a/Content.Client/Weapons/Ranged/Systems/TetherGunSystem.cs +++ /dev/null @@ -1,142 +0,0 @@ -using Content.Client.Gameplay; -using Content.Shared.Weapons.Ranged.Systems; -using Robust.Client.GameObjects; -using Robust.Client.Graphics; -using Robust.Client.Input; -using Robust.Client.Physics; -using Robust.Client.State; -using Robust.Shared.Input; -using Robust.Shared.Map; -using Robust.Shared.Physics.Components; -using Robust.Shared.Timing; - -namespace Content.Client.Weapons.Ranged.Systems; - -public sealed class TetherGunSystem : SharedTetherGunSystem -{ - [Dependency] private readonly IEyeManager _eyeManager = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly IInputManager _inputManager = default!; - [Dependency] private readonly InputSystem _inputSystem = default!; - [Dependency] private readonly PhysicsSystem _physics = default!; - - public bool Enabled { get; set; } - - /// - /// The entity being dragged around. - /// - private EntityUid? _dragging; - private EntityUid? _tether; - - private MapCoordinates? _lastMousePosition; - - public override void Initialize() - { - base.Initialize(); - SubscribeNetworkEvent(OnPredictTether); - SubscribeNetworkEvent(OnTetherGun); - SubscribeLocalEvent(OnUpdatePrediction); - } - - private void OnUpdatePrediction(ref UpdateIsPredictedEvent ev) - { - if (ev.Uid == _dragging || ev.Uid == _tether) - ev.IsPredicted = true; - } - - private void OnTetherGun(TetherGunToggleMessage ev) - { - Enabled = ev.Enabled; - } - - private void OnPredictTether(PredictTetherEvent ev) - { - if (_dragging != ev.Entity || _tether == ev.Entity) - return; - - var oldTether = _tether; - _tether = ev.Entity; - _physics.UpdateIsPredicted(oldTether); - _physics.UpdateIsPredicted(_tether); - } - - public override void Update(float frameTime) - { - base.Update(frameTime); - - if (!Enabled || !_gameTiming.IsFirstTimePredicted) return; - - var state = _inputSystem.CmdStates.GetState(EngineKeyFunctions.Use); - - if (state != BoundKeyState.Down) - { - StopDragging(); - return; - } - - var mouseScreenPos = _inputManager.MouseScreenPosition; - var mousePos = _eyeManager.ScreenToMap(mouseScreenPos); - - if (_dragging == null) - { - var gameState = IoCManager.Resolve().CurrentState; - - if (gameState is GameplayState game) - { - var uid = game.GetClickedEntity(mousePos); - - if (uid != null) - StartDragging(uid.Value, mousePos); - } - - if (_dragging == null) - return; - } - - if (!TryComp(_dragging!.Value, out var xform) || - _lastMousePosition!.Value.MapId != xform.MapID || - !TryComp(_dragging, out var body)) - { - StopDragging(); - return; - } - - if (_lastMousePosition.Value.Position.EqualsApprox(mousePos.Position)) return; - - _lastMousePosition = mousePos; - - RaiseNetworkEvent(new TetherMoveEvent() - { - Coordinates = _lastMousePosition!.Value, - }); - } - - private void StopDragging() - { - if (_dragging == null) return; - - var oldDrag = _dragging; - var oldTether = _tether; - RaiseNetworkEvent(new StopTetherEvent()); - _dragging = null; - _lastMousePosition = null; - _tether = null; - - _physics.UpdateIsPredicted(oldDrag); - _physics.UpdateIsPredicted(oldTether); - } - - private void StartDragging(EntityUid uid, MapCoordinates coordinates) - { - _dragging = uid; - _lastMousePosition = coordinates; - RaiseNetworkEvent(new StartTetherEvent() - { - Entity = _dragging!.Value, - Coordinates = coordinates, - }); - - _physics.UpdateIsPredicted(uid); - - } -} diff --git a/Content.Server/PowerCell/PowerCellSystem.cs b/Content.Server/PowerCell/PowerCellSystem.cs index 7719773d9d..2ba103a05b 100644 --- a/Content.Server/PowerCell/PowerCellSystem.cs +++ b/Content.Server/PowerCell/PowerCellSystem.cs @@ -157,6 +157,18 @@ public sealed partial class PowerCellSystem : SharedPowerCellSystem return false; } + /// + /// Whether the power cell has any power at all for the draw rate. + /// + public bool HasDrawCharge(EntityUid uid, PowerCellDrawComponent? battery = null, + PowerCellSlotComponent? cell = null, EntityUid? user = null) + { + if (!Resolve(uid, ref battery, ref cell, false)) + return true; + + return HasCharge(uid, float.MinValue, cell, user); + } + #endregion public void SetPowerCellDrawEnabled(EntityUid uid, bool enabled, PowerCellDrawComponent? component = null) diff --git a/Content.Server/Weapons/Misc/TetherGunSystem.cs b/Content.Server/Weapons/Misc/TetherGunSystem.cs new file mode 100644 index 0000000000..3b62e3f8ca --- /dev/null +++ b/Content.Server/Weapons/Misc/TetherGunSystem.cs @@ -0,0 +1,46 @@ +using Content.Server.PowerCell; +using Content.Shared.PowerCell.Components; +using Content.Shared.Weapons.Misc; +using Robust.Shared.Physics.Components; + +namespace Content.Server.Weapons.Misc; + +public sealed class TetherGunSystem : SharedTetherGunSystem +{ + [Dependency] private readonly PowerCellSystem _cell = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnGunEmpty); + } + + private void OnGunEmpty(EntityUid uid, TetherGunComponent component, ref PowerCellSlotEmptyEvent args) + { + StopTether(uid, component); + } + + protected override bool CanTether(EntityUid uid, TetherGunComponent component, EntityUid target, EntityUid? user) + { + if (!base.CanTether(uid, component, target, user)) + return false; + + if (!_cell.HasDrawCharge(uid, user: user)) + return false; + + return true; + } + + protected override void StartTether(EntityUid gunUid, TetherGunComponent component, EntityUid target, EntityUid? user, + PhysicsComponent? targetPhysics = null, TransformComponent? targetXform = null) + { + base.StartTether(gunUid, component, target, user, targetPhysics, targetXform); + _cell.SetPowerCellDrawEnabled(gunUid, true); + } + + protected override void StopTether(EntityUid gunUid, TetherGunComponent component, bool transfer = false) + { + base.StopTether(gunUid, component, transfer); + _cell.SetPowerCellDrawEnabled(gunUid, false); + } +} diff --git a/Content.Server/Weapons/Ranged/Systems/TetherGunSystem.cs b/Content.Server/Weapons/Ranged/Systems/TetherGunSystem.cs deleted file mode 100644 index d81f571a32..0000000000 --- a/Content.Server/Weapons/Ranged/Systems/TetherGunSystem.cs +++ /dev/null @@ -1,199 +0,0 @@ -using Content.Server.Ghost.Components; -using Content.Shared.Administration; -using Content.Shared.Weapons.Ranged.Systems; -using Robust.Server.Console; -using Robust.Server.Player; -using Robust.Shared.Containers; -using Robust.Shared.Map; -using Robust.Shared.Physics; -using Robust.Shared.Physics.Components; -using Robust.Shared.Physics.Dynamics.Joints; -using Robust.Shared.Physics.Systems; -using Robust.Shared.Players; -using Robust.Shared.Timing; -using Robust.Shared.Utility; - -namespace Content.Server.Weapons.Ranged.Systems; - -public sealed class TetherGunSystem : SharedTetherGunSystem -{ - [Dependency] private readonly IConGroupController _admin = default!; - [Dependency] private readonly IPlayerManager _playerManager = default!; - [Dependency] private readonly SharedContainerSystem _container = default!; - [Dependency] private readonly SharedJointSystem _joints = default!; - [Dependency] private readonly SharedPhysicsSystem _physics = default!; - - private readonly Dictionary _tethered = new(); - private readonly HashSet _draggers = new(); - - private const string JointId = "tether-joint"; - - public override void Initialize() - { - base.Initialize(); - SubscribeNetworkEvent(OnStartTether); - SubscribeNetworkEvent(OnStopTether); - SubscribeNetworkEvent(OnMoveTether); - - _playerManager.PlayerStatusChanged += OnStatusChange; - } - - private void OnStatusChange(object? sender, SessionStatusEventArgs e) - { - StopTether(e.Session); - } - - public override void Shutdown() - { - base.Shutdown(); - - _playerManager.PlayerStatusChanged -= OnStatusChange; - } - - public void Toggle(ICommonSession? session) - { - if (session == null) - return; - - if (_draggers.Add(session)) - { - RaiseNetworkEvent(new TetherGunToggleMessage() - { - Enabled = true, - }, session.ConnectedClient); - return; - } - - _draggers.Remove(session); - RaiseNetworkEvent(new TetherGunToggleMessage() - { - Enabled = false, - }, session.ConnectedClient); - } - - public bool IsEnabled(ICommonSession? session) - { - if (session == null) - return false; - - return _draggers.Contains(session); - } - - private void OnStartTether(StartTetherEvent msg, EntitySessionEventArgs args) - { - if (args.SenderSession is not IPlayerSession playerSession || - !_admin.CanCommand(playerSession, CommandName) || - !Exists(msg.Entity) || - Deleted(msg.Entity) || - msg.Coordinates == MapCoordinates.Nullspace || - _tethered.ContainsKey(args.SenderSession)) return; - - var tether = Spawn("TetherEntity", msg.Coordinates); - - if (!TryComp(tether, out var bodyA) || - !TryComp(msg.Entity, out var bodyB)) - { - Del(tether); - return; - } - - EnsureComp(msg.Entity); - - if (TryComp(msg.Entity, out var xform)) - { - xform.Anchored = false; - } - - if (_container.IsEntityInContainer(msg.Entity)) - { - xform?.AttachToGridOrMap(); - } - - if (TryComp(msg.Entity, out var body)) - { - _physics.SetBodyStatus(body, BodyStatus.InAir); - } - - _physics.WakeBody(tether, body: bodyA); - _physics.WakeBody(msg.Entity, body: bodyB); - var joint = _joints.CreateMouseJoint(tether, msg.Entity, id: JointId); - - SharedJointSystem.LinearStiffness(5f, 0.7f, bodyA.Mass, bodyB.Mass, out var stiffness, out var damping); - joint.Stiffness = stiffness; - joint.Damping = damping; - joint.MaxForce = 10000f * bodyB.Mass; - - _tethered.Add(playerSession, (msg.Entity, tether, joint)); - RaiseNetworkEvent(new PredictTetherEvent() - { - Entity = msg.Entity - }, args.SenderSession.ConnectedClient); - } - - private void OnStopTether(StopTetherEvent msg, EntitySessionEventArgs args) - { - StopTether(args.SenderSession); - } - - private void StopTether(ICommonSession session) - { - if (!_tethered.TryGetValue(session, out var weh)) - return; - - RemComp(weh.Entity); - - if (TryComp(weh.Entity, out var body) && - !HasComp(weh.Entity)) - { - Timer.Spawn(1000, () => - { - if (Deleted(weh.Entity)) return; - - _physics.SetBodyStatus(body, BodyStatus.OnGround); - }); - } - - _joints.RemoveJoint(weh.Joint); - Del(weh.Tether); - _tethered.Remove(session); - } - - private void OnMoveTether(TetherMoveEvent msg, EntitySessionEventArgs args) - { - if (!_tethered.TryGetValue(args.SenderSession, out var tether) || - !TryComp(tether.Tether, out var xform) || - xform.MapID != msg.Coordinates.MapId) return; - - xform.WorldPosition = msg.Coordinates.Position; - } - - public override void Update(float frameTime) - { - base.Update(frameTime); - - var toRemove = new RemQueue(); - var bodyQuery = GetEntityQuery(); - - foreach (var (session, entity) in _tethered) - { - if (Deleted(entity.Entity) || - Deleted(entity.Tether) || - !entity.Joint.Enabled) - { - toRemove.Add(session); - continue; - } - - // Force it awake, always - if (bodyQuery.TryGetComponent(entity.Entity, out var body)) - { - _physics.WakeBody(entity.Entity, body: body); - } - } - - foreach (var session in toRemove) - { - StopTether(session); - } - } -} diff --git a/Content.Server/Weapons/TetherGunCommand.cs b/Content.Server/Weapons/TetherGunCommand.cs deleted file mode 100644 index 38136ce220..0000000000 --- a/Content.Server/Weapons/TetherGunCommand.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Content.Server.Administration; -using Content.Server.Weapons.Ranged.Systems; -using Content.Shared.Administration; -using Content.Shared.Weapons.Ranged.Systems; -using Robust.Shared.Console; - -namespace Content.Server.Weapons; - -[AdminCommand(AdminFlags.Fun)] -public sealed class TetherGunCommand : IConsoleCommand -{ - public string Command => SharedTetherGunSystem.CommandName; - public string Description => "Allows you to drag mobs around with your mouse."; - public string Help => $"{Command}"; - public void Execute(IConsoleShell shell, string argStr, string[] args) - { - var system = IoCManager.Resolve().GetEntitySystem(); - system.Toggle(shell.Player); - - if (system.IsEnabled(shell.Player)) - shell.WriteLine("Tether gun toggled on"); - else - shell.WriteLine("Tether gun toggled off"); - } -} diff --git a/Content.Shared/Buckle/Components/BuckleComponent.cs b/Content.Shared/Buckle/Components/BuckleComponent.cs index 1e4cc3c196..8b5d092e29 100644 --- a/Content.Shared/Buckle/Components/BuckleComponent.cs +++ b/Content.Shared/Buckle/Components/BuckleComponent.cs @@ -94,7 +94,7 @@ public sealed class BuckleComponentState : ComponentState } [ByRefEvent] -public readonly record struct BuckleAttemptEvent(EntityUid StrapEntity, EntityUid BuckledEntity, bool Buckling, bool Cancelled = false); +public record struct BuckleAttemptEvent(EntityUid StrapEntity, EntityUid BuckledEntity, bool Buckling, bool Cancelled = false); [ByRefEvent] public readonly record struct BuckleChangeEvent(EntityUid StrapEntity, EntityUid BuckledEntity, bool Buckling); diff --git a/Content.Shared/Weapons/Misc/SharedTetherGunSystem.cs b/Content.Shared/Weapons/Misc/SharedTetherGunSystem.cs new file mode 100644 index 0000000000..67fb9904a7 --- /dev/null +++ b/Content.Shared/Weapons/Misc/SharedTetherGunSystem.cs @@ -0,0 +1,267 @@ +using System.Diagnostics.CodeAnalysis; +using Content.Shared.ActionBlocker; +using Content.Shared.Buckle.Components; +using Content.Shared.Hands.Components; +using Content.Shared.Interaction; +using Content.Shared.Mobs.Systems; +using Content.Shared.Movement.Events; +using Content.Shared.Throwing; +using Content.Shared.Toggleable; +using Robust.Shared.Map; +using Robust.Shared.Network; +using Robust.Shared.Physics; +using Robust.Shared.Physics.Components; +using Robust.Shared.Physics.Systems; +using Robust.Shared.Serialization; + +namespace Content.Shared.Weapons.Misc; + +public abstract class SharedTetherGunSystem : EntitySystem +{ + [Dependency] private readonly INetManager _netManager = default!; + [Dependency] private readonly ActionBlockerSystem _blocker = default!; + [Dependency] private readonly MobStateSystem _mob = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedJointSystem _joints = default!; + [Dependency] private readonly SharedPhysicsSystem _physics = default!; + [Dependency] protected readonly SharedTransformSystem TransformSystem = default!; + [Dependency] private readonly ThrownItemSystem _thrown = default!; + + private const string TetherJoint = "tether"; + + private const float SpinVelocity = MathF.PI; + private const float AngularChange = 1f; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnTetherActivate); + SubscribeLocalEvent(OnTetherRanged); + SubscribeAllEvent(OnTetherMove); + + SubscribeLocalEvent(OnTetheredBuckleAttempt); + SubscribeLocalEvent(OnTetheredUpdateCanMove); + } + + private void OnTetheredBuckleAttempt(EntityUid uid, TetheredComponent component, ref BuckleAttemptEvent args) + { + args.Cancelled = true; + } + + private void OnTetheredUpdateCanMove(EntityUid uid, TetheredComponent component, UpdateCanMoveEvent args) + { + args.Cancel(); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + // Just to set the angular velocity due to joint funnies + var tetheredQuery = EntityQueryEnumerator(); + + while (tetheredQuery.MoveNext(out var uid, out _, out var physics)) + { + var sign = Math.Sign(physics.AngularVelocity); + + if (sign == 0) + { + sign = 1; + } + + var targetVelocity = MathF.PI * sign; + + var shortFall = Math.Clamp(targetVelocity - physics.AngularVelocity, -SpinVelocity, SpinVelocity); + shortFall *= frameTime * AngularChange; + + _physics.ApplyAngularImpulse(uid, shortFall, body: physics); + } + } + + private void OnTetherMove(RequestTetherMoveEvent msg, EntitySessionEventArgs args) + { + var user = args.SenderSession.AttachedEntity; + + if (user == null) + return; + + if (!TryGetTetherGun(user.Value, out var gunUid, out var gun) || gun.TetherEntity == null) + { + return; + } + + if (!msg.Coordinates.TryDistance(EntityManager, TransformSystem, Transform(gunUid.Value).Coordinates, + out var distance) || + distance > gun.MaxDistance) + { + return; + } + + TransformSystem.SetCoordinates(gun.TetherEntity.Value, msg.Coordinates); + } + + private void OnTetherRanged(EntityUid uid, TetherGunComponent component, AfterInteractEvent args) + { + if (args.Target == null || args.Handled) + return; + + TryTether(uid, args.Target.Value, args.User, component); + } + + protected bool TryGetTetherGun(EntityUid user, [NotNullWhen(true)] out EntityUid? gunUid, [NotNullWhen(true)] out TetherGunComponent? gun) + { + gunUid = null; + gun = null; + + if (!TryComp(user, out var hands) || + !TryComp(hands.ActiveHandEntity, out gun)) + { + return false; + } + + gunUid = hands.ActiveHandEntity.Value; + return true; + } + + private void OnTetherActivate(EntityUid uid, TetherGunComponent component, ActivateInWorldEvent args) + { + StopTether(uid, component); + } + + public void TryTether(EntityUid gun, EntityUid target, EntityUid? user, TetherGunComponent? component = null) + { + if (!Resolve(gun, ref component)) + return; + + if (!CanTether(gun, component, target, user)) + return; + + StartTether(gun, component, target, user); + } + + protected virtual bool CanTether(EntityUid uid, TetherGunComponent component, EntityUid target, EntityUid? user) + { + if (HasComp(target) || !TryComp(target, out var physics)) + return false; + + if (physics.BodyType == BodyType.Static && !component.CanUnanchor) + return false; + + if (physics.Mass > component.MassLimit) + return false; + + if (!component.CanTetherAlive && _mob.IsAlive(target)) + return false; + + if (TryComp(target, out var strap) && strap.BuckledEntities.Count > 0) + return false; + + return true; + } + + protected virtual void StartTether(EntityUid gunUid, TetherGunComponent component, EntityUid target, EntityUid? user, + PhysicsComponent? targetPhysics = null, TransformComponent? targetXform = null) + { + if (!Resolve(target, ref targetPhysics, ref targetXform)) + return; + + if (component.Tethered != null) + { + StopTether(gunUid, component, true); + } + + TryComp(gunUid, out var appearance); + _appearance.SetData(gunUid, TetherVisualsStatus.Key, true, appearance); + _appearance.SetData(gunUid, ToggleableLightVisuals.Enabled, true, appearance); + + // Target updates + TransformSystem.Unanchor(target, targetXform); + component.Tethered = target; + var tethered = EnsureComp(target); + _physics.SetBodyStatus(targetPhysics, BodyStatus.InAir, false); + _physics.SetSleepingAllowed(target, targetPhysics, false); + tethered.Tetherer = gunUid; + tethered.OriginalAngularDamping = targetPhysics.AngularDamping; + _physics.SetAngularDamping(targetPhysics, 0f); + _physics.SetLinearDamping(targetPhysics, 0f); + _physics.SetAngularVelocity(target, SpinVelocity, body: targetPhysics); + _physics.WakeBody(target, body: targetPhysics); + var thrown = EnsureComp(component.Tethered.Value); + thrown.Thrower = gunUid; + _blocker.UpdateCanMove(target); + + // Invisible tether entity + var tether = Spawn("TetherEntity", Transform(target).MapPosition); + var tetherPhysics = Comp(tether); + component.TetherEntity = tether; + _physics.WakeBody(tether); + + var joint = _joints.CreateMouseJoint(tether, target, id: TetherJoint); + + SharedJointSystem.LinearStiffness(component.Frequency, component.DampingRatio, tetherPhysics.Mass, targetPhysics.Mass, out var stiffness, out var damping); + joint.Stiffness = stiffness; + joint.Damping = damping; + joint.MaxForce = component.MaxForce; + + // Sad... + if (_netManager.IsServer && component.Stream == null) + component.Stream = _audio.PlayPredicted(component.Sound, gunUid, null); + + Dirty(tethered); + Dirty(component); + } + + protected virtual void StopTether(EntityUid gunUid, TetherGunComponent component, bool transfer = false) + { + if (component.Tethered == null) + return; + + if (component.TetherEntity != null) + { + _joints.RemoveJoint(component.TetherEntity.Value, TetherJoint); + + if (_netManager.IsServer) + QueueDel(component.TetherEntity.Value); + + component.TetherEntity = null; + } + + if (TryComp(component.Tethered, out var targetPhysics)) + { + var thrown = EnsureComp(component.Tethered.Value); + _thrown.LandComponent(component.Tethered.Value, thrown, targetPhysics); + + _physics.SetBodyStatus(targetPhysics, BodyStatus.OnGround); + _physics.SetSleepingAllowed(component.Tethered.Value, targetPhysics, true); + _physics.SetAngularDamping(targetPhysics, Comp(component.Tethered.Value).OriginalAngularDamping); + } + + if (!transfer) + { + component.Stream?.Stop(); + component.Stream = null; + } + + TryComp(gunUid, out var appearance); + _appearance.SetData(gunUid, TetherVisualsStatus.Key, false, appearance); + _appearance.SetData(gunUid, ToggleableLightVisuals.Enabled, false, appearance); + + RemCompDeferred(component.Tethered.Value); + _blocker.UpdateCanMove(component.Tethered.Value); + component.Tethered = null; + Dirty(component); + } + + [Serializable, NetSerializable] + protected sealed class RequestTetherMoveEvent : EntityEventArgs + { + public EntityCoordinates Coordinates; + } + + [Serializable, NetSerializable] + public enum TetherVisualsStatus : byte + { + Key, + } +} diff --git a/Content.Shared/Weapons/Misc/TetherGunComponent.cs b/Content.Shared/Weapons/Misc/TetherGunComponent.cs new file mode 100644 index 0000000000..7feaf7f518 --- /dev/null +++ b/Content.Shared/Weapons/Misc/TetherGunComponent.cs @@ -0,0 +1,58 @@ +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared.Weapons.Misc; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class TetherGunComponent : Component +{ + [ViewVariables(VVAccess.ReadWrite), DataField("maxDistance"), AutoNetworkedField] + public float MaxDistance = 10f; + + /// + /// The entity the tethered target has a joint to. + /// + [DataField("tetherEntity"), AutoNetworkedField] + public EntityUid? TetherEntity; + + /// + /// The entity currently tethered. + /// + [ViewVariables(VVAccess.ReadWrite), DataField("tethered"), AutoNetworkedField] + public EntityUid? Tethered; + + /// + /// Can the tethergun unanchor entities. + /// + [ViewVariables(VVAccess.ReadWrite), DataField("canUnanchor"), AutoNetworkedField] + public bool CanUnanchor = false; + + [ViewVariables(VVAccess.ReadWrite), DataField("canTetherAlive"), AutoNetworkedField] + public bool CanTetherAlive = false; + + /// + /// Max force between the tether entity and the tethered target. + /// + [ViewVariables(VVAccess.ReadWrite), DataField("maxForce"), AutoNetworkedField] + public float MaxForce = 200f; + + [ViewVariables(VVAccess.ReadWrite), DataField("frequency"), AutoNetworkedField] + public float Frequency = 10f; + + [ViewVariables(VVAccess.ReadWrite), DataField("dampingRatio"), AutoNetworkedField] + public float DampingRatio = 2f; + + /// + /// Maximum amount of mass a tethered entity can have. + /// + [ViewVariables(VVAccess.ReadWrite), DataField("massLimit"), AutoNetworkedField] + public float MassLimit = 100f; + + [ViewVariables(VVAccess.ReadWrite), DataField("sound"), AutoNetworkedField] + public SoundSpecifier? Sound = new SoundPathSpecifier("/Audio/Weapons/weoweo.ogg") + { + Params = AudioParams.Default.WithLoop(true).WithVolume(-8f), + }; + + public IPlayingAudioStream? Stream; +} diff --git a/Content.Shared/Weapons/Misc/TetheredComponent.cs b/Content.Shared/Weapons/Misc/TetheredComponent.cs new file mode 100644 index 0000000000..3a92c69fbf --- /dev/null +++ b/Content.Shared/Weapons/Misc/TetheredComponent.cs @@ -0,0 +1,16 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Weapons.Misc; + +/// +/// Added to entities tethered by a tethergun. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class TetheredComponent : Component +{ + [DataField("tetherer"), AutoNetworkedField] + public EntityUid Tetherer; + + [ViewVariables(VVAccess.ReadWrite), DataField("originalAngularDamping"), AutoNetworkedField] + public float OriginalAngularDamping; +} diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedTetherGunSystem.cs b/Content.Shared/Weapons/Ranged/Systems/SharedTetherGunSystem.cs deleted file mode 100644 index 8b0ed07162..0000000000 --- a/Content.Shared/Weapons/Ranged/Systems/SharedTetherGunSystem.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Robust.Shared.Map; -using Robust.Shared.Serialization; - -namespace Content.Shared.Weapons.Ranged.Systems; - -public abstract class SharedTetherGunSystem : EntitySystem -{ - public const string CommandName = "tethergun"; -} - -/// -/// Sent from server to client if tether gun is toggled on. -/// -[Serializable, NetSerializable] -public sealed class TetherGunToggleMessage : EntityEventArgs -{ - public bool Enabled; -} - -[Serializable, NetSerializable] -public sealed class StartTetherEvent : EntityEventArgs -{ - public EntityUid Entity; - public MapCoordinates Coordinates; -} - -[Serializable, NetSerializable] -public sealed class StopTetherEvent : EntityEventArgs {} - -[Serializable, NetSerializable] -public sealed class TetherMoveEvent : EntityEventArgs -{ - public MapCoordinates Coordinates; -} - -/// -/// Client can't know the tether's in advance so needs to be told about it for prediction. -/// -[Serializable, NetSerializable] -public sealed class PredictTetherEvent : EntityEventArgs -{ - public EntityUid Entity; -} diff --git a/Resources/Audio/Weapons/attributions.yml b/Resources/Audio/Weapons/attributions.yml index c7be93af11..483a0e1d2a 100644 --- a/Resources/Audio/Weapons/attributions.yml +++ b/Resources/Audio/Weapons/attributions.yml @@ -1,4 +1,4 @@ -- files: ["plasm_cutter.ogg"] +- files: ["plasma_cutter.ogg"] license: "CC-BY-SA-3.0" copyright: "Taken from Citadel station." source: "https://github.com/Citadel-Station-13/Citadel-Station-13-RP/blob/5b43cb2545a19957ec6ce3352dceac5e347e77df/sound/weapons/plasma_cutter.ogg" diff --git a/Resources/Audio/Weapons/licenses.txt b/Resources/Audio/Weapons/licenses.txt index b16fcd263a..7b077ffc71 100644 --- a/Resources/Audio/Weapons/licenses.txt +++ b/Resources/Audio/Weapons/licenses.txt @@ -12,4 +12,8 @@ boxingbell.ogg taken from Herkules92 at https://freesound.org/people/Herkules92/ block_metal1.ogg taken from https://github.com/Citadel-Station-13/Citadel-Station-13/commit/31c5996a5db8cce0cb431cb1dc20d99cac83f268 under CC BY-SA 3.0 -pierce.ogg taken from: https://github.com/tgstation/tgstation/commit/106cd26fc00851a51dd362f3131120318d848a53 \ No newline at end of file +pierce.ogg taken from: https://github.com/tgstation/tgstation/commit/106cd26fc00851a51dd362f3131120318d848a53 + +- files: ["weoweo.ogg"] + license: "SONNISS #GAMEAUDIOGDC BUNDLE LICENSING" + copyright: "Taken from Sonniss.com - GDC 2023 - Systematic Sound - TonalElements Obscurum - Dark Drones" \ No newline at end of file diff --git a/Resources/Audio/Weapons/weoweo.ogg b/Resources/Audio/Weapons/weoweo.ogg new file mode 100644 index 0000000000000000000000000000000000000000..e7d6ceac39a1feb7e5586e790b7b6ca34e9befd6 GIT binary patch literal 34523 zcmd?RbyQT}*D!wRMp{6?p@gBNOOfvG28jWNA*2NyMM0FVp}RY!1w^_*8cC%=KvX2v z-yQsXV?FO$@B94!n|0@M@7d?=uTbe(|ndtA4JY4AOP;>2tr`qK5j639*8mA9tP3(ck_0F$k}*#@j>+69lRl0?r<-# z*$)PL9EP8}97_ljQu=J>+w`2;}ZN^ln##N7{M`~Q-57&w2e z7gSE(2m`7Rm9L0|RqhozvxdTH$<1^WJV zf(YAF0{}J<#7PjHzoqItCgDiS5$%~H0oM{QhTw(ku1OGdo!qf=E2=L-xQ#*C@kvZ^ z0MIh(B{?q$1qUF(8iKn830ji7CHc{kdz|$X zazwoKlWH0QGe&k*?YNdtyv8K9GyXXdT<-${u0;-)&YnyTAC3Msv?#?BMD=%D5FiNL zCZHTgrCLihT+1-}fld1xk1nOi2O&j$15HEl<6~*;3!C%xne#=Oro1$7Mw&LiG@pNI zdHT|ZHuRt447qxWKCZV8!2ohtC6d;mc`WpKpC$6JLP9Gr0edt_AO!I&(D;1SA_wOx zczUB#d86xa9nWwb@pTu_wP2%H1LVNdivEwo!88f>|2|}#2Dktjke2-(4E-K#ih6AQ zo;-Nh6dnLTp33O)^m+;_dkOb@-3Je4Z-qgW#^?`?8~!7vC?LyvdL zQ^eRyYR*e@4kQJdBLDZ#^J{qlH^Q9hkmMYMFBEHYO_m@KEp0BoJn`R|zz(l-Hy~*f zY2QaBNYgfRN~zMP-iH~abF`GEq+fH;WsGhe4+8rOYrL4KI3qd0NwUK#YYC@o6S6JU*-!4G8)&Gin)k6fyq0DG$BV|09wEl6|JOJ z8myy7$5H70;(F&000<$wmg0Y%u0{E;6c@yYa}9C684(=jL7ytR$0YY_y2<2;1wbk0 z5doz*s$nb3t4cxzQP?nR#$AZgQ-c=%)hLju5c^nJT)Jx|2~F`Ff);~X@!yR5$~I2U z_~E~f@nZ&E3U=`LAjqpPBxPt|Xzc51n(VXK^wM(PXLSy_Iu~VqGxUE7*1t6e0F@@> zS|?Gqkplf0!CGk7F2&V^gnV)12fP{U)saUHAi~qOP!}KDFfsYM&_@ zn7*jxln89f5H{lrTWExtHz7?M|52E~YO^}$^Iw{SRuLA7=yjEN?Eh#^4rlad@n}}n zcsA4cJN`+IVQHnQS-Yiqg#SZxoWhG!!i!&rZ@-S_3`>HCrIoehxeQh9xBfqme`}7i zCmVQxnxp8+_FtOQDZn5PYEvDL=J&sQl==V?)LZf9e=`68I%A2|ukDDg9`B5v$c!GZ zp@G!@U1LD#jIidEFi6-$0H6Z^R*=adWZ|B%a&A&4_ySvOIJpwIxjnQY#biRn5+p3% zv9cUe&G8c5#NXHSIH?shf}_~Qq9G(*MHZ@?;`pH1!v=H#AV^?9poi9TOm#3vVN8G^ z6Ez^gQJ65P3gu0r6@s!CQP{0#!~3CCZ(MrN)o}{l6`- z9wGE4N^cCh6{|NSu*smOCQ+QBKPG|C7&0V)n;A?7Eo9IigZ49ojL2?g1W(9v0sy2F z1N_Qy3fn6JWE{ZSBewAbVRb5YbxOr?D%c#Q=3JuisIZ8xf#EQv;f#UdB8{eDBfBQ0 zrsfX=LrO(MYQw1{O~VG)abehkf#EWZ;Y=fJk>;s!lFzD;rYU$k3qpP7l91N3u9hkP zpwgteMkQ)E*C?XvZK!JqGc_*b z)Xsu-%PF0XRg2ccCZWpzAdWjy6|6_;f^`;8@Kt(8M{HR)C5`;A9L-8}oPkIJg5 z%Im(Mp{Yt*w)K7ImbMX(E_6%-S6Wt? zURJ(e=f>S#u`j1|$sA;Y~h(WaKKt=+EniCW?sfU+asH29+Ma}9VYKx|A4Qdi?O8UY14e^OSZw17fi zwX^|5Raiiyt|rh(W$q?0%K(ljpfFd3_EG7(^7f^%_CY{YgXqbx=h#d^fv8f0 zh=#3?UM?a(r_CzRbEtzJ!Yiib#0a!HL0EuH5CJR)Z9>p$EBjh+OchS%IU>PDAU7hx zQR=B72Zb7r$l|j%j7dPDy|WVd?1ePyT)e$T2q+ZX1uqzPT&pdvW>_x|p#}mFqb&figo6jvVBJy_<)9_t61KnIL=XfdW28VRm2J4dc7{AYv^NEe zaf)csp$F(>(eXzl2mo*UK!C(H1NxNV75$&UT zL~(s<=kiaGp7Qthzhd_PMDPE%D|198D02UO0%YD1;sJl~ZW$?yL+Ocl(0e2UlQ`P$ z6mZ43j3J@Woq`aMJ-PB~5}fRylt7`N_<$OXGE+nCSp+Yra%$kMZKO!39@wRK-nK%ZU{Vj%Pg=VQP=U-4;L;Ji z(1uyt$Oe%9poN&VjS!hNBLddk9sxlrH6Edf1#h}OtX=b(84R}NuBnYq4D>)=2yEppbE1U$KK%1b+j# zYhetb07E$xi1}|DiUOSDI=n;ap(PR|4H|GQs@GQp%xH35cV_-O799(MB8r8!!mK-N z`9mx&!k@aZbesm%fFNQ3@R)brht3W_dNV?j)I(xD$!z(^^};2TYhfyMy|gnZfkG;M zJ;Y9iZKSStrk$EVcLmBwjWh1Wq-RBg?+92@g5U%EWXwX(WiY5{2f&F!u%SRsP3MGw z1vd5ug&-j@VSk9%BpeGM3mG7edu>8YL0R@Z&sGvJv3NLu7epKtRUbjLBiM;!x#R;0 zfnYPg?!};r4GN}od;FP1yZJqVq+%iIbsa7U0GI$Eo&>_ek|q&N8gnC-ERH;$B7qVG ziZ1}H0YNu_AU2%WuU|Vv=XbATu_@Sx6!dIhvtNVJCw%_1`*O=XDtm0MK>W3Jq)SP9i>faw=aTII;F^03Dw z@q?aYm?hhUh7b7=Gpm1$I#3j8_<-bodl-H|l{{m<RPj zHI62n*E%V3MGDstNk=!3Vl<{%F5v&z*Ws9;%L;rt=(M8%48^3`+Wi!ivYnkg;LTDp zqR;%zZU^NKeY|ZiAaOf&s*C*B_RXD5+nY4*=C~sF3L>yGFNV`!v!(i4C9I|-r@v0! zRx;rcmg2l+sa?g~-E&cg2^73gPL|8qo>4~GJJI<8Nmx&v2w38mZR1l%cFFusY{otErLXPhN$n+2$J?-396c_VYBYtII`HLX-4eG4~3q zJbf&8MU0av#8A_iK;52{3FeqjiL3Cftia#7&PRuxBsrCnRQkmUGog3RXWG@OpD^sO zlmC=AO7$)F;+>LLT^hY03hXD>-***?X{C=Jrj}vz33wh+6h)t`1_kg z0YE|Mw)1PBcU6;d-bn{QC)dN1h?Jz;;QJ4s(z81uV=w-JN-r)y~JD6gt78RCTHEH8cnnh+T!#A*S~qYW!_O| zPFV@qv)VEfJut*o=i5=f(_iAvK+gG4;C8N4YvBN@CdfkHju8Ot9S(L0+QavQ*lOx9 z9&Q4ub4guI1&CLLt+Tg4W^EFcocdZ~lCkyf-3DfjPg$*rf0f?5^A@+&`0h<0@~LvN zfm;=V0Emq=5(N|)W%S*Ax$=LsKa?4ixSSn zeppznnYNR}1g4{tarbJgFbAFJR@o>!^Xg;s>OLvDR@2=B>Yr}&wLJLVfDM46AcPUr zpw!bGb*44y7WPRrwH*uSacI(vXdc+-inTX-O4_LsiyayyqP{!@r|$SANm~)V9eI-O z#ft&Nuh`=0OalzX``iW>U%1{sQ|({!uLh=*#tSsPq>Y~!G)3M6{IDK)M6d|PmF9h+ zFa&zSPY20%O{+0f9btzz9`=~Zz1E{1r#Vj~0=(5m6Oc3O7N_iw<1-RdfgD{zOE&hX z&kSp&GZ>M!`=1ELEN-wpPdqEbc~rio$PGVB+PvjSEG&1fDRJ?+6&o^8(MAYxk8C>& z+jLTEi&(T~i{aE8O;HA$41r9j6?DhgQy1l3cZoH+e4+cYRVgd3A~cz6<~+?f0bA9v z1&gzc;EX^|V0WZ|Hy$bDrSQxOm~54D3Qn2Jb;}pJf67y~!Xkvx6aHW#c`jS^NMv|x z<#nF$we9m|#A|1vreEu`zrP+ONrwS7ep$ixbpr;-Eaqs)4`?CGyJTj~`s>K)cCB?X=$ z*EZP)E5@jDep?sx$I?Xw{<(Zsud!K)Rq$f*VZ-5xGs}vMVEqzC4OhkvwwgR?dl@;srfGa7B(;v9#g^mz=K3ZY544p zR?v6ec&@@8hl|H2ByGNzgi;aLY<7nA0VgmvH&%~YD^2eCsD)qI*Z|7xdzO!cMKXY? zYJ2VlC~>!skm!Z57^t-GI!Ll&PDi`TdLNq^Q?l8|dMDirvgKSe*IF-E?tKvOoW|g% zuL2-Byc~`zP%Xc#^yX8`_M+oA2DxiHo!@uo>es!y8TZzrXbB8+n^a?j2FAbUVIP^? zNQ=p-99<<%-d0j3y#jHiDmWA+6I16B5V`5HRh8=X9TJu4!D9Xwm<(0t z#DG-=vI!UT2SO9{S%FoUKz+vtD*5x;#k^lG)1sCfU#A)Zp>Hz{`AIF}^&fqss2o<_ z?}#V*0?;k;OzytFM_HOkbyJ@CD`|1WlNiIyz+KW>g|>+I{kUAKJ!pGFkOX`E+#I z21j~MHfMa9<0=E|sS1_wy-Xd6Pw{>&dTg)BU)Uv&j0`ghi21LPW(;@pgnh3GE?H~vFFOB4K-}I`T>Gu$ z`1hGaoL8aaTai*zSMytsJF+trnqIRQ4^IlSV!hcPJaN0lr#Yqb`0_jni2-D_Eu&_G zd>G5>-hFsHQ zN9AXKWv<({Mt9h-+-69C>88gkpQ58;iXFrB`?uO_#y0e(+%+=8S`9d93ZjLiQ&LXckHq4xV?(xTE-_Z^N-d=KRBfthepGq$Afcz+vD@6{Uii zPOY#Gqot5&poLS>4Xt9GXunrbd$Z+?omRSlh|Bv)m8~~*Y$m5?;d30rJ9$;^x;F&s z>lqvTq>rI&Llm6eBn>V1zL8WWb4QBakQh&7WqZ1WoO@AV4Kn=)@wkrxPFEp`;>sUs zeGY%^;y3=ci}3fmf4dyC;p|S1kbmtnfTa%8nI0#ten(}~P%*~RG8BDDb7!Xs=^FD? zcC#G2xZ&YoUMv>Kg*Z1^%gQ0DGMoL96KWif~MMsc-4bH7q-h+od*1ga4{OomXB#c=ZFt(N9xbPrCtPm&W3{i zmFUPegS6FeKcQ2PK3S4@yRPrT_k6tGMnAu~#@wIv5mcuzUjS;%I?Z7v@k)j1j~J5O&S~qdlI7F8tgDCjHWD!TGq^P;yZ^jfRy*03c?8mb;l>;&D{;{VL(OrxD4U3Nc9~R z@jSNnP12kaoRQL>4#}T+piJ-ICMGs90pIr8@o!}8>n!d}JzDkpw$Lxduad*%yq0@z zH0tf_z8h=I!@G`|kR^9~iTEIK==ke4A|1utjJ?PzRz|1t>k<5pl&?hmibK~6 zt7oehyFvVu!r_Zj{tLE@?>NuOY$S0CeAfs0=bHJxz9=wB4a2C|)#Bn93V?nKuOtky z+PC2t{@l?)96!I;h8L75%Gal;ln@pvq;>M=&yA(E*@K+2u8PWC z?;Y|NUEcjG8J zjE?e3O&iE?TULCZeJ%+hsO%9F2&%r5q-Gv+gixYTCqP+kD^9jHSCz{+oWBK5;7YTI z0i#7<=r{iL7EY`T+o_jSJS}_}`0+hM+YJpwYN0(IO}Eh4SvVR(WBJCl9_#rDWVr zo7onw4C|SWyecbhY`h!D=pxD`k16C8uFy|mGwWy1%}dzVPqWobgLtV@nYiUZn1{m% zWCUD(c|L!6B0~YDDdNPBd01Hs>hZg`e*QGYtguQp^pu)IFsev$OXG3UM3wqe(Rh?S zrflxIWC03n*E0=jtE_|RNm^S{w>`yuDxMVw)1^kpT zn2mX{chIE{eddg2R5*71zRr}BC@5t~l!7n^OhZY%jo(qmZgX#RKi;>KGME-hTsT&8 zm-0F^J@l8zf0pGjZD~PdqFokxj2C?_@=V;aaTdowzE6nkO+HIvowcK#69W?i8;hMiBRxG>z_@Mez{o_;$i&S2&=!23z`+LQxD>i=YL~Sw!jhVJ z#zm=9(fc^=ag_U!%f3e*P~qJ4UgP*jIRU1etf1)_PUniJPqw|~xh&D%m)&Y5Fcwrh z5DK#>K*%`2v;db%b~=GFia$Lids7d#Sb5vRV-((;J*{RBN>M4>Bn>je_|soXJ0s{T zb8pOS=no#?xsO!GoA&Yc(U2Ygy7axUZ84JqVo_JbDR%4Xc;q0zMvO-C_`R1_^-<#? z)eNj-7ehNu&qRvO^>V_(o9hKt27UoE9JW?qENiB5zwuyBLD-DDFXgG0X3QWf%ff3r zU3J}&s_)bTxPZ6ksLfi%FVGV4tmCcmLt5^-E+&j=TG+@@dO<4t8LaW#TVlX)w z1E$6HdkNB=F0wA4-7nj4wZj5NLSxFjFEgugJF*Izo)`vQwCF@(nNvyC{dnA7)P_k5 z(7%;}y)v20J(O{5K0-=pI(Y&m;kf(@OE(v#VxrFP!qerFk;W1De$w^9S{X*7 zn5HoJopA%eSkrg|Q|4T^h~L8|2^Yt6wvTCqO|gmLCrQdzm8$3|fLq(a9|7aJwKZ{uk*Faxa5o_g@2y&x=o`LE>52T2%@}1f zHJRyrKN`1xW>1)@eH47~h~tC9@6#SRS7*cxSn6iM3&%wDH>>tPG&uz@jD{>9V$AxW zqvqltHvpYNk>2ga=R^cw>VSn8?&~cB60UJD6!cRp>1UH-q(|e63B2^d|&nCC#c;J zXp$!No|x(&`!@T@v0J!q#3dDgQaX538xhq)|5(;Rf+HxvS1#a0PzCq3jd%Wq-Hsy$ z{qS-cA?V>bCg=|@M=0MN90C(VlDYiODsP{$PW4-g-VSA8+ZffE#xxz8WjGquoi2;Hs(kC@*-ZpZw3lmoN4U8;y@O@t+(4r0Ria?cIzPr! zFkr<6jmY8-x@a{}NS+g4@;oB5)F67*vj=kfflYsP7A(!TDxm+5UIfRx3;vgfBCbTW zM%Bu9*vuk-ILBxti7CZB&UB~2bI{U9@ur?wVEt_F9mw~bt9Y&06IixUa{KpN&cgRX#TIB^rx9%mV%tatN^Xy4j2`C z2=QMi>9-9$th;DWlS&;EGYrdB9E4pamKAh_`dRb4uVJPK`8o0(INPNr)sEfJx5H<; z@i84QWaLo_-hw22B-7rYiA#> zqET1h-fqR({DO4*_xk6sl!4}x3th{XW?|t5`QGrJX@BE{UF)}qLFePd>|!HL(V-9m z>uE@iTI1w>>rw8+A`0!`+|5rse#3P+pWGh3Ps2sK=%HSVit^_-+45me9I?Je$+x>n zeRo=&d<;wnG^rB4n?*=TsUkpQadw-cPcTo|_8r7n3>>D$^7}Iv==E*^qQoWZEcOP3 zaulT!4y-`E@1ldkoKI$3>_){1Z4gX8uMB&mWD5E<2>_E3_<${Ql{!Gq46k$nOeEGK zGYhK~4DSzWW3j9Lp&N0#%#!NxM6TheI{1M0$&Yo@1O-35EWaDG^+A^kkX&rv!EE@a zw0f>5k^2GIgv)zKS+4re&#W?iTYmz7=Cd7! z0Af~U$WBO zXURlVSGb+mO8`TT*bi-7HrK0=u?4VgW))mcLg<04VdNRTBv_=Y2kl$Gm`PB*wsQEZ z%gP4~yx9kwey|Lx_33%6j)9zsjAn|+n4a4zzbhm)Wiw}uSgtfiD{)4>XeSj~%h((2 z>D*!EbenqDopOuW zHSx<$p^I0w^_~5iZ(g)LP7+DnWZ9r_$osWGJ@jf=&t2%#U5KquL_oRGyieOmWeP>Q zZ(_v@<0oRP)MKKYXgzyjZ)M!ms#yp|w+wrjm=F@Dn9t=a78{c*qfc5taQ4QhZ3jyv zGjJ|n+|c8@^sq2;5}{0^%#_+gRo%!mDs`UP^|2IpL^{fPFRxt5J#+ops$1UOl;uz! z=P&i+^AdkC8}PJkdAbz%C3(#bPk+DIJGweQc&iz+PdAlqr|g;n8dKc^^5(63_}<`9 zAdF63lVIL81$ri}dnY#rQ}5>BYgVO&?Zn027AMpG%)&E@c|zM(ZlVaE`K}~z^EkD= z1{Y{-m4ahTRp-y3%d#tXPxeO#sDf(qaL0bN9lqVxR)Li=LdX&jl4U)nR~z!1`J8m$Bh_ z>4yZ}FC_sB&+}dA=e;?M)Wl}2hYi5NxuD=)P23zSyhl3vy2lZr-Z2PNC1WoXJMI?td1mivG&jL`yZ0O+Zkz-RAu`zDo6-TRwy>B zsn+NzkV}J`RA)VAAAD*3M-u>bg&8#(fznb6Oh?*s`1wRdjzc7<-D;noqNBx~V zHb_oea=wMSP09-=`dPxeeWis4jNL9TB{D7l9{g5T{8oAdC0O3=hkS1uE5`=YcW_1= z{xKZZ_P8!0?X|H6$}iFGs$DTY)G7gBtr4%&O8@nASzhw)%W^QlJY9Z$_=`T)fcsbq zW5R=xnKmg$$;bPqnqdE^q3)tdY%;}^f(w-mX zGJ;@Hbe{jAdD}qJPud;p_M>AaX=zG;ez<)X9nm+TxpB3-?BN|BBq~WlrB%Lul=zL8 za(pzTK{6+S7v-Znff4xjw%!Qkffx2b*++6)DrtEEZ21kx9s~E|*S6uOt&O4O(+o;# zO2n&j4@!DP`;sO*dEIb~(lTZ74(4(la=^!6zvgy#T4w-5UHyX4=QX~%8{3#$4@l%K zZuj4tmlsY~<-8-%NKs%gTGVG%nl1v9nm$Uq@9xS?hRPv#<%+T7j;-o*YJ6M;*t#hmnN^IB1DW0I0T9=Saf-UGD0J9~9;WYI}WMW?><)C;zVD>hJ|)%`9i zI*7ob=xDWsDc4jXrb(}>VEzO&ITV%9fyE|dm|yj?kBnL<-qsZDq^?9)7xNyj%f1*Uz(DUj z)W%8-F8RJhD@@EBiUVEZ?>hCL)*jgI=#`1rRGBS6$!AhEQTeQC879_Zmn05KVI1t&JylBA*MfO-~t_sNRAu6 zmSUy%CeZf8vw#k`!;T2A-idq6>C9KbDJA0M@=JNkFZ7$&P?yVGbB=8ibP1uIm|-$O zbHoltcbrdP!Cx1&%FQfq;N&RxHR#lC<%Hiy|@+ogbi4k zU~Lh%Yr@$_R8}^Nb^b?R6otZq*O%OSaSb8CE6*7aBGZviAlZ zg#BbK%&e_zM5GiD)CI5T9L1{)Tbbn~^LGum-bH8&Wnw-ZL5>sH&HALbVvUAgHr{6t zE^X`#nA*Q-)pB`d{6JF(UM{frwOn(&>##MKidWiM5#v>9eL+l&E5gmhL|ZhnjRz$n z>&WU!LNv1i%e~X~HCnrH)*&=MKQUFlTU?t23GF|0HR}VB^p&a&m(+!Lp_A zCa=^DHNbN!By5#+5_%iTFD{zDN`<^pj8f7nGXEluS>3hfLiOgQ!7}N0W9Pl2IALGf zDud27g1~qF$+H8ZEO@O;CMKQlu>VzvDEUtz0{zm(`$WG}E|{aegFVdA&dLsE>j1O2 zhr?`a?QCsrZ0zivZEc+FZ5=>>t(}dfV^%q`85dOLrVn7oW1Wu@mZ8tow&{_dRrzx! z>>Bx(mF;OM~W}!P5s6x&|qK()m z8{PbPcJ|}J-lt10ciWktlf9t6fpllO6QmiX18!#j;fjUVM8)1j>MnOBN01KOZoDrz2;gZ7lut!S@;t7aRFs81b?6%Ad#l5KcWU5-PjVUYUtl zJ#~3H*lF_BGi=6FI3Z%gS$2kZxz>Nw@Y&ej5oTqESbueDfpT_C<2{oF0~t3ta|*}s zoD1GB_oTxBjuc{N9N_oxFHQpSIn6y1J%=Aav=pys2TGGLi9$&4(ykjPP z^oWges0xv;4UIq{JL_ej*4ziBcPW8|i=^<+Z0Z5oVp9<`4o`+mY*mfJMBd~=4%!53 z=PBwHjG%lw0JxK;+5)VUX?%2uZ;3qu820IoTv>@Zk*(;6WbhYq+H@sxleJHMQv^8G0q++~Gy%X1frFMDHXG{9-)N?o-2Vo)BD+o_608JrY*NHSznf8Z_;lYJLy@0iK$d^m$&Dz}yTz z875#g+@Aho!$PbSorAYYuQQWAZQg`p zevfn>v{*5DBQ(8CFBSrS`*X&7`x{ZR`Polq4}99htwhGE;d(%-BlW8ZyOMw4JqGYXTUmVI{lqo*GVBKUx~e>sRaTP2MQ~W>0HCggl=4WXCMeU3&MO z8RqkTv&=r~26oyDwksQ`WS@R>{Q#n@yLXf$!exyuK})VKo%?qL@+U!ei`#_oXshF6 zxAihy!;cu%w=c=XmRC2mS4_L&%i2sHS7~`o)nJv#%6syQA1~R(@C-4I^0qkqOv}y4I@E$xrAVor)7fWF z$4z~_EXKEA7iC5M=1Sm7JNX`;ojzmDNL%!g@VN}Hv0?R2Qb*S#hMSDjO&nuCh)?Xf ztR5^`r>6-vR;jgI8R&Ed%ZgtREohJDplp zFP5ZosMA_l^CZ`ODbhbGgzB%~)@nX|W&g9nH2U$_!y6oykFCfZqzXT{zgUeUUBStS ziGETMWG%VC@IrUd^dre>G4UWXNG#CXL9_QsPte(bRk36(;3`3~QQ1Uz`10G&hhZLs zFv#mCW~1@(_N#~_KOGrSNB4j)o#MsaWaAjE+%)ue#f3lQe+}e}%}`-au74%{;=!kn zZ~tticruwMeC}JdP=13ClB-`p7${)`D_X-aq`F*lUhdjE;a96GxYM+YF)Hd`5p%6- zQ%WeEwH{NwA)BzNkGKNQQ~?2xhCIf5Nzr=0S;Um?y79ciEmeao`>LxR6VgX&JQABt zELutrH1wQU7zUUkkxc>`fYajh)vp#!A+PFf3m%^hm#-#2c-s6{cF?|3!tvgfWfa3; zul|=-s5xCb$6gkr$4LY-)11%C9BFK5Ecwyrc6J)oh#CFQK=OtdBDU`jB%;1d*VWcJ zMVL5*de2{}6B?vpTP^)cVTt!zE{Oh63J-i_d#X~-2P*VRq|{9pd{5j zHtvx$Gv6VB2*?Vp!-b+C37hisRf~3^+QPz~_*{K><(KN36YGis{@>vkuf|5Kx-j

hvNGL+u~%0$iVH3xja$iUsNC+VbnFhYa%=vbCdZvb*}kN-v0YKSzJ;wljX~~v z9SgvN$mMC#P*Oky^WCSGss&#Ln z6O>%ZebO?KG?vlYcJt!Jsc%6Uw_HuVXFNPdv@MT!37K-w7arB;lj2dSUA|yrQ0jOq z=fL>ke!`|@RS8a4IrBX>nI`k&?YlafcjgR#{?__5X_kgEod@}VENm&jnxBpY{nO;v z-#P-$YbPU3Pg>^Oqg_5k2V@JR(AqP+dJ3)8owPXC_g667@H+Sw6KBEZa_Z#tp|*RZ zMu<=2+4sg{hoXD<1n=)q|0s{q)6(vU$R0X8zwzS>_5&~pK&LVHCR{)=S+coe^ig0= zjJ{3#iRey(^TBmuKL>QZdTTltjIbF@XtWH=q*!trh_SD&y?XRqj5nj6hxZsx@zJ7g zW~k?cNy2H6&Gjan91+^SBo#8cISXHSVBUVwk_)<6VsHyt0yl=O0K=^OlxL|3R-;W` zF6Y9VGp=rT#QVFZ2-krda$4>UF|^@&1K)qn>ht#tAfWa~`kq)eob{tajNkS)$)&R5 zEC=^E>dC2Vifb;vENB8N>Bt5!8WAfc2cLXf{{|SjJlMV-PYC**to%NDZ$Y0zF62mF z#TU9nqG+UOf1~ALoQH5?lj?YF%ZRpU5%4pc|MT9l6HS)o%hwlOvz!iQZ2UHAUKWJ z{w7leQk!H4Z9YWqHyHx)g3+H(AGL}7LfmoRNrj`{z>DUgCdRjs7s%l40yxXd;$8?`#%>VJtsJdxnKWw1L*U*8x~IbdzqTV7sudM)kUb=~?&Xrtz%HP>}Upss#Z z+1@l3xM-DO*@V!qTI|{Ig?Jg!y|*U&Sb9|Pc*+IHGDj9kcmpNm=Oope7Y;JLB~ZTK zZI|wD2`%;X;Df~S{a`CN^fRGgD);T`zHNHKN(#kispFNKY+_yf zwsw=`xGf3KWOg~`x_#b=LKE~_JKg4QROZNhYhx(&IiBh@WGzDKbjF=@l`C8HWu>`q zO%fBnzsm~LSTIZ>op>Vsu7W?4TDv8iX1`(dQSUh7=C?yU04uPPEr78t>3u({Eag+jK{shvA!Dp&^ouYSj2mX*iQ z)3#x()>P!4<%B(d@lDY?1LGA3wA8S^ql@^N-m}bhqlko)PkwfYwJDE#D)Iu{^~ovP z$CAOsS?VCiLH!830zFd_27F&J+!{6u#zNZ4(mu zO2CrDEwadr7jon!s8J=iJ8Su9J4%oFEc>iLW?=5CQ)~6c9R*yEdbN8Sj+6fHB!Q>g z$RZJtO!!Yi=jy8Fa@Cx|t8pC;LuJLR9e8_uc*|R!-9Yhb-g@o0oTmgqxE`tR89}Xj z&xvSt_kQLa=nUV%@{4e@c~9v5V{Hxhz_*esHrV0MM5Z#WuC~mcmLVosIv)TNwH&VG(pw%xi-pLpk|2h!f4OEhEtXGZ+#u#dU8a!ys1?t0BZ;yyb$ z^}f4j0tMY?M<<8ZB3;Hw;p0!SmT}};GJA{53{oezc7b~_I6ed)(#G~c8<1|55YQxql3LQ_}9kfVFv;^Ex`jg(V|1k z?2{VtBZ`FpYbtuX=(%vPpC_9jpzv|H| zl~{_2g_{l=u-5f*Qu{Y>p3Pw(_QVda7&a-T>#~zx{SkRj3_KnAmBLzM{VD)_r}NTt zri|237dSr3rW4gJW~}rNtB9zL6;`oynW?$G6sGm3bCU|6Z~I}2u5>@0k}zAW^40mF4ETZ4B5m4N~G)T-zp?(_adp6=zTgwv{ zUa(-EJVy3f$gjLwMGN`Mc8eTit0Vf2e{Nw_j$3riQkpSRW#Wr3R@>`&IrscH4muQB zO8A7>=2rEf^t+add<879Eb(iH`r3aAEhWDJsO<^{nobNCiA0b7WNR&JcfOB%5%f|> z!b)eM^N4lSrAL#n$+V3&X5Ou=jA-Lcf_GHd)~8b7z{8j%D@gLLOJqI{H@_rN+FREW z=mI{~P&g*Q)b`5>2b^I=2?752W#$DiVKkuoq|n1=zr*6j0#rAtA@XzjeNO2&P7lpm z3#TuA+@A$@P z8}%OC`u~dhs(`q5HepNs0R)xMGBp$1!mNci$Cmtp-Or;{b&b`9p8pbFt%`0nw2M#iap-=bt8}~1%%uM%5Ru_DW0c8~<+ig> zVADb(eUS)wrLSw0Vs)G*GUe zi3Dq_#k!yY)hiP|W_ea|?IW$@b@|4)rF1Y&LA@#FBNo|m~ zfXD?b-yDWg4dxvBH&{aZ-MrfNVqT6pUej@1OmE<SI($mr^bp{a`^`E7 zKTpN>!xGEC?mD5SOmcRGRf=q1lOJY>53jYL0q2;O#0I+Ls?A3@T3pIL`5Kz(b{w18 z1r6UACrPnTv)@w_qXc22vB`ET(!_^KJKp@aaj~M%5Z#l{S%N>S#RQ{;kZ=F};L9J! zkAOR#pML!t8e61Fy_f#y%lnJlV|6Zl*jb)}R}beOgnugKICGo0B@dlKzoeC}4NuH@ z-UfbhGf=rm(R#>agfVN(7(vF!n{;Wti}+*u6@sJ^U{a+g0TwFSe85>p@{>l4RJ_3J zN1y9ky^e2>+$MovEOPr#Dzlo{%qIS>VPW2XIGgP)4OY_oID#5R)1hY0?}pQkJp-bI zY;E`07D~%rqek?zkI;@#md9(2N{|IhP>mqk0i0H zQ+1gYJGs%UYK#vGk11K$7!S$tCH2#ygVD{sU(d+H|7}PqWYxPRj1Ep%BTuB91ImPWyKOud$N3AbCBPN9`Ap zGP`Z*4Fo>I39OPd6ka&g-!BJdo6acVfjHYD>pT`toUb^Cn>Cx|6xbBmtd;o2857l@ zc%z~mS2tWj2%$_+J37#(-SPmb8556N86kzCMQZdWwZM`1;tgw$w+5B znb&k~dXMpw9|`RVYli5kBl6p%E$Br;515pP3T+Ydu<@1@-dqfcU1aO=k_}8kU&ABx zoHZaejzJ65P{6|gTf&as`P2XK?-I5up1VTz;x%ASm#Zgr-X4CZZhSVSr{A*jN6cP2 zT6rWI-X3vzZ{%L+8#5Yx2XZHyhLH;$zd?R02EQ>mzrfZPv??U#m-1T}A;4v@;qOdr z4XE0knFu%fG}$1l4_^L0t-0%VT$}z{X#8MCK$5)7eJ?8XHwxz%MuVayhUHgX+%;nV zN2ajCz%cSljNl!cFGe{dqX$KJM?{YMa?074-!;y9XH zAe7vJ8H&%X@p(8L(_fAKSC?NY3589heQnpW9dPsxoqJ1?;JuvGzWJ}^?z7cX#1eFj zC+HXwrkse-oC!Up+qJdU4>=k=_QwHH3GmH;Hh=B8lw`~olxOz?cnnuAQ2q}05rICH z*_R35kJ7kMM#zmuEWZmgEL2(9hx?Tq|0IX3s3BLV^4Is+LNT^1y+in-q?CTdY475h zK~eN&bXa@bD5_HZmmE$!swoQGLUbXQe^NL#<8qoNxZ6r zioa^xBa~PwDCL7{!h)bfxe#b7u$n?F|QZ%M%&QmxIAcuTfP=HelUKuXekBKCc)9DM133NWsd}mSl z+i;aux2&PgJ08NcG1L{i;@u3%M;xj?YoB-M8jl8a7lo>dC6nRtGnEb7)LRa8+vws+ z#|xW?h{~yM=U);>%yP*84}mWbTXL^2+ZMlX#O5+Q3fB`ZHd&>cXXV+x{J@fQw=j1z zSShX1(HLKpnp=krl?CG-oac^Tz?CJnd~)fTZAGr{Pg#hrN8co4g7w=JC(rMDD?Op( zgIjC!Cn)ewwF>-Hhv5CKt0RF3uQcb7##+Dd%=D(Pt=;j$=#=|$$iP;Xl(&g~q{hm( z58P0cZ0~nI@Nu6up^MXg*B~nXb9Y$?veRa9lReAeFK;Yn8lK`~Ag}cNAff2vk+eb! zWNGO~`P`xa0s&e;+f!qfZ%UyXQ^?!!__`9wW@cuwM6q^@H_nks%elk1&41E+~ zJ*vgz0gKGK&`loGj(cpdHd&6hNx8~;0guO9|i7Ti~ar> zZkEdB+um92_)It*Du@rx?25(Oz+V*&VU!)#2rM1`?Re<-SZ z>>^iQv)IVKhta*xi}ofnge1uVPAjle08Z=raqGkkt*8;XNP*NE*pnS3gj#3ly8DV~g_!m}BZ;2SvTwgon@80&dQw2ewl+$gY z45W*JyN0KuYDrBD=8e72a`bU3nBmEGg5T&-MR9vongoJbBAfJ2-MG*rh3)kye)spc zniB)d$>&n^Z~7&r?m!V|8Ii3*P@9E(Eqe0l?CSXES2Ow5fZ49m)EcQ>#@?%<3OatT z{$Wssq#QALnrkV*E;k3isrT6TU-I_@Ae@FbkUFT1P689x)AMj)wDuakn^g!ql}fQ1 zQ^PmQN72L-+OYiXW+&K+X7a{v?_N*tLRQLl@2 z3b^UH=K%-y>K`ltBt0o+L?Fn#ZPLK=qxAI{>qtN&)Y{czVuszTf)S7dll;-1bh zvIWL+&LbaJ7*r7^UtqAR*SQDcY1&`&4&f-8WJlAQOU`#SgdPiUelyRzIB!lhZ487OO1Px#&=|}M(;5z zlnUmDl8r*Vt?hx*_lBKXUC;6g7k9y?$p{_ zqoD1*rJHAbiF0LGKa1LRUj1UAL|o^lNF0{W!{SPza}^qm9TcJ0^RDkY4}*D|E!ZG| zuYi(}i9F+KIHj^bt{owJ-?P4{==@-DN0p4&cR*V77!apro$8j68$tY2Rw}`_&>+_V zluX%0v1XXFe`0<@<171tmd!NaxT8_uciHuBQLx7@161Y$2k}zz`~kM~f9kGppJ+cB zSjjui2xPr{)msu*gb%ZcQitRfPyWFW+iZs@j7*Jz zzec9!1}4U)#zrRQMuz%krbZ?vhE~QVCZ^^VW`@Qu9X`tlK#2ycBaTGxA;UFSl?6Pu zRwsjbGVc~Gb7okW7{g3-swE8{B5?$Dbh?D}Q!zRp4*SAy(Ed;@@_a_*G0XgJ!!z5w zr~k!BPaN;5r7u?^kl0I0+EN2P$^r_g(elXFdZDWU0G#*qr?>F0xw7?n8DF{|@XndA z*ezt~%Np$NC3SF<^7uu9QXnwZ*!0Fm;eO5Bb263n@$M9-bE0hdvrKvcJ*2;#o4U( znnNnTHFG(1+Dm$Sa0K-oi}QpKK8l&!_xXoG7Y6QZ!Q*EsPbQzE&Z$S6on}1dRutyF zZ|z`dDlokP_>?;Xd1mnws@klIK$6{K&A*kp&?hsdrKQXW`z~?4B$~&LBBag30EJNY z$clpQ!*aCM-yY(9*+RulXW4jxL92_66YsBTMLBa8r^JFMsC#WTs>(W-AKw8d<-a}& zR$SO<@%_pt5L20?-kZqPf1KwEFDpU2GqQ_b*0t&H zxmdC~md5-;?9y40-TGKbn>0rYY^s#)9hXA6V&luF2EF_2zrEib1syK)1<`6~>t>B` z{;FkPD<`w^BJdR-Ci-)L^Glj-s^ZxpMo^z2n z;o00JpuX(xWJZGrF@2cIwf$QX0ywHg@45^^r%k{$r;Jl6dk*UiquFnGFcxPG=R^x6 zc+hF;*+oi3(B;VPws+lD#T?fMo6hdw)uL+1?wB9z?y{tS;-$=X4fXRu-8{@Huxx#v z<9HA?yOU+GN+@7DwY*M+$y&g zr*Pz>Z!~c9xv9C>vqveA;GlT(`Y(=tdbKRFn{Z8}N-)1b2Ja?j8RM4%lnJ|k zm@UrP-lFB*l^4i~{7f5f6EB&BdBY9a6I$7o zh>VmiJN%DDK8kK~^)!kV`*0#G+8bma)NZ2;7UvOFD3z-otSnqLiQ{h^)ULwUN@MY?jj!YzTJ<7WD0H4r-$8kjt_CM4 zMy&kLnf?0#X+-A$OR zLC(3sOjFA$yoDmUr<*P9BGTw}os&Q#T`z4qWvp=^2|I&_`5L?)iCpI#u3XO42(=R* zzs^C+nw?6PK^4BENhAccNbP`j6jvzl;EDK5+#V5P%>DZ0dp`P?WwXUYrj-g#peEl6 z$6|tsQc4cz-}QW~ryVL)!Wa(zDu z(G~Ak2m8mq4e+gtg-run!GKn@nrX-QZ4da&%vd2$jpF(#lm*tPli6Ox9nL<`Nt z;yWV$z`+ZWv_dYN$&#;}#Ioa#D()`Uk+xYIdqW8Ipa^-yirIYhui~>>T-3RbbYOvJ zAx!1b&l}`oKS**XCcMatYJt5G{U+qXjU_cnP4F>D z_p6b8=Tw~guM>WXk3AnvcANRKxor|MB7*)f;4fV&^JLOs1u|zo{s}OI^38g-#14Bi zKIN==m>i)o6Vs(crN@rkIqJ6MQmP$YV&iWo8H7i;*ejixCZ$vASy(V{t!u`}3LWOa z;oh($JIFH}I_^mK!j!G9`YlFmm#iLBa-ER0-6$py~0a)1{5Nv@K^p*hOI7SUw zjv;$-Lx8Js)%1tILRm<^Zkx^X4^D+?4@SesF_m&n+JmH|s$NVC3B%1l^uh1R&dxVv zEr}*+KuswMgZzV5h}o(P_X{zvfd`q8Dj&(-^*{rZDVlQUD@v-VxFca1Q+4dp4TGEI+UVkXkLf@`b|FmOcbCo#<*zGa2rvnx zU!<9a9tXCx7UL^qdC0XA-E1^_)*-qppYae!eTjc43qji6nMiyAD>Mv$T0k1NN$nCW&L90YUn2Tjj^r0YR)})nG;oe4#Su~3l}QA_x&jK zHC%=3M=6ra)%U{U0ot`UK%|oQ5BwzXPmg4#;nnI3YI6%e*0)TxR55*zTD9Q$cze41 z<*8Ax>-iu3T^5mF94v`8R;V^(x)km_1((((My%cu=pBMma3SedFkG6@KSX@h^n;dO z$4u>T8)7%$JAf97zR^vyYuyzH@hjEtom9jOn|F$3Gfw!~#K^{r`u&2KBLO!BlSD6vnD19{Lc=qk zSs47={GS3Y;=tUwzML*!AY<8kdfm4-U#XRDwVstKZ_?&MhpT2OSFV*NgNfvoDzj;8 z`!2xzb-TEf&TXpP!ynS?gVU?Stcoi0v~MvWT(J){q139hcf;Ff37rR^BQUaY7P~_f z5(G@2>!LisFIr=yJ)QsMAVpCaLJT*Z^t2^mliVLVusV!lAsU9c5iU7wu5C=bY%?r6 zG`#tzBAu@$#m^2UPT^ihPC0>)%81xYui>dl#ecQo^`{W~Z72s?DR8MBHs>)hEG>0T z{5MNHr=bK7{@Go~n?Q>aZ%9Y+$#ENPRL{aLURK)TO`lUGcoU~RGWr(^x$|yrxFu~1LO`mwZ^C>ZBliD7hMEGD_&nI z8rrGE?Hy>Ov^pK`Sm!#Iit+v&bC|7lweB=;bp6((EHV?}g4LcgPr@Oth5z^4(|A`` z)}r8@Hyumdr-%Xz$|7W6l^Q|F9NSUf(q*@eIAa)R)xg(?qJmn zHsHn9xIfc!6E@P)BvZ~ji@m2Ba>RRxO)qR$VRc!5-E2Rdl#5Cn^UcIX(NHsBZf!+#lq7RTrFN z@H4)Rp8os`MOF*Eo9k70d~H@t(`<^g@50SrMPHN*SqDM=>1H1NN&?xfYemK^OY824 z2o~d=+W_JKw0^aKs@D|?tcX;Eqx!@WPVn=o%bD^brAKEG*{77Dx&sB|@mbxlo8y1!L_xHD{>z$sUE>C4{3M=9&nA z19&!;5CFdb;O|zu{s)>;{L`kZxz#Y^W=97j@E18= za)Z~j(>al+B_f}TF-gwD-c1uH^OHNjh}lJ1Oz3_48?OfdaiDszfpt15IP|kA^PjxB zS^p*nyuPl=Pgh?XrfmJ#fVw-`D?Wqq!Va{nrcQ`98TYmEvkvVU_!^SMjw zwKh7SxB+DM_-nWX3sVB05}%3Ft1$l^c;5uZ1&7?=1Lb*^M~~h+Qga+TMR;$kIO{gQ zO7@jh;sT;_vFCS18i=cf6tjwK9ap1f zsjB=}HRM)FHL}5x%chV2F%H%S!{*t-00|jdA#@DlZtSCFZWJ@>VDM+P zturU%gMXYKK>roSfl%M9>kSjUXxj;U53^sh$BnCgjxd>e>qqrtQRGv57$pO$VP49c z3>GH<_@z+5Id1xdTxf=jC3Npj5pXp~?tZ2e-#eBC$~@E;bI9^bf%rqup?I7%9>e3` zw--t3RAVo>?Wx%d%XVabkjw89y_DH@72NoKC9bzLN3!|>EB=sK8OfrFU=|!jw2(wL z?ONPEPyjT&2K5z@r|j{DeO zwjNwGd%vOYI?yBD{d7ew{NTZxZZ{N;4~fNEFR30MAeg!~2$))reWC%y`+rC+6ors$ zj$O|2+U4Tl>+%5ii++imbm{B-h|4-Hi@UUKjP?E??7eA1Qpk6E&Uo`CxLdw(YGo{V z`M*3Ij~k31l7q&Os*&A9w1^pGUV7DTbpX2Ie+xh`EZ1dpA#MFmuk|G>dY}z@EE2>W zZBOMQy`*)piq_r9J`oH>j<&?6wPoPu!HRDsq}?+Jdqw9gDdN%HTVRCFe5>Z9oEu#b zx?mlvHc2`joa=XOODpw%?HGCBG>HFlA>e?&@Iv_b^oFK@!ok4I08liT8ygxKo0^+h z8tVb_2NQFB10zEtfOaqh^bUY29YaiEnf7`twZb7 z0&+%;oqR~}EUgFz-5X$nO=F9%v4|_!wNabnRj}(}5q83wj~3g{cg1^oHo=0ZGmM=V z@rv55IM{0DR4w8!{UV5O#<8%Q)?Q8;q9U0(Uap}nFSuiE(VL)zW@fE_HFY$YssRQ< z{|U745$cGK6Oa)BAfv^&l|Cw&^?U|5XUo}7FoYEMPathSpL5rDnb<1`eaBC5bA3jm z3agz@TinLkoK^p#FV@B9a+Dry+C6g;MM7*?pS;HMHpqTlxyse)H;?i-mSX5X`OKgL zClb)$0JDP}=C~qE-0A1$jVeO^kKMDG)l12y8JHqF?E-<{@+2G4mOg4SBrPO}iJiup zhtYXaE`Ug)j8#25i_CJ|ZYVM8`eV=jVJ|asmhFUP2vGvv`9FjH2%yFntg*62hp?iP zQ1-^FJDb?gELGL|4*l@QhEbjKO1>y+$b*|DTzjpoW@k?Ve>cKC2q!`zsYE|GmfjAT49$bO0!y%BW6aSq|z5oJcJ;(VW-PiWz zeyK2Bl%eYv*BZ!92lG=(kFCU9r4UEdur}k}S2PC8qp=dXVOA^GOa5XROW6@aPjp$B zyYE*%n_BC?p6q1?Z=e(xVJ%VG|THd|D*r z3~8qINDg$NosIVvRxKgCjAf%%ZN`r!*&#Jat|Ix&|s%z<`=uD(7iQq9 zR2Z>4710jvDk%GVTF|?05l~AnOs6#u`l`j*OdlQ~{dm^!3*)7Dwh$MFBRK{w-~>4T zr=i>^i5Y@WGUH?=Nz7q>w6QT>FM==16#X#6n?$(D5)aKC@Su;WW-mDCXvkTYy%l6# z7&Sjduu_$_ZX<<85PMB>rN1{7V=9JkA~HPQSZ|yhNel({Tj0cJ0nRF5)pjd*RPPT_ z%8rtD*0EqwTt4xX#B(_qI}pDjA+dVpc3IGMxpMYF{>k^32rM)OtI$M`_=nHFdK_37 zD4*>`3)|yXF_oVcFP5IxhE^JB?^au{Vm4V2{BVGg!AB7rxY2J{LGeH-+!+fMRS5A_ z_u0b9(?K!C`eVlia{ug!@23l~A*=lB-_IIhNzdBtsPEWgTL}(a9izUUs2~>`2rSvg z`I4v69>zO4mHnC&lPPwg*s(t;hlJQz1IquTFL48SQeXc|hmi@f$cOw?Q?~Jq+sBHt zhn}8J8PAh^L&qk1wx5;p-=L+%~>oYOrrI-UqytI&;*} zZ){NT_Dm?*%;({y26{9uA1+bMxF^#T6**tWVl7QpIe%AH@;Kfmt2$4u$MM1dyG7pC zE`rg3b@A#hBM7GSl2c+J`VhT=Ivh(a8T-hX?IFV8FtUw;Bb+n{tGvGVlrW&(bW8JE z^4#^;(ho0ojt}&$mOT{xlP`jp^2vjGr3webZBs7(HjCnYb+TmeU_`+wNTIb%OaNSI z4`!PpYSmq?p}aNW=FNKz?&4^oA30`0wqGqbq72Rx>SqmvpV1Z;ckm={t8a!LR+b4Q z7fHLDb4FeDr5rf51GYtLA z5Xqwv+ff;R1a*(3ORC&H9o&g^JDj!N*>tZn)eY5DQfAPK>U#^ox zKDVYpP^(?&*yUu9C>>B8)c*NL;+Z5TUHwS%Zq3LSn$7bu=fNd6cVtemov7 zz~eN?yzIK2Ncq{tB`(lYOsQmrND9Nx!P_0HUEK5zm>(38C)!VcIuQb1y_kNHCT6H% z&=DQavVra-zkES%d@Efgv|gk@tzHC!${&-H8n8U{-6nHJI}B5nk5*lgz#;K)h!%Qy^5dIMDij9_g;K8#gAi zXs>zxyxW`PZ1u9iS+29m~m|#L{ZyXgdl~E zpYa4!9^1u0>PsB!E&213rE@rU?hj>)FZmkw!_kE+dZ<|hy_b(>RovprCsUV+!L{f| zjkPUpe0?6mKX=}r@Lx%~>?TOvecTd96a6T4ao<^m4iiO%^_ys zfKgxQG6CQ^a)hZGTRIvG;PyO0%Z4VlMI_-RWB2%1C$4 zV|}%upR51Xy6{pnB}ED+-3rP@;}6P^_=Ofxf=1ko3T4bZ5RMM8$BNivZFXPYTzWB| zDIiu6BoG1)3E zaqbi22T_9@%+dcuhIue}_#*K2&No%HAUTKOn(U_DmK#7%0JH%%xX*Z1TW!oZnB%;# z0@v+TyF=__m8kGE^ICfZu|w`Y0fwr%QOw)t2e3kRpP4Mh80dFR7i>6P^Y3ns8>R-D z>1lSkY-y-#l1j=`ZLwWQa>d-1{FwC3>qEH88osx7a0 z2Ydol&)f&exQccVLhC>PtJE=Ij^zf(6A-t0-Zxu+#M@?DZIqYWOP?88ELxWAA0003 zv$_)PaeZs(G1j|9U6Y`*HMcEqHrX5%XbR;O3RJU6>ZJ}lmcuyv+*RfNyzfVR4y8WR zPqkC;fI&61h zcObG5Nl3uL{`~Q84Sr+LxK+ufJz|HLNW;G0z5*_ctbFY>1*vUH3vvogBP(QGMwWQQ7_AP8{K2ne-b{kr z^HukS#l-8=E6$J|$nQD=k1F!W0LG7*CCE9V*9@Si{GhL}*IjNk2S?{KC(5m_#pE8E zNJ{xPWN|pjn#yQrYRwL58}uQQYAS4I79Oz}8F)*SPdVa|^4y%qx0(hqgk}0U&$3$4 zF`7ykZ77J1^=C~%hib9xPe8PyT_VaNAM85m^|?{D0)A4$C{1c-IQjN{gVN9Yzck6% zVr&$~qK~w2&6VR&G;viD0xa;sfr%=jg!ytTDR~jqhvJ5d$eft=#n=-Qc_CCG}aPSU5Sh-(>Q z3?&;+C^HPO5!`=?%6OjEs6Md3ifP7B`m$|)x9d7j21^6T_dp97{+?j@9&jJ*>fvmy zL@rFG8EVdd?nO;%Y%($7ik~(Vq?J)4q8-ss9|XaYCR1BvD7mf0uxg&BrV?(_y|}=; zYK1NvZo`^;63)ONX#2p)6mb&WX8F2SWvc&JRm}wtTrFVd*ISy55PCT5z6_z^r!+0C zS@#+jJIy^Wb^9lsOM2D_IZ8N15#o^)jX z-d46IYG(dyIT%Q+aVRDG7C#9C$qUYU_>X1)zi?v@H(Y|j94uNe1-uoeU_FDWv6+F9 z8K7+dhy^QsGZS+|K-54$OiT*AywUOPK^uP`)dk8gK!KTr&+-w4r_PdX6$(C%W?K68Q|& zK4I}8Hl`d(>~rI95E8a~lkf%1EoEoW{lyaX>M17tgW}9g-&TVfhofgtQZ%OQDm!8^ zNk38~pZ>4JB)SUqf7KfBCxTPIwY3`2>8-^a?-oIZKdOZtctejX9V?^Yc%1s$Bnj8^ z6Od9Ka&guKn9*s!RzAIBW~PRBp|M_&k{lLJWsS-Ju_N`n3$P(mJ2dGm)97{?(G3g# zd_a3g1wK7Zfkr*2fUpV}b-Nbhkd>LpgO_mtH( zonRbk!e*t$BC=&762ll(Y=g_?sFZokAW2_d=>Lj3F0*41s3o1w+wDAP=Eg04sIp71 zqMVQ|C->%=P0z<_92k?HCYV z%l6p)Jm>xbFf^g3D02}R+qX;CCmb9#IiyXn(Jw;CS(rJ0H8@$U(cL}{35C#%@$0ip z3H_-@$Qkx~AU1XEc?sKCpr;fiCQE?);zAh-{n>?ESzkMsclhsb7{mpLjU%7rFw>rD zr5UBS^ro;KGMv0|HnbAL77Q3BqGanIyX&q@SlTOs_8mLgw0w8pd>9hZ+?@ig!5o3IVUz&r~TtLFjGVw)myp)NDb; zX|W2MTX%h9R#R1eJ>{XRf@02^KaN*x?3o9bK%_=1$4ES|h~ zzdc!hk*}u+cf`V4bcX$5$sIX`GYhqlRh(|EaDB4nH$tZ6^eNjZ5$zliiYzL{EDu%) z8?y$z+jJ1Wu8B&#RXyBv8_|*xh+u!#6adh-4=~f|+K~*-OaA?U;=|kFeaFUD7qZY& z+oB^RmPh^Fq{pm}B3t9aW9I5eYBaEFdWcPsEwJ(Xh^R~E!Q|0GKhCbGS=CQ3a#`-} zT-Jioq5-T`*@j`MGI6J5598Bhd7^!^ z&JSDh{HiHuyqgx#v%fi3)3AuN5)YN`!@Q*KGdIoDZBa&%wK~eQ7kd^6<=UVJ2Xgt% z5DHc}SD#}-0OH12;(>NM6?ee(n#yD>%D^wd_V16`_R)zV+)RVt_(@-7{Thw@5)t*J zN3*7>rq(>D1eb^;<+HPf*KMV{VtKs?>t1Q1c%t2kvc?iV8}+O@IVJBBOu|*8SalZ{ zDn!oHa~g4qGYHHoIvBJNnh)e91OTwC{@2Id^wO7u6Nb|A%$T+VoObrB z6wi)%j*Y`y^;3VTpp&^fPP3rPCk+QG%6%_m#M{m`Z54+DKx8BYRwJ0)9?`f41_JGx zsf8{t;ll@J`|-}kgMs6D1(w0NuGxDb3zeB~oX7P0$0jO*cdckAZu2X$Y1m-#Lb_0-Ofq95#JNQ*~x(E}x zFD=a{_IeVJI1O7EAf~q6e@Tj|Fi)fC)T1iQ`vsDOwkR*UcXg8Eb6Waj`R(NlpkXwD z>ISNUJN6AY)a}}aIjt7Gvs7Fk<#kA~+Wwqmpwmv}jWv6G@R$0eBMCi&syHlt_S-B< z%9YxTC;6m^6pA9l5#J)5^pVKInf|HmTbvtuinVm6L9izx>BryRxncsCBz zWa~#b)f1t%Hbd#5JMQy$9WyDnqVm`|C}$YlWY6H+98ap*Zad%4jrt@nA#r>o+7Y%x zFp3`E)x&?+edO~Hwx#P1I1&JnsqbWl55%}T5@*3Kht^)n^E{43$wFHbOnv=MPW~24 z5I^$tJj$BM8W*V~xe<%;^G?*)p^lZid)CO60XsDw3m&_RR)H9Yhk4(1+x00obd8Ug zz>uT5W!|Mw2M+KaA1C3T*;^gDXtoat{D88oZas*=K%rW}-&p@k| z;HKxebGCL1%WWnFlu}ZwO(t!wwVAINg*>hHAStxqU7@JFvrk{$lTY}c3fX4Wq5)KK`=t1R zuza*tsbm7lTMm$^B$_Ku+vfvu0y=K^+5tc5BNRlSv!(``>AAnX^61DxyP#kRYZKLM z{j0CXX~VK=`_?nsOa2-2d}tSEk^*n#j!7Oldn*BKtwMy|K~?Jdx{#sl!D*SWb#9D# zM;Zog46)6-=j$b*5l)vh8nIvL=uQ04fNl*S+X2PY+d#_gqy&Vp1(X=*Hu>1uL>+C& z)vO!2$uGR$ZyQ)?%H%!*rCV`@eD0Ir!Or4qUlfU`s`Y1U8`Q<7iqMqh(7_NxKT_2Z2s?kil|JX(w7r91eA0L`7TSm1* z*{5qIk{-~hcXVZfUlZ^aqt7V(wH6{-T&zxc{g89Rs7NaWpT2!E`6-V5>7^uvLsE)J zP5KhncK6_;K`i@&aDu$_nf&h(IL~omyeldDh96}h%0uewlz3nCLdJ-KsPkP&^KVB` ztALjVoIEAnW2XX64)!6TYlY|sqTpXL8$QhY^1rut%Pcyb=q{ ztt8ne;IT?$&ZzYnH8jq_JkBuYGDEUuq!YILiH%2HhH)acanVOegEFj}jZj*G@s!?y z0U`7RTG(R)m}^%!@LJI|9RorwBjBFK-gxeSDaZ0jPdwsZZV2%Vzr`NeQo#I7%Z@lQ z{F#PshPt~3X3&q&qNe)kD?$87R>I)lqx!iUNJjj)&atZqyO}~Pe%tEvMr~jh z5y3`#SgN;m198F!;#sJ`olM8JOYYP;!Z+wv8>lGZI z5b(;GcV6~r`OrLwglXnn+#hJDYJnHZO>Ow{-+QMR^}s(?!6%4f({uOQI@MBQOb@vhx*ofRMbnpOY7Kj z`)2S+mF*|js)p(+MC4O#ZdEOi*}F_1QiNS7+3at~1@`V4;|=BC6o|S?Y-t+o+64{k ztiv)HJBI6E(pCNf0`ZP~mcZ`I|MF;711$Y7&ES5`jLEsP+7*&tkR{c>*Sg~v)ud`I zLuGekh*kD5aOQVR0ESvyIiO%*w{nRufAP8^DOIAa#dJl1`oy-c=2qBin1X{~k7?o4E6d#YtN`0ZlnYO9m@ zth}}NcLmv^|1@FN&GWi#om&{>!OF{QS@6}|tJkx+Li?C*+N{v6N*S|18@chK< z|Fppgr6@)*-`-v(Hl78m)D!7ilrBBb_gWE=WAs1(nQ_!L0pn#*VwK)k3a0F@<~0cj z$f6aLIj=Qzh;K0~F27WpQd8f&n8onAj+X9lYuSW?=Gt8pavjtc?P+re77}!Kp(WdQ zas_?csARd)CCukkM8^X1IjiI^w#*4NPXsw2H!6IJ5P&yPoxD|0r!pfTv`8Y?_KL%z zn{R|>x${q+baxH>u4yU9K9Q>sex<_CZ~LVD!8bInSZaN9&nwq2jPtQy;VTqztzrhP z%cNv+?{)NhWwc3*VVrHlw}R0xsBSSJUNoQhrSq!Am^tSFx*nx&yjGI2Dq#8fn5}X{ ze^vN;>ytI6Hrq++0%M|qO2e;?fE|>(xRHN735>h_TT}o+_NKa5Idn+ORA4|n~F#rGn literal 0 HcmV?d00001 diff --git a/Resources/Locale/en-US/research/technologies.ftl b/Resources/Locale/en-US/research/technologies.ftl index e6c9ae3102..c35e97a205 100644 --- a/Resources/Locale/en-US/research/technologies.ftl +++ b/Resources/Locale/en-US/research/technologies.ftl @@ -34,6 +34,7 @@ research-technology-alternative-research = Alternative Research research-technology-magnets-tech = Localized Magnetism research-technology-advanced-parts = Advanced Parts research-technology-abnormal-artifact-manipulation = Abnormal Artifact Manipulation +research-technology-gravity-manipulation = Gravity Manipulation research-technology-mobile-anomaly-tech = Mobile Anomaly Tech research-technology-rped = Rapid Part Exchange research-technology-super-parts = Super Parts diff --git a/Resources/Prototypes/Entities/Objects/Fun/pai.yml b/Resources/Prototypes/Entities/Objects/Fun/pai.yml index 6f34e113fa..29d25a621e 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/pai.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/pai.yml @@ -16,7 +16,6 @@ - key: enum.InstrumentUiKey.Key type: InstrumentBoundUserInterface - type: Sprite - netsync: false sprite: Objects/Fun/pai.rsi layers: - state: pai-base diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml index ade1337c79..4356efa474 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml @@ -151,7 +151,81 @@ soundInsert: path: /Audio/Weapons/Guns/Gunshots/grenade_launcher.ogg +- type: entity + name: tether gun + parent: + - BaseItem + - PowerCellSlotMediumItem + id: WeaponTetherGun + description: Manipulates gravity around objects to fling them at high velocities. + components: + - type: TetherGun + - type: PowerCellDraw + - type: Sprite + sprite: Objects/Weapons/Guns/Launchers/tether_gun.rsi + layers: + - state: base + - state: base-unshaded + map: [ "unshaded" ] + shader: unshaded + visible: false + - type: ToggleableLightVisuals + spriteLayer: unshaded + inhandVisuals: + left: + - state: inhand-left-unshaded + shader: unshaded + right: + - state: inhand-right-unshaded + shader: unshaded + - type: Appearance + - type: GenericVisualizer + visuals: + enum.TetherVisualsStatus.Key: + unshaded: + True: { visible: true } + False: { visible: false } + # Admeme +- type: entity + name: tether gun + parent: BaseItem + id: WeaponTetherGunAdmin + suffix: admin + description: Manipulates gravity around objects to fling them at high velocities. + components: + - type: TetherGun + canTetherAlive: true + canUnanchor: true + maxForce: 10000 + massLimit: 10000 + dampingRatio: 4 + frequency: 20 + - type: Sprite + sprite: Objects/Weapons/Guns/Launchers/tether_gun.rsi + layers: + - state: base + - state: base-unshaded + map: [ "unshaded" ] + shader: unshaded + visible: false + - type: ToggleableLightVisuals + spriteLayer: unshaded + inhandVisuals: + left: + - state: inhand-left-unshaded + shader: unshaded + right: + - state: inhand-right-unshaded + shader: unshaded + - type: Appearance + - type: GenericVisualizer + visuals: + enum.TetherVisualsStatus.Key: + unshaded: + True: { visible: true } + False: { visible: false } + - type: entity name: meteor launcher parent: WeaponLauncherMultipleRocket diff --git a/Resources/Prototypes/Entities/Objects/base_item.yml b/Resources/Prototypes/Entities/Objects/base_item.yml index ca0c34f72e..b8f71ee236 100644 --- a/Resources/Prototypes/Entities/Objects/base_item.yml +++ b/Resources/Prototypes/Entities/Objects/base_item.yml @@ -105,3 +105,18 @@ cell_slot: name: power-cell-slot-component-slot-name-default startingItem: PowerCellMedium + +- type: entity + id: PowerCellSlotHighItem + abstract: true + components: + - type: ContainerContainer + containers: + cell_slot: !type:ContainerSlot { } + - type: PowerCellSlot + cellSlotId: cell_slot + - type: ItemSlots + slots: + cell_slot: + name: power-cell-slot-component-slot-name-default + startingItem: PowerCellHigh diff --git a/Resources/Prototypes/Entities/Virtual/tether.yml b/Resources/Prototypes/Entities/Virtual/tether.yml index 4c6bd86864..ce953854d6 100644 --- a/Resources/Prototypes/Entities/Virtual/tether.yml +++ b/Resources/Prototypes/Entities/Virtual/tether.yml @@ -4,6 +4,7 @@ components: - type: Physics bodyType: Dynamic + sleepingAllowed: false - type: Fixtures fixtures: tether: diff --git a/Resources/Prototypes/Research/experimental.yml b/Resources/Prototypes/Research/experimental.yml index edac88d2a4..f6f940a997 100644 --- a/Resources/Prototypes/Research/experimental.yml +++ b/Resources/Prototypes/Research/experimental.yml @@ -116,6 +116,18 @@ recipeUnlocks: - TraversalDistorterMachineCircuitboard +- type: technology + id: GravityManipulation + name: research-technology-gravity-manipulation + icon: + sprite: Objects/Weapons/Guns/Launchers/tether_gun.rsi + state: base + discipline: Experimental + tier: 2 + cost: 7500 + recipeUnlocks: + - WeaponTetherGun + - type: technology id: MobileAnomalyTech name: research-technology-mobile-anomaly-tech diff --git a/Resources/Textures/Objects/Weapons/Guns/Launchers/tether_gun.rsi/base-unshaded.png b/Resources/Textures/Objects/Weapons/Guns/Launchers/tether_gun.rsi/base-unshaded.png new file mode 100644 index 0000000000000000000000000000000000000000..84cabefc32592a06d5952392ed05325302454c10 GIT binary patch literal 6130 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�a1nKoxz%K11N9%&mcdRBg{`|UByw2Akr zgYJ%9e+luc3MCDeDBuq}A@)hRJ2G8r%^YvTTI}Gk;+~HKS*ft7-OJRg$FKLKt$Iw|q73H?1io)8;ZyyC ze*KQrN9R?bzAIHAHY+gY##e)tM}lIgmG*<(l_ zDc135tn;aSi3CbVJ`d*j_c71dHy=m+AX15dvLJ?skaMd9?>`Q>D0A| z-sw@Wp68n5t@w^w<1O71gxRUz%3ZbweCRFvxN~|$_9(Iap0``x+%Y-Lw519%vhmG* zb*x+gw>gSK&a26BC#L5Y9-UDx-%?)$l)rO-W=X=~2Y zgg_wLR97bk`0c1Xr>cS1)4Z@J5QutEw70K>!IVOUA_12d0zf5ELI4Ux^0*L4WJ~XU zUeVjj+KFF+XRqFjqs#W0Y=E5GV&!1mzL6LhO|6qppQ;;Rz?TD=8NLe(W(_-x$6bGF z%dmvcs`rU0{A*cvPF@8?Zd7&g?0|)0$iDW&>@N-%k{<1F@_LzN9PhtzI6gQHIVr8R zgZgCdh7TXF+h2WsPmeLmc}<`X&s}8nu#p}=ueN&tX0N@o>ReIFp{wgQ_f~BzE6gUx zRUlUjT9GD4zx-7h;~sR!yw~tUCGN%W0mtEWI#K=505;-Dy12hU>b|jVa#HN8yhrt! z_022Hu10*?RNG@7_teP#o*KB;x=oP-K%R(extFW=ivUZy2otQqM7ai zVK-+gHXaSbRAxlD)>7Q8U&xCA8kx3xva`c;>cN<`ml9q~9$p?CeRt858^gidVlLdO zwrs#T@2s?&8W*|kXq+%LZ|TleF(0=_<#g3?=cOKA*R2K{ARVzN-SV{VUefb}OXzL4 zvtaY9T5cp#$5t(>#^29Oz5Y2J;rXZ$f?x$PG3YIj{7S3hTkc*B`eB?&$0{DoB(R~n z&JC=LQ(XZSxlvtO_VtlcT1Jr01+P1fORJGn4rQsY-wV5$w$DXNyN2PEz1?jO;^a%e z(+~VgqCE`{mQ0>qc)I06Pf+GT^FkYb;gC)Ao6HmDWf8rF3VSuSj@9(5MiTuS8Gxl} z#pzSH9vjnV*0*J=^XhCy4J`|=*!o%dPKX443wH32W26(y}5x z%|$-Q`d1twev@D9iG88jS597~pIkX~*J)4$OP#wZhYm|Fpg1}%u6nznSk_fd;I7IW z1E|XxhUaI`N9$VInGy!H<-3iNiK6mE|NHM%N(Teer|Gm$PaoahD$R%I9gi{@u3jpA zv$w|nNuLeFz$0SayJu-@#|Fn+?|;cTPL`==4!zZHq((@NY^chf5l!T0^4k0m_W1-^T|=H7L6^J$jT& zvs1RNemJXd@haBYn31;r^YZ+CHx9&XEh%_+vZU_R8P%*n#>kBLoCKW;Prys3Q?~Tr zjyV}uafh5czQoiwoqhdwi)~Qkn62$>e5u!S7i<>U6G4$n57W%GHN)y3mPGl>$1I-9 zB)Wcio@A>Rj@?YOM;$a0~U<;nfCZY46Ys@k?) z$G3KSM%-~Js6KZ2l;5&S(a<%tkB-~lw_cx^w0*5)@4>)h-VDUnP0hV?XViAyHDUE# zBI@boji#nsjMQ4l4c;Hv+egVRvTP)D8MfQaY2{QqE6_=_&Kc9>(<;17veF4UmL}MC zr0W@z{Wowak8X%mcekHKBt{<6Twn0cjn`*|OW}LYxb}I~)>O|Jh1s0~z0%ys>Hc0; zW^qC9?lqI$(5bf-4O!Gf^OK~&T{5*dMI-I%tcWF+9z6{B@MZoplMJD~Xiz3<7&|`& zI#!hmL3KhGsazv1QaKjmrV7!MPJ--L3qCm`d0NXoGHzT|w%AdoTJp4JlZRJ;Kc@ao zQTxl3j;vixUQ3Qw3SX(J+|S)3N*iZ&%ukMVU}*CD*L6KXn)V7P<=UUqw9Wlv2D{b_ zpWRj@V;h{C8brQbb$ezCN5(?twx;M76Hgt93qr^a*mPTZy63s+Gcqhjt6fg73hK=~ zfF=8GZ@YM=-yDMr)7p|S&Cv(cp_-l(x z(D4v@m-$Pdc~RvZ8ybsEy$3ur67lB!1qwXnei|mfafJ))0C*|ASfz`>e|D-l)sdTx z>kVFvUB1HRG2BsJF?4HfYQhq@$q^&`8LdMP<+Xy^hvBuG_UkR|A6s)jqK2Md{GmKx zUq>}6Y91YpFbv#oJwrlIZ4^H2_O46fU5ZV>b%>*%Ht*-s=X0hIRPW*`-L5S?E4Dk1oZ^g` zoX`?1|ERkQ)BN~E+`Nw@J3p7#AJ_M#uf>jgZhhu2@g1?asek3p8}8!P#!JUVwaMKk z#V)~5xd9`=jA5jW(|DoLxJG5o7GnduWJ?G{C6Py=(5V#4_h&Bnq&>Vbo$PwU(Xeuz zm%H;D^~XzYE}(>;gIaW&t+d*_wZSK-siLa^8Pu>l`=YI8(G+!uIR!e1y353inwvY+ zlM8n2Ik7`FQl5Puc5BP?xGQqS#TfOeyEMJ-7HK#(S((gEOKEO9tsm?z8zPndn&_z=laq1-G8q66`8@Q93BYv`2=X^%C?$McP29hP6 z%ZhFz%EJ&utNuIxN~hkPnUqq=QolX_j@vdj63x)ld)ND|XKri0g4b=xx#g$mLTbGz z*^7O|ONFK`TDUuL>Rg=6GhwS);XHFw#s%XK{nPEn7hd9s_EuCEZ?f=qO*I~y9w!Z+ zlWW?ZP1l-w$i)x)M3KGO_8=f58MO!(v}n10zQJt5wHM6Bwq;bksuI~L!^+&4hAGp77)k_ zCBypU5(b?xkpz=rzBD?NA`k&kECP!_!JQ*{5g3@gCX^)NaES~jmv0c@FET7h zA`udiNU2nckXj=IqCg~?Kp-Gd7$gP*2QA>@s89(r5*{ixQ9^vha00|^5l<-L2|}St zOeRYZE+NBUpdR`?KfaJg`vD&+{>B2x2Qrc=M4}NWB%hD`*+VRGjsQWvCG=lC#NOam z63GC>f^ZQVaE<^%B_=;ZaM(Zmh2f%*iE=n>BoG4dK~pgp75z)dWmFpdhli4aKptN> z;RTZYi=~9e{fDeya#Lz1%K14F(ESJQFV^2{pD+fkXf&defE}((kLpB*DdQ740yd9B zoVdl}S+-afz=mU3HUJ!pu|~mJ022$h!P^qJ92SPn0jz(5qK1kk%uqI0HXCkh%fZ00)=Vbc7Kg&YZO}}NH5QM>u<_iVAXbQYU{^9je$Gk>#Q~vgZ7^s& z7K?)um~1>8i$>w$Of&}vXJN1e6am8oxG2H|6o*Z85s3Iqa5#B-u5e;+_3 z276J7ibf$YwiE8kfgytBfYdUToeBa>$iZre6cNCb2t?ijK?oV9ObV*>oM><;>Fcn# z^2DG;l(Of)b-fo5_Vw4-Nf5%DP(h&+jZ0**zXlOABLL1sAkgotiXFrZ4Ftd${;j3H z%X$B0xVRiP3P7U(I17zN!?7F;IB-lR9&U@V!GQ{lwJjR>6)gwIt+!@Ijg|_-PRU z{l3b;#RXiekUtiyZ+s~!{6Buajl=&j0to#l$Zzrchps<#{T2hiW&EeR{?PSX4E&by zpYHmf(WUv%>kbeK?trA=%S=LUS_}9hq{ebz<^=hoJdTy+?ExhkLf6$|2xQt!<*5QW zcvv44s!OOeXZ2T8bhPH_k>GwZP_&ckw8R_yE4igu`vz2Z%6%`QpF-;vbZ~8&2B|J* z7tA>&XY%T*0z0pC^(z4&ka&v2`p&ZRgOj+<>l_>>4hW>^ Zg-#)NWf@;1?wHbs>g?fEv~>OEe*+LhV3_~_ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Weapons/Guns/Launchers/tether_gun.rsi/inhand-left.png b/Resources/Textures/Objects/Weapons/Guns/Launchers/tether_gun.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..5d314fb76d1bbdf713b2c22523b3a23a22328bf2 GIT binary patch literal 6134 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 H_t1X>cYEG4 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Weapons/Guns/Launchers/tether_gun.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/Launchers/tether_gun.rsi/meta.json new file mode 100644 index 0000000000..4d8baad4cf --- /dev/null +++ b/Resources/Textures/Objects/Weapons/Guns/Launchers/tether_gun.rsi/meta.json @@ -0,0 +1,33 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Sprited by discord Kheprep#7153", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "base" + }, + { + "name": "base-unshaded" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "inhand-left-unshaded", + "directions": 4 + }, + { + "name": "inhand-right-unshaded", + "directions": 4 + } + ] +} \ No newline at end of file -- 2.52.0