예제 #1
0
    def startup(self, **kwargs):
        self.state = "normal"

        # this sprite is used to display the item
        self.item_center = self.rect.width * .164, self.rect.height * .13
        self.item_sprite = Sprite()
        self.item_sprite.image = None
        self.sprites.add(self.item_sprite)

        # do not move this line
        super().startup(**kwargs)
        self.menu_items.line_spacing = tools.scale(7)

        # this is the area where the item description is displayed
        rect = self.client.screen.get_rect()
        rect.top = tools.scale(106)
        rect.left = tools.scale(3)
        rect.width = tools.scale(250)
        rect.height = tools.scale(32)
        self.text_area = TextArea(self.font, self.font_color, (96, 96, 128))
        self.text_area.rect = rect
        self.sprites.add(self.text_area, layer=100)

        self.image_center = self.rect.width * .16, self.rect.height * .45
        self.buyer = kwargs["buyer"]
        self.seller = kwargs["seller"]
        self.buyer_purge = kwargs.get("buyer_purge", False)
예제 #2
0
    def startup(self, **kwargs):
        self.state = "normal"

        # this sprite is used to display the item
        # its also animated to pop out of the backpack
        self.item_center = self.rect.width * .164, self.rect.height * .13
        self.item_sprite = Sprite()
        self.item_sprite.image = None
        self.sprites.add(self.item_sprite)

        # do not move this line
        super().startup(**kwargs)
        self.menu_items.line_spacing = tools.scale(7)

        # this is the area where the item description is displayed
        rect = self.client.screen.get_rect()
        rect.top = tools.scale(106)
        rect.left = tools.scale(3)
        rect.width = tools.scale(250)
        rect.height = tools.scale(32)
        self.text_area = TextArea(self.font, self.font_color, (96, 96, 128))
        self.text_area.rect = rect
        self.sprites.add(self.text_area, layer=100)

        # load the backpack icon
        self.backpack_center = self.rect.width * .16, self.rect.height * .45
        self.load_sprite("gfx/ui/item/backpack.png", center=self.backpack_center, layer=100)
예제 #3
0
파일: combat.py 프로젝트: sradigan/Tuxemon
    def draw_hp_bars(self):
        """ Go through the HP bars and redraw them

        :returns: None
        """
        for monster, hud in self.hud.items():
            rect = Rect(0, 0, tools.scale(70), tools.scale(8))
            rect.right = hud.image.get_width() - tools.scale(8)
            rect.top += tools.scale(12)
            self._hp_bars[monster].draw(hud.image, rect)
예제 #4
0
    def animate_party_hud_in(self, player, home):
        """ Party HUD is the arrow thing with balls.  Yes, that one.

        :param player: the player
        :type home: Rect
        :param slots: Number of slots
        :return:
        """
        if self.get_side(home) == "left":
            tray = self.load_sprite('gfx/ui/combat/opponent_party_tray.png',
                                    bottom=home.bottom,
                                    right=0,
                                    layer=hud_layer)
            self.animate(tray.rect, right=home.right, duration=2, delay=1.5)
            centerx = home.right - scale(13)
            offset = scale(8)
        else:
            tray = self.load_sprite('gfx/ui/combat/player_party_tray.png',
                                    bottom=home.bottom,
                                    left=home.right,
                                    layer=hud_layer)
            self.animate(tray.rect, left=home.left, duration=2, delay=1.5)
            centerx = home.left + scale(13)
            offset = -scale(8)

        for index in range(player.party_limit):
            if len(player.monsters) > index:
                monster = player.monsters[index]
                if any(t for t in monster.status if t.slug == "status_faint"):
                    sprite = self.load_sprite(
                        'gfx/ui/icons/party/party_icon03.png',
                        top=tray.rect.top + scale(1),
                        centerx=centerx - index * offset,
                        layer=hud_layer)
                elif len(monster.status) > 0:
                    sprite = self.load_sprite(
                        'gfx/ui/icons/party/party_icon02.png',
                        top=tray.rect.top + scale(1),
                        centerx=centerx - index * offset,
                        layer=hud_layer)
                else:
                    sprite = self.load_sprite(
                        'gfx/ui/icons/party/party_icon01.png',
                        top=tray.rect.top + scale(1),
                        centerx=centerx - index * offset,
                        layer=hud_layer)
            else:
                sprite = self.load_sprite('gfx/ui/combat/empty_slot_icon.png',
                                          top=tray.rect.top + scale(1),
                                          centerx=centerx - index * offset,
                                          layer=hud_layer)

            # convert alpha image to image with a colorkey so we can set_alpha
            sprite.image = graphics.convert_alpha_to_colorkey(sprite.image)
            sprite.image.set_alpha(0)
            animate = partial(self.animate,
                              duration=1.5,
                              delay=2.2 + index * .2)
            animate(sprite.image, set_alpha=255, initial=0)
            animate(sprite.rect, bottom=tray.rect.top + scale(3))
