From 9838cdaac02529f1c223d2a1578ada4cd9297a19 Mon Sep 17 00:00:00 2001 From: frank <420@shampoo.ooo> Date: Sat, 12 Jun 2021 01:12:25 -0400 Subject: [PATCH] add is_suppressed to Input, fill borders based on which borders are being drawn --- pgfw/Animation.py | 3 +-- pgfw/Audio.py | 31 ++++++++++++++++++++----------- pgfw/Configuration.py | 19 +++++++++++++------ pgfw/GameChild.py | 3 +-- pgfw/Input.py | 18 +++++++++++++++--- pgfw/Profile.py | 1 + pgfw/Sprite.py | 4 ++++ pgfw/extension.py | 22 +++++++++++++++++++--- 8 files changed, 74 insertions(+), 27 deletions(-) diff --git a/pgfw/Animation.py b/pgfw/Animation.py index 3e26ec5..7808842 100644 --- a/pgfw/Animation.py +++ b/pgfw/Animation.py @@ -25,8 +25,7 @@ class Animation(GameChild): else: self.accounts[method].set_interval(interval) - def play(self, method=None, interval=None, delay=0, play_once=False, - **kwargs): + def play(self, method=None, interval=None, delay=0, play_once=False, **kwargs): account = self.accounts[self.get_default(method)] account.set_delay(delay) account.set_args(kwargs) diff --git a/pgfw/Audio.py b/pgfw/Audio.py index 1ddedc5..a09c70a 100644 --- a/pgfw/Audio.py +++ b/pgfw/Audio.py @@ -76,19 +76,24 @@ class Audio(Animation): elif compare(event, "volume-down"): self.set_volume(increment=self.DOWN) - # - # Loading SFX procedure - # - # - load config file name/path definitions at init - # - check project specific sfx paths at init, load any that don't conflict - # - check default sfx paths at init, load any that don't conflict - # - repository paths are not loaded at init but can replace loaded paths - # and get written to config file - # def load_sfx(self, sfx_location=None): + """ + Load SFX from paths defined in config. This can be run without arguments, and it will attempt to auto find + SFX following the below procedure. If sfx_location is set, paths for SFX files in the config are overridden. + + Auto-loading SFX procedure: + + * load config file name/path definitions at init + * check project specific sfx paths at init, load any that don't conflict + * check default sfx paths at init, load any that don't conflict + * repository paths are not loaded at init but can replace loaded paths + and get written to config file + """ for name, sfx_definition in self.get_configuration("sfx").items(): sfx_definition_members = sfx_definition.split(self.CONFIG_SEPARATOR) + # default values for everything besides path in case those aren't included in the config definition path, volume, fade_out, loops, maxtime = sfx_definition_members[0], 1.0, 0, 0, 0 + # format for an SFX defintion in config is: "name = path[, volume][, fade out][, loops][, maxtime]" for ii, member in enumerate(sfx_definition_members[1:]): if ii == 0: volume = float(member) @@ -99,8 +104,8 @@ class Audio(Animation): elif ii == 3: maxtime = float(member) self.load_sfx_file( - path, name, True, volume=volume, fade_out=fade_out, loops=loops, - maxtime=maxtime) + path, name, True, volume=volume, fade_out=fade_out, loops=loops, maxtime=maxtime) + # override config definitions of SFX paths if sfx_location is None: sfx_location = self.get_configuration("audio", "sfx-project-path") + \ self.get_configuration("audio", "sfx-default-path") @@ -116,6 +121,7 @@ class Audio(Animation): else: for node, branches, leaves in os.walk(root, followlinks=True): for leaf in leaves: + # use path elements to prepend subdirectories to the SFX name prefix = re.sub(r"{}".format(root), r"", r"{}".format(node)) prefix = re.sub(r"^{}".format(os.path.sep), r"", prefix) if prefix: @@ -133,6 +139,8 @@ class Audio(Animation): print("loading sound effect {} into {}".format(path, name)) self.sfx[name] = SoundEffect(self, path, volume, loops, fade_out, maxtime=maxtime) return True + else: + print("couldn't load sound effect, path is not loadable {}".format(path)) return False def get_sfx(self, name): @@ -175,6 +183,7 @@ class Audio(Animation): self.set_bgm(os.path.join(node, leaf), prefix=prefix) def set_bgm(self, path, name=None, prefix="", volume=1.0): + path = self.get_resource(path) print("setting {} music to {}".format(name, path)) try: pygame.mixer.music.load(path) diff --git a/pgfw/Configuration.py b/pgfw/Configuration.py index 10cf2cb..383152a 100644 --- a/pgfw/Configuration.py +++ b/pgfw/Configuration.py @@ -364,19 +364,26 @@ class Configuration(RawConfigParser): if use_main: path = self.locate_project_config_file() if not path: - path = join(self.resource_path or "", - self.default_project_file_rel_path) + path = join(self.resource_path or "", self.default_project_file_rel_path) fp = open(path, "w") break_line = False for section in self.order: if section in modifiable: - break_line and fp.write("\n") + if break_line: + fp.write("\n") fp.write("[%s]\n" % section) for option in modifiable[section]: if self.has_option(section, option): - value = self.get(section, option) - fp.write("%s = %s\n" % (option, - self.get_raw_value(value))) + raw_value = self.get_raw_value(self.get(section, option)) + # handle multiline entries + if "\n" in raw_value: + lines = raw_value.split("\n") + fp.write("{} = {}\n".format(option, lines[0])) + for line in lines[1:]: + # have to indent lines after the first to be compatible with configparser + fp.write(" {}\n".format(line)) + else: + fp.write("{} = {}\n".format(option, raw_value)) break_line = True if use_main: fp.close() diff --git a/pgfw/GameChild.py b/pgfw/GameChild.py index 8043919..3f8386e 100644 --- a/pgfw/GameChild.py +++ b/pgfw/GameChild.py @@ -70,8 +70,7 @@ class GameChild: path = join(root, rel_path) if exists(path): return normpath(path) - self.print_debug("Couldn't find resource: {0} {1}".format( - path_or_section, option)) + print("warning: couldn't find resource: {0} {1}".format(path_or_section, option)) def is_shared_mode(self): return self.check_command_line("s") diff --git a/pgfw/Input.py b/pgfw/Input.py index 48e4d09..7a446dc 100644 --- a/pgfw/Input.py +++ b/pgfw/Input.py @@ -36,13 +36,28 @@ class Input(GameChild): "volume-down", "volume-up", "volume-mute"]) self.any_press_ignored_keys = set() + def suppress(self): + self.suppressed = True + def unsuppress(self): self.suppressed = False + def is_suppressed(self): + """ + Return True if input is suppressed + """ + return self.suppressed + def unsuppress_any_on_mods(self): + """ + Prevent modifier keys from triggering an any key event + """ self.suppressed_any_key_on_mods = False def suppress_any_key_on_mods(self): + """ + Allow modifier keys to trigger an any key event + """ self.suppressed_any_key_on_mods = True def subscribe_to_events(self): @@ -67,9 +82,6 @@ class Input(GameChild): def build_joy_button_map(self): self.joy_button_map = self.get_configuration("joy") - def suppress(self): - self.suppressed = True - def translate_key(self, event): if not self.suppressed: cancel = event.type == KEYUP diff --git a/pgfw/Profile.py b/pgfw/Profile.py index b22a983..8b3b7c0 100644 --- a/pgfw/Profile.py +++ b/pgfw/Profile.py @@ -23,4 +23,5 @@ class Profile(cProfile.Profile, GameChild): mkdir(root) self.disable() self.create_stats() + self.print_stats(sort="cumtime") self.dump_stats(join(root, strftime("%Y%m%d-%H%M_%S.stat"))) diff --git a/pgfw/Sprite.py b/pgfw/Sprite.py index 07babd9..b9874e9 100644 --- a/pgfw/Sprite.py +++ b/pgfw/Sprite.py @@ -253,6 +253,10 @@ class Sprite(Animation): self.children.pop(name) def wipe_out(self): + """ + Increase index of wipe animation, causing blinds frames to grow. To launch the animation use + sprite.play(sprite.wipe_out) + """ for child in self.children.values(): if not child.is_playing(child.wipe_out): child.play(child.wipe_out) diff --git a/pgfw/extension.py b/pgfw/extension.py index 95d03af..6d5a7c9 100644 --- a/pgfw/extension.py +++ b/pgfw/extension.py @@ -192,16 +192,28 @@ def get_value_in_range(start, end, position, reverse=False): return (end - start) * position + start def fill_borders(surface, color=Color(0, 0, 0), thickness=1, rect=None, flags=0, include=(True, True, True, True)): + ''' + Draw borders on a surface at rect position. A subset of the four borders can be drawn by passing the include + iterable with bools for each position (top, right, bottom, left) + ''' if rect is None: rect = surface.get_rect() + # handle horizontal sides differently based on whether top and bottom are being drawn + horizontal_h = rect.h - thickness * 2 + horizontal_y = rect.top + thickness + if not include[0]: + horizontal_y = rect.top + horizontal_h += thickness + if not include[2]: + horizontal_h += thickness if include[0]: surface.fill(color, (rect.left, rect.top, rect.w, thickness), flags) if include[1]: - surface.fill(color, (rect.right - thickness, rect.top + thickness, thickness, rect.h - thickness * 2), flags) + surface.fill(color, (rect.right - thickness, horizontal_y, thickness, horizontal_h), flags) if include[2]: surface.fill(color, (rect.left, rect.bottom - thickness, rect.w, thickness), flags) if include[3]: - surface.fill(color, (rect.left, rect.top + thickness, thickness, rect.h - thickness * 2), flags) + surface.fill(color, (rect.left, horizontal_y, thickness, horizontal_h), flags) def get_boxed_surface(surface, background=None, border=None, border_width=1, padding=0): if padding: @@ -351,6 +363,10 @@ def get_inverted_surface(base): return surface def fill_tile(surface, tile, rect=None, flags=0, offset=Vector(0, 0)): + ''' + Fill surface with tile surface. If rect is set, only fill in that section. If offset is set, start filling + with tile shifted by offset (-x, -y) + ''' w, h = tile.get_size() surface.set_clip(rect) for x in range(-offset.x, surface.get_width(), w): @@ -535,7 +551,7 @@ def compute_bezier_points(vertices, numPoints=60): return points def get_marching_ants_color(position, time=0, colors=((0, 0, 0), (255, 255, 255))): - return Color(*(colors[0], colors[1])[((position / 2) % 2 + (time % 2)) % 2]) + return Color(*(colors[0], colors[1])[((position // 2) % 2 + (time % 2)) % 2]) def diagonal_to_rect(start, end): sx, sy = start