def __init__(self,level_file_name):
        self.level_name = level_file_name
        self.level = eval(level_file_name)()
        self.letter_map = self.level.letter_map
        self.tile_map = TileMap(self.letter_map)

        self.level_menu = LevelMenu()
        self.tower_list = [] #List of all towers currently on the screen
    def __init__(self,level_file_name):
        pygame.mixer.init()
        self.player = PlayerModel(150, 5)

        self.level_name = level_file_name
        self.level = eval(level_file_name)()
        self.letter_map = self.level.letter_map
        self.tile_map = TileMap(self.letter_map)

        self.enemy_waves = self.level.enemy_waves
        self.current_enemy_wave_number = 0
        self.total_enemy_waves = len(self.enemy_waves)
        self.current_enemy_wave = EnemyWave(self.tile_map,empty_wave)

        self.display_level = self
        self.level_menu = LevelMenu(self.display_level)
        self.tower_list = [] #List of all towers currently on the screen

        self.level_finished = False
        self.game_over = None #Game over screen

        self.placement_phase = True
        self.update_sound()
class DisplayLevel:

    def __init__(self,level_file_name):
        self.level_name = level_file_name
        self.level = eval(level_file_name)()
        self.letter_map = self.level.letter_map
        self.tile_map = TileMap(self.letter_map)

        self.level_menu = LevelMenu()
        self.tower_list = [] #List of all towers currently on the screen

    def display_towers(self):
        for tower in self.tower_list:
            tower.display_tower()

    def display_tile_map(self):
        self.tile_map.display_tile_map()

    def display_level_menu(self):
        self.level_menu.display_start_menu()

    def update(self):

        ##FOR TESTING:
        #Circles to emulate enemies on the board - solely for visual testing purposes
        #If the circles are within the towers' attack_radius, then the towers will shoot at them
        pygame.draw.circle(pygame.display.get_surface(), (145,255,255), (186,245), 5)
        pygame.draw.circle(pygame.display.get_surface(), (145,255,255), (184, 27), 5)
        #---------------------------------------------

        #Tower shooting loop
        for tower in self.tower_list:
            if tower.placed == True:
                tower.attack_enemy()

        for event in pygame.event.get(MOUSEBUTTONUP):
            mouse_pos = pygame.mouse.get_pos()

            #If mouse_pos is within the tile map
            if ((mouse_pos[0] > 0 and mouse_pos[0] < self.tile_map.map_size) and (mouse_pos[1] > 0 and mouse_pos[1] < self.tile_map.map_size)): #if mouse is within the tile_map bounds
                self.tile_map_click(mouse_pos)

            #If mouse pos is within the level menu
            elif ((mouse_pos[0] > self.tile_map.map_size and mouse_pos[0] < self.tile_map.window.get_width()) and (mouse_pos[1] > 0 and mouse_pos[1] < self.tile_map.window.get_height())):

                if not (self.is_tower_being_placed()): #Only spawn a new tower if currently a tower is NOT being placed
                    #The level_menu.clicked method returns none if player did not click on a button (e.g. whitespace)
                    #This method is also passed the tile_size, so it can adjust the size of the tower according to the tile
                    #Also passed is the map_size, so the tower knows the boundary of the tile_map
                    newTower = self.level_menu.clicked(mouse_pos, self.tile_map.tile_size, self.tile_map.map_size)
                else:
                    newTower = None

                if (isinstance(newTower, BaseTower)):
                    self.tower_list.append(newTower)
                else: #Player clicked on level menu whitespace and NOT button
                      #So if they are in the process of placing a tower, remove that tower
                    for tower in self.tower_list:
                        if tower.placed == False:
                            self.tower_list.remove(tower)

    #Player clicked on tile map
    def tile_map_click(self, mouse_pos):
        selected_tile = self.tile_map.clicked(mouse_pos) #Gets the tile that has been clicked on

        for tower in self.tower_list:
            if tower.placed == False: #If a tower has not been placed yet
                selected_tile.place_tower(tower) #Assign the tower variable of the selected_tile
                break

    #Returns true if the player is in the process of placing a tower
    def is_tower_being_placed(self):
        for tower in self.tower_list:
            if (tower.placed == False):
                return True