예제 #5
0
    def draw_exp_bars(self):
        """ Go through the EXP bars and redraw them

        :rtype: None
        """
        for monster, hud in self.hud.items():
            if hud.player:
                rect = Rect(0, 0, tools.scale(70), tools.scale(6))
                rect.right = hud.image.get_width() - tools.scale(8)
                rect.top += tools.scale(31)
                self._exp_bars[monster].draw(hud.image, rect)
예제 #6
0
파일: menu.py 프로젝트: sradigan/Tuxemon
    def calc_menu_items_rect(self):
        """ Calculate the area inside the internal rect where items are listed

        :rtype: Rect
        """
        # WARNING: hardcoded values related to menu arrow size
        #          if menu arrow image changes, this should be adjusted
        cursor_margin = -tools.scale(11), -tools.scale(5)
        inner = self.calc_internal_rect()
        menu_rect = inner.inflate(*cursor_margin)
        menu_rect.bottomright = inner.bottomright
        return menu_rect
예제 #7
0
    def animate_trainer_leave(self, trainer):
        """

        :type trainer: tuxemon.core.player.Player
        :return:
        """
        sprite = self._monster_sprite_map[trainer]
        if self.get_side(sprite.rect) == "left":
            x_diff = -scale(150)
        else:
            x_diff = scale(150)

        self.animate(sprite.rect, x=x_diff, relative=True, duration=.8)
예제 #8
0
    def calc_inner_rect(rect):
        """ Calculate the inner rect to draw fg_color that fills bar
            The values here are calculated based on game scale and
            the content of the border image file.

        :param rect:
        :returns:
        """
        inner = rect.copy()
        inner.top += tools.scale(2)
        inner.height -= tools.scale(4)
        inner.left += tools.scale(9)
        inner.width -= tools.scale(11)
        return inner
예제 #9
0
    def animate_update_party_hud(self, player, home):
        """ Party HUD is the arrow thing with balls.  Yes, that one.

        This function updates the balls to reflect how many Tuxemon have fainted.

        :param player: the player
        :type home: Rect
        :param slots: Number of slots
        :return:
        """
        if self.get_side(home) == "left":
            tray = self.load_sprite('gfx/ui/combat/opponent_party_tray.png',
                                    bottom=home.bottom,
                                    right=0,
                                    layer=hud_layer)
            self.animate(tray.rect, right=home.right, duration=0.1, delay=0.1)
            centerx = home.right - scale(13)
            offset = scale(8)
        else:
            tray = self.load_sprite('gfx/ui/combat/player_party_tray.png',
                                    bottom=home.bottom,
                                    left=home.right,
                                    layer=hud_layer)
            self.animate(tray.rect, left=home.left, duration=0.1, delay=0.1)
            centerx = home.left + scale(13)
            offset = -scale(8)

        count_fainted = 0

        for monster in player.monsters:
            if any(t for t in monster.status if t.slug == "status_faint"):
                count_fainted += 1

        for index in range(player.party_limit):
            sprite = None
            if len(player.monsters
                   ) - count_fainted > index:  # render alive Tuxemon balls
                sprite = self.load_sprite(
                    'gfx/ui/icons/party/party_icon01.png',
                    top=tray.rect.top + scale(1),
                    centerx=centerx - index * offset,
                    layer=hud_layer)
            elif len(player.monsters) > index:  # render fainted Tuxemon balls
                sprite = self.load_sprite(
                    'gfx/ui/icons/party/party_icon03.png',
                    top=tray.rect.top + scale(1),
                    centerx=centerx - index * offset,
                    layer=hud_layer)
            else:
                sprite = self.load_sprite('gfx/ui/combat/empty_slot_icon.png',
                                          top=tray.rect.top + scale(1),
                                          centerx=centerx - index * offset,
                                          layer=hud_layer)

            # convert alpha image to image with a colorkey so we can set_alpha
            sprite.image = graphics.convert_alpha_to_colorkey(sprite.image)
            sprite.image.set_alpha(0)
            animate = partial(self.animate, duration=0.1, delay=0.1)
            animate(sprite.image, set_alpha=255, initial=0)
            animate(sprite.rect, bottom=tray.rect.top + scale(3))
