Пример #1
0
 def __init__(self, director, background_name=False, page_number=False):
     self.director = director
     self.is_failed = False
     self.page = False
     self.is_move = False
     if not page_number and background_name:
         self.background = resize(load_image(config.backgrounds+background_name+SMALL+PNG_EXT), (800, 600))
     else:
         directorie = config.definition_pages+page_number+PNG_EXT
         print "Directorie: "+directorie
         self.background = load_image(directorie)
     
     self.failed_rect = rect.Rect((0, 0), (0, 0))                    
     self.failed_img = load_image(config.titles+'failed'+PNG_EXT, True)
     self.failed_rect.topleft = (0, 0)
     self.failed_rect.size = self.failed_img.get_rect().size        
     
     self.common_buttoms = {
                            EXIT: Buttom(config.exit_btn_pos, config.exit_btn_size, 'exit_pressed'+PNG_EXT, 'exit_release'+PNG_EXT),
                            MAIN_MENU_SCENE: Buttom(config.main_menu_btn_pos, config.main_menu_btn_size, 'main_menu_pressed'+PNG_EXT, 'main_menu_release'+PNG_EXT)
                             }     
     
     self.pages = False
     self.go_scene = False
     self.exit = False
     self.is_complete = False
Пример #2
0
def load_gfxfile(fn):
    if fn.startswith('flags/'):
        return load_flag(fn[len('flags/'):])
    else:
        if not fn.startswith('data/'):
            fn = 'data/' + fn
            try:
                return graphics.load_image(fn + '.png')
            except graphics.SDLError:
                return graphics.load_image(fn + '.jpg')
        return graphics.load_image(fn)
Пример #3
0
def load_gfxfile(fn):
    if fn.startswith('flags/'):
        return load_flag(fn[len('flags/'):])
    else:
        if not fn.startswith('data/'):
            fn = 'data/' + fn
            try:
                return graphics.load_image(fn + '.png')
            except graphics.SDLError:
                return graphics.load_image(fn + '.jpg')
        return graphics.load_image(fn)
Пример #4
0
def main():
    features.parse_options()
    setup_game_version()
    setup_android_version()
    setup_errors()

    maybe_start_remote_debug()

    monitor.start()
    save.start_zygote()

    client.window.init_screen()
    osutil.init()
    set_logical_size()

    ui.init()
    ui.set_fill_image(graphics.load_image('data/user/background.jpg'))

    setup_freeciv_config()
    client.window.init()
    gamescreen.init()

    start_autoupdate()
    start_marketnotice()

    ctrl.maybe_init()

    client.freeciv.run()
Пример #5
0
 def __init__(self, x_scale, y_scale, crafts, game):
     self.x_scale = x_scale
     self.y_scale = y_scale
     self.selected = (0, y_scale)
     self.game = game
     if not game.is_server:
         self.icon = load_image('icon.png')
         self.arrow = load_image('arrow.png')
         self.bar_icon = load_image('bar_icon.png')
         self.selected_icon = load_image('selected_icon.png')
     self.main_container = ItemContainer(self, x_scale, y_scale)
     self.bar_container = BarContainer(self, x_scale, 1)
     self.item_buffer = ItemBuffer(self)
     self.crafts = crafts
     self.grabbed = None
     self.craft_model = CraftModel(self, (2, 2), (1, 1), self.crafts, self.game.objects, check_craft)
Пример #6
0
    def __init__(self, game_opts):
        # initialize the state
        State.__init__(self, constants.SCENES['intro'])

        ## the game's command line options
        self.game_opts = game_opts

        ## intro slides
        slide_num = len(constants.FILES['graphics']['intro']['slides'])
        self.slides = [
            graphics.load_image(
                constants.FILES['graphics']['intro']
                ['slides'][i])[0] for i in range(slide_num)
            ]

        ## cut scenes object
        self.cutscenes = IntroCutScene(self.slides)

        # set sound volume to minimum
        pygame.mixer.music.set_volume(0.0)

        # play the background music theme
        sound_mixer.play_music(
            constants.FILES['sounds']['menu']['share']['bg'][0])

        # pause or unpause music according to user preference
        if self.game_opts.music:
            pygame.mixer.music.unpause()
        else:
            pygame.mixer.music.pause()

        # set sound volume to maximum
        pygame.mixer.music.set_volume(MAX_VOLUME)
Пример #7
0
def init_orders():
    global order_sprites
    img_orders = graphics.load_image('data/user/theme_orders_buttons.png')
    order_sprites = client.common.split_sprites(img_orders, start=(0, 1), each=(29, 31), size=(31, 29), num=(1, 38))

    for line in order_sprites:
        line[0] = line[0].scale((56, 56))
Пример #8
0
def main():
    features.FEATURE_FILE_PATH = os.path.join(save.get_save_dir(), 'features')
    features.parse_options()
    setup_game_version()
    setup_android_version()
    setup_errors()

    maybe_start_remote_debug()

    monitor.start()
    save.start_zygote()

    client.window.init_screen()
    osutil.init()

    ui.init()
    ui.set_fill_image(graphics.load_image('data/user/background.jpg'))

    setup_freeciv_config()
    client.window.init()
    gamescreen.init()

    start_autoupdate()
    start_marketnotice()

    client.freeciv.run()
Пример #9
0
    def __init__(self):
        self.bkgdImg = graphics.load_image(os.path.join("img", "city.png"))
        self.foreImg = graphics.load_image(os.path.join("img", "street.png"))

        self.bkgd_W = self.bkgdImg.get_width()
        self.bkgd_X = 0.

        self.bkgd_X1 = self.bkgd_X
        self.bkgd_X2 = self.bkgd_X + self.bkgd_W

        self.fore_W = self.foreImg.get_width()
        self.fore_X = 0.

        self.fore_X1 = self.fore_X
        self.fore_X2 = self.fore_X - self.fore_W
        self.fore_X3 = self.fore_X + self.fore_W
Пример #10
0
def init_orders():
    global order_sprites
    img_orders = graphics.load_image('data/user/theme_orders_buttons.png')
    order_sprites = client.common.split_sprites(img_orders, start=(0, 1), each=(29, 31), size=(31, 29), num=(1, 38))

    for line in order_sprites:
        line[0] = line[0].scale((56, 56))
Пример #11
0
def main():
    features.FEATURE_FILE_PATH = os.path.join(save.get_save_dir(), 'features')
    features.parse_options()
    setup_game_version()
    setup_android_version()
    setup_errors()

    maybe_start_remote_debug()

    monitor.start()
    save.start_zygote()

    client.window.init_screen()
    osutil.init()

    ui.init()
    ui.set_fill_image(graphics.load_image('data/user/background.jpg'))

    setup_freeciv_config()
    client.window.init()
    gamescreen.init()

    start_autoupdate()
    start_marketnotice()

    client.freeciv.run()
Пример #12
0
def load_flags_file(name):
    img = graphics.load_image('data/flags/%s-output.png' % name)
    for line in osutil.open_res('data/flags/%s.index' % name):
        name, rect = line.split(' ', 1)
        rect = map(int, rect.split())
        flag = graphics.create_surface_small(rect[2], rect[3])
        flag.blit(img, (0, 0), rect)
        flag_index[name] = flag
Пример #13
0
def load_flags_file(name):
    img = graphics.load_image('data/flags/%s-output.png' % name)
    for line in osutil.open_res('data/flags/%s.index' % name):
        name, rect = line.split(' ', 1)
        rect = map(int, rect.split())
        flag = graphics.create_surface_small(rect[2], rect[3])
        flag.blit(img, (0, 0), rect)
        flag_index[name] = flag
Пример #14
0
 def __init__(self, path, BLOCK_SIZE):
     image = load_image(path)
     rect = image.get_rect()
     image = pygame.transform.scale(image,
                                    (int(rect.width * (BLOCK_SIZE / 32)),
                                     int(rect.height * (BLOCK_SIZE / 32))))
     rect = image.get_rect()
     tile = TileImage(image, rect.width, rect.height)
     super().__init__(tile)
Пример #15
0
 def __init__(self):
     self._score = 0
     self.sprite_sheet = graphics.load_image(
         os.path.join("img", "score.png"))
     self.nums = [x * 20 for x in xrange(0, 10)]
     self.pad = 2
     self.wid = 20
     self.x = constants.SCR_HEIGHT + 3 * self.pad + 2.5 * self.wid  # The right of the score.
     self.y = 5
     self._inds = [0 for x in xrange(0, 5)]
Пример #16
0
def get_white_mask(mask):
    # HACK: SDL doesn't allow us to access raw pixel data of textures
    # so load modified image from disk based on surface _filename
    name, params = mask.filename[:-1].split('[', 1)
    params = tuple(map(int, params.split(',')))
    base, ext = name.split('.')
    name = base + '_white.' + ext
    if (name, params) not in mask_cache:
        base_img = graphics.load_image(name)
        mask_cache[name, params] = crop_sprite(base_img, *params)
    return mask_cache[name, params]
Пример #17
0
    def __init__(self, image, init_pos):
        '''Create a new static sprite.

        Arguments:
        image -- the sprite's image filename
        init_pos -- the sprite's initial position
        '''
        pygame.sprite.Sprite.__init__(self)
        self.image = load_image(image)[0]
        self.rect = self.image.get_rect()
        self.rect.topleft = init_pos
Пример #18
0
    def __init__(self):
        super(Slime, self).__init__(graphics.load_image(os.path.join("img", "slime spritesheet calciumtrice.png")))
        self.sprite = (0, 0, 32, 32)
        self.waypoints = []

        self.speed = 2
        self.frame = 0.0
        self.facing = RIGHT
        self.action = Actions.IDLE

        self.dir = Dir.NONE
Пример #19
0
    def __init__(self, image, init_pos):
        '''Create a new static sprite.

        Arguments:
        image -- the sprite's image filename
        init_pos -- the sprite's initial position
        '''
        pygame.sprite.Sprite.__init__(self)
        self.image = load_image(image)[0]
        self.rect = self.image.get_rect()
        self.rect.topleft = init_pos
