diff --git a/NS.py b/NS.py index 2108a88..dcfb9ea 100644 --- a/NS.py +++ b/NS.py @@ -10,7 +10,7 @@ # # This is the main file containing all the pygame code. -import argparse, pathlib, operator, subprocess, sys +import argparse, pathlib, operator, subprocess, sys, os from random import randint, choice, random from math import pi from copy import copy @@ -585,10 +585,10 @@ class LevelSelect(Animation): platform.view.frames[ii] = scaled platform.view.get_current_frameset().measure_rect() platform.view.update_location_size() - for corner in platform.glow_masks: - for ii, frame in enumerate(corner): - scaled = pygame.transform.smoothscale(frame, (int(frame.get_width() * scale), int(frame.get_height() * scale))) - corner[ii] = scaled + # for corner in platform.glow_masks: + # for ii, frame in enumerate(corner): + # scaled = pygame.transform.smoothscale(frame, (int(frame.get_width() * scale), int(frame.get_height() * scale))) + # corner[ii] = scaled self.platforms[0].view.location.left = dsr.left + indent self.platforms[1].view.location.centerx = dsr.centerx self.platforms[2].view.location.right = dsr.right - indent @@ -929,14 +929,15 @@ class Tony(Sprite): Sprite.update(self) # Blend the effect frame with the sprite frame - if self.get_configuration("display", "alpha-effect-title"): - self.display_surface = save - self.location = location_save - self.effect.display_surface = intermediate_surface - self.effect.update(flags=BLEND_RGBA_SUB) - self.get_display_surface().blit(intermediate_surface, self.location.topleft) - else: - self.effect.update(flags=BLEND_RGBA_SUB) + if not self.get_configuration("system", "minimize-load-time"): + if self.get_configuration("display", "alpha-effect-title"): + self.display_surface = save + self.location = location_save + self.effect.display_surface = intermediate_surface + self.effect.update(flags=BLEND_RGBA_SUB) + self.get_display_surface().blit(intermediate_surface, self.location.topleft) + else: + self.effect.update(flags=BLEND_RGBA_SUB) # Update title screen objects that are drawn over this sprite if self.get_game().title.active: @@ -1165,9 +1166,9 @@ class Title(Animation): arrow.set_colorkey((255, 0, 255)) arrow.fill((255, 0, 255)) if screen_pos[0] == 0: - points = 0, arrow.get_height() // 2, arrow.get_width(), 0, arrow.get_width(), arrow.get_height() + points = 0, arrow.get_height() // 2, arrow.get_width() - 1, 0, arrow.get_width() - 1, arrow.get_height() - 1 else: - points = 0, 0, 0, arrow.get_height(), arrow.get_width(), arrow.get_height() // 2 + points = 0, 0, 0, arrow.get_height() - 1, arrow.get_width() - 1, arrow.get_height() // 2 pygame.gfxdraw.filled_trigon(arrow, points[0], points[1], points[2], points[3], points[4], points[5], bg) pygame.gfxdraw.trigon(arrow, points[0], points[1], points[2], points[3], points[4], points[5], (0, 0, 0)) self.score_indicator.add_frame(arrow) @@ -1352,6 +1353,8 @@ class Dialogue(Animation): self.name_box.add_frame(frame) self.name_box.location.bottomleft = self.avatar_box.location.bottomright self.speech_channel = None + self.base_message_frame = Surface((self.text_box.location.w - 10, 30 * 2)) + self.base_message_frame.fill(self.BACKGROUND) def reset(self): self.stop_speech() @@ -1410,13 +1413,13 @@ class Dialogue(Animation): font = pygame.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) + frame = self.base_message_frame.copy() for ii, line in enumerate(lines): - surface = font.render(line, True, self.TEXT_COLOR).convert_alpha() + surface = font.render(line, True, self.TEXT_COLOR, self.BACKGROUND).convert() 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() + message.add_frame(frame) + message.location.topleft = self.text_box.location.left + 9, self.text_box.location.top + 8 + message.update() class SkipPrompt(GameChild): @@ -1647,44 +1650,49 @@ class Platform(GameChild): def __init__(self, parent, center): """ Initialize four lights, one for each pad on the platform. Initialize a Sprite for the pad graphics with one - frameset per six possible combinations of lights. Initialize masks for creating a glow effect on the pads. + frameset per six possible combinations of lights. @param parent PGFW game object that initialized this object @param center tuple that gives the (x, y) screen coordinates of this platform """ GameChild.__init__(self, parent) + + # Create objects for tracking the individual pad lights self.lights = [ Light(self, self.get_configuration("pads", "nw_color"), NS.LNW), Light(self, self.get_configuration("pads", "ne_color"), NS.LNE), Light(self, self.get_configuration("pads", "se_color"), NS.LSE), Light(self, self.get_configuration("pads", "sw_color"), NS.LSW) ] + + # Create a sprite which will display the pad self.view = Sprite(self) - self.view.load_from_path("pad", True) + self.view.load_from_path(os.path.join(self.get_resource("pad"), "pad_0.png"), True) self.view.add_frameset([0], name="neutral") - self.view.add_frameset([1], name=str(NS.N)) - self.view.add_frameset([2], name=str(NS.E)) - self.view.add_frameset([3], name=str(NS.NW)) - self.view.add_frameset([4], name=str(NS.NE)) - self.view.add_frameset([5], name=str(NS.W)) - self.view.add_frameset([6], name=str(NS.S)) - self.view.location.center = center - self.glow_masks = [] - base_images = load_frames(self.get_resource("pad_mask"), True) - for image in base_images: - self.glow_masks.append([image]) - for mask in self.glow_masks: + + # For each of the six combinations of lights, create a glowing frameset + light_masks = load_frames(self.get_resource("pad_mask"), True) + for orientation_index, orientation in enumerate((NS.N, NS.E, NS.NW, NS.NE, NS.W, NS.S)): + pad_base_frame = load_frames(os.path.join(self.get_resource("pad"), f"pad_{orientation_index + 1}.png"), True)[0] + self.view.add_frame(pad_base_frame) + frameset = [len(self.view.frames) - 1] intensity_resolution = 12 for intensity in range(1, intensity_resolution): - copy = mask[0].copy() - pixels = pygame.PixelArray(copy) - color = pygame.Color(0, 0, 0) - h, s, l, a = color.hsla - l = int(intensity / intensity_resolution * 100) - color.hsla = h, s, l, a - pixels.replace(pygame.Color(0, 0, 0), color) - del pixels - mask.append(copy) + next_pad_frame = pad_base_frame.copy() + for light_orientation in self.get_buttons_from_edges([orientation]): + copy = light_masks[light_orientation].copy() + pixels = pygame.PixelArray(copy) + color = pygame.Color(0, 0, 0) + h, s, l, a = color.hsla + l = int(intensity / intensity_resolution * 100) + color.hsla = h, s, l, a + pixels.replace(pygame.Color(0, 0, 0), color) + del pixels + next_pad_frame.blit(copy, (0, 0), None, BLEND_RGBA_ADD) + self.view.add_frame(next_pad_frame) + frameset.append(len(self.view.frames) - 1) + self.view.add_frameset(frameset, name=str(orientation)) + self.view.location.center = center def reset(self): """ @@ -1878,9 +1886,9 @@ class Platform(GameChild): """ for ii, light in enumerate(self.lights): light.glow_index = 0 - light.halt(light.glow) + light.unglow() if ii in selected: - light.play(light.glow) + light.glow() def update(self): """ @@ -1897,11 +1905,6 @@ class Platform(GameChild): else: self.view.set_frameset(str(glowing)) self.view.update() - if not self.view.is_hidden() and not self.view.is_playing(self.view.wipe_out): - for light in self.lights: - if light.glowing(): - self.get_display_surface().blit( - self.glow_masks[light.position][light.glow_index], self.view.location, None, BLEND_RGBA_ADD) # track how long an edge has been pressed if self.get_edge_pressed() is not None: if self.get_edge_pressed() != self.previously_pressed_edge: @@ -1914,11 +1917,10 @@ class Platform(GameChild): self.press_elapsed = 0 -class Light(Animation): +class Light(GameChild): """ This class represents a pad on the platform. Typically there are four instances for a platform, one for each corner of the - platform. Each light stores its color and position on the platform. This class contains methods for glowing the light and - getting its properties. + platform. Each light stores its color, position on the platform, and state of glowing. """ TITLE_OFFSET = 0 @@ -1931,7 +1933,7 @@ class Light(Animation): @param color pygame color object @param position the light's position on the platform, one of NS.LNW, NS.LNE, NS.LSE, NS.LSW """ - Animation.__init__(self, parent) + GameChild.__init__(self, parent) self.color = Color(color) self.color.a = 225 self.position = position @@ -1956,39 +1958,46 @@ class Light(Animation): self.points = mid, midright, backright, backmid elif self.position == NS.LSW: self.points = midleft, mid, backmid, backleft - self.register(self.glow) def reset(self): """ Unhide, halt glow animation """ - self.hidden = False - self.halt(self.glow) - self.reset_timer() - self.glow_index = 0 + self.unglow() def glow(self): """ - Moves the glow animation forward a frame by incrementing an index + Set the glow state to True """ - self.glow_index += 1 - if self.glow_index >= len(self.parent.glow_masks[0]): - self.glow_index = 0 + self.is_glowing = True + + def unglow(self): + """ + Set the glow state to False + """ + self.is_glowing = False + + def glowing(self): + """ + Returns True if this light is glowing, False otherwise + + @return True | False + """ + return self.is_glowing def update(self): """ Checks the attack state to determine whether to start or stop glowing """ - Animation.update(self) if not self.get_game().title.active and not self.get_game().level_select.active: boss = self.get_game().boss chemtrails = self.get_game().chemtrails # checks the boss attack queue and chameleon queue index to see if the glow should be started now - if boss.queue and not self.is_playing(self.glow) and self.in_orientation(boss.queue[chemtrails.queue_index]): - self.play(self.glow) + if boss.queue and self.in_orientation(boss.queue[chemtrails.queue_index]): + self.glow() # turns off the glow - elif self.is_playing(self.glow) and (not boss.queue or not self.in_orientation(boss.queue[chemtrails.queue_index])): - self.reset() + elif not boss.queue or not self.in_orientation(boss.queue[chemtrails.queue_index]): + self.unglow() def get_points(self): if self.get_game().title.active: @@ -1999,21 +2008,6 @@ class Light(Animation): else: return self.points - def draw_glow(self): - for ii, y in enumerate(range(0, self.glow_index, 3)): - shifted = [] - for point in self.get_points(): - shifted.append((point[0], point[1] - y)) - if self.position == NS.LSW: - saturation = 0 - else: - saturation = int((self.color.hsla[1] + 80) % 100) - if not ii % 2: - lightness = 0 - else: - lightness = 40 - lines(self.get_display_surface(), get_hsla_color(int(self.color.hsla[0]), saturation, lightness), True, shifted, 3) - def in_orientation(self, orientation): """ Returns True if this light is contained in the given edge @@ -2030,14 +2024,6 @@ class Light(Animation): elif self.position == NS.LSW: return orientation in (NS.S, NS.NE, NS.W) - def glowing(self): - """ - Returns True if this light is glowing, False otherwise - - @return True | False - """ - return self.is_playing(self.glow) - class Chemtrails(Sprite): """ diff --git a/resource/scores b/resource/scores index 77d0dbb..409a734 100644 --- a/resource/scores +++ b/resource/scores @@ -1,6 +1,7 @@ 41802 0 41903 0 42153 0 +47259 0 48935 0 50940 0 51245 0