예제 #10
0
    def animate_sprite_take_damage(self, sprite):
        """

        :type sprite: tuxemon.core.sprite.Sprite
        :return:
        """
        original_x, original_y = sprite.rect.topleft
        animate = partial(self.animate,
                          sprite.rect,
                          duration=1,
                          transition='in_out_elastic')
        ani = animate(x=original_x, initial=original_x + scale(400))
        ani._elapsed = .735  # just want the end of the animation, not the entire thing
        ani = animate(y=original_y, initial=original_y - scale(400))
        ani._elapsed = .735  # just want the end of the animation, not the entire thing
예제 #11
0
    def get_side(self, rect):
        """ [WIP] get 'side' of screen rect is in

        :type rect: Rect
        :return: basestring
        """
        return "left" if rect.centerx < scale(100) else "right"
예제 #12
0
 def animate_monster_up(self):
     ani = self.animate(self.monster_portrait.rect,
                        y=tools.scale(5),
                        duration=1,
                        transition='in_out_quad',
                        relative=True)
     ani.callback = self.animate_monster_down
예제 #13
0
    def animate_monster_leave(self, monster):
        """

        :type monster: tuxemon.core.monster.Monster
        :return:
        """
        sprite = self._monster_sprite_map[monster]
        if self.get_side(sprite.rect) == "left":
            x_diff = -scale(150)
        else:
            x_diff = scale(150)

        cry = monster.combat_call if monster.current_hp > 0 else monster.faint_call
        sound = audio.load_sound(cry)
        sound.play()
        self.animate(sprite.rect, x=x_diff, relative=True, duration=2)
예제 #14
0
    def draw_monster_info(self, surface, monster, rect):
        # position and draw hp bar
        hp_rect = rect.copy()
        left = rect.width * .6
        right = rect.right - tools.scale(4)
        hp_rect.width = right - left
        hp_rect.left = left
        hp_rect.height = tools.scale(8)
        hp_rect.centery = rect.centery

        # draw the hp bar
        self.hp_bar.value = monster.current_hp / monster.hp
        self.hp_bar.draw(surface, hp_rect)

        # draw the name
        text_rect = rect.inflate(-tools.scale(6), -tools.scale(6))
        draw_text(surface, monster.name, text_rect, font=self.font)

        # draw the level info
        text_rect.top = rect.bottom - tools.scale(7)
        draw_text(surface,
                  "  Lv " + str(monster.level),
                  text_rect,
                  font=self.font)

        # draw any status icons
        # TODO: caching or something, idk
        # TODO: not hardcode icon sizes
        for index, status in enumerate(monster.status):
            if status.icon:
                image = graphics.load_and_scale(status.icon)
                pos = (rect.width *
                       .4) + (index * tools.scale(32)), rect.y + tools.scale(5)
                surface.blit(image, pos)