Пример #20
0
def get_white_mask(mask):
    # HACK: SDL doesn't allow us to access raw pixel data of textures
    # so load modified image from disk based on surface _filename
    name, params = mask.filename[:-1].split('[', 1)
    params = tuple(map(int, params.split(',')))
    base, ext = name.split('.')
    name = base + '_white.' + ext
    if (name, params) not in mask_cache:
        base_img = graphics.load_image(name)
        mask_cache[name, params] = crop_sprite(base_img, *params)
    return mask_cache[name, params]
Пример #21
0
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)

        self.image = graphics.load_image('images/food.png', True)
        self.rect = self.image.get_rect()

        x = random.randint(2 , config.blocks[0] - 2 )
        y = random.randint(2 , config.blocks[1] - 2 )

        self.rect.left = x * config.scale
        self.rect.top = y * config.scale
Пример #22
0
 def __init__(self):
     self.text_field_img = resize(load_image(config.name_items+TEXT_FIELD+PNG_EXT, True), config.name_text_field_size)
     self.text_field_rect = self.text_field_img.get_rect()
     self.text_field_rect.center = config.name_text_field_pos
     
     self.is_complete = False
     self.functions = {}
     self.elements = {}
     self.load_elements()
     self.load_functions()
     self.generate_table()
Пример #23
0
    def __init__(self, image, init_pos):
        # call the base sprite constructor
        pygame.sprite.Sprite.__init__(self)

        ## the sprite's image
        self.image = load_image(image)[0]

        ## the sprite's rectangle structure
        self.rect = self.image.get_rect()

        ## the sprite's initial position
        self.rect.topleft = init_pos
Пример #24
0
    def __init__(self):
        super(Slime, self).__init__(
            graphics.load_image(
                os.path.join("img", "slime spritesheet calciumtrice.png")))
        self.sprite = (0, 0, 32, 32)
        self.waypoints = []

        self.speed = 2
        self.frame = 0.0
        self.facing = RIGHT
        self.action = Actions.IDLE

        self.dir = Dir.NONE
Пример #25
0
    def __init__(self, game_opts):
        # initialize the state
        State.__init__(self, 'intro')

        ## the game's command line options
        self.game_opts = game_opts

        ## the intro background slides
        self.slides = [
            graphics.load_image( # slide 0
                constants.FILES['graphics']['intro']['slides'][0])[0],

            graphics.load_image( # slide 1
                constants.FILES['graphics']['intro']['slides'][1])[0],

            graphics.load_image( # slide 2
                constants.FILES['graphics']['intro']['slides'][2])[0]
        ]

        ## a cut scenes object
        self.cs = CutScenes(self.slides)

        # set sound volume to minimum
        pygame.mixer.music.set_volume(0.0)

        # play the background music theme
        sound_mixer.play_music(
            constants.FILES['sounds']['menu']['share']['bg'][0])

        # pause or unpause music according to user preference
        if self.game_opts.music:
            pygame.mixer.music.unpause()
        else:
            pygame.mixer.music.pause()

        # set sound volume to maximum
        pygame.mixer.music.set_volume(1.0)
Пример #26
0
    def __init__(self, filename, speed=SPRITE_SPEED):
        # call the base constructor
        pygame.sprite.Sprite.__init__(self)

        ## set up the speed of the sprite
        self.speed = speed

        ## set up the graphic of the sprite
        self.image = load_image(filename)[0]

        ## set up the x coordinate of the sprite
        self.x = 0

        ## set up the y coordinate of the sprite
        self.y = 0
Пример #27
0
def main():
    if sys.argv[1:] and sys.argv[1] == 'server':
        from freeciv.client import _freeciv
        import os
        _freeciv.func.py_server_main_run(sys.argv[2:])
        os._exit(0)

    features.parse_options()
    if features.get('debug.dsn'):
        sys.excepthook = early_except_hook

    maybe_setup_launch_param()

    setup_game_version()
    setup_android_version()
    setup_errors()

    maybe_notify_about_launch()
    maybe_start_remote_debug()

    monitor.start()
    if features.get('app.fork'):
        save.start_zygote()

    init_window()
    client.window.init_screen()
    osutil.init()

    #Disable "set_logical_size" feature because
    # - it needs patching SDL
    # - there is a zoom feature in the game.
    # - it makes the graphics to be more blurred because they are zoomed twice when using game zoom
    #if not osutil.is_desktop:
    #    set_logical_size() # Deleted. See lib/ui/core.py:scale_for_device


    ui.init()
    ui.set_fill_image(graphics.load_image('userdata/background.jpg'))

    client.window.init()
    gamescreen.init()

    start_autoupdate()
    start_marketnotice()

    if ctrl:
        ctrl.maybe_init()
    client.freeciv.run(['--log', monitor.get_log_path_base() + '.log'])
Пример #28
0
def main():
    # change the current directory to the one of the game
    os.chdir(os.path.abspath(os.path.dirname(sys.argv[0])))

    # parse, get game's command line
    # options, return options' flags
    game_opts = get_parsed_opts()

    # make the window of the game always centered
    os.environ["SDL_VIDEO_CENTERED"] = "1"

    # set up the pygame system for the game
    pygame.init()

    # create game's window screen
    pygame.display.set_mode(
        (constants.SCREEN_WIDTH, constants.SCREEN_HEIGHT),
        pygame.FULLSCREEN if game_opts.fullscreen else 0)

    # set game's window title
    pygame.display.set_caption(GAME_WINDOW_TITLE)

    # set game's window icon
    pygame.display.set_icon(load_image(
        constants.FILES['graphics']['window']['icon'][0])[0])

    # hide game's mouse cursor
    pygame.mouse.set_visible(False)

    # create the game manager
    gm = GameManager(game_opts)

    # main loop flag
    main_loop_running = True

    # main game event loop
    while main_loop_running:
        # run the game manager        
        gm.run_scene()

        # on quit exit the game
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                main_loop_running = False

    # uninitialize all the pygame systems
    pygame.quit()
Пример #29
0
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)

        self.image = graphics.load_image('images/block.png')
        self.rect = self.image.get_rect()

        self.speed = [ 1 , 1 ]

        self.rect.left = config.blocks[0] / 2 * config.scale
        self.rect.top = config.blocks[1] / 2 * config.scale

        self.length = 1
        self.grow_to = 5
        self.vx = 0
        self.vy = -1
        self.body = []
        self.crashed = False
Пример #30
0
    def __init__(self, manager, slides):
        self.event_manager = manager
        self.event_manager.register_listener(self)

        ## the screen surface
        self.screen = pygame.display.get_surface()

        ## the list of background slides
        assert(len(slides) > 0)
        self.slides = slides

        ## the blank background slide
        self.blank = graphics.load_image(
            constants.FILES['graphics']['intro']['blank'][0])[0].convert()
        
        ## set the alpha to maximum value
        self.alphavalue = MAX_ALPHA
Пример #31
0
    def __init__(self, director):
        scene.Scene.__init__(self, director)

        self.mensaje, self.pos_msg = graphics.text(
            "Elija el color que esta escrito", 700, 70, (247, 220, 111), 30)
        self.back = graphics.load_image(confi.fonts + "fondoJuego.jpg")
        self.imagenes = [
            "rojo10", "verde1", "rojo1", "verde2", "rojo2", "verde3", "rojo3",
            "verde4", "rojo4", "verde5", "rojo5", "verde6", "rojo6", "verde7",
            "rojo7", "verde8", "rojo8", "verde9", "rojo9"
        ]
        self.numRandonX = None
        self.numRandonY = None
        #self.Figures=[]
        self.Figures = None
        #self.ser = serial.Serial(port='', baudrate=9600)
        self.datoEnviar = ''
        self.datoRecibido = ''
Пример #32
0
    def __init__(self, ss_off, xoff, ground):
        self.type = EntityType.NONE
        self.sprite_sheet = graphics.load_image(
            os.path.join("img", "objects.png"))
        self.xoff = xoff
        self.x = gamespeed.pos + self.xoff
        self.y = 0.
        self.rect = pygame.Rect(self.x, self.y, OBJECT_SIZE, OBJECT_SIZE)
        self.FRAMES = [(i * OBJECT_SIZE, ss_off * OBJECT_SIZE, OBJECT_SIZE,
                        OBJECT_SIZE) for i in xrange(OBJECT_NUM_OF_FRAMES)]
        self.frame = 0.
        self.gravity = False
        self.vs = 0.

        if ground:
            self.setToGround()
        else:
            self.setToFlying()
Пример #33
0
def main():
    if sys.argv[1:] and sys.argv[1] == 'server':
        from freeciv.client import _freeciv
        import os
        _freeciv.func.py_server_main_run(sys.argv[2:])
        os._exit(0)

    features.parse_options()
    if features.get('debug.dsn'):
        sys.excepthook = early_except_hook

    maybe_setup_launch_param()

    setup_game_version()
    setup_android_version()
    setup_errors()

    maybe_notify_about_launch()
    maybe_start_remote_debug()

    monitor.start()
    if features.get('app.fork'):
        save.start_zygote()

    init_window()
    client.window.init_screen()
    osutil.init()
    if not osutil.is_desktop:
        set_logical_size()

    ui.init()
    ui.set_fill_image(graphics.load_image('data/user/background.jpg'))

    setup_freeciv_config()
    client.window.init()
    gamescreen.init()

    start_autoupdate()
    start_marketnotice()

    if ctrl:
        ctrl.maybe_init()

    client.freeciv.run()
Пример #34
0
def main():
    if sys.argv[1:] and sys.argv[1] == 'server':
        from freeciv.client import _freeciv
        import os
        _freeciv.func.py_server_main_run(sys.argv[2:])
        os._exit(0)

    features.parse_options()
    if features.get('debug.dsn'):
        sys.excepthook = early_except_hook

    maybe_setup_launch_param()

    setup_game_version()
    setup_android_version()
    setup_errors()

    maybe_notify_about_launch()
    maybe_start_remote_debug()

    monitor.start()
    if features.get('app.fork'):
        save.start_zygote()

    init_window()
    client.window.init_screen()
    osutil.init()
    if not osutil.is_desktop:
        set_logical_size()

    ui.init()
    ui.set_fill_image(graphics.load_image('data/user/background.jpg'))

    setup_freeciv_config()
    client.window.init()
    gamescreen.init()

    start_autoupdate()
    start_marketnotice()

    if ctrl:
        ctrl.maybe_init()

    client.freeciv.run()
