def get_sprite(frame):
def load_image(name):
def load_sound(name):
def load_text(name, lang):
def loop_sound(sound):
def on_off(condition):
def percent_str(var):
def play_music(name):
def set_volume():
def init_music_volume():
def show_fps():
def take_screenshot():
def toggle_frame_limit():
def toggle_fullscreen():
def toggle_pause():
    def __init__(self, *keys):
APP_DATA_WIN = 'APPDATA'
APP_DATA_LIN = 'HOME'
BLIT_FLAGS    = HWSURFACE | HWACCEL | ASYNCBLIT | RLEACCEL
CURSOR_BEEP   = load_sound('cursor.wav')
CURSOR_SELECT = load_sound('select.wav')
DATA_STORE    = join(environ[APP_DATA_WIN if 'win' in sys.platform else APP_DATA_LIN], 'Invasodado')
DEBUG         =  __debug__ and not hasattr(sys, 'frozen') #cx_freeze adds 'frozen' to the sys module
DEPTH         = 8
EARTH         = load_image('earth.png')
ENCODING      = 'utf-8'
EVENTS_OK     = (KEYDOWN, MOUSEBUTTONDOWN, QUIT)
FONT          = pygame.font.Font(join('gfx', 'font.ttf'), 18)
FULL_FLAGS    = FULLSCREEN | HWSURFACE | DOUBLEBUF
GRID_BG       = load_image('bg.png')
ON_OFF        = {
                 'en' : ("Off", "On"),
                 'es' : ("No" , "Sí"),
                }
PAUSE         = load_sound('pause.wav')
SCREEN_DIMS   = tuple(pygame.display.list_modes())
SCREEN_HEIGHT = screen.get_height()
SCREEN_RECT   = Rect((0, 0), screen.get_size())
SCREEN_WIDTH  = screen.get_width()
SPRITES       = load_image('sprites.png')
EARTH = EARTH.subsurface(Rect(0, 0, EARTH.get_width(), EARTH.get_height() / 2))
class Enum: LANGUAGES          = (     'en',      'es')
LANGUAGE_NAMES     = ("English", "Español")
LANGUAGE_DICT      = dict(zip(LANGUAGES, LANGUAGE_NAMES))
SETTINGS_KEYS      = (
    'resolution'  ,
    'fullscreen'  ,
    'color_blind' ,
    'language_id'    ,
    'sound_volume',
    'music_volume',
)
SETTINGS_FILE_NAME = 'settings.wtf'
SETTINGS = {
            'color_blind'  : False     ,
            'fullscreen'   : False     ,
            'language_id'  : 0         ,
            'music_volume' : 1.0       ,
            'resolution'   : (640, 480),
            'sound_volume' : 1.0       ,
            }
def toggle_color_blind_mode():
def save_settings(path):
def load_settings(path):
def set_language(lang):
def get_language_code():
def get_language_name(): RED    = Color('#FF3333')
GREEN  = Color('#4FFF55')
BLUE   = Color('#585EFF')
YELLOW = Color('#EBFF55')
PURPLE = Color('#FF55D5')
WHITE  = Color('#FFFFFF')
BLACK  = Color('#000000')
COLOR_BLIND_FRAMES  = tuple(Rect(32 * i, 32, 32, 32) for i in range(4, 10))
COLOR_BLIND_SYMBOLS = {
                        id(RED)    : config.get_sprite(COLOR_BLIND_FRAMES[0]),
                        id(BLUE)   : config.get_sprite(COLOR_BLIND_FRAMES[1]),
                        id(GREEN)  : config.get_sprite(COLOR_BLIND_FRAMES[2]),
                        id(YELLOW) : config.get_sprite(COLOR_BLIND_FRAMES[3]),
                        id(PURPLE) : config.get_sprite(COLOR_BLIND_FRAMES[4]),
                        id(WHITE)  : None                                    ,
                       }
