SET_GAME_STATE   = pygame.USEREVENT + 4 COLOUR_BLUE  = (   0,    0, 255)
COLOUR_RED   = ( 255,    0,   0)
COLOUR_GREEN = (   0,  255,   0)
COLOUR_WHITE = ( 255,  255, 255)
COLOUR_GREY  = ( 128,  128, 128)
COLOUR_BLACK = (   0,    0,   0)
COLOUR_YELLOW = (255,223,0)
COLOUR_LEAVES_OF_AUTUMN = ( 101,  91,  19 )
COLOUR_628450           = (  98, 132,  80 )
COLOUR_FUTURE           = (  96, 150, 107 )
COLOUR_AMLSERVINYOUR    = ( 132, 172, 149 )
COLOUR_ASTERIX          = ( 248, 239, 214 )
COLOUR_IRISH_GREEN  = (   0, 154,  73 )
COLOUR_IRISH_ORANGE = ( 255, 121,   0 ) def render_title(text, colour = colours.COLOUR_AMLSERVINYOUR):
def render_menu_item(text, colour = colours.COLOUR_AMLSERVINYOUR):
def render_huge_text(text, colour = colours.COLOUR_AMLSERVINYOUR):
def render_large_text(text, colour = colours.COLOUR_AMLSERVINYOUR):
def render_text(text, colour = colours.COLOUR_AMLSERVINYOUR ):
def render_small_text(text, colour = colours.COLOUR_AMLSERVINYOUR ):
def render_cursive_small(text, colour = colours.COLOUR_AMLSERVINYOUR ):
def render_text_wrapped(surface, text, rect, color = colours.COLOUR_AMLSERVINYOUR, aa=True): class FadeIn:
class FadeOut:
class MoveValue:
class Delay:
class FrameAnimate:
class ChooseRandom:
class MovePosition:
class DelayCallBack:
class Timeout:
class ParallelAnimation:
class SequenceAnimation:
    def __init__(self, target, start=0, end=255, time=3000):
    def finished(self):
    def animate(self, delta_t):
    def skip(self):
    def __init__(self, target, start=255, end=0, time=3000):
    def finished(self):
    def animate(self, delta_t):
    def skip(self):
    def __init__(self, target, start, end, args=[],  time=200):
    def finished(self):
    def animate(self, delta_t):
    def skip(self):
    def __init__(self, time=150):
    def finished(self):
    def animate(self, delta_t):
    def skip(self):
    def __init__(self, target, frames):
    def compute_trigger_time(self, normal, fuzz):
    def animate(self, delta_t):
    def reset(self):
    def __init__(self, target, options, time=150, fuzz=0):
    def compute_trigger_time(self, normal, fuzz):
    def animate(self, delta_t):
    def __init__(self, start, finish, target, time=150):
    def animate(self, delta_t):
    def finished(self):
    def skip(self):
    def __init__(self, target, args=[], time=150):
    def animate(self, delta_t):
    def finished(self):
    def skip(self):
    def __init__(self, target, args=[], time=150):
    def animate(self, delta_t):
    def __init__(self, animations = None):
    def animate(self, delta_t):
    def add_animation(self, animation):
    def finished(self):
    def skip(self):
    def __init__(self, animations = None):
    def animate(self, delta_t):
    def finished(self):
    def add_animation(self, animation):
    def skip_current(self):
    def skip(self): class MusicManager:

    class __MusicManager:
        def __init__(self, settings):
            self.music = {}
            self.now_playing = ""

            if settings == None:
                self.settings = {
                    "sound" :
                    {
                        "sound_volume":0.3,
                        "sound_enabled" : True
                    }
                }
            else:
                self.settings = settings

            self.track_no     = 0
            self.cur_playlist = []
            self.default_volume = self.settings['sound']['music_volume']
            self.volume         = self.default_volume
            self.enabled        = self.settings['sound']['music_enabled']

            pygame.mixer.init()
            music_files = os.listdir(MUSIC_DIR)
            for music_name in music_files:
                self.music[os.path.splitext(music_name)[0]] = music_name

            self.soundtrack = {
                "main_menu" : [ "long_road" ],
                # "in_game"   : [ "preliator", "killers", "ff8", "skyrim" ]
            }

        def play_song(self, song_name, volume = -1, loops=1):
            if not self.enabled:
                return

            if volume < 0:
                pygame.mixer.music.set_volume(self.volume)
            else:
                pygame.mixer.music.set_volume(volume)

            if song_name not in self.music:
                print("Failed to load song \"{}\"".format(song_name))
                pygame.mixer.music.stop()
                return

            if self.now_playing != song_name or not pygame.mixer.music.get_busy():
                pygame.mixer.music.load(os.path.join(MUSIC_DIR, self.music[song_name]))
                pygame.mixer.music.play(loops)
                self.now_playing = song_name

        def load_playlist(self, playlist):
            if playlist in self.soundtrack:
                self.cur_playlist = self.soundtrack[playlist]
            else:
                self.cur_playlist = []
            self.track_no = -1

        def get_music_volume(self):
            return pygame.mixer.music.get_volume()

        def set_music_volume(self, volume):
            self.volume = volume
            pygame.mixer.music.set_volume(volume)

        def set_default_music_volume(self, volume):
            self.default_volume = volume

        def restore_music_volume(self):
            self.set_music_volume(self.default_volume)

        def set_enabled(self, enabled):
            self.enabled = enabled
            if not self.enabled:
                pygame.mixer.music.stop()
            else:
                self.load_next_song()

        def handle_settings_update(self, event):
            self.set_music_volume(self.settings['sound']['music_volume'])
            self.set_default_music_volume(self.settings['sound']['music_volume'])

            if self.enabled != self.settings['sound']['music_enabled']:
                self.set_enabled(self.settings['sound']['music_enabled'])

        def handle_song_stopped(self, event):
            self.load_next_song()

        def handle_state_change(self, event):
            self.set_music_volume(self.default_volume)
            self.load_playlist(event.state)
            self.load_next_song()

        def set_music_stopped_event(self, event):
            pygame.mixer.music.set_endevent(event)

        def load_next_song(self):
            if len(self.cur_playlist) > 0:
                self.track_no += 1
                self.track_no %= len(self.cur_playlist)
                self.play_song(self.cur_playlist[self.track_no])

    instance = None

    def __init__(self, settings = None):
        if MusicManager.instance == None:
            MusicManager.instance = MusicManager.__MusicManager(settings)

    def __getattr__(self, name):
        return getattr(self.instance, name) class Menu:
    def __init__(self, items):
        self.items = items
        self.selected = 0

        self.item_height = 0
        self.item_width  = 0

        self.padding_bottom = 17

        for item in items:
            if item.surface.get_height() > self.item_height:
                self.item_height = item.surface.get_height()
            if item.surface.get_width() > self.item_width:
                self.item_width = item.surface.get_width()
        self.total_height = self.item_height + self.padding_bottom

        self.surface = pygame.Surface((self.item_width + 15, self.total_height*len(items)))

        for i in range(len(items)):
            y = i*self.total_height
            x = (self.item_width - items[i].surface.get_width())
            self.surface.blit(items[i].surface, (x,y))

    def move_selection(self, distance):
        event = pygame.event.Event(SOUND_EFFECT, message="menu_move")
        pygame.event.post(event)
        self.selected += distance
        self.selected %= len(self.items)

    def get_menu_surface(self):
        return self.surface

    def render(self):
        surface = self.surface.copy()

        y1 = self.selected * self.total_height + (self.total_height-12)/2
        x1 = self.surface.get_width() - 7
        x2 = x1 + 5
        y2 = y1 - 5
        x3 = x1 + 5
        y3 = y1 + 5

        pygame.draw.polygon(surface, colours.COLOUR_WHITE,[(x1,y1), (x2,y2), (x3,y3)])
        return surface

    def click_selected(self):
        event = pygame.event.Event(SOUND_EFFECT, message="menu_click")
        pygame.event.post(event)
        self.items[self.selected].callback() class MenuItem(object):
    def __init__(self, label, height=-1, width=-1):
        self.label = label
        self.surface_label = text_renderer.render_menu_item(label, colours.COLOUR_WHITE)
        self.focused = False
        self.height = height
        self.width  = width

    def set_height(self, height):
        self.height = height

    def get_height(self):
        return self.height

    def set_width(self, width):
        self.width = width

    def get_width(self):
        return self.width

    def set_focused(self, focus):
        self.focused = focus

    def render(self):
        surface = pygame.Surface((self.width, self.height))
        return surface

    def click(self):
        return class SettingsMenu:
    def __init__(self, settings):
        self.settings = settings
        self.selected = 0
        self.valid_resolutions = ["{} x {}".format(item['width'], item['height']) for item in settings['valid_resolutions'] ]
        self.spacing_margin = 25
        self.padding = 10

        self.sound_enabled = BooleanMenuItem("Sound", self.settings['sound']['sound_enabled'])
        self.sound_volume = SliderMenuItem("Sound Volume", 0, 100, self.settings['sound']['sound_volume']*100, self.preview_sound_change)
        self.sound_volume.bottom_margin = self.spacing_margin

        self.music_enabled = BooleanMenuItem("Music", self.settings['sound']['music_enabled'])
        self.music_volume = SliderMenuItem("Music Volume", 0, 100, self.settings['sound']['music_volume']*100, self.preview_music_change)
        self.music_volume.bottom_margin = self.spacing_margin

        self.fullscreen = BooleanMenuItem("Fullscreen", self.settings['screen']['fullscreen'])
        self.resolution = MultiOptionMenuItem("Resolution", self.valid_resolutions, self.settings['screen']['resolution'])
        self.resolution.bottom_margin = self.spacing_margin

        self.finished_choice = ChoiceMenuItem("Apply", "Cancel", self.finished)

        self.sound_manager = SoundManager()
        self.music_manager = MusicManager()
        self.items = [
            self.sound_enabled,
            self.sound_volume,
            self.music_enabled,
            self.music_volume,
            self.fullscreen,
            self.resolution,
            self.finished_choice
        ]

        self.callback = None
        self.done = False

        max_height = 0
        self.width = 0
        for item in self.items:
            if item.get_height() > max_height:
                max_height = item.get_height()
            if item.get_width() > self.width:
                self.width = item.get_width()

        self.height = (max_height+self.padding)*(len(self.items)) - self.padding
        for item in self.items:
            self.height += item.bottom_margin
            item.set_height(max_height)
            item.set_width(self.width)

        self.items[self.selected].set_focused(True)

    def render(self):
        surface = pygame.Surface((self.width, self.height))
        offset = 0
        for i in range(len(self.items)):
            item_surface = self.items[i].render()
            surface.blit(item_surface, (
                0,
                offset
            ))
            offset += self.items[i].get_height()+self.padding+self.items[i].bottom_margin

        return surface

    def preview_sound_change(self, volume):
        self.sound_manager.set_volume(volume/100.0)

    def preview_music_change(self, volume):
        self.music_manager.set_music_volume(volume/100.0)

    def move_selection(self, distance):
        event = pygame.event.Event(SOUND_EFFECT, message="menu_move")
        pygame.event.post(event)
        self.items[self.selected].set_focused(False)
        self.selected += distance//abs(distance)
        self.selected %= len(self.items)
        self.items[self.selected].set_focused(True)

    def click_selected(self, direction):
        if direction == 3:
            self.quit()
        else:
            self.items[self.selected].click(direction)

    def register_finished_callback(self, callback):
        self.callback = callback

    def quit(self):
        self.finished_choice.set_value(1)
        self.finished_choice.click(2)

    def finished(self):
        if self.finished_choice.get_value() == 0:
            self.settings['sound']['sound_enabled'] = self.sound_enabled.get_value()
            self.settings['sound']['sound_volume'] = self.sound_volume.get_value()/100.0
            self.settings['sound']['music_enabled'] = self.music_enabled.get_value()
            self.settings['sound']['music_volume'] = self.music_volume.get_value()/100.0
            self.settings['screen']['fullscreen'] = self.fullscreen.get_value()
            self.settings['screen']['resolution'] = self.resolution.get_value()
            
        event = pygame.event.Event(SETTINGS_UPDATED)
        pygame.event.post(event)

        if self.callback != None:
            self.callback() class ButtonMenuItem:
    def __init__(self, text, callback, height=-1, width=-1):
        self.text = text
        self.callback = callback
        self.bottom_margin = 0
        self.surface = text_renderer.render_menu_item(text, colours.COLOUR_WHITE)

    def render(self):
        return self.surface class TeamViewer:
    def __init__(self, region, teams=[]):
        self.width = region[0]
        self.height = region[1]
        self.callback = None
        self.teams = teams
        self.selected = 0

        self.header_top    = 0
        self.header_bottom = 45

        self.banners = []
        self.banner_width  = 0
        self.banner_height = 0
        self.team_member_height = 100
        self.team_member_width  = 760
        self.team_member_spacing = 10

        self.move_list_offset =  (self.width - self.team_member_width)//2 + 450
        self.hth_surface = text_renderer.render_text("HTH:", colours.COLOUR_WHITE)
        self.atk_surface = text_renderer.render_text("ATK:", colours.COLOUR_WHITE)
        self.def_surface = text_renderer.render_text("DEF:", colours.COLOUR_WHITE)
        self.spd_surface = text_renderer.render_text("SPD:", colours.COLOUR_WHITE)

        for team in teams:
            self.banners.append(text_renderer.render_menu_item(team.get_short_name(), colours.COLOUR_WHITE))
            if self.banners[-1].get_width() > self.banner_width:
                self.banner_width = self.banners[-1].get_width()
            if self.banners[-1].get_height() > self.banner_height:
                self.banner_height = self.banners[-1].get_height()

    def render(self):
        surface = pygame.Surface((self.width, self.height))
        if len(self.teams) == 0:
            counter = text_renderer.render_menu_item("0/0", colours.COLOUR_WHITE)
            surface.blit(counter, (self.width-counter.get_width()-30, (self.header_bottom-counter.get_height())//2))
            return surface

        counter = text_renderer.render_menu_item("{}/{}".format(self.selected+1, len(self.teams)), colours.COLOUR_WHITE)
        surface.blit(counter, ((self.width+self.team_member_width)//2 - counter.get_width(), (self.header_bottom-counter.get_height())//2))

        banner = self.banners[self.selected]
        surface.blit(banner, ((self.width-banner.get_width())//2, (self.header_bottom-counter.get_height())//2))

        x1 = (self.width-self.banner_width)//2 - 15
        y1 = self.header_bottom//2

        x2 = x1  + 5
        y2 = y1 + 5

        x3 = x2
        y3 = y1 - 5

        pygame.draw.polygon(surface, colours.COLOUR_WHITE,[(x1,y1), (x2,y2), (x3,y3)])

        x1 = (self.width+self.banner_width)//2 + 15
        x2 = x1  - 5
        x3 = x2

        pygame.draw.polygon(surface, colours.COLOUR_WHITE,[(x1,y1), (x2,y2), (x3,y3)])

        for i in range(len(self.teams[self.selected])):
            self.render_team_member(surface, self.teams[self.selected][i], i*(self.team_member_height+self.team_member_spacing) + self.header_bottom)

        return surface

    def render_team_member(self, surface, team_member, v_offset):
        images = ImageManager()

        h_offset = (self.width-self.team_member_width)//2
        name = text_renderer.render_text(team_member.get_short_name(), colours.COLOUR_WHITE)
        surface.blit(name, (h_offset + self.team_member_height + 10, v_offset))
        surface.blit(self.hth_surface, (h_offset + self.team_member_height + 10, v_offset+self.team_member_height-60))

        surface.blit(self.hth_surface, (h_offset + self.team_member_height + 10, v_offset+self.team_member_height-60))
        stat_val = text_renderer.render_text(str(team_member.cur_hp), colours.COLOUR_WHITE)
        surface.blit(stat_val, (h_offset + self.team_member_height + 80, v_offset+self.team_member_height-60))

        surface.blit(self.atk_surface, (h_offset + self.team_member_height + 160, v_offset+self.team_member_height-60))
        stat_val = text_renderer.render_text(str(team_member.get_stat("attack")), colours.COLOUR_WHITE)
        surface.blit(stat_val, (h_offset + self.team_member_height + 230, v_offset+self.team_member_height-60))

        surface.blit(self.def_surface, (h_offset + self.team_member_height + 10, v_offset+self.team_member_height-30))
        stat_val = text_renderer.render_text(str(team_member.get_stat("defense")), colours.COLOUR_WHITE)
        surface.blit(stat_val, (h_offset + self.team_member_height + 80, v_offset+self.team_member_height-30))

        surface.blit(self.spd_surface, (h_offset + self.team_member_height + 160, v_offset+self.team_member_height-30))
        stat_val = text_renderer.render_text(str(team_member.get_stat("speed")), colours.COLOUR_WHITE)
        surface.blit(stat_val, (h_offset + self.team_member_height + 230, v_offset+self.team_member_height-30))

        icon = images.get_tile("{}_mage".format(team_member.element.name.lower()), 0, 0)
        surface.blit(icon, (h_offset, v_offset))
        for i in range(len(team_member.spells)):
            spell_val = text_renderer.render_text("{}. {}".format(i+1, team_member.spells[i]), colours.COLOUR_WHITE)
            surface.blit(spell_val, (self.move_list_offset, v_offset+i*23))

        pygame.draw.line(surface, colours.COLOUR_WHITE, (self.move_list_offset-10, v_offset), (self.move_list_offset-10, v_offset+self.team_member_height))
        pygame.draw.line(surface, colours.COLOUR_WHITE, (h_offset+ self.team_member_height, v_offset), (h_offset + self.team_member_height, v_offset+self.team_member_height))
        pygame.draw.rect(surface, colours.COLOUR_WHITE, ((self.width-self.team_member_width)//2, v_offset, self.team_member_width+1, self.team_member_height+1), 1)
        return

    def move_selection(self, distance):
        if distance == 3:
            event = pygame.event.Event(SOUND_EFFECT, message="menu_click")
            pygame.event.post(event)
            self.quit()
        else:
            event = pygame.event.Event(SOUND_EFFECT, message="menu_move")
            pygame.event.post(event)
            if len(self.teams) == 0:
                return
            self.selected += distance
            self.selected %= len(self.teams)

    def register_finished_callback(self, callback):
        self.callback = callback

    def quit(self):
        if self.callback != None:
            self.callback()
import pygame
from collections import defaultdict
from app.resources.event_handler import SET_GAME_STATE
from app.resources import colours
from app.resources import text_renderer
from app.view import animations
from app.resources.music import MusicManager
from app.view.menu import Menu, MenuItem, SettingsMenu, ButtonMenuItem, TeamViewer

class TitleBanner:
    def __init__(self, text):
        words = text.split()
        word_surfaces = []
        max_height = 0
        max_width  = 0

        for word in words:
            ws = text_renderer.render_title(word, colours.COLOUR_WHITE)
            if ws.get_height() > max_height:
                max_height = ws.get_height()
            if ws.get_width() > max_width:
                max_width = ws.get_width()
            word_surfaces.append(ws)

        self.surface = pygame.Surface((max_width, max_height*len(words)))

        for i in range(len(word_surfaces)):
            y = i*max_height
            x = (max_width - word_surfaces[i].get_width())//2
            self.surface.blit(word_surfaces[i], (x,y))

    def render(self):
        return self.surface

class State:
    def render(self):
        return
    def update(self, delta_t):
        return
    def handle_event(self, event):
        return
    def exit_state(self):
        return

class StateTeamView(State):
    def __init__(self, main_menu):
        self.parent     = main_menu.parent
        self.main_menu  = main_menu
        self.teams      = self.parent.teams

        self.parent.event_handler.register_key_listener(self.handle_keypress)
        self.title = text_renderer.render_title("Teams", colours.COLOUR_WHITE)
        self.title_position = (
            (self.parent.resolution[0] - self.title.get_width())// 2,
            15
        )

        self.directions = {
            pygame.K_RIGHT     : [1],
            pygame.K_LEFT      : [-1],
            pygame.K_ESCAPE    : [3],
            pygame.K_BACKSPACE : [3]
        }

        self.animation = None

        menu_region = (self.parent.resolution[0],
            600
        )
        self.menu = TeamViewer(menu_region, self.teams)
        self.menu.register_finished_callback(self.finished)

    def render(self):
        surface = pygame.Surface(self.parent.resolution)
        surface.blit(self.title, self.title_position)
        surface.blit(self.menu.render(), (0,(15 + self.title.get_height() + self.parent.resolution[1]-self.menu.height)//2))
        return surface

    def handle_keypress(self, event):
        if event.type == pygame.KEYDOWN:
            if event.key in self.directions:
                magnitude = self.directions[event.key]

                self.animation = animations.Timeout(