Пример #35
0
    def __init__(self, slides):
        ## the screen surface
        self.screen = pygame.display.get_surface()

        ## the list of background slides
        self.slides = slides

        ## the blank background slide
        self.blank = graphics.load_image(
            constants.FILES['graphics']['intro']['blank'][0])[0].convert()

        ## set the alpha to maximum value
        self.alphavalue = 255

        ## create clock and track time
        self.clock = pygame.time.Clock()

        ## flag to indicate if the scene is finished
        self.is_finished = False
Пример #36
0
 def __init__(self, director, background_name):
     '''
     Constructor
     '''        
     Scene.__init__(self, director, background_name)
     self.title_img = load_image(config.titles+'functional_groups'+PNG_EXT, True)
     self.title_img = pygame.transform.scale(self.title_img, (450, 150))
     self.title_rect = self.title_img.get_rect()
     self.title_rect.centerx = config.width / 2
     self.title_rect.centery = 80
     
     self.buttoms = {
                     DEFINITIONS_SCENE: Buttom((230, 180), config.b_size, "buttom_1_pressed"+PNG_EXT, "buttom_1_release"+PNG_EXT, True),                                                    
                     NAME_SCENE: Buttom((580, 180), config.b_size, "buttom_2_pressed"+PNG_EXT, "buttom_2_release"+PNG_EXT, True), 
                     COTIDIAN_FUNCTION_SCENE: Buttom((230, 300), config.b_size, "buttom_3_pressed"+PNG_EXT, "buttom_3_release"+PNG_EXT, True),
                     MATCH_SCENE: Buttom((580, 300), config.b_size, "buttom_4_pressed"+PNG_EXT, "buttom_4_release"+PNG_EXT, True),
                     ALPHABET_SOUP_SCENE: Buttom((230, 440), config.b_size, "buttom_5_pressed"+PNG_EXT, "buttom_5_release"+PNG_EXT, True),  
                     CRUCIGRAMA_SCENE: Buttom((580, 440), config.b_size, "buttom_6_pressed"+PNG_EXT, "buttom_6_release"+PNG_EXT, True),                        
                     HANGMAN_SCENE: Buttom((config.width / 2, 530), config.b_size, "buttom_7_pressed"+PNG_EXT, "buttom_7_release"+PNG_EXT, True)
                     }
Пример #37
0
 def __init__(self):
     self.text_field_img = resize(load_image(config.name_items+TEXT_FIELD+PNG_EXT, True), config.hangman_text_field_size)
     self.text_field_rect = self.text_field_img.get_rect()
     self.text_field_rect.center = config.hangman_text_field_pos
     
     self.changed = False
     self.intents = 8
     self.paused = False
     self.is_complete = False
     self.tracks = []
     self.words = []
     self.typeds = []
     self.intent = 0
     self.lose = False
     self.word = ''
     self.track = ''
     self.exposed = ''
     
     self.load_words()            
     self.choose_word()
Пример #38
0
    def __init__(self, director):
        Scene.__init__(self, director)

        self.background = pygame.Surface( ( config.width , config.height) )
        self.background.fill( ( 187 , 200 , 0) )

        block = graphics.load_image('images/block.png')

        for x in xrange( 0 , config.blocks[0] ):
            self.background.blit( block , ( x * config.scale , 0 ) )
            self.background.blit( block , ( x * config.scale , config.height - config.scale ) )

        for x in xrange( 1 , config.blocks[1] - 1):
            self.background.blit( block , ( 0 , x * config.scale ) )
            self.background.blit( block , ( config.width - config.scale , x * config.scale ) )

        self.score = 0

        self.worm = sprites.Worm()
        self.food = sprites.Food()
Пример #39
0
    def __init__(self, manager, game_opts):
        self.event_manager = manager
        self.event_manager.register_listener(self)
        self.game_opts = game_opts

        GAME_WINDOW_TITLE = constants.GAME_PACKAGE

        # make the window of the game always centered
        os.environ["SDL_VIDEO_CENTERED"] = "1"

        pygame.init()

        pygame.display.set_mode(
            (constants.SCREEN_WIDTH, constants.SCREEN_HEIGHT),
            pygame.FULLSCREEN if self.game_opts.fullscreen else 0)

        pygame.display.set_caption(GAME_WINDOW_TITLE)

        pygame.display.set_icon(load_image(
                constants.FILES['graphics']['window']['icon'][0])[0])

        pygame.mouse.set_visible(False)
Пример #40
0
    def __init__(self, director):
        scene.Scene.__init__(self, director)
        self.mensaje, self.pos_msg = graphics.text(
            "Bienvenido a tu pausa activa ", 700, 70, (247, 220, 111), 100)
        self.continuar = pygame.transform.scale(
            graphics.load_image(confi.fonts + "continuar1.png"), (150, 50))
        self.back = graphics.load_image(confi.fonts + "fondo1.jpg")
        self.titulo = pygame.transform.scale(
            graphics.load_image(confi.fonts + "bienvenido.jpg"), (900, 150))
        self.beneficios = pygame.transform.scale(
            graphics.load_image(confi.fonts + "beneficios.jpg"), (700, 540))
        self.escudo = pygame.transform.scale(
            graphics.load_image(confi.fonts + "ud.jpg"), (75, 75))
        self.logo = pygame.transform.scale(
            graphics.load_image(confi.fonts + "vrbox.jpg"), (150, 150))

        self.scene_game = sceneGame.SceneGame(director)  #cambiar de escena
Пример #41
0
	def __init__(self):
		self.sprite_sheet = graphics.load_image(os.path.join("img", "jogging_lawrence.png"))
		self.rect = pygame.Rect(_PLAYER_RECT_X_START, _GROUND_PLAYER_HEAD, _RECT_W, _RECT_H)

		self.jump_counter = 0
		self.jump_counter_enabled = False
		self.jump_released = False

		self.down_pressed = False

		# Horizontal and Vertical Speeds
		self.hs = 0
		self.vs = 0
		self.alive = True

		self.on_ground = True # If on the ground.
		self.falling = False  # If down was pressed.

		self.action = Action.RUN
		self.weight = Weight.NORMAL

		self.frame = 0
		self.speed = 3
Пример #42
0
def image_to_painter(filename):
	img = graphics.load_image(filename)
	tolerance = 1/spread
	limit = 0.86
	#process
	def painter(vp, frame):
		if(is_list(vp[0])):
			def get_depth(x,y,dir):
				global spread
				nonlocal pixels
				for c in range(spread):
					ox = round(x+dir*(-0.3*spread+c))
					if(ox>=0 and ox<viewport_size):
						if type(pixels[ox,y]) is int: #this is a workaround for black/white pictures.
							curr = pixels[ox,y]
						else:
							curr = pixels[ox, y][0]
						d = abs(curr - 255*c/spread)
						if(d<=tolerance*255):
							return curr
				return 255
			def ana_out_loop(port, count):
				nonlocal img
				size = graphics.get_image_size(img)
				MAX_X = size[0]
				MAX_Y = size[1]
				tsize = graphics.get_image_size(port)
				TMAX_X = tsize[0]
				TMAX_Y = tsize[1]
				tgtpixels = graphics.get_pixels(port)
				inv_transform = inverse_transform_posn(frame)
				# for y in range(MAX_Y):
					# for x in range(MAX_X):
						# col = get_depth(x,y,count)
						# if(col>255*limit):
							# col = 999
						# else:
							# col = frame.z1 + (frame.z2 - frame.z1) * col
						# if col<=255:
							# transposn = transform(Posn(x,y))
							# if(transposn.x>=0 and transposn.y>=0 and transposn.x<TMAX_X and transposn.y<TMAX_Y):
								# tgtpixels[transposn.x, transposn.y] = (col,col,col)
				#sorry, no supersampling. Takes long enough as it is.
				for y in range(TMAX_Y):
					for x in range(TMAX_X):
						orig = inv_transform(Posn(x,y))
						rx = round(orig.x)
						ry = round(orig.y)
						if (rx>=0 and ry>=0 and rx<MAX_X and ry<MAX_Y): #within bounds
							col = get_depth(rx, ry, count)
							if(col>255*limit):
								col = 999
							else:
								col = round(frame.z1*255 + (frame.z2 - frame.z1) * col)
							if(col<=255):
								#tgtpixels[x,y] = (col, col, col)
								tgtpixels[x,y] = (min(col, tgtpixels[x,y][0]),min(col, tgtpixels[x,y][1]),min(col, tgtpixels[x,y][2]))
				graphics.pixels_to_canvas(port)
			pixels = graphics.get_pixels(img)
			for count, port in enumerate(vp):
				ana_out_loop(port, ((2*count)/(len(vp)-1) - 1))
		else:
			transform = inverse_transform_posn(frame)
			graphics.blit_pixels(vp, transform, graphics.get_pixels(img), graphics.get_image_size(vp), graphics.get_image_size(img), True, frame.z1, frame.z2) #block level image transfer
	return painter
Пример #43
0
import constants as const


def load_story():
    with open(os.path.join("text", "story.txt"), "r") as file:
        data = file.read()
    lines = data.split("\n")
    return lines


story = load_story()

m5x7 = pygame.font.Font(os.path.join("text", "m5x7.ttf"), 32)
m3x6 = pygame.font.Font(os.path.join("text", "m3x6.ttf"), 32)

small_heart = graphics.load_image("heart_small", 2)
small_heart.set_colorkey(const.TRANSPARENT)
large_heart = graphics.load_image("heart_large", 2)
large_heart.set_colorkey(const.TRANSPARENT)

TUTORIAL_TEXT_LEVEL = 16
FIRST_CHECKPOINT_LEVEL = 25
REALIZATION_LEVEL = 36

music_changes = [
    TUTORIAL_TEXT_LEVEL, FIRST_CHECKPOINT_LEVEL, REALIZATION_LEVEL, 38, 40, 43,
    77
]


