Example #1
0
class PlayerBox:
    """Box that holds all the usernames of the players in the game"""
    def __init__(self, x, y, max_num_players, chars_per_line, large_font,
                 small_font, background_color):
        self.x = x
        self.y = y
        self.max_num_players = max_num_players
        self.chars_per_line = chars_per_line
        self.large_font = large_font
        self.small_font = small_font
        self.large_font_height = get_font_height(large_font)
        self.small_font_height = get_font_height(small_font)
        large_font_width = get_font_width(large_font)
        box_height = self.large_font_height * (
            max_num_players + 1) + self.small_font_height * max_num_players * 3
        box_width = large_font_width * chars_per_line
        self.box = NonCenteredRect(background_color, box_height, box_width, x,
                                   y)
        # note: title_text is a SelectableText but will never actually be selected
        self.title_text = SelectableText(large_font, "Players: ", WHITE,
                                         self.x, self.y)
        self.current_top = y + self.large_font_height  # where the next text item should go
        self.players = []

    def add_player(self, player_username, player_color):
        new_player = ClientOtherPlayer(player_username, player_color)
        new_player.set_text(self.large_font, self.small_font)

        # set up where the info regarding this player will be displayed
        # inside the player box
        # 1st, all the new text should be at the same x position as the box
        new_player.name_text.rect.x = self.x
        new_player.victory_point_text.rect.x = self.x
        new_player.dev_card_text.rect.x = self.x
        new_player.knights_played_text.rect.x = self.x

        # 2nd, heights have to be arranged, noting the different font sizes
        new_player.name_text.rect.y = self.current_top
        self.current_top += self.large_font_height
        new_player.victory_point_text.rect.y = self.current_top
        self.current_top += self.small_font_height
        new_player.dev_card_text.rect.y = self.current_top
        self.current_top += self.small_font_height
        new_player.knights_played_text.rect.y = self.current_top
        self.current_top += self.small_font_height

        self.players.append(new_player)

    def check_for_mouse(self, mouse_pos):
        for player in self.players:
            player.check_for_mouse(mouse_pos)

    def draw(self, screen):
        self.box.draw(screen)
        self.title_text.draw(screen)
        for player in self.players:
            player.draw(screen)
Example #2
0
class TextRect(Rect):
    """A colored rectangle with centered text in it. That's it."""

    color = common.LIGHT_BLUE
    text_color = common.BLACK

    def __init__(self, x, y, width, height, text, font):
        # setup rect
        super().__init__(TextRect.color, height, width, (x, y))

        # setup text
        self.text = SelectableText(font, text, TextRect.text_color, x, y)
        self.text.rect.center = self.rect.center

    def draw(self, screen):
        super().draw(screen)
        self.text.draw(screen)
Example #3
0
class ResourceRow:
    """A single line of colored text within a ResourceBlock (itself within the sidebar) representing a single resource"""
    def __init__(self, x, y, resource, color):
        self.resource = resource
        self.color = color
        self.num_resource = 0  # always start with zero of a resource
        self.text = SelectableText(
            large_font, self.resource + ': ' + str(self.num_resource),
            self.color, x, y)

    def check_for_mouse(self, mouse_pos):
        return self.text.check_for_mouse(mouse_pos)

    # change the value of this Row's resource to new
    def update(self, new):
        self.num_resource = new
        self.text.text = self.resource + ': ' + str(self.num_resource)
        # make sure to re-render text
        self.text.render()

    def draw(self, screen):
        self.text.draw(screen)
