# -*- coding: utf-8 -*- from random import randint, choice from math import pi from copy import copy from glob import iglob from os.path import basename from threading import Thread from serial import Serial from PIL import Image, ImageDraw from pygame import Surface, Color from pygame.event import clear from pygame.mixer import Sound from pygame.image import load, fromstring from pygame.transform import rotate, flip from pygame.time import get_ticks from pygame.font import Font from pygame.draw import aalines, lines from pygame.gfxdraw import aapolygon, arc, polygon from pygame.locals import * from lib.pgfw.pgfw.Game import Game from lib.pgfw.pgfw.GameChild import GameChild from lib.pgfw.pgfw.Sprite import Sprite, RainbowSprite from lib.pgfw.pgfw.Animation import Animation from lib.pgfw.pgfw.Audio import SoundEffect from lib.pgfw.pgfw.extension import ( get_step, get_step_relative, get_delta, reflect_angle, render_box, get_hsla_color, get_hue_shifted_surface ) from lib.pgfw.pgfw.gfx_extension import aa_filled_polygon class NS(Game, Animation): LNW, LNE, LSE, LSW = range(4) N, NE, E, NW, S, W = range(6) FRONT_WIDTH = 230 BACK_WIDTH = 500 LENGTH = 150 FRONT = 300 STEP = .4 IDLE_TIMEOUT = 60000 * 5 def __init__(self): Game.__init__(self) Animation.__init__(self, self) self.load_sfx() self.subscribe(self.respond, KEYDOWN) self.subscribe(self.respond, KEYUP) self.subscribe(self.respond) ds = self.get_display_surface() self.background = Surface(ds.get_size()) self.background.fill((0, 0, 0)) self.title = Title(self) self.introduction = Introduction(self) self.ending = Ending(self) self.wipe = Wipe(self) self.platform = Platform(self) self.dialogue = Dialogue(self) self.chemtrails = Chemtrails(self) self.boss = Boss(self) self.get_configuration().type_declarations.add_chart( { "time": { "int": ["timer-max-time", "timer-start-time", "timer-addition", "sword-delay"] }, "input": { "bool": "serial" } }) if self.serial_enabled(): self.serial_kill = False self.serial_data = 0 self.serial_reader = Serial(self.get_configuration("input", "arduino-port"), timeout=.1) self.serial_thread = Thread(target=self.read_serial) self.serial_thread.start() self.last_press = get_ticks() self.register(self.blink_score, interval=500) self.play(self.blink_score) self.reset() self.most_recent_time = None clear() def load_sfx(self): sfx = self.sfx = {} for path in iglob(self.get_resource("sfx/") + "*.wav"): sfx[basename(path.split(".")[0])] = SoundEffect(self, path) def serial_enabled(self): return self.get_configuration("input", "serial") and not self.check_command_line("-no-serial") def read_serial(self): while not self.serial_kill: output = self.serial_reader.readline().strip() if output: self.serial_data = int(output, 2) self.idle_elapsed = 0 else: self.serial_data = 0 def end(self, evt): if evt.type == QUIT or self.delegate.compare(evt, "quit"): self.serial_kill = True Game.end(self, evt) def apply_serial(self): for ii, light in enumerate(self.platform.lights): light.pressed = bool(self.serial_data & (2 ** ii)) def reset(self, leave_wipe_running=False): self.score_hidden = False self.idle_elapsed = 0 self.suppressing_input = False self.title.reset() if not leave_wipe_running: self.wipe.reset() self.introduction.reset() self.ending.reset() self.boss.reset() self.chemtrails.reset() self.platform.reset() self.dialogue.reset() def set_most_recent_time(self, score): self.most_recent_time = score def blink_score(self): self.score_hidden = not self.score_hidden def suppress_input(self): self.suppressing_input = True # self.platform.unpress() def unsuppress_input(self): self.suppressing_input = False def respond(self, event): if not self.suppressing_input and event.type in (KEYDOWN, KEYUP): if self.last_press <= get_ticks() - int(self.get_configuration("input", "buffer")): pressed = True if event.type == KEYDOWN else False lights = self.platform.lights self.idle_elapsed = 0 if event.key in (K_UP, K_o): lights[NS.LNW].pressed = pressed elif event.key in (K_RIGHT, K_p): lights[NS.LNE].pressed = pressed elif event.key in (K_DOWN, K_SEMICOLON): lights[NS.LSE].pressed = pressed elif event.key in (K_LEFT, K_l): lights[NS.LSW].pressed = pressed elif event.key == K_z: self.reset() self.last_press = get_ticks() else: if self.get_delegate().compare(event, "reset-game"): self.reset() def update(self): Animation.update(self) if self.serial_enabled(): self.apply_serial() self.title.update() self.introduction.update() self.ending.update() self.boss.update() if not self.introduction.active: self.platform.update() self.chemtrails.update() self.boss.update_dialogue() self.wipe.update() self.idle_elapsed += self.time_filter.get_last_frame_duration() if self.idle_elapsed >= self.IDLE_TIMEOUT: self.reset() class Title(GameChild): def __init__(self, parent): GameChild.__init__(self, parent) self.plank = Sprite(self) self.plank.load_from_path(self.get_resource("Title_plank.png"), True) ds = self.get_display_surface() dsr = ds.get_rect() self.plank.location.center = dsr.center self.slime_bag = Sprite(self) self.slime_bag.load_from_path(self.get_resource("Title_slime_bag.png"), True) self.slime_bag.location.bottomleft = dsr.bottomleft image = load(self.get_resource("Title_border.png")).convert() image.set_colorkey((0, 0, 0)) self.border = RainbowSprite(self, image, 30) self.border.location.center = dsr.centerx, dsr.bottom - 100 self.text = Sprite(self) self.text.load_from_path(self.get_resource("Title_text.png"), True, False, (255, 0, 0)) self.text.load_from_path(self.get_resource("Title_text_half.png"), True, False, (255, 0, 0)) self.text.add_frameset([0], name="full", switch=True) self.text.add_frameset([1], name="half") self.text.location.center = dsr.centerx, dsr.bottom - 100 self.angle = choice((pi / 4, 3 * pi / 4, 5 * pi / 4, 7 * pi / 4)) self.button_sound = self.get_game().sfx["button"] def reset(self): self.activate() self.first_pressed = False self.first_pressed_elapsed = 0 self.text.set_frameset("full") def activate(self): self.active = True def deactivate(self): self.active = False def activate_introduction(self): self.deactivate() self.get_game().introduction.activate() self.get_game().set_most_recent_time(None) def draw_scores(self): step = 75 ds = self.get_display_surface() lines = map(int, file(self.get_resource("scores")).readlines()) entries = ["BEST"] + sorted(lines)[:9] for ii, entry in enumerate(entries): if ii == 0 or ii == 5: y = 30 font = Font(self.get_resource(Dialogue.FONT_PATH), 18) if ii > 0: text = self.get_formatted_time(entry) else: text = entry message = render_box(font, text, True, Color(255, 255, 255), Color(128, 128, 128), Color(0, 0, 0), padding=2) message.set_alpha(200) rect = message.get_rect() rect.top = y if ii < 5: rect.left = -1 else: rect.right = ds.get_width() + 1 if not entry == self.get_game().most_recent_time or not self.get_game().score_hidden: ds.blit(message, rect) y += step def get_formatted_time(self, entry): if int(entry) == 5999999: return "--:--.-" else: minutes, milliseconds = divmod(int(entry), 60000) seconds, fraction = divmod(milliseconds, 1000) return "%i:%02i.%i" % (minutes, seconds, fraction / 100) def update(self): if self.active: ds = self.get_display_surface() ds.fill((255, 255, 255)) dsr = ds.get_rect() if self.plank.location.right > dsr.right or self.plank.location.left < dsr.left: self.angle = reflect_angle(self.angle, 0) if self.plank.location.right > dsr.right: self.plank.move(dsr.right - self.plank.location.right) else: self.plank.move(dsr.left - self.plank.location.left) if self.plank.location.bottom > dsr.bottom or self.plank.location.top < dsr.top: self.angle = reflect_angle(self.angle, pi) if self.plank.location.bottom > dsr.bottom: self.plank.move(dy=dsr.bottom - self.plank.location.bottom) else: self.plank.move(dy=dsr.top - self.plank.location.top) dx, dy = get_delta(self.angle, 2, False) self.plank.move(dx, dy) self.plank.update() self.slime_bag.update() wipe = self.get_game().wipe if not self.first_pressed and self.get_game().platform.get_edge_pressed() == NS.N: self.first_pressed = True self.first_pressed_elapsed = 0 self.text.set_frameset("half") self.button_sound.play() elif not wipe.is_playing() and self.first_pressed and \ self.get_game().platform.get_edge_pressed() == NS.NW: wipe.start(self.activate_introduction) self.get_game().sfx["confirm"].play() elif self.first_pressed: self.first_pressed_elapsed += self.get_game().time_filter.get_last_frame_duration() if self.first_pressed_elapsed > 4000: self.first_pressed = False self.first_pressed_elapsed = 0 self.text.set_frameset("full") self.border.update() self.text.update() self.draw_scores() class Dialogue(Animation): BACKGROUND = 255, 255, 255 BORDER = 0, 0, 0 TEXT_COLOR = 0, 0, 0 FONT_PATH = "rounded-mplus-1m-bold.ttf" FONT_SIZE = 18 def __init__(self, parent): Animation.__init__(self, parent) ds = self.get_display_surface() dsr = ds.get_rect() frame = Surface((640, 72)) frame.fill(self.BORDER) frame.fill(self.BACKGROUND, (1, 1, frame.get_width() - 2, frame.get_height() - 2)) self.text_box = Sprite(self) self.text_box.add_frame(frame) self.text_box.location.bottomleft = dsr.bottomleft frame = Surface((66, 66)) frame.fill(self.BORDER) frame.fill(self.BACKGROUND, (1, 1, frame.get_width() - 2, frame.get_height() - 2)) self.avatar_box = Sprite(self) self.avatar_box.add_frame(frame) self.avatar_box.location.bottomleft = self.text_box.location.topleft frame = Surface((128, 24)) frame.fill(self.BORDER) frame.fill(self.BACKGROUND, (1, 1, frame.get_width() - 2, frame.get_height() - 2)) self.name_box = Sprite(self) self.name_box.add_frame(frame) self.name_box.location.bottomleft = self.avatar_box.location.bottomright self.speech_channel = None def reset(self): self.stop_speech() self.halt() self.deactivate() self.first_pressed = False self.first_press_elapsed = 0 def stop_speech(self): if self.speech_channel is not None: self.speech_channel.stop() self.speech_channel = None def deactivate(self): self.stop_speech() self.active = False def activate(self): self.active = True def set_avatar(self, image): self.avatar = Sprite(self) self.avatar.add_frame(image) self.avatar.location.center = self.avatar_box.location.center def set_name(self, text): font = Font(self.get_resource(self.FONT_PATH), self.FONT_SIZE) self.name = Sprite(self) self.name.add_frame(font.render(text, True, self.TEXT_COLOR)) self.name.location.midleft = self.name_box.location.left + 5, self.name_box.location.centery def show_text(self, text): self.full_text = text self.text_index = 0 self.speech_channel = self.get_game().sfx["talk"].play(-1) self.play() def build_frame(self): self.text_index += 2 if self.text_index >= len(self.full_text): self.show_all() def show_all(self): self.stop_speech() self.text_index = len(self.full_text) self.halt() def update(self): if self.active: Animation.update(self) self.avatar_box.update() self.avatar.update() self.name_box.update() self.name.update() self.text_box.update() font = Font(self.get_resource(self.FONT_PATH), self.FONT_SIZE) message = Sprite(self) lines = self.full_text[:self.text_index].split("\n") frame = Surface((self.text_box.location.w - 10, 30 * len(lines)), SRCALPHA) for ii, line in enumerate(lines): surface = font.render(line, True, self.TEXT_COLOR) frame.blit(surface, (0, 30 * ii)) message.add_frame(frame) message.location.topleft = self.text_box.location.left + 9, self.text_box.location.top + 8 message.update() class Introduction(Animation): TEXT = "Hey, you lizard slime bag. It's me Giant Tony. " + \ "Do you think you\ncan skate like me? Prove it!", \ "I'll even give you my board for this adventure. And ink my name\n" + \ "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!", \ "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 def __init__(self, parent): Animation.__init__(self, parent) self.tony = load(self.get_resource("Big_Tony.png")).convert() self.skateboard = Sprite(self) self.skateboard.load_from_path(self.get_resource("Introduction_skateboard.png"), True) self.slime_bag = Sprite(self) self.slime_bag.load_from_path(self.get_resource("Introduction_slime_bag.png"), True) self.slime_bag.load_from_path(self.get_resource("Introduction_slime_bag_board.png"), True) self.slime_bag.add_frameset([0], name="standing", switch=True) self.slime_bag.add_frameset([1], name="board") self.slime_bag.location.center = self.get_display_surface().get_rect().center self.tony_avatar = load(self.get_resource("Introduction_tony_avatar.png")).convert() self.advance_prompt = AdvancePrompt(self) self.skip_prompt = SkipPrompt(self, self.start_wipe) self.register(self.start, self.move_board, self.take_board) def reset(self): self.deactivate() self.slime_bag.set_frameset("standing") self.slime_bag.unhide() self.halt() self.skateboard.hide() self.text_index = 0 self.tutorial_index = 0 self.advance_prompt.reset() self.skip_prompt.reset() def deactivate(self): self.active = False 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() dialogue = self.get_game().dialogue dialogue.activate() dialogue.set_avatar(self.tony_avatar) dialogue.set_name("???") dialogue.show_text(self.TEXT[0]) self.text_index = 0 def give_board(self): self.skateboard.location.center = self.SKATEBOARD_START self.skateboard_step = get_step(self.skateboard.location.center, self.slime_bag.location.center, 2) self.skateboard.unhide() self.play(self.move_board) def move_board(self): self.skateboard.move(*self.skateboard_step) if self.skateboard.location.colliderect(self.slime_bag.location.inflate(-30, -30)): self.halt(self.move_board) self.play(self.take_board, delay=2000, play_once=True) self.get_game().sfx["go"].play() def take_board(self): self.skateboard.hide() self.slime_bag.set_frameset("board") def activate_boss(self): self.deactivate() self.get_game().boss.start_level(0) def start_wipe(self): self.get_game().wipe.start(self.activate_boss) def update(self): if self.active: Animation.update(self) dialogue = self.get_game().dialogue wipe = self.get_game().wipe if not wipe.is_playing() and not self.is_playing(self.start) and not self.text_index == 2: if self.advance_prompt.check_first_press(): self.advance_prompt.press_first() elif self.advance_prompt.check_second_press(): if dialogue.is_playing(): dialogue.show_all() else: if self.text_index < len(self.TEXT) - 1: self.text_index += 1 if self.text_index == 1: dialogue.set_name("Tony") self.give_board() elif self.text_index == 2: self.slime_bag.hide() self.halt(self.move_board) self.take_board() platform = self.get_game().platform platform.activate() platform.set_glowing(platform.get_buttons_from_edges( [self.TUTORIAL_MOVES[self.tutorial_index]])) self.get_game().chemtrails.activate() dialogue.show_text(self.TEXT[self.text_index]) else: self.start_wipe() # self.get_game().platform.unpress() self.advance_prompt.cancel_first_press() elif self.text_index == 2: platform = self.get_game().platform if platform.get_edge_pressed() == self.TUTORIAL_MOVES[self.tutorial_index]: self.tutorial_index += 1 self.get_game().sfx["land_0"].play() if self.tutorial_index == len(self.TUTORIAL_MOVES): self.text_index += 1 self.advance_prompt.cancel_first_press() platform.set_glowing([]) dialogue.show_text(self.TEXT[self.text_index]) else: platform.set_glowing(platform.get_buttons_from_edges( [self.TUTORIAL_MOVES[self.tutorial_index]])) self.get_display_surface().blit(self.tony, (0, 0)) self.slime_bag.update() self.skateboard.update() self.get_game().platform.update() self.get_game().dialogue.update() if not wipe.is_playing() and not self.is_playing(self.start) and \ not self.text_index == 2: self.advance_prompt.update() if not wipe.is_playing() and not self.text_index == 2: self.skip_prompt.update() class SkipPrompt(Sprite): def __init__(self, parent, callback): Sprite.__init__(self, parent) self.callback = callback for ii in xrange(3): self.load_from_path(self.get_resource("Skip_%i.png" % ii), True) self.add_frameset([ii]) self.button_sound = self.get_game().sfx["button"] def reset(self): self.press_index = 0 self.press_elapsed = 0 self.set_frameset(1) def update(self): platform = self.get_game().platform if self.press_index == 0 and platform.get_edge_pressed() == NS.S: self.press_index += 1 self.set_frameset(2) self.button_sound.play() elif self.press_index == 1 and platform.get_edge_pressed() == NS.NE: self.press_index += 1 self.set_frameset(3) self.button_sound.play() elif self.press_index == 2 and platform.get_edge_pressed() == NS.W: self.callback() self.get_game().sfx["confirm"].play() elif self.press_index > 0: self.press_elapsed += self.get_game().time_filter.get_last_frame_duration() if self.press_elapsed > 4000: self.reset() Sprite.update(self) class AdvancePrompt(Sprite): def __init__(self, parent): Sprite.__init__(self, parent) self.load_from_path(self.get_resource("Dialogue_buttons_full.png"), True, False, (255, 255, 255)) self.load_from_path(self.get_resource("Dialogue_buttons_half.png"), True, False, (255, 255, 255)) self.add_frameset([0], name="full", switch=True) self.add_frameset([1], name="half") dsr = self.get_display_surface().get_rect() self.location.bottomright = dsr.right - 3, dsr.bottom - 3 def reset(self): self.cancel_first_press() def cancel_first_press(self): self.first_pressed = False self.first_pressed_elapsed = 0 self.set_frameset("full") def check_first_press(self): return not self.first_pressed and self.get_game().platform.get_edge_pressed() == NS.N def press_first(self): self.first_pressed = True self.set_frameset("half") self.get_game().sfx["button"].play() def check_second_press(self): pressed = self.first_pressed and self.get_game().platform.get_edge_pressed() == NS.NW if pressed: self.get_game().sfx["confirm"].play() return pressed def update(self): if self.first_pressed: self.first_pressed_elapsed += self.get_game().time_filter.get_last_frame_duration() if self.first_pressed_elapsed > 4000: self.cancel_first_press() Sprite.update(self) class Wipe(Animation): BLIND_COUNT = 4 SPEED = 6 TRANSPARENT_COLOR = 255, 0, 0 def __init__(self, parent): Animation.__init__(self, parent) self.image = load(self.get_resource("Ink.png")).convert() self.image.set_colorkey(self.TRANSPARENT_COLOR) self.sound = self.get_game().sfx["wipe"] def reset(self): self.deactivate() self.halt() def deactivate(self): self.active = False def activate(self): self.active = True def start(self, callback): self.activate() self.up = True # self.get_game().suppress_input() self.blind_height = self.get_display_surface().get_height() / self.BLIND_COUNT self.callback = callback self.play() self.sound.play() def build_frame(self): if self.up: self.blind_height -= self.SPEED if self.blind_height <= 0: self.up = False self.callback() else: self.blind_height += self.SPEED if self.blind_height >= self.get_display_surface().get_height() / self.BLIND_COUNT: self.halt() self.deactivate() self.get_game().unsuppress_input() def update(self): if self.active: Animation.update(self) ds = self.get_display_surface() dsr = ds.get_rect() frame = self.image.copy() for y in xrange(0, dsr.h, dsr.h / self.BLIND_COUNT): if self.up: frame.fill(self.TRANSPARENT_COLOR, (0, y, dsr.w, self.blind_height)) else: frame.fill(self.TRANSPARENT_COLOR, (0, y + dsr.h / self.BLIND_COUNT - self.blind_height, dsr.w, self.blind_height)) ds.blit(frame, (0, 0)) class Platform(GameChild): def __init__(self, parent): GameChild.__init__(self, parent) self.lights = [ Light(self, "cyan", NS.LNW), Light(self, "magenta", NS.LNE), Light(self, "yellow", NS.LSE), Light(self, "white", NS.LSW) ] def reset(self): self.deactivate() self.reset_lights() def reset_lights(self): for light in self.lights: light.reset() def deactivate(self): self.active = False def activate(self): self.active = True def unpress(self): for light in self.lights: light.pressed = False def get_pressed(self): return [light.position for light in self.lights if light.pressed] def get_edge_pressed(self): pressed = self.get_pressed() if NS.LNW in pressed and NS.LNE in pressed: return NS.N elif NS.LNE in pressed and NS.LSW in pressed: return NS.NE elif NS.LNE in pressed and NS.LSE in pressed: return NS.E elif NS.LNW in pressed and NS.LSE in pressed: return NS.NW elif NS.LSE in pressed and NS.LSW in pressed: return NS.S elif NS.LSW in pressed and NS.LNW in pressed: return NS.W def get_buttons_from_edges(self, edges): buttons = set() for edge in edges: if edge == NS.N: buttons = buttons.union((NS.LNW, NS.LNE)) elif edge == NS.NE: buttons = buttons.union((NS.LNE, NS.LSW)) elif edge == NS.E: buttons = buttons.union((NS.LNE, NS.LSE)) elif edge == NS.NW: buttons = buttons.union((NS.LNW, NS.LSE)) elif edge == NS.S: buttons = buttons.union((NS.LSE, NS.LSW)) elif edge == NS.W: 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 get_color_pair_from_edge(self, edge): if edge == NS.N: return self.lights[NS.LNW].color, self.lights[NS.LNE].color elif edge == NS.NE: return self.lights[NS.LNE].color, self.lights[NS.LSW].color elif edge == NS.E: return self.lights[NS.LNE].color, self.lights[NS.LSE].color elif edge == NS.NW: return self.lights[NS.LNW].color, self.lights[NS.LSE].color elif edge == NS.S: return self.lights[NS.LSW].color, self.lights[NS.LSE].color elif edge == NS.W: return self.lights[NS.LNW].color, self.lights[NS.LSW].color def set_glowing(self, selected): for ii, light in enumerate(self.lights): light.glow_index = 0 light.halt(light.glow) if ii in selected: light.play(light.glow) def update(self): if self.active: for light in self.lights: light.update() for light in self.lights: light.draw_glow() class Light(Animation): MAX_GLOW_INDEX = 16 INTRODUCTION_OFFSET = 80 def __init__(self, parent, color, position): Animation.__init__(self, parent) self.color = Color(color) self.color.a = 225 self.position = position self.pressed = False ds = self.get_display_surface() frontleft = ds.get_width() / 2 - NS.FRONT_WIDTH / 2, NS.FRONT backleft = ds.get_width() / 2 - NS.BACK_WIDTH / 2, NS.FRONT + NS.LENGTH left_step = get_step_relative(frontleft, backleft, NS.STEP) midleft = frontleft[0] + left_step[0], frontleft[1] + left_step[1] frontmid = ds.get_width() / 2, NS.FRONT mid = ds.get_width() / 2, NS.FRONT + NS.LENGTH * NS.STEP backmid = ds.get_width() / 2, NS.FRONT + NS.LENGTH frontright = ds.get_width() / 2 + NS.FRONT_WIDTH / 2, NS.FRONT backright = ds.get_width() / 2 + NS.BACK_WIDTH / 2, NS.FRONT + NS.LENGTH right_step = get_step_relative(frontright, backright, NS.STEP) midright = frontright[0] + right_step[0], frontright[1] + right_step[1] if self.position == NS.LNW: self.points = frontleft, frontmid, mid, midleft elif self.position == NS.LNE: self.points = frontmid, frontright, midright, mid elif self.position == NS.LSE: self.points = mid, midright, backright, backmid elif self.position == NS.LSW: self.points = midleft, mid, backmid, backleft self.register(self.blink, interval=300) self.register(self.glow) def reset(self): self.hidden = False self.halt(self.blink) self.halt(self.glow) self.reset_timer() self.glow_index = 0 def blink(self): self.hidden = not self.hidden def glow(self): self.glow_index += 1 if self.glow_index > self.MAX_GLOW_INDEX: self.glow_index = 0 def update(self): Animation.update(self) 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.glow) \ and 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() if not self.hidden: ds = self.get_display_surface() aa_filled_polygon(ds, self.get_points(), self.color) def get_points(self): if self.get_game().introduction.active: points = [] for point in self.points: points.append((point[0], point[1] - self.INTRODUCTION_OFFSET)) return points else: return self.points def draw_glow(self): for ii in reversed(xrange(0, self.glow_index, 1)): shifted = [] for point in self.get_points(): shifted.append((point[0], point[1] - ii)) ratio = 1 - float(ii + 1) / (self.MAX_GLOW_INDEX + 1) alpha = int(ratio * 255) color = Color(self.color.r, self.color.g, self.color.b, alpha) ds = self.get_display_surface() intermediate = Surface(ds.get_size(), SRCALPHA) lines(intermediate, get_hsla_color(int(color.hsla[0]), int(color.hsla[1]), int(color.hsla[2]), int(ratio * 100)), True, shifted, 5) ds.blit(intermediate, (0, 0)) def in_orientation(self, orientation): if self.position == NS.LNW: return orientation in (NS.N, NS.NW, NS.W) elif self.position == NS.LNE: return orientation in (NS.N, NS.NE, NS.E) elif self.position == NS.LSE: return orientation in (NS.NW, NS.E, NS.S) elif self.position == NS.LSW: return orientation in (NS.S, NS.NE, NS.W) class Chemtrails(Sprite): def __init__(self, parent): Sprite.__init__(self, parent) self.load_from_path(self.get_resource("littleSlimeGoop"), True) for direction in (NS.N, NS.NE, NS.E, NS.NW, NS.S, NS.W): self.add_frameset([direction], switch=(direction == NS.N)) self.life = Life(self) self.timer = Timer(self) def reset(self): self.deactivate() self.life.reset() self.timer.reset() def deactivate(self): self.active = False def activate(self): self.active = True def challenge(self): self.timer.reset() self.queue_index = 0 def update(self): if self.active: self.orient() Sprite.update(self) if not self.get_game().introduction.active: boss = self.get_game().boss if boss.queue: self.timer.tick() self.attack() if self.timer.time_remaining < 0: self.life.decrease() if not boss.is_playing(boss.show_end_dialogue): self.timer.reset() boss.combo() self.timer.update() self.life.update() def attack(self): boss = self.get_game().boss queue = boss.queue if self.orientation == queue[self.queue_index]: self.timer.add_time(self.get_configuration("time", "timer-addition")) 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 boss.sword.block() if self.queue_index == len(queue): self.timer.reset() if not boss.is_playing(boss.show_end_dialogue): boss.combo() # boss.damaged.unhide() self.get_game().sfx["complete_pattern_3"].play() else: self.get_game().sfx["land_0"].play() self.get_game().platform.reset_lights() def orient(self): ds = self.get_display_surface() edge = self.get_game().platform.get_edge_pressed() dy = -Light.INTRODUCTION_OFFSET if self.get_game().introduction.active else 0 if edge is not None: self.set_frameset(edge + 1) self.unhide() else: self.hide() if edge == NS.N: self.location.center = ds.get_width() / 2, NS.FRONT + 15 + dy self.orientation = NS.N elif edge == NS.E: self.location.center = ds.get_width() / 2 + NS.FRONT_WIDTH / 2 - 115, \ NS.FRONT + NS.LENGTH * NS.STEP - 75 + dy self.orientation = NS.E elif edge == NS.S: self.location.center = ds.get_width() / 2, \ NS.FRONT + NS.LENGTH - NS.LENGTH * NS.STEP - 110 + dy self.orientation = NS.S elif edge == NS.W: self.location.center = ds.get_width() / 2 - NS.FRONT_WIDTH / 2 + 100, \ NS.FRONT + NS.LENGTH * NS.STEP - 85 + dy self.orientation = NS.W elif edge == NS.NW: self.location.center = ds.get_width() / 2 + 5, \ NS.FRONT + NS.LENGTH * NS.STEP - 75 + dy self.orientation = NS.NW elif edge == NS.NE: self.location.center = ds.get_width() / 2 + 10, \ NS.FRONT + NS.LENGTH * NS.STEP - 80 + dy self.orientation = NS.NE else: self.orientation = None class Timer(GameChild): TEXT = u"\u25F7" BAR_POSITION = 448, 11 SIZE = 160 TOP = 120 RING_OFFSET = 8 def __init__(self, parent): GameChild.__init__(self, parent) self.background = Sprite(self) image = load(self.get_resource("HUD_background.png")).convert_alpha() image = flip(image, True, False) self.background.add_frame(image) self.background.location.topright = self.get_display_surface().get_rect().topright self.bar = load(self.get_resource("HUD_bar.png")).convert_alpha() self.bar = flip(self.bar, True, False) self.hourglass = Sprite(self) self.hourglass.load_from_path(self.get_resource("Hourglass.png"), True) dsr = self.get_display_surface().get_rect() self.hourglass.location.midright = dsr.right, self.TOP + self.SIZE / 2 def reset(self): self.time_remaining = self.get_configuration("time", "timer-start-time") def add_time(self, amount): self.time_remaining += amount def tick(self): self.time_remaining -= self.get_game().time_filter.get_last_frame_duration() def update(self): self.hourglass.update() if self.time_remaining > 5500: hue = 120 elif self.time_remaining > 3000: hue = 30 else: hue = 0 ds = self.get_display_surface() max_time = self.get_configuration("time", "timer-max-time") remaining_ratio = float(self.time_remaining) / max_time left = ds.get_width() - self.SIZE / 2 ds.blit(self.get_ring(get_hsla_color(hue, lightness=20, alpha=67), remaining_ratio), (left, self.TOP + self.RING_OFFSET)) ds.blit(self.get_ring(get_hsla_color(hue, lightness=80, alpha=67), remaining_ratio), (left, self.TOP - self.RING_OFFSET)) ds.blit(self.get_ring(get_hsla_color(hue, alpha=67), remaining_ratio), (left, self.TOP)) def get_ring(self, color, remaining): image = Image.new("RGBA", (self.SIZE, self.SIZE)) draw = ImageDraw.Draw(image) draw.pieslice((0, 0, self.SIZE - 1, self.SIZE - 1), 90, remaining * 180 + 90, fill=(color.r, color.g, color.b, color.a)) draw.ellipse((self.SIZE / 4, self.SIZE / 4, self.SIZE / 4 * 3, self.SIZE / 4 * 3), (0, 0, 0, 0)) return fromstring(image.tobytes(), image.size, image.mode) class Life(GameChild): SPACING = 30 MARGIN = 0 def __init__(self, parent): GameChild.__init__(self, parent) self.heart = load(self.get_resource("Heart.png")).convert_alpha() def reset(self): self.count = 3 def decrease(self): self.get_game().sfx["hurt"].play() if self.count > 0: self.count -= 1 if self.count <= 0: self.count = 0 self.get_game().boss.finish_battle(False) def update(self): ds = self.get_display_surface() dsr = ds.get_rect() hr = self.heart.get_rect() rect = Rect(0, 0, hr.w * self.count + self.SPACING * (self.count - 1), hr.h) rect.midbottom = dsr.centerx, dsr.h - self.MARGIN for x in xrange(rect.left, rect.right, hr.w + self.SPACING): ds.blit(self.heart, (x, rect.top)) class Boss(Animation): def __init__(self, parent): Animation.__init__(self, parent) self.kool_man = RainbowSprite(self, load(self.get_resource("Kool_man_waah.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_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) self.backgrounds = [Sprite(self), Sprite(self), Sprite(self)] self.backgrounds[0].load_from_path(self.get_resource("local/bg001.png")) self.backgrounds[1].load_from_path(self.get_resource("local/bg002.png")) self.backgrounds[2].load_from_path(self.get_resource("local/bg003.png")) def cancel_flash(self): 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, 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() 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_introduction_dialogue(self): dialogue = self.get_game().dialogue dialogue.activate() if self.level_index == 0: dialogue.show_text("You'll never be able to block my sword, you lizard slime!" + " See\nif you can 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.kills = 0 self.time_elapsed = 0 self.deactivate() self.cancel_flash() self.halt(self.cancel_flash) self.health.reset() self.halt(self.brandish) self.sword.reset() self.advance_prompt.reset() self.queue = None self.brandish_complete = True def deactivate(self): self.active = False def activate(self): self.active = True def combo(self): self.queue = None self.play(self.brandish, delay=2500, play_once=True) def brandish(self): self.queue = [] 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.reset() 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.add_score() self.player_defeated = not win self.kills += not win self.play(self.show_end_dialogue, delay=3000, play_once=True) def add_score(self): self.get_game().set_most_recent_time(self.time_elapsed) file(self.get_resource("scores"), "a").write(str(self.time_elapsed) + "\n") 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 self.kills >= 3: self.get_game().reset(True) elif index < 3: self.start_level(index) else: game = self.get_game() game.boss.reset() game.chemtrails.reset() game.platform.reset() game.ending.activate() def transition_to_title(self): 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) elif self.level_index == 2: self.spoopy.set_frameset(0) def update(self): if self.active: self.backgrounds[self.level_index].update() # self.get_display_surface().fill((0, 0, 0)) dialogue = self.get_game().dialogue if dialogue.active: if self.advance_prompt.check_first_press(): self.advance_prompt.press_first() elif self.advance_prompt.check_second_press(): if dialogue.is_playing(): dialogue.show_all() else: self.get_game().dialogue.deactivate() if not self.battle_finished: self.combo() else: self.get_game().wipe.start(self.transition_to_battle) self.advance_prompt.cancel_first_press() else: self.time_elapsed += self.get_game().time_filter.get_last_frame_duration() 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() def update_dialogue(self): if self.active: dialogue = self.get_game().dialogue if dialogue.active: self.get_game().dialogue.update() self.advance_prompt.update() class Sword(Animation): OFFSET = 10 SPRITE_COUNT = 6 def __init__(self, parent): Animation.__init__(self, parent) swords = self.swords = [] for path in ("Sword_kool_man.png", "Sword_visitor.png", "Sword_spoopy.png"): swords.append([]) image = load(self.get_resource(path)).convert_alpha() for _ in xrange(6): sprite = Sprite(self) sprite.add_frame(image) for angle in 270, 315, 45: sprite.add_frame(rotate(image, angle)) sprite.add_frameset([0], name="vertical") sprite.add_frameset([1], name="horizontal") sprite.add_frameset([2], name="rdiagonal") sprite.add_frameset([3], name="ldiagonal") sprite.set_frameset("vertical") sprite.location.center = self.get_display_surface().get_rect().center swords[-1].append(sprite) # for _ in xrange(self.SPRITE_COUNT): # sprite = Sprite(self) # sprite.load_from_path(self.get_resource("kool/"), True, query="[0-9]-*.png") # for ii in xrange(6): # sprite.add_frameset(ii) # sprite.location.topleft = 114, 0 # sprites.append(sprite) self.register(self.brandish, self.lower) def reset(self): self.halt(self.brandish) self.halt(self.lower) self.next_index = 0 self.sprites = self.swords[self.get_game().boss.level_index] for sword in self.swords: for sprite in sword: sprite.hide() def brandish(self): sprite = self.sprites[self.next_index] sprite.sword_position = position = self.parent.unbrandished.pop(0) self.next_index += 1 sprite.unhide() dsr = self.get_display_surface().get_rect() if position in (NS.W, NS.E): sprite.set_frameset("vertical") sprite.location.centery = dsr.centery - 100 if position == NS.W: sprite.location.centerx = dsr.centerx - 100 else: sprite.location.centerx = dsr.centerx + 100 elif position in (NS.N, NS.S): sprite.set_frameset("horizontal") sprite.location.centerx = dsr.centerx if position == NS.N: # sprite.location.centery = dsr.centery - 200 sprite.location.centery = dsr.centery - 170 else: sprite.location.centery = dsr.centery else: if position == NS.NW: sprite.set_frameset("ldiagonal") else: sprite.set_frameset("rdiagonal") sprite.location.center = dsr.centerx, dsr.centery - 100 # sprite.set_frameset(position + 1) self.get_game().sfx["brandish"].play() self.play(self.lower, delay=400, play_once=True) if len(self.parent.unbrandished) > 0: self.play(self.brandish, delay=self.get_configuration("time", "sword-delay"), play_once=True) def lower(self): # self.hide() if len(self.parent.unbrandished) == 0: self.next_index = 0 self.parent.brandish_complete = True def block(self): for sprite in self.sprites: if not sprite.is_hidden(): sprite.hide() break def update(self): Animation.update(self) display_count = 0 offset = [self.OFFSET] * 6 for sprite in self.sprites: if not sprite.is_hidden(): display_count += 1 offset[sprite.sword_position] -= self.OFFSET display_index = 0 for sprite in reversed(self.sprites): if not sprite.is_hidden(): display_index += 1 alpha = int(float(display_index) / display_count * 255) surface = sprite.get_current_frame().copy() rect = surface.get_rect() colors = self.get_game().platform.get_color_pair_from_edge(sprite.sword_position) color_a = colors[0].r, colors[0].g, colors[0].b, alpha color_b = colors[1].r, colors[1].g, colors[1].b, alpha # color_a = 255, 255, 255, alpha # color_b = 255, 255, 255, alpha if sprite.sword_position == NS.NE: location = sprite.location.move(*([offset[sprite.sword_position]] * 2)).topleft else: location = sprite.location.move(offset[sprite.sword_position], -offset[sprite.sword_position]) if sprite.sword_position == NS.N or sprite.sword_position == NS.S: surface.fill(color_a, (0, 0, rect.w / 2, rect.h), BLEND_RGBA_MIN) surface.fill(color_b, (rect.centerx, 0, rect.w / 2, rect.h), BLEND_RGBA_MIN) else: surface.fill(color_a, (0, 0, rect.w, rect.h / 2), BLEND_RGBA_MIN) surface.fill(color_b, (0, rect.centery, rect.w, rect.h / 2), BLEND_RGBA_MIN) surface.fill((255, 255, 255, alpha), None, BLEND_RGBA_MIN) self.get_display_surface().blit(surface, location) offset[sprite.sword_position] += self.OFFSET # sprite.update() class Health(GameChild): TEXT = "BOSS" BAR_POSITION = 23, 11 BACKGROUND_ALPHA = 125 OFFSET = 11 def __init__(self, parent): GameChild.__init__(self, parent) # self.background = Sprite(self) # self.background.load_from_path(self.get_resource("HUD_background.png"), True) self.background = Sprite(self) self.background.load_from_path(self.get_resource("HUD_boss_health_background.png"), True) dsr = self.get_display_surface().get_rect() self.background.location.center = dsr.centerx, self.OFFSET self.foreground = Sprite(self) self.foreground.load_from_path(self.get_resource("HUD_boss_health_foreground.png"), True) self.foreground.location.center = dsr.centerx, self.OFFSET self.label = Sprite(self) font = Font(self.get_resource("rounded-mplus-1m-bold.ttf"), 24) text = font.render(self.TEXT, True, Color("white")) self.label.add_frame(text) self.label.location.topleft = 2, -2 self.bar = load(self.get_resource("HUD_bar.png")).convert_alpha() def reset(self): self.amount = 100 def decrease(self, damage): self.amount -= damage self.parent.damage() if self.amount <= 0: self.amount = 0 self.get_game().sfx["complete_pattern_1"].play() self.get_game().sfx["defeat"].play() self.get_game().boss.finish_battle(True) else: self.parent.play(self.parent.cancel_flash, delay=1000, play_once=True) def update(self): self.background.update() # self.label.update() if self.amount > 50: shift = 0 elif self.amount > 25: shift = -70 else: shift = -120 # mask = Surface(self.bar.get_size(), SRCALPHA) # mask.fill((128, 128, 128)) # mask.fill(color, (0, 0, int(mask.get_width() * (self.amount / 100.0)), # mask.get_height())) # surface = self.bar.copy() # surface.blit(mask, (0, 0), None, BLEND_RGBA_MIN) # self.get_display_surface().blit(surface, self.BAR_POSITION) ratio = self.amount / 100.0 ds = self.get_display_surface() ds.set_clip((self.foreground.location.left, self.foreground.location.top, int(self.foreground.location.w * ratio), self.foreground.location.h)) surface = get_hue_shifted_surface(self.foreground.get_current_frame(), shift) ds.blit(surface, self.foreground.location.topleft) ds.set_clip(None) class Ending(Animation): TEXT = "Wow! You vanquished all the goons and skated like a pro, slime bag.\n" + \ "You made your father proud today. I love you, child.", def __init__(self, parent): Animation.__init__(self, parent) self.tony = load(self.get_resource("Big_Tony.png")).convert() self.slime_bag = Sprite(self) self.slime_bag.load_from_path(self.get_resource("Introduction_slime_bag.png"), True) self.slime_bag.location.center = self.get_display_surface().get_rect().centerx, 300 self.tony_avatar = load(self.get_resource("Introduction_tony_avatar.png")).convert() self.advance_prompt = AdvancePrompt(self) self.register(self.start) def reset(self): self.deactivate() self.slime_bag.unhide() self.halt() self.text_index = 0 self.advance_prompt.reset() def deactivate(self): self.active = False def activate(self): self.active = True self.play(self.start, delay=3000, play_once=True) font = Font(self.get_resource("rounded-mplus-1m-bold.ttf"), 64) time = self.get_game().title.get_formatted_time(self.get_game().most_recent_time) foreground = font.render(time, True, (255, 28, 28)) # background = font.render(time, True, (0, 220, 220)) dsr = self.get_display_surface().get_rect() self.text = RainbowSprite(self, foreground, 120) self.text.location.midtop = dsr.centerx, 80 # self.shadow = RainbowSprite(self, background, 120) # self.shadow.location.midtop = dsr.centerx + 2, 70 def start(self): self.advance_prompt.cancel_first_press() dialogue = self.get_game().dialogue dialogue.activate() dialogue.set_avatar(self.tony_avatar) dialogue.set_name("Tony") dialogue.show_text(self.TEXT[0]) self.text_index = 0 def end_game(self): self.deactivate() self.get_game().reset(True) def start_wipe(self): self.get_game().wipe.start(self.end_game) def update(self): if self.active: Animation.update(self) dialogue = self.get_game().dialogue wipe = self.get_game().wipe if not wipe.is_playing() and not self.is_playing(self.start) and not self.text_index == 2: if self.advance_prompt.check_first_press(): self.advance_prompt.press_first() elif self.advance_prompt.check_second_press(): if dialogue.is_playing(): dialogue.show_all() else: if self.text_index < len(self.TEXT) - 1: pass else: self.start_wipe() self.advance_prompt.cancel_first_press() self.get_display_surface().blit(self.tony, (0, 0)) self.slime_bag.update() # self.shadow.update() self.text.update() self.get_game().dialogue.update() if not wipe.is_playing() and not self.is_playing(self.start): self.advance_prompt.update()