From 2999966fc028224b26a086d379d0f2a0311c7de8 Mon Sep 17 00:00:00 2001 From: ElCeejo Date: Tue, 30 Aug 2022 18:45:58 -0700 Subject: [PATCH] Libri improvements --- api/api.lua | 235 +++++++++++++----------------- api/behaviors.lua | 9 +- api/libri.lua | 26 +--- craftitems.lua | 182 ++++++++--------------- textures/wolf/animalia_wolf_1.png | Bin 11357 -> 12031 bytes 5 files changed, 181 insertions(+), 271 deletions(-) diff --git a/api/api.lua b/api/api.lua index 56edac8..aecab96 100644 --- a/api/api.lua +++ b/api/api.lua @@ -195,7 +195,9 @@ function animalia.head_tracking(self) end animalia.move_head(self, tyaw, dir.y) return - elseif self:timer(random(6, 12)) then + elseif self:timer(6) + and random(4) < 2 then + local players = creatura.get_nearby_players(self, 6) self.head_tracking = #players > 0 and players[random(#players)] end @@ -220,69 +222,16 @@ end ------------------------ -- Environment Access -- ------------------------ - -function animalia.set_nametag(self, clicker) - local plyr_name = clicker and clicker:get_player_name() - if not plyr_name then return end - local item = clicker:get_wielded_item() - if item - and item:get_name() ~= "animalia:nametag" then - return - end - local name = item:get_meta():get_string("name") - if not name - or name == "" then - return - end - self.nametag = self:memorize("nametag", name) - self.despawn_after = self:memorize("despawn_after", nil) - activate_nametag(self) - if not minetest.is_creative_enabled(plyr_name) then - item:take_item() - clicker:set_wielded_item(item) - end - return true -end - -function animalia.get_group_positions(name, pos, radius) - local objects = minetest.get_objects_in_area(vec_sub(pos, radius), vec_add(pos, radius)) - local group = {} - for i = 1, #objects do - local object = objects[i] - if object - and object:get_luaentity() - and object:get_luaentity().name == name then - table.insert(group, object:get_pos()) - end - end - return group -end - -function animalia.get_group(self) +function animalia.get_nearby_mate(self) local pos = self.object:get_pos() - local radius = self.tracking_range - local objects = minetest.get_objects_in_area(vec_sub(pos, radius), vec_add(pos, radius)) - local group = {} - for i = 1, #objects do - local object = objects[i] - if object - and object ~= self.object - and object:get_luaentity() - and object:get_luaentity().name == self.name then - table.insert(group, object) - end - end - return group -end - -function animalia.get_nearby_mate(self, name) - local objects = minetest.get_objects_inside_radius(self:get_center_pos(), self.tracking_range) + if not pos then return end + local objects = creatura.get_nearby_objects(self, self.name) for _, object in ipairs(objects) do - if creatura.is_alive(object) - and not object:is_player() - and object:get_luaentity().name == name - and object:get_luaentity().gender ~= self.gender - and object:get_luaentity().breeding then + local obj_pos = object and object:get_pos() + local ent = obj_pos and object:get_luaentity() + if obj_pos + and ent.gender ~= self.gender + and ent.breeding then return object end end @@ -313,11 +262,6 @@ function animalia.random_drop_item(self, item, chance) end end -function animalia.protect_from_despawn(self) - self._despawn = self:memorize("_despawn", false) - self.despawn_after = self:memorize("despawn_after", false) -end - --------------- -- Particles -- --------------- @@ -367,9 +311,38 @@ function animalia.particle_spawner(pos, texture, type, min_pos, max_pos) end end --------------- --- Entities -- --------------- +---------- +-- Mobs -- +---------- + +function animalia.protect_from_despawn(self) + self._despawn = self:memorize("_despawn", false) + self.despawn_after = self:memorize("despawn_after", false) +end + +function animalia.set_nametag(self, clicker) + local plyr_name = clicker and clicker:get_player_name() + if not plyr_name then return end + local item = clicker:get_wielded_item() + if item + and item:get_name() ~= "animalia:nametag" then + return + end + local name = item:get_meta():get_string("name") + if not name + or name == "" then + return + end + self.nametag = self:memorize("nametag", name) + self.despawn_after = self:memorize("despawn_after", nil) + activate_nametag(self) + if not minetest.is_creative_enabled(plyr_name) then + item:take_item() + clicker:set_wielded_item(item) + end + return true +end + function animalia.initialize_api(self) self.gender = self:recall("gender") or nil @@ -467,55 +440,73 @@ function animalia.add_trust(self, player, amount) self:memorize("trust", self.trust) end -function animalia.feed(self, player, tame, breed) - local plyr_name = clicker and clicker:get_player_name() - if not plyr_name then return end - local item, item_name = self:follow_wielded_item(player) +function animalia.feed(self, clicker, breed, tame) + local yaw = self.object:get_yaw() + local pos = self.object:get_pos() + if not pos then return end + local name = clicker:is_player() and clicker:get_player_name() + local item, item_name = self:follow_wielded_item(clicker) if item_name then - if not minetest.is_creative_enabled(plyr_name) then + -- Eat Animation + local offset_h = self.head_data.pivot_h + local offset_v = self.head_data.pivot_v + local head_pos = { + x = pos.x + sin(yaw) * -offset_h, + y = pos.y + offset_v, + z = pos.z + cos(yaw) * offset_h + } + local def = minetest.registered_items[item_name] + if def.inventory_image then + minetest.add_particlespawner({ + pos = head_pos, + time = 0.1, + amount = 3, + collisiondetection = true, + collision_removal = true, + vel = {min = {x = -1, y = 3, z = -1}, max = {x = 1, y = 4, z = 1}}, + acc = {x = 0, y = -9.8, z = 0}, + size = {min = 2, max = 4}, + texture = def.inventory_image + }) + end + -- Increase Health + local feed_no = (self.feed_no or 0) + 1 + local max_hp = self.max_health + local hp = self.hp + hp = hp + (max_hp / 5) + if hp > max_hp then hp = max_hp end + self.hp = hp + -- Tame/Breed + if feed_no >= 5 then + feed_no = 0 + if tame then + self.owner = self:memorize("owner", name) + minetest.add_particlespawner({ + pos = {min = vec_sub(pos, self.width), max = vec_add(pos, self.width)}, + time = 0.1, + amount = 12, + vel = {min = {x = 0, y = 3, z = 0}, max = {x = 0, y = 4, z = 0}}, + size = {min = 4, max = 6}, + glow = 16, + texture = "creatura_particle_green.png" + }) + end + if breed + and self.owner + and self.owner == name then + -- TODO: Breeding + end + self._despawn = self:memorize("_despawn", false) + self.despawn_after = self:memorize("despawn_after", false) + end + self.feed_no = feed_no + -- Take item + if not minetest.is_creative_enabled(name) then item:take_item() - player:set_wielded_item(item) + clicker:set_wielded_item(item) end - if self.hp < self.max_health then - self:heal(self.max_health / 5) - end - self.food = self.food + 1 - if self.food >= 5 then - local pos = self:get_center_pos() - local minp = vec_sub(pos, 1) - local maxp = vec_add(pos, 1) - self.food = 0 - local follow = self.follow - if type(follow) == "table" then - follow = follow[1] - end - if tame - and not self.owner - and (follow == item_name) then - self.owner = self:memorize("owner", player:get_player_name()) - local name = correct_name(self.name) - minetest.chat_send_player(player:get_player_name(), name .. " has been tamed!") - if self.logic then - self:clear_task() - end - animalia.particle_spawner(pos, "creatura_particle_green.png", "float", minp, maxp) - if not animalia.pets[self.owner][self.object] then - table.insert(animalia.pets[self.owner], self.object) - end - end - if breed then - if self.breeding then return false end - if self.breeding_cooldown <= 0 then - self.breeding = true - self.breeding_cooldown = 60 - animalia.particle_spawner(pos, "heart.png", "float", minp, maxp) - end - end - end - animalia.protect_from_despawn(self) return true end - return false end function animalia.mount(self, player, params) @@ -592,22 +583,6 @@ minetest.register_on_mods_loaded(function() end end) -local spawn_biomes = { - ["animalia:bat"] = "cave", - ["animalia:bird"] = "temperate", - ["animalia:cat"] = "urban", - ["animalia:chicken"] = "tropical", - ["animalia:cow"] = "grassland", - ["animalia:tropical_fish"] = "ocean", - ["animalia:frog"] = "swamp", - ["animalia:horse"] = "grassland", - ["animalia:pig"] = "temperate", - ["animalia:reindeer"] = "boreal", - ["animalia:sheep"] = "grassland", - ["animalia:turkey"] = "boreal", - ["animalia:wolf"] = "boreal", -} - animalia.register_biome_group("temperate", { name_kw = "", turf_kw = "grass", diff --git a/api/behaviors.lua b/api/behaviors.lua index 967ef18..9242a4c 100644 --- a/api/behaviors.lua +++ b/api/behaviors.lua @@ -972,10 +972,17 @@ creatura.register_utility("animalia:attack_target", function(self, target) local tgt_alive, _, tgt_pos = _self:get_target(target) if not tgt_alive then return true end local dist = vec_dist(pos, tgt_pos) - if dist < width + 1 + local punch_cooldown = self.punch_cooldown or 0 + if punch_cooldown > 0 then + punch_cooldown = punch_cooldown - self.dtime + end + self.punch_cooldown = punch_cooldown + if punch_cooldown <= 0 + and dist < width + 1 and not punch_init then punch_init = true animalia.action_punch(_self, target) + self.punch_cooldown = 3 end if not _self:get_action() then if punch_init then return true end diff --git a/api/libri.lua b/api/libri.lua index 107920c..078e6ae 100644 --- a/api/libri.lua +++ b/api/libri.lua @@ -101,7 +101,7 @@ local function generate_page(mob) element_type = "label", center_text = true, font_size = 20, - offset = {x = 9, y = 1.5}, + offset = {x = 8, y = 1.5}, file = "animalia_libri_" .. name .. ".txt" }, { -- Image @@ -200,7 +200,7 @@ minetest.register_on_mods_loaded(function() element_type = "label", center_text = true, font_size = 24, - offset = {x = 1, y = 1.5}, + offset = {x = 0, y = 1.5}, file = "animalia_libri_home.txt" }, { @@ -228,7 +228,7 @@ minetest.register_on_mods_loaded(function() element_type = "label", center_text = true, font_size = 20, - offset = {x = 9, y = 1.5}, + offset = {x = 8, y = 1.5}, file = "animalia_libri_tropical_fish.txt" }, { -- Image @@ -366,31 +366,21 @@ function libri.render_element(def, meta, playername) if def.element_type == "label" then local font_size_x = (animalia.libri_font_size[playername] or 1) local font_size = (def.font_size or 16) * font_size_x - form = form .. "style_type[label;font_size=" .. font_size .. "]" if def.file then local filename = path .. "/libri/" .. def.file local file = io.open(filename) if file then local i = 0 + local full_text = "" for line in file:lines() do - i = i + 1 - local center_offset = 0 - local max_length = 42 - local line_length = line:len() - if line_length > max_length then line_length = max_length end - local total_line_area = font_size * line_length - local total_max_area = font_size * max_length - if def.center_text then - center_offset = ((total_max_area - total_line_area) / 100) * 0.3 - end - local line_unit = (max_length * 0.075) - local align_x = (offset_x + line_unit - (line_unit * font_size_x)) + center_offset - local align_y = offset_y + (page_spacing * font_size_x) * i - form = form .. "label[" .. align_x .. "," .. align_y .. ";" .. color("#000000", line .. "\n") .. "]" + full_text = full_text .. line .. "\n" end + local total_offset = (offset_x + (0.35 - 0.35 * font_size_x)) .. "," .. offset_y + form = form .. "hypertext[" .. total_offset .. ";8,9;text;" .. full_text .. "]" file:close() end else + form = form .. "style_type[label;font_size=" .. font_size .. "]" local line = def.text form = form .. "label[" .. offset_x .. "," .. offset_y .. ";" .. color("#000000", line .. "\n") .. "]" end diff --git a/craftitems.lua b/craftitems.lua index 28ee1a1..4907571 100644 --- a/craftitems.lua +++ b/craftitems.lua @@ -390,6 +390,7 @@ minetest.register_node("animalia:nest_song_bird", { mesh = "animalia_nest.obj", tiles = {"animalia_nest.png"}, sunlight_propagates = true, + walkable = false, stack_max = 1, groups = {snappy = 3, flammable = 3}, selection_box = { @@ -579,119 +580,20 @@ minetest.register_node("animalia:guano", { end end }) - ------------ --- Libri -- ------------ - -animalia.libri_pages = {} - -function animalia.show_libri_main_form(player, pages, group) - group = group or 1 - local basic_form = table.concat({ - "formspec_version[3]", - "size[16,10]", - "background[-0.7,-0.5;17.5,11.5;animalia_libri_bg.png]" - }, "") - if group == 1 then - if pages[1] then - basic_form = basic_form .. "button[1.75,1.5;4,1;".. pages[1].form .."]" - end - if pages[2] then - basic_form = basic_form .. "button[1.75,3.5;4,1;".. pages[2].form .."]" - end - if pages[3] then - basic_form = basic_form .. "button[1.75,5.5;4,1;".. pages[3].form .."]" - end - if pages[4] then - basic_form = basic_form .. "button[1.75,7.5;4,1;".. pages[4].form .."]" - end - if pages[5] then - basic_form = basic_form .. "button[10.25,1.5;4,1;".. pages[5].form .."]" - end - if pages[6] then - basic_form = basic_form .. "button[10.25,3.5;4,1;".. pages[6].form .."]" - end - if pages[7] then - basic_form = basic_form .. "button[10.25,5.5;4,1;".. pages[7].form .."]" - end - if pages[8] then - basic_form = basic_form .. "button[10.25,7.5;4,1;".. pages[8].form .."]" - end - if pages[9] then - basic_form = basic_form .. "button[12.25,9;1.5,1;btn_next;Next Page]" - end - elseif group == 2 then - if pages[9] then - basic_form = basic_form .. "button[1.75,1.5;4,1;".. pages[9].form .."]" - end - if pages[10] then - basic_form = basic_form .. "button[1.75,3.5;4,1;".. pages[10].form .."]" - end - if pages[11] then - basic_form = basic_form .. "button[1.75,5.5;4,1;".. pages[11].form .."]" - end - if pages[12] then - basic_form = basic_form .. "button[1.75,7.5;4,1;".. pages[12].form .."]" - end - if pages[13] then - basic_form = basic_form .. "button[10.25,1.5;4,1;".. pages[13].form .."]" - end - if pages[14] then - basic_form = basic_form .. "button[10.25,3.5;4,1;".. pages[14].form .."]" - end - if pages[15] then - basic_form = basic_form .. "button[10.25,5.5;4,1;".. pages[15].form .."]" - end - if pages[16] then - basic_form = basic_form .. "button[10.25,7.5;4,1;".. pages[16].form .."]" - end - end - animalia.libri_pages[player:get_player_name()] = pages - minetest.show_formspec(player:get_player_name(), "animalia:libri_main", basic_form) -end - ---[[minetest.register_craftitem("animalia:libri_animalia", { - description = "Libri Animalia", - inventory_image = "animalia_libri_animalia.png", - stack_max = 1, - on_place = function(itemstack, player, pointed_thing) - if pointed_thing and pointed_thing.type == "object" then return end - local meta = itemstack:get_meta() - local pages = minetest.deserialize(meta:get_string("pages")) - if not pages - or #pages < 1 then return end - animalia.show_libri_main_form(player, pages) - end, - on_secondary_use = function(itemstack, player, pointed_thing) - if pointed_thing and pointed_thing.type == "object" then return end - local meta = itemstack:get_meta() - local pages = minetest.deserialize(meta:get_string("pages")) - if not pages - or #pages < 1 then return end - animalia.show_libri_main_form(player, pages) - end -})]] - -------------- -- Crafting -- -------------- +local steel_ingot = "default:steel_ingot" + minetest.register_on_mods_loaded(function() + if minetest.registered_items[steel_ingot] then return end for name, def in pairs(minetest.registered_items) do - if string.find(name, "ingot") - and string.find(name, "steel") then - if not def.groups then - def.groups = {} - end - def.groups["steel_ingot"] = 1 - minetest.register_item(":" .. name, def) - elseif string.find(name, "string") then - if not def.groups then - def.groups = {} - end - def.groups["string"] = 1 - minetest.register_item(":" .. name, def) + if name:find("ingot") + and (name:find("steel") + or name:find("iron")) then + steel_ingot = name + break end end end) @@ -699,8 +601,17 @@ end) minetest.register_craft({ output = "animalia:cat_toy", recipe = { - {"", "", "group:string"}, - {"", "group:stick", "group:string"}, + {"", "", "group:thread"}, + {"", "group:stick", "group:thread"}, + {"group:stick", "", "group:feather"} + } +}) + +minetest.register_craft({ + output = "animalia:cat_toy", + recipe = { + {"", "", "farming:string"}, + {"", "group:stick", "farming:string"}, {"group:stick", "", "group:feather"} } }) @@ -708,36 +619,63 @@ minetest.register_craft({ minetest.register_craft({ output = "animalia:lasso", recipe = { - {"", "group:string", "group:string"}, - {"", "group:leather", "group:string"}, - {"group:string", "", ""} + {"", "group:thread", "group:thread"}, + {"", "group:leather", "group:thread"}, + {"group:thread", "", ""} + } +}) + +minetest.register_craft({ + output = "animalia:lasso", + recipe = { + {"", "farming:string", "farming:string"}, + {"", "group:leather", "farming:string"}, + {"farming:string", "", ""} } }) minetest.register_craft({ output = "animalia:net", recipe = { - {"group:string", "", "group:string"}, - {"group:string", "", "group:string"}, - {"group:stick", "group:string", ""} + {"group:thread", "", "group:thread"}, + {"group:thread", "", "group:thread"}, + {"group:stick", "group:thread", ""} } }) +minetest.register_craft({ + output = "animalia:net", + recipe = { + {"farming:string", "", "farming:string"}, + {"farming:string", "", "farming:string"}, + {"group:stick", "farming:string", ""} + } +}) minetest.register_craft({ output = "animalia:saddle", recipe = { {"group:leather", "group:leather", "group:leather"}, - {"group:leather", "group:steel_ingot", "group:leather"}, - {"group:string", "", "group:string"} + {"group:leather", steel_ingot, "group:leather"}, + {"group:thread", "", "group:thread"} } }) +minetest.register_craft({ + output = "animalia:saddle", + recipe = { + {"group:leather", "group:leather", "group:leather"}, + {"group:leather", steel_ingot, "group:leather"}, + {"farming:string", "", "farming:string"} + } +}) + + minetest.register_craft({ output = "animalia:shears", recipe = { - {"", "group:steel_ingot", ""}, - {"", "group:leather", "group:steel_ingot"} + {"", steel_ingot, ""}, + {"", "group:leather", steel_ingot} } }) @@ -772,9 +710,9 @@ minetest.register_on_craft(function(itemstack, _, old_craft_grid) if itemstack:get_name() == "animalia:libri_animalia" and itemstack:get_count() > 1 then for _, old_libri in pairs(old_craft_grid) do - if old_libri:get_meta():get_string("pages") then - local pages = old_libri:get_meta():get_string("pages") - itemstack:get_meta():set_string("pages", pages) + if old_libri:get_meta():get_string("chapters") then + local chapters = old_libri:get_meta():get_string("chapters") + itemstack:get_meta():set_string("chapters", chapters) return itemstack end end diff --git a/textures/wolf/animalia_wolf_1.png b/textures/wolf/animalia_wolf_1.png index ca9b40b3de59a133a43a6d50c8b9bb81032179a2..33d09a452bedfdff400fdbff06892f5961a93efc 100644 GIT binary patch delta 8362 zcmV;bAXVSpSpQv+B!BvPR9JLUVRs;Ka&Km7Y-J#Hd2nSQWq4_3004N}y_#u~+&Yqk z|Kk*M1Y!q{gVk(qFvp+I0cNSBC%x{TZX2bll0`DHM0j|31kfcw@sir)q* z}7W%sH^Rtt3e~f-y7c?6Mvi8kFS}3I={CKzi#LAv-d1!?{#pAPb)?&}R^?yt^Y+>SQxzkw&v)BFZKlA$I zKzj@F);{ISR;!VHf$5!i0G5gxTgAsuL8sdesU;as1afz#+YJ`CDz!IPa(yWQcfbjmVFL6 z=9F_Tx#m`U2_=?Paw(?N(yFT-a*Q?ATuZIBH70G0-1v0khSs|4zK0%r>baL*dmF%K zgb_y?c@#71XwywU;fa}Mo@LhAmR&$;g%wv?d4H8vSKB~s`yF=NY3E&b-R;Y3)?By# z<@L{d&3?S*j;C~E{_+|h&G|Eg6`e%+43D{B@pzU80JM|Oo?=6AMy`|3o+?g@j#WlE zXIgm-4~Au3-1f_NKRox7-%JSqmfzgRb4ITFPk7GAb${^OU;XwQuT5o}@pyAQq%f3G zAAe8yalgv61)17YboQw*`wQV1E_ZG6-sg>1M=r-3{7H-p-*q+(h zSNFRReWiu5Yg^_ldUaol`_q2@sdw`?H-GfjqGq10g9O&*Z5cC+(n|FqV>7N;>>s-p$|KfD2b&R)0$; z4)?0D_X7$11Uyn7*l}Ud-Dffx-C^7GtL2*JKnLyxRPvr~XV!kK(LJDvZO;8n?qIkC zg4plEoLt?)(afp2nf(^PVwjG<$6~NWF#Fh7?O1VxLfJ3rwnzTsV6GmHspIYjchxz$ z2%HJEx)oV*?1fXaTa)FcF+p>Tp?}Vv(_F50r+JnyW98TGMusm?(i4Q%8)U2b`mf^B z{O-c4HRiVAwAt6z%6b(IoDfKu*5}c-%ve@>R`lT2VD}RDgDH2#hLza&Y=IHro$Xo< zY#wmuYBQ!E1XcoeV`I+9nYj49ayDz@7<@mz0chlG>_yh7#OLO*F#PlLoMxOc7fAC)L=4{(Sr*q%~`k@ zW}B%3RpJajLZ$&2tVvAym47{fmnVs&aQ7T-lAkd-6JaZ zv`v!4HYxYy`p~@__YimFfPp&{HwF-ZMb<`m?rdWX9U~MXr^a0v+b_J70&q=0VY5;Q zur0Fjn*6VPxRP?r7U0-P?WEyE5VGEFea%Gah=^|B$^TKI=pIOzKsr>?Hnh=5fCLbn zzNSI+FcHh^jG^2GjDNs2b8I5*og&>S@b63ywoTckh*+em0&<9e6*SsG?jJl?x0G{5VJdCHP2dNl?gnvyoAp%h$RZI6^gqesc zrl#`1ONOZt2Dt{7{VGE0H%FKxbL$Krs{mUg0hKiEjL79ShZ^4MXNpyw$ zC&)!xs{$ZV*|3d*=7D%H2LV$QFfN3J2Naxy195POt%}&Bz2k)qnSor|QmN^al=8Ga zAN);NXNjo1pMT`gK}H=81x9l2qng7tnY;lf)x$hHu3j{3w{qH66CsS7nBf&k9l}@d zMP}liOboFN(hYyC;rg>erOX=`9`b}l7Mz5RKzUVrmQef>i=*|(oSqWT%Bq!V$h05B zdPv#9h(q)V1kT)0JQPQU~N`-+zLN~ zHYKVJ8_t&u$9CFyCS8)qU68cd2BO~Yz8Rr_X8+p7U%MS^?EbW{yo0C2UgW7Q5Np>d z9I7z)HgYx`9aBw-Ko+#}pcqbCsaZvQa&BwN8)W8$ z?DtS|Mt?l|Hxt$;90sfdju`^q5nkhXZMTVyX3|~|-e*H+o8-ngYn94}bu5wT$taPv zSSb(q1AsvMZ9jz*wh_z5pD_m#g?xCXN(wnnS|W_7LfnokZsf{?w8qxA@PfBefZJeD zgLGR*6M2Z!!=r~^`r&KrA)p}8C4-!N9`>2IK7V&h@N~jMzITXi1Kcwsw4-?{I0JF8 z!nx*$oGj;w&ncN$1o8EN*H?CFBgq`)b(5*Im$n5f0HAIkh!hXv0X)oLvMk|Ktzgo> z!so)o{J;quFdUBD6i-|UU-+tnHGm&XU%oV@z#tA*gaU|WV67pRZj?MIGXbWHtBwfx zC4Vr##bs?>8s*>yY(urA@%COU#4NgES*ahYF5oLEiHsI`BR|rS{wQrE0;yw&zwMcB zPZLze3`NC*#n#|~AzAmedC zKonCQ-J1{vJzl6KdDSV)RpkX>Fr+R&=XwkUZY}X}@t{bulcW{R6qO&#NbLu54tD9U zT`2xWB(_grl$3Gg}KMg9(^Y%;Y617s>;@^?sz?p!#3wPN2(I7B3d4}To8 z%eag}P!R`cr6q0YFF2woHNTX43fAFPxPuXDq+2e2hFT^Usx=QgLN<4zyOGtNtb}(>uab^DwFA6H`u#YG8vrR1w_T~_Y1&|u&tb!0n*J0aYN?ZH}bE?bThZc zLLH4tqRKudJ=J19EE|t{B_<0o+8hY8!zI;wd@$5kk3{5=LuNcFaAt~+uzv$QhNi{X zD%x@LJTccpLZU4~9Y-S7X9UMkILk*%j9bVb>*h95{)kubaIb6Vs|5>L}VDxa+amzo8Qtgas^ zyD0PeG9e2T5}6jzk&aPBXMg4tV9U~`LtzkKSq|+NLa$3B$;6;4QQ9g7jsmBKkK4hr z$zN*J3W#q_6bI>LpxErE+Yswlm%#kmHpp08HdnP#)UfKeWsp^8%HdH}7NB3XU^9Q& zG{HyRv*beJh9n>xqzu?pf)qhZe-SJ*v7ciL_svo^B}90f&7D0|^NRD4`#Xouz9%)D_;MneAvF@u%*)zO>xJP3 zl6CmY%sO-M3!;0jz<+UEm62dNf^jx~M1eg;5(NYZN-|dX1aX>L|`_M zoXS(2*^$vB-(F~PTS@1ZU0tP~n&EhAs>?nmBp7bjqm_CNj4R9sl6c{Q`RM`JQ`=2Q z7`VWNe%uP}xsit|E|gP;FhD?D*r>&@&k{#e2MMZ&-+x@JxI8Cn7Shr7ryqqWM^ZIf zAQt}2syFMDFJn&Ry zugGdKfRNnGQ14OEe%q?ZGYPGms-N3)W5$g1Ci-yFZDQ*&Nu-DcjD#l2eHe7gPcic& zWTHer6a>gCm4n4FT)|@m{riNXky>k0FUp(kmVZh&vO5_|4Chj+{Vb7;kYr_)U#Z9B85sH#4xt}q}KVkBmqS{6lP^~bAZ81Za@RpEa~VvQpNFGa6u zd?T7A{L%ew>e&g5r`Gl%yxH;*{nI{#A0;8{ev_>Ixg~EnK!qQz6!laA!_RRWSTP5j zc7GeJ%24B0Xv|u_7Z0aL7Y$XQAZX>hpPTQ*aRBl9$^nX%kP3OcAO9Ls^+%`FZ`)*7 zC(4zKAcQT|AzA&5PFZt!F{xjE@&|{vE6K$?Pv>9ph_+5SnE=e66&^inJfLE?VY6^Z5pbN?mRFYj?z7x2+zv=1J+o7Vi=B93T_u-ElHyt%i zc_(C0HR;qky>?aF#%~V;pwugOKc7N>ludN_}uBSl6tVIv|n;@&3kBHX{^}kOCcjzHO zp0C&&`qbM98t1XeNrobglXKv`D^aQ6j?i-H(;K0}b5YNFsiRfsx+V72UIwFUvZ?H= z&)-k~)OIkxzd+4`xTknNL*^OD&IAhaN6yfbIeX>QqxRKV84NiUhzxgbC4Z;nv%`KQ zANzy14>-pu9SK;gE*bWX{d-Hze0plG_|-6H>Utv4PIsXohV&SOEjHDLEB++kBNQHQ zkHj<3my(9vtQD7il>1_H{yVC^mjf!mWE2%hIcA70DUrHU-6^^0D>{kf@Iz_z3$hEb z=Yot9=#+~W;c#9vFT8d+Pk$>(4VZ_c^bnT-FrViqHI%}}KNmTU_bJii86~RKVA5%0 zOUMnYj|TBeH7=cXaVQ&+{=;dWOSME_hBaMP;x`AR=T{xE5#fl283Dc6@tiIuqypX9p%xypF}?5eG;3^h&)g>-!ey4ff*ziGD=)llmSnU#vZW~L{5UluGXkMEZoSQkkA z#{LHXIMv|P8}%zC=v+hH2S3Nn1X7&U2GI)APM&mP+G7F#F_qKzn0 z$HiNU>aeKxKOsv=0J6*tMW@Gt)T}t8YKDSPS2OLjB`9PPxI}A6F-C}nb?eD5_EBM^ zTdg@AlHGheomOSG5HM-7x4&g%I`Q9y%LSB>8l5es0Fjtn{THx89zA+f-4Ta{aaS}<=y-g57$~I+yWn%dz8PXNL zZv5-t_%Z*^SB3sR22w2!xBM@L4r#0WgtMRk00D(*LqkwWLqi~Na&Km7Y-Iodc$|Ha zJxIeq9K~N#wM8lpb`Vj>&^lQVzi^Z)7QsSkE41oha_JW|X-HCB90k{cgCC1k2N!2u z9b5%L@P7lu(aA~CMN0f%T4)jD!Ery{-Fw`<1B7~+sb<$WplX(pj77yvc2)Gf!jBR3 zU>aeGnR-06n1<{4x`&6acM+cDe(ulFr{qiqctqkkrW+RV2Jy_MrE}gV4zi-85T6r| z8FWG7N3P3Fe&bwlSm2pKBb}Tl4ibxn4wgHZ6@Lwtc#1frs2b%9nIYciDr?=7 zzc7%~R#IH2IgA*V5Jv(cWK>Z?85Sb6YNVJ*(tgy%Kjiom4yx>~*g4i16Q0%fneyxZT| z+rMX8{rv#jpK{S3XVwM)01no(1r~||BsFF@IAvioHZ3$XHZd(UVKQbdIALTrEn+lf zHezKsV`XDxHIuU#kPR_6H8wFYGdMUgI5jo1P#I7Hlj0d%BQ-TLGdMLcGA%S_Vr4Bf zG%z$RIAu05Ei+|gV>x4CGBss4lVKW73NkoUGBY|gH99b}mm6sa7E#?{c>n+a24YJ` zL;xcI8UPr5|4>_#79=2l9R@c8lSvzZ000RSNklv* z7`(z@YV1(+QxYNDA|WDyR*EZ9wX}+;R4P^NW1k`(S_xHZRq+&wzEpWgqgIiUhc;1A zrM5y9YD0e%6Tny)Y{SBCjY4d#&9XbQckb-=!F%uCnVs3J*Ivti>vE*k&fmQ==iKx2 zopWvgb<&=m?jj)s06<6xjM)GH#u$F~{Z003&_HjW0!tF5Y)a#Xai=l_P$ z0LE;DwH8kysNo2IEYpCZg`uh{0KhVhb!iU4l}^AJr<4i7l<%n(8nGcwfD3~A0M0O_ zR0zT{jg4gjBL|;_9*yDB$Nv#H;Oj?+5h~ik+3{7UltR(M$foBvjsRXcdIY&VMMq3W zBJluix{jA#7y+de+4MXVE$mqJ4W|JBpzAsaA&7T(BNmH)f>H|0G+>!IWYcA5$U~rv z2saE4&~+WbV5KXu%q50fW1YyR=QbV?`fP3wxHtP5c5eF;rXI}V%&E}|O<2zqkh3~DyzzMc;&X#|<)tISsm+s5csWZP8^4AAp15ONyn7qMH}BMpFL-Vt3%4Oa z$SrNd%sT+h#8d*w)GR2auqlNe)iHH1DL&M)sQ7Vz2Bz*Mp+|Mtl!8)c& zXpsmqnG9xADU9Eqb_kY`5W-pu6ha(=;Lq^;4R?ZaQe!a&#%vH05+A}pE~2#{L==4O z_%Q%~z@>kV`A+)6^ZUhfk<#3L^K!u(W?rZ}f7YF5yJ_$4o}$|a8Ac9@q6!nWEQ-7T zedOyuf}<}Vfow`Up$QOe&aZdQmFMKu0=wBU?t|4Oo~8J)an{=_~0M_AhWoLX!|or zFJ`c7R}X&ohd)6f1ot0)j$j~&SVsqXcf^56E3STet?V>CUU2o(YuMJc75Q8iGxw92 zyqhe|6M)4SzW?o4arbTlF})27kDs7T*KzpZAUZci0Ra03zanx79#*ga@`9(sv>0=L zRHfufRZS*9jT{F1zl=y&12u9mnT?LkTkySa0_pjsV*#Z73892&pP8N-^~O0rX3A_3!D!=1oy(Bm^}aLC!EijogxeON?{k*Q!;b z{I0qEi>ClAGY3VB2*jq55G>O`*OtwH*t{u<_O>=WUR;2tswmnvvWp8#9~SSzO!A?_ zgEMBMH{JyR$foC^J=2C=-CZy#MemL{9%nKjM1f@*&`K&xjU0#snB@FnrD)R6cQ}9$ znwa+Y_ZInTb7oC553S@EEXH7(dE8E%{&;f9RRK2RpCaF9O~SRb7oEC1qzknG#|s~Fg#4Dp#pg8{7;LE3yZ>; z%JhrhyjzpT$auiL`aI6Nu>JC)KqFgKK?I;jbx#2-N6qDM=Tv#-DKMFNH}GmYC&<-T zW{x9Pw+6@{NPdpfnw!AtI64M@Ib-F>P)?s^^=HzG%i-D2Av$Jw@6B^XuR=yOGpT1x zJwk9Fm$Ogexaal>ex~B90ctq1Y~WGPm|Ce?3}5w<7%yZl3vHQ=t@iHk?=A9hCktfn z?w+FT@MOP0Dk28+6=dMOH_sL274%z8e*HT?Iak-1dYL!Pyu$}DW@BQ1IuY34-&<^r zXrPoqRS76%4ySkK)F{&P^SF5V-(rlX2B_f(6fKO_cD(}msj4b!{SGu($Cwq=?4Y-| zV)1dd0vB-R;%Dn8mW4NyuQt0_NI&zO3sS|wP{17xtX zZ=la%j?~Cu-#}k=4X{kZS9N7Zc%EL*n3aMdH@J}lLZx}T?bf{%0AOHeH-PeXoKLP^!=FEY9&>;q9!WHb86I4D_nS(bks077KwJn zh2Oa`eiLuM|B*v~06b^Vv=&^SoCyTcB=q+CAK}LMP2pQwW1Wryj-o}-8tbfJo(Z3^ zR3R>x%pou(q^hbTQq`>iyb4oZZQ@y2;8~ZuN7rbd;K{fIxRw)o1J#_KoQBHP77iw4 zRK>xHVdmFF02kl6P?QDmmn&m9K77a_2p%e{6=;IBCL_Gr=ylJlYTIa%;kK$MIIukm zRZ%MPmAXuSz^|+C&zn#EpVCu$N>Ax2{lC-y0PYc z|Kk*Mgv1UU2dmlKV2(eZ16dTCuUpbcG8@v!DrTavM0j|3MAEGP`R{H1i?0}6F(KxX zYDy1Zp@!-jZ_0DO+WBptaDJb!@ZRF@U#^?48;(n!SAYL3>3<#nxo*EExG#-&@!LdY zyf^xJ{lby@fV#k7i8WRO%wbWW$W6{RUjZZfQwANksJ@nX9&%N~8+W;g(Fthmz3tADJz+6HRd@37-eJMXgVZeL!r=DPJS z-~YVV?8j^FcuE8Fm)H1c&Yvl)=p@Q#c+3Th$Fn>Dpq+g76dQswa-DqkR7X@q$1bCs zGp#&^2g9;1Zu{lCzj^K#znKvJEx);s=ZswUpYWWK>;B-mzxwSrUYp7`X(m;E*HueMj)VBNcFCk1mhziv)4OlY680zI(`ZXewX)g@-R4@$!fm<|+cP`o z>V6lZue30BZOfcZukK56e>%@U^=kgkfPdav)XKAUkig!&En|jJTB$x{EQAZn$X=i^ zxF#jvSCWCW-5l-87@^m_>x$>#e&+V*T^l=%n5*6opBPcj``L}V=9f~G)&hC(%W3Y^Yg;0 zHRiTC9d_Q@S+Ami1OK%9^m#Obf4Z{Lv!Vy9j!l?8t(!XuV;;9aG@0-Oo)Tqp@={Ncz(;tX-y-OvJ%8k@DgA(mC)pKI}*O; zBM$8Ps@HAdy|tk*Al|hM?|-L@meB@=sFn~V;MkHMITH(U)iKEz$h$cjj?-P+4|6=s zKL?2d7z!=n84)%!Bf8g(0XOm?Q8Kr}S}wJ51J6s>grjT!@M;Za^`(hMJVCBVzmmZ2}m}$G>&!aSjUUArmiFk5<1Qq z6*!GO7V?DV9Y!C=Mr@ zJx7Ijr$IoMF@(j=ZrD3w2^Emof~z3YLf0tjsKj>>?=h`zO&g(5mh%wQFem8~Od<5M z6jilf2qm&bk9Yy2r>V5KU?-+&(2e9nfGn132y!O@pAG)jKxIxa4zkidlrc;69ZpE| z{1xowq;x~|X@9VL0BwGd4i8%7{m=+iH>aDCWGFQpLC`?Q5q)4Z&b&eE(5H8`65!(8+FF zB!LjDxHEyHlOBtV0!*+|IcPb^l(~h>gG-nJWPkbtT8(_dcgR+6%AnjLRM%n+Se)bK zUynDFqDP!VwnesMm>a5B1inW%e?2?709o<6z@_5?*5ytdmHEAr(xPh0ih?ScQ9-uk zR+1QjKFgJ7a*Vc(+&M5PRx;u%CV~5J?ik(Ll?rnR_}3OgBJ|uY>pfuSOhi4$RMev* zPJh%Bv7ewfB)b%2ei(z4@(J|Ae1tIz_iOkUo#Xo#W$Fk^pM4p^pfPUB6%MB=Z7TuRa*48cP%) z-Vv<PW{85|QQtpG6Ed3X8{(S5Kh>>wgtV&7})7Y^7NgO(V^c`eQ~@p!3UpLlRj? zc@A;ZNCsa9l&Qw)x5lxj#A!H>^ix@BLMcR>BVAM56eJymZB-^fq16~#qY5LlHj}|U zQ=;Uvym9S+qNJ6~z+wMCAAYm9-(oR1J1Z=yHo_ z?;^^xX>n({+(hwkFQ1Fwu-=gKK!2i0%i;)g@Ij%3(xcui66*f)cNgX;XH$X!AbM4& zje>Md)V~vYf>Wlk!frFDb96hY6zd*5p%48g?d+9qT1sN+6q;bb91n7%B7u=NFgC$- zu!hhIsbF3eErHs4JLnvTpoqXp5s)A#8y^Wn(hWfnkmz{T>lCVsI3$_M^nXZ#r+QBr zv3>PO8|5QRe!hBXD^DV`r42Dvyfy{dWU>4vz$r<5rGmu4F)G<6%vy5}Dla@RZjMM| zhFTfUp($|=AKCTRJp|*yXranACRuRqg$ba>ZtU=*d<8r{3 zZ!e;qb_|(s#H{=$?-4W$RwPVzqFnbk*04z5gfysM6aJwTmC~z=G!vqhBPl5zO`uO; z;IVGsS`?DWiV7+)sY+cyQ$s$u(=U@3)ii~Gq_C@7o{;Da)POyDi$&{lWL zc1)J$k(k@R^%{{1Q-7;M7t1p;&C7va2*)j1IZfJ0)qp24I11K6T1v$7kw_35-v8Bb z1M?~bl$#+9wZc+V>!#L9T_N8iJHt;`8%f(BX(Evx3977q>h)cK;wdG`X)UUAag5&) zjwe9$_R3bulVynCRB!%n)4|OxK*OW5$N`Z0P0-kTr(tl>QKJQ@u*%e5s&ZpTF^gZv{m6kzM#}J(1aZdJxRWeKh#;HC`hU zYibJljRWw@DSt)DWKms!On`$Ywj;Dc_kyLjH|iAm!&B>%vAcM2)qHDdiF}~74O(y` zKv)gsg03D=z|MX=@1iJlvO3kg*F;HLk9}hMkAse=j@11gm6h|UoL^I?U^lsXL!_DH zS8%0T0KKH(h5iJ#;d`=?sK5VQ8+1KFMraB z3`rA!`@QpFI(7srJItwG)EpaTl8*T5ze7 z2vEwTti&qAz$v|)gG+$0Tvu3P{O-F0=_R`-q@*YA9zFrq^{`Qp*s=3A8;Dcm$c`tM zUw$d|uw_&!!rN15s;)&^l^h*%m)x&@0BL(5v@pbQx2SPfG_VO6bA%{9AFkihOPbA! zu74jjNV6J$F+==n#?Pe$q3}gmifXsQH-H^AZ`n`hQ;jRx zV1-*~pqtt6>B5{giX`F{@CFu$mQW{dNs7td6gg@t&=-nfsAW!ug`w2!dBxso_kWN? z6cu{#hCI#+>D*5F+K+Emdrq)aRZ`^Hqz9}NQRM%iLLH;Szv@S_Ox7~#;^=(-e!BWk z*XnHh_jkzdlprL)Gi^uwcO8a{AvlvraF|{L;*# z2(5oHV?$MuR-D80^O;}=YKTFl4u70LnxO)=D1UdA``?87DP-DJ8Q-;ZB*7H%S$uVS z#!~fzC^Oxs7EtNHoSKpO)TX7x?LkRi&nt$Koc`qlO)>u_HR1~}b3OIxHcZr=+Q%2& z5MMm#y0s|Vtm=JJtfL2_(AU)EA1#DzB7*DQWvi}W_EW7ghyE)-4Yu3Ojel~wd;8r} zID@oK7a5*IZJXQWP_r>51?2d@JQ5=ZO2meXBersBEZh!~Cl4U?3jXQfWj!Z3jiDyo zR3$R0CQ$_E;i$OliPQ!l8=Z?FQ`c9LPsQAQI;;A}?Ng(3k;;|Wfm3>XTS7bO@t&S5 za(<*AB0-62sCx#Z0SofdfPZ@uHE>igi(aYB{+J{QgRUK&2jbc3IV6%m{VLokOp=R0 zu%0ZP@@yU^WHYHG-0Aex^YlL><)k%;u-k4q&9GK)%WJCT)$ReZ;yZSSSnak1vE17d z`X*W}(yyJ`S;w|QVjB`TV88r$Jdgl`+7w6Hb;2-71;QLPlrc?6pMQo*C`onAJe?tB z+7MJYTX9pe1E21^HJrCy<_nbOn=&Q+ZW9dgR=@ts*m^iU#wqG;IViqUWwOy zT*9BHDAj)x-KVk#a5v+Hr(*j)A%br4dg&@`$#GfFl0$ovGxZq-_eG&t9kzmospF9@ zwDWYfT0jwoSs!wGc%LEQ!6F@g`v}mG1=$pVlnqGPC;3tD<$rTk|6I}Sv-8z~_3!>8 zhxwQO!-Hk@SnfUxxTI*JYAlEx{~)8$g)p^8mqK_HB1<+UUKPZE@AOHiNtvz#VM_$4 z{MOTG6QveZ;zBt3Kb%`+eMtm=)h>zUAN-4j`S<=e3o$rFD(UY72 z00D$)LqkwWLw`dcaB^>EX>4Tx0C=2zkv&MmP!xrasnSv^4t5Z6$WWbH5EXHhRxE;r z(pG5I!Q`cX(4-+rad8w}3l9D)RvlcNb#-tR1i>E=M<*vm7b)?+q|hS93y*x9chAXt z_W?qy##FO^5>PeE$Ry)pzOX9#UlBkMKp&zKGxbzt?f%Ws^^4huXpY~(Tt;xMsT?qRuy zS;bI^XNV(;s!_g>cUj@Q#aXR2Sm&JlhM}UilI1$BF(k2s6w(kOqk$@Fun?oKMv93H z?Z-X*qkoP+O)i;SRWNcapbiz1;|G6(-?KGK(^GCzC=Lv~*!IUb;NJz>P22uHw(a%_ z;ClwHw64G20_HwRZ+5lF5iqn3TwHfGc@MbU0Y;v5$&eh$M@uM`fcGw_HR#Tehoh?e{zeA)j?JO01fxEycUWABxW;W zHe)w7FfC(bGc+wUH)Jv`Vl^>1Eihv-VKy>mVPY^aVv}kakPR>}IXE>nGc!3dF)%T+ z2O3ZUvo;-I2o?+)8TbGI00v@9M??Uk0FnTL4u$y}ldL5me+mK}4bfdaRR9182T4Rh zRCwC$T3u)yRTTa61`j#D^-1Xa%jdC{~ITF(O!LtHoLxO=(4tENg|`xjS>0^q=sDZKRDllnQwOCyp+eZT*}p%j*p z^t3yWD{p=Zbd&TfWUvsuaD;$k8H0=Kr7Hzp4ArL90-JUDnpIHY02!rCv@c_Qs zuG?rw$Ma)9SBwWJRfg~N#Tvo&(}-jM$MfO3E&w2sf5Ea0hn|JLfD{iyr43X6&28|A z6&V6#2*LnTI1EE=h)4!2D+C^S@Bw79S$y!>Nw}^+7%DvV*u%)@avJPt)x$7^0VJcFM|7-*VTecuh-49k zd>srae+6Q6{x_mB&W2dGegn&{?Po7taM~)uH z-ksxc7(fCrnB$H31=SYZxE%pO+uDIF8HDD8&rag(*>f70dgrOKsG*Svdu^PwyYX;z_TjTS7 ze>#o+H3P=G=+miro$vL*5yCJ8J;x2%Q4r)sO{5f*Dnp1~JrSB*Bm=mvi~H}t4*>Ad z7hfm7bl;v`*m~z31_82_q=K*7CsQS_x$FCjSK?ge|bNhHr$&l&sUwoYie==k39GQ_U+k)K$e<& zTFr~J!D`A^LrTDL+~yuIJT#~|JkRCte*C$f@R#47K_;8U@X(+JLJgWR{~#z9HD=6Q zxr$?7ePbv~snX^VnQRsSwD*KzsGmLe>fuyr~Oy;!MniFAAtSUA%h%hL^fA!OF zJReUzR-a%dn}rMlqoh@;43EVqxh;2f$MYeB0Q>grGTt@1d87)EH)VB?fc`i497?4( z>O>`dXX8t(0c@f|%#Dn~zl&s`ug%og%i>qn=x+|LpT_M&>l+l|@2S7LXf#ve<}_bP z!VZH7p^N3N(cy}XBT|;&)o>wFe+p8T@aycgL_NiOuf0&IyKFkPo6B9F6C2lY^z}oJ zKfUC}w850_r7S^-vf-s2?+SNHc&f7%CuJo{nuT&YO=IXCK};xh)BtZCda-i-@9VKu z<125z-;&30K47mt<#~(S&o2vfa;vHbDGaO~h&8}`+?=O7)8$pH!MO4^f1&F-5G42I z$`O;aJ%E!S{+#9~OC17>19S?!VkKtC%V+NXimiBDdTwff4_`l6iECsu3zK%nv||MO zx?X(><2M@JK9;Bj0K z4H-iv8Z!0a>jx`*1(Q~jf4+a>`GakZX;*nEO9logRmO$Ov#GmAhb#SQ4`HbE#ta9& zsmTfCb2*$i{kj6~!@a6?EKi742RcEllHpVQVXNQ3`{kZ;5p@A2W^1KLAs*Jrm z$1%Ejq@j5m`+nZT@;O8@Kp{Ve>it|p&#OicgSg1rTLv}mod4-(965U2FaXsIf1cNea~Ee)J?IiSa`ZUP z|MauQmj28-qk-diY4m5-H7Kt%W>h=G^_F?Lbq^o_Nh&EjwQomq+pRZMXySW!jyFYh z06724B^*07t!sm%*7&cp*HSH4gLc=Kt~tzmya2 z9In{>0{|XP6_J%dmX^c-C*C<+;RZN4eFnS6w;6_@RN1US)6;4(LYs|o zzr}TJJ1v}UyN-jqZ(R%5aT@BCwn8AOt;`XhKSKvAf9&%Got8pAhXNx(*Dhbw+@RHS z$%!FAd-k^SeC7EwT=8=kXS!y~t!W7OUZ2rro)gqYJhrv7Y)h^Yde}kW~sA4 z$7%t7H$X9NSB86leX^|Eyg)Qt{Uqh%@4L_aS7lXJWmQ(?|1SRm&DLZki5t?p00000 LNkvXXu0mjfU6Ckm