Example #4
0
class ResourceCounter:
    """A colored number for each resource representing how much has been selected
    along with up / down arrows to change how much is selected"""

    arrow_size_modifier = 0.3
    arrow_separation = 0.3
    arrow_color = common.BLACK

    font_x_offset = 0.15  # centering the font intuitively looks off-center :\
    font_y_offset = 0.1

    min_value = 0
    max_value = 15

    arrow_color = common.BLACK

    def __init__(self, x, y, resource, font):
        self.resource = resource
        self.font = font

        # counter number initialization
        self.num = SelectableText(font, '0', resource.value, 0, 0)

        font_height = get_font_height(font)
        font_width = get_font_width(font)
        # store this center location long-term for re-centering
        self.num_center = (int(x + ResourceCounter.font_x_offset * font_width),
                           int(y +
                               ResourceCounter.font_y_offset * font_height))
        self.num.rect.center = self.num_center

        # arrow initialization
        arrow_size = int(font_height * ResourceCounter.arrow_size_modifier)
        arrow_offset = int(font_height / 2 +
                           font_height * ResourceCounter.arrow_separation)
        self.up_arrow = Triangle(x, y - arrow_offset, arrow_size,
                                 ResourceCounter.arrow_color)
        self.down_arrow = Triangle(x,
                                   y + arrow_offset,
                                   arrow_size,
                                   ResourceCounter.arrow_color,
                                   pointed_up=False)

        # collision rects for detecting mouse / clicks
        self.up_arrow_collision = pygame.rect.Rect(0, 0, arrow_size,
                                                   arrow_size)
        self.up_arrow_collision.center = (x, y - arrow_offset)
        self.down_arrow_collision = pygame.rect.Rect(0, 0, arrow_size,
                                                     arrow_size)
        self.down_arrow_collision.center = (x, y + arrow_offset)

    def check_for_mouse(self, mouse_pos, mouse_click):
        """"Checks if the mouse is close enough to either arrows to highlight them,
        and if there was a click updates the counter (assuming bounds not passed)"""
        if self.up_arrow_collision.collidepoint(mouse_pos):
            # mouse is near the up arrow
            self.up_arrow.color = common.WHITE
            if mouse_click:
                cur_val = int(self.num.text)
                new_val = cur_val + 1

                # bounds checking
                if new_val <= ResourceCounter.max_value:
                    if cur_val == 9:
                        # need to re-initialize text obj for centering
                        self.num = SelectableText(self.font, str(new_val),
                                                  self.resource.value, 0, 0)
                        self.num.rect.center = self.num_center

                    else:
                        self.num.text = str(new_val)
                        self.num.deselect()

            # up arrow is being moused over, so down arrow shouldn't be selected
            self.down_arrow.color = ResourceCounter.arrow_color

        elif self.down_arrow_collision.collidepoint(mouse_pos):
            # mouse is near the down arrow
            self.down_arrow.color = common.WHITE
            if mouse_click:
                cur_val = int(self.num.text)
                new_val = cur_val - 1
                if new_val >= ResourceCounter.min_value:
                    if cur_val == 10:
                        # need to re-initialize text obj for centering
                        self.num = SelectableText(self.font, str(new_val),
                                                  self.resource.value, 0, 0)
                        self.num.rect.center = self.num_center

                    else:
                        self.num.text = str(cur_val - 1)
                        self.num.deselect()

            # down arrow is being moused over, so up arrow shouldn't be selected
            self.up_arrow.color = ResourceCounter.arrow_color

        else:
            # mouse is away; deselect all
            self.up_arrow.color = ResourceCounter.arrow_color
            self.down_arrow.color = ResourceCounter.arrow_color

    def draw(self, screen):
        self.up_arrow.draw(screen)
        self.num.draw(screen)
        self.down_arrow.draw(screen)
Example #5
0
class TBox(Rect):
    """Base class for all interactive, boxed prompts which require
    the user to select resource or some number of resources, including
    their own resources and those of other players"""

    color = common.BROWN
    width = 400
    height = 300

    font_type = 'graph-35.ttf'
    font_size = 18

    prompt_box_height = 40
    prompt_box_offset = height / 10

    # response boxes consist of OK, CANCEL boxes
    response_box_height = 40
    response_box_width = 90
    response_box_y_offset = height * 9 / 10

    ok_box_x_offset = width / 3
    lone_ok_box_x_offset = width / 2  # if there is no cancel button
    cancel_box_x_offset = width * 2 / 3

    error_text_color = common.BLACK
    error_text_y_offset = height * 7 / 10

    def __init__(self, x, y, prompt, allow_cancel):
        super().__init__(TBox.color, TBox.height, TBox.width, (x, y))

        self.x = x

        self.font = pygame.font.Font(TBox.font_type, TBox.font_size)

        # setup prompt
        prompt_width = get_font_width(self.font) * len(prompt)
        self.prompt = TextRect(x, self.rect.y + TBox.prompt_box_offset,
                               prompt_width, TBox.prompt_box_height, prompt,
                               self.font)

        # setup response buttons
        if allow_cancel:
            self.ok = TextRect(self.rect.left + TBox.ok_box_x_offset,
                               self.rect.top + TBox.response_box_y_offset,
                               TBox.response_box_width,
                               TBox.response_box_height, 'OK', self.font)
            self.cancel = TextRect(self.rect.left + TBox.cancel_box_x_offset,
                                   self.rect.top + TBox.response_box_y_offset,
                                   TBox.response_box_width,
                                   TBox.response_box_height, 'CANCEL',
                                   self.font)
        else:
            self.ok = TextRect(self.rect.left + TBox.lone_ok_box_x_offset,
                               self.rect.top + TBox.response_box_y_offset,
                               TBox.response_box_width,
                               TBox.response_box_height, 'OK', self.font)
            self.cancel = None

        # text for if the user does something bad and should be scolded
        self.error_text = None

    def check_for_mouse(self, mouse_pos, mouse_click):
        """Checks if the mouse is over any of the response buttons. Additionally
        checks for mouse click and will return what the user is trying to do"""
        if self.ok.text.check_for_mouse(mouse_pos):
            self.ok.text.select()
            if mouse_click:
                return TBoxState.OK
        elif self.cancel:
            if self.cancel.text.check_for_mouse(mouse_pos):
                self.cancel.text.select()

                if mouse_click:
                    return TBoxState.CANCEL

        return TBoxState.CONTINUE

    def error(self, text):
        self.error_text = SelectableText(self.font, text,
                                         TBox.error_text_color, 0, 0)
        self.error_text.rect.center = (self.x,
                                       self.rect.y + TBox.error_text_y_offset)

    def draw(self, screen):
        super().draw(screen)
        self.prompt.draw(screen)
        self.ok.draw(screen)
        if self.cancel:
            self.cancel.draw(screen)
        if self.error_text:
            self.error_text.draw(screen)