class Sequence:
Пример #44
0
    def __init__(self, game_opts):
        # initialize the state
        State.__init__(self, 'menu')

        ## the game's command line options
        self.game_opts = game_opts

        ## the screen surface
        self.screen = pygame.display.get_surface() 

        ## flag to control the settings menu's loop
        self.menu_settings_running = None

        ## flag to control the main menu's loop
        self.menu_main_running = True

        # enable key repeat for the menu
        pygame.key.set_repeat(MENU_KEY_DEL, MENU_KEY_INT)

        ## set the main menu's background
        self.menu_main_bg = graphics.load_image(
            constants.FILES['graphics']['menu']['main']['bg'][0])[0]

        ## set the settings menu's background
        self.menu_settings_bg = graphics.load_image(
            constants.FILES['graphics']['menu']['share']['bg'][0])[0]

        ## set the settings menu's background box
        self.menu_box_bg = graphics.load_image(
            constants.FILES['graphics']['menu']['settings']['box'][0])[0]

        ## set the window frame
        self.window_frame = graphics.load_image(
            constants.FILES['graphics']['menu']['share']['frame'][0])[0]

        ## set the mouse cursor
        self.mouse_cursor = graphics.load_image(
            constants.FILES['graphics']['menu']['share']['cursor'][0])[0]

        ## set the sound when a menu option is entered
        self.select_option_snd = sound_mixer.load_sound(
            constants.FILES['sounds']['menu']['share']['sel'][0])

        ## create the main menu - string, callback function
        self.menu_main = KezMenu(self.game_opts,
                         ['Play'     , self._play_option],
                         ['Settings' , self._settings_option],
                         ['Credits'  , self._credits_option],
                         ['Quit'     , self._quit_option])

        # set the position of the main menu
        self.menu_main.set_position(MENU_MAIN_POS_X, MENU_MAIN_POS_Y)

        # set the main menu's font
        self.menu_main.set_font(graphics.load_font(
            constants.FILES['fonts']['menu']['share'][0], 30))

        # set the main menu's highlight color
        self.menu_main.set_highlight_color(pygame.Color('brown'))

        ## create the settings menu - string, callback function
        self.menu_settings = KezMenu(self.game_opts,
                             ['Fullscreen' , self._toggle_fullscreen_option],
                             ['Sounds'     , self._toggle_sounds_option],
                             ['Music'      , self._toggle_music_option],
                             ['Back'       , self._back_option])

        # disable the menu graphic for focused options
        self.menu_settings.toggle_image()

        # set the settings menu's font
        self.menu_settings.set_font(graphics.load_font(
            constants.FILES['fonts']['menu']['share'][0], 25))

        # set the position of the settings menu
        self.menu_settings.center_at(constants.SCREEN_WIDTH / 2.0,
                                     constants.SCREEN_HEIGHT / 2.0)
    
        # set the settings menu's highlight color
        self.menu_settings.set_highlight_color(pygame.Color('orange'))

        ## the animated sprite group
        self.anim_sprites = pygame.sprite.RenderUpdates()

        # vertical sprite sample
        self.anim_sprites.add(VertAnimSprite(
                constants.FILES['graphics']['menu']['share']['anim'][0],
                [0, 0], ANIM_SPRITE_SPEED))

        # horizontal sprite sample
        self.anim_sprites.add(HorAnimSprite(
                constants.FILES['graphics']['menu']['share']['anim'][1],
                [0, 0], ANIM_SPRITE_SPEED))

        ## create clock and track time
        self.clock = pygame.time.Clock()
Пример #45
0
    def __init__(self, col, row):
        super().__init__()
        self.col = col
        self.row = row


class PlayerGoalZone(Tile):
    SOLID = False
    EMITTED = True
    DRAWN_STATICALLY = True

    def __init__(self):
        super().__init__()


punch_box_left = graphics.load_image("punch_box", 2)
punch_box_left.set_colorkey(const.TRANSPARENT)
punch_box_up = pygame.transform.rotate(punch_box_left, -90)
punch_box_right = pygame.transform.rotate(punch_box_left, 180)
punch_box_down = pygame.transform.rotate(punch_box_left, 90)
punch_box_gradient = graphics.load_image("punch_box_gradient", 1)
punch_box_glow = graphics.load_image("punch_box_glow", 1)

checkpoint_activated = graphics.load_image("checkpoint_activated", 2)
checkpoint_activated.set_colorkey(const.TRANSPARENT)
checkpoint_deactivated = graphics.load_image("checkpoint_deactivated", 2)
checkpoint_deactivated.set_colorkey(const.TRANSPARENT)
checkpoint_gradient = graphics.load_image("checkpoint_gradient", 1)
checkpoint_glow = graphics.load_image("checkpoint_glow", 1)

checkpoint_ray_horiz_gradient = graphics.load_image(
Пример #46
0
    entities.player.Player.hard_respawn_key, entities.player.Player.pause_key
]
rebind_descriptions = [
    "Left", "Right", "Jump", "Action", "Reset level", "Pause"
]

m3x6 = pygame.font.Font(os.path.join("text", "m3x6.ttf"), 64)

main_menu_music = sound.load("menu_music")

start_sound = sound.load("game_start")
start_sound.set_volume(0.4)
select_sound = sound.load_numbers("menu%i", 3)
select_sound.set_volumes(0.35)

title = graphics.load_image("title", 1)

title_shade = pygame.Surface(title.get_size())


def render_menu_text(surf, string, y, brightness):
    color = flicker.shade_color[brightness]
    text = m3x6.render(string, False, color)
    x = const.SCRN_W // 2 - text.get_width() // 2
    surf.blit(text, (x, y))


class MainMenu:
    TITLE_X = const.SCRN_W // 2 - title.get_width() // 2
    TITLE_Y = 100
Пример #47
0
import sound

import pygame

import constants as const
import events
import graphics

name = graphics.load_image("splash_name", 4)
name.set_colorkey(const.TRANSPARENT)

_logo_column = graphics.AnimColumn("splash_logo", 11, 4)
_logo_column.set_delay(9)
_logo_sheet = graphics.AnimSheet([_logo_column])
logo = graphics.AnimInstance(_logo_sheet)

LOGO_NAME_GAP = 24

WIDTH = name.get_width() + _logo_column.surface.get_width() + LOGO_NAME_GAP
HEIGHT = name.get_height() + 4

LOGO_X = const.SCRN_W // 2 - WIDTH // 2
NAME_X = LOGO_X + _logo_column.surface.get_width() + LOGO_NAME_GAP

NAME_Y = const.SCRN_H // 2 - HEIGHT // 2
LOGO_Y = NAME_Y + 12

FADE_IN_LENGTH = 60
FADE_HOLD_LENGTH = 140
FADE_OUT_LENGTH = 60
Пример #48
0
    def __init__(self, director, background_name):
        """
        Constructor
        """
        Scene.__init__(self, director, background_name)
        self.scene_winner = Sce_Winner(director, "winner", CRUCIGRAMA_SCENE)

        for buttom in self.common_buttoms.itervalues():
            buttom.is_visible = True

        self.buttoms = {
            VERT_1: Buttom(
                (117, 207),
                config.crux_b_size,
                "crux_" + VERT_1 + "_pressed" + PNG_EXT,
                "crux_" + VERT_1 + "_release" + PNG_EXT,
                True,
            ),
            VERT_2: Buttom(
                (194, 394),
                config.crux_b_size,
                "crux_" + VERT_2 + "_pressed" + PNG_EXT,
                "crux_" + VERT_2 + "_release" + PNG_EXT,
                True,
            ),
            VERT_3: Buttom(
                (221, 257),
                config.crux_b_size,
                "crux_" + VERT_3 + "_pressed" + PNG_EXT,
                "crux_" + VERT_3 + "_release" + PNG_EXT,
                True,
            ),
            VERT_4: Buttom(
                (381, 311),
                config.crux_b_size,
                "crux_" + VERT_4 + "_pressed" + PNG_EXT,
                "crux_" + VERT_4 + "_release" + PNG_EXT,
                True,
            ),
            HORZ_1: Buttom(
                (11, 233),
                config.crux_b_size,
                "crux_" + HORZ_1 + "_pressed" + PNG_EXT,
                "crux_" + HORZ_1 + "_release" + PNG_EXT,
                True,
            ),
            HORZ_2: Buttom(
                (91, 313),
                config.crux_b_size,
                "crux_" + HORZ_2 + "_pressed" + PNG_EXT,
                "crux_" + HORZ_2 + "_release" + PNG_EXT,
                True,
            ),
            HORZ_3: Buttom(
                (141, 365),
                config.crux_b_size,
                "crux_" + HORZ_3 + "_pressed" + PNG_EXT,
                "crux_" + HORZ_3 + "_release" + PNG_EXT,
                True,
            ),
            HORZ_4: Buttom(
                (90, 448),
                config.crux_b_size,
                "crux_" + HORZ_4 + "_pressed" + PNG_EXT,
                "crux_" + HORZ_4 + "_release" + PNG_EXT,
                True,
            ),
        }

        self.words_rect = {
            VERT_1: Rect((102, 218), (131 - 102, 382 - 218)),
            VERT_2: Rect((181, 406), (131 - 102, 516 - 406)),
            VERT_3: Rect((208, 272), (131 - 102, 517 - 272)),
            VERT_4: Rect((366, 326), (131 - 102, 516 - 326)),
            HORZ_1: Rect((22, 219), (179 - 22, 382 - 354)),
            HORZ_2: Rect((103, 300), (289 - 103, 382 - 354)),
            HORZ_3: Rect((155, 353), (395 - 155, 382 - 354)),
            HORZ_4: Rect((102, 434), (289 - 102, 382 - 354)),
        }

        self.words = {
            VERT_1: resize(load_image(config.crux_words_imgs + VERT_1 + PNG_EXT, True), self.words_rect[VERT_1].size),
            VERT_2: resize(load_image(config.crux_words_imgs + VERT_2 + PNG_EXT, True), self.words_rect[VERT_2].size),
            VERT_3: resize(load_image(config.crux_words_imgs + VERT_3 + PNG_EXT, True), self.words_rect[VERT_3].size),
            VERT_4: resize(load_image(config.crux_words_imgs + VERT_4 + PNG_EXT, True), self.words_rect[VERT_4].size),
            HORZ_1: resize(load_image(config.crux_words_imgs + HORZ_1 + PNG_EXT, True), self.words_rect[HORZ_1].size),
            HORZ_2: resize(load_image(config.crux_words_imgs + HORZ_2 + PNG_EXT, True), self.words_rect[HORZ_2].size),
            HORZ_3: resize(load_image(config.crux_words_imgs + HORZ_3 + PNG_EXT, True), self.words_rect[HORZ_3].size),
            HORZ_4: resize(load_image(config.crux_words_imgs + HORZ_4 + PNG_EXT, True), self.words_rect[HORZ_4].size),
        }

        self.is_typing = False
        self.typing_in = ""
        self.complete_word = ""
        self.complete_words = []
        self.finish_typing = False