class DisplayLevel:

    def __init__(self,level_file_name):
        pygame.mixer.init()
        self.player = PlayerModel(150, 5)

        self.level_name = level_file_name
        self.level = eval(level_file_name)()
        self.letter_map = self.level.letter_map
        self.tile_map = TileMap(self.letter_map)

        self.enemy_waves = self.level.enemy_waves
        self.current_enemy_wave_number = 0
        self.total_enemy_waves = len(self.enemy_waves)
        self.current_enemy_wave = EnemyWave(self.tile_map,empty_wave)

        self.display_level = self
        self.level_menu = LevelMenu(self.display_level)
        self.tower_list = [] #List of all towers currently on the screen

        self.level_finished = False
        self.game_over = None #Game over screen

        self.placement_phase = True
        self.update_sound()

    def update_sound(self):
        if (pygame.mixer.music.get_busy()):
            pygame.mixer.music.stop()

        if (self.placement_phase == True):
            #Royalty-free music taken from incompetech.com
            #http://incompetech.com/music/royalty-free/index.html?isrc=USUAN1400005
            pygame.mixer.music.load('Library\Assets\Music\Pippin_the_Hunchback.mp3')
            pygame.mixer.music.play()
        else:
            #Royalty-free music taken from bensound.com
            #http://www.bensound.com/royalty-free-music/track/epic
            pygame.mixer.music.load('Library\Assets\Music\Epic.mp3')
            pygame.mixer.music.set_volume(0.5)
            pygame.mixer.music.play()


    def get_next_wave(self):
        if (self.placement_phase == True):
            self.placement_phase = False
            self.update_sound()

        if(self.current_enemy_wave_number == self.total_enemy_waves):
            self.check_level_finished()
            return
        if(self.current_enemy_wave.dead_enemies == self.current_enemy_wave.num_enemies):
            self.current_enemy_wave = EnemyWave(self.tile_map, self.enemy_waves[self.current_enemy_wave_number])
            self.current_enemy_wave_number += 1
            self.update_tower_enemies()

    def update_tower_enemies(self):
        for tower in self.tower_list:
            tower.get_new_wave(self.current_enemy_wave.enemy_list)

    def display_towers(self):
        show_radii = False

        for tower in self.tower_list:
            tower.display_tower()
            if tower.placed == False:
                show_radii = True

        if show_radii:
            for tower in self.tower_list:
                tower.display_radius()

    def display_tile_map(self):
        self.tile_map.display_tile_map()

    def display_level_menu(self):
        self.level_menu.display_start_menu()

    def display_enemies(self):
        self.current_enemy_wave.tick()

    def check_collide(self):
        for tower in self.tower_list:
            for e in self.current_enemy_wave:
                    for b in tower.bullet_list:
                        if (pygame.sprite.collide_rect(e, b)):
                            e.damage_enemy(tower.bullet_damage)
                            tower.bullet_list.remove(b)
                            #Royalty-Free sound effect from Adobe
                            #http://offers.adobe.com/en/na/audition/offers/audition_dlc.html
                            explodeSound = pygame.mixer.Sound('Library\Assets\Music\Explosion_C-4_01.wav')
                            explodeSound.set_volume(0.4)
                            explodeSound.play()

    def check_level_finished(self):
        if(self.current_enemy_wave.dead_enemies == self.current_enemy_wave.num_enemies):
            self.level_finished = True

    def update(self):
        self.check_collide()

        if (self.current_enemy_wave.dead_enemies == self.current_enemy_wave.num_enemies
            and self.placement_phase == False):
            self.placement_phase = True
            self.update_sound()

        #Update live counter by subtracting each enemy that reached the end
        self.player.lives -= self.current_enemy_wave.reached_end
        self.current_enemy_wave.reached_end = 0

        self.player.wallet += self.current_enemy_wave.dead_cash_enemies * self.current_enemy_wave.cash_yield
        self.current_enemy_wave.dead_cash_enemies = 0

        if (self.player.lives < 1):
            # So lives don't become negative when game over screen is displayed
            if (self.player.lives < 0):
                self.player.lives = 0
            if (isinstance(self.game_over, GameOverScreen)):
                self.game_over.display_self()
                if (self.game_over.timer > 170):
                    #Exit game
                    #Make a method for proper quitting
                    pygame.quit()
                    sys.exit()
            else:
                self.game_over = GameOverScreen()

        #Tower shooting loop
        for tower in self.tower_list:
            if tower.placed == True:
                tower.attack_enemy()

        for event in pygame.event.get(MOUSEBUTTONUP):
            mouse_pos = pygame.mouse.get_pos()

            #If mouse position is within the tile map
            if ((mouse_pos[0] > 0 and mouse_pos[0] < self.tile_map.map_size)):
                self.tile_map_click(mouse_pos)

            #If mouse pos is within the level menu
            elif ((mouse_pos[0] > self.tile_map.map_size and mouse_pos[0] < self.tile_map.window.get_width())):
                if not (self.is_tower_being_placed()):
                    #The level_menu.clicked method returns none if player did not click on a button (e.g. whitespace)
                    clickedObj = self.level_menu.clicked()
                else:
                    clickedObj = None

                #If the player clicked on the BaseTower button AND can afford a BaseTower
                if (isinstance(clickedObj, BaseTower) and self.player.wallet >= clickedObj.cost):
                    self.tower_list.append(clickedObj)
                else: #Player clicked on level menu whitespace and NOT button
                    self.stop_tower_placement()

    #Player clicked on tile map
    def tile_map_click(self, mouse_pos):
        selected_tile = self.tile_map.clicked(mouse_pos) #Gets the tile that has been clicked on

        if (selected_tile.type == "Path"):
            self.stop_tower_placement()
            return None

        for tower in self.tower_list:
            if (tower.placed == False): #If a tower has not been placed yet
                if (selected_tile.tower == None):
                    self.player.wallet -= tower.cost
                selected_tile.place_tower(tower) #Assign the tower variable of the selected_tile
                break

    #Returns true if the player is in the process of placing a tower
    def is_tower_being_placed(self):
        for tower in self.tower_list:
            if (tower.placed == False):
                return True

    #If player is in the process of placing a tower, and decides against it, delete that tower
    def stop_tower_placement(self):
        for tower in self.tower_list:
            if tower.placed == False:
                self.tower_list.remove(tower)