From 599c599a4efbc13df5b603eff8fbf3f952f80aba Mon Sep 17 00:00:00 2001 From: Ed <96445749+TheShuEd@users.noreply.github.com> Date: Fri, 2 Aug 2024 13:51:54 +0300 Subject: [PATCH] Some shit (#380) * telegraphy effects * shadow step spell backend * add component spell * predict sharpening * Update ring.yml * locale sync * Update entities.ftl * icon shadow step --- .../Damage/Systems/DamageOtherOnHitSystem.cs | 5 +- .../_CP14/MagicSpell/CP14MagicSystem.cs | 4 +- .../CP14MeleeSelfDamageComponent.cs | 10 - .../_CP14/Skills/CP14SkillSystem.cs | 6 +- .../_CP14/MagicSpell/CP14SharedMagicSystem.cs | 232 ++++++++++-------- .../Components/CP14MagicEffectComponent.cs | 6 + .../Events/CP14CastMagicEffectEvent.cs | 2 +- .../Spells/CP14SpellAddComponent.cs | 17 ++ .../Spells/CP14SpellCasterTeleport.cs | 23 ++ .../CP14MeleeSelfDamageComponent.cs | 16 ++ .../Components/CP14SharpenedComponent.cs | 5 +- .../CP14SharpeningStoneComponent.cs | 8 +- .../CP14MeleeSelfDamageSystem.cs | 4 +- .../EntitySystems/CP14SharpeningSystem.cs | 9 +- .../Locale/en-US/_CP14/sharpening/sharp.ftl | 2 + .../ru-RU/_CP14/_PROTO/entities/entities.ftl | 176 ++++++++++--- .../Locale/ru-RU/_CP14/sharpening/sharp.ftl | 4 +- .../Entities/Actions/Spells/cure_wounds.yml | 4 + .../Entities/Actions/Spells/shadow_step.yml | 42 ++++ .../_CP14/Entities/Clothing/Rings/ring.yml | 3 + .../Effects/Magic/spells_icons.rsi/meta.json | 3 + .../Magic/spells_icons.rsi/shadow_step.png | Bin 0 -> 1469 bytes 22 files changed, 410 insertions(+), 171 deletions(-) delete mode 100644 Content.Server/_CP14/MeleeWeapon/Components/CP14MeleeSelfDamageComponent.cs create mode 100644 Content.Shared/_CP14/MagicSpell/Spells/CP14SpellAddComponent.cs create mode 100644 Content.Shared/_CP14/MagicSpell/Spells/CP14SpellCasterTeleport.cs create mode 100644 Content.Shared/_CP14/MeleeWeapon/Components/CP14MeleeSelfDamageComponent.cs rename {Content.Server => Content.Shared}/_CP14/MeleeWeapon/Components/CP14SharpenedComponent.cs (75%) rename {Content.Server => Content.Shared}/_CP14/MeleeWeapon/Components/CP14SharpeningStoneComponent.cs (87%) rename {Content.Server => Content.Shared}/_CP14/MeleeWeapon/EntitySystems/CP14MeleeSelfDamageSystem.cs (85%) rename {Content.Server => Content.Shared}/_CP14/MeleeWeapon/EntitySystems/CP14SharpeningSystem.cs (92%) create mode 100644 Resources/Prototypes/_CP14/Entities/Actions/Spells/shadow_step.yml create mode 100644 Resources/Textures/_CP14/Effects/Magic/spells_icons.rsi/shadow_step.png diff --git a/Content.Server/Damage/Systems/DamageOtherOnHitSystem.cs b/Content.Server/Damage/Systems/DamageOtherOnHitSystem.cs index ea4887bad6..a93b46c9f2 100644 --- a/Content.Server/Damage/Systems/DamageOtherOnHitSystem.cs +++ b/Content.Server/Damage/Systems/DamageOtherOnHitSystem.cs @@ -1,8 +1,7 @@ -using Content.Server._CP14.MeleeWeapon; -using Content.Server._CP14.MeleeWeapon.Components; using Content.Server.Administration.Logs; using Content.Server.Damage.Components; using Content.Server.Weapons.Ranged.Systems; +using Content.Shared._CP14.MeleeWeapon.Components; using Content.Shared.Camera; using Content.Shared.Damage; using Content.Shared.Damage.Events; @@ -43,7 +42,7 @@ namespace Content.Server.Damage.Systems damage *= sharp.Sharpness; var dmg = _damageable.TryChangeDamage(args.Target, damage, component.IgnoreResistances, origin: args.Component.Thrower); - //CrystallPunk Melee pgrade end + //CrystallPunk Melee upgrade end // Log damage only for mobs. Useful for when people throw spears at each other, but also avoids log-spam when explosions send glass shards flying. if (dmg != null && HasComp(args.Target)) diff --git a/Content.Server/_CP14/MagicSpell/CP14MagicSystem.cs b/Content.Server/_CP14/MagicSpell/CP14MagicSystem.cs index 6eaeefb1ef..f377b78ee7 100644 --- a/Content.Server/_CP14/MagicSpell/CP14MagicSystem.cs +++ b/Content.Server/_CP14/MagicSpell/CP14MagicSystem.cs @@ -16,7 +16,7 @@ public sealed partial class CP14MagicSystem : CP14SharedMagicSystem SubscribeLocalEvent(OnSpellSpoken); SubscribeLocalEvent(OnSpawnMagicVisualEffect); - SubscribeLocalEvent(OnDespawnMagicVisualEffect); + SubscribeLocalEvent(OnDespawnMagicVisualEffect); } private void OnSpellSpoken(Entity ent, ref CP14VerbalAspectSpeechEvent args) @@ -32,7 +32,7 @@ public sealed partial class CP14MagicSystem : CP14SharedMagicSystem ent.Comp.SpawnedEntity = vfx; } - private void OnDespawnMagicVisualEffect(Entity ent, ref CP14StopCastMagicEffectEvent args) + private void OnDespawnMagicVisualEffect(Entity ent, ref CP14EndCastMagicEffectEvent args) { QueueDel(ent.Comp.SpawnedEntity); ent.Comp.SpawnedEntity = null; diff --git a/Content.Server/_CP14/MeleeWeapon/Components/CP14MeleeSelfDamageComponent.cs b/Content.Server/_CP14/MeleeWeapon/Components/CP14MeleeSelfDamageComponent.cs deleted file mode 100644 index f5f199f6f8..0000000000 --- a/Content.Server/_CP14/MeleeWeapon/Components/CP14MeleeSelfDamageComponent.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Content.Shared.Damage; - -namespace Content.Server._CP14.MeleeWeapon.Components; - -[RegisterComponent] -public sealed partial class CP14MeleeSelfDamageComponent : Component -{ - [DataField(required: true)] - public DamageSpecifier DamageToSelf; -} diff --git a/Content.Server/_CP14/Skills/CP14SkillSystem.cs b/Content.Server/_CP14/Skills/CP14SkillSystem.cs index bf2266848b..b9c5126922 100644 --- a/Content.Server/_CP14/Skills/CP14SkillSystem.cs +++ b/Content.Server/_CP14/Skills/CP14SkillSystem.cs @@ -1,16 +1,12 @@ -using System.Numerics; using Content.Server._CP14.Alchemy; -using Content.Server._CP14.MeleeWeapon; -using Content.Server._CP14.MeleeWeapon.EntitySystems; using Content.Server.Popups; +using Content.Shared._CP14.MeleeWeapon.EntitySystems; using Content.Shared._CP14.Skills; using Content.Shared._CP14.Skills.Components; -using Content.Shared.Chemistry.Components; using Content.Shared.Damage; using Content.Shared.Examine; using Content.Shared.Hands.EntitySystems; using Content.Shared.Popups; -using Content.Shared.Stunnable; using Content.Shared.Throwing; using Content.Shared.Weapons.Melee; using Content.Shared.Weapons.Melee.Events; diff --git a/Content.Shared/_CP14/MagicSpell/CP14SharedMagicSystem.cs b/Content.Shared/_CP14/MagicSpell/CP14SharedMagicSystem.cs index b8342726f1..39bb05278b 100644 --- a/Content.Shared/_CP14/MagicSpell/CP14SharedMagicSystem.cs +++ b/Content.Shared/_CP14/MagicSpell/CP14SharedMagicSystem.cs @@ -36,6 +36,10 @@ public partial class CP14SharedMagicSystem : EntitySystem SubscribeLocalEvent(OnBeforeCastMagicEffect); + SubscribeLocalEvent(OnInstantAction); + SubscribeLocalEvent(OnEntityTargetAction); + SubscribeLocalEvent(OnWorldTargetAction); + SubscribeLocalEvent(OnDelayedInstantActionDoAfter); SubscribeLocalEvent(OnDelayedEntityTargetDoAfter); SubscribeLocalEvent(OnDelayedWorldTargetDoAfter); @@ -47,15 +51,132 @@ public partial class CP14SharedMagicSystem : EntitySystem SubscribeLocalEvent(OnAfterCastMagicEffect); - SubscribeLocalEvent(OnInstantAction); - SubscribeLocalEvent(OnEntityTargetAction); - SubscribeLocalEvent(OnWorldTargetAction); + } + + private void OnBeforeCastMagicEffect(Entity ent, ref CP14BeforeCastMagicEffectEvent args) + { + if (!TryComp(args.Performer, out var magicContainer)) + { + args.Cancel(); + return; + } + + if (!_magicEnergy.HasEnergy(args.Performer, ent.Comp.ManaCost, magicContainer, ent.Comp.Safe)) + { + args.PushReason(Loc.GetString("cp14-magic-spell-not-enough-mana")); + args.Cancel(); + } + else if(!_magicEnergy.HasEnergy(args.Performer, ent.Comp.ManaCost, magicContainer, true) && _net.IsServer) + { + _popup.PopupEntity(Loc.GetString("cp14-magic-spell-not-enough-mana-cast-warning-"+_random.Next(5)), args.Performer, args.Performer, PopupType.SmallCaution); + } + } + + private void OnInstantAction(CP14DelayedInstantActionEvent args) + { + if (args.Handled) + return; + + args.Handled = true; + + if (args is not ICP14DelayedMagicEffect delayedEffect) + return; + + if (!TryCastSpell(args.Action, args.Performer)) + return; + + var doAfterEventArgs = new DoAfterArgs(EntityManager, args.Performer, delayedEffect.Delay, new CP14DelayedInstantActionDoAfterEvent(), args.Action) + { + BreakOnMove = delayedEffect.BreakOnMove, + BreakOnDamage = delayedEffect.BreakOnDamage, + BlockDuplicate = true, + }; + + _doAfter.TryStartDoAfter(doAfterEventArgs); + + //Telegraphy effects + if (_net.IsServer && TryComp(args.Action, out var magicEffect)) + { + foreach (var effect in magicEffect.TelegraphyEffects) + { + effect.Effect(EntityManager, new CP14SpellEffectBaseArgs(args.Performer, args.Performer, Transform(args.Performer).Coordinates)); + } + } + } + + private void OnWorldTargetAction(CP14DelayedWorldTargetActionEvent args) + { + if (args.Handled) + return; + + args.Handled = true; + + if (args is not ICP14DelayedMagicEffect delayedEffect) + return; + + if (!TryCastSpell(args.Action, args.Performer)) + return; + + var doAfter = new CP14DelayedWorldTargetActionDoAfterEvent() + { + Target = EntityManager.GetNetCoordinates(args.Target) + }; + + var doAfterEventArgs = new DoAfterArgs(EntityManager, args.Performer, delayedEffect.Delay, doAfter, args.Action) + { + BreakOnMove = delayedEffect.BreakOnMove, + BreakOnDamage = delayedEffect.BreakOnDamage, + BlockDuplicate = true, + }; + + _doAfter.TryStartDoAfter(doAfterEventArgs); + + //Telegraphy effects + if (_net.IsServer && TryComp(args.Action, out var magicEffect)) + { + foreach (var effect in magicEffect.TelegraphyEffects) + { + effect.Effect(EntityManager, new CP14SpellEffectBaseArgs(args.Performer, null, args.Target)); + } + } + } + + private void OnEntityTargetAction(CP14DelayedEntityTargetActionEvent args) + { + if (args.Handled) + return; + + args.Handled = true; + + if (args is not ICP14DelayedMagicEffect delayedEffect) + return; + + if (!TryCastSpell(args.Action, args.Performer)) + return; + + var doAfterEventArgs = new DoAfterArgs(EntityManager, args.Performer, delayedEffect.Delay, new CP14DelayedEntityTargetActionDoAfterEvent(), args.Action, args.Target) + { + BreakOnMove = delayedEffect.BreakOnMove, + BreakOnDamage = delayedEffect.BreakOnDamage, + BlockDuplicate = true, + }; + + _doAfter.TryStartDoAfter(doAfterEventArgs); + + //Telegraphy effects + if (_net.IsServer && TryComp(args.Action, out var magicEffect)) + { + foreach (var effect in magicEffect.TelegraphyEffects) + { + effect.Effect(EntityManager, new CP14SpellEffectBaseArgs(args.Performer, args.Target, null)); + } + } } private void OnDelayedWorldTargetDoAfter(Entity ent, ref CP14DelayedWorldTargetActionDoAfterEvent args) { - var stopEv = new CP14StopCastMagicEffectEvent(); - RaiseLocalEvent(ent, ref stopEv); + var endEv = new CP14EndCastMagicEffectEvent(); + RaiseLocalEvent(ent, ref endEv); if (args.Cancelled || !_net.IsServer) return; @@ -71,8 +192,8 @@ public partial class CP14SharedMagicSystem : EntitySystem private void OnDelayedEntityTargetDoAfter(Entity ent, ref CP14DelayedEntityTargetActionDoAfterEvent args) { - var stopEv = new CP14StopCastMagicEffectEvent(); - RaiseLocalEvent(ent, ref stopEv); + var endEv = new CP14EndCastMagicEffectEvent(); + RaiseLocalEvent(ent, ref endEv); if (args.Cancelled || !_net.IsServer) return; @@ -88,8 +209,8 @@ public partial class CP14SharedMagicSystem : EntitySystem private void OnDelayedInstantActionDoAfter(Entity ent, ref CP14DelayedInstantActionDoAfterEvent args) { - var stopEv = new CP14StopCastMagicEffectEvent(); - RaiseLocalEvent(ent, ref stopEv); + var endEv = new CP14EndCastMagicEffectEvent(); + RaiseLocalEvent(ent, ref endEv); if (args.Cancelled || !_net.IsServer) return; @@ -154,80 +275,6 @@ public partial class CP14SharedMagicSystem : EntitySystem RaiseLocalEvent(ent, ref ev); } - private void OnInstantAction(CP14DelayedInstantActionEvent args) - { - if (args.Handled) - return; - - args.Handled = true; - - if (args is not ICP14DelayedMagicEffect delayedEffect) - return; - - if (!TryCastSpell(args.Action, args.Performer)) - return; - - var doAfterEventArgs = new DoAfterArgs(EntityManager, args.Performer, delayedEffect.Delay, new CP14DelayedInstantActionDoAfterEvent(), args.Action) - { - BreakOnMove = delayedEffect.BreakOnMove, - BreakOnDamage = delayedEffect.BreakOnDamage, - BlockDuplicate = true, - }; - - _doAfter.TryStartDoAfter(doAfterEventArgs); - } - - private void OnWorldTargetAction(CP14DelayedWorldTargetActionEvent args) - { - if (args.Handled) - return; - - args.Handled = true; - - if (args is not ICP14DelayedMagicEffect delayedEffect) - return; - - if (!TryCastSpell(args.Action, args.Performer)) - return; - - var doAfter = new CP14DelayedWorldTargetActionDoAfterEvent() - { - Target = EntityManager.GetNetCoordinates(args.Target) - }; - - var doAfterEventArgs = new DoAfterArgs(EntityManager, args.Performer, delayedEffect.Delay, doAfter, args.Action) - { - BreakOnMove = delayedEffect.BreakOnMove, - BreakOnDamage = delayedEffect.BreakOnDamage, - BlockDuplicate = true, - }; - - _doAfter.TryStartDoAfter(doAfterEventArgs); - } - - private void OnEntityTargetAction(CP14DelayedEntityTargetActionEvent args) - { - if (args.Handled) - return; - - args.Handled = true; - - if (args is not ICP14DelayedMagicEffect delayedEffect) - return; - - if (!TryCastSpell(args.Action, args.Performer)) - return; - - var doAfterEventArgs = new DoAfterArgs(EntityManager, args.Performer, delayedEffect.Delay, new CP14DelayedEntityTargetActionDoAfterEvent(), args.Action, args.Target) - { - BreakOnMove = delayedEffect.BreakOnMove, - BreakOnDamage = delayedEffect.BreakOnDamage, - BlockDuplicate = true, - }; - - _doAfter.TryStartDoAfter(doAfterEventArgs); - } - private bool TryCastSpell(EntityUid spell, EntityUid performer) { var ev = new CP14BeforeCastMagicEffectEvent @@ -251,25 +298,6 @@ public partial class CP14SharedMagicSystem : EntitySystem return !ev.Cancelled; } - private void OnBeforeCastMagicEffect(Entity ent, ref CP14BeforeCastMagicEffectEvent args) - { - if (!TryComp(args.Performer, out var magicContainer)) - { - args.Cancel(); - return; - } - - if (!_magicEnergy.HasEnergy(args.Performer, ent.Comp.ManaCost, magicContainer, ent.Comp.Safe)) - { - args.PushReason(Loc.GetString("cp14-magic-spell-not-enough-mana")); - args.Cancel(); - } - else if(!_magicEnergy.HasEnergy(args.Performer, ent.Comp.ManaCost, magicContainer, true) && _net.IsServer) - { - _popup.PopupEntity(Loc.GetString("cp14-magic-spell-not-enough-mana-cast-warning-"+_random.Next(5)), args.Performer, args.Performer, PopupType.SmallCaution); - } - } - private void OnAfterCastMagicEffect(Entity ent, ref CP14AfterCastMagicEffectEvent args) { if (_net.IsClient) diff --git a/Content.Shared/_CP14/MagicSpell/Components/CP14MagicEffectComponent.cs b/Content.Shared/_CP14/MagicSpell/Components/CP14MagicEffectComponent.cs index bc521e78c9..70ff6eccff 100644 --- a/Content.Shared/_CP14/MagicSpell/Components/CP14MagicEffectComponent.cs +++ b/Content.Shared/_CP14/MagicSpell/Components/CP14MagicEffectComponent.cs @@ -15,6 +15,12 @@ public sealed partial class CP14MagicEffectComponent : Component [DataField] public bool Safe = false; + /// + /// Effects that will trigger at the beginning of the cast, before mana is spent. Should have no gameplay importance, just special effects, popups and sounds. + /// + [DataField] + public List TelegraphyEffects = new(); + [DataField] public List Effects = new(); } diff --git a/Content.Shared/_CP14/MagicSpell/Events/CP14CastMagicEffectEvent.cs b/Content.Shared/_CP14/MagicSpell/Events/CP14CastMagicEffectEvent.cs index 27e8302b93..3dd5a6d6d5 100644 --- a/Content.Shared/_CP14/MagicSpell/Events/CP14CastMagicEffectEvent.cs +++ b/Content.Shared/_CP14/MagicSpell/Events/CP14CastMagicEffectEvent.cs @@ -34,7 +34,7 @@ public sealed class CP14StartCastMagicEffectEvent : EntityEventArgs /// is invoked on the spell itself when the spell process has been completed or interrupted /// [ByRefEvent] -public sealed class CP14StopCastMagicEffectEvent : EntityEventArgs +public sealed class CP14EndCastMagicEffectEvent : EntityEventArgs { } diff --git a/Content.Shared/_CP14/MagicSpell/Spells/CP14SpellAddComponent.cs b/Content.Shared/_CP14/MagicSpell/Spells/CP14SpellAddComponent.cs new file mode 100644 index 0000000000..9be22aa78e --- /dev/null +++ b/Content.Shared/_CP14/MagicSpell/Spells/CP14SpellAddComponent.cs @@ -0,0 +1,17 @@ +using Robust.Shared.Prototypes; + +namespace Content.Shared._CP14.MagicSpell.Spells; + +public sealed partial class CP14SpellAddComponent : CP14SpellEffect +{ + [DataField] + public ComponentRegistry Components = new(); + + public override void Effect(EntityManager entManager, CP14SpellEffectBaseArgs args) + { + if (args.Target is null) + return; + + entManager.AddComponents(args.Target.Value, Components); + } +} diff --git a/Content.Shared/_CP14/MagicSpell/Spells/CP14SpellCasterTeleport.cs b/Content.Shared/_CP14/MagicSpell/Spells/CP14SpellCasterTeleport.cs new file mode 100644 index 0000000000..070460a21f --- /dev/null +++ b/Content.Shared/_CP14/MagicSpell/Spells/CP14SpellCasterTeleport.cs @@ -0,0 +1,23 @@ +using Robust.Shared.Map; +using Robust.Shared.Prototypes; + +namespace Content.Shared._CP14.MagicSpell.Spells; + +public sealed partial class CP14SpellCasterTeleport : CP14SpellEffect +{ + public override void Effect(EntityManager entManager, CP14SpellEffectBaseArgs args) + { + EntityCoordinates? targetPoint = null; + if (args.Position is not null) + targetPoint = args.Position.Value; + else if (args.Target is not null && entManager.TryGetComponent(args.Target.Value, out var transformComponent)) + targetPoint = transformComponent.Coordinates; + + if (targetPoint is null || args.User is null) + return; + + var transform = entManager.System(); + + transform.SetCoordinates(args.User.Value, targetPoint.Value); + } +} diff --git a/Content.Shared/_CP14/MeleeWeapon/Components/CP14MeleeSelfDamageComponent.cs b/Content.Shared/_CP14/MeleeWeapon/Components/CP14MeleeSelfDamageComponent.cs new file mode 100644 index 0000000000..fa1604c24a --- /dev/null +++ b/Content.Shared/_CP14/MeleeWeapon/Components/CP14MeleeSelfDamageComponent.cs @@ -0,0 +1,16 @@ +using Content.Shared.Damage; + +namespace Content.Shared._CP14.MeleeWeapon.Components; + +[RegisterComponent] +public sealed partial class CP14MeleeSelfDamageComponent : Component +{ + [DataField] + public DamageSpecifier DamageToSelf = new() + { + DamageDict = new() + { + { "Blunt", 1 }, + } + }; +} diff --git a/Content.Server/_CP14/MeleeWeapon/Components/CP14SharpenedComponent.cs b/Content.Shared/_CP14/MeleeWeapon/Components/CP14SharpenedComponent.cs similarity index 75% rename from Content.Server/_CP14/MeleeWeapon/Components/CP14SharpenedComponent.cs rename to Content.Shared/_CP14/MeleeWeapon/Components/CP14SharpenedComponent.cs index abf9ce6311..ee7c81042a 100644 --- a/Content.Server/_CP14/MeleeWeapon/Components/CP14SharpenedComponent.cs +++ b/Content.Shared/_CP14/MeleeWeapon/Components/CP14SharpenedComponent.cs @@ -1,7 +1,6 @@ +using Content.Shared._CP14.MeleeWeapon.EntitySystems; -using Content.Server._CP14.MeleeWeapon.EntitySystems; - -namespace Content.Server._CP14.MeleeWeapon.Components; +namespace Content.Shared._CP14.MeleeWeapon.Components; /// /// allows the object to become blunt with use diff --git a/Content.Server/_CP14/MeleeWeapon/Components/CP14SharpeningStoneComponent.cs b/Content.Shared/_CP14/MeleeWeapon/Components/CP14SharpeningStoneComponent.cs similarity index 87% rename from Content.Server/_CP14/MeleeWeapon/Components/CP14SharpeningStoneComponent.cs rename to Content.Shared/_CP14/MeleeWeapon/Components/CP14SharpeningStoneComponent.cs index 31a639bad6..75b0e4b878 100644 --- a/Content.Server/_CP14/MeleeWeapon/Components/CP14SharpeningStoneComponent.cs +++ b/Content.Shared/_CP14/MeleeWeapon/Components/CP14SharpeningStoneComponent.cs @@ -1,8 +1,8 @@ -using Content.Server._CP14.MeleeWeapon.EntitySystems; +using Content.Shared._CP14.MeleeWeapon.EntitySystems; using Content.Shared.Damage; using Robust.Shared.Audio; -namespace Content.Server._CP14.MeleeWeapon.Components; +namespace Content.Shared._CP14.MeleeWeapon.Components; /// /// component allows you to sharpen objects by restoring their damage. @@ -34,7 +34,7 @@ public sealed partial class CP14SharpeningStoneComponent : Component { DamageDict = new() { - { "Blunt", 1 } + { "Blunt", 1 }, } }; @@ -46,7 +46,7 @@ public sealed partial class CP14SharpeningStoneComponent : Component { DamageDict = new() { - { "Blunt", 1 } + { "Blunt", 1 }, } }; } diff --git a/Content.Server/_CP14/MeleeWeapon/EntitySystems/CP14MeleeSelfDamageSystem.cs b/Content.Shared/_CP14/MeleeWeapon/EntitySystems/CP14MeleeSelfDamageSystem.cs similarity index 85% rename from Content.Server/_CP14/MeleeWeapon/EntitySystems/CP14MeleeSelfDamageSystem.cs rename to Content.Shared/_CP14/MeleeWeapon/EntitySystems/CP14MeleeSelfDamageSystem.cs index ef818729b0..468d8e20a3 100644 --- a/Content.Server/_CP14/MeleeWeapon/EntitySystems/CP14MeleeSelfDamageSystem.cs +++ b/Content.Shared/_CP14/MeleeWeapon/EntitySystems/CP14MeleeSelfDamageSystem.cs @@ -1,8 +1,8 @@ -using Content.Server._CP14.MeleeWeapon.Components; +using Content.Shared._CP14.MeleeWeapon.Components; using Content.Shared.Damage; using Content.Shared.Weapons.Melee.Events; -namespace Content.Server._CP14.MeleeWeapon.EntitySystems; +namespace Content.Shared._CP14.MeleeWeapon.EntitySystems; public sealed class CP14MeleeSelfDamageSystem : EntitySystem { diff --git a/Content.Server/_CP14/MeleeWeapon/EntitySystems/CP14SharpeningSystem.cs b/Content.Shared/_CP14/MeleeWeapon/EntitySystems/CP14SharpeningSystem.cs similarity index 92% rename from Content.Server/_CP14/MeleeWeapon/EntitySystems/CP14SharpeningSystem.cs rename to Content.Shared/_CP14/MeleeWeapon/EntitySystems/CP14SharpeningSystem.cs index ca48977ddf..17bab6d1b1 100644 --- a/Content.Server/_CP14/MeleeWeapon/EntitySystems/CP14SharpeningSystem.cs +++ b/Content.Shared/_CP14/MeleeWeapon/EntitySystems/CP14SharpeningSystem.cs @@ -1,21 +1,23 @@ using System.Linq; -using Content.Server._CP14.MeleeWeapon.Components; +using Content.Shared._CP14.MeleeWeapon.Components; using Content.Shared.Damage; using Content.Shared.Examine; using Content.Shared.Interaction; using Content.Shared.Placeable; +using Content.Shared.Popups; using Content.Shared.Timing; using Content.Shared.Weapons.Melee.Events; using Content.Shared.Wieldable; using Robust.Shared.Audio.Systems; -namespace Content.Server._CP14.MeleeWeapon.EntitySystems; +namespace Content.Shared._CP14.MeleeWeapon.EntitySystems; public sealed class CP14SharpeningSystem : EntitySystem { [Dependency] private readonly DamageableSystem _damageableSystem = default!; [Dependency] private readonly UseDelaySystem _useDelay = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; public override void Initialize() { @@ -87,6 +89,9 @@ public sealed class CP14SharpeningSystem : EntitySystem _damageableSystem.TryChangeDamage(target, stone.Comp.TargetDamage); component.Sharpness = MathHelper.Clamp01(component.Sharpness + stone.Comp.SharpnessHeal); + + if (component.Sharpness >= 0.99) + _popup.PopupEntity(Loc.GetString("sharpening-ready"), target, user); } _useDelay.TryResetDelay(stone); diff --git a/Resources/Locale/en-US/_CP14/sharpening/sharp.ftl b/Resources/Locale/en-US/_CP14/sharpening/sharp.ftl index 26ffec99e2..a415c29a99 100644 --- a/Resources/Locale/en-US/_CP14/sharpening/sharp.ftl +++ b/Resources/Locale/en-US/_CP14/sharpening/sharp.ftl @@ -7,3 +7,5 @@ damage-weapon-1 = Looks completely intact damage-weapon-2 = Covered in a couple of scratches. damageable-weapon-3 = Looks worn. damageable-weapon-4 = It's about to break. + +sharpening-ready = Perfectly sharpened diff --git a/Resources/Locale/ru-RU/_CP14/_PROTO/entities/entities.ftl b/Resources/Locale/ru-RU/_CP14/_PROTO/entities/entities.ftl index 994da33555..d422315c52 100644 --- a/Resources/Locale/ru-RU/_CP14/_PROTO/entities/entities.ftl +++ b/Resources/Locale/ru-RU/_CP14/_PROTO/entities/entities.ftl @@ -27,12 +27,21 @@ ent-CP14BaseLock = стальной замок ent-CP14LockTavern = замок от таверны .desc = { ent-CP14BaseLock.desc } +ent-CP14BaseMagicRune = magic rune + .desc = manifestation of magical energy in the physical plane + +ent-CP14BaseMagicImpact = magic impact + .desc = manifestation of magical energy in the physical plane + ent-CP14ClothingCloakArmoredRed = бронированная красная накидка .desc = Огромные металлические наплечники дают дополнительную защиту от отрубания головы. ent-CP14ClothingCloakBlacksmithArpon = фартук кузнеца .desc = Свободные кожанные полоски, все еще фактически являющиеся одеждой. +ent-CP14ClothingCloakMaidArpon = фартук горничной + .desc = Чистота, порядок и послушание - вот основные черты хорошей горничной. + ent-CP14ClothingCloakFurcapeBlack = меховая накидка .desc = Брутальная, выделанная из шерсти, накидка на плечи. @@ -108,6 +117,21 @@ ent-CP14ClothingPantsAristocratic = штаны аристократа ent-CP14ClothingPantsLoincloth = набедренная повязка .desc = Свободные, ничего не мешает, да еще и выглядят экстремально брутально +ent-CP14ClothingDressBlack = черное платье + .desc = Просторная женское платье + +ent-CP14ClothingRingIceDagger = conductive ring + .desc = A standard mana-conductive ring that allows the user to summon ice daggers. + .suffix = Ice Dagger + +ent-CP14ClothingRingFlameCreation = conductive ring + .desc = A standard mana-conductive ring that allows the user to summon artificial flames. + .suffix = Flame creation + +ent-CP14ClothingRingCureWounds = conductive ring + .desc = A standard mana-conductive ring that allows the user to heal physical injuries. + .suffix = Cure Wounds + ent-CP14ClothingShirtCottonBlue = хлопковая синяя рубаха .desc = { ent-CP14ClothingShirtCottonBlue.desc } @@ -143,6 +167,9 @@ ent-CP14Mist = облако ent-CP14MistVitalExtract = { ent-CP14Mist } .desc = { ent-CP14Mist.desc } +ent-CP14AuraNodeBase = aura node + .desc = An energy node that affects the elemental energy in the surrounding space. + ent-CP14ExpeditionShipTargetPoint = пункт назначения экспедиционного судна .desc = Один из возможных пунктов прибытия корабля с игроками. @@ -150,6 +177,8 @@ ent-CP14SpawnPointAdventurer = авантюрист ent-CP14SpawnPointAlchemist = алхимик +ent-CP14SpawnPointCaptain = капитан + ent-CP14ConstrainedSpawnerBase = None .desc = lol @@ -267,6 +296,41 @@ ent-CP14WalletFilledTest = { ent-CP14Wallet } .desc = { ent-CP14Wallet.desc } .suffix = Filled test +ent-CP14CopperBar1 = медный слиток + .desc = Тяжелый, слегка зеленый кусок обработанной меди. + .suffix = 1 + +ent-CP14CopperBar5 = { ent-CP14CopperBar1 } + .desc = { ent-CP14CopperBar1.desc } + .suffix = 5 + +ent-CP14CopperBar10 = { ent-CP14CopperBar1 } + .desc = { ent-CP14CopperBar1.desc } + .suffix = 10 + +ent-CP14IronBar1 = iron bar + .desc = A heavy piece of refined iron + .suffix = 1 + +ent-CP14IronBar5 = { ent-CP14IronBar1 } + .desc = { ent-CP14IronBar1.desc } + .suffix = 5 + +ent-CP14IronBar10 = { ent-CP14IronBar1 } + .desc = { ent-CP14IronBar1.desc } + .suffix = 10 + +ent-CP14GoldBar1 = золотой слиток + .desc = Теплый на ощупь, мягкий кусок изысканного золота. + +ent-CP14GoldBar5 = { ent-CP14GoldBar1 } + .desc = { ent-CP14GoldBar1.desc } + .suffix = 5 + +ent-CP14GoldBar10 = { ent-CP14GoldBar1 } + .desc = { ent-CP14GoldBar1.desc } + .suffix = 10 + ent-CP14DirtBlock1 = блок земли .desc = Блок великолепной плодородной почвы. @@ -345,6 +409,36 @@ ent-CP14VialSmallLumiMushroom = { ent-CP14VialTiny } .desc = { ent-CP14VialTiny.desc } .suffix = Люмигриб +ent-CP14MeltingMoldBase = форма для выплавки + .desc = Деревянная доска для заливки металла в необходимые формы. + +ent-CP14MeltingMoldBlank = форма для выплавки заготовок + .desc = Пустая форма для литья металла. Вы можете вырезать в ней любую нужную форму на столе для резки деталей. + +ent-CP14MeltingMoldDaggers = форма для кинжала + .desc = { ent-CP14MeltingMoldBase.desc } + +ent-CP14MeltingMoldNails = форма для гвоздей + .desc = { ent-CP14MeltingMoldBase.desc } + +ent-CP14MeltingMoldPickaxe = форма для кирки + .desc = { ent-CP14MeltingMoldBase.desc } + +ent-CP14MeltingMoldShovel = форма для лопаты + .desc = { ent-CP14MeltingMoldBase.desc } + +ent-CP14MeltingMoldSickle = форма для серпа + .desc = { ent-CP14MeltingMoldBase.desc } + +ent-CP14MeltingMoldSword = форма для меча + .desc = { ent-CP14MeltingMoldBase.desc } + +ent-CP14MeltingMoldThrowableSpear = форма для метательного копья + .desc = { ent-CP14MeltingMoldBase.desc } + +ent-CP14MeltingMoldTwoHandedSword = форма для двуручного меча + .desc = { ent-CP14MeltingMoldBase.desc } + ent-CP14Wheat = сноп пшеницы .desc = У вас есть выбор: посадить семена обратно в землю, либо пустить их в муку. @@ -367,9 +461,9 @@ ent-CP14LumiMushroom = люмигриб .desc = Слабо светящийся гриб. Часто используется алхимиками как средство для концентрации растворов. ent-CP14EnergyCrystalBase = None - .desc = Обработанные кристаллы кварца являются прекрасными хранителями магической энергии. А специальные разъемы позволяют удобно вставлять их в магические устройства, превращая в энергетические батарейки. + .desc = Shards of one of the Khyber dragon, used to bind and control elemental energy. -ent-CP14EnergyCrystalSmall = маленький энергокристалл +ent-CP14EnergyCrystalSmall = small Khyber shard .desc = { ent-CP14EnergyCrystalBase.desc } .suffix = Full @@ -377,7 +471,7 @@ ent-CP14EnergyCrystalSmallEmpty = { ent-CP14EnergyCrystalSmall } .desc = { ent-CP14EnergyCrystalSmall.desc } .suffix = Empty -ent-CP14EnergyCrystalMedium = энергокристалл +ent-CP14EnergyCrystalMedium = Khyber shard .desc = { ent-CP14EnergyCrystalBase.desc } .suffix = Full @@ -385,9 +479,12 @@ ent-CP14EnergyCrystalMediumEmpty = { ent-CP14EnergyCrystalMedium } .desc = { ent-CP14EnergyCrystalMedium.desc } .suffix = Empty +ent-CP14AuraScanner = сканер ауры + .desc = Сканирует полярность потоков элементальной энергии в этом месте. + ent-CP14Bucket = ведро .desc = Старое скучное ведро - .suffix = CP14! + .suffix = CP14 ent-CP14OldLantern = Старая Лампа .desc = Пережиток прошлого техномагии. Большой, тяжелый, непрактичный. Таким приятно разве что бить по голове. @@ -443,28 +540,12 @@ ent-CP14BasePickaxe = кирка ent-CP14BaseShovel = лопата .desc = Орудие для вскапывания земли, рытья грядок или могил. -ent-CP14WeaponRevolverNavy = револьвер "Марин" - .desc = Увесистый капсюльный револьвер серии "Марин". В настоящее время револьверы серии "Марин" стоят баснословные деньги, и их могут позволить себе исключительно преуспевающие моряки и торговцы. - ent-CP14BaseLightCrossbow = легкий арбалет .desc = Небольшой, компактный арбалет, который удобно держать одной рукой. Не слишком меткий с обратной стороны. -ent-CP14WeaponRifleCrush = крушитель - .desc = Легкая, дорогая и непростая в обращении винтовка. - -ent-CP14WeaponRifleDurandal = дюрандаль - .desc = Винтовка среднего размера, дорогая и не очень удобная в использовании. - -ent-CP14WeaponRifleLebel = лебел - .desc = Тяжелая, дорогая и не очень удобная в использовании винтовка. - ent-CP14Crossbolt = арбалетный болт .desc = Стержень с заостренным концом. Без оперения, это вам не лук. -ent-CP14CartridgeBulletRifle = винтовочный патрон - -ent-CP14BulletRifle = винтовочная пуля - ent-CP14DungeonEntrance = спуск в подземелье .desc = Темные глубины подземного мира зовут вас. @@ -477,6 +558,22 @@ ent-CP14BaseSharpeningStoneStructure = стационарный точильны ent-CP14Mannequin = манекен .desc = Удобная подставка для одежды или доспехов. +ent-CP14StatueGob = статуя Гоба + .desc = Он прекрасен. + .suffix = Нормальная + +ent-CP14StatueGobVines = статуя Гоба + .desc = { ent-CP14StatueGob.desc } + .suffix = Нормальная. Заросшая + +ent-CP14StatueGobRuined = разрушенная статуя Гоба + .desc = { ent-CP14StatueGob.desc } + .suffix = Разрушенная + +ent-CP14StatueGobRuinedVines = разрушенная статуя Гоба + .desc = { ent-CP14StatueGob.desc } + .suffix = Разрушенная. Заросшая + ent-CP14WallmountWoodenBoards = доски .desc = Прибиты к стене. Зачем? не совсем ясно. @@ -738,6 +835,9 @@ ent-CP14WallmountBarShelfB = { ent-CP14WallmountBarShelfA } ent-CP14Workbench = верстак .desc = Стол для создания различного базового инструментария. +ent-CP14WorkbenchMeltingMolds = стол для резки форм + .desc = Специализированный стол, позволяющий вырезать формы для выплавки металла. + ent-CP14FrameWooden = каркас деревянной стены .desc = Деревянный каркас для деревянных стен любых видов. @@ -789,6 +889,9 @@ ent-CP14GatherableLumiMushroom = люмигрибы .desc = Слабо светящийся гриб. Часто используется алхимиками как средство для концентрации растворов. .suffix = Gatherable +ent-CP14ElementalReactor = elemental reactor + .desc = A work of art created by the dwarves of Zilagro and House Lyrandar, controlling the fire elemental and allowing it to produce vast amounts of energy. + ent-CP14ChestGeneric = сундук .desc = Chest. @@ -804,6 +907,15 @@ ent-CP14BrassChest = латунный сундук ent-CP14CrateCoffin = гроб .desc = Удобный и красивый гроб, чтобы с удобствами дождаться своего воскрешения. +ent-CP14BaseSmallCrate = { ent-CP14BaseCrate } + .desc = { ent-CP14BaseCrate.desc } + +ent-CP14LargeWoodenCrate = большой деревянный ящик + .desc = Ящик из дерева. + +ent-CP14SmallWoodenCrate = малый деревянный ящик + .desc = Ящик из дерева. + ent-CP14Cliff = обрыв .desc = Серьезные неровности природного ландшафта. .suffix = Прямой @@ -858,6 +970,14 @@ ent-CP14BaseWall = стена ent-CP14WallStonebrick = каменная кирпичная стена .desc = { ent-CP14BaseWall.desc } +ent-CP14WallStonebrickCrushedMedium = каменная кирпичная стена + .desc = { ent-CP14BaseCrushed.desc } + .suffix = CrushedMedium + +ent-CP14WallStonebrickCrushedLow = каменная кирпичная стена + .desc = { ent-CP14BaseCrushed.desc } + .suffix = CrushedLow + ent-CP14WallWhitebrick = белая кирпичная стена .desc = { ent-CP14BaseWall.desc } @@ -957,22 +1077,6 @@ ent-CP14CaveStoneWallGoldOre = { ent-CP14CaveStoneWall } ent-CP14CardboardWall = стена из картона .desc = Тонкая, непрочная стена из бумаги и картона. Пользуется популярностью в теплых странах. -ent-CP14StatueGob = статуя Гоба - .desc = Он прекрасен. - .suffix = Нормальная - -ent-CP14StatueGobVines = статуя Гоба - .desc = { ent-CP14StatueGob.desc } - .suffix = Нормальная. Заросшая - -ent-CP14StatueGobRuined = разрушенная статуя Гоба - .desc = { ent-CP14StatueGob.desc } - .suffix = Разрушенная - -ent-CP14StatueGobRuinedVines = разрушенная статуя Гоба - .desc = { ent-CP14StatueGob.desc } - .suffix = Разрушенная. Заросшая - ent-CPBaseSharpeningStoneStructure = стационарный точильный камень .desc = прочный, долговечный точильный камень, способный затачивать оружие без особого вреда для него. diff --git a/Resources/Locale/ru-RU/_CP14/sharpening/sharp.ftl b/Resources/Locale/ru-RU/_CP14/sharpening/sharp.ftl index 06f676ac28..7a6dfa0cc4 100644 --- a/Resources/Locale/ru-RU/_CP14/sharpening/sharp.ftl +++ b/Resources/Locale/ru-RU/_CP14/sharpening/sharp.ftl @@ -6,4 +6,6 @@ sharpening-examined-25 = Выглядит крайне сильно затупи damageable-weapon-1 = Выглядит полностью целым damageable-weapon-2 = Покрыт парой царапин damageable-weapon-3 = Выглядит изношенным -damageable-weapon-4 = Он вот-вот сломается \ No newline at end of file +damageable-weapon-4 = Он вот-вот сломается + +sharpening-ready = Идеально заточен \ No newline at end of file diff --git a/Resources/Prototypes/_CP14/Entities/Actions/Spells/cure_wounds.yml b/Resources/Prototypes/_CP14/Entities/Actions/Spells/cure_wounds.yml index 1e78ba9671..c06aa14b02 100644 --- a/Resources/Prototypes/_CP14/Entities/Actions/Spells/cure_wounds.yml +++ b/Resources/Prototypes/_CP14/Entities/Actions/Spells/cure_wounds.yml @@ -5,6 +5,10 @@ components: - type: CP14MagicEffect manaCost: 15 + telegraphyEffects: + - !type:CP14SpellSpawnEntity + spawns: + - CP14ImpactEffectCureWounds effects: - !type:CP14SpellSpawnEntity spawns: diff --git a/Resources/Prototypes/_CP14/Entities/Actions/Spells/shadow_step.yml b/Resources/Prototypes/_CP14/Entities/Actions/Spells/shadow_step.yml new file mode 100644 index 0000000000..f46741e0dc --- /dev/null +++ b/Resources/Prototypes/_CP14/Entities/Actions/Spells/shadow_step.yml @@ -0,0 +1,42 @@ +- type: entity + id: CP14ActionSpellShadowStep + name: Shadow step + description: A step through the gash of reality that allows you to cover a lot of distance quickly + components: + - type: CP14MagicEffect + manaCost: 40 + telegraphyEffects: + - !type:CP14SpellSpawnEntity + spawns: + - CP14ImpactEffectShadowStep + effects: + - !type:CP14SpellSpawnEntity + spawns: + - CP14ImpactEffectShadowStep + - !type:CP14SpellCasterTeleport + - type: CP14MagicEffectVerbalAspect + startSpeech: "Tenebrae, accipe me..." + endSpeech: "in alium locum" + - type: WorldTargetAction + useDelay: 15 + range: 10 + checkCanAccess: false + itemIconStyle: BigAction + sound: !type:SoundPathSpecifier + path: /Audio/Magic/rumble.ogg + icon: + sprite: _CP14/Effects/Magic/spells_icons.rsi + state: shadow_step + event: !type:CP14DelayedWorldTargetActionEvent + delay: 1 + +- type: entity + id: CP14ImpactEffectShadowStep + parent: CP14BaseMagicImpact + categories: [ HideSpawnMenu ] + components: + - type: Sprite + layers: + - state: particles_up + color: "#79b330" + shader: unshaded \ No newline at end of file diff --git a/Resources/Prototypes/_CP14/Entities/Clothing/Rings/ring.yml b/Resources/Prototypes/_CP14/Entities/Clothing/Rings/ring.yml index f37dcf637e..28ffdc5562 100644 --- a/Resources/Prototypes/_CP14/Entities/Clothing/Rings/ring.yml +++ b/Resources/Prototypes/_CP14/Entities/Clothing/Rings/ring.yml @@ -15,6 +15,7 @@ id: CP14ClothingRingIceDagger parent: CP14ClothingRingBase name: conductive ring + suffix: Ice Dagger description: A standard mana-conductive ring that allows the user to summon ice daggers. components: - type: Sprite @@ -33,6 +34,7 @@ parent: CP14ClothingRingBase name: conductive ring description: A standard mana-conductive ring that allows the user to summon artificial flames. + suffix: Flame creation components: - type: Sprite layers: @@ -50,6 +52,7 @@ parent: CP14ClothingRingBase name: conductive ring description: A standard mana-conductive ring that allows the user to heal physical injuries. + suffix: Cure Wounds components: - type: Sprite layers: diff --git a/Resources/Textures/_CP14/Effects/Magic/spells_icons.rsi/meta.json b/Resources/Textures/_CP14/Effects/Magic/spells_icons.rsi/meta.json index cfa3c9545b..07bc47f918 100644 --- a/Resources/Textures/_CP14/Effects/Magic/spells_icons.rsi/meta.json +++ b/Resources/Textures/_CP14/Effects/Magic/spells_icons.rsi/meta.json @@ -15,6 +15,9 @@ }, { "name": "ice_dagger" + }, + { + "name": "shadow_step" } ] } \ No newline at end of file diff --git a/Resources/Textures/_CP14/Effects/Magic/spells_icons.rsi/shadow_step.png b/Resources/Textures/_CP14/Effects/Magic/spells_icons.rsi/shadow_step.png new file mode 100644 index 0000000000000000000000000000000000000000..ace5af8acac114f9e16bc42e640bf0c051056f90 GIT binary patch literal 1469 zcmV;u1w#6XP)Px)cS%G+R9J=WR!xXxR~7!wIrrzi`suFf>FQ}sVkDU+WON~tjUuB47vi`u2`Ct1 zAdrFHxeswC2w6*Dc0q7uvXCh1A`1}_QBXu7I;g=6v@_j3UDef9_1?Sp92fnn>Fya7 z-RPn}c)UOEIp00^`_8?<1uk%b|1oI!aQ)ggoqh*kKlthE_MZfM=F?v%2hV*s;DKM| zQMpFLvS> z`t4YG^Ts=Lx&i=T0F)t{4DLzA#GJp!e6u=n3teu?$z>x~7X(0`2 zzveccI?{V9m%>o)PN!*5cIr;>zXPz<5~u-W0Ct{0I{r!ZK-NEc(Cn@b{pjZ@8zzei z4-NZp%xJPc27nw>j!s;a^54C4BbS6&NfhdmC2lmOM)NGIE|Th1$NVP%8#pC)cS`*X zfDC4eoRT%Eu?my4_r=ncy{?pU`{1DI_;47Ud?2YE33D#IBQJb)nyVGgP!KxfwD*h4 z{$XUx&t}b*O=o5{2e8@B{)`Bh0t^7WK|{6_7npUj=3Z^pYJ++uTMF5-Ryhm{7ZzTm z5tdvAmy_ms)9}=1PEMsa^y@FaU*CG;F~0hi5Whem1u!?WhUnM{ZN=|%!5)As8M$kw zE43|tJcr;&C+P4NswN|)8go`Wx;B7g0TIJYF|Nlqm^eiaC4o2AuLGXr4Dey}89ZCN&tm1@7$V}j2r@>|&mf2(fck+_B1^=A! z3yGXjQ{aLfu_Lm$NcQbdY+AG|Io~?(AjSLpiT%MsPKVe zaO8uKM9)43iosLxLe57CzL3a;i|kpPFh^mF%qRitC&h*tjjCF=KRD<^&0da9{vgcn zG0{GNYT1Y!0JJ?nKmXZRRmf>Uoh0OvkR&F`p1nG9D&&m797H5KPlfXq#HHXkIi?8_ z!C>8#^=NlG|HdQ3Ra7Z`Er`5FpdC8az=;4)YXAW7;rQfI4+KDnP&nqEW9|}B0N@r) z^Rt`@9~upD>&`x&*zALeKm;7si;t=5yjK)&_hQ7XZl3YNcZK;56HNd#r<31D;G883 z7&=YXce5&<*j&fEJ9~)EeaZ>z&Uk90eh0IvQD&_htE+ilSjtM1`sg!JLWmM8VVVe2 zO#~2;v`ek$ZFrsp1K0uZxMTiEa1!6&pP(CkN?9v4tFvlugV?w^)Ps6VqTZTGk^dCNDa`ORbTo3S55+5zqZW) zl)yf6yfW~Ep1DJRXByM6=+6r0X8;yBwFy0tz&C&NReR<0-#x=p&Fs~;zx?k`M$3(C z)+U(ZSWDU_U0xZ$nNtzn7wW&n^=sQiV2&Jl;0L@}j_7h{-G)V93+Eqr9J{~;{x9$k XKIwO3I7!H?00000NkvXXu0mjfYcIPe literal 0 HcmV?d00001