Пример #1
0
class ATMMenu(ATMState):
    def __init__(self):
        super(ATMMenu, self).__init__()
        self.make_buttons()

    def set_next(self, next_state):
        self.beep()
        self.next = next_state
        self.done = True

    def make_buttons(self):
        self.buttons = ButtonGroup()
        self.labels = []
        buttons = [
            ("Balance Inquiry", "ACCOUNTSCREEN", (34, 450)),
            ("Deposit", "DEPOSIT", (34, 580)),
            ("Withdrawal", "WITHDRAWAL", (1278, 450)),
            ("Cash Advance", "ADVANCE", (1278, 580)),
            ("Exit", "", (1278, 840)),
        ]
        for text, next_state_name, topleft in buttons:
            callback = self.set_next
            bound = []
            if text == "Exit":
                callback = self.back_to_lobby
                bound = [pg.K_ESCAPE]
            Button((topleft, (88, 65)), self.buttons, args=next_state_name, call=callback, bindings=bound)
            if topleft[0] == 34:
                rect_pos = {"midleft": (topleft[0] + 115, topleft[1] + 32)}
            else:
                rect_pos = {"midright": (topleft[0] - 27, topleft[1] + 32)}
            label = Label(self.font, 36, text, "white", rect_pos, bg="blue2")
            self.labels.append(label)
        title = Label(
            self.font,
            48,
            "Select Transaction Type",
            "white",
            {"midtop": (self.screen_rect.centerx, self.screen_rect.top + 80)},
        )
        self.labels.append(title)

    def back_to_lobby(self, *args):
        self.beep()
        self.quit = True

    def get_event(self, event, scale):
        self.buttons.get_event(event)
        if event.type == pg.QUIT:
            self.back_to_lobby()

    def update(self, surface, keys, current, dt, scale, player):
        self.buttons.update(tools.scaled_mouse_pos(scale))
        self.draw(surface)

    def draw(self, surface):
        surface.fill(pg.Color("blue2"))
        for label in self.labels:
            label.draw(surface)
Пример #2
0
class ATMMenu(ATMState):
    def __init__(self):
        super(ATMMenu, self).__init__()
        self.make_buttons()

    def set_next(self, next_state):
        self.beep()
        self.next = next_state
        self.done = True

    def make_buttons(self):
        self.buttons = ButtonGroup()
        self.labels = []
        buttons = [("Balance Inquiry", "ACCOUNTSCREEN", (34, 450)),
                   ("Deposit", "DEPOSIT", (34, 580)),
                   ("Withdrawal", "WITHDRAWAL", (1278, 450)),
                   ("Cash Advance", "ADVANCE", (1278, 580)),
                   ("Exit", "", (1278, 840))]
        for text, next_state_name, topleft in buttons:
            callback = self.set_next
            bound = []
            if text == "Exit":
                callback = self.back_to_lobby
                bound = [pg.K_ESCAPE]
            Button((topleft, (88, 65)),
                   self.buttons,
                   args=next_state_name,
                   call=callback,
                   bindings=bound)
            if topleft[0] == 34:
                rect_pos = {"midleft": (topleft[0] + 115, topleft[1] + 32)}
            else:
                rect_pos = {"midright": (topleft[0] - 27, topleft[1] + 32)}
            label = Label(self.font, 36, text, "white", rect_pos, bg="blue2")
            self.labels.append(label)
        title = Label(
            self.font, 48, "Select Transaction Type", "white",
            {"midtop": (self.screen_rect.centerx, self.screen_rect.top + 80)})
        self.labels.append(title)

    def back_to_lobby(self, *args):
        self.beep()
        self.quit = True

    def get_event(self, event, scale):
        self.buttons.get_event(event)
        if event.type == pg.QUIT:
            self.back_to_lobby()

    def update(self, surface, keys, current, dt, scale, player):
        self.buttons.update(tools.scaled_mouse_pos(scale))
        self.draw(surface)

    def draw(self, surface):
        surface.fill(pg.Color("blue2"))
        for label in self.labels:
            label.draw(surface)
Пример #3
0
class AccountScreen(ATMState):
    def __init__(self):
        super(AccountScreen, self).__init__()
        self.buttons = ButtonGroup()
        Button(((1278, 840), (88, 65)), self.buttons, call=self.back_to_menu)

    def back_to_menu(self, *args):
        self.beep()
        self.next = "MAINMENU"
        self.done = True

    def get_event(self, event, scale):
        self.buttons.get_event(event)
        if event.type == pg.QUIT:
            self.back_to_menu()
        elif event.type == pg.KEYUP:
            if event.key == pg.K_ESCAPE:
                self.back_to_menu()

    def update(self, surface, keys, current, dt, scale, player):
        self.buttons.update(tools.scaled_mouse_pos(scale))
        self.labels = []

        balance = "Account Balance: ${:.2f}".format(player.account.balance)
        self.labels.append(
            Label(self.font, 48, balance, "white", {"topleft": (200, 150)}))
        self.labels.append(
            Label(self.font, 36, "Menu", "white",
                  {"midright": (1278 - 27, 840 + 32)}))
        top = 300
        for transaction, amount in player.account.transactions[::-1]:
            label1 = Label(self.font, 36, transaction, "white",
                           {"topleft": (200, top)})
            label2 = Label(self.font, 36, "${:.2f}".format(amount), "white",
                           {"topright": (1220, top)})
            self.labels.extend([label1, label2])
            top += label1.rect.height
        self.draw(surface)

    def draw(self, surface):
        surface.fill(pg.Color("blue2"))
        for label in self.labels:
            label.draw(surface)
Пример #4
0
class AccountScreen(ATMState):
    def __init__(self):
        super(AccountScreen, self).__init__()
        self.buttons = ButtonGroup()
        Button(((1278, 840), (88, 65)), self.buttons, call=self.back_to_menu)

    def back_to_menu(self, *args):
        self.beep()
        self.next = "MAINMENU"
        self.done = True

    def get_event(self, event, scale):
        self.buttons.get_event(event)
        if event.type == pg.QUIT:
            self.back_to_menu()
        elif event.type == pg.KEYUP:
            if event.key == pg.K_ESCAPE:
                self.back_to_menu()

    def update(self, surface, keys, current, dt, scale, player):
        self.buttons.update(tools.scaled_mouse_pos(scale))
        self.labels = []

        balance = "Account Balance: ${:.2f}".format(player.account.balance)
        self.labels.append(Label(self.font, 48, balance, "white", {"topleft": (200, 150)}))
        self.labels.append(Label(self.font, 36, "Menu", "white", {"midright": (1278 - 27, 840 + 32)}))
        top = 300
        for transaction, amount in player.account.transactions[::-1]:
            label1 = Label(self.font, 36, transaction, "white", {"topleft": (200, top)})
            label2 = Label(self.font, 36, "${:.2f}".format(amount), "white", {"topright": (1220, top)})
            self.labels.extend([label1, label2])
            top += label1.rect.height
        self.draw(surface)

    def draw(self, surface):
        surface.fill(pg.Color("blue2"))
        for label in self.labels:
            label.draw(surface)
Пример #5
0
class GameWin(_State):
    def __init__(self, controller):
        super(GameWin, self).__init__(controller)
        font = prog_constants.FONTS["Fixedsys500c"]
        color = constants.LOW_LIGHT_GREEN
        sr = constants.SCREEN_RECT
        self.labels = [
            Label(font, 48, "Congratulations", color,
                  {"midtop": (sr.centerx, 200)}),
            Label(font, 48, "Your cities are saved", color,
                  {"midtop": (sr.centerx, 300)})
        ]
        self.buttons = ButtonGroup()
        NeonButton((373, 630), "OK", 32, self.to_title, None, self.buttons)

    def to_title(self, *args):
        self.done = True
        self.next = "TITLE"
        self.player.clear_save()

    def startup(self, persistent):
        self.persist = persistent
        self.player = self.persist["player"]

    def get_event(self, event, scale):
        self.buttons.get_event(event)

    def update(self, surface, keys, current_time, dt, scale):
        self.buttons.update(scaled_mouse_pos(scale))

        self.draw(surface)

    def draw(self, surface):
        surface.fill(constants.BACKGROUND_BASE)
        for label in self.labels:
            label.draw(surface)
        self.buttons.draw(surface)
Пример #6
0
class MessageScreen(ATMState):
    """
    Displays a message from the previous state to the screen
    and returns to the ATM Menu.
    """
    def __init__(self):
        super(MessageScreen, self).__init__()
        self.buttons = ButtonGroup()
        Button(((1278, 840), (88, 65)), self.buttons, call=self.back_to_menu)

    def startup(self, persistent):
        self.persist = persistent
        msg = self.persist["message"]
        self.label = Label(self.font, 36, msg, "white",
                           {"center": self.screen_rect.center})
        self.exit_label = Label(self.font, 36, "OK", "white",
                                {"midright": (1251, 872)})

    def update(self, surface, keys, current, dt, scale, player):
        self.buttons.update(tools.scaled_mouse_pos(scale))
        self.draw(surface)

    def back_to_menu(self, *args):
        self.beep()
        self.next = "MAINMENU"
        self.done = True

    def get_event(self, event, scale):
        self.buttons.get_event(event)
        if event.type == pg.KEYDOWN:
            if event.key == pg.K_RETURN:
                self.back_to_menu()

    def draw(self, surface):
        surface.fill(pg.Color("blue2"))
        self.label.draw(surface)
        self.exit_label.draw(surface)
Пример #7
0
class MessageScreen(ATMState):
    """
    Displays a message from the previous state to the screen
    and returns to the ATM Menu.
    """

    def __init__(self):
        super(MessageScreen, self).__init__()
        self.buttons = ButtonGroup()
        Button(((1278, 840), (88, 65)), self.buttons, call=self.back_to_menu)

    def startup(self, persistent):
        self.persist = persistent
        msg = self.persist["message"]
        self.label = Label(self.font, 36, msg, "white", {"center": self.screen_rect.center})
        self.exit_label = Label(self.font, 36, "OK", "white", {"midright": (1251, 872)})

    def update(self, surface, keys, current, dt, scale, player):
        self.buttons.update(tools.scaled_mouse_pos(scale))
        self.draw(surface)

    def back_to_menu(self, *args):
        self.beep()
        self.next = "MAINMENU"
        self.done = True

    def get_event(self, event, scale):
        self.buttons.get_event(event)
        if event.type == pg.KEYDOWN:
            if event.key == pg.K_RETURN:
                self.back_to_menu()

    def draw(self, surface):
        surface.fill(pg.Color("blue2"))
        self.label.draw(surface)
        self.exit_label.draw(surface)
Пример #8
0
class WithdrawalScreen(ATMState):
    def __init__(self):
        super(WithdrawalScreen, self).__init__()
        self.title = Label(
            self.font,
            36,
            "Enter Withdrawal Amount",
            "white",
            {"midtop": (self.screen_rect.centerx, self.screen_rect.top + 300)},
        )

        self.make_textbox()
        self.make_enter_button()

    def make_enter_button(self):
        self.buttons = ButtonGroup()
        self.labels = []
        Button(((1278, 840), (88, 65)), self.buttons, bindings=[pg.K_RETURN])
        rect_pos = {"midright": (1251, 872)}
        label = Label(self.font, 36, "Enter", "white", rect_pos, bg="blue2")
        self.labels.append(label)

    def make_textbox(self):
        rect = (self.screen_rect.centerx - 200, self.screen_rect.top + 600, 400, 200)
        self.textbox = TextBox(
            rect,
            outline_color=pg.Color("white"),
            color=pg.Color("blue2"),
            font=pg.font.Font(self.font, 36),
            font_color=pg.Color("white"),
        )
        self.textbox.accepted = string.digits
        self.dollar_sign = Label(self.font, 36, "$", "white", {"midright": (rect[0] - 5, rect[1] + 100)})
        # update needed to set textbox.render_area
        self.textbox.update()

    def leave_message(self, msg):
        self.make_textbox()
        self.persist["message"] = msg
        self.next = "MESSAGESCREEN"
        self.done = True

    def back_to_menu(self):
        self.beep()
        self.next = "MAINMENU"
        self.done = True

    def get_event(self, event, scale):
        self.textbox.get_event(event, tools.scaled_mouse_pos(scale))
        self.buttons.get_event(event)
        if event.type == pg.QUIT:
            self.back_to_menu()
        elif event.type == pg.KEYUP:
            if event.key == pg.K_ESCAPE:
                self.back_to_menu()

    def update(self, surface, keys, current, dt, scale, player):
        self.textbox.update()
        if not self.textbox.active:
            self.beep()
            try:
                amount = int(self.textbox.final)
            except ValueError:
                amount = 0
            if player.account.balance >= amount:
                player.account.withdrawal(amount)
                player.cash += amount
                self.leave_message("${:.2f} Withdrawn".format(amount))
            else:
                msg = "Insufficient Funds for Withdrawal"
                self.leave_message(msg)
        self.buttons.update(tools.scaled_mouse_pos(scale))
        text = "You have ${:.2f} available for withdrawal".format(player.account.balance)
        self.dyna_label = Label(
            self.font, 36, text, "white", {"midtop": (self.screen_rect.centerx, self.screen_rect.top + 80)}
        )
        self.draw(surface)

    def draw(self, surface):
        surface.fill(pg.Color("blue2"))
        self.title.draw(surface)
        self.dollar_sign.draw(surface)
        self.textbox.draw(surface)
        for label in self.labels:
            label.draw(surface)
        self.dyna_label.draw(surface)
Пример #9
0
class WithdrawalScreen(ATMState):
    def __init__(self):
        super(WithdrawalScreen, self).__init__()
        self.title = Label(
            self.font, 36, "Enter Withdrawal Amount", "white",
            {"midtop": (self.screen_rect.centerx, self.screen_rect.top + 300)})

        self.make_textbox()
        self.make_enter_button()

    def make_enter_button(self):
        self.buttons = ButtonGroup()
        self.labels = []
        Button(((1278, 840), (88, 65)), self.buttons, bindings=[pg.K_RETURN])
        rect_pos = {"midright": (1251, 872)}
        label = Label(self.font, 36, "Enter", "white", rect_pos, bg="blue2")
        self.labels.append(label)

    def make_textbox(self):
        rect = (self.screen_rect.centerx - 200, self.screen_rect.top + 600,
                400, 200)
        self.textbox = TextBox(rect,
                               outline_color=pg.Color("white"),
                               color=pg.Color("blue2"),
                               font=pg.font.Font(self.font, 36),
                               font_color=pg.Color("white"))
        self.textbox.accepted = string.digits
        self.dollar_sign = Label(self.font, 36, "$", "white",
                                 {"midright": (rect[0] - 5, rect[1] + 100)})
        #update needed to set textbox.render_area
        self.textbox.update()

    def leave_message(self, msg):
        self.make_textbox()
        self.persist["message"] = msg
        self.next = "MESSAGESCREEN"
        self.done = True

    def back_to_menu(self):
        self.beep()
        self.next = "MAINMENU"
        self.done = True

    def get_event(self, event, scale):
        self.textbox.get_event(event, tools.scaled_mouse_pos(scale))
        self.buttons.get_event(event)
        if event.type == pg.QUIT:
            self.back_to_menu()
        elif event.type == pg.KEYUP:
            if event.key == pg.K_ESCAPE:
                self.back_to_menu()

    def update(self, surface, keys, current, dt, scale, player):
        self.textbox.update()
        if not self.textbox.active:
            self.beep()
            try:
                amount = int(self.textbox.final)
            except ValueError:
                amount = 0
            if player.account.balance >= amount:
                player.account.withdrawal(amount)
                player.cash += amount
                self.leave_message("${:.2f} Withdrawn".format(amount))
            else:
                msg = "Insufficient Funds for Withdrawal"
                self.leave_message(msg)
        self.buttons.update(tools.scaled_mouse_pos(scale))
        text = "You have ${:.2f} available for withdrawal".format(
            player.account.balance)
        self.dyna_label = Label(
            self.font, 36, text, "white",
            {"midtop": (self.screen_rect.centerx, self.screen_rect.top + 80)})
        self.draw(surface)

    def draw(self, surface):
        surface.fill(pg.Color("blue2"))
        self.title.draw(surface)
        self.dollar_sign.draw(surface)
        self.textbox.draw(surface)
        for label in self.labels:
            label.draw(surface)
        self.dyna_label.draw(surface)