COLOR_KEY           = config.SPRITES.get_at((0, config.SPRITES.get_height() - 1))
LIST                = (RED, BLUE, GREEN, YELLOW, PURPLE)
def blend_color(surface, color):
def get_colored_objects(frames, has_alpha=True, color_blind=False, pause_frame=True):
def _rand_color_appear(self): def _star_appear(self):
def _star_move(self):
STARS_GROUP = pygame.sprite.RenderUpdates()
_STAR_IMAGE = config.get_sprite(Rect(4, 170, 2, 2))
EARTH = HudObject(config.EARTH  , (0, 0))
GRID  = HudObject(config.GRID_BG, (0, 0))
STARS = ParticleEmitter(
                        ParticlePool(_STAR_IMAGE, _star_move, _star_appear),
                        Rect(0, 0, 0, config.SCREEN_HEIGHT),
                        8,
                        STARS_GROUP
                        ) class MenuState(GameState):
    def __init__(self, *args, **kwargs):
        super().__init__()
        ### Local Variables ####################################################
        cursor_up   = partial(self._move_cursor, -1)
        cursor_down = partial(self._move_cursor,  1)
        ########################################################################
        
        ### Object Attributes ##################################################
        self.cursor_index = 0
        self.hud_cursor   = make_text("\u2192", (0, 0))
        self.menu_actions = ()
        self.key_actions  = {
                             K_RETURN : self._enter_selection ,
                             K_SPACE  : self._enter_selection ,
                             K_UP     : cursor_up             ,
                             K_w      : cursor_up             ,
                             K_DOWN   : cursor_down           ,
                             K_s      : cursor_down           ,
                             K_ESCAPE : sys.exit              ,
                             K_PRINT  : config.take_screenshot,
                             K_F12    : config.take_screenshot,
                             K_SYSREQ : config.take_screenshot,
                            }
        ########################################################################
        
    def render(self):
        super().render()
        pygame.display.flip()
        
    def _move_cursor(self, index):
        '''
        Move the cursor.
        
        @param index: How many menu positions the cursor should be moved by.
        '''
        #TODO: Throw in some animation
        self.cursor_index += index
        self.cursor_index %= len(self.menu_actions)
        config.CURSOR_BEEP.play()
        
    def _enter_selection(self, toggle=None):
        '''
        I can't just put "self.menu_actions[self.cursor_index]" in
        self.key_actions because it'll store self.menu_actions[0], and then only
        one menu item will actually be executed.
        '''
        config.CURSOR_SELECT.play()
        if toggle is None:
            self.menu_actions[self.cursor_index]()
        else:
            self.menu_actions[self.cursor_index](toggle) @lru_cache(maxsize=64)
def make_text(text, pos=(0, 0), col=color.WHITE, font=HudObject.fonts[0], vspace=8, surfaces=False):
        '''
        @param text: The text we want visible to the user. If a list, one element per line
        @param pos: The topleft corner of the position rect
        @param col: The color of the text
        @param font: The font used; it defaults to the first font entry
        @param vspace: Space between lines in pixels. Ignored if only one line.
        @param surfaces: True if we want Surfaces instead of HudObjects (pos is then ignored)

        @return: list(pygame.Surface) if surfaces else list(HudObject)
        '''

        if isinstance(text, str):
        #If we were given a single string...
            hud = font.render(text, False, col).convert(config.DEPTH, config.BLIT_FLAGS)
            hud.set_colorkey(color.BLACK)
            return hud if surfaces else HudObject(hud, pos)
        else:
            def d(t):
                hud = font.render(text[t], False, col).convert(config.DEPTH, config.BLIT_FLAGS)
                hud.set_colorkey(color.BLACK)
                return hud if surfaces else HudObject(hud, (pos[0], pos[1] + vspace * t))

            return [d(i) for i in range(len(text))] class HudObject(GameObject):
    '''
    HudObject is meant for displays like lives, score, etc.

    It is its own type so it can be in collisions._do_not_check, because we
    don't intend for these to collide with anything.
    '''
    STATES = config.Enum('IDLE')
    fonts  = (config.FONT,)
    
    def __init__(self, image, pos):
        super().__init__()
        self.image = image
        self.rect  = pygame.Rect(pos, image.get_size())
        del self.velocity, self.acceleration, self.position, self.next_state
        
    def center(self):
        self.rect.centerx = config.SCREEN_RECT.centerx
        return self

    def update(self):
        '''
        Since HudObjects have no functionality, let's make update() do nothing!
        '''
        pass ENEMY_STATES    = ('IDLE', 'APPEARING', 'LOWERING', 'ACTIVE', 'DYING', 'CHEERING')
FRAMES          = tuple(Rect(32 * i, 32, 32, 32) for i in range(4))
LOWER_INCREMENT = 16
START_POS       = (32.0, 32.0)
ENEMY_FRAMES             = color.get_colored_objects(FRAMES, True, False, True)
ENEMY_FRAMES_COLOR_BLIND = color.get_colored_objects(FRAMES, True, True , True)
    STATES       = config.Enum(*ENEMY_STATES)
    GROUP        = None
class Enemy(GameObject):
    def __init__(self, form_position):
    def appear(self):
    def move(self):
    def die(self):
    def lower(self):
    def cheer(self):
    def __animate(self): def _burst_appear(self):
def _radius_appear(self):
def _radius_move(self):
    def __init__(self):
    def animate(self):
    def __init__(self):
    def __init__(self):
    def on_fire_bullet(self):
    def respawn(self):
    def move(self):
    def die(self):
    def instadie(self, other):
    def wait_to_respawn(self):
