From 0c527114367875ed9697410581a8ab4c5442c3b5 Mon Sep 17 00:00:00 2001 From: Frank DeMarco Date: Thu, 28 Dec 2017 08:01:58 -0500 Subject: [PATCH] pattern --- NS.py | 444 ++++++++++++++++++++++++++++-------- resource/Spoopy.png | Bin 0 -> 7823 bytes resource/Spoopy_avatar.png | Bin 0 -> 1776 bytes resource/Visitor.png | Bin 0 -> 8073 bytes resource/Visitor_avatar.png | Bin 0 -> 1829 bytes 5 files changed, 351 insertions(+), 93 deletions(-) create mode 100644 resource/Spoopy.png create mode 100644 resource/Spoopy_avatar.png create mode 100644 resource/Visitor.png create mode 100644 resource/Visitor_avatar.png diff --git a/NS.py b/NS.py index 723f728..7735145 100644 --- a/NS.py +++ b/NS.py @@ -71,15 +71,13 @@ class NS(Game, Animation): self.chemtrails = Chemtrails(self) self.boss = Boss(self) self.last_press = get_ticks() - self.register(self.unsuppress_restart) self.reset() - def reset(self): + def reset(self, leave_wipe_running=False): self.suppressing_input = False - self.suppress_restart = False - self.game_over = False self.title.reset() - self.wipe.reset() + if not leave_wipe_running: + self.wipe.reset() self.introduction.reset() self.boss.reset() self.chemtrails.reset() @@ -88,7 +86,7 @@ class NS(Game, Animation): def suppress_input(self): self.suppressing_input = True - self.platform.unpress() + # self.platform.unpress() def unsuppress_input(self): self.suppressing_input = False @@ -100,8 +98,6 @@ class NS(Game, Animation): lights = self.platform.lights if event.key in (K_UP, K_o): lights[NS.LNW].pressed = pressed - if self.game_over and not self.suppress_restart: - self.reset() elif event.key in (K_RIGHT, K_p): lights[NS.LNE].pressed = pressed elif event.key in (K_DOWN, K_SEMICOLON): @@ -113,31 +109,6 @@ class NS(Game, Animation): if self.get_delegate().compare(event, "reset-game"): self.reset() - def finish_battle(self, win): - self.game_over = True - font = Font(self.get_resource("rounded-mplus-1m-bold.ttf"), 128) - text = font.render("YOU WIN" if win else "GAME OVER", True, Color("white")) - self.message = Sprite(self) - self.message.add_frame(text) - self.message.location.center = self.get_display_surface().get_rect().center - self.boss.halt(self.boss.brandish) - self.boss.sword.reset() - self.boss.queue = [] - self.boss.brandish_complete = True - if win: - self.boss.set_frameset(0) - self.suppress_restart = True - self.play(self.unsuppress_restart, delay=4000, play_once=True) - - def unsuppress_restart(self): - self.suppress_restart = False - font = Font(self.get_resource("rounded-mplus-1m-bold.ttf"), 48) - text = font.render("(PRESS BLUE TO RESTART)", True, Color("white")) - self.restart_message = Sprite(self) - self.restart_message.add_frame(text) - dsr = self.get_display_surface().get_rect() - self.restart_message.location.center = dsr.centerx, dsr.centery + 80 - def update(self): Animation.update(self) self.title.update() @@ -147,10 +118,6 @@ class NS(Game, Animation): self.platform.update() self.chemtrails.update() self.boss.update_dialogue() - if self.game_over: - self.message.update() - if not self.suppress_restart: - self.restart_message.update() self.wipe.update() @@ -329,10 +296,10 @@ class Introduction(Animation): "on it. Now the power of Giant Tony pulses through you.", \ "Before you go, show me you can scrape! Use your board to touch\n" + \ "the glowing pads on the platform!", \ - "Great job, lizard scum! Maybe now you're ready to take on Kool\n" + \ + "Good job, lizard scum! Maybe now you're ready to take on Kool\n" + \ "Man and his friends. Don't let me down!" SKATEBOARD_START = -30, -20 - TUTORIAL_MOVES = NS.S, NS.NE, NS.N, NS.E, NS.NW, NS.W, NS.E, NS.W + TUTORIAL_MOVES = NS.S, NS.NE, NS.N, NS.E def __init__(self, parent): Animation.__init__(self, parent) @@ -367,6 +334,7 @@ class Introduction(Animation): def activate(self): self.active = True self.play(self.start, delay=3000, play_once=True) + # self.get_game().platform.unpress() def start(self): self.advance_prompt.cancel_first_press() @@ -395,7 +363,7 @@ class Introduction(Animation): def activate_boss(self): self.deactivate() - self.get_game().boss.start_level() + self.get_game().boss.start_level(0) def start_wipe(self): self.get_game().wipe.start(self.activate_boss) @@ -429,7 +397,7 @@ class Introduction(Animation): dialogue.show_text(self.TEXT[self.text_index]) else: self.start_wipe() - self.get_game().platform.unpress() + # self.get_game().platform.unpress() self.advance_prompt.cancel_first_press() elif self.text_index == 2: platform = self.get_game().platform @@ -451,7 +419,7 @@ class Introduction(Animation): if not wipe.is_playing() and not self.is_playing(self.start) and \ not self.text_index == 2: self.advance_prompt.update() - if not self.text_index == 2: + if not wipe.is_playing() and not self.text_index == 2: self.skip_prompt.update() @@ -646,6 +614,48 @@ class Platform(GameChild): buttons = buttons.union((NS.LSW, NS.LNW)) return list(buttons) + def get_steps_from_edge(self, edge): + if edge == NS.N: + return NS.NE, NS.NW + elif edge == NS.NE: + return NS.N, NS.E, NS.S, NS.W + elif edge == NS.E: + return NS.NE, NS.NW + elif edge == NS.NW: + return NS.N, NS.E, NS.S, NS.W + elif edge == NS.S: + return NS.NE, NS.NW + elif edge == NS.W: + return NS.NE, NS.NW + + def get_right_angles_from_edge(self, edge): + if edge == NS.N: + return NS.E, NS.W + elif edge == NS.NE: + return None + elif edge == NS.E: + return NS.N, NS.S + elif edge == NS.NW: + return None + elif edge == NS.S: + return NS.E, NS.W + elif edge == NS.W: + return NS.N, NS.S + + def get_opposite_of_edge(self, edge): + if edge == NS.N: + return NS.S + elif edge == NS.NE: + return NS.NW + elif edge == NS.E: + return NS.W + elif edge == NS.NW: + return NS.NE + elif edge == NS.S: + return NS.N + elif edge == NS.W: + return NS.E + def set_glowing(self, selected): for ii, light in enumerate(self.lights): light.glow_index = 0 @@ -714,11 +724,11 @@ class Light(Animation): if not self.get_game().introduction.active: boss = self.get_game().boss chemtrails = self.get_game().chemtrails - if boss.queue and boss.brandish_complete and not self.is_playing(self.blink) \ + if boss.queue and boss.brandish_complete and not self.is_playing(self.glow) \ and self.in_orientation(boss.queue[chemtrails.queue_index]): - self.play(self.blink) - elif self.is_playing(self.blink) and (not boss.queue or - not self.in_orientation(boss.queue[chemtrails.queue_index])): + self.play(self.glow) + elif self.is_playing(self.glow) and (not boss.queue or + not self.in_orientation(boss.queue[chemtrails.queue_index])): self.reset() points = self.points else: @@ -777,20 +787,15 @@ class Chemtrails(GameChild): if self.active: self.orient() if not self.get_game().introduction.active: - if self.get_game().boss.queue: + boss = self.get_game().boss + if boss.queue: self.timer.tick() self.attack() if self.timer.time_remaining < 0: self.life.decrease() - if not self.get_game().game_over: + if not boss.is_playing(boss.show_end_dialogue): self.timer.reset() - self.get_game().boss.combo() - # font = Font(self.get_resource("rounded-mplus-1m-bold.ttf"), 24) - # text = font.render("%.2f" % max(0, self.timer_remaining / 1000.0), True, Color("white")) - # rect = text.get_rect() - # ds = self.get_display_surface() - # rect.topright = ds.get_rect().topright - # ds.blit(text, rect) + boss.combo() self.timer.update() self.life.update() @@ -799,11 +804,18 @@ class Chemtrails(GameChild): queue = boss.queue if self.orientation == queue[self.queue_index]: self.timer.add_time(self.TIME_ADDITION) - boss.health.decrease(5) + if boss.level_index == 0: + boss.health.decrease(4) + elif boss.level_index == 1: + boss.health.decrease(4) + elif boss.level_index == 2: + boss.health.decrease(4) self.queue_index += 1 + boss.last_attack = self.orientation if self.queue_index == len(queue): self.timer.reset() - self.get_game().boss.combo() + if not boss.is_playing(boss.show_end_dialogue): + boss.combo() self.get_game().platform.reset_lights() def orient(self): @@ -918,7 +930,7 @@ class Life(GameChild): self.count -= 1 if self.count <= 0: self.count = 0 - self.get_game().finish_battle(False) + self.get_game().boss.finish_battle(False) def update(self): ds = self.get_display_surface() @@ -930,46 +942,85 @@ class Life(GameChild): ds.blit(self.heart, (x, rect.top)) -class Boss(RainbowSprite): +class Boss(Animation): def __init__(self, parent): - RainbowSprite.__init__(self, parent, load("resource/Kool_man.png").convert_alpha(), 30) + Animation.__init__(self, parent) + self.kool_man = RainbowSprite(self, load(self.get_resource("Kool_man.png")).convert_alpha(), 30) + self.visitor = RainbowSprite(self, load(self.get_resource("Visitor.png")).convert_alpha(), 30) + self.spoopy = RainbowSprite(self, load(self.get_resource("Spoopy.png")).convert_alpha(), 30) self.health = Health(self) self.sword = Sword(self) - self.register(self.brandish, self.cancel_flash, self.show_dialogue) - self.add_frameset([0], name="normal") - self.kool_man_avatar = load(self.get_resource("resource/Kool_man_avatar.png")).convert() + self.register(self.brandish, self.cancel_flash, self.show_introduction_dialogue, + self.show_end_dialogue) + self.kool_man.add_frameset([0], name="normal", switch=True) + self.visitor.add_frameset([0], name="normal", switch=True) + self.spoopy.add_frameset([0], name="normal", switch=True) + self.kool_man_avatar = load(self.get_resource("Kool_man_avatar.png")).convert() + self.visitor_avatar = load(self.get_resource("Visitor_avatar.png")).convert() + self.spoopy_avatar = load(self.get_resource("Spoopy_avatar.png")).convert() self.advance_prompt = AdvancePrompt(self) def cancel_flash(self): - self.set_frameset("normal") + if self.level_index == 0: + self.kool_man.set_frameset("normal") + elif self.level_index == 1: + self.visitor.set_frameset("normal") + elif self.level_index == 2: + self.spoopy.set_frameset("normal") - def start_level(self): + def start_level(self, index): + self.level_index = index + self.battle_finished = False + self.player_defeated = False + self.health.reset() + self.get_game().chemtrails.timer.reset() + self.get_game().chemtrails.life.reset() self.activate() dialogue = self.get_game().dialogue dialogue.deactivate() - dialogue.set_avatar(self.kool_man_avatar) - dialogue.set_name("Kool Man") - self.play(self.show_dialogue, delay=3000, play_once=True) + if index == 0: + dialogue.set_avatar(self.kool_man_avatar) + dialogue.set_name("Kool Man") + self.kool_man.unhide() + self.kool_man.set_frameset("normal") + elif index == 1: + dialogue.set_avatar(self.visitor_avatar) + dialogue.set_name("Visitor") + self.visitor.unhide() + self.visitor.set_frameset("normal") + elif index == 2: + dialogue.set_avatar(self.spoopy_avatar) + dialogue.set_name("Spoopy") + self.spoopy.unhide() + self.spoopy.set_frameset("normal") + self.play(self.show_introduction_dialogue, delay=3000, play_once=True) self.get_game().platform.activate() self.get_game().chemtrails.activate() + self.last_attack = NS.NW - def show_dialogue(self): + def show_introduction_dialogue(self): dialogue = self.get_game().dialogue dialogue.activate() - dialogue.show_text("You'll never be able to block my sword, you lizard slime!" + - " See if you\ncan keep up with these moves!") + if self.level_index == 0: + dialogue.show_text("You'll never be able to block my sword, you lizard slime!" + + " See if you\ncan keep up with these moves!") + elif self.level_index == 1: + dialogue.show_text("We're just warming up, slime breath! Prepare to get spun" + + " by\nthese combos!") + elif self.level_index == 2: + dialogue.show_text("Lizard! My moves are so unpredictable you might as well" + + " give\nup now!") def reset(self): + self.level_index = 0 self.deactivate() - self.unhide() self.cancel_flash() self.halt(self.cancel_flash) self.health.reset() self.halt(self.brandish) self.sword.reset() self.advance_prompt.reset() - # self.combo() self.queue = None self.brandish_complete = True @@ -985,26 +1036,225 @@ class Boss(RainbowSprite): def brandish(self): self.queue = [] - choices = range(6) - if self.health.amount > 90: - length = 1 - elif self.health.amount > 70: - length = 2 - elif self.health.amount > 40: - length = 3 - else: - length = 4 - while len(self.queue) < length: - while True: - orientation = randint(0, 5) - if not self.queue or orientation != self.queue[-1]: - self.queue.append(orientation) - break + platform = self.get_game().platform + if self.level_index == 0: + if self.health.amount > 90: + first = choice(platform.get_steps_from_edge(self.last_attack)) + self.queue = [first] + elif self.health.amount > 70: + first = choice(platform.get_steps_from_edge(self.last_attack)) + self.queue = [first, choice(platform.get_steps_from_edge(first))] + elif self.health.amount > 30: + choices = [0] + if self.last_attack in (NS.NE, NS.NW): + choices.append(1) + else: + choices.extend((2, 3)) + result = choice(choices) + if result == 0: + first = choice(platform.get_steps_from_edge(self.last_attack)) + second = choice(platform.get_steps_from_edge(first)) + self.queue = [first, second, first, second] + elif result == 1: + first = choice(platform.get_steps_from_edge(self.last_attack)) + self.queue = [first, choice(platform.get_steps_from_edge(first)), + choice(platform.get_right_angles_from_edge(first))] + elif result == 2: + first = choice(platform.get_steps_from_edge(self.last_attack)) + self.queue = [first, choice(platform.get_steps_from_edge(first)), + platform.get_opposite_of_edge(first)] + elif result == 3: + first = choice(platform.get_steps_from_edge(self.last_attack)) + second = choice(platform.get_steps_from_edge(first)) + self.queue = [first, second, + choice(platform.get_right_angles_from_edge(second))] + else: + choices = [0, 1] + if self.last_attack in (NS.NE, NS.NW): + choices.extend((2, 3, 4)) + else: + choices.append(5) + result = choice(choices) + if result == 0 or result == 1: + first = choice(platform.get_steps_from_edge(self.last_attack)) + second = choice(platform.get_steps_from_edge(first)) + last = second if result else platform.get_opposite_of_edge(second) + self.queue = [first, second, platform.get_opposite_of_edge(first), + last] + elif result == 2: + first = choice(platform.get_steps_from_edge(self.last_attack)) + self.queue = [first, choice(platform.get_right_angles_from_edge(first)), + platform.get_opposite_of_edge(first)] + elif result == 3: + first = choice(platform.get_steps_from_edge(self.last_attack)) + self.queue = [first, choice(platform.get_steps_from_edge(first)), + choice(platform.get_right_angles_from_edge(first)), + platform.get_opposite_of_edge(first)] + elif result == 4: + first = choice(platform.get_steps_from_edge(self.last_attack)) + second = choice(platform.get_steps_from_edge(first)) + self.queue = [first, second, + choice(platform.get_right_angles_from_edge(first)), + platform.get_opposite_of_edge(second)] + elif result == 5: + first = choice(platform.get_steps_from_edge(self.last_attack)) + second = choice(platform.get_steps_from_edge(first)) + self.queue = [first, second, platform.get_opposite_of_edge(first), + choice(platform.get_right_angles_from_edge(second))] + elif self.level_index == 1: + if self.health.amount > 85: + if self.last_attack in (NS.NE, NS.NW): + choices = 1, 2 + else: + choices = 0, + result = choice(choices) + if result == 0: + first = choice(platform.get_steps_from_edge(self.last_attack)) + self.queue = [first, platform.get_opposite_of_edge(first)] + elif result == 1: + first = choice(platform.get_steps_from_edge(self.last_attack)) + self.queue = [first, choice(platform.get_right_angles_from_edge(first)), + platform.get_opposite_of_edge(first)] + elif result == 2: + first = choice(platform.get_steps_from_edge(self.last_attack)) + self.queue = [first, platform.get_opposite_of_edge(first)] + elif self.health.amount > 60: + if self.last_attack in (NS.NE, NS.NW): + choices = 2, 3 + else: + choices = 0, 1 + result = choice(choices) + first = choice(platform.get_steps_from_edge(self.last_attack)) + if result == 0: + second = choice(platform.get_steps_from_edge(first)) + self.queue = [first, second, platform.get_opposite_of_edge(second)] + elif result == 1: + second = choice(platform.get_steps_from_edge(first)) + self.queue = [first, second, + choice(platform.get_right_angles_from_edge(second)), + platform.get_opposite_of_edge(first)] + elif result == 2: + second = platform.get_opposite_of_edge(first) + self.queue = [first, second, + choice(platform.get_right_angles_from_edge(second))] + elif result == 3: + second = choice(platform.get_right_angles_from_edge(first)) + self.queue = [first, second, platform.get_opposite_of_edge(first), + platform.get_opposite_of_edge(second)] + elif self.health.amount > 30: + result = choice(range(3)) + if result == 0: + first = self.choose_new_edge((NS.N, NS.E, NS.S, NS.W)) + self.queue = [first, choice(platform.get_steps_from_edge(first)), + platform.get_opposite_of_edge(first), first] + elif result == 1: + first = self.choose_new_edge((NS.NE, NS.NW)) + second = choice(platform.get_steps_from_edge(first)) + self.queue = [first, second, platform.get_opposite_of_edge(second), + choice(platform.get_right_angles_from_edge(second))] + elif result == 2: + first = self.choose_new_edge((NS.NE, NS.NW)) + second = choice(platform.get_steps_from_edge(first)) + self.queue = [first, second, + choice(platform.get_right_angles_from_edge(second)), + platform.get_opposite_of_edge(second)] + else: + result = choice(range(4)) + if result == 0: + first = self.choose_new_edge((NS.NE, NS.NW)) + second = platform.get_opposite_of_edge(first) + self.queue = [first, second, first, second] + elif result == 1: + first = self.choose_new_edge((NS.N, NS.E, NS.S, NS.W)) + self.queue = [first, platform.get_opposite_of_edge(first), first] + elif result == 2: + first = self.choose_new_edge((NS.N, NS.E, NS.S, NS.W)) + self.queue = [first, choice(platform.get_steps_from_edge(first)), + choice(platform.get_right_angles_from_edge(first)), + platform.get_opposite_of_edge(first), first] + elif result == 3: + first = self.choose_new_edge((NS.N, NS.E, NS.S, NS.W)) + second = platform.get_opposite_of_edge(first) + third = choice(platform.get_right_angles_from_edge(first)) + self.queue = [first, second, third, platform.get_opposite_of_edge(second), + platform.get_opposite_of_edge(third)] + elif self.level_index == 2: + if self.health.amount > 90: + length = 3 + elif self.health.amount > 70: + length = 4 + elif self.health.amount > 40: + length = 5 + else: + length = 6 + while len(self.queue) < length: + while True: + orientation = randint(0, 5) + if (not self.queue and orientation != self.last_attack) or \ + (len(self.queue) > 0 and orientation != self.queue[-1]): + self.queue.append(orientation) + break self.unbrandished = copy(self.queue) self.brandish_complete = False self.sword.play(self.sword.brandish, play_once=True) self.get_game().chemtrails.challenge() + def choose_new_edge(self, edges): + while True: + edge = choice(edges) + if edge != self.last_attack: + return edge + + def finish_battle(self, win): + self.battle_finished = True + self.halt(self.brandish) + self.halt(self.cancel_flash) + self.sword.reset() + self.queue = [] + self.brandish_complete = True + if win: + if self.level_index == 0: + self.kool_man.set_frameset(0) + elif self.level_index == 1: + self.visitor.set_frameset(0) + elif self.level_index == 2: + self.spoopy.set_frameset(0) + self.player_defeated = not win + self.play(self.show_end_dialogue, delay=3000, play_once=True) + + def show_end_dialogue(self): + dialogue = self.get_game().dialogue + dialogue.activate() + if self.level_index == 0: + if self.player_defeated: + dialogue.show_text("Maybe next time!") + else: + dialogue.show_text("Hey! Wow! Lizard!") + elif self.level_index == 1: + if self.player_defeated: + dialogue.show_text("Wiped out!") + else: + dialogue.show_text("Well done! But it's not over yet!") + elif self.level_index == 2: + if self.player_defeated: + dialogue.show_text("Just like I thought!") + else: + dialogue.show_text("H-how? But you're only a lizard! How could you" + + " manage to defeat\nall of us?") + + def transition_to_battle(self): + index = self.level_index + (not self.player_defeated) + if index < 3: + self.start_level(index) + else: + self.get_game().reset(True) + + def damage(self): + if self.level_index == 0: + self.kool_man.set_frameset(0) + elif self.level_index == 1: + self.visitor.set_frameset(0) + def update(self): if self.active: self.get_display_surface().fill((0, 0, 0)) @@ -1017,10 +1267,18 @@ class Boss(RainbowSprite): dialogue.show_all() else: self.get_game().dialogue.deactivate() - self.combo() + if not self.battle_finished: + self.combo() + else: + self.get_game().wipe.start(self.transition_to_battle) self.advance_prompt.cancel_first_press() - RainbowSprite.update(self) - # self.get_display_surface().blit(self.image, (0, 0)) + Animation.update(self) + if self.level_index == 0: + self.kool_man.update() + elif self.level_index == 1: + self.visitor.update() + elif self.level_index == 2: + self.spoopy.update() self.sword.update() self.health.update() @@ -1112,12 +1370,12 @@ class Health(GameChild): def decrease(self, damage): self.amount -= damage + self.parent.damage() if self.amount <= 0: self.amount = 0 - self.get_game().finish_battle(True) + self.get_game().boss.finish_battle(True) else: self.parent.play(self.parent.cancel_flash, delay=1000, play_once=True) - self.parent.set_frameset(0) def update(self): self.background.update() diff --git a/resource/Spoopy.png b/resource/Spoopy.png new file mode 100644 index 0000000000000000000000000000000000000000..1cbd9dc7e36c48553a320284362b382405c54356 GIT binary patch literal 7823 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 literal 0 HcmV?d00001 diff --git a/resource/Spoopy_avatar.png b/resource/Spoopy_avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..4df14fd36d3dcd1d7ca44abbc889e31226e5294d GIT binary patch literal 1776 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 SO+!bH5uB;bsp^v+@&5yeMEwH* literal 0 HcmV?d00001 diff --git a/resource/Visitor_avatar.png b/resource/Visitor_avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..80d5496e50a8720b8d1c48873820c3e21d206678 GIT binary patch literal 1829 zcmV+=2io|FP)}K`t&XMyu6|ot>T3 zb)yQv^z<|yK73e|(TTXOt`28sXa6n$!r?I9xpOBi!(&;YP~hFWcX4@nIr{;aot;Ia z(U>vgV|nl1y%`4~qX2yR^a%?J3aA(#VVzEgE|)9&0O;uGz`VRXs>VlHuh*m3>&+ej zUcP)OiQ%!le*Jn327~egFfcHH`T6;h0{{Sc>eMM@Syny(rlzJ)sZ`2he1v;?dgK8h z5C~vpWu>gf0{~hq7I^@;cI}$%#z*+quV2yvFgiM#HO2z~Ub%8bS^%o6tFsCKtyYT* z3kxX$KztnT?(T-KU%zJ6k#>H59_)6zH2#36PoF{}9}2@TU^1ED_3PI#HZ}%rZEdh; z&z`i5Q>j#N_3Bmd`~853;B-3S^y$-aWkR74*zI;m$+tt&UFPTKv9`80VOP9)^CqXx z!omWcIB_DSuAP&UgHN73;nn5#?b~r>ckkYfOG`_1=YYw{$%LDpy1Kfgb#*!&F#t_X zO-W@oG&IDO_xt^H0r>Le3$LPid3iW9Gn2G#e}6xb@oU$v72M_Z_4T1fqlwme^ym>? z03JSk$gAx2>(_B*WhH6dP$O$ zwSr~J%F2jj#%{K#0uTy?IC&Kn6+{h+DX-V-iDZ_Smq*h-e*B;Z0N+?IEG#5yu(-Hb za0uk*=M%{+Dk_Sm{eC|^0M@KollH+y%;ct2Dv4yO)#_+^X=y3D0a#gC5iAo9hlyk^ zFE1w@rWpgkU@)Yu?A+X3N~=vWnx3BK1ta4CY}&Mmljrexh#H)noD|xa!PL|gkxaMS z{l7s91w8;_XWLYl9Wl<7@$qpYnGS~|<@tjMfXd2BPF_z>4^e|3K70`D0i>Y5d-qNn z0Jdz|!pVE}>XqpF!C(-aPN%3t7t6Au<;EU@v|24a05lp6XWe(Z-J-|rz`y|SZjx`9 z%*@P)lKKAq`?!^5!-frX0oc5GGiO#8>ednJ>go~&z_)MT;>L9{YH4YS`@Lhw4tfBr zTel8MOH1SOSeAun&z=dc@4;XY+S}Vjw{_#j4Z$)Vj|bkqeH)jzbLUQa{s2V8=H_PJ zGrZI3Oj@tCwUyW>`26|vq%!%UP=<$x>0XTV_4OgcFr0=WERk*&sp5q*KyWLn?TAK2$PgPYF`g}eNhr@`7$g(VU zcX#uCgp(&v65GP05-EE5@@3BC6CtC~2#t-6px5hRWMl-|+S-VZsC<*J#bSZN!a{Jl zT+q?c!Mo*s@!|!T&1SlD03zbZ$cU)OE|BnkP^D7g@87@a-wj5b8bXc@F{i#v((&WR z%|FqurSYE=r6zp37k;n=LDPKswQ*X@|)jIB-B#ft3S~s^l+FT)sHv$5T3cI1 zmDOssU^E&bH#Zl;;V}4oK2fePrBVqtn+*;fI+PiuGyO!Syu4i0S3H0IJWfnZL|>TL zY&J9)41)FA+uO7I#fZn_Nhu&oh#7{#2M-?n9dCxl#>TLsq9UUJq!Iun8vv2vux;D6 zj2v_O`}=9BiPYZ>-nw;5R9p}rH#Ron`1m+g{Umuf>G%8b(xpp8JG_q{Kc@W}MDk@& zi2nTf1CJj+hR)7T7#$sr-V`$o1G%}mP*YO_=gysjBS(%%c9N77fNZ3H{`L5O?1PYn T+Sb?p00000NkvXXu0mjfIgx;X literal 0 HcmV?d00001