Example #6
0
class OtherPlayerView:
    """The players view of other players in the game"""
    def __init__(self, username, color, large_font, small_font,
                 large_font_height, small_font_height, x, y):
        self.username = username
        self.color = color

        self.small_font = small_font
        self.small_font_height = small_font_height

        self.name_text = SelectableText(large_font, self.username + ':',
                                        self.color, x, y)

        self.x = x
        self.y = y + large_font_height

        self.victory_point_text = None
        self.dev_card_text = None
        self.knights_played_text = None
        self.update({'vp': 0, 'dev': 0, 'knights': 22})

    # updates the text under player based on the dictionary passed
    def update(self, fields):
        y = self.y
        self.victory_point_text = SelectableText(
            self.small_font, 'Victory Points: ' + str(fields['vp']),
            self.color, self.x, y)
        y += self.small_font_height
        self.dev_card_text = SelectableText(self.small_font,
                                            'Dev Cards: ' + str(fields['dev']),
                                            self.color, self.x, y)
        y += self.small_font_height
        self.knights_played_text = SelectableText(
            self.small_font, 'Knights Played: ' + str(fields['knights']),
            self.color, self.x, y)

    # deselect all text associated with this player
    def deselect(self):
        text_items = [
            self.name_text, self.victory_point_text, self.dev_card_text,
            self.knights_played_text
        ]
        for item in text_items:
            item.deselect()

    # select all text associated with this player
    def select(self):
        text_items = [
            self.name_text, self.victory_point_text, self.dev_card_text,
            self.knights_played_text
        ]
        for item in text_items:
            item.select()

    def check_for_mouse(self, mouse_pos):
        selected = False
        text_items = [
            self.name_text, self.victory_point_text, self.dev_card_text,
            self.knights_played_text
        ]
        for item in text_items:
            if item.rect.collidepoint(mouse_pos):
                selected = True
        if selected:
            return self
        else:
            self.deselect()
            return None

    def draw(self, screen):
        self.name_text.draw(screen)
        self.victory_point_text.draw(screen)
        self.dev_card_text.draw(screen)
        self.knights_played_text.draw(screen)