PART_IMAGE  = Rect(4, 170, 4, 4)
APPEAR      = config.load_sound('appear.wav')
APPEAR_POOL = ParticlePool(config.get_sprite(PART_IMAGE), _radius_move, _radius_appear)
DEATH       = config.load_sound('death.wav')
DEATH_POOL  = ParticlePool(config.get_sprite(PART_IMAGE), appear_func=_burst_appear)
FRAMES      = tuple(config.get_sprite(Rect(32 * i, 128, 32, 32)) for i in range(5))
GRAVITY     = 0.5
SHIP_STATES = ('IDLE', 'SPAWNING', 'ACTIVE', 'DYING', 'DEAD', 'RESPAWN')
SPEED       = 4
START_POS   = Rect(config.SCREEN_WIDTH / 2, config.SCREEN_HEIGHT * .8, 32, 32)
    FRAMES = tuple(config.get_sprite(Rect(32*i, 0, 32, 32)) for i in range(6))
    GROUP  = None
    SIZE = Rect(0, 0, 32, config.SCREEN_HEIGHT - 32 * 3)
    STATES = config.Enum(*SHIP_STATES)
    GROUP  = None
class FlameTrail(GameObject):
class LightColumn(GameObject):
class Ship(GameObject): AVG_WAIT   = 9000 #Expected time in frames between UFO appearance
DEATH      = config.load_sound('ufo_explosion.wav')
FRAMES     = tuple(
              Rect(64 * (i % 4), 192 + 32 * (i // 4), 64, 32)
              for i in range(10, -1, -1)
             )
INVADE     = config.load_sound('ufo.wav')
START_POS  = (640, 16)
UFO_FRAMES = color.get_colored_objects(FRAMES)
UFO_STATES = ('IDLE', 'APPEARING', 'ACTIVE', 'DYING', 'LEAVING', 'LOWERING', 'GAMEOVER')
    STATES      = config.Enum(*UFO_STATES)
    GROUP       = None
    BLOCK_GROUP = None
class UFO(GameObject):
    def __init__(self):
    def appear(self):
    def move(self):
    def die(self):
    def leave(self):
    def wait(self): BLOCK_STATES = ('IDLE', 'APPEARING', 'ACTIVE', 'START_FALLING', 'FALLING', 'IMPACT', 'DYING')
FRAMES       = tuple(pygame.Rect(32 * i, 160, 32, 32) for i in range(8))
GRAVITY      =  0.5
MAX_SPEED    = 12.0
UFO_BLOCK    = config.load_sound('ufo_block.wav')
    STATES         = config.Enum(*BLOCK_STATES)
    GROUP          = None
def clean_up():
def get_block(position, newcolor=choice(color.LIST), special=False):
    def __init__(self, position, newcolor=choice(color.LIST), special=False):
    def __str__(self):
    def __repr__(self):
    def appear(self):
    def start_falling(self):
    def fall(self):
    def wait(self):
    def stop(self):
    def vanish(self):
    def __replace(self):
    def __animate(self):
    def __get_snap(self):
class Block(GameObject):
from functools import partial
from random import choice
from pygame.constants import *
from pygame.sprite    import Group, OrderedUpdates
from core           import config
from core           import settings
from core           import color
from game           import bg
from game.menustate import MenuState
from game.hudobject import make_text, HudObject
from game           import enemy
from game import player
from game import ufo
from game import block
import pygame.display



### Groups #####################################################################
GRID_BG = OrderedUpdates()
TEXT    = Group()
SPRITES = Group()
################################################################################

### Constants ##################################################################
'''
@var DIST_APART: Vertical distance between text lines in pixels
@var TOP_LEFT: Coordinates of the top-left of the text, in pixels
'''
ALIEN_DIST = 12 + enemy.ENEMY_FRAMES[id(color.RED)][0].get_width()
ALIEN_Y    = 24
BLOCK_Y    = 72
DIST_APART = 24
TOP_LEFT   = (16, 32)
################################################################################

### Sprite Positions ###########################################################
'''
Due to the differences in language, different translations of this help screen
will have text of varying verbosity.
'''
ALIEN_BLOCK_POS = {
    'en' : lambda i: 176 + ALIEN_DIST * i,
    'es' : lambda i: 182 + ALIEN_DIST * i,
}

SHIP_POS = {
    'en' : (176, 120),
    'es' : (200, 116),
}

UFO_POS = {
    'en' : (400, 384),
    'es' : (512, 384),
}
################################################################################

class HelpScreen(MenuState):
    def __init__(self, *args, **kwargs):
        ### Local Variables ####################################################
        ALIEN_FRAMES = enemy.ENEMY_FRAMES_COLOR_BLIND if settings.SETTINGS['color_blind'] else enemy.ENEMY_FRAMES
        BLOCK_FRAMES = block._block_frames_color_blind if settings.SETTINGS['color_blind'] else block._block_frames
        go_back      = partial(self.change_state, kwargs['next'])
        langcode     = settings.get_language_code()
        AB           = ALIEN_BLOCK_POS[langcode]
        ########################################################################
        
        ### Object Attributes ##################################################
        self.group_list = (bg.STARS_GROUP, GRID_BG, TEXT, SPRITES)
        self.key_actions = {
                            K_ESCAPE : go_back,
                            K_SPACE  : go_back,
                            K_RETURN : go_back,
                           }
        

        self.aliens = (HudObject(ALIEN_FRAMES[id(color.LIST[i])][ 0], (AB(i), ALIEN_Y)) for i in range(len(color.LIST)))