Пример #49
0
import pygame

import constants as const
import graphics

import grid

punchers = []

punch_left = graphics.load_image("punch", 2)
punch_left.set_colorkey(const.TRANSPARENT)
punch_right = pygame.transform.flip(punch_left, True, False)
punch_up = pygame.transform.rotate(punch_right, 90)
punch_down = pygame.transform.rotate(punch_right, -90)


def add(col, row, direction):
    punchers.append(Puncher(col, row, direction))


def draw(surf, camera):
    for puncher in punchers:
        puncher.draw(surf, camera)


def update():
    for puncher in reversed(punchers):
        puncher.update()

        if puncher.done:
            punchers.remove(puncher)
Пример #50
0
from graphics import load_image
import pygame
import time

class Buttom(Sprite):
    '''
    classdocs
    ''' 


    def __init__(self, (x, y), (width, heigth), img_pressed_path, img_release_path, visible = False):
        '''
        Constructor
        '''
        Sprite.__init__(self)
        self.pressed_img = load_image(config.buttoms_png+img_pressed_path, True, (0,0))
        self.pressed_img = pygame.transform.scale(self.pressed_img, (width, heigth))
        self.pressed_rect = self.pressed_img.get_rect() 
        self.release_img = load_image(config.buttoms_png+img_release_path, True, (0,0))
        self.release_img = pygame.transform.scale(self.release_img, (width, heigth))
        self.release_rect = self.release_img.get_rect()
        self.pressed_rect.center = (x, y)
        self.release_rect.center = (x, y)
        self.is_pressed = False
        self.is_over = False
        self.beep = pygame.mixer.Sound('beep1.ogg')

        self.state = self.release_img
        self.state_rect = self.release_rect
        
        self.is_visible = visible
Пример #51
0
clock = pygame.time.Clock()

goal_light_activate = sound.load_numbers("level_start%i", 3)
goal_light_activate.set_volumes(0.14)

hum = sound.load("hum")
MAX_HUM_VOLUME = 1.0
hum.set_volume(0)
hum.play(-1)

music = [sound.load("music%i" % x) for x in range(1, 8)]
for m in music:
    m.set_volume(0)

background = graphics.load_image("background", 1)
player_glow = graphics.load_image("player_gradient", 1)


def draw_background(surf):
    surf.fill((20, 20, 20))
    surf.blit(background, (0, 0))


def screen_update(fps):
    pygame.display.flip()
    main_surf.fill(const.BLACK)
    clock.tick(fps)


def levels_with_number(shared_name, first, last):
Пример #52
0
__author__ = 'sofamaniac'
__copyright__ = 'Copyright 2014, Antoine Grimod'
__license__ = 'Copyright'
__version__ = '0.1'
__maintainer__ = 'Antoine Grimod'
__email__ = '*****@*****.**'
__status__ = 'Production'

import graphics

import os

import globals

#on creer la fenetre
fenetre = graphics.Fenetre("jeu2D", graphics.load_image("img/logo.png"),
                           (400, 400))

#on charge toutes les images dont le jeu aura besoin
list_image = os.listdir("img")

#on creer un dictionnaire qui contiendra le nom de l'image plus l'image chargee
globals.dico_images = {}

for path in list_image:
    globals.dico_images[path[:-4]] = graphics.load_image(
        "img/" + path)  # on retire l'extension dans le dictionnaire

list_music = os.listdir("music")
dico_music = {}
Пример #53
0
 def load_word_in_soup(self):
     for word in self.valid_words_key:
         self.words_img[word] = load_image(config.alphabet_soup+word+PNG_EXT, True)
         self.words_rect[word] = self.words_img[word].get_rect()
Пример #54
0
    def __init__(self, game_opts, *menu_opts):

        ## create a programmer friendly mapping stucture of the menu options
        self.options = [{'label': x[0], 'callable': x[1]} for x in menu_opts]

        ## store the game options
        self.game_opts = game_opts

        # set the default menu dimensions (these dimensions
        # are calculated depending on the font and its size)

        ## menu's width
        self.width = 0

        ## menu's height
        self.height = 0

        # set up the default coordinates of the menu

        ## menu's x coordinate
        self.x = 0

        ## menu's y coordinate
        self.y = 0

        ## the topleft corner of the screen
        self.screen_topleft_offset = (0, 0)

        ## set the default focused option
        self.option = 0

        ## set the default previous focused option
        self.option_previous = self.option

        ## set the default normal color of the menu font
        self.normal_color = pygame.Color('black')

        ## set the default focused color of the menu font
        self.focus_color = pygame.Color('red')

        ## default is to enable support of menu image on focused options
        self.image_enabled = True

        ## default is to enable support mouse on menu
        self.mouse_enabled = True

        ## set mouse focusing at unknown at default
        self.mouse_focus = None
        self._font = None

        ## set a default font and its size (also fix size)
        self.font = pygame.font.Font(None, FONT_SIZE)
        self._fix_size()

        ## set the default sound to play when an option is focused
        self.focus_sound = load_sound(
            constants.FILES['sounds']['menu']['share']['focus'][0])

        ## set the default sound to play when an option is entered
        self.select_sound = load_sound(
            constants.FILES['sounds']['menu']['share']['sel'][0])

        ## set the default graphic to display before the option label
        self.focus_graphic = load_image(
            constants.FILES['graphics']['menu']['share']['focus'][0])[0]
Пример #55
0
    def __init__(self, game_opts):
        # initialize the state
        State.__init__(self, constants.SCENES['menu'])

        ## the game's command line options
        self.game_opts = game_opts

        ## the screen surface
        self.screen = pygame.display.get_surface()

        ## flag to control the settings menu's loop
        self.menu_settings_running = None

        ## flag to control the main menu's loop
        self.menu_main_running = True

        # enable key repeat for the menu
        pygame.key.set_repeat(MENU_KEY_DEL, MENU_KEY_INT)

        ## set the main menu's background
        self.menu_main_bg = graphics.load_image(
            constants.FILES['graphics']['menu']['main']['bg'][0])[0]

        ## set the settings menu's background
        self.menu_settings_bg = graphics.load_image(
            constants.FILES['graphics']['menu']['share']['bg'][0])[0]

        ## set the settings menu's background box
        self.menu_box_bg = graphics.load_image(
            constants.FILES['graphics']['menu']['settings']['box'][0])[0]

        ## set the window frame
        self.window_frame = graphics.load_image(
            constants.FILES['graphics']['menu']['share']['frame'][0])[0]

        ## set the mouse cursor
        self.mouse_cursor = graphics.load_image(
            constants.FILES['graphics']['menu']['share']['cursor'][0])[0]

        ## set the sound when a menu option is entered
        self.select_option_snd = sound_mixer.load_sound(
            constants.FILES['sounds']['menu']['share']['sel'][0])

        ## create the main menu - string, callback function
        self.menu_main = KezMenu(self.game_opts, ['Play', self._play_option],
                                 ['Settings', self._settings_option],
                                 ['Credits', self._credits_option],
                                 ['Quit', self._quit_option])

        # set the position of the main menu
        self.menu_main.set_position(MENU_MAIN_POS_X, MENU_MAIN_POS_Y)

        # set the main menu's font
        self.menu_main.set_font(
            graphics.load_font(constants.FILES['fonts']['menu']['share'][0],
                               MAIN_FONT_SIZE))

        # set the main menu's highlight color
        self.menu_main.set_highlight_color(MAIN_FOCUS_COLOR)

        ## create the settings menu - string, callback function
        self.menu_settings = KezMenu(
            self.game_opts, ['Fullscreen', self._toggle_fullscreen_option],
            ['Sounds', self._toggle_sounds_option],
            ['Music', self._toggle_music_option], ['Back', self._back_option])

        # disable the menu graphic for focused options
        self.menu_settings.toggle_image()

        # set the settings menu's font
        self.menu_settings.set_font(
            graphics.load_font(constants.FILES['fonts']['menu']['share'][0],
                               MENU_FONT_SIZE))

        # set the position of the settings menu
        self.menu_settings.center_at(constants.SCREEN_WIDTH / 2.0,
                                     constants.SCREEN_HEIGHT / 2.0)

        # set the settings menu's highlight color
        self.menu_settings.set_highlight_color(SETTINGS_FOCUS_COLOR)

        ## the animated sprite group
        self.anim_sprites = pygame.sprite.RenderUpdates()

        # create the animated sprites
        sprite_num = len(constants.FILES['graphics']['menu']['share']['anim'])
        sprite_fact = SpriteFactory()
        for i in range(sprite_num):
            # create the "right" type of animated sprite using the factory
            r_sprite = sprite_fact.create_anim_sprite(
                i, constants.FILES['graphics']['menu']['share']['anim'][i],
                ANIM_SPRITE_SPEED)
            self.anim_sprites.add(r_sprite)

        ## create clock and track time
        self.clock = pygame.time.Clock()