예제 #15
0
        def shake_ball(initial_delay):
            animate = partial(self.animate,
                              duration=0.1,
                              transition='linear',
                              delay=initial_delay)
            animate(capdev.rect, y=scale(3), relative=True)

            animate = partial(self.animate,
                              duration=0.2,
                              transition='linear',
                              delay=initial_delay + 0.1)
            animate(capdev.rect, y=-scale(6), relative=True)

            animate = partial(self.animate,
                              duration=0.1,
                              transition='linear',
                              delay=initial_delay + 0.3)
            animate(capdev.rect, y=scale(3), relative=True)
예제 #16
0
    def initialize_items(self):
        # get a ref to the combat state
        combat_state = self.client.get_state_by_name("CombatState")

        # TODO: trainer targeting
        # TODO: cleanup how monster sprites and whatnot are managed
        # TODO: This is going to work fine for simple matches, but controls will be wonky for parties
        # TODO: (cont.) Need better handling of cursor keys for 2d layouts of menu items
        # get all the monster positions

        # this is used to determine who owns what monsters and what not
        # TODO: make less duplication of game data in memory, let combat state have more registers, etc
        self.targeting_map = defaultdict(list)

        for player, monsters in combat_state.monsters_in_play.items():
            for monster in monsters:

                # TODO: more targeting classes
                if player == self.player:
                    targeting_class = "own monster"
                else:
                    targeting_class = "enemy monster"

                self.targeting_map[targeting_class].append(monster)

                # TODO: handle odd cases where a situation creates no valid targets
                # if this target type is not handled by this action, then skip it
                if targeting_class not in self.action.target:
                    continue

                # inspect the monster sprite and make a border image for it
                sprite = combat_state._monster_sprite_map[monster]
                item = MenuItem(None, None, None, monster)
                item.rect = sprite.rect.copy()
                center = item.rect.center
                item.rect.inflate_ip(tools.scale(16), tools.scale(16))
                item.rect.center = center

                yield item
예제 #17
0
파일: menu.py 프로젝트: sradigan/Tuxemon
    def set_font(self, size=5, font=None, color=(10, 10, 10), line_spacing=10):
        """Set the font properties that the menu uses including font _color, size, typeface,
        and line spacing.

        The size and line_spacing parameters will be adjusted the
        the screen scale.  You should pass the original, unscaled values.

        :param size: The font size in pixels.
        :param font: Path to the typeface file (.ttf)
        :param color: A tuple of the RGB _color values
        :param line_spacing: The spacing in pixels between lines of text

        :type size: Integer
        :type font: String
        :type color: Tuple
        :type line_spacing: Integer

        :rtype: None
        :returns: None

        .. image:: images/menu/set_font.png

        """
        if font is None:
            font = self.font_filename

        if size < self.min_font_size:
            size = self.min_font_size

        self.line_spacing = tools.scale(line_spacing)

        if prepare.CONFIG.large_gui:
            self.font_size = tools.scale(size + 1)
        else:
            self.font_size = tools.scale(size)

        self.font_color = color
        self.font = pygame.font.Font(font, self.font_size)
예제 #18
0
    def animate_sprite_tackle(self, sprite):
        """

        :type sprite: tuxemon.core.sprite.Sprite
        :return:
        """
        duration = .3
        original_x = sprite.rect.x

        if self.get_side(sprite.rect) == "left":
            delta = scale(14)
        else:
            delta = -scale(14)

        self.animate(sprite.rect,
                     x=original_x + delta,
                     duration=duration,
                     transition='out_circ')
        self.animate(sprite.rect,
                     x=original_x,
                     duration=duration,
                     transition='in_out_circ',
                     delay=.35)
예제 #19
0
파일: menu.py 프로젝트: sradigan/Tuxemon
    def fit_border(self):
        """ Resize the window border to fit the contents of the menu

        :return:
        """
        # get bounding box of menu items and the cursor
        center = self.rect.center
        rect1 = self.menu_items.calc_bounding_rect()
        rect2 = self.menu_sprites.calc_bounding_rect()
        rect1 = rect1.union(rect2)

        # expand the bounding box by the border and some padding
        # TODO: do not hardcode these values
        # border is 12, padding is the rest
        rect1.width += tools.scale(18)
        rect1.height += tools.scale(19)
        rect1.topleft = 0, 0

        # set our rect and adjust the centers to match
        self.rect = rect1
        self.rect.center = center

        # move the bounding box taking account the anchors
        self.position_rect()
