From f6b9858f4f6d878e931f124700c8ec36e96f2243 Mon Sep 17 00:00:00 2001 From: Timothy Teakettle <59849408+timothyteakettle@users.noreply.github.com> Date: Thu, 24 Feb 2022 05:01:13 +0000 Subject: [PATCH] adds snake coiling (#15514) * new signals for resting and stop pulling these are to be used as signals that will cancel the coiling * Create coiling.dm * Update coiling.dm * adds sprite accessory for coiled naga * main changes that apply the actual visuals to the coiling mechanics * adds message to coiling, fixes offset, adds action icon * coil offset was using old direction * reordering * fixes coil sprite not disappearing * fixes offsets, solves loadout issue * follows lin's suggestion and adds support for slimes by making it entirely handled in handle mutant --- code/__DEFINES/dcs/signals.dm | 3 + code/modules/client/preferences.dm | 1 + .../sprite_accessories/_sprite_accessories.dm | 8 +- .../sprite_accessories/legs_and_taurs.dm | 5 + .../carbon/human/innate_abilities/coiling.dm | 89 ++++++++++++++++++ .../mob/living/carbon/human/species.dm | 20 +++- code/modules/mob/living/living.dm | 1 + code/modules/mob/living/living_mobility.dm | 2 + icons/mob/actions/actions_snake.dmi | Bin 0 -> 494 bytes modular_citadel/icons/mob/mam_taur.dmi | Bin 59290 -> 62367 bytes tgstation.dme | 1 + 11 files changed, 124 insertions(+), 6 deletions(-) create mode 100644 code/modules/mob/living/carbon/human/innate_abilities/coiling.dm create mode 100644 icons/mob/actions/actions_snake.dmi diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index fdded58308..dad0f49832 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -359,6 +359,9 @@ #define COMSIG_LIVING_RUN_BLOCK "living_do_run_block" //from base of mob/living/do_run_block(): (real_attack, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone) #define COMSIG_LIVING_GET_BLOCKING_ITEMS "get_blocking_items" //from base of mob/living/get_blocking_items(): (list/items) +#define COMSIG_LIVING_RESTING "living_on_resting" //from mob/living/set_resting +#define COMSIG_LIVING_STOPPED_PULLING "living_on_stop_pulling" //from mob/living/stop_pulling + #define COMSIG_LIVING_ACTIVE_BLOCK_START "active_block_start" //from base of mob/living/keybind_start_active_blocking(): (obj/item/blocking_item, list/backup_items) #define COMPONENT_PREVENT_BLOCK_START 1 #define COMSIG_LIVING_ACTIVE_PARRY_START "active_parry_start" //from base of mob/living/initiate_parry_sequence(): (parrying_method, datum/parrying_item_mob_or_art, list/backup_items, list/override) diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 3272060835..8d6646b8d0 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -3066,6 +3066,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) save_character() character.dna.features = features.Copy() + character.set_species(chosen_species, icon_update = FALSE, pref_load = TRUE) character.dna.species.eye_type = eye_type if(chosen_limb_id && (chosen_limb_id in character.dna.species.allowed_limb_ids)) diff --git a/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm b/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm index 1dc50bfe73..f5e1c2e113 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm @@ -28,10 +28,9 @@ for(var/path in typesof(prototype)) if(path == prototype && skip_prototype) continue - if(roundstart) - var/datum/sprite_accessory/P = path - if(initial(P.locked)) - continue + var/datum/sprite_accessory/P = path + if((roundstart && initial(P.locked)) || initial(P.ignore)) + continue var/datum/sprite_accessory/D = new path() if(D.icon_state) @@ -64,6 +63,7 @@ var/mutant_part_string //Also used in species.handle_mutant_bodyparts() to generate the overlay icon state. var/alpha_mask_state var/matrixed_sections = MATRIX_NONE //if color_src is MATRIXED, how many sections does it have? 1-3 + var/ignore = FALSE //NEVER include in customization if set to TRUE //Special / holdover traits for Citadel specific sprites. var/extra = FALSE diff --git a/code/modules/mob/dead/new_player/sprite_accessories/legs_and_taurs.dm b/code/modules/mob/dead/new_player/sprite_accessories/legs_and_taurs.dm index c525a13ef8..11fde50a37 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/legs_and_taurs.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/legs_and_taurs.dm @@ -126,6 +126,11 @@ hide_legs = USE_SNEK_CLIP_MASK matrixed_sections = MATRIX_RED_GREEN +/datum/sprite_accessory/taur/naga/coiled + name = "Naga (coiled)" + icon_state = "naga_coiled" + ignore = TRUE + /datum/sprite_accessory/taur/otie name = "Otie" icon_state = "otie" diff --git a/code/modules/mob/living/carbon/human/innate_abilities/coiling.dm b/code/modules/mob/living/carbon/human/innate_abilities/coiling.dm new file mode 100644 index 0000000000..52e2a87a7d --- /dev/null +++ b/code/modules/mob/living/carbon/human/innate_abilities/coiling.dm @@ -0,0 +1,89 @@ + +/datum/action/innate/ability/coiling + name = "Coil Grabbed Mob" + check_flags = AB_CHECK_CONSCIOUS + button_icon_state = "coil_icon" + icon_icon = 'icons/mob/actions/actions_snake.dmi' + background_icon_state = "bg_alien" + required_mobility_flags = MOBILITY_STAND + var/currently_coiling = FALSE + var/mob/living/carbon/human/currently_coiled + var/mutable_appearance/tracked_overlay + +/datum/action/innate/ability/coiling/Activate() + // make sure they meet the mobility/check flags + if(IsAvailable()) + // check that the user has grabbed someone and they are not currently coiling someone + if(ishuman(owner.pulling) && !currently_coiling) + coil_mob(owner.pulling) + +/datum/action/innate/ability/coiling/proc/update_coil_offset(atom/source, old_dir, new_dir) + // update the coiling offset on the coiled user depending on the way the owner is facing + switch(new_dir) + if(NORTH) + currently_coiled.pixel_x = -12 + if(EAST) + currently_coiled.pixel_x = -12 + if(SOUTH) + currently_coiled.pixel_x = 12 + if(WEST) + currently_coiled.pixel_x = 12 + +/datum/action/innate/ability/coiling/proc/coil_mob(var/mob/living/carbon/human/H) + // begin the coiling action + H.visible_message("[owner] coils [H] with their tail!", \ + "[owner] coils you with their tail!") + currently_coiling = TRUE + currently_coiled = H + + H.layer -= 0.1 // LISTEN I HATE TOUCHING MOB LAYERS TOO BUT THIS IS JUST SO THEY RENDER UNDER THE OTHER PLAYER SDFHSDFHDSFHDSH + + // move user to same tile + H.forceMove(get_turf(owner)) + + // cancel the coiling action if certain things are done + RegisterSignal(owner, COMSIG_MOVABLE_MOVED, .proc/cancel_coil) + RegisterSignal(owner, COMSIG_LIVING_RESTING, .proc/cancel_coil) + RegisterSignal(owner, COMSIG_LIVING_STOPPED_PULLING, .proc/cancel_coil) + + // update the coil offset, update again if owner changes direction + RegisterSignal(owner, COMSIG_ATOM_DIR_CHANGE, .proc/update_coil_offset) + update_coil_offset(null, null, owner.dir) + + // set our overlay to new image + var/mob/living/carbon/human/user = owner + user.dna.species.mutant_bodyparts["taur"] = "Naga (coiled)" + user.dna.features["taur"] = "Naga (coiled)" + user.update_mutant_bodyparts() + +/datum/action/innate/ability/coiling/proc/cancel_coil() + var/mob/living/carbon/human/H = owner + + // cancel the coiling action by removing the overlay + currently_coiled.pixel_x = 0 + + currently_coiling = FALSE + currently_coiled = null + + // unregister signals + UnregisterSignal(owner, COMSIG_MOVABLE_MOVED) + UnregisterSignal(owner, COMSIG_LIVING_RESTING) + UnregisterSignal(owner, COMSIG_LIVING_STOPPED_PULLING) + UnregisterSignal(owner, COMSIG_ATOM_DIR_CHANGE) + + // change overlay back to original image + H.dna.species.mutant_bodyparts["taur"] = "Naga" + H.dna.features["taur"] = "Naga" + H.update_mutant_bodyparts() + + H.update_body() + + H.layer += 0.1 + + // remove the added overlay + owner.cut_overlay(tracked_overlay) + tracked_overlay = null + +/datum/action/innate/ability/coiling/Remove(mob/M) + cancel_coil() + ..(M) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index bbe2781403..e6ac8ae881 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -612,7 +612,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if(Q.type in blacklisted_quirks) removed_quirks += Q.type . += 1 - qdel(Q) + qdel(Q) else var/point_overhead = 0 for(var/datum/quirk/Q as anything in C.roundstart_quirks) @@ -906,6 +906,22 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) var/tauric = mutant_bodyparts["taur"] && H.dna.features["taur"] && H.dna.features["taur"] != "None" + // stuff for adding/removing the coiling ability if you have a taur part + // if another action is ever based on mutant parts we should probably make a system for it so it's all done in one proc with less overhead + var/datum/action/found_action + + for(var/datum/action/A in H.actions) + if(A.type == /datum/action/innate/ability/coiling) + found_action = A + + if(found_action && (!tauric || (H.dna.features["taur"] != "Naga" && H.dna.features["taur"] != "Naga (coiled)"))) + found_action.Remove(H) + + if(!found_action && tauric && H.dna.features["taur"] == "Naga") + found_action = new /datum/action/innate/ability/coiling() + found_action.Grant(H) + + for(var/mutant_part in mutant_bodyparts) var/reference_list = GLOB.mutant_reference_list[mutant_part] if(reference_list) @@ -1220,7 +1236,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if(!HAS_TRAIT(H, TRAIT_ROBOTIC_ORGANISM)) H.adjustBruteLoss(1) else - H.adjustFireLoss(1) //Robots melt instead of taking brute. + H.adjustFireLoss(1) //Robots melt instead of taking brute. /datum/species/proc/spec_death(gibbed, mob/living/carbon/human/H) if(H) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 2070d07e14..bf3094cb08 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -395,6 +395,7 @@ ..() update_pull_movespeed() update_pull_hud_icon() + SEND_SIGNAL(src, COMSIG_LIVING_STOPPED_PULLING) /mob/living/verb/stop_pulling1() set name = "Stop Pulling" diff --git a/code/modules/mob/living/living_mobility.dm b/code/modules/mob/living/living_mobility.dm index af34fb54cf..6aed30ab83 100644 --- a/code/modules/mob/living/living_mobility.dm +++ b/code/modules/mob/living/living_mobility.dm @@ -9,6 +9,8 @@ resting = new_resting if(!silent) to_chat(src, "You are now [resting? "resting" : "getting up"].") + if(resting == 1) + SEND_SIGNAL(src, COMSIG_LIVING_RESTING) update_resting(updating) /mob/living/proc/update_resting(update_mobility = TRUE) diff --git a/icons/mob/actions/actions_snake.dmi b/icons/mob/actions/actions_snake.dmi new file mode 100644 index 0000000000000000000000000000000000000000..6856171b0d69d1b5fafdc9bb76eb4ed131ed8ed3 GIT binary patch literal 494 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dymH|E?t_Kbrn83iWkAb0#f#C!L z!xo_U0tSXl3=FHloM#LSO$>K{f*(L)KpsdbP~9|!&s=+XfLz9sAirP+hi5m^fSlZ_ zkcbkO)Z*l#%z~24{5%GRiaEhy1x2ObzXTV2{Q5-8TUYDcne)LLLJck&KX{~b-beE! zLs3uf4h!QTW8v33eA&IPn-46_Dl6+^~8Om83&5ACp1W|__TL{^^pgER?Rn;=T$oF=X~^I$;D1% zyNj)QPKDovnj#ssHB9ES34IXdJR%z5bidVMO7xrF;^{`OT`i(EY+;rOdugHeW4@5{%9)f)wJoS$u0PWak( zx8WZ5s&`?@{G}grZ!0bM(OebwNH49_J~h^0s&1b88lQtnm9oJVSAU&aU1S;AFVJ$v7K&p!K{^M0LmbH^Zs>yR{N082sy0)cXoUEe_< zg2*uQhk^H8o;p48@DKFx^96xI^51+jHb$z^#4X*9NYo3LOH7fYVyk+mSA8o?kUbcl z5|||>T3NV&#C=ea+4S3O3zddg1shS1R7}Sv9*b~(r|!2J_6P`iBbYH!T$aDfdCx%{JOK<{&@rXW7~_OIs%WHs=qU}!}6_cr@n zw1ZkN6vCF7Csp!}lSGbA);E~Yc+;w>%MISHwY=5)Wi!kq%yO2QebE$}^`u!t#StYV%o&*Y?-ZObNvYrS;p=$Cs z$MeEC>;$c+E19IxS98dx*1lvS->Q$Ot<+QnfTniF4><%!}dM&x}jUZJL+guP7g z)h@+0)|xM^*_qUSMlCtfjK9n={(W(!_bll$+c(Kr#sdL}eHEDET`pEkfTmZrpGWN0 z_LoNAcoXYrt(Zz=U*j&C0loN+ltP+*^efwame(eR0A4t6feyOyBE zcGP0{d_}8YA#gXcMG59yi$3|*ZLy6Vs9w@<`h|AqL{Ia0b=5XAXPIVuA4r~+vDR=# zs)SPpSc2qsL5dg^?_)k@-D>$41ZDNERV_Imi%Nf=>_x|VHkU`pYA)y_(QghTW`&Lm zY@E+n1f}5KHgBsH&E?>EGd9}z=V%Fs1*2J5tz(@ga1q<=R}w`d2N#t)>rZJ){3Yhk z6g)>bU@~$U(%wgo`F(ds*rCg{h|uo+xA3}R(ZycQy~q7xm|G3p0lwn4$Hw(u%@P?; z*ju80vD=+R0^*mS!=7s+4rr}+<+O%R1$*Z=3Uxv`=N%B6m75cTr0?fQvj|#?gXP-5 zpLMb#fD-T;coZ{6D@3^*WprMo*~0}6mYmcqXfl=59pOzI;WdW^R*E6{(mZa9c!`+* zJ)CH(oTuC&lDNGp=k^wU8>3+1yPc{@e}1J%Qls~ded4pk!!!*g(Y@}^$LGg%O~{O- zN@meD2nT&9Rpd?eEZP>j({bQ#Gb}F5<|&;L&=VhbYvaA6qrj;?@QUO zPyH5(>72QK^d={-80vjuCAyB8H(HY=PW4ZdeodubSWlj{g{K$v==(Q3jOp>9TA>+S zwKj((Ck>8|1WJo+``ixfiwkhKBeW0B?Bng>UoL;Q<5DQ!0>52z1K+WJzD>EQ~FtgQR-Bx@@05h%jNi_=UeQ!>>8l+9| z2hy8D?79QTkvFNZXthvgH`5nX#d7oR<`p;YdDd|8lcF#~eDN1y8w+vnZdb&ot6SEA z@u)odtu0x`Q&z=>21p32d_9Q>TvZzoFR&NhKUo-~ooOanP#0fQG7W_f|Kc)-<;M@! zL$BzY|6YlE^t9GM&%9=g7=eTvU?*RFaZ2LsZweeuQi1~N&f?7hsY4vT9prB1JhN83$ zwXb26CRW6Lbq@@7q2_li(--b7iBG9L;SFqOk$uadb6jqEg-Tvo@;y%6XA0QSxs6W- zLO82vZ0`kuWF%GJ%5SMZkOH9cf>&fh2QBE=tp4-CSf(ay7G!k4Qx4J@H`7_#6VLrv zzuuH3VkLFNggM^QvRnMPzLbb*s;7G7=xk5JF=a)XY2HW9edH&uovE$!FEslT6b=5p zZy(*dg^jV8#{q(nnTx%`{lyDc+P3WuLM{VtDk*H_(SxP zM(&HyF~;n|9UWH|IMdhy+gYZ8#xnUGDUU1G5AMG8cWX@u#ZMvhu~;?B|r$LrGN z^%3iER<9$*U@kz`^^KNzE8NqWJ`!sKC#{-QL0c#(a)b83uPUWc?v6EjgThHnp1H!N ztP$|xm9AR5vp4YJ8ivf`8DB{)mwXMEh2*uar?Z#i{2#WgvfH_KYc=D#e6{bN%7HH? zYJa(Q?S!FQxnOsHj-|5lC5j`N_!JAz|XB^-7~>YJCj@w zSOUGTWVTi=7Tu#z7u*{fnXLwItUAxBjV5=iL5U+CjD{99kX_E6FY{G>$0$k>PLK1 z>y6%FIN7j$gYl=Sv^6+kSsv>wH7N0cbhOi>D;;;$BUeTly9eF4x)Qt@2bwob77sT@ zt~mS^#J)eL3gv(pJr5ro4qH};S+f_N+R+3Un>pQ+o{)NU#$zufsu-RXlPz$%Tg}FI zti0&uz}p@W_|tDuv{8tkNEUNOlUF`4*Dz*%4a&mIWp4b)sXzetRR16hKg9Be-dTmF(y*er*&u01F$I}a^&EP9psQmW`?tn#&pnCS;5<%RP zsl--H!c;;jp%1o{DkZB}-{u280;-Wl!f9IM%Rv2ohL_1T%qYN7;IsB4cp>q}=ZBuj;_E?ogsmN`omDSmM?_ zafQUfTOop=!tOo&d2s8N!>)$Eu~*M;*zqD9&k~Rsf=aNKZzS@q8V#39R2Op zROk;n-B!O@?~9*$wukI7DCx3Ut>ES#-Z6w$OYvf zbp(aP3m{Z^{h_UApVrqluaq#28ZPX-1bN>r>Qm~#=^`A)+`W?>M)0%7N0*~fi^E zpX3Pfupex$A|y5-DmZjAd!7=Z{xPwXLpJoj7ULsT;i{j+r=9>%qG}Ab9%YsvI&%BX zsY~!$F(6+^g^I$Htu@f$Bq2g)s~76=yMN?yQ4_$C!~RJf@Qf@7I{S6Q6U3eggKuga zBTbK3G9-__IM7K!XQe25uCJRSpNao#8WP<3_oh@LnHik&pJu7#l5Pfve=UmA%KsB} z?V9Y!yBpct9*ZvgAt=yrXeN1aLK`=L~N}0fN#nO0#QRFT60^7P`!++!8+2DMWmHPpc61yky7nWXA^lz4_21J6#8ly=JxpI46?im2p8R@bj?K8Fj zylbc)p6N7$NTvIk&c0bjHTuMU^ZDiP6KNFuYUT%l!3=9|cC4 z8cjGpm!IY74n|FT|J)@MwtiO}rQM?gz4LGT(w#q$A5vF9Vj4FK8J} zdJ14F92aM>N#E+%LCueYz)qfsIszrQWbs8S3Yq73MkjQTEU!Ott0ocy##+g@5@|n+ zYgA6i@LfgqFQSL8M-xo5<`xe$k!f_0w|o+3<-=BXF!}71s}7&>+*_ygX^Y##4YeRg!a_LlrGUs zN$7#pcv^ScnX8LW zISX&Bf-zYW#eZS`sO)1oVYE&DpvD`i;jE?ZlP8>|%Y0hyfm_fi;D#Sde?4omfhN1Z zA4NdI6PAE60v9Ano^uwd89d{QA@+tLJLEU@JKD+ktXFT?()fecJGbFuF&{9lm37RH#bLR zM2j7XY6N<4adrod^a-a~D->^cOqdP0nEEJ5l7*ky+5|XTY+grz|@=tuaReg=4;8*RB_FQ;er0*JT!M zGx230uNfnXf$%8x4c!S)RnM1+&v=w`__vUjIT}YB*2{Vl!IPHcZDxgg$}Ro!k;ryo zboT*hKXGl;Z@f)<*+tlBf#3^7$8#L|L0v9ZLC|P{MyT2D%x7jj&#n6lI|7CH6ZKuE z=cdVDs{I9kTGbDdd!bNX1Y1-xHSop-KcsbPeUg_tpe9r5LArd0fwdPQj0rfP^)D4^ zUHaK*${}~YZfZwt)E!tPb8$=N9Ltt(OSD52Osu~jQDhxgoJ}r++<~p$53We1ikQ`` zcSmuRlZYZXz@Pj{vg_Wo*Hb`pCMiB2OV@p?Zz};p8`;qmqt&)$71??OZYC#-qvY5S z70)U~QjX{;HY`ctX!I0#8o3DlHg=?HQo@-(%je5-D}W_nlEDL?*UL%O3>Bq$CRw%e zH;6D0Y(ZJS+2K84OM3ZoWa61WpntAzewK1wRHjilRP6x!f=k?59;NHQvPxZSpJ%7VQcPXE#tj;`%KKPgpR%5Z&BM zfuQ5hmChsVntrObDLtaCT1iH*MG^ykdUEY#Y`})M^T;%pW$(;)2n5O4;x9d*! z`h0$mMhjzZ@#gj2A`1Qthh9uDIWk<=*Wr7>};wN3&QNd?U7yAnH>ujiMuA#KQ9(%_Ncl9Ki879{BJHI^3S%ze3ZrHA=?8z!$d8N*p$Pfa|(Y2f7>3nTooVw%C~%@j+}Gb4-%?O9@i zy%USMSo-dVuKo1E+<;HF7tS+%^3{ICha7Tip!xhnQ>lsgoV3Nm?g#WS?LPlPP|AX+ z*2?wn{R_(n0JcQQh|D?-oVdvc$QCoE(GqvK7}L!*#Tn zMIB08*-8$BZkHNq#U0e0EUFeSlG|L7GommF%EIr%CuX-1btTg7#ERxHOR(|hiMvZW zr%}CnfiZ}Y$k`E`Uj$obXS(j|DFT2fKQ86O^9~VUW%-;6JV!(5+r{8eTJKR-0pUWE(qhNwx6Ur*!x%gf0P-ZFG%EH>E3#k{Z+IEv8GtJ!0@$mZRd7DcXK+R=8M zJu(;G)nIH>8gHzpeM1t+zjnI*l6ri#)}Huv@#>X86Vji+B2j-sxQEXCz36&3*j)HZ z$9#9Mj{|UW7wf-14HDH_SKF5s%c(nFrz`Rm^{3w9qz*?g0)MY=lfml`ej+Q$38f;b zWy0=%e165Ktt;A2z!*M=&h6Fxs;79avP|~>$IRK{XA(;mZjlsi%w)9~cwQGTTa z7LQ%I<+rOE{po6r{DII5KY|L!b;_0ybp=K0U3U4iyUY6HcIQ@;!@sSb2YCjq7i5_{ z!#V}ltynM+N&viOhyjy66xhNO;&La=>h_iaj;o$c2oFbFj%WD`m_$;biC`*%UuvcM zgongt;T=%l`1kwW>=p+m46 zyMzHQtiz>}?d#^RT#p0m^6-hw`I7aU0X5!^N?m;zRo)j*W^b{}6aREww){JD_%SC8 z81QzWyObv&zsHWN=RVDRf8?)ZB4_z?_ag44AMhKar%JoygH|M;Fch(bwEg}X^|Hz7 zhzHFba8e}Q$vFy%idjoY*Nxhkfh^F7c|5yIhgJ5cy<=W^F+%+t=f(i8Rnw1*s^A_+ z8kr|hiqIl+pBhUgulQo^nE={E=pQJXuvd zr)C_2sEn|X;74(A?BBPYO7@i5+lf45GrYdw+%+@`KzoAMSCF72A zt+kg!C<2~=P|Nc+UqHeSKbjUw{;Zt2gaL(%iRS~VFv6g&o8EJtLi6nE(TocdZ{7OJ zHtuBI0U023Tq1L{%+klMR&q!rJa$}?!U-kWq^0iTFv7d*%?N2Tgsb1n_zKhUU ztp)UELi|b-eaJWUOcxLCVk|E%=y9QR*6)3!ZJ%r!Pt4y@>xkqISl3GhBiZ^TT!4S5 zbp0Zpe3Ff3@IO?_yD{|-lWtmYbN3CQa36;(Ps1IPK6{Rsm4ea+`hrB?BMLQ-l0_Ph zw+DAP*wKdf7=E#-o{9ZTe9YoO!@RT0bO~fjPYws{fBI~X(%N-VBwqaBGXB5ZnoO&6 zbN6ofCpDI9q>Kd|S+rt=G5?s?P-p5$R{yURYigbi_Wswyk%6%s#Qwhy|DUe6#GoM` z78mDrsa^~Hacuktpp!3M2g&wbdjXYX(Ot^7^n*R}xBA2`9-hhl+c;p$^Z&lKW|cN0c4nn_FHUn+<=2E+YflSQ@nu$$>gHt+4p4h9c((sD@jp& zJvhMSs8IFjaBicJKMOCf8+M-5e#snu{^9=Q2*3;QyeMY-~HT@N8-g%+z6m%&zYeiV20b1L8Z|OC9J9%z0AEbJXU4v)ac&= zl=+)4ndvlPa7&)|QA#_X>MF{r-xcmPr3)ivG^rtlkhhe!RsqgMO$kq3Hk(8@n{@2! zbF!DI$C>@7gRvdm?+AS$%40$2ewy|gi~uB>+|FG6Y%vM_9oHLBwEoF;Wvg?78HOiE zUAd_|wz_`d--dH;?w$jJg+Oj|SxiCbroNN_U3tQSV*!(*-ElntC(`l;o^zYjmyN@?pr@*i7l~tzy=CzFl2&FQ;Fq>w zqLmx^c#(w-h9?%}-Ud3Hj#ar5o393j(ipIq%}6ql{VEkqlWtLIx|iQT-KV-jZY~}C zFItdVO+lR0hF$a+cp@p1G^tzPHF!G>FgX=vnOkE$!}w3yYXyJpWDT&u zluw8GYp{0 znW`WxY#nte?E?l!R&)**iYhvc%@$OPCI_~arv(rE_>ZiMU8?>^)+t8IU&}h(Z{Pzy zQ+!5SuMOSowzxM8A8vN@SXD15?B+w<*xi5`;3tXGO+#eW9d}W)YL|!mqmdC*B;7=b zdrJU?Ba6$+PVGNHi+X+1H6i)5u zosx1+yl@cgj7ic?Y|;|FMR_ei04Ilm{6n1N<#{3Mx`&E=cKBbex)L;? zMjeh-jC?Jj)TRC-s#mfaC%yHruClB3@S;ig=27M2n92pLYNwcR? z&_2`LKcJdaw00Q}wjXnV3`wO0@c{UueP)flI@X75GQmsQ5@N6R*Go6UWv#p~!CNz% z_-NLheY-S2WLXB`?(Xg9$BP@IYA}szJi~pQF+U9dLI0msgS8RLGR4|4U@Zih-ZJ#M z3q1jQxnscr;JNee9f4teNfb}*66b!blQzZ3@x3eKC;~r65;5iRufq_)dZ;4i?uEZ> z^)D;1Hd}ANjd_ySE+n@fT=^2~tu@}^uDEIq9WpR}nHHM{9oz!czu_YaNnDRr!+Rg$ zljgz7Vo;U{0hVMlr_)0on3sh4s+<~(>Tx{Z&C{Hf*?~_qY^ocjw(2dk$$_cJ*qcUL zx7-PP@Z9Ce1s7;ky6;WRpEpjV-yrt{hK_lM{kMVQnZ4Acnj_IZ_%t3|i`UzkqGG&G jFz@cU{SMhap7^NC90t)MU z@cJ}Tg|Q)0Ni$W{L2o%yNt0iayXVK%%YPG}EQt7IL1W_wjM(@A7vj#R#0HlRAtq{P z9k{uD13CPWf);6KC1g6?Xv}iD(U@U^egg;kNd(&ySa~Rz%Xi>=c*;P{8V)FB4F}mC zaqX)dNFEUFK`7vidiT0WMdvvTTI+3!>)FgH$VwN$b z7;6>dW>c)CX}6Ja>>#UH7Hl2X(pm=WG7*TG6dRdn8&hP+-9NtfmtROlur2TR$nSh+ ze)IC)yDxL!Iq$uD?z!iln<#%)W8t+L7=JfBau0L41EI!0T+Z<1oAD$6 zukYaPIMca3SQrD$Y6f~Be8u07Twq5nupcOb>e&i2ZAYW+%UWP-nY<~tzJqRUtA&;& zvFt-S7AjqjgUL8Rnktpmp=>LJC4VZTA7Y^&SkeMbWhy%r^$lzHp*VktnGhzqe3QnG zTA&x`h2}Z1A9>~{>JU!>^JCc~K>0?X5O$X7*dCPmCh27Wf2mJvuodObW(Gpbcu< z;5lF^O8LYzCSqu6s261AkdezSBrAF(%giq$(?dws zOq1-FB3;zB0d2rYH-2+QH_!?6$+)dQ0KY=tub%?d-3lWr?uYVj)LA(O#p`u>A?o1d zqU!mI#{eh9ZwLKRh|&m+1>T5%AF0t$@6nvp&T*1qG+H%mun~WJ1JHAZ@>TV^D9rFi zJ=cT&SK z3X&C<4v}G$=@m%UO>>p;;ZmfF%*A0re#kJ5gsUWb+irn=pcATgX-f%kA5?V%ThL_Q zScU>9-V84-m$!fT0W7R=PjDi*0h}Pe1^5swXoZ$iJ?w?R1YlD9y#h2~VYR;i&M@Lz zSeOXRZH67?Y7Yv?wgDwAu(=E##=@5dJ^NvezXxd|ln1*P3!fi!>A|!`8J~19(XTbe6#= z-~eZyJ?(#_iw>l}cI41nftKS1HRdCT#vE$*$0K7eb8am#qYjR)Q>e?CMgfKsJ?LI9 z0~XZ5%j@LHJ&9y9p6ntDFChoX$wB)okR#;)vYQIx|8mktxHcNXn=G&cDZewGoQe#B zQ^*EDx_pEDcn{Ko8^8(i1%lc07TV{+)c*kHp$C6|5^xCqWh3x5Jb$N#5#PX#U}t#n zX8esrArQOQ!n}HDUIXRzuzR)6|6x#BC%ueAtL(` zPpup1|8oU!dA$B$yzWbR@U6RzU=L#Y<9p|sY5%h>>Quy{lc15?5+V6>F-eAbkuai28fFA*K ztMv&xft*>r$g>N`BAXry&jTjQu)Doc9i4yUz%hVA8FQ5tiQYm^sjSdFQz#i6M>4s+ zF&e*tXHV@AA)_zbc*vEkUf+0>49FyZ0gQ@2`;8TJC5(E1IDun$;M zjf|-t2ut%rb{8VnXn{`xKS$4fW34%p#hB} zkLAj_qqz$ z1k|+X_{FizqQqra;h*!owB=Rk^8J-r|$s62Mw5{Ck;3u6~U^c<+zr-jCAS zbO04VO<9Z;M)8mb@X2t_g^fLKVG^*gS#d8JF`^J&1|>t!7be7eE|d(q-o5l`ScL@^N11=mmkwS*I&sp8J*a%Z zg&P#%GSta`0%b#+wgKpg<()+E5Qqe@8Vf8!v0wYpgogKPsKeG<;EyN-Vg{NR@wCo0 zAj6>$&6)dOJQTvYu&~V*n2m-rZa^*dRNx?l)xoU60#_i{Zwc@dG$gVQ!g7Ds)5tO` z)B#0p=zCUzR%n0t7_c?#2|g2dV__!pU~)CE2e<}!0Ydfg*16SM7<$jG)ry3;>nz`P ztFXWl;1?)s&<p9p`FK5@<)estj*=h^x8x#q&XbsZq zG+?_z#Bx~myuc0M^UOeu@0dXc-_~Zp0EU5N*g!TGvPOSKa3*D7U);J8>|7{VqXi}* zm)C4$=*CG=12Mo8;_>NmI|DfCvA}8O-MqbLGk~qm0w>6h1A|;+BhDT^aiL>%7Bcrb zK$OMV?)@*3xsw~LHtMWD{!SqWSV7hRrXSe{1)Me}KioTmX}}F&$8j9TaqyfV8{8hu<$w-_F&;LU!){)9*eSn9SgYp9mjE;_lT!KbDa0U&#-U=IEL1Bn6U*o z0!)VfrC^?;`MeUaP%ud5FE7>F856Y2CtUuHU& zp95|M=0HIO*irXJo-gdEg@OuT4wCujq=V5&Czq>~%inPv$2lu*0H+k&XTiEGyp4tb z@YM?^8=tjDEU8PFT_>?#7IY572tha#CwZLbAX5f0XzIzvhrLLDGu`L!T zLStClfpXw+=&gpo87SpCNsa7-M9gq-*^Z_iV5q2u@~rt7e5PE1Hbnn z#hmaK@NFBN8RxL021s1jujo&h0mK%S+ zj^m^oH-OX5)xaXSsu9|O-dxuw57`5>0t>2vtw0|zUB+)tE9OWC(~(ZLN=L0oXHIf_ z3@8DZ2|NY7nA7Swj^msaH-OX5Wk3(mr#59rj;oW8T!W$==m)+6{0s$}I_Y2v(#cnV ze(CC(oK`6R=m36~*|`x|l)Jh(j^lrv3vK|Xo$bIbc(Dq;2wa)#`s67m0X~g}+K)n* z=icA65atErDALWRqpqAp>5e}@9^hTMtBd0}&be?=t}Ec2g<{|oTs0cHR>}$KB+Ee1 z^Is|0v7XVr1ui4x!ipisL3e0ocQ90&G;+`v}@Q^BTM2xWiTQM9Kl@EU(`6nXD2 zg>a*HC>_U17WV+Boo9e&_2+g54Kq54VFcR+>|KR=AVr?*H%(YY%m~ph9qqzb!2Mt{XMZJ3rt1%>aGQ5>t|d1eR3QpSv(C|f>?t-@?rHmcty@|&URa1 z3^dPDDDaoPVb2L2SlAB~0keOrQJ`r%a1vUULD^QI07B`X>gNYoSkj`h4=vNNFS#C1 zGja)+ zpd{wKC^TYzEPMnumdjyZwlf~v6Eoj9PC|GZwEV_Bz)A8ZFe_{9X0U$-3(Sh=hw?md z7(RiFFDEx#MzE1U8_-q@JO?ZV%3vBmDR2m^&B70`U~So753%ensBF{kVJtlCDeVU2 zkdX_!fTil}4VGa>rW^uFqs+@xmgl6CHee)f{N{>opc5tJ*jNq+>VaRO1!8^*-POQe z=r4xua&=aY0qcw7KPZ2U9URAToCNR~;G`K1+yFM%__+bK`0qe{l`ff1u<1$E&p9L4 z5v(Jlx5+3xr5olpq4a2<0j9?|?VGaKT?%jt#XCklSGL8IH)o%NeDMkoHv9+Vka_;6 z0H>nN2FY+hrdI%4qs)JZ3Qo>mdR?B#FpYdH%Km9A^dn<2)pB3Pq^u+sJDIL`US4d8^ZjTRUU&2yoA2Wk-t7-$7rN}y~r*h3aVW%lEL zr#I-S;x>ZWdJBAh(7`u=vB0;0K1D`wBzyWGXqM1y;KyiUV-K(sDxX2_%nw85HVfhA z;jM3Lv(cWb{s4af1(iueK~%sZ;8oxd(1PRvuoGAe9FH;^B*S)qUn0-@m&wXJa&rfS zwZmI>7Yd&u*r$O1L8Bk9qQR{ND3xO;atfaS=AsCeR^q|2zy}krvg0^;h=)KVfVIRW zjZ2`s6V{gi2eQA05-95gZUJV-@=p5cKt|e&z;A&SXf}Tks4?#xwErS79vOR?b8De) zK|KFFXB-6>R`j5ICEoj5vKCP>l2K+6g_j1M%j~Z}vVIZCz9WG;JAW2`Pq2T8p+h^6 z%AQ1_4`X7PQ^3WU3kp!jCLi7d$8mCwdw`SR&G;J$jE1$lp?)5$X@>f8SiL)*|HGiN zPI?)K*4uyWjQd^jSUYf7d1yBktC8Ey9MVxvZ@aFC~yKAZjl-@ zsw+f;05da%+i?TfahybO12_qephh|~wAU+J7~+4n7kNM4hddxhhW-O5RTKd~g6cA; zjoBRrRsk5H%{Ua<@EQtH-A~rATe$^UbjM=a+AgT5O!5YDOGPC-+8pow7?Q;wpz(G+ z{*#eGbObqs55*#kK<`Q~8b3cYNC!ScG_^dwPDXD(N(eC?rPQ8c;o8=3jy#V+)un+ix z>(fa9PlJ}i)4iqISgcEYNqdRHz2>KcK?@Z>~=d4J7y=_G_3!1;|EzzOj{ zO#L*5Y>3+(1iL>TA4fLy*A3uwV|5m|1L%O3nKIBOp$7dng586KLS(EB4QEuIT6s4| zA|tpR8GiZV#e574uc1MY{mAg0hKzsO6GO_5LvlTijNJc>-s7XlI4;|d1bV+OqL60p z#lqSRz(Ul^-v;4+-LJf+GYzZ07gM=5mfJm+BtvczuIZx z5ZQaKj^PYE17Z2u4WHWxwhRl8wnA+wS{wW$4CDfKQp_^cTkPiaNf6yAJZv#gm7A(L zj+1|Q8nguXJ{Fh+%?p7(XeuUV_Sd$lSjU?e0yE$dUm+~r>;PU-rib}JU8&mcW$#6A zUBKZu5$t7{a2~3eRwe+v9PfYqFxkN9b6^=379*L@M>^mYq!TBVd?)4u-cX2wzK6Q` zPXMQ2!!(VUe8<0kj^iYN8^Gt8N3bvr*m%8`Gj5zMXK%wAoo`s9{l?ikzwvry$#Nq& z<&09;!*j?G+Yc<^9F5>kpbKi}YCz!YOXa}4I}dbzHx?$Nd!B}5Ko@`6lydLFGAt}X zvYwA*KMArqwVc#(KNhY7u0^rhbOPP5x-@DSKK}kZco!VU$t@lOe4cp# z3zLACkzw18;u?>UjRBqzk57-=87RilV}aAlyBWGoXVKd|SU5p;6d2?f8^Q3O%ykbI zGWVJxBa5@$`(Gk+CpR}_I(7Z=cZzJ*$NLEO)wpc(n0RckN9HcqsdJw37~uTo{{c*x VBdbs;W@`Wd002ovPDHLkV1lD*