Пример #56
0
class Room:
    """the grid where all the tiles on a single screen are placed"""
    WIDTH = const.SCRN_W // TILE_W  # the amount of tiles across the room
    HEIGHT = const.SCRN_H // TILE_H
    PIXEL_W = WIDTH * TILE_W
    PIXEL_H = HEIGHT * TILE_H

    goal_sound = sound.load("goal")
    goal_sound.set_volume(0)
    goal_sound_playing = False

    def __init__(self, name):
        """name is the name of the file in the levels folder"""
        self.grid = [[[] for _ in range(self.HEIGHT)]
                     for _ in range(self.WIDTH)]

        self.player_spawn = PlayerSpawn(0, 0)
        self.player_goal = PlayerGoal(0, 0)
        self.grid[0][0].append(self.player_spawn)
        self.grid[0][0].append(self.player_goal)

        self.unique_flickers = []

        self.text_x = 0
        self.text_y = 0
        self.heart_direction = const.UP

        self.name = name
        self.load()

    def out_of_bounds(self, col, row):
        """returns whether or not a tile is outside of the grid"""
        if 0 <= col < self.WIDTH:
            if 0 <= row < self.HEIGHT:
                return False

        return True

    def clear(self):
        for col in range(self.WIDTH):
            for row in range(self.HEIGHT):
                self.clear_point(col, row)

    def add_tile(self, col, row, tile):
        if not self.out_of_bounds(col, row):
            self.grid[col][row].append(tile)

        else:
            print("add_tile() tried to add a tile out of bounds")

    def clear_point(self, col, row):
        if not self.out_of_bounds(col, row):
            new_tile = []

            # Spawn and goal shouldn't be erasable
            if self.has_tile(PlayerSpawn, col, row):
                spawn = self.get_tile(PlayerSpawn, col, row)
                new_tile.append(spawn)
            if self.has_tile(PlayerGoal, col, row):
                goal = self.get_tile(PlayerGoal, col, row)
                new_tile.append(goal)

            self.grid[col][row] = new_tile

        else:
            print("clear_point() tried to clear a tile out of bounds")

    def add_rect(self, col, row, w, h, constructor):
        """places a rectangle of tiles at the given coordinates

        the tiles changed are relative to the current room,
        not the entire level
        """
        for col_index in range(col, col + w):
            for row_index in range(row, row + h):
                self.add_tile(col_index, row_index, constructor())

    def clear_rect(self, col, row, w, h):
        for col_index in range(col, col + w):
            for row_index in range(row, row + h):
                self.clear_point(col_index, row_index)

    def add_checkpoint(self, col, row, direction):
        self.add_tile(col, row, Checkpoint(direction, col, row))

    def move_player_spawn(self, col, row):
        # Remove old spawn
        old_col = self.player_spawn.col
        old_row = self.player_spawn.row
        if self.player_spawn in self.grid[old_col][old_row]:
            self.grid[old_col][old_row].remove(self.player_spawn)

        # Place new spawn
        self.player_spawn = PlayerSpawn(col, row)
        self.add_tile(col, row, self.player_spawn)

    def move_player_goal(self, col, row):
        # Remove old goal
        old_col = self.player_goal.col
        old_row = self.player_goal.row
        if self.player_goal in self.grid[old_col][old_row]:
            self.grid[old_col][old_row].remove(self.player_goal)

        # Place new goal
        self.player_goal = PlayerGoal(col, row)
        self.add_tile(col, row, self.player_goal)

    def tiles_at(self, col, row):
        """returns the tiles at a given point"""
        if not self.out_of_bounds(col, row):
            return self.grid[col][row]

        return [Void()]

    def has_tile(self, type_, col, row):
        """determines if a certain space contains a tile"""
        if not self.out_of_bounds(col, row):
            for tile in self.tiles_at(col, row):
                if type(tile) == type_:
                    return True
            return False

        return type_ == Void

    def get_tile(self, type_, col, row):
        """gets the first tile with a given type on this space"""
        for tile in self.tiles_at(col, row):
            if type(tile) == type_:
                return tile

        raise ("There is not tile of type %s there!" % str(type_))

    def has_listed_tile(self, types, col, row):
        """determines if a certain space contains any tiles in the list"""
        for type_ in types:
            if self.has_tile(type_, col, row):
                return True

        return False

    def is_empty(self, col, row):
        return not self.tiles_at(col, row)

    def has_solid(self, col, row):
        """returns whether a tile is solid or not"""
        for tile in self.tiles_at(col, row):
            if tile.SOLID:
                return True

        return False

    def _initiate_deathlock_flicker(self):
        for row in range(self.HEIGHT):
            for col in range(self.WIDTH):
                if self.has_tile(Deathlock, col, row):
                    self._initiate_deathlock_flicker_recursion(
                        flicker.FlickerSequence(), col, row)

    def _initiate_deathlock_flicker_recursion(self, flicker_sequence, col,
                                              row):
        tile = self.get_tile(Deathlock, col, row)
        if tile.flicker_initiated:
            return

        tile.flicker_sequence = flicker_sequence
        if self.has_tile(Deathlock, col - 1, row):
            self._initiate_deathlock_flicker_recursion(flicker_sequence,
                                                       col - 1, row)
        if self.has_tile(Deathlock, col + 1, row):
            self._initiate_deathlock_flicker_recursion(flicker_sequence,
                                                       col + 1, row)
        if self.has_tile(Deathlock, col, row - 1):
            self._initiate_deathlock_flicker_recursion(flicker_sequence, col,
                                                       row - 1)
        if self.has_tile(Deathlock, col, row + 1):
            self._initiate_deathlock_flicker_recursion(flicker_sequence, col,
                                                       row + 1)

    def _record_unique_flickers(self):
        self.unique_flickers = [self.player_spawn.flicker_sequence]
        for row in range(self.HEIGHT):
            for col in range(self.WIDTH):
                if self.grid[col][row]:
                    tile = self.grid[col][row][0]
                    if hasattr(tile, "flicker_sequence"):
                        for flicker_sequence in self.unique_flickers:
                            if flicker_sequence.sequence_list is tile.flicker_sequence.sequence_list:
                                break
                        else:
                            self.unique_flickers.append(tile.flicker_sequence)

    def emit(self):
        """Emits PunchZones from all PunchBoxes and CheckpointRays from
        all Checkpoints"""
        for col in range(self.WIDTH):
            for row in range(self.HEIGHT):
                for tile in self.tiles_at(col, row):
                    if type(tile) == PlayerGoal:
                        self.emit_player_goal_zone(col, row)
        for col in range(self.WIDTH):
            for row in range(self.HEIGHT):
                for tile in self.tiles_at(col, row):
                    if type(tile) == Checkpoint:
                        self.emit_checkpoint_ray(col, row, tile)
        for col in range(self.WIDTH):
            for row in range(self.HEIGHT):
                for tile in self.tiles_at(col, row):
                    if type(tile) == PunchBox:
                        self.emit_punch_zone(col, row, tile)

    def unemit(self):
        """Emits PunchZones from all PunchBoxes"""
        for col in range(self.WIDTH):
            for row in range(self.HEIGHT):
                for tile in reversed(self.tiles_at(col, row)):
                    if tile.EMITTED:
                        self.tiles_at(col, row).remove(tile)

    def emit_punch_zone(self, col, row, tile):
        if tile.direction == const.LEFT:
            self.add_tile(col - 1, row, PunchZone(const.LEFT))
        elif tile.direction == const.UP:
            self.add_tile(col, row - 1, PunchZone(const.UP))
        elif tile.direction == const.RIGHT:
            self.add_tile(col + 1, row, PunchZone(const.RIGHT))
        elif tile.direction == const.DOWN:
            self.add_tile(col, row + 1, PunchZone(const.DOWN))

    def emit_checkpoint_ray(self, col, row, tile):
        if tile.direction == const.LEFT:
            ray_col = col
            while not self.stops_checkpoint_ray(ray_col, row):
                self.add_tile(ray_col, row, CheckpointRay(tile, const.HORIZ))
                ray_col -= 1
        elif tile.direction == const.RIGHT:
            ray_col = col
            while not self.stops_checkpoint_ray(ray_col, row):
                self.add_tile(ray_col, row, CheckpointRay(tile, const.HORIZ))
                ray_col += 1
        elif tile.direction == const.UP:
            ray_row = row
            while not self.stops_checkpoint_ray(col, ray_row):
                self.add_tile(col, ray_row, CheckpointRay(tile, const.VERT))
                ray_row -= 1
        elif tile.direction == const.DOWN:
            ray_row = row
            while not self.stops_checkpoint_ray(col, ray_row):
                self.add_tile(col, ray_row, CheckpointRay(tile, const.VERT))
                ray_row += 1

    def emit_player_goal_zone(self, col, row):
        # Place goal zones in a 3x3 area around the goal tile
        for x in range(col - 1, col + 2):
            for y in range(row - 1, row + 2):
                if not self.out_of_bounds(x, y):
                    self.add_tile(x, y, PlayerGoalZone())

    def stops_checkpoint_ray(self, col, row):
        if self.has_solid(col, row):
            return True
        if self.has_tile(Deathlock, col, row):
            return True
        if self.has_tile(Void, col, row):
            return True
        return False

    def collide_vert(self, x, y1, y2, collide_deathlock):
        col = col_at(x)
        start_row = row_at(y1)
        end_row = row_at(y2)
        for row in range(start_row, end_row + 1):
            if collide_deathlock and self.has_tile(Deathlock, col, row):
                return True
            if self.has_solid(col, row):
                return True

        return False

    def collide_horiz(self, x1, x2, y, collide_deathlock):
        start_col = col_at(x1)
        end_col = col_at(x2)
        row = row_at(y)
        for col in range(start_col, end_col + 1):
            if collide_deathlock and self.has_tile(Deathlock, col, row):
                return True
            if self.has_solid(col, row):
                return True

        return False

    def _shift_location_tiles(self, col_change, row_change):
        """Change the position of all things that store their own position.

        Currently, that would only be checkpoints and spawns."""
        self.player_spawn.col += col_change
        self.player_spawn.row += row_change
        self.player_goal.col += col_change
        self.player_goal.row += row_change
        for col in range(0, self.WIDTH):
            for row in range(0, self.HEIGHT):
                for tile in self.grid[col][row]:
                    if type(tile) == Checkpoint:
                        tile.col += col_change
                        tile.row += row_change

    # Note: these shift functions currently don't erase the very last row/col
    # so it just becomes a "copy".  This is fine for my purposes since all my
    # levels never directly touch edge.
    def shift_left(self):
        for col in range(0, self.WIDTH - 1):
            for row in range(0, self.HEIGHT):
                self.grid[col][row] = self.grid[col + 1][row]
        self._shift_location_tiles(-1, 0)

    def shift_right(self):
        for col in range(self.WIDTH - 1, 0, -1):
            for row in range(0, self.HEIGHT):
                self.grid[col][row] = self.grid[col - 1][row]
        self._shift_location_tiles(1, 0)

    def shift_up(self):
        for row in range(0, self.HEIGHT - 1):
            for col in range(0, self.WIDTH):
                self.grid[col][row] = self.grid[col][row + 1]
        self._shift_location_tiles(0, -1)

    def shift_down(self):
        for row in range(self.HEIGHT - 1, 0, -1):
            for col in range(0, self.WIDTH):
                self.grid[col][row] = self.grid[col][row - 1]
        self._shift_location_tiles(0, 1)

    def draw_silhouette(self, surf):
        for col in range(self.WIDTH):
            for row in range(self.HEIGHT):
                x = col * TILE_W
                y = row * TILE_H
                rect = (x, y, TILE_W, TILE_H)
                if self.has_solid(col, row):
                    pygame.draw.rect(surf, const.BLACK, rect)

    def draw_tile_at(self,
                     surf,
                     camera,
                     col,
                     row,
                     player_dead=False,
                     original_spawn=False):
        x = col * TILE_W - int(camera.x)
        y = row * TILE_H - int(camera.y)
        rect = (x, y, TILE_W, TILE_H)

        if self.has_tile(Wall, col, row):
            pygame.draw.rect(surf, const.BLACK, rect)

        elif self.has_tile(PlayerSpawn, col, row):
            if original_spawn:
                color = (81, 255, 113)
            else:
                color = (71, 158, 71)
            pygame.draw.rect(surf, color, rect)

        elif self.has_tile(Deathlock, col, row):
            if player_dead:
                color = (88, 91, 173)
            else:
                color = (109, 112, 255)
            pygame.draw.rect(surf, color, rect)

        elif self.has_tile(PunchBox, col, row):
            punch_box = self.get_tile(PunchBox, col, row)
            if punch_box.direction == const.LEFT:
                surf.blit(punch_box_left, (x, y))
            elif punch_box.direction == const.UP:
                surf.blit(punch_box_up, (x, y))
            elif punch_box.direction == const.RIGHT:
                surf.blit(punch_box_right, (x, y))
            elif punch_box.direction == const.DOWN:
                surf.blit(punch_box_down, (x, y))

        elif self.has_tile(Checkpoint, col, row):
            checkpoint = self.get_tile(Checkpoint, col, row)
            self.draw_checkpoint_and_ray(surf, checkpoint)

        elif self.has_tile(PlayerGoalZone, col, row):
            pygame.draw.rect(surf, (250, 250, 250), rect)

    def draw_deathlock(self, surf, camera, player_dead):
        for col in range(self.WIDTH):
            for row in range(self.HEIGHT):
                if self.has_tile(Deathlock, col, row):
                    x = col * TILE_W - int(camera.x)
                    y = row * TILE_H - int(camera.y)
                    rect = (x, y, TILE_W, TILE_H)

                    if player_dead:
                        color = (88, 91, 173)
                    else:
                        color = (109, 112, 255)
                    pygame.draw.rect(surf, color, rect)

    def draw_flicker_glow(self, surf, frame):
        for row in range(self.HEIGHT):
            for col in range(self.WIDTH):
                if self._flicker_bright_enough_for_gradient(col, row, frame):
                    self.draw_glow_at(surf, col, row, frame)

    def _flicker_bright_enough_for_gradient(self, col, row, frame):
        if self.grid[col][row]:
            tile = self.grid[col][row][0]
            is_ray = type(tile) is CheckpointRay
            if hasattr(tile, "flicker_sequence") or is_ray:
                if is_ray:
                    brightness = tile.checkpoint.flicker_sequence.brightness(
                        frame)
                else:
                    brightness = tile.flicker_sequence.brightness(frame)
                if brightness >= flicker.BRIGHT:
                    return True

        return False

    def _stops_flicker_gradient(self, type_, col, row, frame):
        if self.out_of_bounds(col, row):
            return True

        if self.grid[col][row]:
            if type(self.grid[col][row][0]) is type_:
                return self._flicker_bright_enough_for_gradient(
                    col, row, frame)

        return False

    shade_soft = pygame.Surface((TILE_W, TILE_H))
    shade_soft.fill(flicker.shade_color[flicker.SOFT])
    shade_medium = pygame.Surface((TILE_W, TILE_H))
    shade_medium.fill(flicker.shade_color[flicker.MEDIUM])
    shade_bright = pygame.Surface((TILE_W, TILE_H))
    shade_bright.fill(flicker.shade_color[flicker.BRIGHT])
    checkpoint_shade_soft = graphics.load_image("checkpoint_shade_soft", 2)
    checkpoint_shade_medium = graphics.load_image("checkpoint_shade_medium", 2)
    checkpoint_shade_bright = graphics.load_image("checkpoint_shade_bright", 2)

    def draw_flicker_tiles(self, surf, camera, frame):
        # Draw all checkpoints first, so that the rays can be shaded later
        for row in range(self.HEIGHT):
            for col in range(self.WIDTH):
                if self.grid[col][row]:
                    tile = self.grid[col][row][0]
                    if type(tile) is Checkpoint:
                        if tile.flicker_sequence.brightness(
                                frame) > flicker.NONE:
                            self.draw_tile_at(surf, camera, col, row)

        # Draw other tiles and shade them all
        for row in range(self.HEIGHT):
            for col in range(self.WIDTH):
                if self.grid[col][row]:
                    tile = self.grid[col][row][0]
                    is_ray = type(tile) is CheckpointRay
                    if hasattr(tile, "flicker_sequence") or is_ray:
                        if is_ray:
                            brightness = tile.checkpoint.flicker_sequence.brightness(
                                frame)
                        else:
                            brightness = tile.flicker_sequence.brightness(
                                frame)

                        if brightness != flicker.NONE and not type(
                                tile) is Checkpoint and not is_ray:
                            self.draw_tile_at(surf, camera, col, row)
                        if brightness == flicker.SOFT:
                            shade = self.shade_soft
                        elif brightness == flicker.MEDIUM:
                            shade = self.shade_medium
                        elif brightness == flicker.BRIGHT:
                            shade = self.shade_bright
                        else:  # Skip FULL brightness, since no shade is drawn
                            continue

                        if is_ray:
                            if tile.orientation == const.HORIZ:
                                pos = (x_of(col), y_of(row) + TILE_H // 3)
                                rect = (0, 0, TILE_W, TILE_H // 3 + 2)
                            else:
                                pos = (x_of(col) + TILE_W // 3, y_of(row))
                                rect = (0, 0, TILE_W // 3 + 2, TILE_H)
                            surf.blit(shade,
                                      pos,
                                      rect,
                                      special_flags=pygame.BLEND_MULT)
                        else:
                            if type(tile) is Checkpoint:
                                if brightness == flicker.SOFT:
                                    shade = self.checkpoint_shade_soft
                                elif brightness == flicker.MEDIUM:
                                    shade = self.checkpoint_shade_medium
                                elif brightness == flicker.BRIGHT:
                                    shade = self.checkpoint_shade_bright
                            pos = (x_of(col), y_of(row))
                            surf.blit(shade,
                                      pos,
                                      special_flags=pygame.BLEND_MULT)

    glow_surf = pygame.Surface((const.SCRN_W, const.SCRN_H))

    def draw_glow(self, surf):
        self.glow_surf.fill(const.BLACK)
        for row in range(self.HEIGHT):
            for col in range(self.WIDTH):
                self.draw_glow_at(self.glow_surf, col, row)
        surf.blit(self.glow_surf, (0, 0), special_flags=pygame.BLEND_ADD)

    def draw_glow_at(self, surf, col, row, flicker_frame=-1):
        center_x = center_x_of(col)
        center_y = center_y_of(row)

        if self.has_tile(PunchBox, col, row):
            draw_glow_centered(surf, punch_box_glow, center_x, center_y)
            if flicker_frame == -1:
                self._draw_gradient_efficient(surf, PunchBox,
                                              punch_box_gradient, col, row)
            else:
                self._draw_flicker_gradient_efficient(surf, PunchBox,
                                                      punch_box_gradient, col,
                                                      row, flicker_frame)
        elif self.has_tile(Deathlock, col, row):
            draw_glow_centered(surf, deathlock_glow, center_x, center_y)
            if flicker_frame == -1:
                self._draw_gradient_efficient(surf, Deathlock,
                                              deathlock_gradient, col, row)
            else:
                self._draw_flicker_gradient_efficient(surf, Deathlock,
                                                      deathlock_gradient, col,
                                                      row, flicker_frame)

        elif self.has_tile(Checkpoint, col, row):
            draw_glow_centered(surf, checkpoint_glow, center_x, center_y)
            if flicker_frame == -1:
                self._draw_gradient_efficient(surf, Checkpoint,
                                              checkpoint_gradient, col, row)
            else:
                self._draw_flicker_gradient_efficient(surf, Checkpoint,
                                                      checkpoint_gradient, col,
                                                      row, flicker_frame)

        elif self.has_tile(CheckpointRay, col, row):
            tile = self.get_tile(CheckpointRay, col, row)
            if tile.orientation == const.HORIZ:
                draw_glow_centered(surf, checkpoint_ray_horiz_glow, center_x,
                                   center_y)
                draw_glow_centered(surf, checkpoint_ray_horiz_gradient,
                                   center_x, center_y)

            elif tile.orientation == const.VERT:
                draw_glow_centered(surf, checkpoint_ray_vert_glow, center_x,
                                   center_y)
                draw_glow_centered(surf, checkpoint_ray_vert_gradient,
                                   center_x, center_y)

        elif self.has_tile(PlayerSpawn, col, row):
            draw_glow_centered(surf, player_spawn_glow, center_x, center_y)
            draw_glow_centered(surf, player_spawn_gradient, center_x, center_y)

    def _draw_gradient_efficient(self, surf, type_, gradient, col, row):
        gradient_width = gradient.get_width()
        gradient_height = gradient.get_height()
        x_to_center = gradient_width // 2 - TILE_W // 2
        y_to_center = gradient_height // 2 - TILE_H // 2
        x_remainder = gradient_width - x_to_center
        y_remainder = gradient_height - y_to_center

        if self.has_tile(type_, col - 1, row):
            x = x_of(col)
            slice_x = x_to_center
            slice_width = x_remainder
        else:
            x = x_of(col) - x_to_center
            slice_x = 0
            slice_width = gradient_width
        if self.has_tile(type_, col + 1, row):
            slice_width -= x_to_center

        if self.has_tile(type_, col, row - 1):
            y = y_of(row)
            slice_y = y_to_center
            slice_height = y_remainder
        else:
            y = y_of(row) - y_to_center
            slice_y = 0
            slice_height = gradient_height
        if self.has_tile(type_, col, row + 1):
            slice_height -= y_to_center

        rect = (slice_x, slice_y, slice_width, slice_height)
        surf.blit(gradient, (x, y), rect, special_flags=pygame.BLEND_MAX)

    MAX_SEARCH_PUNCH_BOX = (punch_box_gradient.get_width() // TILE_W -
                            1) // 2 + 1
    MAX_SEARCH_CHECKPOINT = (checkpoint_gradient.get_width() // TILE_W -
                             1) // 2 + 1
    MAX_SEARCH_DEATHLOCK = (deathlock_gradient.get_width() // TILE_W -
                            1) // 2 + 1

    def _draw_flicker_gradient_efficient(self, surf, type_, gradient, col, row,
                                         frame):
        if type_ is PunchBox:
            max_search = self.MAX_SEARCH_PUNCH_BOX
        elif type_ is Checkpoint:
            max_search = self.MAX_SEARCH_CHECKPOINT
        else:
            max_search = self.MAX_SEARCH_DEATHLOCK

        x_to_center = gradient.get_width() // 2 - TILE_W // 2
        y_to_center = gradient.get_height() // 2 - TILE_H // 2

        space_left = 0
        for c in range(1, max_search + 1):
            if self._stops_flicker_gradient(type_, col - c, row, frame):
                break
            space_left += 1

        space_right = 0
        for c in range(1, max_search + 1):
            if self._stops_flicker_gradient(type_, col + c, row, frame):
                break
            space_right += 1

        space_up = 0
        for r in range(1, max_search + 1):
            if self._stops_flicker_gradient(type_, col, row - r, frame):
                break
            space_up += 1

        space_down = 0
        for r in range(1, max_search + 1):
            if self._stops_flicker_gradient(type_, col, row + r, frame):
                break
            space_down += 1

        x = x_of(col) - space_left * TILE_W
        y = y_of(row) - space_up * TILE_H
        slice_x = x_to_center - space_left * TILE_W
        slice_y = y_to_center - space_up * TILE_H
        slice_width = (space_left + space_right + 1) * TILE_W
        slice_height = (space_up + space_down + 1) * TILE_H
        rect = (slice_x, slice_y, slice_width, slice_height)

        surf.blit(gradient, (x, y), rect, special_flags=pygame.BLEND_MAX)

    def draw_goal_glow(self, surf):
        glow_surf = pygame.Surface(surf.get_size())
        for col in range(self.player_goal.col - 1, self.player_goal.col + 2):
            for row in range(self.player_goal.row - 1,
                             self.player_goal.row + 2):
                center_x = center_x_of(col)
                center_y = center_y_of(row)

                gradient_x = int(center_x -
                                 (player_goal_gradient.get_width() / 2))
                gradient_y = int(center_y -
                                 (player_goal_gradient.get_height() / 2))
                glow_surf.blit(player_goal_gradient, (gradient_x, gradient_y),
                               special_flags=pygame.BLEND_MAX)
        surf.blit(glow_surf, (0, 0), special_flags=pygame.BLEND_ADD)

    def draw_static(self, surf, camera):
        """draws the entire stage"""
        self.draw_glow(surf)
        self.draw_tiles(surf, camera)
        self.draw_goal_glow(surf)

    def draw_tiles(self, surf, camera):
        for row in range(self.HEIGHT):
            for col in range(self.WIDTH):
                if self.grid[col][row] and self.grid[col][row][
                        0].DRAWN_STATICALLY:
                    self.draw_tile_at(surf, camera, col, row)

    def draw_dynamic(self, surf, camera, player_dead, original_spawn):
        for row in range(self.HEIGHT):
            for col in range(self.WIDTH):
                if self.grid[col][
                        row] and not self.grid[col][row][0].DRAWN_STATICALLY:
                    self.draw_tile_at(surf, camera, col, row, player_dead,
                                      original_spawn)

    def draw_checkpoint_and_ray(self, surf, checkpoint):
        col = checkpoint.col
        row = checkpoint.row

        x = x_of(col)
        y = y_of(row)
        if checkpoint.active:
            surf.blit(checkpoint_activated, (x, y))
        else:
            surf.blit(checkpoint_deactivated, (x, y))

        if checkpoint.direction == const.LEFT:
            stop_col = col - 1
            while not self.stops_checkpoint_ray(stop_col, row):
                stop_col -= 1
            stop_col += 1

            if stop_col == col:
                return

            x = x_of(stop_col)
            y += TILE_H // 3
            width = (col - stop_col) * TILE_W
            height = TILE_H // 3 + 2

        elif checkpoint.direction == const.RIGHT:
            stop_col = col + 1
            while not self.stops_checkpoint_ray(stop_col, row):
                stop_col += 1
            stop_col -= 1

            if stop_col == col:
                return

            x += TILE_W
            y += TILE_H // 3
            width = (stop_col - col) * TILE_W
            height = TILE_H // 3 + 2

        elif checkpoint.direction == const.UP:
            stop_row = row - 1
            while not self.stops_checkpoint_ray(col, stop_row):
                stop_row -= 1
            stop_row += 1

            if stop_row == row:
                return

            x += TILE_W // 3
            y = y_of(stop_row)
            width = TILE_W // 3 + 2
            height = (row - stop_row) * TILE_H

        else:
            stop_row = row + 1
            while not self.stops_checkpoint_ray(col, stop_row):
                stop_row += 1
            stop_row -= 1

            if stop_row == row:
                return

            x += TILE_W // 3
            y += TILE_H
            width = TILE_W // 3 + 2
            height = (stop_row - row) * TILE_H

        if checkpoint.active:
            color = (81, 255, 113)
        else:
            color = (71, 158, 71)

        pygame.draw.rect(surf, color, (x, y, width, height))

    def update_goal_sound(self, player, is_transitioning):
        if is_transitioning:
            self.goal_sound_playing = False
            self.goal_sound.stop()
            return

        distance_x = player.center_x - center_x_of(self.player_goal.col)
        distance_y = player.center_y - center_y_of(self.player_goal.row)
        distance = math.sqrt(distance_x**2 + distance_y**2)

        if distance < 300.0:
            if distance == 20:
                return

            if distance < 75:
                # Reciprocal rises fast as distance gets closer to 20
                mult = 2 / (distance - 20)
            else:
                # A line from where the reciprocal ends at x=75 to 0 at x=200
                connection = 2 / (75 - 20)
                m = -connection / (300 - 75)
                b = -m * 300
                mult = m * distance + b
            volume = 0.97 * mult
            self.goal_sound.set_volume(volume)

            if not self.goal_sound_playing:
                self.goal_sound_playing = True
                self.goal_sound.play(-1)

        elif self.goal_sound_playing:
            self.goal_sound_playing = False
            self.goal_sound.stop()

    def place_tile_from_id(self, col, row, tile_id):
        """These ids are only used for writing and reading levels."""
        if tile_id == 1:
            tile = Wall()
        elif tile_id == 2:
            tile = Deathlock()
        elif tile_id == 3:
            tile = PunchBox(const.LEFT)
        elif tile_id == 4:
            tile = PunchBox(const.UP)
        elif tile_id == 5:
            tile = PunchBox(const.RIGHT)
        elif tile_id == 6:
            tile = PunchBox(const.DOWN)
        elif tile_id == 7:
            tile = Checkpoint(const.LEFT, col, row)
        elif tile_id == 8:
            tile = Checkpoint(const.UP, col, row)
        elif tile_id == 9:
            tile = Checkpoint(const.RIGHT, col, row)
        elif tile_id == 10:
            tile = Checkpoint(const.DOWN, col, row)
        elif tile_id == 11:
            self.move_player_spawn(col, row)
            return
        elif tile_id == 12:
            self.move_player_goal(col, row)
            return
        else:
            return

        self.add_tile(col, row, tile)

    def save(self):
        strings = [
            "%i %i %i" % (self.text_x, self.text_y, self.heart_direction)
        ]
        for row in range(self.HEIGHT):
            row_of_ids = []
            for col in range(self.WIDTH):
                tiles = self.tiles_at(col, row)
                id = id_of(tiles)
                row_of_ids.append(str(id))
            strings.append(" ".join(row_of_ids))
        data = "\n".join(strings)

        with open(level_path(self.name), "w") as file:
            file.write(data)

    def load(self):
        self.clear()

        path = level_path(self.name)
        if not os.path.exists(path):
            return

        with open(path, "r") as file:
            data = file.read()

        lines = data.split("\n")
        text_position = lines[0].split(" ")
        self.text_x = int(text_position[0])
        self.text_y = int(text_position[1])
        self.heart_direction = int(text_position[2])

        level_rows = lines[1:]

        for row_index, row in enumerate(level_rows):
            for col_index, tile in enumerate(row.split(" ")):
                self.place_tile_from_id(col_index, row_index, int(tile))

        self._initiate_deathlock_flicker()
        self._record_unique_flickers()
        self.emit()