From bd9a49dd7ea428e724c4e32440f2a6ca21410e76 Mon Sep 17 00:00:00 2001 From: Letter N <24603524+LetterN@users.noreply.github.com> Date: Wed, 14 Jan 2026 02:38:48 +0800 Subject: [PATCH] pixel w/z stuff (#7477) ## About The Pull Request byond shenanigans ## Why It's Good For The Game ## Changelog :cl: add: you can now point items inside your inventory tweak: update fulton /:cl: --- code/__DEFINES/_planes+layers.dm | 3 + code/__HELPERS/unsorted.dm | 6 +- code/datums/progressbar.dm | 10 +- code/game/atoms/_atom.dm | 7 +- .../effects/temporary_visuals/point.dm | 17 +- code/modules/mining/tools/fulton.dm | 316 ++++++++++-------- code/modules/mob/living/living.dm | 17 +- code/modules/mob/mob.dm | 107 +++++- code/modules/mob/observer/dead/dead.dm | 8 +- icons/effects/effects.dmi | Bin 446134 -> 413935 bytes sound/items/fulext_deploy.wav | Bin 96908 -> 0 bytes sound/items/fultext_launch.wav | Bin 87442 -> 0 bytes 12 files changed, 313 insertions(+), 178 deletions(-) delete mode 100644 sound/items/fulext_deploy.wav delete mode 100644 sound/items/fultext_launch.wav diff --git a/code/__DEFINES/_planes+layers.dm b/code/__DEFINES/_planes+layers.dm index 885fa0a270e..b897a46c5f4 100644 --- a/code/__DEFINES/_planes+layers.dm +++ b/code/__DEFINES/_planes+layers.dm @@ -346,6 +346,9 @@ */ #define OBSERVER_PLANE 30 +/// Just above ghosts +#define POINT_PLANE 31 + /** *! -- Augmented Plane *? Augmented-reality stuff. diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 011efc5bf1c..eed1884f234 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -1190,12 +1190,12 @@ var/list/WALLITEMS = list( /// Returns an x and y value require to reverse the transformations made to center an oversized icon /atom/proc/get_oversized_icon_offsets() - if (pixel_x == 0 && pixel_y == 0) + if (!base_pixel_x && !base_pixel_y && !base_pixel_w && !base_pixel_z) return list("x" = 0, "y" = 0) var/list/icon_dimensions = get_icon_dimensions(icon) var/icon_width = icon_dimensions["width"] var/icon_height = icon_dimensions["height"] return list( - "x" = icon_width > 32 && pixel_x != 0 ? (icon_width - 32) * 0.5 : 0, - "y" = icon_height > 32 && pixel_y != 0 ? (icon_height - 32) * 0.5 : 0, + "x" = icon_width > world.icon_size && (base_pixel_x || base_pixel_w) ? (icon_width - world.icon_size) * 0.5 : 0, + "y" = icon_height > world.icon_size && (base_pixel_y || base_pixel_z) ? (icon_height - world.icon_size) * 0.5 : 0, ) diff --git a/code/datums/progressbar.dm b/code/datums/progressbar.dm index 8b0e81746ef..7a017f7e074 100644 --- a/code/datums/progressbar.dm +++ b/code/datums/progressbar.dm @@ -79,9 +79,9 @@ continue progress_bar.listindex-- - progress_bar.bar.pixel_y = 32 + offset_y + (PROGRESSBAR_HEIGHT * (progress_bar.listindex - 1)) - var/dist_to_travel = 32 + offset_y + (PROGRESSBAR_HEIGHT * (progress_bar.listindex - 1)) - PROGRESSBAR_HEIGHT - animate(progress_bar.bar, pixel_y = dist_to_travel, time = PROGRESSBAR_ANIMATION_TIME, easing = SINE_EASING) + progress_bar.bar.pixel_z = world.icon_size + offset_y + (PROGRESSBAR_HEIGHT * (progress_bar.listindex - 1)) + var/dist_to_travel = world.icon_size + offset_y + (PROGRESSBAR_HEIGHT * (progress_bar.listindex - 1)) - PROGRESSBAR_HEIGHT + animate(progress_bar.bar, pixel_z = dist_to_travel, time = PROGRESSBAR_ANIMATION_TIME, easing = SINE_EASING) LAZYREMOVEASSOC(user.progressbars, bar_loc, src) user = null @@ -126,10 +126,10 @@ ///Adds a smoothly-appearing progress bar image to the player's screen. /datum/progressbar/proc/add_prog_bar_image_to_client() - bar.pixel_y = 0 + bar.pixel_z = 0 bar.alpha = 0 user_client.images += bar - animate(bar, pixel_y = 32 + offset_y + (PROGRESSBAR_HEIGHT * (listindex - 1)), alpha = 255, time = PROGRESSBAR_ANIMATION_TIME, easing = SINE_EASING) + animate(bar, pixel_z = world.icon_size + offset_y + (PROGRESSBAR_HEIGHT * (listindex - 1)), alpha = 255, time = PROGRESSBAR_ANIMATION_TIME, easing = SINE_EASING) ///Updates the progress bar image visually. /datum/progressbar/proc/update(progress) diff --git a/code/game/atoms/_atom.dm b/code/game/atoms/_atom.dm index 43b14bfafde..df6c62c88c3 100644 --- a/code/game/atoms/_atom.dm +++ b/code/game/atoms/_atom.dm @@ -193,7 +193,12 @@ /// and permanent adjustment. /// * Do **not** use this when calculating auto-centering; if we are a wall-mount it doesn't make sense to do so, as an example. var/base_pixel_y = 0 - /// expected icon width + ///Default pixel w shifting for the atom's icon. + var/base_pixel_w = 0 + ///Default pixel z shifting for the atom's icon. + var/base_pixel_z = 0 + + /// expected icon width; centering offsets will be calculated from this and our base pixel x. /// * this **should**, but often is not necessarily, always set to the icon's actual file dimensions. /// if an admin edits an icon this is often not set and we can't really assume alignment either way, so. /// * this is not necessarily able to be used for centering unless we are actually centered in the icon. diff --git a/code/game/objects/effects/temporary_visuals/point.dm b/code/game/objects/effects/temporary_visuals/point.dm index 1b16a3a5da8..a819fb60371 100644 --- a/code/game/objects/effects/temporary_visuals/point.dm +++ b/code/game/objects/effects/temporary_visuals/point.dm @@ -1,9 +1,16 @@ /obj/effect/temp_visual/point - name = "arrow" - desc = "It's an arrow hanging in mid-air. There may be a wizard about." + name = "pointer" icon = 'icons/mob/screen1.dmi' icon_state = "arrow" - plane = ABOVE_PLANE - anchored = 1 + plane = POINT_PLANE + duration = (2.5 SECONDS) + anchored = TRUE mouse_opacity = 0 - duration = 2 SECONDS + +/obj/effect/temp_visual/point/Initialize(mapload, set_invis = 0) + . = ..() + var/atom/old_loc = loc + abstract_move(get_turf(src)) + pixel_x = old_loc.pixel_x + pixel_y = old_loc.pixel_y + set_invisibility(set_invis) diff --git a/code/modules/mining/tools/fulton.dm b/code/modules/mining/tools/fulton.dm index b2c3a787de1..8acfa3de0d4 100644 --- a/code/modules/mining/tools/fulton.dm +++ b/code/modules/mining/tools/fulton.dm @@ -1,4 +1,4 @@ -var/global/list/total_extraction_beacons = list() +GLOBAL_LIST_EMPTY(total_extraction_beacons) // todo: this should be included in the air-support module being added later, not just a mining exclusive @@ -8,12 +8,19 @@ var/global/list/total_extraction_beacons = list() icon = 'icons/obj/fulton.dmi' icon_state = "extraction_pack" w_class = WEIGHT_CLASS_NORMAL - var/obj/structure/extraction_point/beacon + /// Beacon weakref + var/datum/weakref/beacon_ref + /// List of networks var/list/beacon_networks = list("station") + /// Number of uses left var/uses_left = 3 - var/can_use_indoors = FALSE - var/safe_for_living_creatures = 1 + /// Can be used indoors + var/can_use_indoors + /// Can be used on living creatures + var/safe_for_living_creatures = TRUE var/stuntime = 15 + /// Maximum force that can be used to extract + var/max_force_fulton = MOVE_FORCE_STRONG /obj/item/extraction_pack/wormhole name = "wormhole fulton extraction pack" @@ -27,143 +34,171 @@ var/global/list/total_extraction_beacons = list() icon = 'icons/obj/storage.dmi' icon_state = "phoroncrate" -/obj/item/extraction_pack/examine(mob/user, dist) +/obj/item/extraction_pack/examine() . = ..() - . +="It has [uses_left] use\s remaining." + . += SPAN_INFOPLAIN("It has [uses_left] use\s remaining.") + + var/obj/structure/extraction_point/beacon = beacon_ref?.resolve() + + if(isnull(beacon)) + beacon_ref = null + . += SPAN_INFOPLAIN("It is not linked to a beacon.") + return + + . += SPAN_INFOPLAIN("It is linked to [beacon.name].") /obj/item/extraction_pack/attack_self(mob/user, datum/event_args/actor/actor) . = ..() if(.) return var/list/possible_beacons = list() - for(var/B in global.total_extraction_beacons) - var/obj/structure/extraction_point/EP = B - if(EP.beacon_network in beacon_networks) - possible_beacons += EP + for(var/datum/weakref/point_ref as anything in GLOB.total_extraction_beacons) + var/obj/structure/extraction_point/extraction_point = point_ref.resolve() + if(isnull(extraction_point)) + GLOB.total_extraction_beacons.Remove(point_ref) + continue + if(extraction_point.beacon_network in beacon_networks) + possible_beacons += extraction_point - if(!possible_beacons.len) - to_chat(user, "There are no extraction beacons in existence!") + if(!length(possible_beacons)) + balloon_alert(user, "no beacons") return - else - var/A - - A = input("Select a beacon to connect to", "Balloon Extraction Pack", A) as null|anything in possible_beacons - - if(!A) - return - beacon = A - to_chat(user, "You link the extraction pack to the beacon system.") - -/obj/item/extraction_pack/afterattack(atom/movable/target, mob/user, clickchain_flags, list/params) - if(!beacon) - to_chat(user, "[src] is not linked to a beacon, and cannot be used.") + var/chosen_beacon = tgui_input_list(user, "Beacon to connect to", "Balloon Extraction Pack", sortNames(possible_beacons)) + if(isnull(chosen_beacon)) return - if(!can_use_indoors) - var/turf/T = get_turf(target) - if(T && !T.outdoors) - to_chat(user, "[src] can only be used on things that are outdoors!") - return + + beacon_ref = WEAKREF(chosen_beacon) + balloon_alert(user, "linked!") + +/obj/item/extraction_pack/afterattack(atom/interacting_with, mob/user, clickchain_flags, list/params) if(!(clickchain_flags & CLICKCHAIN_HAS_PROXIMITY)) return - if(!istype(target)) + if(!ismovable(interacting_with)) + return + if(!isturf(interacting_with.loc)) // no extracting stuff inside other stuff + return + var/atom/movable/thing = interacting_with + if(thing.anchored) return - else - if(!safe_for_living_creatures && check_for_living_mobs(target)) - to_chat(user, "[src] is not safe for use with living creatures, they wouldn't survive the trip back!") - return - if(!isturf(target.loc)) // no extracting stuff inside other stuff - return - if(target.anchored) - return - to_chat(user, "You start attaching the pack to [target]...") - if(do_after(user,50,target=target)) - to_chat(user, "You attach the pack to [target] and activate it.") - /* No components, sorry. No convienence for you! - if(loc == user && istype(user.back, /obj/item/storage/backpack)) - var/obj/item/storage/backpack/B = user.back - B.SendSignal(COMSIG_TRY_STORAGE_INSERT, src, user, FALSE, FALSE) - */ - uses_left-- - if(uses_left <= 0) - user.temporarily_remove_from_inventory(src, INV_OP_FORCE | INV_OP_SHOULD_NOT_INTERCEPT | INV_OP_SILENT) - var/mutable_appearance/balloon - var/mutable_appearance/balloon2 - var/mutable_appearance/balloon3 - if(isliving(target)) - var/mob/living/M = target - M.adjust_stunned(20 * 10) // Keep them from moving during the duration of the extraction - if(M.buckled) - M.buckled.unbuckle_mob(M) - else - target.anchored = TRUE - target.density = FALSE - var/obj/effect/extraction_holder/holder_obj = new(target.loc) - holder_obj.appearance = /obj/item/extraction_holdercrate - target.forceMove(holder_obj) - balloon2 = mutable_appearance('icons/obj/fulton_balloon.dmi', "fulton_expand") - balloon2.pixel_y = 18 - balloon2.appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM - holder_obj.add_overlay(balloon2) - sleep(4) - balloon = mutable_appearance('icons/obj/fulton_balloon.dmi', "fulton_balloon") - balloon.pixel_y = 18 - balloon.appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM - holder_obj.cut_overlay(balloon2) - holder_obj.add_overlay(balloon) - playsound(holder_obj.loc, 'sound/items/fulext_deploy.wav', 50, 1, -3) - animate(holder_obj, pixel_z = 10, time = 20) - sleep(20) - animate(holder_obj, pixel_z = 15, time = 10) - sleep(10) - animate(holder_obj, pixel_z = 10, time = 10) - sleep(10) - animate(holder_obj, pixel_z = 15, time = 10) - sleep(10) - animate(holder_obj, pixel_z = 10, time = 10) - sleep(10) - playsound(holder_obj.loc, 'sound/items/fultext_launch.wav', 50, 1, -3) - animate(holder_obj, pixel_z = 1000, time = 30) - if(ishuman(target)) - var/mob/living/carbon/L = target - L.adjust_stunned(20 * stuntime) - L.drowsyness = 0 - sleep(30) - var/list/flooring_near_beacon = list() - for(var/turf/T in range(1, beacon)) - if(T.density) - continue - flooring_near_beacon += T - if(!length(flooring_near_beacon)) - holder_obj.forceMove(get_turf(beacon)) - else - holder_obj.forceMove(pick(flooring_near_beacon)) - animate(holder_obj, pixel_z = 10, time = 50) - sleep(50) - animate(holder_obj, pixel_z = 15, time = 10) - sleep(10) - animate(holder_obj, pixel_z = 10, time = 10) - sleep(10) - balloon3 = mutable_appearance('icons/obj/fulton_balloon.dmi', "fulton_retract") - balloon3.pixel_y = 10 - balloon3.appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM - holder_obj.cut_overlay(balloon) - holder_obj.add_overlay(balloon3) - sleep(4) - holder_obj.cut_overlay(balloon3) - target.anchored = FALSE // An item has to be unanchored to be extracted in the first place. - target.density = initial(target.density) - animate(holder_obj, pixel_z = 0, time = 5) - sleep(5) - target.forceMove(holder_obj.loc) - qdel(holder_obj) - if(uses_left <= 0) - qdel(src) + var/obj/structure/extraction_point/beacon = beacon_ref?.resolve() + if(isnull(beacon)) + balloon_alert(user, "not linked!") + beacon_ref = null + return + var/turf/turf = get_turf(thing) + if(!can_use_indoors) + if(!turf?.outdoors) + balloon_alert(user, "not outdoors!") + return + if(!safe_for_living_creatures && check_for_living_mobs(thing)) + to_chat(user, SPAN_WARNING("[src] is not safe for use with living creatures, they wouldn't survive the trip back!")) + balloon_alert(user, "not safe!") + return + if(thing.move_resist > max_force_fulton) + balloon_alert(user, "too heavy!") + return + + balloon_alert_to_viewers("attaching...") + playsound(thing, 'sound/items/zip.ogg', vol = 50, vary = TRUE) + if(isliving(thing)) + var/mob/living/creature = thing + if(creature.mind) + to_chat(thing, SPAN_USERDANGER("You are being extracted! Stand still to proceed.")) + + if(!do_after(user, 5 SECONDS, target = thing)) + return + + balloon_alert_to_viewers("extracting!") + // if(loc == user && ishuman(user)) + // var/mob/living/carbon/human/human_user = user + // human_user.back?.atom_storage?.attempt_insert(src, user, force = STORAGE_SOFT_LOCKED) + uses_left-- + + if(uses_left <= 0) + user.transfer_item_to_loc(src, thing, INV_OP_FORCE | INV_OP_SHOULD_NOT_INTERCEPT | INV_OP_SILENT) + + if(isliving(thing)) + var/mob/living/creature = thing + creature.set_paralyzed(32 SECONDS) // Keep them from moving during the duration of the extraction + if(creature.buckled) + creature.buckled.unbuckle_mob(creature, TRUE) // Unbuckle them to prevent anchoring problems + else + thing.set_anchored(TRUE) + thing.set_density(FALSE) + + var/obj/effect/extraction_holder/holder_obj = new(get_turf(thing)) + holder_obj.appearance = thing.appearance + thing.forceMove(holder_obj) + var/mutable_appearance/balloon2 = mutable_appearance('icons/obj/fulton_balloon.dmi', "fulton_expand", layer = ABOVE_MOB_LAYER+0.1, appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM | KEEP_APART) + balloon2.pixel_z = 10 + holder_obj.add_overlay(balloon2) + addtimer(CALLBACK(src, PROC_REF(create_balloon), thing, user, holder_obj, balloon2), 0.4 SECONDS) + +/obj/item/extraction_pack/proc/create_balloon(atom/movable/thing, mob/living/user, obj/effect/extraction_holder/holder_obj, mutable_appearance/balloon2) + var/mutable_appearance/balloon = mutable_appearance('icons/obj/fulton_balloon.dmi', "fulton_balloon", layer = ABOVE_MOB_LAYER+0.1, appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM | KEEP_APART) + balloon.pixel_z = 10 + holder_obj.cut_overlay(balloon2) + holder_obj.add_overlay(balloon) + playsound(holder_obj.loc, 'sound/items/fultext_deploy.ogg', vol = 50, vary = TRUE, extrarange = -3) + + animate(holder_obj, pixel_z = 10, time = 2 SECONDS, flags = ANIMATION_RELATIVE) + animate(pixel_z = 5, time = 1 SECONDS, flags = ANIMATION_RELATIVE) + animate(pixel_z = -5, time = 1 SECONDS, flags = ANIMATION_RELATIVE) + animate(pixel_z = 5, time = 1 SECONDS, flags = ANIMATION_RELATIVE) + animate(pixel_z = -5, time = 1 SECONDS, flags = ANIMATION_RELATIVE) + + sleep(6 SECONDS) + + playsound(holder_obj.loc, 'sound/items/fultext_launch.ogg', vol = 50, vary = TRUE, extrarange = -3) + animate(holder_obj, pixel_z = 1000, time = 3 SECONDS, flags = ANIMATION_RELATIVE) + + if(ishuman(thing)) + var/mob/living/carbon/human/creature = thing + creature.set_unconscious(0) + creature.drowsyness = 0 + creature.set_sleeping(0) + + sleep(3 SECONDS) + + var/turf/flooring_near_beacon = list() + var/turf/beacon_turf = get_turf(beacon_ref.resolve()) + for(var/turf/floor as anything in RANGE_TURFS(1, beacon_turf)) + if(!is_blocked_turf(floor)) + flooring_near_beacon += floor + + if(!length(flooring_near_beacon)) + flooring_near_beacon += beacon_turf + + holder_obj.forceMove(pick(flooring_near_beacon)) + + animate(holder_obj, pixel_z = -990, time = 5 SECONDS, flags = ANIMATION_RELATIVE) + animate(pixel_z = 5, time = 1 SECONDS, flags = ANIMATION_RELATIVE) + animate(pixel_z = -5, time = 1 SECONDS, flags = ANIMATION_RELATIVE) + + sleep(7 SECONDS) + + var/mutable_appearance/balloon3 = mutable_appearance('icons/obj/fulton_balloon.dmi', "fulton_retract", layer = ABOVE_MOB_LAYER+0.1, appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM | KEEP_APART) + balloon3.pixel_z = 10 + holder_obj.cut_overlay(balloon) + holder_obj.add_overlay(balloon3) + + sleep(0.4 SECONDS) + + holder_obj.cut_overlay(balloon3) + thing.set_anchored(FALSE) // An item has to be unanchored to be extracted in the first place. + thing.set_density(initial(thing.density)) + animate(holder_obj, pixel_z = -10, time = 0.5 SECONDS, flags = ANIMATION_RELATIVE) + sleep(0.5 SECONDS) + thing.forceMove(holder_obj.loc) + qdel(holder_obj) + if(uses_left <= 0) + qdel(src) /obj/item/fulton_core - name = "extraction beacon signaller" - desc = "Emits a signal which fulton recovery devices can lock onto. Activate in hand to create a beacon." + name = "extraction beacon assembly kit" + desc = "When built, emits a signal which fulton recovery devices can lock onto. Activate in hand to unfold into a beacon." icon = 'icons/obj/stock_parts.dmi' icon_state = "subspace_amplifier" @@ -171,9 +206,12 @@ var/global/list/total_extraction_beacons = list() . = ..() if(.) return - if(do_after(user,15,target = user) && !QDELETED(src)) - new /obj/structure/extraction_point(get_turf(user)) - qdel(src) + if(!do_after(user, 1.5 SECONDS, target = user) || QDELETED(src)) + return + + new /obj/structure/extraction_point(get_turf(user)) + playsound(src, 'sound/items/Deconstruct.ogg', vol = 50, vary = TRUE, extrarange = -5) + qdel(src) /obj/structure/extraction_point name = "fulton recovery beacon" @@ -187,11 +225,16 @@ var/global/list/total_extraction_beacons = list() /obj/structure/extraction_point/Initialize(mapload) . = ..() name += " ([rand(100,999)]) ([get_area_name(src, TRUE)])" - global.total_extraction_beacons += src + GLOB.total_extraction_beacons.Add(WEAKREF(src)) -/obj/structure/extraction_point/Destroy() - global.total_extraction_beacons -= src - ..() +/obj/structure/extraction_point/attack_hand(mob/living/user, datum/event_args/actor/clickchain/e_args) + . = ..() + balloon_alert_to_viewers("undeploying...") + if(!do_after(user, 1.5 SECONDS, src)) + return + new /obj/item/fulton_core(drop_location()) + playsound(src, 'sound/items/Deconstruct.ogg', vol = 50, vary = TRUE, extrarange = -5) + qdel(src) /obj/effect/extraction_holder name = "extraction holder" @@ -202,17 +245,16 @@ var/global/list/total_extraction_beacons = list() if(isliving(A)) var/mob/living/L = A if(L.stat != DEAD) - return 1 + return TRUE for(var/thing in A.get_all_contents()) if(isliving(A)) var/mob/living/L = A - update_icon() if(L.stat != DEAD) - return 1 - return 0 + return TRUE + return FALSE -/obj/effect/extraction_holder/singularity_pull() +/obj/effect/extraction_holder/singularity_act() return -/obj/effect/extraction_holder/singularity_pull() +/obj/effect/extraction_holder/singularity_pull(atom/singularity, current_size) return diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 7657ecaf396..888eea065cb 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -97,16 +97,19 @@ TYPE_REGISTER_SPATIAL_GRID(/mob/living, SSspatial_grids.living) start_pulling(AM) //mob verbs are faster than object verbs. See above. -/mob/living/pointed(atom/A as mob|obj|turf in view()) +/mob/living/pointed(atom/A as mob|obj|turf in view(client.view, src)) if(src.stat || src.restrained()) - return 0 + return FALSE if(src.status_flags & STATUS_FAKEDEATH) - return 0 - if(!..()) - return 0 + return FALSE - usr.visible_message("[src] points to [A]") - return 1 + return ..() + +/mob/living/_pointed(atom/pointing_at) + if(!..()) + return FALSE + log_emote("POINTED --> at [pointing_at] ([COORD(pointing_at)]).", src) + visible_message(SPAN_INFOPLAIN("[SPAN_NAME("[src]")] points at [pointing_at]."), SPAN_NOTICE("You point at [pointing_at].")) /*one proc, four uses swapping: if it's 1, the mobs are trying to switch, if 0, non-passive is pushing passive diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 516c880133a..2e856460455 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -391,6 +391,8 @@ to_chat(src, "
[result.Join("\n")]") SEND_SIGNAL(src, COMSIG_MOB_EXAMINATE, A) +#define POINT_TIME (2.5 SECONDS) + /** * Point at an atom * @@ -408,27 +410,100 @@ set name = "Point To" set category = VERB_CATEGORY_OBJECT - if(!src || !isturf(src.loc) || !(A in view(14, src))) - return 0 - if(istype(A, /obj/effect/temp_visual/point)) - return 0 + return FALSE - var/tile = get_turf(A) - if (!tile) - return 0 + // i am queued sometimes + _pointed(A) - var/obj/P = new /obj/effect/temp_visual/point(tile) - P.invisibility = invisibility - P.plane = ABOVE_PLANE - P.layer = FLY_LAYER - P.pixel_x = A.pixel_x + world.icon_size * (x - A.x) - P.pixel_y = A.pixel_y + world.icon_size * (y - A.y) - animate(P, pixel_x = A.pixel_x, pixel_y = A.pixel_y, time = 0.5 SECONDS, easing = QUAD_EASING) - face_atom(A) - log_emote("POINTED --> at [A] ([COORD(A)]).", src) +/mob/proc/_pointed(atom/pointing_at) + if(client) //Clientless mobs can just go ahead and point + if(!(pointing_at in view(client.view, src))) + return FALSE + // since we dont have the datum emote for pointing, too lazy to implement! (it sets the cooldown) + // if(iscarbon(src)) // special interactions for carbons + // var/mob/living/carbon/our_carbon = src + // if(our_carbon.get_usable_hand_count() <= 0 || our_carbon.handcuffed /* || HAS_TRAIT(src, TRAIT_HANDS_BLOCKED)*/) + // if(!TIMER_COOLDOWN_CHECK(src, "point_verb_emote_cooldown")) + // //cooldown handled in the emote. + // our_carbon.emote("point [pointing_at]") + // else + // to_chat(src, SPAN_WARNING("You need to wait before pointing again!")) + // return FALSE + + point_at(pointing_at, TRUE) return 1 +/** + * Point at an atom + * + * Intended to enable and standardise the pointing animation for all atoms + * + * Not intended as a replacement for the mob verb + */ +/atom/movable/proc/point_at(atom/pointed_atom, intentional = FALSE) + if(!isturf(loc)) + return FALSE + + if (pointed_atom in src) + create_point_bubble(pointed_atom) + return FALSE + + var/turf/tile = get_turf(pointed_atom) + if (!tile) + return FALSE + + var/turf/our_tile = get_turf(src) + var/obj/visual = new /obj/effect/temp_visual/point(our_tile, invisibility) + + // SEND_SIGNAL(src, COMSIG_MOVABLE_POINTED, pointed_atom, visual, intentional) + + animate(visual, pixel_x = (tile.x - our_tile.x) * world.icon_size + pointed_atom.pixel_x, pixel_y = (tile.y - our_tile.y) * world.icon_size + pointed_atom.pixel_y, time = 1.7, easing = EASE_OUT) + return TRUE + +/mob/point_at(atom/pointed_atom, intentional = FALSE) + . = ..() + if(.) + face_atom(pointed_atom) + +/atom/movable/proc/create_point_bubble(atom/pointed_atom) + var/mutable_appearance/thought_bubble = mutable_appearance( + 'icons/effects/effects.dmi', + "thought_bubble", + plane = POINT_PLANE, + appearance_flags = KEEP_APART, + ) + + var/mutable_appearance/pointed_atom_appearance = new(pointed_atom.appearance) + pointed_atom_appearance.blend_mode = BLEND_INSET_OVERLAY + pointed_atom_appearance.plane = FLOAT_PLANE + pointed_atom_appearance.layer = FLOAT_LAYER + pointed_atom_appearance.pixel_x = 0 + pointed_atom_appearance.pixel_y = 0 + thought_bubble.overlays += pointed_atom_appearance + // pointed_atom_appearance.remove_filter(HOVER_OUTLINE_FILTER) + + thought_bubble.pixel_w = 16 + thought_bubble.pixel_z = 32 + thought_bubble.alpha = 200 + + var/mutable_appearance/point_visual = mutable_appearance( + 'icons/mob/screen1.dmi', + "arrow" + ) + + thought_bubble.overlays += point_visual + + add_overlay(thought_bubble) + // LAZYADD(update_overlays_on_z, thought_bubble) + addtimer(CALLBACK(src, PROC_REF(clear_point_bubble), thought_bubble), POINT_TIME) + +/atom/movable/proc/clear_point_bubble(mutable_appearance/thought_bubble) + // LAZYREMOVE(update_overlays_on_z, thought_bubble) + cut_overlay(thought_bubble) + +#undef POINT_TIME + /mob/verb/set_self_relative_layer() set name = "Set relative layer" set desc = "Set your relative layer to other mobs on the same layer as yourself" diff --git a/code/modules/mob/observer/dead/dead.dm b/code/modules/mob/observer/dead/dead.dm index a25340b1e72..8361a8584fd 100644 --- a/code/modules/mob/observer/dead/dead.dm +++ b/code/modules/mob/observer/dead/dead.dm @@ -595,11 +595,11 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp W.add_hiddenprint(src) W.visible_message("Invisible fingers crudely paint something in blood on [T]...") -/mob/observer/dead/pointed(atom/A as mob|obj|turf in view()) +/mob/observer/dead/_pointed(atom/pointed_at) if(!..()) - return 0 - usr.visible_message("[src] points to [A]") - return 1 + return FALSE + + visible_message(SPAN_DEADSAY("[src] points to [pointed_at].")) /mob/observer/dead/proc/manifest(mob/user) is_manifest = TRUE diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index 6a7bac7c7333516350e26e1a2287edba8c394aec..af888b6092d609f3663a834a2844e51c7c3174af 100644 GIT binary patch literal 413935 zcmZU4byQSu80JtSprF!?N_TfFAWBPjNO$Kj1B!HaH%NDPOLxZ*k^_u@%uvHDzdgHq z&hGwkzjN!m_q*r5^}NsfhO4P4yu_uz1pojq6+eB{001yepEl{|&z{cY7ck^L9klvs z>Uw;%bhmJ`b@8xub^-u=va0kZV+w^|NiwOvo-|C?MmJ-0Ul}h~sEGHnrtRZ3?Tx65 zcTAXCuTh*M#Nc!gWg`+e_5xZiPwQx%PiIPj9
FtPOtG&UpVFNH$XrG^a?kS-A>Ed_ucW0m)Fg99>r18#`V;lds`2?@; zI;|{vtQ|L63}CC)_Ko(rRcoDU+N~M2U7sP9Fg!upamJgiX19@p!#XbWl2Fm;33-`Y2iY1+! zNpVj5O)lG)Zm N>Q_EItOfyRDjEF;=Ey=$6J+JB0erlK_e*5Rm4w#@!f +doNS;CNw^3MXUlCM@gdPQBd8lm(PM&dCT#Z9wzLR!w6(2ntgV@YIKpBp zcSJg-aHJhSo4{69A`>l^5tS8B-&+ukOi8{!1+q=>*gMFJ>qkvXM~lU{Y6s}fi1s~T z8FQ@Z0-T{5Y2Jqi2m0VeraQIe23&wwQ1|-A^s2j?@qKLjk^}xy>t)n-+c$(ntsCSK zL_o7@?Oin;dnD!`0xavAUEr&I>GG!P%ah}3_)pHiZlO8}GnF&(_e|#R;;H>n>%18l z!nQ5mjvM}P@9{vLmBX?#nXUY`>$2*(T8%x}v+c?Lewe73n6tOGjt~_7x$$<@|5M#@ zU3ar%4b@u4iH}Jo=bo}8<;k}wfy~^yh(%kNLbd0fv*XW4#>Yo4&Hz-)I%)y}0^Xm? z?_@xI5!Z>Vc3D59g^wj)d_lsI;yFn?fhVYt#qVyD*OhSL+ee*TWl7+g^7|H1avq~b z)Xr^aGXi7^a?ef?P&-3i4ujN<=9^LXK Y0*dge{FFUPE?$DqE zU~KWXoqZq#pysL}O_%XFBM_dqR~T%tRS0a|8&VH>NXH2TS@qv}D={Pa2vwvSFN2a1 zXDHapq4NraS%BH&48{g9 zGutpnw>){Q@v)AjE`n3B0|fBSREJPA@?OxJplWPH`;hX SP4Xg zU7I2QnM0)NFVh6YQcq0NpjqAZ4RKQAVLn|_5+zm$CCWHJu6janaj&qh$S(IE2o zwzl0F?_WoB0c8*`fOB}1!g6xWTGfHdnH)x&nb0+SckqV_ipKsr%7mqwqze D#l`-Sk&&@y-m0hG&I1?~_Z;@$o34Kv<*p!M2EZhO%1-Nj z>I;A*8vaH?Jr!|_rG#~R3TjXejT@7_Q6wBN;dqb2xW6~LzZVmng6XcG1|h08z0a >xbLsYXp$;>7Mfu!I*n(r&Zw;Kztq9ab1>h^J6+C0GkrQasRRh zXz%NL8;?ZgNZ30y#1s+L*a0QYqw8tU_^@rSCrrD#ErB3Yq+#77I`c9)6UZVST(LNc z%*6yes|EbESXyg3)&mZ#J;p2|>!MLy4xC#}Z1w=-0rxSBd#cAy=d;UG Nt-geP^v&wsco~}`o2oW(kT*hTg$u#dLoIuFU+AH_&xJZ zFwo5LX^%C?0J8S@s5;+%*4GC6b6aU-E!k*3{gd1vl@IQa=08x4a4gq3Z5SR1mFmA^ zz@wYma_rDwAHuMQ UQ* z=sTXvq%59of-df*+V!tr_9|t%Y;q}6ylRg^Ur>c`y{R83L(z?07cGsnCRZx5dUgSi zu*ulI-)*9Dfr8~UFBBFZxtt%63j)fpP{p1GP7LsiIYh(KO3?^}04Gcuu(uF4FPKz> zg@$$oX2_~tvwr>vk$o+Tlb82G&lfL$x?ACuyl`MtFTRcWGWPQ## Lk2oYfhB#B8gpnYLx(S6RYCTuHU_Vm;5OIQkE z2DiOQ-H1vFOnA%dr8=rl{Wzu^B0Ew9if Z5;_VN0xUfh!yu*i}KE+Fq+3UzCZCBUWijM-^MvAe?_TU-{cMUbSfyxtEW3kyfg zX4q+ITj+-6ZCgmVOjpNN;YcS46^HRKF^9HPaT1B HbCDk&!(VXrBp}B4WmkbMsye>s=hwc7sIk z{lKD1A@_vB5{QXl3SRdZ0PP%XZ3wWV9 UfyRN@cg8`pu-lGoAL1?c_yHRKH+_{!~Y+l!ho-X+_ zB;+xV8GvS>jjxO^95C+Zd_NsjtDvXd;FSqrf_q;D89{z69zbdqNh&ASt@&CSD(jLg zD+lzKjvFIX4tvMUoIpaA?D~|Ck1Y_%vSm_7YOYR;{YgMK`-;E!>TrFhS`8P+3d-^2 z#2S^rDYX&EA*&GqT0-2T1kAR@%`WPLH<*bBZMAw8$^gSYczbW^OO@Nsi(Petl jl7!mRdb_F|V)4QD@R7+|p+r2AeXlNTfo6Jr%IP_F}(_ z0yWy`39XbMurdI;+WCpQ%8%3ne=suIv>hDBo=>#B8?Q2?^C#uUI6<(r!o^pwa5m{E zVig%QiPIKDv9NfG?2k8%pOr%Np9A8@i*5C!pM!^}aR!a0NY3GiZlL@|$Qk{hu`o$k z{QW87=JG3T$-a}{R9Tf$>+uyXE~Z7o%w(r2>(uCDur$7q>LCsEJ-P^L mdTvJPn zcWqZ!S5HI3{JY *$EY7?*C++Cy!0%r{K^ncb7O!(~ zcGD`SN5{g1Uk=9iVI6;ah$UNjCB%%5W)aT!zTq0n@Ff7aU4=_WzBfc+s#n@1dHyR8 zppxI27eEectsbj{>{0#+vgsh)EKnPMuIm8AGQ4cFM2?!{GCYriHcR)(U5qK8+Y$nl zoy;T=ZpwS##F%`TgVbF?4bw4a-^B-AnP+AzbJ;XHoys_>7bcH|?eCt%ki-z8=0LI# zYT0&n)3v*tH7sYUl*EnhO#}V#+T75mc7cEJom&Xm C%E=?`e#398JP*Yks8!X$7s082$!q1n<8$HYD4-*^)xr3|%gFG1 z-IsabHF5E}9*CZ?aiF`W=k?U??r!js7A9K92UwUcY{__YnBUn_uUg@pA}E0xO I)qx;RsDJs`{kRvnb}UzCPFZxvr>p= zeD?{9Pc>k-BoebUw&IwHw1h4Gh`vw`Qfbjs2$ 4+JM zF`@-Ld_K04RO?hf(b*3SfgZ9$(Tt&b0SY8<&KZYSt{>Xp&!kDHi`4 nB8?)5l` z4d`MR@{jB_qLVjvsUsMs4*4-G2Gn4p$Jj?1OGqisI48q<5S3?c)_S0?eoDnY9qd DKQ76V>e&LIm@BH2MW_DUMp%*Aq{6|q zoq2Q8IJ}=NeRuo5y^cF=@gMv=GkQm@^jkTui*4w F3uhHDlZ0cX#aHBKi zu NExyC!K-N`&q(N=E8uFH_{1$c V5e}Em+C~;#o)F#(hqnn z1I$#)IM;mo@0s88Y{@q^mW>9F?d^SXmBRu2xdczClh?Ncwwpz$1Vaj{ePpwK3kG}Z zR x9e89Gcwhhbm$e07Wj^UvROwmhaL)g)(s6*ZF6 z^b6hXaSJ_@%I)Sp;WKw4d)fMl)wBbi)ER5t ak>Osgj`s6A@pj|vs$YQ1_D$~1qUJ1s2Uw`rH#%GvxZO$?u%B2t?~lY;&h z?@MjY8e%y1XBVnrvcTqS73P2>8uV(j_yVn#(04H5z!+S~G4!2(3`{y~XwgiqYALDe z5J}`B0r;J-Cv;fqtk*;;Ps!*C!a)YslM)7>;g8c#>9E+UAL= E{(s~;@e^zkoaL Ri1Ccn=~RGU6s5W69eyveh;h8Y+@mzFuQ z umn- zz%3qcvK38ZgSaI2zS3y?D(L*9Q9Uc4A%R g?Vd9z9 z@^Fi)!;3r4adaYal!2wn*kgpsx @x5j#_r42=&=XAgn$KzSZn7EwXOztNkI zxd06J^y6u}oRf&xJGqBB(aj|DVA8q$O>>-zXK400Z{_UQ`C43JH#o!_rbqv^%jMCd z`!gH >c}w%{XKs{mt7W54oZC%$~*l? SUEys!&5)ZLF?^y3AfMj(ts6P5LBN=3C=6`^>+7>^R_Qhsjn2Q&Xw6> zqpJ{=8%=%yW17_jpB0C#?nQ^KChLVY*+SRxrQs9vLf7>i)fVehe~Yb7Yp)0l&?J^^ z(%1&KCuprSZdG-2PtXz80xLWn&?=E33U)OJn%R DJfp_MOelIT)%f{<`~-Rq@gG{E@pQNivbV7)e&_&K_zCS%4M(bv6-4OAh1z2um_ zy=1(wJoZ2JfAdt7koFqPZs}Uqya=baX>Omhj{Y@0XDLE@L=4k!bb!+_=WQP4 eILJT}C7g4D|IgO!V|dKUDw|&NtfTn_=F{eQUL% z-j!7!hy=3#y;t+6_zFF29&Mr&obn_LTlV(yYCdhZUY01%g&Q_$l%(;gq=@v5j9Hs3 zPmS{bn)smEYm+F#XbfgCGRVx#Ofovb{=xG$t0rz=tR8=*4ic|53Z0Vm)6_|tGaZiM zJ!5LuFhtVdeOwQvp!IyWF^$V_UogEQ-k 9p^E5BEY!YNZ#Z`zArzn%1D`3h0ckU>GHX(OAgl;wm*Dw|7eRr_-4W7mE#>@r z-%cbgm3=7L501NQ_TDYz4SQqNBeswcg$rUG2Wu|j{9X9kjsDy6^YWLT9R pojq+gNU%F8M*}M((+BmG2GeN$gq4m|D8ntzu8$p1u@HwvR*C9!+ zfM@8q=5HH>rKC*awA;K-O#*K%FHRQO<{0>zl>*RLd$TeAKGS)%#*~B|Fx3?3lLBxv z-`tkT`gR+qki(-=IZXzl2wtzRt @WTq|oY?M|q)bGs@EHOFB zz6Pf+HjM4D9eXS5O%0xY0oVLMlPL?_eBg+~kdSkE>bgh+{^omTj#@_%G#>g^H(GWb zKAGgq3DGGGHZk#ve=Tf#e#YPYsu9CMWpLEw7OJKTRiyxbbQWq`tDuY|rnK%lMCN)y zP+qD7Keb>U@JlcM<#{zGnsG*Np|_b4RH-F&=%yEQ4ra_lP(}C6XZKBW=C*xy_cXmf zm6V?1RUmd=1Cey<0Y(SREMtjw4T$(1_T&rkn%3r&3hN@UqAmiw>a;T(tVedU<@c8K z8+^S3tqua^_0K*5pLmGa>WE$8m#$({g%!N9dqsi7!HNJE(rjsh@(HE;yDUuQ3V$sr z68!J*t~FH6JU==a65U~b1);8{2yNz&3;be=AxjaF)`347K*fO7M^5M O(0>D~kJIY{Ow<~REAtg1{#DMh6moMbD>Q$SL9iZ_O(FGPOqJq~B@$BB* zsV%PNb?(f?g^X8jn43!dqMwx&g1IARgD@|?`pQAl34 wqvaR})vX=)E$Tmf8`Yp%ld z@SLw(egwaC2&bX?vFRI B8-) zU@Zz`@z7rFb9D#LZ{B=H@cD}5(GR-1N|A$?fej;dvT3BKuPnLD@kL)1%pi%EF$sV4 zJY3ROA&}B(>b9X)jqs))XLSLNj%OFa3=xuMb!8BlNJD&0eqBzjrACf8%$!4BILsPvTxYB=<%+er| z&GAPuW#{FnPo<>!U}IYM;O4r^?QWNe0bP?P!0K{Eh~3^Hph5YX(q*{HQi)2}f!}F$ zt$mpqQH+*m8y4#J+6XHZT)`b{J*)NUT5R%4tP1K*amQ12p?p{8Lbh;ctG|3G=Rpid zG5>OK`O7+Gp$8=~dl{s{xcj` Nq0c_epF`E^z`&HGqa*+ELOT3Z^W^u0ppfaLDg4%(kaUW zlaIwprLoG_#H5U>p=|EA4@Eel=sqOqcb8(Ax<6*wQ|NWW3MX7deVB{cqYrL0G+v)u zi{vcY`jyX{Cs8PMyk;z`@HgN1GE2?oD$zQShR0HKJ`j74u8k!~fTPni9nK!1Q1UfE zMHW%$#s~$sZ+sNS@=9d|kb#*s0EoX*uca6EqmuyaS=>en m#{iIDVmP)T;X4u ze^{oR!xAo}FNpYhyRNUV&!aVZ?dowOKHJbcxk}m@ef&~vocg-5NZhB){(BIrjflJ2 z5h*!KX1orn>)!pH+*kFMKgRH!^7`mq{5ZRE9kW|B z4OK}W=-a6^_R+&=e*ECT20W8o{)eG9O{BYMa3gLS)A{yD6dD;3mg1=uH7%`2^-> z3Z3qrX}5U6!BVa39F)Y5Rlg(v^3*f+DA0)7oiuz-#*Eqe@f9P9x1w1jCkMy%If&in zM5CyXZ7TnOOTUrWPhS2r|MFvHzH`&I`6z{ZMI`;;sO)ViIlmINssGXu4{OYB^USg# zbZOJd1=3&q#``n76A?SPT7b6uqNhau@408Bqt;LCk?K>u!17u96H$Fxw1!%IjD6tx zn>2n!F8#_lc~H9!VRe-Q3=B y&w1idPWL!v-wt;5sLV2hj2Pd8%(mmjbuZ?#8;`NQ2W`0utWV^K*Y;{`G`~_*vuG zrpkAD9s#JUZc7@yNL`ShiK|&VvH5J=&+L(TCGRc!((^$yX6AQ=F9m({F1vvl^itet zsf6PMOq=;%Z72@wAan_dD%a}-FL`?k@pF6= 2MGmq-Xy#-c}rURh7U@0^zBtpJqaw{ z<)}1*SvD)iEhA#WDcEHaNg3uq9&9=_Ccr|xk}y`ei9GSVqgK_jK;ap^&ch))?yvsg zjM>zTxzk?FRNA{IN7Sd4U$VlY+w4-WYJ$@!yH=3WTf$CoE^(#NNP%uq@54IUCE7Mz zZexP(WrQ46L~TNUex$ *V z+s5aom~;40!;$%SJ7al7Q-%?4TYOe6_(wk+gdCB%j|>_VZBq9`T!Ha{H#?yUb sL|3zS;~!%q{=8*;zWp})g7EJ2cYO>DK#$ud |{ti&LP(YZTQjU_4fXS z;=hRq83Q~PNVkuxdZX_KlYBDquA*7pLO9*z= QlWe9YkE-Txu;O(7zx7xy16uiuyKGO5z28f9S0Wz?ozez=N5N!YPz3h!#lT$7 zu6+cJwsP@$UEVD_Zx1$fQ?~H>)3}3t zBS2P9%h;sV_4)^f%HikDSnF`73|ZP}OjoKm>YbsWAHM&sj}kB(zVA_Wli^Hc2vu MA;xgy$CqD)gbIBfiTuIBDC*G_$$ zbo!SgZ!`m0j%)b}B3Q={GhFH4^(u~CMr^I006!WF g4<4XM&BHcItZ)dPZ`8^(v1y&b3LeTsRg10Qb>Sx6Loxu2TSSCtzI zw@YUmX(Bku1ISf_^f+f1Br}FO@*o#8glEl31G1g5rW)@mSiF7X$7MJr#cmje-sU)r zygz=fb_;4S#d-}Jf2X@R5LzuJlcoW4Nxju42#6bRkAM@Xna%-DnifzWui|hkE%3>l z4Gr3c$ bDOURvOt11$g@r;zgJ6-Vu3E5%CY;z@! z;jI}`fllGU9ZGgG{P~M`ILi{6Bp(z5;rxAkZ0LJ)`;|VX4h^=;?pi;t0u;TL$TIyR zq!5)?>%Et9BY(8hBR!F^gdZdhuX3<6@^S? k6!E5 za8xt|WqU+e=j9?`_lliVh$h8?(VM=~un`-O0EpOF89TYko1{iRWej}&b%dgr5Rj@( ziNRRmA3Hslg8-$CkdP;y>IK F&flhmw6P6-Rhrm18Cp{B zcBsrS!wK 28)z1wlF% zNnz=RW!eA!zUMyo(|x$-%=x@$=6YSTi2ykayh^C0KY*K3mJ4g`D!p8?)@eQnk fw7J6m1k>~b_c*W5d<7nw^g;> yNm!+KASl3|H_z)J{T_RA?MzE7s(S`jnAFcy3A8Nh&-MY!z?j4tM!DrN3+PD{CU zpR+^k0l;ud({30`vnA6G8_uBQiO4&r!&ELG4%`jWHyb@4P=kL|T_mw;wOgx(cMqDr z!=2xn(OxrmXg9ncg)`!COn^vjWsUWx@qjC1qySR!ZLSac7z}@KI`MvO>K0BPp{IGC zy
?;_3^WKjNeuI92cs2 zda0wFniw0ada9b3nzFh|!8%ytW4cTkob-N~{nn>8^V3XI7|ZkhfsY}{rcTV2C$nb2 z(NVm+T3ln2>^gUKT+OCzAXrqF4JunJhf9bv{+J1?aauo71}UmP`TYoE zjyYqGaTC4nXcGe^S0pX4M-~w#|J# zp$pO>=j%nF$OH6H9Q+YiA($!FvUJkbIN68j01njRnsmwH*09mI?S?47%+)1Wu{{XQ zUDM9p36qhx2cbAYNP*rVbyhJ9l7L?6j zsnu&dX^n`|5Oap-$8^CjQy@ zy5!TA99fLpG`Z3zKU;Q)_Y!Jy2 zqXgdCWjwQtApf(VzgT31)*CbQspom>fI>>n@Y!v7dtDcFTXIq@sSDfmbTwE{Z2~J@ zZt|E51ED!%EE_Jd HkEJ3hQ zR!ld0&iJ258`H>lF1vrPI|V9h45Sk^)QYgc?=W+siiCL#g$%y~^etQEsI=wzt{$j3 z81+4@Gn|uugW^Y@pZo3< -m81zpNZxNEJjrN8Ec6dJjfUjOjqBS)c-YKts?^Uy^OBF>>0 z-_S4rr!?{%YRw!X2} 5(EwLQ#@7(&T5xSVo@5 zM*-w0@!vZ9!ouiBL@3Wmn@?Kq&L>t@n7WPphK^p&r|nJEZM3_3MeO}@L;oDV6_ jMS1O)^%lw85dU$)QVW~BJSorDve_%4=;x1Ip!$g?s5N>hZgV @dDW(TRP-~ZgKsP6E+Jz5TDpL#TDwmrD* z!!68uE#&MhRL~Mc$8$nlS50#{+OB3KKu@G($#N2X7uql=kq1*p5j@}m*%g#(;{sy0 zrZ~q8lo&X2V{LQ*4pj7oesNN209I5YyYgImHV+SThEmdiT)D6CgcD}^;Sl_?Hx{-N zLfn9Ih|DX3xW@_E0#mZG5K#iB%vab1R|NuI{hIk~8o-`{FMj$0H{HstBFMKBIy{&n z1GjtuyY!7ADwfnez9A}4&c@klFQ-ZY @PsWZyPjX9f7)>-EM|5lk(Zyjuoc( z9uv$d9F-7$qpO#X9y>8dYV(pTmRNgPpkj5$hS|T(d6Bogv>}VzIGkah*N{+z*(Q{l zVl3y71=aX>#aA*4eu6>m@|`<9xh{@@i;OO1CVp?`b(u^|?@7f3w3)fDRQSC08k6Pu zn;cBfS{ltX%^7dlX3z{Lo0#f;ejD$+joW;SYcb!? sCe~n|=B*#zJ)!uC zoOO{R5Kae7mbcjH@$OHK%YRIDbSn!|$i73iy}BqI;OcJc-QOHc=L0)dZ!pxd7{?w3 zDyBBV(ujk&J`@d8kyqFBo2uF}5YI|n_AjNqVboZ(QTf~c))|c}trz9H6e^0fMQNrY zH{0tvZ6azOj5a^AH^ieGSLmoB5kg8ixEGIdPiHFfwa)MzNo>JgIX7zXy77r4Kuwsh zHRG3`y_Z+>&C$XSw;gIq&}m(bu`kAG%k~z!$Nf6aR!mQ_fxnQsmiVCIG1*Ak_Dn~e z {#D!IwxDrv;7+k$RrUY;UW89COz z&Z#mX$e9p{3M@SLufQyRFs8 veN=bz@i+ZXF4=lx7ioZD9RS>9eqjc ~SO5d1~=~Gc2z6jHvr8bhXvGNzwW2+oplvpKRR0HElp2)l#WN=%vcR z2&1@w!(quu!P|(06KQH6=~&%ig2U)X0@^jaj|8OXcdb;cRez+u-;+1~5}wmYmMofn z8%(vg3XR4Z8cmnz{HW!8z#E_92vB0yWG *M|RDSgNAnB}`+9pm=PKjh!* zPl^)X7|UyHd6NZ_GiG4mtkt2b%(_i||JW}+nWm860U()eFQYZ!zvr?@S^!0US4mmBL7CmMP8VLJHu_ z_~x4oIALvPGAu2B)Ab{5ly(DGAtkqDdSqS`_&&3U3IqO6c5%<|U0gFUB~!S;X&fl% z{flYXMj)qog~!OWo~~*#uClUSs{QeT-0tTdN+pm_x}r1BYc8x=8dW??7bhLq&;>MKmAQ2=5((e<}SSG6svp z7m<(4NXHlmZn!AoisZ$%^P$Ll@+r4x{=*!}@pBaWfR26b?F>L}d) BvvBqMFTIP;tvn58WF)qS{cusJT}hm^nB8v__r{?GA)f6elc@?l``=Bjd7( zrzh#^FP>9JK1|1`44%Mo%_t{_em22rSUT5Q@@SJl$e+DmgW~?1kIQLf2LG>G^rQB0 zxQbDvuuY*^`IlX4EyzcM7bb^kT+A7&WwW!s)mgg>M-9d%g71e7k#ja357eM&^|l?! z#swpmoUTxp8qQZ`@VOdZx+8x;I|qGbe|ED2qB8HjvNb~0X{=?~=_ZCo8NK3*%57}j z{0##}AgUFHd=6w0|BFSMetF*BYDaVxpAm%wJqK68PydU#9N^4_Izx(GLT7#XkB02} zl5q$6B`S&!;FXXd*x}H(LlOFd@(}-k%jefSI}q7`OEFG!`vu_iGFBnPD%SVE*bG2g zFezmJkXsKKc#F=ig4g-|yoPlP-y!TAbKs$Lj !YO{AH~W(w~6rF%Qp1T$m5(aY&^neBEZ$; z(L*{;zIJV*CJf&Y)V6M^BmE-YGAx{i;8d>JX-wO7-s6%cLZFQ;VJv+ f%?h<=F`teDuU-|N)! zS>|HVB6(b#q7h^CF -9P7aZE0$Q(s2e;d@4bEyU5$cf-guqAdsHTE$=Dg8Vy wO1>F>^ANKLh*SmzVqZQ>Z^JOI$mS5 zW0(@rcyzpyx5Q)`%a0f;eU|i*NT4<;O7183!JFg*fb{*B*K+-R&yUU!#Ie*#aI$e) zRK{3t4T|vLpkvk8h62C->l3uaJ9(X^&!Hu|RZVh#a~oW3f?nK(()tx3SdEg-pNzL8 zhOfp#4BH`gfknr0OP;ba;O}q-Jg^(1;cAs8fJ*L{Rs*;!xCYf?6#|%*CQ53Zc{Mg! z$lRgO^dgU%rMNqvta`U`T0Q)A8kWdH-wZ~d2zo*TW+@Hc6S&lVezI#L;xaz%7^TCN zJ`Ra09K(wb5JCiJT`s@!^7oFzcvadkC~IqsjhpxvV-bTt-Ut<8Y U;8LD$rEq&UA_w&5hMJB3T%0asUew-MIY)TyHkH3x|>j1LPc>r|M>ET-@Eh_?;nF zKDu*uC@J#}rnurF2@0UOKGC;oyKhBe6p%spG63J`>;55Bq8-!XopLLGiMW8ATX?A1 zp|F>1BFMWR>W~K*aI65r54D9NhHA8GP^@CYQ16?vFz@nDxxPLfmc7RXPZ^L*@08i$ z$Nervf8hMw-}2b!B$^N9w7xY#9R@h**t-ofHon(+Bp%e*y6WJK)w(VX2$Bwv$*?@B ziU$aCO6BCR{P__YO;Yn)^#i(P5$c=ipFcYRUp~d4TKbd#7)k0&KdYe}j%IF&(C|>L z8usLC$i08}N!rqrRO_}U6dN8C6qJ9vMj%XRY$kC0sJ18=O++vK?-FnoL{9tz(MK+n zfs( p0}7O&Ra7ix`E#am-rivfFPEF2d(u#onAN~@zkV3j zix-VO#yliXGE}hZ!+4<+<7t?hrrB=n{K-B8v2|Jn#w=KpTuCUeQT~b^zhY?T0`}rk z#l5mzN?R Ta_Pne)kC!<`mVx5HUe?G;wAtn z>s2&6?l+;9l6Ihid>BsrN(cBU0s<3$Cm(Rymz$}i`X`$GR+)OhrU-~m*5+i6gq%Wp zZCbjzRxvD2q)zSN8>ml>{dAzldY!=y3Lzrd$mZ3V-wNeSMfbg)!A@`~;?e`MnKDfj z;(S$rg+FGi3w_%EuRfgq1Gq(gD{vxGgi=pOY{@0ho@^%YjRyPJ>S|moY6l8(#63>p zf0m3Lgg5|jY4X~;I1}IPRq#RTomwA!oNch68I%Ga<3>h+157&u13eTpKt_#5+xM@d z4koyHD6kI(LSuO%7Bmzt1qM;0{9j37bx3o`{*1i~wSs;{16=)i?r!ddFJ7Yw+Ue(V z%)yIX2uuAT=<%`g-=;6LokFl24 c1y^zlIS zFj}_Vmj+zOfYNVNrCc)8zg>3yW@P@6a%)Kgk+DoD#EONsvAUzByrb_LVJKybJBR#( z{NSnE+uJU)2OuN $(j&^ryGd^P!RhkkB!tg^&Y;b5A27y5=iD@}69=c~jjX5|Zwp~LPm9NmKa zJh}1@FGwo&oANjtKB^!3k`;yrfzaRyHv BGME@vB6;M55l$$p$&@Y_@#r=;}HOUS3~M0BpIgwg)j| zQ*WS}tx!UwWMJRLOpI6O>rLe*5*ATW8jKMZE0Rxhk4+M 5`z1!Av0uAz9AtY z1GgNx{rkuS1RAD2)0Ku8ze?cl^MLf(hhV8Vu}pf*RdSt_f4PlTcQSUN>?k0K7uesi z>sX9{>+O*B#jBFa0I3u 9~S_ReVFIOO`bav$b@ zgOJc}_)OY|6QG?@4b_xO{X*mCM!2}m+2Es^L%N^r&}2?&99_3rd&24 zy!K8Id2&^XO2;m1%5^j8HyeXAs&7J-4oZJ7O*2R}%0Seby)rsGo0~;=asn28yxw{} z9F~|~0U6X z` 34>(0Y#s;|atvE?)5MxD7 zYNMCKMwG9OC5B5V%`i0NXh-thqqp+;IxQX!ktP(y?^mp-o^%x&XV>UfFAz30k^W6| z^Zs7p$61<%W%u$M_<~3AL|RuQI~K!omFJZ~ALuJ5A3i1Afh@I)W$ljXEnBhcylN2l z-8p?LJFN~HsYHFgt!}*x#xVyZuR0>hC9$vog@gvH<`M RF3P*3Z1UYAgW2NJxu*}1K3MM&c%+&C{z zHq|Cd*;3EZe{(GAzK|>T3;Ik^X8_@c#
{=Awvf})~tv&=-^P9U?tZEdvWClmMj z|5gU1%L1$`UWBDk-M{vY3?i~SJOE+bIGp+?wdq_3__itfHrc=!0HdRL7XRAq^-BNc zdY0G|JSnH%@~VS2w%>mZ_U8n|K#m=equZjRSOc$jWW`s#Fh*4*7GQH1`e_?p%*iM! zUZjA!a=ks!0_7@K#iKI~l2qf ;Dlzc!2>Vn%%R~t^;KCG@7udTbh!#X&Ar$Sh(JX7OXGM`~9Oa zX69GgV#6^_Oy;`59OX_#G(lZ3%3FEL>S(e>^JXuiU3<>6=>(GRGKw;v|X8Po3Cd zoQ15ks6D*IHmE-+xRf`yy3hJdo_0BahvRR8)i12}V|y9F6->^Ak3s?{Igca;`Z&k2 ztH~FD(zN+Bz}it`${}u}4hOoqx7ar=kM@`g%u?$i)uW`y)g)` w|!`o0>n0#Ys4Ijk>{TK(iTgFF9OlNz{)Jeobp8 zaIdikRyEE)Pf9-1=JEnzi@JAtmuL=|N{lti#@45KPD`0!*70h(pVfG }eH z&HgBFE~G4I&Phvf7~Spdt2%t3S!f^g>oGg^UBG1V(14^9dtZ`VOjXkla+_` zMJ%B2X%Xd u?j-{(T5 bk(;U#|`8Qgs zR_WZA^>vWs%&e LV#zvEqB=F;Oj!syRJexhu{r{dz&Q+@lEA3{M%3ld zkF1_M6XoeozI3+~B9n~?UPW4`8&<3IqGW#qZVDHpXJlc#xD%WoG|hB5KjG~0?~!IR z5ri>37=H~CnsSFm3cdiQx )r XITlcFo7)CD*xk(rdcY zjX7~%v@(gSL}Tdq-Ed1mC6bPT|AIDw=|f$)-bcEc-|j>=E-Hch7do(VvH{bJjg9Oy zdP5>zb#Qfka|yJ{NAF&b31#?i_QIZg2Tq_9eB^{3GcGt$1LZcsrbFcelMM}Hh6#+g zA^(6dxUnlQu2&D*D1Bu_=4vO-owTlF`p|sl!DMT}Fzn*g>lzAMgYe5Dp1kBTgKx#5 zKv_R#%dN`LfuEK6*2Y0|lpyPpVP0*{bM%c7Ta= GAHozK3sY0+#s9@B*5MF` zr|t|x8gM+kr`mbrORBPB+w4BCoI1TZLsHnM`hJ8Em0dN~*0=Y>C>$VG!s~^TvrYr& zplVLhk3u?4?~(SLojKd7gzE)pz~*PiG^O+<8GV`~wWFS+fGOi%0=8L6{4b3K>LOm! z=m9rax0lcMb)F+E!~(j3u{c+cNI^w+KdgJc2n$UYXdtLOXd0k)&Ur*z@mBk#50TWq zZlZI_bH++E=d{IZyqc+5p$c)FMQKW|?J{5am*qgiu)6tYL{!GkRLh3Rm>uj@Tqhqa zSML^POYU @H6Tv*WOdE9=< f7W0D7&h`VXxJ zTP_9N=3)U1vT(A|DG(TcDeQ3G@)(LTKdL}VNt@Ij=4IP#*MjKg94n8zJ~1_{Xq$2{DWr=fYcBDUslA@%Z={ z6-g;zhrG;uF{*A6!vuDxwf(9IRcvZk{t`ooOVx+yN2WAjdrwbK3@$~n>hq6BKk9X8 zW4aY}^2E}JvCv9l9ts<8^Ag1LsgHeI?tsEU$zco|)_|q35}JF-3&!bNI%KX{?lIXQ zMAc)P2>3Mn;Eqe>)rktJbtlqH{m>lfwr2k$58{A9Vn)CW-b3a+GOR_vy*crnE1T99 z&>VRFa;$xOXE }@>Ly6`|N`~f4tgTrm zyGw2Fo$QF0Gj5HDV_70G 4Tyf{CFR?- z0IrkHjc%7K1zv1xa?i7*TIU)~fZGwS?Ge{jc6Ro`76X)nz<5>~GXoBv47r<1OiV ym;@b{=qky!JHh( Rx4dnL4Cepzgat9T6?Z|bag z`h5!w>!71TVpPb?2S5 tILQ!p zqaopk0>!OWq{PFxTk1AxbEU1ef9UM^t|)Fb sP{PfyEtEbKixak+P~0obyPO?S!0c!ibFFU z?}PD)2A&xuUXJi8{SpkJ416RRq#Yn)$RWNTM=unsT^F0!PYS;f6&ey7$eDko1+gYp z5NqVP|C&iFzYu9Ej9|PbC5qDEfPGq%XJp44s@KGZb3|H`g_{9JXxFgqw%ZmEm91Af z05H30>Gf+L+(V9-%Zss_Fs* ;9YVP5;qps^Lw)!Ere zfNc$rF}4L*_O*o*_aP=YiaSV=dcR^_EE3(b%7L4~ bs1VR|!k|?3h)%*z+6s zX&!l#hb*`ttOE_jY1#~BkP!I*nzhFAjLvX~{ms+dQIK1|)aQ$B44b!G9DMUKP~aps zZi)TyU=t|a3tWe;{N%f4#$_8k`!i`|os-R7GcLsh#f}LeoP`b0>u(NtpnI8X%}%Tj z*5Q7EY`Q9`q=hjqir@t2?c5bheCghE&;h;*|FL@ldJYwUDLy$gi^7+|5p0n+cZbh5 zy$bI#M469$D#(02>gvj$9 nINlntc+~xsPhiek zqG2v381_}48?KQ6HXtR8G;qv60!Fa-E`e@}UCqn@BbK*cuhYr9+=K0?m?u28Y0;q{ zkksK!z)!e1x?~WNT!95IMTiQNmxQ=1VTn?<*A`Dr6FB3{&Ya%09D@KL0nr!W6jMf9 zcITXp%uEXFj`dVL60h(nI?H38e1t_^eSK&nvi^g3^`0*U5W<(mz5STyO)V|gIj=2G zF7W*eB3pV0!telJjYI%(dLHd4AQ$J}0Py1Vcr6Z3p?gg)r04TP+8?Of%d`SiFe?)p zG2r}oa4_7*icm1)U{H<6R>c_`JC0xI_Xi|Z_hsFhRpt}ZCxFtacD<;mXkX)C^ItaS za!Sxcbm%=+k^PkDbI@ogxY({c8PqdfR&{{s4*+Q?NPmChCOYk@ET@h?NNv_eY8>pc z(koCCQWJDr^IT={?0|qYJ(K^psPA8SA_DL<-{J;a9^WFJcn`rrwVS$vn;&aMix-@> zK+ja*)|d|d*aQu!NHbJF=3C@+^sWz?Z}#~ybZg&Bww^S{2hKKdJ}5qZ{NxPnzq<=< zemI*?k-(XCz14I+5L(GTz6(TLoz~M~0>1c+!KPo>$O7%*Ec0o-9I0qd1a|6%qi=Z4 zKLm+B{WNffsq u(e)54|)pn$!(1m*`>J@dCt_l)C;6;X<)TMHEe6Q_?8Z6Y_9I z(8s-BxnsEdWCOIA?FI`;w1*?tWrWj~&x9U0c2N0W(FYAb&-j(gKNGwR>$@sE^G2c4 zlB_k4oDr+3jV=gTHAIK+qWeVO3#xkfC=4nXjWFB3 8m*-TI9@3T?iv3L-La zm%IoBXItQaJfUPz0kyr-jf2VP);&iDyZy5VWsH{Lc};DcNm}g4+*nIxPjVP$e15&= zMbO8n>oO2$`I6FKMzZl&6j+wKs9#Km@+dNXVQl2%u6qg)jf^`?ZgV8HR)mxmjDR!f z-{{8i;G*)s>(EPSja?>zEK7&FE!FELjDsT59Qy-o5f;t;*($2j6M`VZDhQ|L@CnN2 z^rmd5B;4E$sjZP7GBhMMkpIjfPjbo2TN&BY04+WitAE}WcpiLkpTr6_-TISHW@%#Y z=Y!jqAe_y4<4j`BJe-5~)FOtb!ae()eLgT5Vq=2>SQC-$Z-KtzvaFYVI#;9w*8({$ zHDPWP>fd-ff(PbJ)d)^zuuau*?G|Hk8+gBVoto-_RrC|0Vv0d!=&2Jq-lMiVjc4Yo zwKTmPTfoQP$p9kV=hIbFo13kYB60*3Y!GY0T;ZjGG-JE8gZexv!sequ@ Kvg!?a^bWcgr?=;w +lJl8y&9b_d z8KX=-D-zZv-Wj=} lra1|iiJ$RP1iLmuV1^EzHV#^14PDw2b8$A7f#Ja!asj*sI zLR9o4#+;Cb{6Y@fyR~-Rj^2VBvlTG7oT9|BQWaok*Jbn0Tga>eIj+5RyL=X~5ir|> zixUJhAV1$L&Gy)H*u`h7p$s{^%H01X$bNlXWg<)%lLvr={szDJOU(2~Q&&OmCt(;x zs=$WQCM&NN;N-E13^f4Nh>^l7L7rNNY;e`&0^JmVAO4(&vsnPL{z70GcHUuE?3x4a zNF2dJZNw?XyS>Z9N%u=9c4z*0G9FI&f}Hv0Oec#M0vI%U2o?Y|x3)%IN<>g-kj&}K z+~D?bQcIfM=r2cNhX!c%V5%`;44~v_VgFMJl43tETesu_A)Q+xbL<@F{Giaw3647S zYk(kj&s}W_{V06pJvM3&8?l{I+~0yD-cki>ZIg6B((lk3GMxfRqhHIk{3UxUh~hOw zC 4zh7omY$Lx@N5J`>(=zTM70+cma$)Bh+y7FW0XHE*_~?R& zvn4_uug=~V@(NZnh3H4X`lH=D%xXXM8))K~G`?;qB_AH<5znBB7;B6@1-$iuUFImp zZfmeIy%)yKE6%WKBw1@!z+JEEC=Wg#z~Z}L$j-|PZU=2U_Q$)i3!S3hENt74=;C9B zQymy#jUNq~2{Eh8;yT*3t*O!R!DHcjAOtl z8=?<(riO7Fm?Kpr>IU>i{q$3~;k_Q5Z0k1e-r*)=ZoHnZtW39LLb}puE50Q%og|W+ z>5=5qV@&`QR7aqM2MHgo5%h!e# wy8r4I(hCbE6ByYHejS9MB&y-olb`XCq@|_Z2fYlCbv`Si z0Oc5)hU6Tbi(}UZHL#mE`?77~<|e2-Jf-m r**?!c;N5S?Ze{fDPn7f5@2(N zJS|u&iWpz*a1MpRkS%7@jHpv MJO1K;LbUc&+>lHfw#~n;dZjC7> ze)YD4+kVH^HiQEl)_c YWjsF!ND8S zrN|(I7k11^jHibhK5Eb~>R5G_dAMN?m<$aZ`8WGF2F~MtzPpD&sTP*SwdYqd9ir73 zMxGy(sKTT$=GGAQxPh%W6={sogH3eU;{R6o4;mGmI`vhjZQ+A4H|mBs8F-`$9E{W9 zr}igIoWjvkO_&Pbk_^N&3o#kK(_(`>t>~gi>~KaV$VV! 8?EgtZi2ylB_MwhEVa zCO~2TiwN26zo3U>L|N b3cjh}Uy__GQ=rxUTT$+9 `+I%p1QmgKAg0#t-m`)wAa>8^SyA5t}Hp*c6*187oWq%xAf@p zZ8xvfP0|r5eQQKtW@PIQA07-PQlR6L3whdMu=hL$#Cz*ODVC7D!KkiESdF@n4>4w+ zufmq`Vq?|0oo2d0U{Davo@C}8s#kN_r)B5hQrU89ecs&rB35PjHn@Y?3&G>Em+P4w zADQG_O+fnZz%utfJm}+lxS-=6U~RB5+20+MuC%Ep&X0~)mi@NCE+43YtEcC0Gk!db zsfDX00w&T56#G8%66tvaiU-baZ_>>avN8WUYIK62=|MpJcNn}(vYZ$Hz LOmc79q*PwW0Q0t1d9= qEYHOHy819)Wl-)YX3vgO#L#&7S>eu%||cS_TL?vur@4lkmFi+S431oFJdje zyoMd;tDbecODr+Dcq~^{>`R-y%$tkOn?oMx*%Y2x3U^>( 4XkO-G
@7 zncCQG1t4Y+86r&IP>wwPuS%>2Ee5*LdV=5(y9^I*^w`VPPsG8OB%g3h<4Id6Gg%7p zmAyR0*bqPZAAi{3VtYCeQ&GfMay3NMFv9#!*Bu4;_(tX(v?r!jD>8H5$A$!$YrqQa zXXGSObP81;Rz{!lm(e;@WCAXCmvQdhL#}AF-3w{$RIpP;Bha-h0A{3el(=<9oY;U@ zt{99;B!7L;L+8}eS5!F0Lxg_>ZrJuveh$NaQ$X8EIDHfnc_@>aL;ZT`u(DV|UH;#{ zO-|5QAIy;twS%jf)0IG<3g>&EgAEgyJB*2BTo;Tj8GG5giu>}bbV#^X@|vD)!)2_{ zM^l{n!yu9Y4hr&GDpr4O9}3ArB=g|w@+66YCFq1%I8Yn>fzu+-Pb=T%I6rUI*G|=W zcD|q6fLM*F4nv~OlhZ~r_+zke ah8Xxw`Q&T)EhpKBJ>L#nlY(mo|4rn>`kob=Gbw+*G#5; z1GNvK9;@hjd!+P@4951te;s57V;HG2RNDjubn=U_-p}-nes_gETpg^{oA+8H#-@!o z$a|_X9K!aqsH=s2ZloCqD?q2p&}@~CuMX=*u0mBtfhC{I6d#Q)`i5SssQFKelFdKS zPwtHjQ2y_K{#K@;y2?^y{Ezki_k6UQ+(J2r{v^)jj4|5z!0o%AkFm(pLTnB{YEU+W zb!H+vfS<`sXG7|IQmSX%e5y=vLI0wO7(V*m^n$yX>G4ih{AGImJZ&4(xM<$hwGsy; zzkM^cKMt+^Z&-w!bFu-Zn=;2vZZ}V~4rVubT!RqyM)k*}Ho0C@usSQqPb|aYb^Z54 zdfj)7wzNk%H69)FPAA8?R1M1Oe^a7j!1uYE2qw+j=Vyes%hS(N@dvbK|LtHG%#z zWN|DP{_xPg`g7lG2AuH^dG%l!*57Pf|6~l+k5C4jg_1FSuySM^I$nETo&hVmx~v(9 z9wX{&+@heMA7d+nK`JC8%sN!Qo=;6{GL3eJ@1pb7C-H#as Nx3cPDgEq+ zyit*koIFm4pe^t1pGB7Hu1`@#Z|PVXnpFMeyXj@Y!^LV2 %X<$pgYN`Rv^BWojfAPMo!#XW|_8lV&{sp zGGfWGtN!2(uK!uz!_(Ew->*DjZ&fHy4!w;J7?8Q^# gN3OPOSV(!tf0 zkHQk?K21GWx w zw)zLXHPh?c`0X?q=A%F1B+DwOa&b`_0!F`0s^*QsV-43oEa2Q`#>N9()5V78VG^yu zsP{XE717o0#j+;dZhLx> }g;IjEs&DLU4<5LRIP_NiKSg3y&Aq>%bSG4xjct%8d z(h8&z)I_}#CA{o8JVO{b|7h-p?IC71^Mj28&F-x1@Ast^Oc%@)#kzhIq?M>Rly}LY z`kHSqJMWErm=e$$kFJqseeg=FS$=0N!WO5;xsu9kcQ`VY#-~e;1<>?tQHe)q)R0;5 zK7)^XUBXVT-uw9Yh@qsEIOM`pvDzOA?bm~f;cND1!7gTy%7KVZgNBRw^PCF<*4em` zXZOlw>jR&k((_oPMc(cRB385ah d?A|6>^wq8cLE;YD0T9?;*`Z9!u|U7ksr3lwLtF&{)y~lZ(e@b`CDC?gO5l{?Jof z1+uMQSGA=%v}t$nOs+cD_f~%GxsviMHW? nIc$Adgq9E@wg=<5>7lXt34>oVPG3j43nhT>Hs2hbpX;E+ zT)qDn35cosjy{gAiZ8MCba|aEm*Vvtg0?wNB$J|rl1XOsr~1Zl3a0^` |YB37F>sBXv|K?Y5=tSh3xfZz* z2R_5U)SuSKI?rOwG1Z*Y3ud2gECinH>zAK`gPV>m1g}IEtxL+jrQBG}F$MZXV3J>@ z3bAHE^H|m0L;`WuE^zr`SS9IdBD%D-hM{r ?LDgNdH6WN zDV8iS@c5cFVP_$JdySSb9O;1P!+Dx%7K)-By)48I8WgF!(x)R-s6pJe&yPW`?~Vhe z5x|Xuu5NbK`wW-+>$CSvk}%uhu3|Ds5bwYJ^nE;FEBsu030S9}5|6_Km1gl}2)cnF zdQFPmL$?Bg|J+||?UeQAE;T1T;(IHkc&$skKL0*NRxD9gElmG2!)a3ELA&n;12Onm zf27@eGjeA)J?3L(0a-AvrYd1j{y;$RC|vJ@bLd3loY7pw1u#QuS2 !`$r22J~|P2dbfBxlMSpyEav$; z{UIG5#QXwBOIhCxy<60-0sSv zYcs!l!Qy-J`;&%=XGNjVnP;t~n^#VTl#BUZoeT=!USMtB!_|IL<1}5Z`{yvNmxa=~ z53>O+Db}^sZqqQO?*J<(<42ReEe~nz=N9I3(yH%;7L&Zhf^6!NKNk8TdLJ(y{z7VG zyB(~3w0vZ-jvm(n>o%WT%ZfMYuPo-!I+J=gh`@h-etZAEyZ)($z=0kiL6~Us(Qgv8 zm8Wod#j%+~y((XBoylFrvsV35B#iXU${|ih!*EsH<{R_(#XS#xEHnt)6XPSm2W!-b z!0ph7g;2y@nt5Nx4bIi#SN-UU`Q=+aF`1pl83l}=wKd602JHy{+o)4I9;vHk?cgK* zyWW8WF!H)*hJgIv=d=NcsH(rF$zXTgR~#PpLgP32csZ*$ 6k?Z%aGA=b zdwFt)$TE`i%zhgj7|>~}>vw9);gh7)@0zx2NAp&|n%ClQ$Gf%Xxu8Oh08!CrJpo?Y zlH CwoD;;Y<-UrRTZ=eUy)z|(VU(NF%3yN$o+?cQ0z zW8@=u)0XGKJ H4nXXd(tkg`uq9b2 z1du={j+fa_>X#>V;~J8ZUaqmxCqw0eL|$pyoE-Ko6yy6gdTGYJrrC1;7{5Q5!a=t< z1?fzOEIm(7_Ghw2FE8b+^XwIoTFbaH+)bgYB(y^xnQ>Bwo#I{(JZ*@U{f0RGGRX@u zW1Fxz456h>Pu!`u{%jF20|in&VJ<0_g&1?xAsnvR*K~I?zdz0feLvHk(bxW|iwOGz z%w5MQ+;|@pgh%xG>~b$Z&{Z>c;eCanVWGLP<3g>;Z$;>IQ|QF&%(=Gyd&RXeKf9tq z)85F|(AbqxHUYq5IJEGN4XVDHy_4hOwQi6VjMrn-m~6^1sxIvLzNPC3{@8UR<}NFl z293UX*d95HxZ7+i`)%SY-RH=WE=97>HMsi5h)g|1W!~KruG{x}Nm2Gb?gaYoOoS*o zkp2oW!;SzRKU^;y{EVNXyb;)Z9_ZF{c(%Ou{67GiKxMzZx4NUZ4qtiTv(Ernzck#o zUmI@eX||~jvMu{|zHMJix7451+q(0|S2}8AwKoNnEo}UB4S@pQ=R}|irsb6Y&EHU4 z-81^NAA6h+dtO-kRedAb(J#AAeWTscH~hA_;kV4oe%pTC?8FYTqVa0EacZgVR6MVI z^J2H-p6(tT`| j-Kt6fviC-89O-G}tyY4?Z)0?R`;pZ)Dr%<$TAQMw!g& zB#zYz`mj ) zJ_i!Uj trri)u$dRX?0oe;UtqcTLMatg-iMfH5sRe>wz5z?u#RlgD8? SZNXT zw=%6&el+*$tIf80(QQ%Qpg``ZZS`^r88n708gJ@nrth!3ds%HW%SAki)j}3QplYAZ zJLTxifQgQ*R@~`mXtn_y%cEcRTk7n*|G3W!?i%gcmZ>#(u}oxqY>i?pRJZ~c>m5gG zI7$5K$f_j=u)W{vszFbmQ9n9A@cI4x*=RX|ilWu#$f>c0KqxCU`%1T?Ui91U=k?#c zjK02hP1gJR+OE0LZ0TpZFyFruecbMETu?g?*=PTAeQsdy!}=|O!R-R0uUchl0{wt( zkN0&Hoob^~C;@zh-gELfjW0t`!76DZ71KDACxb2%yl>UHKA5P)p7g#ML9Q=A4=~`x z4m|0o2W%PY0^f{wqQ>hK`~MK*7+22cb?5be%69y>;|u;ub#HBGe7X_#{unaBe7)FK z-_kqk!_7}`-#`6)?eg;$oSiZUe%or(_Lse5E}8XO$JqCi6d1?q_?!8*zmaaMFORm> z&(Gdn|Br=+B%ukJfaz|+yR9Y39h2RRdF2wma^AUer)_5!oU6C_Z)4J}Bw4(WW#_iD zY-2l)7q{{K&8FGksH$6QRdsu =!`Lp= zy@Xd@MRftn^(Fj$k;!>b&f$0GP|qgn*y*}*C%oUDgCf3!G75$ppFR2H?PPoVThY?e zAE(x4Lu0Z VGpN+@Ao8WiJX!P3vIuX|=4`VUBwSWcSMrY`6 z!oFjCNdV5gB1_|Q&1)r@-I^KBBaZd#_yN913;f-Hb)$@ceHKvGcsD!O6`y0in@z3- z?`p? 2POEjjw^WvIE>_iBOIZI6tl4&0vpIfSE_Pj&2Ct}l59fqQ zi}0NxXbj((t>ASPWf{L;!24sow-Ek4Tf@IM@cr|URw#}r82vQMSm#CbV~qX`<9Ixb zq5%}MbOG}Qh13i=Fa1~_cnJLS{L=un{} $q`>69@CVhz?Q6d^R*v8p*KlCA|pL%Kruv(HYhO8HV4=~RB{P`EN_4Pjo{r$Tb zG#GDed?~5xTUlM-DKNJ~@Y(=>XIooek1>Zf&wo9_7~;Mp0X)mPr+ptDYWcwX$63&^ z?shR;vzBb2TmZO!0`FbGXXJa*!FiN*lvR}FzEDQ+1`R6y6J8|;{-2 %I=Tv rZ)P8HaM2cLfO`Rvy(Jumfr?dtRTn@>G&{$lGB`nTd;eI4NAh3K08 zt^8RdsRSYuef{$D53~(k2@13)4~-i1uXehCqCY56ax2D9o?s=~_!LTZky$lNt$a4b z-vcP(nTY^E3v~{wz6`Z&q^!>W)!^CWh2`D+g|*#fD69pP)gLQ=6+JLsSlu t-8li*2%P_JMt2pV&9)Bl^ldv+o=O$HFnamv;XH zesfUyC9Yp<)Gw&Sd 5t*{if^?Aot?}t=l{nY^P`^6_-j)44JiJl z(`nV{B5KsaMyp1vUX9nhnk;uF{d}_fj{N L_|u4~Yr7rN7w5tJ2_8I&EAA>Vii&p+xRj|N`7wtRhYH$%O21 ~m20Gd5oL{6C%0`q^dZlXckbh* zp2uD|dA%k)NM0mQk~hht lEV~+F)C3lWnsP> xC>RWX;!gq|xv0Fq zgi#K`gE{Ckiz7dP>|6fA`A>|#vh#@_Ne=uZo 6f&9PbsH7x6s0~hg%f_|XJkx`R0)??@d1L2cSEn R}zbvVsKTF4@Qd>EUOPaE&YrB~}S?{{XM-#lvk;vx2sM`}dM(li#+x(H{<;jlXd26X}hM&t+e~{9N+2C!Vu^vib@A+lKP? zS|~33{Ta$&cg l}eU8J!F3NZlWeA0DC%TSnCp{%b$L0*Q!j!mOW@ycX0d-&e$;NYIyc$$8b z#-Fh<7QiY(u~4Y(5|nDlZcUGyWq>az_}!X10e*gwC$T&MWs?4IA2*ZYRcYHE5h&qv z4G xu9xB}1KQxS1>UgTX6)HoN4PmSz^?LLD_geTBJd7I<3B zY|p5dU{gE~c=C)g>J4I(9#Br`k)&i(;)!sZ_NUB)@Le cM z>>oZe%RLQot_HkCFSzLPwu-O1( pox^lEwivS4fvit{xLQTp?J- zI0sA|6%>Nt8PaEImu&6oelHPW$k6sZFN~$7GVbRLJTqS+5C 8pI0MwNDyaZr9%Io@8TGw~ez-Kg~Fq?N=P_B~>druY~lR32SPq*J2WzsO`c8sw? zp%^UTbpva=jx{DYD(J=1d#4=(e=36csWB4ZlMZCf@VZD@!S7 f_% $}7Y69h1hmO@UkOEVJ=Rb^`J09q;d8DL-djVTH?fY8TQTVf zwAZ13j{Lz5tHT_0m;?Wq{~z=J*#{tkZl(zoiHPpzv3F)U^;EE<((1@3?2lT2(wpf{ zS<`s)SLqHBQCfp1rj8&&d2tU% Bg218c@R+o4kQ?C7v(zfCcE{DX2-+IVffyGDgRd)!wD}ZGwGMs}20_ zLs}FEb@0sWwTFf!5PZJ1c)`9px}d+Nw$+oTPN{yc*wx?2w~cq+5O5RlczWen@V-I6 ztj^JP0qvy7@NbN9fcKW2(c_k$u#KAe#?M|d+s#M)gD1oE{Gl5?$B#uDV$n7*mkY7c zX&gc60g!|SI>5LVsNBtK?`|G2ot+n8!trbBupt!dIO86~2YN`qki?rC>5hM RRQU zmbI~T`hL0FQa3!>evhZbR4QLqTO3#H3G6_R28tjw?Xl)94CrHn$@S=m@_l Bl=~@Y7L4%X%0=_y>P7cXUR!^%_Hn&G_et&i763hs?!yi`ScCO+N@t!j zkTU@}?iHYKt=b#Sw!h)G$zKs(=>hQmowNebp-%Dmpw|QFBI?jygT?PEDw|LwH@H zn;zES_Ce|E5Bpc&vpYEHAM=(}V6GB>pbdlZYx;f{slk6$0T5yTL%XG3vfK8Cl&uge zFJMVUlUPM78L!_~K1r>~Q+}rG8 te7vZ)X$N~$wH0YdKs%k%)mynQJWf*%tO4Vc-tF1!I zDZEFg4^Z7ceqW*e2j+tS5xkUjohtCX3~(($y-i!IBc@SM!Q&%bt8VdX#WT>-ipzuq z5d_3{k{$hRyRANS>J )=34qmV%0*8 zxo@0|pK?jpop$JNv)5{Tq{V9zpST;*R(I?r@@}8c$GZ?UD$i2LUX8uhb6@lOM>V4{ zROiG)wfE5Q_a#U6? l+b@-O|svdtO&xy7-*F0~z}_`HrHe z>vbDEM81{o=s|9D0gk%63fjB#gZtW|=La_N44ZY14L^g1)Xh63cW;CD4c3`tjr|wk z-l(yq2PE_e>`w>yN(Tb*k~7{i>IX`$0i8CgX80)gXOsnz7nM5X9`WsDN4+w Shq<@QE q7_ieQG6m*UcqrV?CCVPS>wE;-bg JWf*J>P(*Dx;h zBZU&8F9JARqE`;U#1jAlPvAFCP;o}NgnnH@HJ9<*OMQEsKY9uA_v^ukmC(3^KEwmw zcE)@MyvrP*E2U>exC^~oMmq$U^f1^)e=cGUE^-a ~+VCWsVQArMG2V+_8myP(j<|32 rcbTS?eePV9s` j6 5k?SpR`3}?q&@8~5Q&&}|&qDz#e#1U^D#Ne~08U$W0G}-l z4&Hv=T(f^*uSNe~el5vkRTPmL4XhcaP!Lsvu{kxs_*S6gZ0M2yr+|OI1}*Zuj`Xs{ zXP6_?U@wOvJoL^_(APy*sD pogd+v4ti>)+n%^wHci!4OXgtpLU2(|;qU({$B0@;|FW7-i?9&;1Zjm`^|P zoQ7hVpiFe<7cjm>D8B1ZdY9485K3`k98Z`%bFUNtdj!6~n0}Nvx_#> Rqm1>3Jl}uQnd!{OzEP#F)osu^xIrznnf_oGL;rG6;~Ra4xd);BE(3sW02HhO zv@d|GxWA>>-ERCodc(-|!#)_A26t;UJZ#kf{E=4x0Tte_wc3Dg{v s#P0Mi%Exz!%VNo0Nh%ggdYj;6)*K%eb8j;Lq-hKng=kM z23 |O>W+Ztzw17{7 zLxREh4+bCqkv(DLx2S`4u}-O5F7r_l+hp79gYWyqzOj$&EBnm8a||2{e=B2qm(N$W zKM^eq^q@#U*OA%;k7c)~>do6T^~O=7=D_xm<$=@jwe^ACqCOHX3H<;5c*0N~Uhj4z z)M;7t4C``)eTXK7Mm#%KG4qR 1Mf>dwb)3OAt#0oCzH$&k`{gFQtX6dtD1pQdmz3;w1FM9H;A?P zcCGHpOkr=eRu@UC^CZ51Ug(`OhpZ}F6_w P(xR)pua5kbyo)leW;9~@!ZReQP{sA7Yw`8fUCo>~ z%Z-{YVn->!ml60LiXx4gW1IK|)U{kS-T3IJi|+1s?)E{aW{?GrUMP|YDHx%HY*N7( z!}+F3#P|@Vi8=qR;@$5B*OO}+>niI|bt<|wcka&2HPgyt8};-Ok463m9?R-RMRlz- z3J+ignCD#PrWH@v=(_&ZN7CT20Y>xgYXFo502e6Rqw`Q+x1hM6V;BOIRus*@&(rwA z_n~O7p!CYP6e!CX6#wEf6kRC5G} sb{#x1mJTOfOMy>_pa3S-K%KhNwjwbdknylU+Z(v zWW9CHs58oU4@eoVQ2)GH0B~Jn z7zgU0L2iZKANXt;buabdTntT+Q}A#y&RjszBEGkZb~afsR(eb=_ov|*??a~njyG{K zX*07!pMH2-7)pP=7rju@5$Z!*nE*VjQt$cXmjQqwY@10i?3D!g3<+9C*}{7Oe(g>V z#Cq_X(|ABY2XGfh{hjb9b8yQ0rNH-w0Q^fB1L+;>sTt+~fY+>`Fg$Jng&rsq(AN@v zwt?SZy$6>tKTqQID%KmIZ}KGS*<@Xq%K?C78obJa0p>Uqs0W@jPNtzWG3KZU-Y_M= zW`nUf@)E)JDnoDZH|K(MxDgBx^%nkpk$i{szJm4pK$0vxg}-SO-AdDywKQF$VJQ!} zob1_6fCu#!^An@L<0M%=9{~9H9AyE %gc=B7v zK7Q-S={NSAd;6gC08mkF^m41!mf ^Q)U4V_kHr&& zUa1E20FdEnY6xdPz`kmRdR~u=o*OG}@~MU<2xWk3-A!GpDk;?n+Qaa-?QZ<} p-d7=-=Mlb^E1v0GV_v0YPAlks6>r<{a5UTNhCO3KT}*Otp|`wG8ENC3X5+vD05e zZw67M7V(=UO~7u|YGd_!t@Tn9>x+Pkzl2$TviBA|c_vVh#w|XDf>YI)^2XnRbSP$4 zKV2Dh2@2VAuKYTX$bxR6+@Vb`dtqx5@ z@20c!FEZe+)4IlrHR5W&tUC$oSp+dIQFBf-lM+F2h^GVoOjL| TqQdN3bYb{b5z#NrDmHUwE}3`WWu z^k}Med1zHPGkP1a>0*R_6tNyG3{3o`&37M$K;9&el2^&IlH}5P+qOJ;b%qK!3PBXX zIjBiP4(r|vR0|NLk(9E6GJ~>%GK8{(GKI2*GUjZ%%z5$~YBz$yo~tR!T!CBFTRhd5 z`3Ct>Xr)T;*;ai&>eNw4#mzHT)qz&B$fz~TJZ( rfANtncd6@CX=OP ZB;9PGCe b-@f{M@^0yn z-{o)kTh_t4SSRad8*GbhvTgQ(eUU!(R|d1M>@)k$F>oxwV5njl Yf{%2?j_+N=v7wWgN zw=BpWQ-V)s8qi*SPw3Rk0q3Bpm8(j12zr}Vt<$#;eEj>TLL}emAy7Y@JI#H(!aO$} z))ll*BW7xR!Q4c>m$BqP4Ev8yXdK46WKFAzrt`7CcU?O3+G%=%bj~x0>jO_T)6Q0^ zcAc7o)a#Z86i^v|2>OM#?v0geXYhU}o-c%beJ@pe~4%1me^GOD%CmsO*hmXbRB zp9YvcRqHu+ipVAs!nC9@CK{TK`*8EnsXH^}_h!!R&%HaGqjJnaM4GdTv 8NbjyXpoc+@x~!2)fg4#*(4(>^-x?180gYZtNH?!ZYZ)S z>7-Y>$HDzu+_8tC6*&nAAq?3B;DZV||4sM*B;1&BRM++0s%iGxy1sL!EA$-Z%?{r5 zinyFW@U{)b{Qh1nl5#@YySe97>=}O1wg;28JzT}VchJt|K0nMl0W-c^;1%mv`EV~d z)Hj}Q+ Pf47Nxlj6QxgcChhjP{fN{P`| z-1cb&Hc2?Gb}UTbnuJ$b&jNMPlOk=~S<>ee0?2QdP*woWu _^kkX zybszcKzEtYL-42}J*OjjO{D3{PLeEd(pv_=pFA)M#!?!t2$mZt(;#) zZL9zz)rMi%6NsUMa)I`5TBrY3@g$po8wvmvu;I|iwILOhMqUk=8-NbesMY}c0i29L zb(>LPw$q_rnv7J!n?~6Fe|z|6{`S;60Fw>?#aDE-#llVT^CR%YOzXV%YSea6-Y{M$ z-{+uwFWbalhJtdDASaU;FdqT@1Ei^fky}s}#T6HvUbskYV@H1)dMJ~(-e-Wpzk&79 zrqg=bsH1~My*6#tU)4^18RhE$rZ4$cf3x;_#wY^-i`636mj}6iB8?>kEoCB1o=`5N zYRr;E%+Z7O1ZajL#$*KmLpsLy; 4;=Xt5Mi5|o;z+j}dQmd8#7DhJnzl{D4V&?5h)Zn1>8S|^0r2)yg zg3tIJewV-DZ&?THVx6p;ZLlr2$+p=C_9Y9bz_E|)tMoa9pF|vsjEQ5z7&%ss`D`Bu zcsxV8X#9ymhfFve=>epLi(7R!sog=;K|r dSP%qk^sO$ zeu%T}yxWHfxvBW)kxC;gVLjksH3qyJqL%;?dXfDEjU3Lr{z2WTS8C^1ROGIXQnfNF z^lFis;#*HXn78F&4|$V3N?wgStZyfw9Z}n=2z+e-=DLF^byDfa1ZwjV4G>``Vd%Tc zr>*vs6_gp29h4!IC6p fk;)9PBiigMEfEMfsoiunSqFVS-i@<7aHyorpFkr>YrWesJ{>9Lb1 z$Q$Gl@`{o>QzXzKCNCZH6?u%jhK3XJ9{PPT%QX!qlX<5ajQ?(1>KD5s_2O*iZvxEi z-JGd6-kz)1Z&&K@sG&FDgUXjuVzi?-?NiW>Ht10#g won&M zuC~#?9AyDJXx`Q;gPh81tlb=K(N%-7IFxCWZIp48b(DF>4S)9o&+BhqeLh_(7(&bd z1~GsZCIRS9b(&aEf)?+D65}pCXU40h0}!S`qN-H|;FS`j=ZU(6Ie{Li3j8~5JD-)c zU&41r^eTBL8svBQUH*o@WgV=Gb+T@@!M4~Y+h!lw7xsyLlRl!a>@)k$F>ov#6UW9e za;zNlqxyjPqZef1fZ|i^)=+*-T&Xu8Q>GE-I?wcSo??uVUSRl{mT+`E!L~Z4?AOO3 zaN-H~qw~M&J)$LyCRK|ln $cH3$^^v;O%+;-Gj-j;P z-rj$7{;|`~XU4mxHOlUl-p~L+LrjI=yO8IMG