예제 #20
0
파일: menu.py 프로젝트: sradigan/Tuxemon
    def trigger_cursor_update(self, animate=True):
        """ Force the menu cursor to move into the correct position

        :param animate: If True, then arrow will move smoothly into position
        :returns: None or Animation
        """
        selected = self.get_selected_item()
        if not selected:
            return

        x, y = selected.rect.midleft
        x -= tools.scale(2)

        if animate:
            self.remove_animations_of(self.arrow.rect)
            return self.animate(self.arrow.rect,
                                right=x,
                                centery=y,
                                duration=self.cursor_move_duration)
        else:
            self.arrow.rect.midright = x, y
            return None
예제 #21
0
    def animate_parties_in(self):
        # TODO: break out functions here for each
        left_trainer, right_trainer = self.players
        right_monster = right_trainer.monsters[0]

        surface = pygame.display.get_surface()
        x, y, w, h = surface.get_rect()

        # TODO: not hardcode this
        player, opponent = self.players
        player_home = self._layout[player]['home'][0]
        opp_home = self._layout[opponent]['home'][0]

        y_mod = scale(50)
        duration = 3

        back_island = self.load_sprite('gfx/ui/combat/' +
                                       self.graphics['island_back'],
                                       bottom=opp_home.bottom + y_mod,
                                       right=0)

        if self.is_trainer_battle:
            enemy = self.load_sprite(
                'gfx/sprites/player/' + opponent.sprite_name + '_front.png',
                bottom=back_island.rect.bottom - scale(12),
                centerx=back_island.rect.centerx)
            self._monster_sprite_map[opponent] = enemy
        else:
            enemy = right_monster.get_sprite("front",
                                             bottom=back_island.rect.bottom -
                                             scale(12),
                                             centerx=back_island.rect.centerx)
            self._monster_sprite_map[right_monster] = enemy
            self.monsters_in_play[opponent].append(right_monster)

        self.sprites.add(enemy)
        self.build_hud(self._layout[opponent]['hud'][0], right_monster)

        if self.is_trainer_battle:
            self.alert(
                T.format('combat_trainer_appeared',
                         {"name": opponent.name.upper()}))
        else:
            self.alert(
                T.format('combat_wild_appeared',
                         {"name": right_monster.name.upper()}))

        front_island = self.load_sprite('gfx/ui/combat/' +
                                        self.graphics['island_front'],
                                        bottom=player_home.bottom - y_mod,
                                        left=w)

        trainer1 = self.load_sprite(
            'gfx/sprites/player/' + player.sprite_name + '_back.png',
            bottom=front_island.rect.centery + scale(6),
            centerx=front_island.rect.centerx)
        self._monster_sprite_map[left_trainer] = trainer1

        def flip():
            enemy.image = pygame.transform.flip(enemy.image, 1, 0)
            trainer1.image = pygame.transform.flip(trainer1.image, 1, 0)

        flip()  # flip images to opposite
        self.task(flip, 1.5)  # flip the images to proper direction

        if not self.is_trainer_battle:  # the combat call is handled by fill_battlefield_positions for trainer battles
            self.task(audio.load_sound(right_monster.combat_call).play,
                      1.5)  # play combat call when it turns back

        animate = partial(self.animate,
                          transition='out_quad',
                          duration=duration)

        # top trainer
        animate(enemy.rect, back_island.rect, centerx=opp_home.centerx)
        animate(enemy.rect,
                back_island.rect,
                y=-y_mod,
                transition='out_back',
                relative=True)

        # bottom trainer
        animate(trainer1.rect, front_island.rect, centerx=player_home.centerx)
        animate(trainer1.rect,
                front_island.rect,
                y=y_mod,
                transition='out_back',
                relative=True)