Example #7
0
class SideBar:
    """All the info to be displayed at the side of the screen"""
    x = 875  # left side of the bar
    y = 0  # top of the bar
    background = MAROON
    font_type = 'graph-35.ttf'
    large_font_size = 18
    small_font_size = 15
    normal_header_text_color = WHITE
    normal_text_color = BLACK
    chars_per_line = 15

    def __init__(self, num_players):
        # font stuff
        self.large_font = pygame.font.Font(SideBar.font_type,
                                           SideBar.large_font_size)
        self.small_font = pygame.font.Font(SideBar.font_type,
                                           SideBar.small_font_size)
        self.large_font_height = get_font_height(self.large_font)
        self.small_font_height = get_font_height(self.small_font)

        # now begin adding Text items to the SideBar from the top to the bottom
        self.player_header = SelectableText(self.large_font, 'Players: ',
                                            SideBar.normal_header_text_color,
                                            SideBar.x, SideBar.y)
        self.cur_player_top = SideBar.y + self.large_font_height
        self.players = []

        # players can't be added yet, so skip down and create everything else
        self.cur_top = self.cur_player_top + (self.large_font_height + 3 * self.small_font_height)  \
                                           * num_players

        # resources are the first thing after the players
        self.resources_header = SelectableText(
            self.large_font, 'Resources: ', SideBar.normal_header_text_color,
            SideBar.x, self.cur_top)
        self.cur_top += self.large_font_height
        self.resources = ResourceBlock(SideBar.x, self.cur_top)
        self.cur_top += 5 * self.large_font_height  # 5 for the number of different resources

        # next come the development cards
        self.cards_header = SelectableText(self.large_font, 'Dev Cards: ',
                                           SideBar.normal_header_text_color,
                                           SideBar.x, self.cur_top)
        self.cur_top += self.large_font_height
        self.cards = self.create_cards()

        # then the actions a user can take when it is their turn
        self.action_header = SelectableText(self.large_font, 'Actions: ',
                                            SideBar.normal_header_text_color,
                                            SideBar.x, self.cur_top)
        self.cur_top += self.large_font_height
        self.actions = self.create_actions()

        # finally, create the box that will be in the background
        box_width = SideBar.chars_per_line * get_font_width(self.large_font)
        self.box = NonCenteredRect(SideBar.background,
                                   self.cur_top - SideBar.y, box_width,
                                   SideBar.x, SideBar.y)

    # create the 4 different development cards
    def create_cards(self):
        cards = []
        cards.append(
            SelectableText(self.large_font, 'Knight: 0',
                           SideBar.normal_text_color, SideBar.x, self.cur_top))
        self.cur_top += self.large_font_height
        cards.append(
            SelectableText(self.large_font, 'Rd. Builder: 0',
                           SideBar.normal_text_color, SideBar.x, self.cur_top))
        self.cur_top += self.large_font_height
        cards.append(
            SelectableText(self.large_font, 'V. Point: 0',
                           SideBar.normal_text_color, SideBar.x, self.cur_top))
        self.cur_top += self.large_font_height
        cards.append(
            SelectableText(self.large_font, 'Monopoly: 0',
                           SideBar.normal_text_color, SideBar.x, self.cur_top))
        self.cur_top += self.large_font_height
        return cards

    # create the __ different actions a user can take on their turn
    def create_actions(self):
        actions = []
        actions.append(
            SelectableText(self.large_font, 'Buy Road',
                           SideBar.normal_text_color, SideBar.x, self.cur_top))
        self.cur_top += self.large_font_height
        actions.append(
            SelectableText(self.large_font, 'Buy Sett.',
                           SideBar.normal_text_color, SideBar.x, self.cur_top))
        self.cur_top += self.large_font_height
        actions.append(
            SelectableText(self.large_font, 'Buy City',
                           SideBar.normal_text_color, SideBar.x, self.cur_top))
        self.cur_top += self.large_font_height
        actions.append(
            SelectableText(self.large_font, 'Buy Dev Card',
                           SideBar.normal_text_color, SideBar.x, self.cur_top))
        self.cur_top += self.large_font_height
        actions.append(
            SelectableText(self.large_font, 'Use Dev Card',
                           SideBar.normal_text_color, SideBar.x, self.cur_top))
        self.cur_top += self.large_font_height
        actions.append(
            SelectableText(self.large_font, 'Trade', SideBar.normal_text_color,
                           SideBar.x, self.cur_top))
        self.cur_top += self.large_font_height
        return actions

    # add a player and their associated info to the sidebar under the Players section
    def add_player(self, username, color):
        self.players.append(
            OtherPlayerView(username, color, self.large_font, self.small_font,
                            self.large_font_height, self.small_font_height,
                            SideBar.x, self.cur_player_top))
        self.cur_player_top += self.large_font_height + 3 * self.small_font_height

    # select among players
    def select_player(self, mouse_pos):
        self.select_common(self.players, mouse_pos)

    # select among resources
    def select_resource(self, mouse_pos):
        self.select_common(self.resources.resources, mouse_pos)

    # select among development cards
    def select_card(self, mouse_pos):
        self.select_common(self.cards, mouse_pos)

    # select among player actions
    def select_action(self, mouse_pos):
        self.select_common(self.actions, mouse_pos)

    # utility for selection
    # if the mouse is between 2 text items, they will both try to be highlighted
    # this must be prevented by taking count of all items that think they are selected
    # and only actually going through with the selection for one of them
    def select_common(self, category, mouse_pos):
        selected = []
        for item in category:
            selection = item.check_for_mouse(mouse_pos)
            if selection:
                selected.append(selection)

        if len(selected) < 2:
            # either 1 thing selected or none
            for item in selected:
                item.select()
        else:
            # 2 (possibly more, but I hope this is not possible) possible selections
            selected[0].select()
            for item in selected[1:]:
                item.deselect()

    def deselect(self, category):
        for item in category:
            item.deselect()

    def draw(self, screen):
        self.box.draw(screen)

        self.player_header.draw(screen)
        for player in self.players:
            player.draw(screen)

        self.resources_header.draw(screen)
        self.resources.draw(screen)

        self.cards_header.draw(screen)
        for card in self.cards:
            card.draw(screen)

        self.action_header.draw(screen)
        for action in self.actions:
            action.draw(screen)