From b3619d28c6502f3423ae699956970dfdecaad499 Mon Sep 17 00:00:00 2001 From: ScarKy0 <106310278+ScarKy0@users.noreply.github.com> Date: Wed, 29 Apr 2026 23:16:39 +0200 Subject: [PATCH] Changeling Dna Sting (#43785) * init * fix objective * Somehow this locale got lost i guess * some more flavor idk * wording * sprites * be gone copy paste * we * review * rename * explosion * oops * Apply suggestion from @slarticodefast Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> --- .../Systems/ChangelingObjectiveSystem.cs | 5 ++- .../ChangelingBiodegradeAbilityComponent.cs | 3 +- .../Systems/ChangelingAbilitySystem.cs | 24 +++++++++++++ .../Systems/ChangelingDevourSystem.cs | 33 +++++++----------- .../Systems/SharedChangelingIdentitySystem.cs | 19 +++++++--- .../Locale/en-US/changeling/changeling.ftl | 8 +++-- .../Locale/en-US/store/changeling-catalog.ftl | 3 ++ Resources/Prototypes/Actions/changeling.yml | 24 ++++++++++++- .../Prototypes/Catalog/changeling_catalog.yml | 14 ++++++++ .../changeling2.rsi/extract_dna_off.png | Bin 0 -> 1302 bytes .../changeling2.rsi/extract_dna_on.png | Bin 0 -> 1441 bytes .../Actions/changeling2.rsi/meta.json | 10 +++++- 12 files changed, 111 insertions(+), 32 deletions(-) create mode 100644 Resources/Textures/Interface/Actions/changeling2.rsi/extract_dna_off.png create mode 100644 Resources/Textures/Interface/Actions/changeling2.rsi/extract_dna_on.png diff --git a/Content.Server/Objectives/Systems/ChangelingObjectiveSystem.cs b/Content.Server/Objectives/Systems/ChangelingObjectiveSystem.cs index 451e56426c..3b5b3c9006 100644 --- a/Content.Server/Objectives/Systems/ChangelingObjectiveSystem.cs +++ b/Content.Server/Objectives/Systems/ChangelingObjectiveSystem.cs @@ -20,7 +20,10 @@ public sealed class ChangelingObjectiveSystem : EntitySystem private void OnChangelingDevoured(ref ChangelingDevouredEvent args) { - if (!args.Unique) + // We check if the devour granted us Dna. + // We do this because we could already have gotten the identity by other means before, such as the Dna sting. + // Dna grant basically ensures this is the first time valid devour has happened on a target. + if (!args.GrantedDna) return; if (!_mind.TryGetObjectiveComp(args.Changeling, out var obj)) diff --git a/Content.Shared/Changeling/Components/ChangelingBiodegradeAbilityComponent.cs b/Content.Shared/Changeling/Components/ChangelingBiodegradeAbilityComponent.cs index c0c97d5852..7c43f0d970 100644 --- a/Content.Shared/Changeling/Components/ChangelingBiodegradeAbilityComponent.cs +++ b/Content.Shared/Changeling/Components/ChangelingBiodegradeAbilityComponent.cs @@ -6,8 +6,7 @@ using Robust.Shared.GameStates; namespace Content.Shared.Changeling.Components; /// -/// Allows the changeling to spawn dummy chameleon clothing items that will transform with them, -/// mimicing the equipment of the stored disguise. +/// Allows the changeling to vomit acid over restraints, setting themselves free and stunning whoever is pulling them. /// [RegisterComponent, NetworkedComponent] public sealed partial class ChangelingBiodegradeAbilityComponent : Component diff --git a/Content.Shared/Changeling/Systems/ChangelingAbilitySystem.cs b/Content.Shared/Changeling/Systems/ChangelingAbilitySystem.cs index d7fb5111d2..825903e34e 100644 --- a/Content.Shared/Changeling/Systems/ChangelingAbilitySystem.cs +++ b/Content.Shared/Changeling/Systems/ChangelingAbilitySystem.cs @@ -1,4 +1,6 @@ using System.Linq; +using Content.Shared.Actions; +using Content.Shared.Atmos.Rotting; using Content.Shared.Changeling.Components; using Content.Shared.Cuffs; using Content.Shared.Ensnaring; @@ -20,12 +22,15 @@ public sealed partial class ChangelingAbilitySystem : EntitySystem [Dependency] private readonly PullingSystem _pulling = default!; [Dependency] private readonly SharedStunSystem _stun = default!; [Dependency] private readonly SharedPuddleSystem _puddle = default!; + [Dependency] private readonly SharedChangelingIdentitySystem _changelingIdentity = default!; + [Dependency] private readonly ChangelingDevourSystem _changelingDevour = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnBiodegradeAction); + SubscribeLocalEvent(OnStingDna); } private void OnBiodegradeAction(Entity ent, ref ChangelingBiodegradeActionEvent args) @@ -66,4 +71,23 @@ public sealed partial class ChangelingAbilitySystem : EntitySystem if (ent.Comp.SpillSolution != null) _puddle.TrySpillAt(args.Performer, ent.Comp.SpillSolution, out _, false); } + + private void OnStingDna(Entity ent, ref ChangelingStingDnaEvent args) + { + if (args.Target == ent.Owner) + return; // Can't sting yourself. + + if (!_changelingDevour.CanDevour(ent.Owner, args.Target, checkDead: false, checkProtected: false)) + return; + + _popup.PopupClient(Loc.GetString("changeling-sting-success", ("target", Identity.Entity(args.Target, EntityManager))), args.Target, ent.Owner, PopupType.Medium); + _changelingIdentity.GrantIdentity(ent, args.Target); + + args.Handled = true; + } } + +/// +/// Action event for the Dna sting ability. Used to grand the changeling an identity without devouring somebody. +/// +public sealed partial class ChangelingStingDnaEvent : EntityTargetActionEvent; diff --git a/Content.Shared/Changeling/Systems/ChangelingDevourSystem.cs b/Content.Shared/Changeling/Systems/ChangelingDevourSystem.cs index 63aad8b4d6..adfcbc396a 100644 --- a/Content.Shared/Changeling/Systems/ChangelingDevourSystem.cs +++ b/Content.Shared/Changeling/Systems/ChangelingDevourSystem.cs @@ -1,4 +1,3 @@ -using System.Linq; using Content.Shared.Actions; using Content.Shared.Administration.Logs; using Content.Shared.Armor; @@ -29,7 +28,7 @@ public sealed class ChangelingDevourSystem : EntitySystem [Dependency] private readonly MobStateSystem _mobState = default!; [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] private readonly SharedChangelingIdentitySystem _changelingIdentitySystem = default!; + [Dependency] private readonly SharedChangelingIdentitySystem _changelingIdentity = default!; [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; [Dependency] private readonly SharedPopupSystem _popupSystem = default!; [Dependency] private readonly SharedStoreSystem _store = default!; @@ -175,7 +174,7 @@ public sealed class ChangelingDevourSystem : EntitySystem var willGrantDna = WillDevourGrantDna(ent.Owner, target); // Even if not unique, target is supposed to give us an identity if it is not currently in our identity list. - var becomesIdentity = !HasIdentity(ent.Owner, target); + var becomesIdentity = !_changelingIdentity.HasIdentity(ent.Owner, target); var ev = new ChangelingDevouredEvent(ent.Owner, target, becomesIdentity, uniqueIdentity, willGrantDna); RaiseLocalEvent(ent, ref ev, true); // We broadcast the event to allow relevant objectives to update. @@ -190,21 +189,10 @@ public sealed class ChangelingDevourSystem : EntitySystem _store.TryAddCurrency(ent.Comp.DevourDnaReward, ent.Owner, store); } - /// - /// Whether the given changeling has a valid identity of the given entity. - /// - public bool HasIdentity(Entity changeling, EntityUid devoured) - { - if (!Resolve(changeling, ref changeling.Comp, false)) - return false; - - return changeling.Comp.ConsumedIdentities.FirstOrDefault(data => data.Original == devoured && data.Identity != null) != null; - } - /// /// Can the given changeling devour the given victim? /// - public bool CanDevour(Entity changeling, EntityUid victim, bool showPopup = true) + public bool CanDevour(Entity changeling, EntityUid victim, bool checkDead = true, bool checkProtected = true, bool showPopup = true) { if (!Resolve(changeling, ref changeling.Comp)) return false; @@ -226,7 +214,7 @@ public sealed class ChangelingDevourSystem : EntitySystem return false; } - if (!_mobState.IsDead(victim)) + if (checkDead && !_mobState.IsDead(victim)) { if (showPopup) _popupSystem.PopupClient(Loc.GetString("changeling-devour-attempt-failed-not-dead"), changeling.Owner, changeling.Owner, PopupType.Medium); @@ -240,14 +228,14 @@ public sealed class ChangelingDevourSystem : EntitySystem return false; } - if (IsTargetProtected(victim, changeling!)) + if (checkProtected && IsTargetProtected(victim, changeling)) { if (showPopup) _popupSystem.PopupClient(Loc.GetString("changeling-devour-attempt-failed-protected"), changeling.Owner, changeling.Owner, PopupType.Medium); return false; } - if (!HasIdentity(changeling.Owner, victim) && !_changelingIdentitySystem.HasFreeDisguiseSlot(changeling.Owner)) + if (!_changelingIdentity.HasIdentity(changeling.Owner, victim) && !_changelingIdentity.HasFreeDisguiseSlot(changeling.Owner)) { if (showPopup) _popupSystem.PopupClient(Loc.GetString("changeling-devour-attempt-failed-no-space"), changeling.Owner, changeling.Owner, PopupType.Medium); @@ -263,8 +251,11 @@ public sealed class ChangelingDevourSystem : EntitySystem /// The Targeted entity /// Changelings Devour Component /// Is the target Protected from the attack - private bool IsTargetProtected(EntityUid target, Entity ent) + public bool IsTargetProtected(EntityUid target, Entity ent) { + if (!Resolve(ent, ref ent.Comp, false)) + return false; + var ev = new CoefficientQueryEvent(SlotFlags.OUTERCLOTHING); RaiseLocalEvent(target, ev); @@ -291,7 +282,7 @@ public sealed class ChangelingDevourSystem : EntitySystem if (!Resolve(ent, ref ent.Comp, false)) return false; - return !_changelingIdentitySystem.TryGetDataFromOriginal(ent, devoured, out _); + return !_changelingIdentity.TryGetDataFromOriginal(ent, devoured, out _); } /// @@ -306,7 +297,7 @@ public sealed class ChangelingDevourSystem : EntitySystem return false; // This target was never devoured, so obviously it can grant us DNA. - if (!_changelingIdentitySystem.TryGetDataFromOriginal(ent, devoured, out var data)) + if (!_changelingIdentity.TryGetDataFromOriginal(ent, devoured, out var data)) return true; // If the entity was Devoured, it means it already granted DNA, so we return False. diff --git a/Content.Shared/Changeling/Systems/SharedChangelingIdentitySystem.cs b/Content.Shared/Changeling/Systems/SharedChangelingIdentitySystem.cs index a6c1379a7a..7523533eb7 100644 --- a/Content.Shared/Changeling/Systems/SharedChangelingIdentitySystem.cs +++ b/Content.Shared/Changeling/Systems/SharedChangelingIdentitySystem.cs @@ -44,8 +44,7 @@ public abstract class SharedChangelingIdentitySystem : EntitySystem { if (args.ObtainedIdentity) { - CloneToPausedMap(ent, args.Devoured); - AddDevouredReference(ent, args.Devoured); + GrantIdentity(ent, args.Devoured); } if (args.GrantedDna && TryGetDataFromOriginal(ent.AsNullable(), args.Devoured, out var data)) @@ -67,7 +66,7 @@ public abstract class SharedChangelingIdentitySystem : EntitySystem private void OnMapInit(Entity ent, ref MapInitEvent args) { // Make a backup of our current identity so we can transform back. - CloneToPausedMap(ent, ent.Owner); + GrantIdentity(ent, ent.Owner); if (!TryGetDataFromOriginal(ent.AsNullable(), ent, out var data)) return; @@ -197,7 +196,7 @@ public abstract class SharedChangelingIdentitySystem : EntitySystem /// /// The Changeling. /// The target to clone. - public EntityUid? CloneToPausedMap(Entity ent, EntityUid target) + public EntityUid? GrantIdentity(Entity ent, EntityUid target) { var clone = CloneToPausedMap(ent.Comp.IdentityCloningSettings, target); @@ -213,6 +212,7 @@ public abstract class SharedChangelingIdentitySystem : EntitySystem } UpdateIdentityData(newIdentity, clone.Value, target); + AddDevouredReference(ent, target); HandlePvsOverride(ent, clone.Value); Dirty(ent); @@ -319,6 +319,17 @@ public abstract class SharedChangelingIdentitySystem : EntitySystem return ent.Comp.ConsumedIdentities.Count(data => data.Identity != null) < ent.Comp.MaxStoredDisguises; } + /// + /// Whether the given changeling has a valid identity of the given entity. + /// + public bool HasIdentity(Entity changeling, EntityUid devoured) + { + if (!Resolve(changeling, ref changeling.Comp, false)) + return false; + + return changeling.Comp.ConsumedIdentities.FirstOrDefault(data => data.Original == devoured && data.Identity != null) != null; + } + /// /// Create a paused map for storing devoured identities as a clone of the player. /// diff --git a/Resources/Locale/en-US/changeling/changeling.ftl b/Resources/Locale/en-US/changeling/changeling.ftl index 4a851d6fa7..52daca4783 100644 --- a/Resources/Locale/en-US/changeling/changeling.ftl +++ b/Resources/Locale/en-US/changeling/changeling.ftl @@ -5,6 +5,7 @@ roles-antag-changeling-objective = A intelligent predator that assumes the ident # devour changeling-devour-attempt-failed-cannot-devour = We cannot devour this! changeling-devour-attempt-failed-already-devoured = We already consumed this body! +changeling-devour-attempt-failed-devoured-recently = This body is too mangled to devour! changeling-devour-attempt-failed-not-dead = This body yet lives! We cannot consume it alive! changeling-devour-attempt-failed-rotting = This corpse has only rotted biomass. changeling-devour-attempt-failed-protected = This victim's biomass is protected by armor! @@ -25,8 +26,8 @@ changeling-transform-attempt-others = { CAPITALIZE(POSS-ADJ($user)) } bones snap changeling-transform-bui-select-entity = {$entity} changeling-transform-bui-drop-identity-menu = Drop a devoured identity from your memory. changeling-transform-bui-drop-identity-entity = Drop {$entity} -changeling-transform-bui-drop-identity-entity-popup = You dropped {$entity} from your memory. -changeling-transform-bui-drop-identity-cannot-drop = You cannot drop your current identity. +changeling-transform-bui-drop-identity-entity-popup = We dropped {$entity} from our memory. +changeling-transform-bui-drop-identity-cannot-drop = We cannot drop our current identity. # voice mimicry changeling-voice-mimic-window-title = Voice Mimicry @@ -41,5 +42,8 @@ changeling-flesh-clothing-alert-desc = Whether clothing transformation is enable changeling-biodegrade-used-popup = {CAPITALIZE(THE($user))} vomits acid over {POSS-ADJ($user)} {$restraint}! changeling-biodegrade-used-popup-self = We vomit acid over our {$restraint}! +# stings +changeling-sting-success = We silently sting {THE($target)}! + # other changeling-paused-map-name = Changeling identity storage map diff --git a/Resources/Locale/en-US/store/changeling-catalog.ftl b/Resources/Locale/en-US/store/changeling-catalog.ftl index 893f2a84af..134ad32b08 100644 --- a/Resources/Locale/en-US/store/changeling-catalog.ftl +++ b/Resources/Locale/en-US/store/changeling-catalog.ftl @@ -9,3 +9,6 @@ changeling-catalog-voice-mimic-desc = Change your vocal coords at will to imitat changeling-catalog-biodegrade-name = Biodegrade changeling-catalog-biodegrade-desc = You learn to utilize acid glands within your body to vomit acid over constraints, setting yourself free. + +changeling-catalog-sting-dna-name = Extract DNA +changeling-catalog-sting-dna-desc = Learn to utilize your stinger to absorb the identity of unsuspecting victims. Does not grant DNA to your store or objective progress. diff --git a/Resources/Prototypes/Actions/changeling.yml b/Resources/Prototypes/Actions/changeling.yml index c3cd19e5ec..d7fb2b5610 100644 --- a/Resources/Prototypes/Actions/changeling.yml +++ b/Resources/Prototypes/Actions/changeling.yml @@ -29,7 +29,6 @@ - type: Action useDelay: 60 # TODO: Short cooldown but chemical cost raiseOnAction: true - itemIconStyle: BigAction checkCanInteract: false icon: sprite: Interface/Actions/changeling2.rsi @@ -46,6 +45,7 @@ - type: Action icon: { sprite : Interface/Actions/changeling.rsi, state: "devour" } iconOn: { sprite : Interface/Actions/changeling.rsi, state: "devour_on" } + itemIconStyle: BigAction priority: 1 - type: TargetAction - type: EntityTargetAction @@ -80,3 +80,25 @@ state: mimicry - type: InstantAction event: !type:VoiceMaskSetNameEvent + +- type: entity + parent: BaseAction + id: ActionChangelingStingDna + name: Extract DNA + description: Sneakily absorb the identity of unsuspecting victims. Does not grant DNA to your store or objective progress. + components: + - type: Action + icon: { sprite : Interface/Actions/changeling2.rsi, state: "extract_dna_off" } + iconOn: { sprite : Interface/Actions/changeling2.rsi, state: "extract_dna_on" } + itemIconStyle: BigAction + priority: 1 + useDelay: 90 # TODO: Chemical cost, maybe this could be a DoAfter action? + raiseOnUser: true + - type: TargetAction + - type: EntityTargetAction + canTargetSelf: false + whitelist: + components: + - MobState + - HumanoidProfile + event: !type:ChangelingStingDnaEvent diff --git a/Resources/Prototypes/Catalog/changeling_catalog.yml b/Resources/Prototypes/Catalog/changeling_catalog.yml index c15fbde62c..f03ddeb7b1 100644 --- a/Resources/Prototypes/Catalog/changeling_catalog.yml +++ b/Resources/Prototypes/Catalog/changeling_catalog.yml @@ -56,3 +56,17 @@ - !type:ListingLimitedStockCondition stock: 1 productAction: ActionChangelingBiodegrade + +- type: listing + id: ChangelingStingDna + name: changeling-catalog-sting-dna-name + description: changeling-catalog-sting-dna-desc + applyToMob: true + cost: + ChangelingDNA: 10 + categories: + - ChangelingStoreStealth + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + productAction: ActionChangelingStingDna diff --git a/Resources/Textures/Interface/Actions/changeling2.rsi/extract_dna_off.png b/Resources/Textures/Interface/Actions/changeling2.rsi/extract_dna_off.png new file mode 100644 index 0000000000000000000000000000000000000000..593e0ddcc4db1e27ba26005f846b1a5289c51c2e GIT binary patch literal 1302 zcmV+x1?l>UP)Px(&`Cr=R9J<*mtSa8R~*MbH{J{}rW$eCYy+|WS=Z>S^I@%GVWzc+_=h3LDtnkx z8B%=N!x)Y}1$`J}4+AM;nR}2T10RM%hO_NMS7*m?t+tV%UA^O`)yy_aV@Bs~d-rgA zPHvjqBtzyG4!ODK_wW49@BF^^C@i8o95&Nx1_1Azhhx3H3T2=>95%)C->+=}z_-#X z=abLU_*Qy(s`c>EjX?$ALQB25DiGxTufJ7PyRm-lFRI;czzXEbiKAvp*H{$@lF~IP z=biJ&=j-t}o7Qg!AOH-E4zYKwTh6Zll5Am8Sx?8-j2Wo3bW^&jGS&fX0DC+fioc&c*GHst8 zIYdg=@T#sn1A#!m`fY3H=I>TbY~KF1oX_0;sc05D2Zwq3e4gVQYlw`DC;)0>a5b*L zT518tVx)Af;OYT-y3W(o)((Ku`#k^;7k^8w-i}(opYCwjJl5N*s8%{OP_uhmX!Qco zXp~SWMAMQilv=$VBI^LITE8F2?n~$3FzLAk$1!=UPa1085TtT8Bb`s&yoOhGISzqp zw;R!OT#$RN%Rx`qdHEa)g#ehm)mJp|^xQ&TW-qkVo33&@-cm%P(VQTPtz3-s+=A2* zT`?ylaqdeQTDNOYUJ&nmc&cOu3L&rBM5IomviTqYo`&5_EceJl1Y}_4KyZkr$JPo@6m>K#lPv)0z zIt%LC?FyeNSOl|_bc*5Oml63aDp+Kp*aEz&i>J@$0T?$7V6g`7KADv)R|?|T*^P=J zin7!x7&i>6-EJ<&V%hHji`lZLpcq6K6g==?aT`|7W{PG&pxW)08BhUUef`ax6*(DL z$_0W46tY}kZ&FU!zVi@~i|4F9aP{OFGqA?be0)?!U#tg+G&i-iV}=i4h7YjmXUWQydg+58qMPZM_rrUuD1}yVob3|KD6t>$i%2V06eT zLVY^hieDxd1QwDg$G0__E0h^hv$M2r+s0=%t~n~y>^scN%#7p#$Tp$o4MF*?7#Eyv zIY?@1iu;KKwSGUUby=t+^=OFH)KpoKJ8^;dYbFA3vr)kw9F6l#Z=i<=t-F zFxX#J#V0@amleo=!RI?0NgD={UvG1KV+~-{f?~gt1$;jAWRhCHzu@)C4)HN-hm%er zS%9=*SOEYu`u*t1WRAeNVQ@JXlQ&whUtr0T6_-@V?JeSj$vK}7uiMSQ)ReV_A_zMg zgRAqLh!05tq4(~N76wL#a%3;v?az^Iud6fH%+JgJ)614|et1~<7xr|=qJ<4khX4Qo M07*qoM6N<$g05z74gdfE literal 0 HcmV?d00001 diff --git a/Resources/Textures/Interface/Actions/changeling2.rsi/extract_dna_on.png b/Resources/Textures/Interface/Actions/changeling2.rsi/extract_dna_on.png new file mode 100644 index 0000000000000000000000000000000000000000..93b1726bba75e144bf4c1013ca18289da65923e3 GIT binary patch literal 1441 zcmV;S1z!4zP)Px)TS-JgR9JgC>AFStFzBA7dtC%x03|rpabv#4K6F zkj*Uqi7^`gA~>V_cTs~sLSl$n;vdU4%-DuOBoneQK!~XmvCAvC&QfZv0rc z^;($UBHRP<( ze52jz^RcmP3jhwFZ)}L2MHXW`4+yfEDWQy$l@ZlZtj!I{UamFnQ;k)AR#Bm9#x>}I z@?<1w#fkkBilP}`nTvPgkzx3r-=D^mEZQi2y%>N^%D(`Fr3ivfqdw`%xQA~VJ|QG~ zY3UtIQv`6bW*Y!gLKy(wsY!nM>yD{x;+&S=L3Y0J4$55IL7~I#Ry%z@$}JYIjC&}` z&Eashi*xGQFxq{N`@*xo&a zWG_}pOjF>h7Z-o?ICJ|a0Bjoz;{tW>QSo9PR+zJJu78*(^9vl@P(jP+r~n|t0ZRphHu0GXd2BUc>X5A^EcsFbB8mb)8{kVlGAP{Oayr{f}=P;HD1dhG!qHgPFZEnq zsH;}R7f2v@(gAO}^cmt|km5zW^eNX^}u80aZj&*fNv_O4q-U+}^7VoPJ8X*7>(Tg+KV)T`T+Kr1k* zMJFpha2ZY8;;+s^wgp%vktg#D08A*_*%1Lo{+TtZ+)`*u<)|A;O^h! zTyHwA8VsZ&8-?wJXhb^)BgYQWd}0#*)W&-DW)I;+y}@T;0K~m*rv!Q0Pw87bGR;dv z?aV`?eYRD*W(_pYF1r?ZrzVa0B7mdNzHH+jQNGs431b3;b2vbnkPIZG&@T}RTU??e#kiC z_az3l_8WbA5*j&nC@%Nxk?H(!G)8OPZbE?o_xygGb~}>xSSTj+XoyfCkkw=V z{l%y?sRgyfw;&ud-|yDC-N=t0)9d%6KZ1mlm6gWZZbDJmRZ_yy-+Qw<@-jHHy@s%& z(DKI}4sNIbw6h>2KFJ(58*(s+({49?UM0e5PY>NpbIfD`!iu6f08nGMBL{;?0uzeD zRgcGb(L&+_mNZ%YkqXJVMUOCJ%x1%CvCtO?Xm3N^iA2