Пример #10
0
class StatsMenu(data.state.State):
    """
    This state allows the player to choose which game's stats they
    want to view or return to the lobby.
    """
    name = "stats_menu"

    def __init__(self):
        super(StatsMenu, self).__init__()
        self.font = prepare.FONTS["Saniretro"]
        self.title = None
        self.buttons = ButtonGroup()
        self.labels = []
        self.lines = []
        self.use_music_handler = False

    def collect_games_with_stats(self):
        for name, scene in self.controller.query_all_states().items():
            if hasattr(scene, 'initialize_stats'):
                yield name

    def make_labels(self):
        self.labels = []
        cash = self.player.cash
        balance = self.player.account_balance
        assets = cash + balance
        starting_cash = prepare.MONEY
        profit = assets - starting_cash
        label_info = [("Cash", cash, 110),
                      ("Account", balance, 150),
                      ("Assets", assets, 198),
                      ("Starting Cash", -starting_cash, 238),
                      ("Profit", profit, 283)]
        left = 500
        right = 900
        for name, value, topy in label_info:
            label1 = Label(self.font, 36, name, "white",
                                  {"topleft": (left, topy)})
            color = "darkgreen" if value >= 0 else "darkred"
            label2 = Label(self.font, 36, "{:.2f}".format(value),
                                  color, {"topright": (right, topy)})
            self.labels.extend([label1, label2])
        self.lines = [((left, 193), (right, 193)),
                          ((left, 280), (right, 280))]

    def make_buttons(self, games, screen_rect, col=2):
        spacer_x = 20
        spacer_y = 20
        start_y = 410
        start_x = (screen_rect.w-NeonButton.width*col-spacer_x*(col-1))//2
        buttons = ButtonGroup()
        for i,game in enumerate(games):
            y,x = divmod(i, col)
            pos = (start_x+x*(NeonButton.width+spacer_x),
                   start_y+y*(NeonButton.height+spacer_y))
            button = NeonButton(pos, game, self.view_game_stats, game, buttons)
        pos = (screen_rect.centerx-(NeonButton.width//2),
               screen_rect.bottom-(NeonButton.height+10))
        NeonButton(pos, "Lobby", self.back_to_lobby, None, buttons,
                   bindings=[pg.K_ESCAPE])
        return buttons

    def back_to_lobby(self, *args):
        self.done = True
        self.next = "lobby"

    def view_game_stats(self, game):
        self.persist["current_game_stats"] = game
        self.next = "stats_screen"
        self.done = True

    def startup(self, current_time, persistent):
        screen_rect = pg.Rect((0, 0), prepare.RENDER_SIZE)
        self.title = Label(self.font, 64, "Statistics", "darkred",
                          {"midtop":(screen_rect.centerx, screen_rect.top+10)})
        self.start_time = current_time
        self.persist = persistent
        self.player = self.persist["casino_player"]
        games = self.collect_games_with_stats()
        self.buttons = self.make_buttons(games, screen_rect, 3)
        self.make_labels()

    def get_event(self, event, scale=(1,1)):
        if event.type == pg.QUIT:
            self.done = True
            self.next = "lobby"
        self.buttons.get_event(event)

    def draw(self, surface):
        surface.fill(prepare.BACKGROUND_BASE)
        self.title.draw(surface)
        self.buttons.draw(surface)
        for label in self.labels:
            label.draw(surface)
        for line in self.lines:
            pg.draw.line(surface, pg.Color("white"), *line)

    def update(self, surface, keys, current_time, dt, scale):
        mouse_pos = tools.scaled_mouse_pos(scale)
        self.buttons.update(mouse_pos)
        self.draw(surface)
Пример #11
0
class Keno(data.state.State):
    """Class to represent a casino game."""
    show_in_lobby = True
    name = 'keno'

    def __init__(self):
        super(Keno, self).__init__()
        self.screen_rect = pg.Rect((0, 0), prepare.RENDER_SIZE)
        self.game_started = False
        self.font = prepare.FONTS["Saniretro"]
        self.advisor = KenoAdvisor()
        self.mock_label = Label(self.font, 64, 'KENO [WIP]', 'gold3',
                                {'center': (672, 102)})

        b_width = 360
        b_height = 90
        side_margin = 10
        w = self.screen_rect.right - (b_width + side_margin)
        h = self.screen_rect.bottom - (b_height + 15)
        self.buttons = ButtonGroup()
        NeonButton((w, h), "Lobby", self.back_to_lobby, None, self.buttons)

        self.turns = 16
        self.play_max_active = False

        ball_path = os.path.join('resources', 'keno', 'balls', '64x64',
                                 'sheet.png')
        ball_sheet = pg.image.load(ball_path).convert_alpha()
        self.balls = tools.strip_from_sheet(ball_sheet, (0, 0), (64, 64), 10,
                                            8)

        self.keno_card = KenoCard(self.balls)
        #self.keno_card = KenoCard() -- no ball graphics

        self.prev_spot_count = 0

        self.pay_table = PayTable(self.keno_card)
        self.pay_table.update(0)

        self.round_history = RoundHistory(self.keno_card)

        self.alert = None

        self.quick_picking = Action(
            pg.Rect(370, 760, 150, 75),
            Label(self.font, 32, 'QUICK PICK', 'gold3', {'center': (0, 0)}),
            self.activate_quick_pick)

        self.betting = Action(
            pg.Rect(682, 760, 150, 75),
            Label(self.font, 32, 'BET 1', 'gold3', {'center': (0, 0)}),
            self.activate_bet)

        self.clearing = Action(
            pg.Rect(526, 760, 150, 75),
            Label(self.font, 32, 'CLEAR', 'gold3', {'center': (0, 0)}),
            self.activate_clear)

        self.playing = Action(
            pg.Rect(838, 760, 156, 75),
            Label(self.font, 32, 'PLAY', 'gold3', {'center': (0, 0)}),
            self.activate_play)

        self.playing_max = Action(
            pg.Rect(838, 840, 156, 75),
            Label(self.font, 32, 'PLAY MAX', 'gold3', {'center': (0, 0)}),
            self.activate_playmax)

        self.actions = {
            'quick pick': self.quick_picking,
            'betting': self.betting,
            'clearing': self.clearing,
            'playing': self.playing,
            'playing max': self.playing_max,
        }

        self.gui_widgets = {
            'title': self.mock_label,
            'card': self.keno_card,
            'quick_pick': self.quick_picking,
            'play': self.playing,
            'play_max': self.playing_max,
            'pay_table': self.pay_table,
            'round_history': self.round_history,
            'balance': None,
            'bet_action': None,
            'clear': None,
            'bet': None,
            'won': None,
            'spot': None,
        }

    @staticmethod
    def initialize_stats():
        """Return OrderedDict suitable for use in game stats

        :return: collections.OrderedDict
        """
        stats = OrderedDict([("games played", 0)])
        return stats

    def activate_quick_pick(self):
        self.keno_card.reset()
        numbers = pick_numbers(10)

        for number in numbers:
            self.keno_card.toggle_owned(number)

    def activate_bet(self):
        log.debug("betting activated")

        try:
            self.make_bet(1)
        except InsufficientFundsException:
            self.handle_insufficient_funds()

        spot_count = self.keno_card.spot_count
        self.pay_table.update(spot_count, self.pot._balance)

    def activate_clear(self):
        log.debug("clear activated")
        self.keno_card.ready_play(clear_all=True)
        self.clear_bet()
        self.round_history.clear()

    def validate_configuration(self):
        if not self.pot.paid and self.pot._balance > 0:

            try:
                self.pot.repeat_bet()
                return True
            except InsufficientFundsException:
                self.handle_insufficient_funds()
                return False

        elif not self.pot.paid:
            self.alert = NoticeWindow(self.screen_rect.center,
                                      "Please place your bet.")
            return False

        spot_count = self.keno_card.spot_count
        if spot_count <= 0:
            self.alert = NoticeWindow(self.screen_rect.center,
                                      "Please pick your spots.")
            return False

        return True

    def handle_insufficient_funds(self):
        self.pot.clear_bet(with_payout=False)
        self.play_max_active = False
        self.turns = 0
        self.alert_insufficient_funds()

    def alert_insufficient_funds(self):
        self.alert = NoticeWindow(self.screen_rect.center,
                                  "You cannot afford that bet.")

    def activate_play(self):

        if not self.validate_configuration():
            return

        numbers = pick_numbers(20)
        log.debug("pick: {}".format(numbers))

        self.keno_card.ready_play()
        self.keno_card.current_pick = numbers
        for number in numbers:
            self.keno_card.toggle_hit(number)

        self.play_game()

    def activate_playmax(self):
        self.round_history.clear()

        if not self.validate_configuration():
            return

        self.continue_playmax()
        self.play_game()

    def continue_playmax(self):
        log.debug("turns={0}".format(self.turns))

        try:
            self.pot.repeat_bet()
            self.play_max_active = True
            numbers = pick_numbers(20)

            self.keno_card.ready_play()
            self.keno_card.current_pick = numbers
            for number in numbers:
                self.keno_card.toggle_hit(number)

            self.turns -= 1
            if self.turns <= 0:
                self.play_max_active = False
                self.turns = 16

        except InsufficientFundsException:
            self.turns = 0
            self.handle_insufficient_funds()
            self.play_max_active = False

    def make_bet(self, amount):
        try:
            self.pot.change_bet(amount)
        except InsufficientFundsException:
            self.handle_insufficient_funds()

    def clear_bet(self):
        self.pot.clear_bet()

    def result(self, spot, hit):

        paytable = PAYTABLE[spot]
        payment = 0.0
        for entry in paytable:
            if entry[0] == hit:
                payment = entry[1]

            if payment > 0.0:
                break

        self.pot.payout(payment)
        self.casino_player.cash = self.wallet.balance

    def back_to_lobby(self, *args):
        self.game_started = False
        self.done = True
        self.next = "lobby"

    def startup(self, current_time, persistent):
        """This method will be called each time the state resumes."""
        self.persist = persistent
        #This is the object that represents the user.
        self.casino_player = self.persist["casino_player"]
        self.casino_player.current_game = self.name
        self.gui_widgets['bet_action'] = self.betting
        self.gui_widgets['clear'] = self.clearing

        self.wallet = Wallet(self.casino_player.cash)
        self.pot = Pot(self.wallet)

        self.casino_player.increase("games played", 1)

    def play_game(self):
        spot_count = self.keno_card.spot_count
        hit_count = self.keno_card.hit_count
        self.result(spot_count, hit_count)
        self.round_history.update(spot_count, hit_count)

    def get_event(self, event, scale=(1, 1)):
        """This method will be called for each event in the event queue
        while the state is active.
        """
        if event.type == pg.QUIT and not self.alert:
            self.done = True
            self.next = "lobby"
        elif event.type == pg.MOUSEBUTTONDOWN and not self.alert:
            #Use tools.scaled_mouse_pos(scale, event.pos) for correct mouse
            #position relative to the pygame window size.
            event_pos = tools.scaled_mouse_pos(scale, event.pos)
            log.info(event_pos)  #[for debugging positional items]

            for action in self.actions.values():
                action.execute(event_pos)

            self.keno_card.update(event_pos)

            spot_count = self.keno_card.spot_count
            if spot_count != self.prev_spot_count:
                self.pay_table.update(spot_count, self.pot._balance)
                self.prev_spot_count = spot_count

        if not self.alert:
            self.buttons.get_event(event)
        self.alert and self.alert.get_event(event)

    def draw(self, surface):
        """This method handles drawing/blitting the state each frame."""
        surface.fill(prepare.FELT_GREEN)

        self.buttons.draw(surface)
        self.advisor.draw(surface)
        for widget in self.gui_widgets.values():
            if widget:
                widget.draw(surface)

        if self.alert and not self.alert.done:
            self.alert.draw(surface)

    def update(self, surface, keys, current_time, dt, scale):
        """
        This method will be called once each frame while the state is active.
        Surface is a reference to the rendering surface which will be scaled
        to pygame's display surface, keys is the return value of the last call
        to pygame.key.get_pressed. current_time is the number of milliseconds
        since pygame was initialized. dt is the number of milliseconds since
        the last frame.
        """

        self.advisor.update(dt)

        if self.play_max_active:
            self.continue_playmax()
            self.play_game()

        total_text = "Balance:  ${}".format(self.wallet.balance)

        self.gui_widgets['balance'] = Label(self.font, 48, total_text, "gold3",
                                            {"topleft": (24, 760)})

        bet_text = "Bet: ${}".format(self.pot._balance)
        self.gui_widgets['bet'] = Label(self.font, 48, bet_text, "gold3",
                                        {"topleft": (24, 760 + 48)})

        won_text = "Won: ${}".format(self.pot.won)
        self.gui_widgets['won'] = Label(self.font, 48, won_text, "gold3",
                                        {"topleft": (24, 760 + 48 + 48)})

        spot_count = self.keno_card.spot_count
        spot_text = "Spot: {}".format(spot_count)
        self.gui_widgets['spot'] = Label(self.font, 48, spot_text, "gold3",
                                         {"topleft": (1036, 760)})

        mouse_pos = tools.scaled_mouse_pos(scale)
        self.buttons.update(mouse_pos)
        if self.alert:
            self.alert.update(mouse_pos)
            if self.alert.done:
                self.alert = None

        self.draw(surface)
Пример #12
0
class HighScores(_State):
    def __init__(self, controller):
        super(HighScores, self).__init__(controller)

    def startup(self, persistent):
        self.persist = persistent
        self.labels = []
        score = self.persist["player"].cash
        current_highs = self.load_high_scores()
        if len(current_highs) < 10:
            current_highs.append(("", score))
        elif current_highs[0][1] < score:
            current_highs[0] = ("", score)
        current_highs = sorted(current_highs, key=lambda x: x[1], reverse=True)
        self.make_high_scores_table(current_highs, score)
        self.labels.append(
            Label(prog_constants.FONTS["Fixedsys500c"], 64, "High Scores",
                  constants.LOW_LIGHT_GREEN, {"midtop": (464, 20)}))
        self.buttons = ButtonGroup()
        NeonButton((373, 630), "OK", 32, self.to_title, None, self.buttons)

    def make_high_scores_table(self, high_scores, score):
        font = prog_constants.FONTS["Fixedsys500c"]
        color = constants.LOW_LIGHT_GREEN
        left1, left2, top = 350, 500, 100
        placed = False
        self.name_label = None
        self.flasher = None
        self.textbox = None
        for i, info in enumerate(high_scores):
            name, high_score = info
            name_label = Label(font, 32, name, color,
                               {"topleft": (left1, top)})
            if high_score == score and not placed and not name:
                placed = True
                label = FlashingText(font, 32, "{}".format(high_score), color,
                                     {"topleft": (left2, top)}, 500)
                self.flasher = label
                self.name_label = name_label
                self.name_index = i
                validator = lambda x: len(x) == 3
                box_size = (96, 32)
                self.textbox = Textbox2({"topleft": (left1 - 4, top + 2)},
                                        call=self.enter_name,
                                        box_size=box_size,
                                        validator=validator,
                                        font_path=font)
            else:
                label = Label(font, 32, "{}".format(high_score), color,
                              {"topleft": (left2, top)})

            self.labels.extend([label, name_label])
            top += 40
        self.high_scores = high_scores

    def load_high_scores(self):
        p = os.path.join(".", "data", "games", "missiles", "resources",
                         "high_scores.json")
        try:
            with open(p, "r") as f:
                return sorted(json.load(f), key=lambda x: x[1])
        except IOError:
            return []

    def save_scores(self, scores):
        p = os.path.join(".", "data", "games", "missiles", "resources",
                         "high_scores.json")
        with open(p, "w") as f:
            json.dump(scores, f)

    def to_title(self, *args):
        if self.textbox is None:
            self.save_scores(self.high_scores)
            self.done = True
            self.next = "TITLE"

    def enter_name(self, name):
        self.name_label.set_text(name)
        score = self.high_scores[self.name_index][1]
        self.high_scores[self.name_index] = name, score
        self.textbox = None

    def get_event(self, event, scale):
        if self.textbox is not None:
            self.textbox.get_event(event)
        self.buttons.get_event(event)

    def update(self, surface, keys, current_time, dt, scale):
        if self.flasher is not None:
            self.flasher.update(current_time)
        if self.textbox is not None:
            self.textbox.buffer = "".join(
                (x.upper() for x in self.textbox.buffer))
            self.textbox.update(dt)
        self.buttons.update(scaled_mouse_pos(scale))
        self.draw(surface)

    def draw(self, surface):
        surface.fill(constants.BACKGROUND_BASE)
        for label in self.labels:
            label.draw(surface)
        if self.textbox is not None:
            self.textbox.draw(surface)
        self.buttons.draw(surface)
Пример #13
0
class PlayerTurn(GutsState):
    def __init__(self):
        super(PlayerTurn, self).__init__()

    def startup(self, game):
        self.game = game
        self.current_player = self.game.deal_queue[self.game.current_player_index]
        self.player_buttons = ButtonGroup()
        self.animations = pg.sprite.Group()
        self.timer  = 0
        self.time_limit = 600

        if self.current_player is self.game.dealer:
            self.next = "Show Cards"
        else:
            self.next = "Player Turn"
        if self.current_player is self.game.player:
            x, y = self.screen_rect.centerx -120, 695
            NeonButton((x, y - 55), "Stay", self.stay, None, self.player_buttons)
            NeonButton((x, y + 55), "Pass", self.stay_out, None, self.player_buttons)
            if self.current_player is self.game.dealer:
                stays = [x for x in self.game.players if x.stayed]
                if not stays:
                    self.stay()
        else:
            self.current_player.play_hand(self.game)

    def toggle_player_buttons(self, boolean):
        for b in self.player_buttons:
            b.active = boolean
            b.visible = boolean

    def end_player_turn(self):
        self.done = True
        self.game.current_player_index += 1

    def stay(self, *args):
        self.current_player.stay()
        self.game.casino_player.increase("stays")
        self.animations.add(Task(self.end_player_turn, 1000))
        self.toggle_player_buttons(False)

    def stay_out(self, *args):
        self.current_player.stay_out()
        self.game.casino_player.increase("passes")
        self.animations.add(Task(self.end_player_turn, 1000))
        self.toggle_player_buttons(False)

    def update(self, dt, scale):
        mouse_pos = tools.scaled_mouse_pos(scale)
        self.general_update(dt, mouse_pos)
        if not self.window:
            self.timer += dt
            if self.current_player is not self.game.player:
                if self.timer > self.time_limit:
                    self.done = True
            self.player_buttons.update(mouse_pos)

    def draw(self, surface):
        surface.fill(prepare.FELT_GREEN)
        for player in self.game.players:
            player.draw(surface)
        self.game.draw(surface)
        self.buttons.draw(surface)
        self.player_buttons.draw(surface)
        self.money_icon.draw(surface)
        self.draw_advisor(surface)
        if self.window:
            self.window.draw(surface)

    def get_event(self, event):
        if self.window:
            self.window.get_event(event)
        else:
            self.buttons.get_event(event)
            self.player_buttons.get_event(event)
            self.advisor_button.get_event(event)
Пример #14
0
class PlayerTurn(BlackjackState):
    def __init__(self):
        super(PlayerTurn, self).__init__()
        pos = (self.screen_rect.right - (NeonButton.width + 10),
               self.screen_rect.bottom - (NeonButton.height + 15))
        self.make_buttons()
        self.lobby_button = NeonButton(pos,
                                       "Lobby",
                                       self.back_to_lobby,
                                       None,
                                       self.buttons,
                                       bindings=[pg.K_ESCAPE])
        self.last_click = 0

    def play_deal_sound(self):
        choice(self.game.deal_sounds).play()

    def make_buttons(self):
        side_margin = 10
        vert_space = 12
        left = self.screen_rect.right - (NeonButton.width + side_margin)
        top = self.screen_rect.bottom - (
            (NeonButton.height * 5) + vert_space * 5)
        self.hit_button = NeonButton((left, top), "Hit", self.hit_click)
        top += NeonButton.height + vert_space
        self.stand_button = NeonButton((left, top), "Stand", self.stand)
        top += NeonButton.height + vert_space
        self.double_down_button = NeonButton((left, top), "Double",
                                             self.double_down)
        top += NeonButton.height + vert_space
        self.split_button = NeonButton((left, top), "Split", self.split_hand)
        self.buttons = ButtonGroup(self.hit_button, self.stand_button,
                                   self.double_down_button, self.split_button)

    def hit_click(self, *args):
        self.hit(self.game.current_player_hand)

    def hit(self, hand):
        """Draw a card from deck and add to hand."""
        self.play_deal_sound()
        self.game.player.add_slot(hand)
        card = self.game.deck.draw_card()
        card.face_up = True
        destination = hand.slots[-1]
        dest_x, dest_y = destination.topleft
        hand.cards.append(card)
        dur = get_distance(destination.center, card.pos) * 20 // card.speed
        ani = Animation(x=dest_x, y=dest_y, duration=dur, round_values=True)
        ani.start(card.rect)
        self.animations.add(ani)

    def stand(self, *args):
        """Player is done with this hand."""
        self.game.current_player_hand.final = True

    def double_down(self, *args):
        """
        Double player's bet on the hand, deal one
        more card and finalize hand.
        """
        hand = self.game.current_player_hand
        bet = hand.bet.get_chip_total()
        bet_chips = self.game.player.chip_pile.withdraw_chips(bet)
        hand.bet.add_chips(bet_chips)
        self.hit(hand)
        hand.final = True

    def split_hand(self, *args):
        """
        Split player's hand into two hands, adjust hand locations
        and deal a new card to both hands.
        """
        player = self.game.player
        hand = self.game.current_player_hand
        bet = hand.bet.get_chip_total()

        hand.slots = hand.slots[:-1]
        move = ((self.screen_rect.left + 50) - hand.slots[0].left, 0)
        player.move_hands(move)
        p_slot = player.hands[-1].slots[0]
        hand_slot = p_slot.move(int(prepare.CARD_SIZE[0] * 3.5), 0)
        card = hand.cards.pop()
        new_hand = Hand(hand_slot.topleft, [card],
                        player.chip_pile.withdraw_chips(bet))
        new_hand.slots = [hand_slot]
        card.rect.topleft = hand_slot.topleft
        player.hands.append(new_hand)
        player.add_slot(new_hand)

        self.play_deal_sound()
        self.game.player.add_slot(hand)
        card1 = self.game.deck.draw_card()
        dest = hand.slots[-1]
        dest_x, dest_y = dest.topleft
        card1.face_up = True
        hand.cards.append(card1)
        ani = Animation(x=dest_x, y=dest_y, duration=1000, round_values=True)
        ani.start(card1.rect)

        card2 = self.game.deck.draw_card()
        dest = new_hand.slots[-1]
        dest_x, dest_y = dest.topleft
        card2.face_up = True
        new_hand.cards.append(card2)
        ani2 = Animation(x=dest_x,
                         y=dest_y,
                         duration=1000,
                         delay=500,
                         round_values=True)
        ani2.start(card2.rect)
        ani3 = Task(self.play_deal_sound, 1500)
        self.animations.add(ani, ani2, ani3)

    def startup(self, game):
        self.game = game
        self.animations = pg.sprite.Group()

    def get_event(self, event, scale):
        now = pg.time.get_ticks()
        span = now - self.last_click
        if event.type == pg.QUIT:
            self.back_to_lobby()
        if event.type == pg.MOUSEBUTTONUP:
            self.last_click = now
        self.game.get_event(event)
        if span > 300:
            if self.window:
                self.window.get_event(event)
            else:
                self.buttons.get_event(event)

    def update(self, surface, keys, current_time, dt, scale):
        mouse_pos = tools.scaled_mouse_pos(pg.mouse.get_pos(), scale)
        g = self.game
        g.update(dt, mouse_pos)

        self.split_button.active = False
        self.split_button.visible = False
        self.double_down_button.active = False
        self.double_down_button.visible = False

        hand = g.current_player_hand
        hand_score = hand.best_score()
        if hand_score is None:
            hand.busted = True
            hand.final = True
        chip_total = g.player.chip_pile.get_chip_total()
        bet = hand.bet.get_chip_total()

        if len(hand.cards) == 2 and len(g.player.hands) < 2:
            c1 = hand.card_values[hand.cards[0].value]
            c2 = hand.card_values[hand.cards[1].value]
            if c1 == c2 and chip_total >= bet:
                self.split_button.active = True
                self.split_button.visible = True
        if len(hand.cards) == 2:
            if hand_score == 21:
                hand.blackjack = True
                hand.final = True
            elif chip_total >= bet:
                self.double_down_button.active = True
                self.double_down_button.visible = True

        if hand.final:
            if all([hand.final for hand in g.player.hands]):
                if not self.animations:
                    g.dealer.hand.cards[0].face_up = True
                    self.next = "Dealer Turn"
                    self.done = True
            else:
                next_hand = [x for x in g.player.hands if not x.final][0]
                g.current_player_hand = next_hand
        if self.window:
            self.window.update(mouse_pos)
            if self.window.done:
                self.window = None
        else:
            self.buttons.update(mouse_pos)
            self.animations.update(dt)

    def draw_hand_frame(self, surface):
        hand = self.game.current_player_hand
        rects = [x for x in hand.slots]
        pg.draw.rect(surface, pg.Color("gold3"),
                     hand.slots[0].unionall(rects).inflate(8, 8), 3)

    def draw(self, surface):
        g = self.game
        surface.fill(prepare.FELT_GREEN)
        for label in g.labels:
            label.draw(surface)
        g.player.draw_hand_bets(surface)
        g.player.chip_pile.draw(surface)
        g.chip_total_label.draw(surface)
        g.dealer.draw_hand(surface)
        g.deck.draw(surface)
        g.chip_rack.draw(surface)
        self.buttons.draw(surface)
        self.lobby_button.draw(surface)
        g.player.draw_hands(surface)
        self.draw_advisor(surface)
        self.draw_hand_frame(surface)
        self.game.player.chip_pile.draw(surface)
        self.window and self.window.draw(surface)
Пример #15
0
class ShowResults(GutsState):
    def __init__(self):
        super(ShowResults, self).__init__()
        self.buttons = ButtonGroup()
        pos = (self.screen_rect.right - (NeonButton.width + 10),
               self.screen_rect.bottom - (NeonButton.height + 10))
        self.lobby_button = NeonButton(pos,
                                       "Lobby",
                                       self.warn,
                                       None,
                                       self.buttons,
                                       bindings=[pg.K_ESCAPE])

    def make_player_buttons(self, free_ride):
        self.player_buttons = ButtonGroup()
        w, h = NeonButton.width, NeonButton.height
        sr = self.screen_rect
        pos = sr.centerx - (w // 2), sr.centery + 120
        text = "OK" if free_ride else "Ante Up"
        NeonButton(pos, text, self.new_game, None, self.player_buttons)

    def new_game(self, *args):
        self.game.game_over = True
        self.done = True
        self.next = "Betting"
        self.advisor.empty()

    def add_player_cash(self, amount):
        self.game.player.cash += amount

    def add_to_pot(self, amount):
        self.game.pot += amount

    def toggle_buttons(self, boolean):
        for button in self.player_buttons:
            button.active = boolean
            button.visible = boolean

    def cash_advance(self, amount):
        acct = self.game.casino_player.account
        acct.cash_advance(amount)
        self.add_player_cash(amount)

    def startup(self, game):
        self.game = game
        self.lobby_button.call = self.warn
        self.toggled = False
        self.alpha = 255
        self.labels = []
        self.blinkers = []
        self.calculated = False
        self.animations = pg.sprite.Group()

        stayers = [x for x in self.game.players if x.stayed]
        winners = self.game.get_winners()
        share = self.game.pot // len(winners)

        ani_duration = 2000
        self.free_ride = False

        for stayer in stayers:
            pos = stayer.name_label.rect.center
            dest = pos[0], pos[1] - 120
            cards_center = stayer.cards[0].rect.union(
                stayer.cards[1].rect).center
            if stayer not in winners:
                text = "${}".format(self.game.pot)
                color = "darkred"
                stayer.lost = self.game.pot
                self.free_ride = True
                dest = self.game.pot_label.rect.center
                if stayer is self.game.player:
                    pos = self.money_icon.rect.center
                    if self.game.player.cash < stayer.lost:
                        amount = stayer.lost - self.game.player.cash
                        self.cash_advance(amount)
                        msg = "You were forced to take a cash advance to cover your loss. Visit the ATM to view your account."
                        self.notice(msg)
                    self.add_player_cash(-stayer.lost)
                task = Task(self.add_to_pot, ani_duration, args=[stayer.lost])
                self.animations.add(task)
                lose_label = Blinker(self.font, 96, "Loser", color,
                                     {"center": cards_center}, 500)
                self.animations.add(
                    Task(self.blinkers.append, ani_duration,
                         args=[lose_label]))
            else:
                text = "${}".format(share)
                color = "darkgreen"
                stayer.won = share
                pos = self.game.pot_label.rect.center
                if stayer is self.game.player:
                    self.cha_ching.play()
                    dest = self.money_icon.rect.center
                    task = Task(self.add_player_cash,
                                ani_duration,
                                args=[share])
                    self.animations.add(task)
                win_label = Blinker(self.font, 96, "Winner", color,
                                    {"center": cards_center}, 500)
                self.animations.add(
                    Task(self.blinkers.append, ani_duration, args=[win_label]))
            label = Label(self.font,
                          128,
                          text,
                          color, {"center": pos},
                          bg=prepare.FELT_GREEN)
            label.image.set_colorkey(prepare.FELT_GREEN)
            self.labels.append(label)
            move = Animation(centerx=dest[0],
                             centery=dest[1],
                             duration=ani_duration,
                             round_values=True,
                             transition="in_quart")
            move.start(label.rect)
            self.animations.add(move)

        fader = Animation(alpha=0,
                          duration=ani_duration + 200,
                          round_values=True)
        fader.start(self)
        self.animations.add(fader)
        self.game.pot = 0

        self.make_player_buttons(self.free_ride)
        self.toggle_buttons(False)
        if self.free_ride:
            self.advice_texts = ["Press OK to play the next round"]
        else:
            self.advice_texts = [
                "Ante Up ${} to play again".format(self.game.bet)
            ]
        self.advice_texts.append("Press the Lobby button to exit")

    def fade_labels(self):
        for label in self.labels:
            label.image.set_alpha(self.alpha)

    def update(self, dt, scale):
        mouse_pos = tools.scaled_mouse_pos(scale)
        self.general_update(dt, mouse_pos)
        if not self.window:
            for blinker in self.blinkers:
                blinker.update(dt)
            self.player_buttons.update(mouse_pos)
            self.fade_labels()
            if self.alpha < 1 and not self.toggled:
                self.toggle_buttons(True)
                self.toggled = True
                for text in self.advice_texts:
                    self.advisor.queue_text(text, dismiss_after=3500)
                if not self.free_ride:
                    self.lobby_button.call = self.back_to_lobby

    def get_event(self, event):
        if self.window:
            self.window.get_event(event)
        else:
            self.buttons.get_event(event)
            self.player_buttons.get_event(event)
            self.advisor_button.get_event(event)

    def draw(self, surface):
        surface.fill(prepare.FELT_GREEN)
        self.game.draw(surface)
        for p in self.game.players:
            p.draw(surface)
        self.money_icon.draw(surface)
        self.buttons.draw(surface)
        self.player_buttons.draw(surface)
        for label in self.labels:
            label.draw(surface)
        for blinker in self.blinkers:
            blinker.draw(surface)
        self.draw_advisor(surface)
        if self.window:
            self.window.draw(surface)
Пример #16
0
class PlayerTurn(GutsState):
    def __init__(self):
        super(PlayerTurn, self).__init__()

    def startup(self, game):
        self.game = game
        self.current_player = self.game.deal_queue[
            self.game.current_player_index]
        self.player_buttons = ButtonGroup()
        self.animations = pg.sprite.Group()
        self.timer = 0
        self.time_limit = 600

        if self.current_player is self.game.dealer:
            self.next = "Show Cards"
        else:
            self.next = "Player Turn"
        if self.current_player is self.game.player:
            x, y = self.screen_rect.centerx - 120, 695
            NeonButton((x, y - 55), "Stay", self.stay, None,
                       self.player_buttons)
            NeonButton((x, y + 55), "Pass", self.stay_out, None,
                       self.player_buttons)
            if self.current_player is self.game.dealer:
                stays = [x for x in self.game.players if x.stayed]
                if not stays:
                    self.stay()
        else:
            self.current_player.play_hand(self.game)

    def toggle_player_buttons(self, boolean):
        for b in self.player_buttons:
            b.active = boolean
            b.visible = boolean

    def end_player_turn(self):
        self.done = True
        self.game.current_player_index += 1

    def stay(self, *args):
        self.current_player.stay()
        self.game.casino_player.increase("stays")
        self.animations.add(Task(self.end_player_turn, 1000))
        self.toggle_player_buttons(False)

    def stay_out(self, *args):
        self.current_player.stay_out()
        self.game.casino_player.increase("passes")
        self.animations.add(Task(self.end_player_turn, 1000))
        self.toggle_player_buttons(False)

    def update(self, dt, scale):
        mouse_pos = tools.scaled_mouse_pos(scale)
        self.general_update(dt, mouse_pos)
        if not self.window:
            self.timer += dt
            if self.current_player is not self.game.player:
                if self.timer > self.time_limit:
                    self.done = True
            self.player_buttons.update(mouse_pos)

    def draw(self, surface):
        surface.fill(prepare.FELT_GREEN)
        for player in self.game.players:
            player.draw(surface)
        self.game.draw(surface)
        self.buttons.draw(surface)
        self.player_buttons.draw(surface)
        self.money_icon.draw(surface)
        self.draw_advisor(surface)
        if self.window:
            self.window.draw(surface)

    def get_event(self, event):
        if self.window:
            self.window.get_event(event)
        else:
            self.buttons.get_event(event)
            self.player_buttons.get_event(event)
            self.advisor_button.get_event(event)
Пример #17
0
class StartGame(GutsState):
    """Choose between starting a new game or view tutorial."""
    def __init__(self):
        super(StartGame, self).__init__()

    def startup(self, game):
        self.game = game
        sr = self.screen_rect
        title = Label(self.font,
                      128,
                      "Two-Card Guts",
                      "gold3", {"midtop": (sr.centerx, 5)},
                      bg=prepare.FELT_GREEN)
        title.image.set_alpha(160)
        title2 = Label(self.font,
                       96,
                       "${} Ante".format(self.game.bet),
                       "darkred", {"midtop": (sr.centerx, title.rect.bottom)},
                       bg=prepare.FELT_GREEN)
        title2.image.set_alpha(140)
        self.titles = [title, title2]
        self.player_buttons = ButtonGroup()
        w, h = NeonButton.width, NeonButton.height
        pos = sr.centerx - (w // 2), sr.centery - (h // 2)
        NeonButton(pos, "Ante Up", self.start_game, None, self.player_buttons)
        pos2 = sr.centerx - (w // 2), sr.centery + (h // 2) + 50
        self.tutorial_button = NeonButton(pos2, "Tutorial", self.to_tutorial,
                                          None, self.player_buttons)
        self.advisor.queue_text("Ante Up ${} to play".format(self.game.bet),
                                dismiss_after=2500)
        self.advisor.queue_text("Press Tutorial to learn how to play",
                                dismiss_after=2500)
        self.advisor.queue_text("Press the Lobby button to exit",
                                dismiss_after=2500)

    def start_game(self, *args):
        self.done = True
        self.next = "Betting"
        self.advisor.empty()

    def to_tutorial(self, *args):
        self.done = True
        self.next = "Tutorial"
        self.advisor.empty()

    def get_event(self, event):
        if self.window:
            self.window.get_event(event)
        else:
            self.buttons.get_event(event)
            self.player_buttons.get_event(event)
            self.advisor_button.get_event(event)

    def update(self, dt, scale):
        mouse_pos = tools.scaled_mouse_pos(scale)
        self.general_update(dt, mouse_pos)
        if not self.window:
            self.player_buttons.update(mouse_pos)

    def draw(self, surface):
        surface.fill(prepare.FELT_GREEN)
        for title in self.titles:
            title.draw(surface)
        self.buttons.draw(surface)
        self.player_buttons.draw(surface)
        self.money_icon.draw(surface)
        self.draw_advisor(surface)
        if self.window:
            self.window.draw(surface)
Пример #18
0
class GutsState(object):
    font = prepare.FONTS["Saniretro"]
    deal_sounds = [prepare.SFX["cardshove{}".format(x)] for x in (1, 3, 4)]
    flip_sounds = [prepare.SFX["cardplace{}".format(x)] for x in (2, 3, 4)]
    cha_ching = prepare.SFX["coins"]
    screen_rect = pg.Rect((0, 0), prepare.RENDER_SIZE)
    money_icon = MoneyIcon((0, screen_rect.bottom - 75))
    draw_group = pg.sprite.Group()
    move_animations = pg.sprite.Group()
    advisor = Advisor(draw_group, move_animations)
    advisor.active = True
    advisor_back = prepare.GFX["advisor_back"]
    advisor_front = prepare.GFX["advisor_front"]
    advisor_back_dim = prepare.GFX["advisor_back_dim"]
    advisor_front_dim = prepare.GFX["advisor_front_dim"]
    advisor_active = True
    window = None

    def __init__(self):
        self.done = False
        self.quit = False
        self.next = None
        rect = self.advisor_back.get_rect().union(
            self.advisor_front.get_rect())
        self.advisor_button = Button(rect, call=self.toggle_advisor)
        self.buttons = ButtonGroup()
        pos = (self.screen_rect.right - (NeonButton.width + 10),
               self.screen_rect.bottom - (NeonButton.height + 10))
        lobby_button = NeonButton(pos,
                                  "Lobby",
                                  self.back_to_lobby,
                                  None,
                                  self.buttons,
                                  bindings=[pg.K_ESCAPE])
        self.animations = pg.sprite.Group()

    def warn(self, *args):
        warning = "Exiting the game will abandon the current pot!"
        GutsState.window = WarningWindow(self.screen_rect.center, warning,
                                         self.leave)

    def notice(self, msg):
        GutsState.window = NoticeWindow(self.screen_rect.center, msg)

    def back_to_lobby(self, *args):
        if self.game.pot:
            self.warn()
        else:
            self.leave()

    def leave(self):
        self.quit = True
        self.advisor.empty()

    def toggle_advisor(self, *args):
        GutsState.advisor_active = not GutsState.advisor_active

    def draw_advisor(self, surface):
        if self.advisor_active:
            surface.blit(self.advisor_back, (0, 0))
            self.draw_group.draw(surface)
            surface.blit(self.advisor_front, (0, 0))
        else:
            surface.blit(self.advisor_back_dim, (0, 0))
            surface.blit(self.advisor_front_dim, (0, 0))

    def general_update(self, dt, mouse_pos):
        if self.window:
            self.window.update(mouse_pos)
            if self.window.done:
                GutsState.window = None
        else:
            self.advisor_button.update(mouse_pos)
            self.animations.update(dt)
            self.buttons.update(mouse_pos)
            self.money_icon.update(self.game.player.cash)
            self.advisor_button.update(mouse_pos)
            if self.advisor_active:
                self.move_animations.update(dt)
            self.game.update()

    def startup(self, game):
        self.game = game

    def update(self, dt, scale):
        pass

    def get_event(self, event):
        pass

    def draw(self, surface):
        pass

    def play_deal_sound(self):
        choice(self.deal_sounds).play()

    def play_flip_sound(self):
        choice(self.flip_sounds).play()

    def play_stay_sound(self):
        choice(self.stay_sounds).play()

    def play_pass_sound(self):
        choice(self.fold_sounds).play()
Пример #19
0
class AdvanceScreen(ATMState):
    def __init__(self):
        super(AdvanceScreen, self).__init__()
        self.make_textbox()
        self.title = Label(
            self.font,
            36,
            "Enter Cash Advance Amount",
            "white",
            {"midtop": (self.screen_rect.centerx, self.screen_rect.top + 300)},
        )
        self.make_enter_button()

    def make_dynamic_labels(self, player):
        text = "The maximum advance is ${:.2f}".format(player.account.max_advance)
        dyna1 = Label(self.font, 36, text, "white", {"midtop": (self.screen_rect.centerx, self.screen_rect.top + 80)})
        fee_text = "A {}% fee will be added to the advance amount".format(player.account.lending_rate * 100)
        dyna2 = Label(self.font, 36, fee_text, "white", {"midtop": (self.screen_rect.centerx, dyna1.rect.bottom + 10)})
        self.dynamic_labels = [dyna1, dyna2]

    def make_enter_button(self):
        self.button_labels = []
        self.buttons = ButtonGroup()
        Button(((1278, 840), (88, 65)), self.buttons, bindings=[pg.K_RETURN])
        rect_pos = {"midright": (1251, 872)}
        label = Label(self.font, 36, "Enter", "white", rect_pos, bg="blue2")
        self.button_labels.append(label)

    def make_textbox(self):
        rect = (self.screen_rect.centerx - 200, self.screen_rect.top + 600, 400, 200)
        self.textbox = TextBox(
            rect,
            outline_color=pg.Color("white"),
            color=pg.Color("blue2"),
            font=pg.font.Font(self.font, 36),
            font_color=pg.Color("white"),
        )
        self.textbox.accepted = string.digits
        self.dollar_sign = Label(self.font, 36, "$", "white", {"midright": (rect[0] - 5, rect[1] + 100)})
        self.textbox.update()

    def leave_message(self, msg):
        self.make_textbox()
        self.beep()
        self.persist["message"] = msg
        self.next = "MESSAGESCREEN"
        self.done = True

    def back_to_menu(self):
        self.beep()
        self.next = "MAINMENU"
        self.done = True

    def get_event(self, event, scale):
        self.textbox.get_event(event, tools.scaled_mouse_pos(scale))
        self.buttons.get_event(event)
        if event.type == pg.QUIT:
            self.back_to_menu()
        elif event.type == pg.KEYUP:
            if event.key == pg.K_ESCAPE:
                self.back_to_menu()

    def update(self, surface, keys, current, dt, scale, player):
        self.textbox.update()
        if not self.textbox.active:
            self.beep()
            try:
                amount = int(self.textbox.final)
            except ValueError:
                amount = 0
            if amount > player.account.max_advance:
                amount = 0
                self.leave_message("You are not authorized for this amount")
            else:
                player.account.cash_advance(amount)
                player.cash += amount
                msg = "${:.2f} Dispensed".format(amount)
                self.leave_message(msg)
        self.buttons.update(tools.scaled_mouse_pos(scale))
        self.make_dynamic_labels(player)
        self.draw(surface)

    def draw(self, surface):
        surface.fill(pg.Color("blue2"))
        self.title.draw(surface)
        self.dollar_sign.draw(surface)
        self.textbox.draw(surface)
        for label in self.dynamic_labels:
            label.draw(surface)
        for b_label in self.button_labels:
            b_label.draw(surface)
Пример #20
0
class GutsState(object):
    font = prepare.FONTS["Saniretro"]
    deal_sounds = [prepare.SFX["cardshove{}".format(x)] for x in (1,3,4)]
    flip_sounds = [prepare.SFX["cardplace{}".format(x)] for x in (2,3,4)]
    cha_ching = prepare.SFX["coins"]
    screen_rect = pg.Rect((0,0), prepare.RENDER_SIZE)
    money_icon = MoneyIcon((0, screen_rect.bottom - 75))
    draw_group = pg.sprite.Group()
    move_animations = pg.sprite.Group()
    advisor = Advisor(draw_group, move_animations)
    advisor.active = True
    advisor_back = prepare.GFX["advisor_back"]
    advisor_front = prepare.GFX["advisor_front"]
    advisor_back_dim = prepare.GFX["advisor_back_dim"]
    advisor_front_dim = prepare.GFX["advisor_front_dim"]
    advisor_active = True
    window = None
    def __init__(self):
        self.done = False
        self.quit = False
        self.next = None
        rect = self.advisor_back.get_rect().union(self.advisor_front.get_rect())
        self.advisor_button = Button(rect, call=self.toggle_advisor)
        self.buttons = ButtonGroup()
        pos = (self.screen_rect.right-(NeonButton.width+10),
               self.screen_rect.bottom-(NeonButton.height+10))
        lobby_button = NeonButton(pos, "Lobby", self.back_to_lobby, None, self.buttons, bindings=[pg.K_ESCAPE])
        self.animations = pg.sprite.Group()

    def warn(self, *args):
        warning = "Exiting the game will abandon the current pot!"
        GutsState.window = WarningWindow(self.screen_rect.center, warning, self.leave)

    def notice(self, msg):
        GutsState.window = NoticeWindow(self.screen_rect.center, msg)

    def back_to_lobby(self, *args):
        if self.game.pot:
            self.warn()
        else:
            self.leave()

    def leave(self):
        self.quit = True
        self.advisor.empty()

    def toggle_advisor(self, *args):
        GutsState.advisor_active = not GutsState.advisor_active

    def draw_advisor(self, surface):
        if self.advisor_active:
            surface.blit(self.advisor_back, (0, 0))
            self.draw_group.draw(surface)
            surface.blit(self.advisor_front, (0, 0))
        else:
            surface.blit(self.advisor_back_dim, (0, 0))
            surface.blit(self.advisor_front_dim, (0, 0))

    def general_update(self, dt, mouse_pos):
        if self.window:
            self.window.update(mouse_pos)
            if self.window.done:
                GutsState.window = None
        else:
            self.advisor_button.update(mouse_pos)
            self.animations.update(dt)
            self.buttons.update(mouse_pos)
            self.money_icon.update(self.game.player.cash)
            self.advisor_button.update(mouse_pos)
            if self.advisor_active:
                self.move_animations.update(dt)
            self.game.update()


    def startup(self, game):
        self.game = game

    def update(self, dt, scale):
        pass

    def get_event(self, event):
        pass

    def draw(self, surface):
        pass

    def play_deal_sound(self):
        choice(self.deal_sounds).play()

    def play_flip_sound(self):
        choice(self.flip_sounds).play()

    def play_stay_sound(self):
        choice(self.stay_sounds).play()

    def play_pass_sound(self):
        choice(self.fold_sounds).play()
Пример #21
0
class LobbyScreen(data.state.State):
    """
    This state represents the casino lobby where the player can choose
    which game they want to play or view their game statistics. This is also
    the exit point for the game.
    """
    name = "lobby"
    per_page = 6

    def __init__(self):
        super(LobbyScreen, self).__init__()
        self.game = None
        self.chip_curtain = None  # Created on startup
        self.animations = pg.sprite.Group()

    def collect_game_scenes(self):
        all_scenes = self.controller.query_all_states()
        games = OrderedDict()
        for name, scene in all_scenes.items():
            if hasattr(scene, 'show_in_lobby'):
                games[name] = scene
        return games

    def update_screen_buttons(self, games):
        screen_rect = pg.Rect((0, 0), prepare.RENDER_SIZE)
        number_of_pages = int(math.ceil(len(games) / float(self.per_page)))
        self.loop_length = prepare.RENDER_SIZE[0] * number_of_pages
        self.game_buttons = self.make_game_pages(games, screen_rect,
                                                 self.per_page)
        nav_buttons = self.make_navigation_buttons(screen_rect)
        main_buttons = self.make_main_buttons(screen_rect)
        self.buttons = ButtonGroup(nav_buttons, main_buttons)

    def make_game_pages(self, games, screen_rect, per):
        games = list(games.keys())
        groups = (games[i:i + per] for i in range(0, len(games), per))
        columns = 3
        width, height = GameButton.width, GameButton.height
        spacer_x, spacer_y = 50, 80
        start_x = (screen_rect.w - width * columns - spacer_x *
                   (columns - 1)) // 2
        start_y = screen_rect.top + 105
        step_x, step_y = width + spacer_x, height + spacer_y
        buttons = ButtonGroup()
        for offset, group in enumerate(groups):
            offset *= prepare.RENDER_SIZE[0]
            for i, game in enumerate(group):
                y, x = divmod(i, columns)
                pos = (start_x + step_x * x + offset, start_y + step_y * y)
                GameButton(pos, game, self.change_state, buttons)
        return buttons

    def make_navigation_buttons(self, screen_rect):
        sheet = prepare.GFX["nav_buttons"]
        size = (106, 101)
        y = 790
        from_center = 15
        icons = tools.strip_from_sheet(sheet, (0, 0), size, 4)
        buttons = ButtonGroup()
        l_kwargs = {
            "idle_image": icons[0],
            "hover_image": icons[1],
            "call": self.scroll_page,
            "args": 1,
            "bindings": [pg.K_LEFT, pg.K_KP4]
        }
        r_kwargs = {
            "idle_image": icons[2],
            "hover_image": icons[3],
            "call": self.scroll_page,
            "args": -1,
            "bindings": [pg.K_RIGHT, pg.K_KP6]
        }
        left = Button(((0, y), size), buttons, **l_kwargs)
        left.rect.right = screen_rect.centerx - from_center
        right = Button(((0, y), size), buttons, **r_kwargs)
        right.rect.x = screen_rect.centerx + from_center
        return buttons

    def make_main_buttons(self, screen_rect):
        buttons = ButtonGroup()
        pos = (9, screen_rect.bottom - (NeonButton.height + 11))
        NeonButton(pos, "Credits", self.change_state, "credits", buttons)
        pos = (screen_rect.right - (NeonButton.width + 10),
               screen_rect.bottom - (NeonButton.height + 11))
        NeonButton(pos, "Stats", self.change_state, "stats_menu", buttons)
        pos = (screen_rect.centerx - (NeonButton.width // 2),
               screen_rect.bottom - (NeonButton.height + 11))
        NeonButton(pos,
                   "Exit",
                   self.exit_game,
                   None,
                   buttons,
                   bindings=[pg.K_ESCAPE])
        rect_style = (screen_rect.left, screen_rect.top, 150, 95)
        Button(rect_style,
               buttons,
               idle_image=prepare.GFX["atm_dim"],
               hover_image=prepare.GFX["atm_bright"],
               call=self.change_state,
               args="atm")
        return buttons

    def scroll_page(self, mag):
        if not self.animations:
            for game in self.game_buttons:
                self.normalize_scroll(game, mag)
                fx, fy = game.rect.x + prepare.RENDER_SIZE[0] * mag, game.rect.y
                ani = Animation(x=fx,
                                y=fy,
                                duration=350.0,
                                transition='in_out_quint',
                                round_values=True)
                ani.start(game.rect)
                self.animations.add(ani)
            prepare.SFX["cardplace4"].play()

    def normalize_scroll(self, game, mag):
        if game.rect.x < 0 and mag == -1:
            game.rect.x += self.loop_length
        elif game.rect.x >= prepare.RENDER_SIZE[0] and mag == 1:
            game.rect.x -= self.loop_length

    def startup(self, current_time, persistent):
        self.persist = persistent
        self.chip_curtain = ChipCurtain(None, **CURTAIN_SETTINGS)
        games = self.collect_game_scenes()
        self.update_screen_buttons(games)

    def exit_game(self, *args):
        with open(os.path.join("resources", "save_game.json"), "w") as f:
            json.dump(self.persist["casino_player"].stats, f)
        self.done = True
        self.quit = True

    def change_state(self, next_state):
        self.done = True
        self.next = next_state

    def get_event(self, event, scale=(1, 1)):
        if self.game:
            self.game.get_event(event, scale)
        elif event.type == pg.QUIT:
            self.exit_game()
        else:
            self.buttons.get_event(event)
            self.game_buttons.get_event(event)

    def update(self, surface, keys, current_time, dt, scale):
        if self.game:
            self.game.update(surface, keys, current_time, dt, scale)
            if self.game.done:
                self.game.cleanup()
                self.game = None
        else:
            mouse_pos = tools.scaled_mouse_pos(scale)
            self.chip_curtain.update(dt)
            self.buttons.update(mouse_pos)
            self.game_buttons.update(mouse_pos)
            self.animations.update(dt)
            self.draw(surface)

    def draw(self, surface):
        rect = surface.get_rect()
        surface.fill(prepare.BACKGROUND_BASE)
        self.chip_curtain.draw(surface)
        self.buttons.draw(surface)
        for button in self.game_buttons:
            if button.rect.colliderect(rect):
                button.draw(surface)
Пример #22
0
class AdvanceScreen(ATMState):
    def __init__(self):
        super(AdvanceScreen, self).__init__()
        self.make_textbox()
        self.title = Label(
            self.font, 36, "Enter Cash Advance Amount", "white",
            {"midtop": (self.screen_rect.centerx, self.screen_rect.top + 300)})
        self.make_enter_button()

    def make_dynamic_labels(self, player):
        text = "The maximum advance is ${:.2f}".format(
            player.account.max_advance)
        dyna1 = Label(
            self.font, 36, text, "white",
            {"midtop": (self.screen_rect.centerx, self.screen_rect.top + 80)})
        fee_text = "A {}% fee will be added to the advance amount".format(
            player.account.lending_rate * 100)
        dyna2 = Label(
            self.font, 36, fee_text, "white",
            {"midtop": (self.screen_rect.centerx, dyna1.rect.bottom + 10)})
        self.dynamic_labels = [dyna1, dyna2]

    def make_enter_button(self):
        self.button_labels = []
        self.buttons = ButtonGroup()
        Button(((1278, 840), (88, 65)), self.buttons, bindings=[pg.K_RETURN])
        rect_pos = {"midright": (1251, 872)}
        label = Label(self.font, 36, "Enter", "white", rect_pos, bg="blue2")
        self.button_labels.append(label)

    def make_textbox(self):
        rect = (self.screen_rect.centerx - 200, self.screen_rect.top + 600,
                400, 200)
        self.textbox = TextBox(rect,
                               outline_color=pg.Color("white"),
                               color=pg.Color("blue2"),
                               font=pg.font.Font(self.font, 36),
                               font_color=pg.Color("white"))
        self.textbox.accepted = string.digits
        self.dollar_sign = Label(self.font, 36, "$", "white",
                                 {"midright": (rect[0] - 5, rect[1] + 100)})
        self.textbox.update()

    def leave_message(self, msg):
        self.make_textbox()
        self.beep()
        self.persist["message"] = msg
        self.next = "MESSAGESCREEN"
        self.done = True

    def back_to_menu(self):
        self.beep()
        self.next = "MAINMENU"
        self.done = True

    def get_event(self, event, scale):
        self.textbox.get_event(event, tools.scaled_mouse_pos(scale))
        self.buttons.get_event(event)
        if event.type == pg.QUIT:
            self.back_to_menu()
        elif event.type == pg.KEYUP:
            if event.key == pg.K_ESCAPE:
                self.back_to_menu()

    def update(self, surface, keys, current, dt, scale, player):
        self.textbox.update()
        if not self.textbox.active:
            self.beep()
            try:
                amount = int(self.textbox.final)
            except ValueError:
                amount = 0
            if amount > player.account.max_advance:
                amount = 0
                self.leave_message("You are not authorized for this amount")
            else:
                player.account.cash_advance(amount)
                player.cash += amount
                msg = "${:.2f} Dispensed".format(amount)
                self.leave_message(msg)
        self.buttons.update(tools.scaled_mouse_pos(scale))
        self.make_dynamic_labels(player)
        self.draw(surface)

    def draw(self, surface):
        surface.fill(pg.Color("blue2"))
        self.title.draw(surface)
        self.dollar_sign.draw(surface)
        self.textbox.draw(surface)
        for label in self.dynamic_labels:
            label.draw(surface)
        for b_label in self.button_labels:
            b_label.draw(surface)
Пример #23
0
class TitleScreen(data.state.State):
    """
    Initial state of the game. Introduces the game and lets user load a
    saved game if there's one present.
    """
    name = "title_screen"

    def __init__(self):
        super(TitleScreen, self).__init__()
        self.screen_rect = pg.Rect((0, 0), prepare.RENDER_SIZE)
        self.marquees = []
        self.scrollers, self.marquees = self.make_titles()
        self.buttons = ButtonGroup()
        self.new_game, self.load_game = self.make_buttons()
        self.lights = self.make_spotlights()
        self.use_music_handler = False

    def make_spotlights(self):
        lights = pg.sprite.LayeredDirty()
        y = self.screen_rect.bottom + 20
        for i in range(1, 5):
            start = 0 if i % 2 else 0.5
            pos = (i * self.screen_rect.w / 5, y)
            spotlight.SpotLight(pos, 4, 140, start, lights)
        return lights

    def make_titles(self):
        font = prepare.FONTS["Saniretro"]
        scrollers = pg.sprite.Group()
        marquees = pg.sprite.Group()
        pos = {"right": 0, "centery": self.screen_rect.y + 123}
        Scroller(pos, prepare.GFX["pyrollers_shiny"], 0.6, scrollers)
        pos = {"center": (self.screen_rect.centerx, pos["centery"])}
        MarqueeFrame(pos, prepare.GFX["pyrollers_shiny"], 20, 120, marquees)
        pos = {"left": self.screen_rect.w, "centery": 370}
        Scroller(pos, prepare.GFX["casino_shiny"], -0.6, scrollers)
        pos = {"center": (self.screen_rect.centerx, pos["centery"])}
        MarqueeFrame(pos, prepare.GFX["casino_shiny"], 20, 120, marquees)
        return scrollers, marquees

    def make_buttons(self):
        x = self.screen_rect.centerx - (NeonButton.width // 2)
        y = 600
        new_game = NeonButton((x, y),
                              "New",
                              self.load_or_new,
                              False,
                              self.buttons,
                              visible=False)
        y = new_game.rect.bottom + 50
        load_game = NeonButton((x, y),
                               "Load",
                               self.load_or_new,
                               True,
                               self.buttons,
                               visible=False)
        return new_game, load_game

    def load_or_new(self, try_to_load_data):
        if try_to_load_data:
            self.persist = self.controller.load_persist_from_disk()
        self.next = "lobby"
        self.done = True

    def get_event(self, event, scale):
        if event.type == pg.QUIT:
            self.done = True
            self.quit = True
        elif event.type == pg.MOUSEBUTTONDOWN and event.button == 1:
            for scroller in self.scrollers:
                scroller.done = True
        elif event.type == pg.KEYUP:
            if event.key == pg.K_ESCAPE:
                self.done = True
                self.quit = True
        self.buttons.get_event(event)

    def cleanup(self):
        spotlight.SpotLight.clear_cache()  # Clear cache to reclaim memory.
        return super(TitleScreen, self).cleanup()

    def update(self, surface, keys, current_time, dt, scale):
        mouse_pos = tools.scaled_mouse_pos(scale)
        self.buttons.update(mouse_pos)
        self.scrollers.update(self.screen_rect, dt)
        if self.scrollers:
            if all(scroller.done for scroller in self.scrollers):
                self.scrollers.empty()
        else:
            self.marquees.update(dt)
            self.new_game.visible = True
            self.load_game.visible = self.controller.saved_stats_are_available
        self.lights.update(dt)
        self.draw(surface, dt)

    def draw(self, surface, dt):
        surface.fill(prepare.BACKGROUND_BASE)
        self.scrollers.draw(surface)
        if not self.scrollers:
            self.marquees.draw(surface)
        self.lights.draw(surface)
        self.buttons.draw(surface)
Пример #24
0
class PlayerTurn(BlackjackState):
    def __init__(self):
        super(PlayerTurn, self).__init__()
        pos = (self.screen_rect.right-(NeonButton.width+10),
               self.screen_rect.bottom-(NeonButton.height+15))
        self.make_buttons()
        self.lobby_button = NeonButton(pos, "Lobby", self.back_to_lobby, None, self.buttons, bindings=[pg.K_ESCAPE])
        self.last_click = 0

    def play_deal_sound(self):
        choice(self.game.deal_sounds).play()

    def make_buttons(self):
        side_margin = 10
        vert_space = 12
        left = self.screen_rect.right-(NeonButton.width + side_margin)
        top = self.screen_rect.bottom-((NeonButton.height*5)+vert_space*5)
        self.hit_button = NeonButton((left,top), "Hit", self.hit_click)
        top += NeonButton.height + vert_space
        self.stand_button = NeonButton((left, top), "Stand", self.stand)
        top += NeonButton.height + vert_space
        self.double_down_button = NeonButton((left,top), "Double",
                                             self.double_down)
        top += NeonButton.height + vert_space
        self.split_button = NeonButton((left, top), "Split", self.split_hand)
        self.buttons = ButtonGroup(self.hit_button, self.stand_button,
                                          self.double_down_button,
                                          self.split_button)

    def hit_click(self, *args):
        self.hit(self.game.current_player_hand)

    def hit(self, hand):
        """Draw a card from deck and add to hand."""
        self.play_deal_sound()
        self.game.player.add_slot(hand)
        card = self.game.deck.draw_card()
        card.face_up = True
        destination = hand.slots[-1]
        dest_x, dest_y = destination.topleft
        hand.cards.append(card)
        dur = get_distance(destination.center, card.pos) * 20 // card.speed
        ani = Animation(x=dest_x, y=dest_y, duration=dur, round_values=True)
        ani.start(card.rect)
        self.animations.add(ani)


    def stand(self, *args):
        """Player is done with this hand."""
        self.game.current_player_hand.final = True

    def double_down(self, *args):
        """
        Double player's bet on the hand, deal one
        more card and finalize hand.
        """
        hand = self.game.current_player_hand
        bet = hand.bet.get_chip_total()
        bet_chips = self.game.player.chip_pile.withdraw_chips(bet)
        hand.bet.add_chips(bet_chips)
        self.hit(hand)
        hand.final = True

    def split_hand(self, *args):
        """
        Split player's hand into two hands, adjust hand locations
        and deal a new card to both hands.
        """
        player = self.game.player
        hand = self.game.current_player_hand
        bet = hand.bet.get_chip_total()

        hand.slots = hand.slots[:-1]
        move = ((self.screen_rect.left+50)-hand.slots[0].left, 0)
        player.move_hands(move)
        p_slot = player.hands[-1].slots[0]
        hand_slot = p_slot.move(int(prepare.CARD_SIZE[0] * 3.5), 0)
        card = hand.cards.pop()
        new_hand = Hand(hand_slot.topleft, [card],
                        player.chip_pile.withdraw_chips(bet))
        new_hand.slots = [hand_slot]
        card.rect.topleft = hand_slot.topleft
        player.hands.append(new_hand)
        player.add_slot(new_hand)

        self.play_deal_sound()
        self.game.player.add_slot(hand)
        card1 = self.game.deck.draw_card()
        dest = hand.slots[-1]
        dest_x, dest_y = dest.topleft
        card1.face_up = True
        hand.cards.append(card1)
        ani = Animation(x=dest_x, y=dest_y, duration=1000, round_values=True)
        ani.start(card1.rect)

        card2 = self.game.deck.draw_card()
        dest = new_hand.slots[-1]
        dest_x, dest_y = dest.topleft
        card2.face_up = True
        new_hand.cards.append(card2)
        ani2 = Animation(x=dest_x, y=dest_y, duration=1000, delay=500, round_values=True)
        ani2.start(card2.rect)
        ani3 = Task(self.play_deal_sound, 1500)
        self.animations.add(ani, ani2, ani3)

    def startup(self, game):
        self.game = game
        self.animations = pg.sprite.Group()

    def get_event(self, event, scale):
        now = pg.time.get_ticks()
        span = now - self.last_click
        if event.type == pg.QUIT:
            self.back_to_lobby()
        if event.type == pg.MOUSEBUTTONUP:
            self.last_click = now
        self.game.get_event(event)
        if span > 300:
            if self.window:
                self.window.get_event(event)
            else:
                self.buttons.get_event(event)

    def update(self, surface, keys, current_time, dt, scale):
        mouse_pos = tools.scaled_mouse_pos(pg.mouse.get_pos(), scale)
        g = self.game
        g.update(dt, mouse_pos)

        self.split_button.active = False
        self.split_button.visible = False
        self.double_down_button.active = False
        self.double_down_button.visible = False

        hand = g.current_player_hand
        hand_score = hand.best_score()
        if hand_score is None:
            hand.busted = True
            hand.final = True
        chip_total = g.player.chip_pile.get_chip_total()
        bet = hand.bet.get_chip_total()

        if len(hand.cards) == 2 and len(g.player.hands) < 2:
            c1 = hand.card_values[hand.cards[0].value]
            c2 = hand.card_values[hand.cards[1].value]
            if c1 == c2 and chip_total >= bet:
                self.split_button.active = True
                self.split_button.visible = True
        if len(hand.cards) == 2:
            if hand_score == 21:
                hand.blackjack = True
                hand.final = True
            elif chip_total >= bet:
                self.double_down_button.active = True
                self.double_down_button.visible = True

        if hand.final:
            if all([hand.final for hand in g.player.hands]):
                if not self.animations:
                    g.dealer.hand.cards[0].face_up = True
                    self.next = "Dealer Turn"
                    self.done = True
            else:
                next_hand = [x for x in g.player.hands if not x.final][0]
                g.current_player_hand = next_hand
        if self.window:
            self.window.update(mouse_pos)
            if self.window.done:
                self.window = None
        else:
            self.buttons.update(mouse_pos)
            self.animations.update(dt)

    def draw_hand_frame(self, surface):
        hand = self.game.current_player_hand
        rects = [x for x in hand.slots]
        pg.draw.rect(surface, pg.Color("gold3"),
                     hand.slots[0].unionall(rects).inflate(8, 8), 3)

    def draw(self, surface):
        g = self.game
        surface.fill(prepare.FELT_GREEN)
        for label in g.labels:
            label.draw(surface)
        g.player.draw_hand_bets(surface)
        g.player.chip_pile.draw(surface)
        g.chip_total_label.draw(surface)
        g.dealer.draw_hand(surface)
        g.deck.draw(surface)
        g.chip_rack.draw(surface)
        self.buttons.draw(surface)
        self.lobby_button.draw(surface)
        g.player.draw_hands(surface)
        self.draw_advisor(surface)
        self.draw_hand_frame(surface)
        self.game.player.chip_pile.draw(surface)
        self.window and self.window.draw(surface)
Пример #25
0
class EndRound(BlackjackState):
    def __init__(self):
        super(EndRound, self).__init__()
        pos = (self.screen_rect.right - (NeonButton.width + 10),
               self.screen_rect.bottom - (NeonButton.height + 15))
        self.lobby_button = NeonButton(pos,
                                       "Lobby",
                                       self.back_to_lobby,
                                       bindings=[pg.K_ESCAPE])
        self.make_buttons()

    def make_buttons(self):
        self.buttons = ButtonGroup()
        self.new_game_button = NeonButton(
            (0, 0), "Change", self.new_game_click, None, self.buttons)
        self.quick_bet_button = NeonButton(
            (0, 0), "Again", self.quick_bet_click, None, self.buttons)
        self.quick_bet_button.rect.midbottom = (self.screen_rect.centerx,
                                                self.screen_rect.centery - 30)
        self.new_game_button.rect.center = (self.screen_rect.centerx,
                                            self.screen_rect.centery + 30)

    def new_game_click(self, *args):
        self.game.advisor.empty()
        self.next = "Betting"
        self.done = True

    def quick_bet_click(self, *args):
        self.game.quick_bet = self.game.last_bet
        self.new_game_click()

    def startup(self, game):
        self.game = game
        if game.advisor_active:
            text = "The current bet amount is ${}".format(self.game.last_bet)
            self.game.advisor.queue_text(text, dismiss_after=3000)
            text2 = "Press Change Bet for a different amount"
            self.game.advisor.queue_text(text2, dismiss_after=3000)
            text3 = "Press the Lobby button to exit"
            self.game.advisor.queue_text(text3, dismiss_after=3000)

    def get_event(self, event, scale):
        if event.type == pg.QUIT:
            self.back_to_lobby()
        self.game.get_event(event)
        if self.window:
            self.window.get_event(event)
        else:
            self.buttons.get_event(event)
            self.lobby_button.get_event(event)

    def update(self, surface, keys, current_time, dt, scale):
        mouse_pos = tools.scaled_mouse_pos(pg.mouse.get_pos(), scale)
        self.game.update(dt, mouse_pos)
        for label in self.game.result_labels:
            label.update(dt)
        if self.window:
            self.window.update(mouse_pos)
            if self.window.done:
                self.window = None
        else:
            self.buttons.update(mouse_pos)
            self.lobby_button.update(mouse_pos)

    def draw(self, surface):
        g = self.game
        surface.fill(prepare.FELT_GREEN)
        for label in g.labels:
            label.draw(surface)
        g.player.draw_hand_bets(surface)
        g.player.chip_pile.draw(surface)
        g.chip_total_label.draw(surface)
        g.dealer.draw_hand(surface)
        g.deck.draw(surface)
        g.chip_rack.draw(surface)
        self.lobby_button.draw(surface)
        g.player.draw_hands(surface)
        for blinker in self.game.result_labels:
            blinker.draw(surface)
        self.buttons.draw(surface)
        self.draw_advisor(surface)
        self.game.player.chip_pile.draw(surface)
        self.window and self.window.draw(surface)
Пример #26
0
class EndRound(BlackjackState):
    def __init__(self):
        super(EndRound, self).__init__()
        pos = (self.screen_rect.right-(NeonButton.width+10),
               self.screen_rect.bottom-(NeonButton.height+15))
        self.lobby_button = NeonButton(pos, "Lobby", self.back_to_lobby, bindings=[pg.K_ESCAPE])
        self.make_buttons()

    def make_buttons(self):
        self.buttons = ButtonGroup()
        self.new_game_button = NeonButton((0,0), "Change", self.new_game_click,
                                          None, self.buttons)
        self.quick_bet_button = NeonButton((0, 0), "Again", self.quick_bet_click,
                                           None, self.buttons)
        self.quick_bet_button.rect.midbottom = (self.screen_rect.centerx,
                                               self.screen_rect.centery-30)
        self.new_game_button.rect.center = (self.screen_rect.centerx,
                                             self.screen_rect.centery+30)

    def new_game_click(self, *args):
        self.game.advisor.empty()
        self.next = "Betting"
        self.done = True

    def quick_bet_click(self, *args):
        self.game.quick_bet = self.game.last_bet
        self.new_game_click()

    def startup(self, game):
        self.game = game
        if game.advisor_active:
            text = "The current bet amount is ${}".format(self.game.last_bet)
            self.game.advisor.queue_text(text, dismiss_after=3000)
            text2 = "Press Change Bet for a different amount"
            self.game.advisor.queue_text(text2, dismiss_after=3000)
            text3 = "Press the Lobby button to exit"
            self.game.advisor.queue_text(text3, dismiss_after=3000)

    def get_event(self, event, scale):
        if event.type == pg.QUIT:
            self.back_to_lobby()
        self.game.get_event(event)
        if self.window:
            self.window.get_event(event)
        else:
            self.buttons.get_event(event)
            self.lobby_button.get_event(event)


    def update(self, surface, keys, current_time, dt, scale):
        mouse_pos = tools.scaled_mouse_pos(pg.mouse.get_pos(), scale)
        self.game.update(dt, mouse_pos)
        for label in self.game.result_labels:
            label.update(dt)
        if self.window:
            self.window.update(mouse_pos)
            if self.window.done:
                self.window = None
        else:
            self.buttons.update(mouse_pos)
            self.lobby_button.update(mouse_pos)

    def draw(self, surface):
        g = self.game
        surface.fill(prepare.FELT_GREEN)
        for label in g.labels:
            label.draw(surface)
        g.player.draw_hand_bets(surface)
        g.player.chip_pile.draw(surface)
        g.chip_total_label.draw(surface)
        g.dealer.draw_hand(surface)
        g.deck.draw(surface)
        g.chip_rack.draw(surface)
        self.lobby_button.draw(surface)
        g.player.draw_hands(surface)
        for blinker in self.game.result_labels:
            blinker.draw(surface)
        self.buttons.draw(surface)
        self.draw_advisor(surface)
        self.game.player.chip_pile.draw(surface)
        self.window and self.window.draw(surface)
Пример #27
0
class StartGame(GutsState):
    """Choose between starting a new game or view tutorial."""
    def __init__(self):
        super(StartGame, self).__init__()

    def startup(self, game):
        self.game = game
        sr = self.screen_rect
        title = Label(self.font, 128, "Two-Card Guts", "gold3",
                          {"midtop": (sr.centerx, 5)},
                          bg=prepare.FELT_GREEN)
        title.image.set_alpha(160)
        title2 = Label(self.font, 96, "${} Ante".format(self.game.bet), "darkred",
                            {"midtop": (sr.centerx, title.rect.bottom)},
                            bg=prepare.FELT_GREEN)
        title2.image.set_alpha(140)
        self.titles = [title, title2]
        self.player_buttons = ButtonGroup()
        w, h = NeonButton.width, NeonButton.height
        pos = sr.centerx - (w//2), sr.centery - (h//2)
        NeonButton(pos, "Ante Up", self.start_game, None, self.player_buttons)
        pos2 = sr.centerx - (w//2), sr.centery + (h//2) + 50
        self.tutorial_button = NeonButton(pos2, "Tutorial", self.to_tutorial,
                                          None, self.player_buttons)
        self.advisor.queue_text("Ante Up ${} to play".format(self.game.bet), dismiss_after=2500)
        self.advisor.queue_text("Press Tutorial to learn how to play", dismiss_after=2500)
        self.advisor.queue_text("Press the Lobby button to exit", dismiss_after=2500)

    def start_game(self, *args):
        self.done = True
        self.next = "Betting"
        self.advisor.empty()

    def to_tutorial(self, *args):
        self.done = True
        self.next = "Tutorial"
        self.advisor.empty()

    def get_event(self, event):
        if self.window:
            self.window.get_event(event)
        else:
            self.buttons.get_event(event)
            self.player_buttons.get_event(event)
            self.advisor_button.get_event(event)

    def update(self, dt, scale):
        mouse_pos = tools.scaled_mouse_pos(scale)
        self.general_update(dt, mouse_pos)
        if not self.window:
            self.player_buttons.update(mouse_pos)


    def draw(self, surface):
        surface.fill(prepare.FELT_GREEN)
        for title in self.titles:
            title.draw(surface)
        self.buttons.draw(surface)
        self.player_buttons.draw(surface)
        self.money_icon.draw(surface)
        self.draw_advisor(surface)
        if self.window:
            self.window.draw(surface)
Пример #28
0
class TitleScreen(data.state.State):
    """
    Initial state of the game. Introduces the game and lets user load a
    saved game if there's one present.
    """
    name = "title_screen"

    def __init__(self):
        super(TitleScreen, self).__init__()
        self.screen_rect = pg.Rect((0, 0), prepare.RENDER_SIZE)
        self.marquees = []
        self.scrollers, self.marquees = self.make_titles()
        self.buttons = ButtonGroup()
        self.new_game, self.load_game = self.make_buttons()
        self.lights = self.make_spotlights()
        self.use_music_handler = False

    def make_spotlights(self):
        lights = pg.sprite.LayeredDirty()
        y = self.screen_rect.bottom+20
        for i in range(1,5):
            start = 0 if i%2 else 0.5
            pos = (i*self.screen_rect.w/5, y)
            spotlight.SpotLight(pos, 4, 140, start, lights)
        return lights

    def make_titles(self):
        font = prepare.FONTS["Saniretro"]
        scrollers = pg.sprite.Group()
        marquees = pg.sprite.Group()
        pos = {"right" : 0, "centery": self.screen_rect.y+123}
        Scroller(pos, prepare.GFX["pyrollers_shiny"], 0.6, scrollers)
        pos = {"center": (self.screen_rect.centerx, pos["centery"])}
        MarqueeFrame(pos, prepare.GFX["pyrollers_shiny"], 20, 120, marquees)
        pos = {"left" : self.screen_rect.w, "centery": 370}
        Scroller(pos, prepare.GFX["casino_shiny"], -0.6, scrollers)
        pos = {"center": (self.screen_rect.centerx, pos["centery"])}
        MarqueeFrame(pos, prepare.GFX["casino_shiny"], 20, 120, marquees)
        return scrollers, marquees

    def make_buttons(self):
        x = self.screen_rect.centerx-(NeonButton.width//2)
        y = 600
        new_game = NeonButton((x, y), "New", self.load_or_new,
                              False, self.buttons, visible=False)
        y = new_game.rect.bottom + 50
        load_game = NeonButton((x, y), "Load", self.load_or_new,
                               True, self.buttons, visible=False)
        return new_game, load_game

    def load_or_new(self, try_to_load_data):
        if try_to_load_data:
            self.persist = self.controller.load_persist_from_disk()
        self.next = "lobby"
        self.done = True

    def get_event(self, event, scale):
        if event.type == pg.QUIT:
            self.done = True
            self.quit = True
        elif event.type == pg.MOUSEBUTTONDOWN and event.button == 1:
            for scroller in self.scrollers:
                scroller.done = True
        elif event.type == pg.KEYUP:
            if event.key == pg.K_ESCAPE:
                self.done = True
                self.quit = True
        self.buttons.get_event(event)

    def cleanup(self):
        spotlight.SpotLight.clear_cache()  # Clear cache to reclaim memory.
        return super(TitleScreen, self).cleanup()

    def update(self, surface, keys, current_time, dt, scale):
        mouse_pos = tools.scaled_mouse_pos(scale)
        self.buttons.update(mouse_pos)
        self.scrollers.update(self.screen_rect, dt)
        if self.scrollers:
            if all(scroller.done for scroller in self.scrollers):
                self.scrollers.empty()
        else:
            self.marquees.update(dt)
            self.new_game.visible = True
            self.load_game.visible = self.controller.saved_stats_are_available
        self.lights.update(dt)
        self.draw(surface, dt)

    def draw(self, surface, dt):
        surface.fill(prepare.BACKGROUND_BASE)
        self.scrollers.draw(surface)
        if not self.scrollers:
            self.marquees.draw(surface)
        self.lights.draw(surface)
        self.buttons.draw(surface)
Пример #29
0
class ShowResults(GutsState):
    def __init__(self):
        super(ShowResults, self).__init__()
        self.buttons = ButtonGroup()
        pos = (self.screen_rect.right-(NeonButton.width+10),
               self.screen_rect.bottom-(NeonButton.height+10))
        self.lobby_button = NeonButton(pos, "Lobby", self.warn, None, self.buttons, bindings=[pg.K_ESCAPE])

    def make_player_buttons(self, free_ride):
        self.player_buttons = ButtonGroup()
        w, h = NeonButton.width, NeonButton.height
        sr = self.screen_rect
        pos = sr.centerx - (w//2), sr.centery + 120
        text = "OK" if free_ride else "Ante Up"
        NeonButton(pos, text, self.new_game, None, self.player_buttons)

    def new_game(self, *args):
        self.game.game_over = True
        self.done = True
        self.next = "Betting"
        self.advisor.empty()

    def add_player_cash(self, amount):
        self.game.player.cash += amount

    def add_to_pot(self, amount):
        self.game.pot += amount

    def toggle_buttons(self, boolean):
        for button in self.player_buttons:
            button.active = boolean
            button.visible = boolean

    def cash_advance(self, amount):
        acct = self.game.casino_player.account
        acct.cash_advance(amount)
        self.add_player_cash(amount)


    def startup(self, game):
        self.game = game
        self.lobby_button.call = self.warn
        self.toggled = False
        self.alpha = 255
        self.labels = []
        self.blinkers = []
        self.calculated = False
        self.animations = pg.sprite.Group()

        stayers = [x for x in self.game.players if x.stayed]
        winners = self.game.get_winners()
        share = self.game.pot // len(winners)

        ani_duration = 2000
        self.free_ride = False

        for stayer in stayers:
            pos = stayer.name_label.rect.center
            dest = pos[0], pos[1] - 120
            cards_center = stayer.cards[0].rect.union(stayer.cards[1].rect).center
            if stayer not in winners:
                text = "${}".format(self.game.pot)
                color = "darkred"
                stayer.lost = self.game.pot
                self.free_ride = True
                dest = self.game.pot_label.rect.center
                if stayer is self.game.player:
                    pos = self.money_icon.rect.center
                    if self.game.player.cash < stayer.lost:
                        amount = stayer.lost - self.game.player.cash
                        self.cash_advance(amount)
                        msg = "You were forced to take a cash advance to cover your loss. Visit the ATM to view your account."
                        self.notice(msg)
                    self.add_player_cash(-stayer.lost)
                task = Task(self.add_to_pot, ani_duration, args=[stayer.lost])
                self.animations.add(task)
                lose_label = Blinker(self.font, 96, "Loser", color, {"center": cards_center}, 500)
                self.animations.add(Task(self.blinkers.append, ani_duration, args=[lose_label]))
            else:
                text = "${}".format(share)
                color = "darkgreen"
                stayer.won = share
                pos = self.game.pot_label.rect.center
                if stayer is self.game.player:
                    self.cha_ching.play()
                    dest = self.money_icon.rect.center
                    task = Task(self.add_player_cash, ani_duration, args=[share])
                    self.animations.add(task)
                win_label = Blinker(self.font, 96, "Winner", color, {"center": cards_center}, 500)
                self.animations.add(Task(self.blinkers.append, ani_duration, args=[win_label]))
            label = Label(self.font, 128, text, color,
                    {"center": pos}, bg=prepare.FELT_GREEN)
            label.image.set_colorkey(prepare.FELT_GREEN)
            self.labels.append(label)
            move = Animation(centerx=dest[0], centery=dest[1], duration=ani_duration,
                                        round_values=True, transition="in_quart")
            move.start(label.rect)
            self.animations.add(move)

        fader = Animation(alpha=0, duration=ani_duration + 200, round_values = True)
        fader.start(self)
        self.animations.add(fader)
        self.game.pot = 0

        self.make_player_buttons(self.free_ride)
        self.toggle_buttons(False)
        if self.free_ride:
            self.advice_texts = ["Press OK to play the next round"]
        else:
            self.advice_texts = ["Ante Up ${} to play again".format(self.game.bet)]
        self.advice_texts.append("Press the Lobby button to exit")

    def fade_labels(self):
        for label in self.labels:
            label.image.set_alpha(self.alpha)

    def update(self, dt, scale):
        mouse_pos = tools.scaled_mouse_pos(scale)
        self.general_update(dt, mouse_pos)
        if not self.window:
            for blinker in self.blinkers:
                blinker.update(dt)
            self.player_buttons.update(mouse_pos)
            self.fade_labels()
            if self.alpha < 1 and not self.toggled:
                self.toggle_buttons(True)
                self.toggled = True
                for text in self.advice_texts:
                    self.advisor.queue_text(text, dismiss_after=3500)
                if not self.free_ride:
                    self.lobby_button.call = self.back_to_lobby

    def get_event(self, event):
        if self.window:
            self.window.get_event(event)
        else:
            self.buttons.get_event(event)
            self.player_buttons.get_event(event)
            self.advisor_button.get_event(event)

    def draw(self, surface):
        surface.fill(prepare.FELT_GREEN)
        self.game.draw(surface)
        for p in self.game.players:
            p.draw(surface)
        self.money_icon.draw(surface)
        self.buttons.draw(surface)
        self.player_buttons.draw(surface)
        for label in self.labels:
            label.draw(surface)
        for blinker in self.blinkers:
            blinker.draw(surface)
        self.draw_advisor(surface)
        if self.window:
            self.window.draw(surface)
Пример #30
0
class Keno(data.state.State):
    """Class to represent a casino game."""
    show_in_lobby = True
    name = 'keno'

    def __init__(self):
        super(Keno, self).__init__()
        self.screen_rect = pg.Rect((0, 0), prepare.RENDER_SIZE)
        self.game_started = False
        self.font = prepare.FONTS["Saniretro"]
        self.advisor = KenoAdvisor()
        self.mock_label = Label(self.font, 64, 'KENO [WIP]', 'gold3', {'center':(672,102)})

        b_width = 360
        b_height = 90
        side_margin = 10
        w = self.screen_rect.right - (b_width + side_margin)
        h = self.screen_rect.bottom - (b_height+15)
        self.buttons = ButtonGroup()
        NeonButton((w, h), "Lobby", self.back_to_lobby, None, self.buttons)

        self.turns = 16
        self.play_max_active = False

        ball_path = os.path.join('resources', 'keno', 'balls', '64x64', 'sheet.png')
        ball_sheet = pg.image.load(ball_path).convert_alpha()
        self.balls = tools.strip_from_sheet(ball_sheet, (0,0), (64,64), 10, 8)

        self.keno_card = KenoCard(self.balls)
        #self.keno_card = KenoCard() -- no ball graphics

        self.prev_spot_count = 0

        self.pay_table = PayTable(self.keno_card)
        self.pay_table.update(0)

        self.round_history = RoundHistory(self.keno_card)

        self.alert = None


        self.quick_picking = Action(pg.Rect(370, 760, 150, 75),
                                    Label(self.font, 32, 'QUICK PICK', 'gold3', {'center':(0,0)}),
                                    self.activate_quick_pick)


        self.betting = Action(pg.Rect(682, 760, 150, 75),
                              Label(self.font, 32, 'BET 1', 'gold3', {'center':(0,0)}),
                              self.activate_bet)

        self.clearing = Action(pg.Rect(526, 760, 150, 75),
                               Label(self.font, 32, 'CLEAR', 'gold3', {'center':(0,0)}),
                               self.activate_clear)

        self.playing = Action(pg.Rect(838, 760, 156, 75),
                              Label(self.font, 32, 'PLAY', 'gold3', {'center':(0,0)}),
                              self.activate_play)

        self.playing_max = Action(pg.Rect(838, 840, 156, 75),
                                  Label(self.font, 32, 'PLAY MAX', 'gold3', {'center':(0,0)}),
                                  self.activate_playmax)

        self.actions = {
            'quick pick'    : self.quick_picking,
            'betting'       : self.betting,
            'clearing'      : self.clearing,
            'playing'       : self.playing,
            'playing max'   : self.playing_max,
        }

        self.gui_widgets = {
            'title'         : self.mock_label,
            'card'          : self.keno_card,
            'quick_pick'    : self.quick_picking,
            'play'          : self.playing,
            'play_max'      : self.playing_max,
            'pay_table'     : self.pay_table,
            'round_history' : self.round_history,
            'balance'       : None,
            'bet_action'    : None,
            'clear'         : None,
            'bet'           : None,
            'won'           : None,
            'spot'          : None,
        }

    @staticmethod
    def initialize_stats():
        """Return OrderedDict suitable for use in game stats

        :return: collections.OrderedDict
        """
        stats = OrderedDict([("games played", 0)])
        return stats

    def activate_quick_pick(self):
        self.keno_card.reset()
        numbers = pick_numbers(10)

        for number in numbers:
            self.keno_card.toggle_owned(number)

    def activate_bet(self):
        log.debug("betting activated")

        try:
            self.make_bet(1)
        except InsufficientFundsException:
            self.handle_insufficient_funds()

        spot_count = self.keno_card.spot_count
        self.pay_table.update(spot_count, self.pot._balance)

    def activate_clear(self):
        log.debug("clear activated")
        self.keno_card.ready_play(clear_all=True)
        self.clear_bet()
        self.round_history.clear()

    def validate_configuration(self):
        if not self.pot.paid and self.pot._balance > 0:

            try:
                self.pot.repeat_bet()
                return True
            except InsufficientFundsException:
                self.handle_insufficient_funds()
                return False

        elif not self.pot.paid:
            self.alert = NoticeWindow(self.screen_rect.center, "Please place your bet.")
            return False

        spot_count = self.keno_card.spot_count
        if spot_count <= 0:
            self.alert = NoticeWindow(self.screen_rect.center, "Please pick your spots.")
            return False

        return True

    def handle_insufficient_funds(self):
        self.pot.clear_bet(with_payout=False)
        self.play_max_active = False
        self.turns = 0
        self.alert_insufficient_funds()

    def alert_insufficient_funds(self):
        self.alert = NoticeWindow(self.screen_rect.center, "You cannot afford that bet.")

    def activate_play(self):

        if not self.validate_configuration():
            return

        numbers = pick_numbers(20)
        log.debug("pick: {}".format(numbers))

        self.keno_card.ready_play()
        self.keno_card.current_pick = numbers
        for number in numbers:
            self.keno_card.toggle_hit(number)

        self.play_game()

    def activate_playmax(self):
        self.round_history.clear()

        if not self.validate_configuration():
            return

        self.continue_playmax()
        self.play_game()

    def continue_playmax(self):
        log.debug("turns={0}".format(self.turns))

        try:
            self.pot.repeat_bet()
            self.play_max_active = True
            numbers = pick_numbers(20)

            self.keno_card.ready_play()
            self.keno_card.current_pick = numbers
            for number in numbers:
                self.keno_card.toggle_hit(number)

            self.turns -= 1
            if self.turns <= 0:
                self.play_max_active = False
                self.turns = 16

        except InsufficientFundsException:
            self.turns = 0
            self.handle_insufficient_funds()
            self.play_max_active = False

    def make_bet(self, amount):
        try:
            self.pot.change_bet(amount)
        except InsufficientFundsException:
            self.handle_insufficient_funds()

    def clear_bet(self):
        self.pot.clear_bet()

    def result(self, spot, hit):

        paytable = PAYTABLE[spot]
        payment = 0.0
        for entry in paytable:
            if entry[0] == hit:
                payment = entry[1]

            if payment > 0.0:
                break

        self.pot.payout(payment)
        self.casino_player.cash = self.wallet.balance

    def back_to_lobby(self, *args):
        self.game_started = False
        self.done = True
        self.next = "lobby"

    def startup(self, current_time, persistent):
        """This method will be called each time the state resumes."""
        self.persist = persistent
        #This is the object that represents the user.
        self.casino_player = self.persist["casino_player"]
        self.casino_player.current_game = self.name
        self.gui_widgets['bet_action'] = self.betting
        self.gui_widgets['clear'] = self.clearing

        self.wallet = Wallet(self.casino_player.cash)
        self.pot    = Pot(self.wallet)

        self.casino_player.increase("games played", 1)

    def play_game(self):
        spot_count = self.keno_card.spot_count
        hit_count = self.keno_card.hit_count
        self.result(spot_count, hit_count)
        self.round_history.update(spot_count, hit_count)

    def get_event(self, event, scale=(1,1)):
        """This method will be called for each event in the event queue
        while the state is active.
        """
        if event.type == pg.QUIT and not self.alert:
            self.done = True
            self.next = "lobby"
        elif event.type == pg.MOUSEBUTTONDOWN and not self.alert:
            #Use tools.scaled_mouse_pos(scale, event.pos) for correct mouse
            #position relative to the pygame window size.
            event_pos = tools.scaled_mouse_pos(scale, event.pos)
            log.info(event_pos) #[for debugging positional items]

            for action in self.actions.values():
                action.execute(event_pos)

            self.keno_card.update(event_pos)

            spot_count = self.keno_card.spot_count
            if spot_count != self.prev_spot_count:
                self.pay_table.update(spot_count, self.pot._balance)
                self.prev_spot_count = spot_count

        if not self.alert:
            self.buttons.get_event(event)
        self.alert and self.alert.get_event(event)

    def draw(self, surface):
        """This method handles drawing/blitting the state each frame."""
        surface.fill(prepare.FELT_GREEN)

        self.buttons.draw(surface)
        self.advisor.draw(surface)
        for widget in self.gui_widgets.values():
            if widget:
                widget.draw(surface)

        if self.alert and not self.alert.done:
            self.alert.draw(surface)

    def update(self, surface, keys, current_time, dt, scale):
        """
        This method will be called once each frame while the state is active.
        Surface is a reference to the rendering surface which will be scaled
        to pygame's display surface, keys is the return value of the last call
        to pygame.key.get_pressed. current_time is the number of milliseconds
        since pygame was initialized. dt is the number of milliseconds since
        the last frame.
        """

        self.advisor.update(dt)

        if self.play_max_active:
            self.continue_playmax()
            self.play_game()

        total_text = "Balance:  ${}".format(self.wallet.balance)

        self.gui_widgets['balance'] = Label(self.font, 48, total_text, "gold3",
                               {"topleft": (24, 760)})

        bet_text = "Bet: ${}".format(self.pot._balance)
        self.gui_widgets['bet'] = Label(self.font, 48, bet_text, "gold3",
                               {"topleft": (24, 760+48)})

        won_text = "Won: ${}".format(self.pot.won)
        self.gui_widgets['won'] = Label(self.font, 48, won_text, "gold3",
                               {"topleft": (24, 760+48+48)})

        spot_count = self.keno_card.spot_count
        spot_text = "Spot: {}".format(spot_count)
        self.gui_widgets['spot'] = Label(self.font, 48, spot_text, "gold3",
                               {"topleft": (1036, 760)})

        mouse_pos = tools.scaled_mouse_pos(scale)
        self.buttons.update(mouse_pos)
        if self.alert:
            self.alert.update(mouse_pos)
            if self.alert.done:
                self.alert = None

        self.draw(surface)
Пример #31
0
class LevelWin(_State):
    def __init__(self, controller):
        super(LevelWin, self).__init__(controller)

    def startup(self, persistent):
        self.persist = persistent
        self.animations = pg.sprite.Group()
        self.buttons = ButtonGroup()
        font = prog_constants.FONTS["Fixedsys500c"]
        color = constants.LOW_LIGHT_GREEN
        sr = constants.SCREEN_RECT
        NeonButton((373, 630), "Next Level", 32, self.next_level,
                    None, self.buttons)
        self.make_city_icons()
        total = sum((icon.current_points for icon in self.city_icons))
        points_text = "${}".format(total)
        self.points_label = Label(font, 32,
                    points_text, color, {"center": (sr.centerx, 200)})
        level_num = self.persist["player"].level_num
        self.title = Label(font, 48, "Level {} Complete".format(level_num),
                    color, {"midtop": (sr.centerx, 5)})

    def make_city_icons(self):
        level = self.persist["level"]
        player = self.persist["player"]
        self.city_icons = []
        for city in player.cities:
            points = 0
            if not city.damaged:
                points = city.population * 100
            cx = city.rect.centerx
            icon = CityIcon((cx, 300), points, city.image)
            self.city_icons.append(icon)
            if points:
                time_scale = points / 1000.
                dur = min(1000 + (points * time_scale), 5000)
                ani = Animation(current_points=points, duration=dur,
                            round_values=True)
                ani.start(icon)
                self.animations.add(ani)

    def next_level(self, *args):
        player = self.persist["player"]
        total = sum((icon.points for icon in self.city_icons))
        player.cash += total
        player.level_num += 1
        for city in player.cities:
            if city.damaged:
                city.kill()
            else:
                city.population += 1
        player.cities = [c for c in player.cities if not c.damaged]

        player.save()
        if player.level_num > 42:
            self.next = "GAME_WIN"
        else:
            self.next = "LEVEL_START"
            level = Level(player)
            self.persist["level"] = level
        self.done = True

    def get_event(self, event, scale):
        self.buttons.get_event(event)

    def update(self, surface, keys, current_time, dt, scale):
        self.animations.update(dt)
        total = sum((icon.current_points for icon in self.city_icons))
        points_text = "${}".format(total)
        if self.points_label.text != points_text:
            self.points_label.set_text(points_text)
        for icon in self.city_icons:
            icon.update()
        self.buttons.update(scaled_mouse_pos(scale))
        self.draw(surface)

    def draw(self, surface):
        surface.fill(constants.BACKGROUND_BASE)
        for icon in self.city_icons:
            icon.draw(surface)
        self.buttons.draw(surface)
        self.points_label.draw(surface)
        self.title.draw(surface)
Пример #32
0
class LobbyScreen(data.state.State):
    """
    This state represents the casino lobby where the player can choose
    which game they want to play or view their game statistics. This is also
    the exit point for the game.
    """
    name = "lobby"
    per_page = 6

    def __init__(self):
        super(LobbyScreen, self).__init__()
        self.game = None
        self.chip_curtain = None  # Created on startup
        self.animations = pg.sprite.Group()

    def collect_game_scenes(self):
        all_scenes = self.controller.query_all_states()
        games = OrderedDict()
        for name, scene in all_scenes.items():
            if hasattr(scene, 'show_in_lobby'):
                games[name] = scene
        return games

    def update_screen_buttons(self, games):
        screen_rect = pg.Rect((0, 0), prepare.RENDER_SIZE)
        number_of_pages = int(math.ceil(len(games)/float(self.per_page)))
        self.loop_length = prepare.RENDER_SIZE[0] * number_of_pages
        self.game_buttons = self.make_game_pages(games, screen_rect, self.per_page)
        nav_buttons = self.make_navigation_buttons(screen_rect)
        main_buttons = self.make_main_buttons(screen_rect)
        self.buttons = ButtonGroup(nav_buttons, main_buttons)

    def make_game_pages(self, games, screen_rect, per):
        games = list(games.keys())
        groups = (games[i:i+per] for i in range(0,len(games),per))
        columns = 3
        width, height = GameButton.width, GameButton.height
        spacer_x, spacer_y = 50, 80
        start_x = (screen_rect.w-width*columns-spacer_x*(columns-1))//2
        start_y = screen_rect.top+105
        step_x, step_y = width+spacer_x, height+spacer_y
        buttons = ButtonGroup()
        for offset,group in enumerate(groups):
            offset *= prepare.RENDER_SIZE[0]
            for i,game in enumerate(group):
                y,x = divmod(i, columns)
                pos = (start_x+step_x*x+offset, start_y+step_y*y)
                GameButton(pos, game, self.change_state, buttons)
        return buttons

    def make_navigation_buttons(self, screen_rect):
        sheet = prepare.GFX["nav_buttons"]
        size = (106,101)
        y = 790
        from_center = 15
        icons = tools.strip_from_sheet(sheet, (0,0), size, 4)
        buttons = ButtonGroup()
        l_kwargs = {"idle_image" : icons[0], "hover_image" : icons[1],
                    "call" : self.scroll_page, "args" : 1,
                    "bindings" : [pg.K_LEFT, pg.K_KP4]}
        r_kwargs = {"idle_image"  : icons[2], "hover_image" : icons[3],
                    "call" : self.scroll_page, "args" : -1,
                    "bindings" : [pg.K_RIGHT, pg.K_KP6]}
        left = Button(((0,y),size), buttons, **l_kwargs)
        left.rect.right = screen_rect.centerx-from_center
        right = Button(((0,y),size), buttons, **r_kwargs)
        right.rect.x = screen_rect.centerx+from_center
        return buttons

    def make_main_buttons(self, screen_rect):
        buttons = ButtonGroup()
        pos = (9, screen_rect.bottom-(NeonButton.height+11))
        NeonButton(pos, "Credits", self.change_state, "credits", buttons)
        pos = (screen_rect.right-(NeonButton.width+10),
               screen_rect.bottom-(NeonButton.height+11))
        NeonButton(pos, "Stats", self.change_state, "stats_menu", buttons)
        pos = (screen_rect.centerx-(NeonButton.width//2),
               screen_rect.bottom-(NeonButton.height+11))
        NeonButton(pos, "Exit", self.exit_game, None,
                   buttons, bindings=[pg.K_ESCAPE])
        rect_style = (screen_rect.left, screen_rect.top, 150, 95)
        Button(rect_style, buttons, idle_image=prepare.GFX["atm_dim"],
               hover_image=prepare.GFX["atm_bright"],
               call=self.change_state, args="atm")
        return buttons

    def scroll_page(self, mag):
        if not self.animations:
            for game in self.game_buttons:
                self.normalize_scroll(game, mag)
                fx, fy = game.rect.x+prepare.RENDER_SIZE[0]*mag, game.rect.y
                ani = Animation(x=fx, y=fy, duration=350.0,
                                transition='in_out_quint', round_values=True)
                ani.start(game.rect)
                self.animations.add(ani)
            prepare.SFX["cardplace4"].play()

    def normalize_scroll(self, game, mag):
        if game.rect.x < 0 and mag == -1:
            game.rect.x += self.loop_length
        elif game.rect.x >= prepare.RENDER_SIZE[0] and mag == 1:
            game.rect.x -= self.loop_length

    def startup(self, current_time, persistent):
        self.persist = persistent
        self.chip_curtain = ChipCurtain(None, **CURTAIN_SETTINGS)
        games = self.collect_game_scenes()
        self.update_screen_buttons(games)

    def exit_game(self, *args):
        with open(os.path.join("resources", "save_game.json"), "w") as f:
            json.dump(self.persist["casino_player"].stats, f)
        self.done = True
        self.quit = True

    def change_state(self, next_state):
        self.done = True
        self.next = next_state

    def get_event(self, event, scale=(1,1)):
        if self.game:
            self.game.get_event(event, scale)
        elif event.type == pg.QUIT:
            self.exit_game()
        else:
            self.buttons.get_event(event)
            self.game_buttons.get_event(event)

    def update(self, surface, keys, current_time, dt, scale):
        if self.game:
            self.game.update(surface, keys, current_time, dt, scale)
            if self.game.done:
                self.game.cleanup()
                self.game = None
        else:
            mouse_pos = tools.scaled_mouse_pos(scale)
            self.chip_curtain.update(dt)
            self.buttons.update(mouse_pos)
            self.game_buttons.update(mouse_pos)
            self.animations.update(dt)
            self.draw(surface)

    def draw(self, surface):
        rect = surface.get_rect()
        surface.fill(prepare.BACKGROUND_BASE)
        self.chip_curtain.draw(surface)
        self.buttons.draw(surface)
        for button in self.game_buttons:
            if button.rect.colliderect(rect):
                button.draw(surface)
class LobbyScreen(_State):
    """
    This state represents the lobby where the player can choose
    which game they want to play or view their high scores. This is also
    the exit point for the game.
    """
    per_page = 6

    def __init__(self, controller):
        super(LobbyScreen, self).__init__(controller)
        self.animations = pg.sprite.Group()

    def update_screen_buttons(self, games):
        screen_rect = pg.Rect((0, 0), prepare.RENDER_SIZE)
        number_of_pages = int(math.ceil(len(games) / float(self.per_page)))
        self.loop_length = prepare.RENDER_SIZE[0] * number_of_pages
        self.game_buttons = self.make_game_pages(games, screen_rect, self.per_page)
        nav_buttons = self.make_navigation_buttons(screen_rect)
        main_buttons = self.make_main_buttons(screen_rect)
        self.buttons = ButtonGroup(nav_buttons, main_buttons)

    def make_game_pages(self, games, screen_rect, per):
        games_list = list(games.keys())
        groups = (games_list[i:i+per] for i in range(0, len(games), per))
        columns = 3
        width, height = GameButton.width, GameButton.height
        spacer_x, spacer_y = 50, 80
        start_x = (screen_rect.w - width * columns - spacer_x * (columns-1))//2
        start_y = screen_rect.top + 105
        step_x, step_y = width + spacer_x, height + spacer_y
        buttons = ButtonGroup()
        for offset,group in enumerate(groups):
            offset *= prepare.RENDER_SIZE[0]
            for i,game in enumerate(group):
                y, x = divmod(i, columns)
                pos = (start_x + step_x * x + offset, start_y + step_y * y)
                GameButton(pos, game, games[game], self.change_state, buttons)
        return buttons

    def make_navigation_buttons(self, screen_rect):
        sheet = prepare.GFX["nav_buttons"]
        size = (53, 50)
        y = 530
        from_center = 15
        icons = tools.strip_from_sheet(sheet, (0, 0), size, 4)
        buttons = ButtonGroup()
        l_kwargs = {"idle_image" : icons[0], "hover_image" : icons[1],
                    "call" : self.scroll_page, "args" : 1,
                    "bindings" : [pg.K_LEFT, pg.K_KP4]}
        r_kwargs = {"idle_image"  : icons[2], "hover_image" : icons[3],
                    "call" : self.scroll_page, "args" : -1,
                    "bindings" : [pg.K_RIGHT, pg.K_KP6]}
        left = Button(((0, y), size), buttons, **l_kwargs)
        left.rect.right = screen_rect.centerx - from_center
        right = Button(((0, y), size), buttons, **r_kwargs)
        right.rect.x = screen_rect.centerx + from_center
        return buttons

    def make_main_buttons(self, screen_rect):
        buttons = ButtonGroup()
        pos = (9, screen_rect.bottom-(NeonButton.height+11))
        NeonButton(pos, "Credits", 32, self.change_state, "credits", buttons)
        pos = (screen_rect.right-(NeonButton.width+10),
               screen_rect.bottom-(NeonButton.height+11))
        NeonButton(pos, "High Scores", 28, self.change_state, "high_scores",
                   buttons)
        pos = (screen_rect.centerx-(NeonButton.width//2),
               screen_rect.bottom-(NeonButton.height+11))
        NeonButton(pos, "Exit", 32, self.exit_game, None,
                   buttons, bindings=[pg.K_ESCAPE])
        rect_style = (screen_rect.left, screen_rect.top, 150, 95)
        return buttons

    def scroll_page(self, mag):
        if not self.animations and len(self.game_buttons) > self.per_page:
            for game in self.game_buttons:
                self.normalize_scroll(game, mag)
                fx, fy = game.rect.x+prepare.RENDER_SIZE[0]*mag, game.rect.y
                ani = Animation(x=fx, y=fy, duration=350.0,
                                transition='in_out_quint', round_values=True)
                ani.start(game.rect)
                self.animations.add(ani)
            prepare.SFX["cardplace4"].play()

    def normalize_scroll(self, game, mag):
        if game.rect.x < 0 and mag == -1:
            game.rect.x += self.loop_length
        elif game.rect.x >= prepare.RENDER_SIZE[0] and mag == 1:
            game.rect.x -= self.loop_length

    def startup(self, persistent):
        super(LobbyScreen, self).startup(persistent)
        games = self.controller.game_thumbs
        self.update_screen_buttons(games)

    def exit_game(self, *args):
        self.done = True
        self.quit = True

    def change_state(self, next_state):
        self.done = True
        self.next = next_state

    def get_event(self, event, scale=(1,1)):
        if event.type == pg.QUIT:
            self.exit_game()
        else:
            self.buttons.get_event(event)
            self.game_buttons.get_event(event)

    def update(self, surface, keys, current_time, dt, scale):
        mouse_pos = tools.scaled_mouse_pos(scale)
        self.buttons.update(mouse_pos)
        self.game_buttons.update(mouse_pos)
        self.animations.update(dt)
        self.draw(surface)

    def draw(self, surface):
        rect = surface.get_rect()
        surface.fill(prepare.BACKGROUND_BASE)
        self.buttons.draw(surface)
        for button in self.game_buttons:
            if button.rect.colliderect(rect):
                button.draw(surface)
Пример #34
0
class StatsMenu(data.state.State):
    """
    This state allows the player to choose which game's stats they
    want to view or return to the lobby.
    """
    name = "stats_menu"

    def __init__(self):
        super(StatsMenu, self).__init__()
        self.font = prepare.FONTS["Saniretro"]
        self.title = None
        self.buttons = ButtonGroup()
        self.labels = []
        self.lines = []
        self.use_music_handler = False

    def collect_games_with_stats(self):
        for name, scene in self.controller.query_all_states().items():
            if hasattr(scene, 'initialize_stats'):
                yield name

    def make_labels(self):
        self.labels = []
        cash = self.player.cash
        balance = self.player.account_balance
        assets = cash + balance
        starting_cash = prepare.MONEY
        profit = assets - starting_cash
        label_info = [("Cash", cash, 110), ("Account", balance, 150),
                      ("Assets", assets, 198),
                      ("Starting Cash", -starting_cash, 238),
                      ("Profit", profit, 283)]
        left = 500
        right = 900
        for name, value, topy in label_info:
            label1 = Label(self.font, 36, name, "white",
                           {"topleft": (left, topy)})
            color = "darkgreen" if value >= 0 else "darkred"
            label2 = Label(self.font, 36, "{:.2f}".format(value), color,
                           {"topright": (right, topy)})
            self.labels.extend([label1, label2])
        self.lines = [((left, 193), (right, 193)), ((left, 280), (right, 280))]

    def make_buttons(self, games, screen_rect, col=2):
        spacer_x = 20
        spacer_y = 20
        start_y = 410
        start_x = (screen_rect.w - NeonButton.width * col - spacer_x *
                   (col - 1)) // 2
        buttons = ButtonGroup()
        for i, game in enumerate(games):
            y, x = divmod(i, col)
            pos = (start_x + x * (NeonButton.width + spacer_x),
                   start_y + y * (NeonButton.height + spacer_y))
            button = NeonButton(pos, game, self.view_game_stats, game, buttons)
        pos = (screen_rect.centerx - (NeonButton.width // 2),
               screen_rect.bottom - (NeonButton.height + 10))
        NeonButton(pos,
                   "Lobby",
                   self.back_to_lobby,
                   None,
                   buttons,
                   bindings=[pg.K_ESCAPE])
        return buttons

    def back_to_lobby(self, *args):
        self.done = True
        self.next = "lobby"

    def view_game_stats(self, game):
        self.persist["current_game_stats"] = game
        self.next = "stats_screen"
        self.done = True

    def startup(self, current_time, persistent):
        screen_rect = pg.Rect((0, 0), prepare.RENDER_SIZE)
        self.title = Label(
            self.font, 64, "Statistics", "darkred",
            {"midtop": (screen_rect.centerx, screen_rect.top + 10)})
        self.start_time = current_time
        self.persist = persistent
        self.player = self.persist["casino_player"]
        games = self.collect_games_with_stats()
        self.buttons = self.make_buttons(games, screen_rect, 3)
        self.make_labels()

    def get_event(self, event, scale=(1, 1)):
        if event.type == pg.QUIT:
            self.done = True
            self.next = "lobby"
        self.buttons.get_event(event)

    def draw(self, surface):
        surface.fill(prepare.BACKGROUND_BASE)
        self.title.draw(surface)
        self.buttons.draw(surface)
        for label in self.labels:
            label.draw(surface)
        for line in self.lines:
            pg.draw.line(surface, pg.Color("white"), *line)

    def update(self, surface, keys, current_time, dt, scale):
        mouse_pos = tools.scaled_mouse_pos(scale)
        self.buttons.update(mouse_pos)
        self.draw(surface)