예제 #22
0
    def animate_capture_monster(self, is_captured, num_shakes, monster):
        """ Animation for capturing monsters.

        :param is_captured: boolean representing success of capture
        :param num_shakes: number of shakes before animation ends
        :param monster: the monster
        :return:
        """
        monster_sprite = self._monster_sprite_map.get(monster, None)
        capdev = self.load_sprite('gfx/items/capture_device.png')
        animate = partial(self.animate,
                          capdev.rect,
                          transition='in_quad',
                          duration=1.0)
        graphics.scale_sprite(capdev, .4)
        capdev.rect.center = scale(0), scale(0)
        animate(x=monster_sprite.rect.centerx)
        animate(y=monster_sprite.rect.centery)
        self.task(partial(toggle_visible, monster_sprite),
                  1.0)  # make the monster go away temporarily

        def kill():
            self._monster_sprite_map[monster].kill()
            self.hud[monster].kill()
            del self._monster_sprite_map[monster]
            del self.hud[monster]

        # TODO: cache this sprite from the first time it's used.
        # also, should loading animated sprites be more convenient?
        images = list()
        for fn in ["capture%02d.png" % i for i in range(1, 10)]:
            fn = 'animations/technique/' + fn
            image = graphics.load_and_scale(fn)
            images.append((image, .07))

        tech = PygAnimation(images, False)
        sprite = Sprite()
        sprite.image = tech
        sprite.rect = tech.get_rect()
        self.task(tech.play, 1.0)
        self.task(partial(self.sprites.add, sprite), 1.0)
        sprite.rect.midbottom = monster_sprite.rect.midbottom

        def shake_ball(initial_delay):
            animate = partial(self.animate,
                              duration=0.1,
                              transition='linear',
                              delay=initial_delay)
            animate(capdev.rect, y=scale(3), relative=True)

            animate = partial(self.animate,
                              duration=0.2,
                              transition='linear',
                              delay=initial_delay + 0.1)
            animate(capdev.rect, y=-scale(6), relative=True)

            animate = partial(self.animate,
                              duration=0.1,
                              transition='linear',
                              delay=initial_delay + 0.3)
            animate(capdev.rect, y=scale(3), relative=True)

        for i in range(0, num_shakes):
            shake_ball(1.8 + i * 1.0)  # leave a 0.6s wait between each shake

        if is_captured:
            self.task(kill, 2 + num_shakes)
        else:
            breakout_delay = 1.8 + num_shakes * 1.0
            self.task(partial(toggle_visible, monster_sprite),
                      breakout_delay)  # make the monster appear again!
            self.task(
                audio.load_sound(monster.combat_call).play, breakout_delay)
            self.task(tech.play, breakout_delay)
            self.task(capdev.kill, breakout_delay)
