Some more boilerplate.
authorJeremy Thurgood <firxen@gmail.com>
Sun, 11 May 2014 09:00:58 +0000 (11:00 +0200)
committerJeremy Thurgood <firxen@gmail.com>
Sun, 11 May 2014 09:00:58 +0000 (11:00 +0200)
naja/resources.py [new file with mode: 0644]
naja/sound.py [new file with mode: 0644]

diff --git a/naja/resources.py b/naja/resources.py
new file mode 100644 (file)
index 0000000..00ebe1c
--- /dev/null
@@ -0,0 +1,103 @@
+import os
+import sys
+
+try:
+    from pkg_resources import resource_filename
+except ImportError:
+    # OK, we're most likely running under py2exe, so this is safe
+    # (for values of safe that are unconcerned about py2exe being involved)
+    def resource_filename(mod, path):
+        # There are better ways of doing this, but I've spent too much
+        # time going down this rabbithole already
+        return os.path.join(os.path.dirname(__file__), '..', 'data', path)
+import pygame
+
+
+class ResourceNotFound(Exception):
+    pass
+
+
+class Resources(object):
+    CONVERT_ALPHA = True
+
+    def __init__(self, resource_module, language=None):
+        self.resource_module = resource_module
+        self.lang_dialect = language
+        self.language = language.split('_', 1)[0] if language else None
+        self._cache = {}
+
+    def create_resource_path(self, *path_fragments):
+        return resource_filename(self.resource_module,
+                                 os.path.join(*path_fragments))
+
+    def get_resource_path(self, *path_fragments):
+        for mod, full_path_fragments in self.lang_locations(path_fragments):
+            path = resource_filename(mod, os.path.join(*full_path_fragments))
+            if os.path.exists(path):
+                return path
+        raise ResourceNotFound(os.path.join(*path_fragments))
+
+    def lang_locations(self, path_fragments):
+        '''
+        For each resource module, yield:
+        * (<module>, (<lang>_<dialect>, <path>))
+        * (<module>, (<lang>, <path>))
+        * (<module>, (<path>, ))
+        '''
+        for module in (self.resource_module,):
+            if self.lang_dialect:
+                yield (module, (self.lang_dialect,) + path_fragments)
+            if self.language != self.lang_dialect:
+                yield (module, (self.language,) + path_fragments)
+            yield (module, path_fragments)
+
+    def get_file(self, *path_fragments, **kw):
+        mode = kw.get('mode', "rU")
+        try:
+            path = self.get_resource_path(*path_fragments)
+        except ResourceNotFound:
+            if 'w' in mode:
+                path = self.create_resource_path(*path_fragments)
+            else:
+                raise
+        return file(path, mode)
+
+    def get_image(self, *name_fragments, **kw):
+        transforms = kw.get('transforms', ())
+        basedir = kw.get('basedir', 'images')
+
+        path = (basedir,) + name_fragments
+
+        if path not in self._cache:
+            fn = self.get_resource_path(*path)
+            image = pygame.image.load(fn)
+            if self.CONVERT_ALPHA:
+                if not pygame.display.get_init():
+                    print >> sys.stderr, ("Display not initialized, "
+                                          "image '%s' not loaded."
+                                          % os.path.join(*path))
+                    return
+                image = image.convert_alpha(pygame.display.get_surface())
+            self._cache[path] = image
+
+        key = (path, transforms)
+        if key not in self._cache:
+            image = self._cache[path]
+            for mutator in transforms:
+                image = mutator(image)
+            self._cache[key] = image
+
+        return self._cache[key]
+
+    def get_font(self, file_name, font_size):
+        basedir = 'fonts'
+        key = (basedir, file_name, font_size)
+
+        if key not in self._cache:
+            fn = self.get_resource_path(basedir, file_name)
+            self._cache[key] = pygame.font.Font(fn, font_size)
+
+        return self._cache[key]
+
+
+resources = Resources('data')
diff --git a/naja/sound.py b/naja/sound.py
new file mode 100644 (file)
index 0000000..3115865
--- /dev/null
@@ -0,0 +1,93 @@
+"""Sound utilities."""
+
+from pygame import mixer
+
+from naja.options import options
+from naja.resources import resources
+from naja.constants import (
+    FREQ, BITSIZE, CHANNELS, BUFFER, DEFAULT_SOUND_VOLUME,
+    DEFAULT_MUSIC_VOLUME)
+
+
+class DummySound(object):
+    def init(self):
+        pass
+
+    def play_sound(self, name, volume=DEFAULT_SOUND_VOLUME):
+        pass
+
+    def play_music(self, name, volume=DEFAULT_MUSIC_VOLUME):
+        pass
+
+    def pause_music(self):
+        pass
+
+    def resume_music(self):
+        pass
+
+    def stop(self):
+        pass
+
+
+class PygameSound(object):
+    def __init__(self):
+        self._sounds = {}
+
+    def init(self):
+        mixer.init(FREQ, BITSIZE, CHANNELS, BUFFER)
+        silence = self.load_sound("silence.ogg")
+        if silence.get_length() < 1:
+            raise RuntimeError("Sound load error - silence.ogg too short")
+        self.play_sound("silence.ogg")
+
+    def load_sound(self, name):
+        track_name = resources.get_resource_path("sounds", name)
+        sound = self._sounds.get(track_name)
+        if sound is None:
+            sound = self._sounds[track_name] = mixer.Sound(track_name)
+        return sound
+
+    def play_sound(self, name, volume=DEFAULT_SOUND_VOLUME):
+        sound = self.load_sound(name)
+        if sound is not None:
+            sound.set_volume(volume)
+            sound.play()
+
+    def play_music(self, name, volume=DEFAULT_MUSIC_VOLUME):
+        if not options.music:
+            return
+        track_name = resources.get_resource_path("music", name)
+        mixer.music.load(track_name)
+        mixer.music.set_volume(volume)
+        mixer.music.play(-1)  # loop sound
+
+    def pause_music(self):
+        mixer.music.pause()
+
+    def unpause_music(self):
+        mixer.music.unpause()
+
+    def stop(self):
+        mixer.fadeout(1000)
+        mixer.music.stop()
+
+
+class SoundProxy(object):
+    def __init__(self):
+        self._sound = DummySound()
+
+    def init(self):
+        """Attempt to initialize the sound system."""
+        if options.sound:
+            try:
+                pyg_sound = PygameSound()
+                pyg_sound.init()
+                self._sound = pyg_sound
+            except Exception, err:
+                print "Failed to enable sound: %r" % (err,)
+
+    def __getattr__(self, name):
+        return getattr(self._sound, name)
+
+
+sound = SoundProxy()