예제 #23
0
    def animate_monster_release(self, npc, monster):
        """

        :type npc: tuxemon.core.npc.Npc
        :type monster: tuxemon.core.monster.Monster
        :return:
        """
        feet = list(self._layout[npc]['home'][0].center)
        feet[1] += tools.scale(11)

        capdev = self.load_sprite('gfx/items/capture_device.png')
        graphics.scale_sprite(capdev, .4)
        capdev.rect.center = feet[0], feet[1] - scale(60)

        # animate the capdev falling
        fall_time = .7
        animate = partial(self.animate,
                          duration=fall_time,
                          transition='out_quad')
        animate(capdev.rect, bottom=feet[1], transition='in_back')
        animate(capdev, rotation=720, initial=0)

        # animate the capdev fading away
        delay = fall_time + .6
        fade_duration = .9
        h = capdev.rect.height
        animate = partial(self.animate, duration=fade_duration, delay=delay)
        animate(capdev, width=1, height=h * 1.5)
        animate(capdev.rect, y=-scale(14), relative=True)

        # convert the capdev sprite so we can fade it easily
        def func():
            capdev.image = graphics.convert_alpha_to_colorkey(capdev.image)
            self.animate(capdev.image,
                         set_alpha=0,
                         initial=255,
                         duration=fade_duration)

        self.task(func, delay)
        self.task(capdev.kill, fall_time + delay + fade_duration)

        # load monster and set in final position
        monster_sprite = monster.get_sprite(
            "back" if npc.isplayer else "front", midbottom=feet)
        self.sprites.add(monster_sprite)
        self._monster_sprite_map[monster] = monster_sprite

        # position monster_sprite off screen and set animation to move it back to final spot
        monster_sprite.rect.top = self.client.screen.get_height()
        self.animate(monster_sprite.rect,
                     bottom=feet[1],
                     transition='out_back',
                     duration=.9,
                     delay=fall_time + .5)

        # capdev opening animation
        images = list()
        for fn in ["capture%02d.png" % i for i in range(1, 10)]:
            fn = 'animations/technique/' + fn
            image = graphics.load_and_scale(fn)
            images.append((image, .07))

        delay = 1.3
        tech = PygAnimation(images, False)
        sprite = Sprite()
        sprite.image = tech
        sprite.rect = tech.get_rect()
        sprite.rect.midbottom = feet
        self.task(tech.play, delay)
        self.task(partial(self.sprites.add, sprite), delay)

        # attempt to load and queue up combat_call
        call_sound = audio.load_sound(monster.combat_call)
        if call_sound:
            self.task(call_sound.play, delay)

        # update tuxemon balls to reflect fainted tuxemon
        for player, layout in self._layout.items():
            self.animate_update_party_hud(player, layout['party'][0])
예제 #24
0
    def animate_party_hud_in(self, player, home):
        """ Party HUD is the arrow thing with balls.  Yes, that one.

        :param player: the player
        :type home: Rect
        :param slots: Number of slots
        :return:
        """
        if self.get_side(home) == "left":
            tray = self.load_sprite('gfx/ui/combat/opponent_party_tray.png',
                                    bottom=home.bottom,
                                    right=0,
                                    layer=hud_layer)
            self.animate(tray.rect, right=home.right, duration=2, delay=1.5)
            centerx = home.right - scale(13)
            offset = scale(8)

        else:
            tray = self.load_sprite('gfx/ui/combat/player_party_tray.png',
                                    bottom=home.bottom,
                                    left=home.right,
                                    layer=hud_layer)
            self.animate(tray.rect, left=home.left, duration=2, delay=1.5)
            centerx = home.left + scale(13)
            offset = -scale(8)

        for index in range(player.party_limit):
            status = None
            #opponent tuxemon should order from left to right
            if (self.get_side(home) == "left"):
                pos = len(player.monsters) - index - 1
            else:
                pos = index
            if len(player.monsters) > index:
                monster = player.monsters[index]
                if any(t for t in monster.status if t.slug == "status_faint"):
                    status = "faint"
                    sprite = self.load_sprite(
                        'gfx/ui/icons/party/party_icon03.png',
                        top=tray.rect.top + scale(1),
                        centerx=centerx - pos * offset,
                        layer=hud_layer)
                elif len(monster.status) > 0:
                    status = "effected"
                    sprite = self.load_sprite(
                        'gfx/ui/icons/party/party_icon02.png',
                        top=tray.rect.top + scale(1),
                        centerx=centerx - pos * offset,
                        layer=hud_layer)
                else:
                    status = "alive"
                    sprite = self.load_sprite(
                        'gfx/ui/icons/party/party_icon01.png',
                        top=tray.rect.top + scale(1),
                        centerx=centerx - pos * offset,
                        layer=hud_layer)
            else:
                status = "empty"
                monster = None
                sprite = self.load_sprite('gfx/ui/combat/empty_slot_icon.png',
                                          top=tray.rect.top + scale(1),
                                          centerx=centerx - index * offset,
                                          layer=hud_layer)
            capdev = CaptureDeviceSprite(sprite=sprite,
                                         tray=tray,
                                         monster=monster,
                                         state=status)
            self.capdevs.append(capdev)
            animate = partial(self.animate,
                              duration=1.5,
                              delay=2.2 + index * .2)
            capdev.draw(animate)