Ejemplo n.º 1
0
class VideoPoker(data.state.State):
    """Class to represent the Video Poker game."""
    show_in_lobby = True
    name = 'video_poker'

    def __init__(self):
        super(VideoPoker, self).__init__()
        w, h = prepare.RENDER_SIZE
        self.screen_rect = pg.Rect((0, 0), (w, h))
        self.machine = Machine((0, 0), (w - 300, h))
        pos = (self.screen_rect.right - 330, self.screen_rect.bottom - 120)
        self.lobby_button = NeonButton(pos, "lobby", self.back_to_lobby)
        self.casino_player = None

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

        :return: collections.OrderedDict
        """
        stats = OrderedDict([
            ("games played", 0),
            ("games won", 0),
            ("games lost", 0),
            ("double ups won", 0),
            ("double ups lost", 0),
            ("total wagered", 0),
            ("total won", 0),
            ("total lost", 0),
        ])
        return stats

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

    def startup(self, current_time, persistent):
        self.persist = persistent
        self.casino_player = self.persist["casino_player"]
        self.casino_player.current_game = self.name
        self.machine.startup(self.casino_player)

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

        self.lobby_button.get_event(event)
        self.machine.get_event(event, scale)

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

    def draw(self, surface, dt):
        surface.fill(prepare.FELT_GREEN)
        self.machine.draw(surface)
        self.lobby_button.draw(surface)
Ejemplo n.º 2
0
class CreditsScreen(data.state.State):
    """
    This is the main state governing the credits screen.
    """
    name = 'credits'

    def __init__(self):
        super(CreditsScreen, self).__init__()
        self.screen = pg.Rect((0, 0), prepare.RENDER_SIZE)
        self.next = "lobby"
        self.font = prepare.FONTS["Saniretro"]
        self.dev_names = DEVELOPERS
        self.artist_names = ARTISTS
        self.assets_names = ASSETS_NAMES
        self.software_names = SOFTWARE
        self.zipper_blocks =[]
        self.zipper_block = None
        self.chip_curtain = None
        pos = (self.screen.centerx-(NeonButton.width//2),
               self.screen.bottom-NeonButton.height-10)
        self.done_button = NeonButton(pos, "Lobby", self.back_to_lobby)
        self.use_music_handler = False

    def back_to_lobby(self, *args):
        self.done = True
        pg.mixer.stop()

    def make_groups(self, names, group_size=5):
        return [names[i:i+group_size] for i in range(0, len(names), group_size)]

    def make_titles_blocks(self, title_name_pairs):
        titles = []
        zipper_blocks = []
        for pair in title_name_pairs:
            title_text, names = pair
            title = SlotReelTitle((self.screen.centerx, 20), title_text, initial_move=(0, -120))
            grouped = self.make_groups(names)
            for group in grouped:
                block = ZipperBlock(self.font, group, (700, 230))
                zipper_blocks.append(block)
                titles.append(title)
        return iter(titles), iter(zipper_blocks)

    def startup(self, current_time, persistent):
        """
        Prepare title, spinners, and zipper blocks.  Names are randomized each
        time so that no single dev is always first in the credits.
        """
        self.persist = persistent
        self.zipper_blocks = []
        dev_names = self.dev_names[:]
        artist_names = self.artist_names[:]
        assets_names = self.assets_names[:]
        software_names = self.software_names[:]
        for names in (dev_names, artist_names, assets_names):
            random.shuffle(names)
        self.titles, self.zipper_blocks = self.make_titles_blocks(
                                                [("Developers", dev_names),
                                                ("Artists", artist_names),
                                                ("Assets", assets_names),
                                                ("Software", software_names)])
        self.title = next(self.titles)
        self.zipper_block = next(self.zipper_blocks)
        spots = [(self.title.rect.left-100, self.title.rect.centery),
                 (self.title.rect.right+100, self.title.rect.centery)]
        self.spinners = pg.sprite.Group()
        Spinner(spots[0], "black", self.spinners)
        Spinner(spots[1], "black", self.spinners, reverse=True)
        self.chip_curtain = None
        self.title.startup()

    def get_event(self, event, scale=(1, 1)):
        """
        Set the state to done on Xing; pressing escape; or clicking the
        lobby button.
        """
        if event.type == pg.QUIT:
            self.back_to_lobby()
        elif event.type == pg.KEYUP and event.key == pg.K_ESCAPE:
            self.back_to_lobby()
        self.done_button.get_event(event)

    def switch_blocks(self):
        """
        Switch to the next zipper block and title.  If all blocks have been
        used, initialize the chip_curtain.
        """
        try:
            rect = self.title.rect
            self.zipper_block = next(self.zipper_blocks)
            self.title = next(self.titles)
            if self.title.rect != rect:
                rect = self.title.rect
                spots = [(rect.x-100, rect.centery),
                         (rect.right+100, rect.centery)]
                self.spinners.empty()
                Spinner(spots[0], "blue", self.spinners)
                Spinner(spots[1], "blue", self.spinners, reverse=True)
                self.title.startup()
        except StopIteration:
            self.end_titles = []


            self.zipper_block = None
            self.title = None
            self.spinners.empty()
            self.back_to_lobby()

    def update(self, surface, keys, current_time, dt, scale):
        """Update all elements and then draw the state."""
        mouse_pos = tools.scaled_mouse_pos(scale)
        self.done_button.update(mouse_pos)
        if self.title:
            if self.title.moving:
                for spinner in self.spinners:
                    spinner.rect.move_ip(self.title.move_speed)
            self.title.update()

        if self.zipper_block and self.title.spun_out:
            self.zipper_block.update(dt)
            if self.zipper_block.done:
                self.switch_blocks()
        if self.chip_curtain:
            self.chip_curtain.update(dt)
            if self.chip_curtain.done:
                self.done = True
        self.spinners.update(dt)
        self.draw(surface)

    def draw(self, surface):
        """Render all currently active elements to the target surface."""
        surface.fill(prepare.BACKGROUND_BASE)
        if self.title:
            self.title.draw(surface)
        self.spinners.draw(surface)
        if self.zipper_block:
            self.zipper_block.draw(surface)
        if self.chip_curtain:
            self.chip_curtain.draw(surface)
        self.done_button.draw(surface)
Ejemplo n.º 3
0
class Betting(BlackjackState):
    def __init__(self):
        super(Betting, self).__init__()
        self.make_buttons()
        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,
                                       None,
                                       self.buttons,
                                       bindings=[pg.K_ESCAPE])

    def back_to_lobby(self, *args):
        player = self.game.player
        for hand in player.hands:
            player.chip_pile.add_chips(cash_to_chips(
                hand.bet.get_chip_total()))
        self.leave_state()

    def startup(self, game):
        self.game = game
        if self.game.quick_bet and (
                self.game.quick_bet <=
                self.game.player.chip_pile.get_chip_total()):
            chips = self.game.player.chip_pile.withdraw_chips(
                self.game.quick_bet)
            self.game.current_player_hand.bet.add_chips(chips)
            self.deal()
        elif self.game.advisor_active:
            self.game.advisor.queue_text(
                "Click chips in your chip pile to place bet",
                dismiss_after=3000)
            self.game.advisor.queue_text(
                "Click chips in pot to remove from bet", dismiss_after=3000)

    def make_buttons(self):
        self.buttons = ButtonGroup()
        side_margin = 10
        vert_space = 15
        left = self.screen_rect.right - (NeonButton.width + side_margin)
        top = self.screen_rect.bottom - (
            (NeonButton.height * 5) + vert_space * 4)
        self.deal_button = NeonButton((left, top), "Deal", self.deal, None,
                                      self.buttons)

    def deal(self, *args):
        bets = [x.bet.get_chip_total() for x in self.game.player.hands]
        self.game.last_bet = max(bets)
        self.game.quick_bet = 0
        self.next = "Dealing"
        self.game.casino_player.increase("games played")
        self.game.advisor.empty()
        self.done = True

    def get_event(self, event, scale):
        self.game.get_event(event)
        if event.type == pg.QUIT:
            self.back_to_lobby()
        elif event.type == pg.MOUSEBUTTONDOWN:
            pos = tools.scaled_mouse_pos(scale, event.pos)
            if not self.game.moving_stacks and event.button == 1:
                new_movers = self.game.player.chip_pile.grab_chips(pos)
                self.last_click = pg.time.get_ticks()
                if new_movers:
                    self.play_chip_sound()
                    self.game.moving_stacks.append(new_movers)
                for hand in self.game.player.hands:
                    unbet_stack = hand.bet.grab_chips(pos)
                    if unbet_stack:
                        self.play_chip_sound()
                        self.game.player.chip_pile.add_chips(unbet_stack.chips)

        elif event.type == pg.MOUSEBUTTONUP:
            now = pg.time.get_ticks()
            span = now - self.last_click
            pos = tools.scaled_mouse_pos(scale, event.pos)
            if self.game.moving_stacks and event.button == 1:
                for stack in self.game.moving_stacks:
                    stack.rect.bottomleft = pos
                    if self.game.chip_rack.rect.collidepoint(pos):
                        self.play_chip_sound()
                        self.game.player.chip_pile.add_chips(
                            self.game.chip_rack.break_chips(stack.chips))
                    elif span > 300 and self.game.player.chip_pile.rect.collidepoint(
                            pos):
                        self.play_chip_sound()
                        self.game.player.chip_pile.add_chips(stack.chips)
                    else:
                        self.play_chip_sound()
                        self.game.current_player_hand.bet.add_chips(
                            stack.chips)
                self.game.moving_stacks = []
        if self.window:
            self.window.get_event(event)
        else:
            self.lobby_button.get_event(event)
            self.deal_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)
        bets = [x.bet.get_chip_total() for x in self.game.player.hands]
        self.deal_button.visible = any(bets) and not self.game.moving_stacks

        if self.window:
            self.window.update(mouse_pos)
            if self.window.done:
                self.window = None
        else:
            self.lobby_button.update(mouse_pos)
            self.deal_button.update(mouse_pos)
        for stack in self.game.moving_stacks:
            x, y = mouse_pos
            stack.rect.bottomleft = (x - (self.game.chip_size[0] // 2), y + 6)

    def draw(self, surface):
        g = self.game
        surface.fill(prepare.FELT_GREEN)
        for label in g.labels:
            label.draw(surface)
        g.player.draw_hands(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)
        for stack in g.moving_stacks:
            stack.draw(surface)
        self.buttons.draw(surface)
        self.draw_advisor(surface)
        self.window and self.window.draw(surface)
Ejemplo n.º 4
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)
Ejemplo n.º 5
0
class DealerTurn(BlackjackState):
    def __init__(self):
        super(DealerTurn, 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])

    def startup(self, game):
        self.game = game
        g = game
        if all([hand.busted for hand in g.player.hands]):
            g.dealer.hand.final = True
            self.state = "End Round"
        delay = 1000
        while not g.dealer.hand.final:
            hand_score = g.dealer.hand.best_score()
            if hand_score is None:
                g.dealer.hand.busted = True
                g.dealer.hand.final = True
            elif hand_score == 21 and len(g.dealer.hand.cards) == 2:
                g.dealer.hand.blackjack = True
                g.dealer.hand.final = True
            elif hand_score < 17:
                self.hit(g.dealer.hand, delay)
                delay += 1000
            else:
                g.dealer.hand.final = True

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

    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.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)
        if self.window:
            self.window.update(mouse_pos)
            if self.window.done:
                self.window = None
        else:
            self.lobby_button.update(mouse_pos)
            self.animations.update(dt)
            if not self.animations:
                self.next = "Show Results"
                self.done = True

    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)
        self.draw_advisor(surface)
        self.game.player.chip_pile.draw(surface)
        self.window and self.window.draw(surface)
Ejemplo n.º 6
0
class ShowResults(BlackjackState):
    def __init__(self):
        super(ShowResults, 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.coin_sound = prepare.SFX["coins"]

    def startup(self, game):
        self.game = game
        self.game.result_labels = []
        self.fade_labels = []
        self.alpha = 255
        total_ani_time = 2000
        fade_ani = Animation(alpha=0, duration=total_ani_time)
        fade_ani.start(self)
        self.animations.add(fade_ani)
        self.game.tally_hands()
        payout = self.game.pay_out()
        if payout:
            self.coin_sound.play()
        hands = self.game.player.hands
        if len(hands) > 2:
            text_size = 64
        elif len(hands) == 2:
            text_size = 80
        else:
            text_size = 96
        win_piles = []
        loss_piles = []
        self.winnings = []
        self.losses = []
        for hand in hands:
            amount = hand.bet.get_chip_total()
            hand.bet_amount = amount
            bl = hand.bet.stacks[0].rect.bottomleft
            if hand.blackjack:
                text, color = "Blackjack", "gold3"
                text_size -= 8
                chips = cash_to_chips(int(amount * 2.5))
                amount = int(amount * 1.5)
                win_piles.append(BetPile(bl, self.game.chip_size, chips))
            elif hand.winner:
                text, color = "Win", "gold3"
                chips = cash_to_chips(amount * 2)
                win_piles.append(BetPile(bl, self.game.chip_size, chips))
            elif hand.push:
                text, color = "Push", "gold3"
                chips = cash_to_chips(amount)
                win_piles.append(BetPile(bl, self.game.chip_size, chips))
            elif hand.busted:
                text, color = "Bust", "darkred"
                chips = cash_to_chips(amount)
                loss_piles.append(BetPile(bl, self.game.chip_size, chips))
                amount *= -1
            else:
                text, color = "Loss", "darkred"
                chips = cash_to_chips(amount)
                loss_piles.append(BetPile(bl, self.game.chip_size, chips))
                amount *= -1
            centerx = (hand.slots[0].left + hand.slots[-1].right) // 2
            centery = hand.slots[0].centery
            label = Blinker(self.font, text_size, text, color,
                            {"center": (centerx, centery)}, 450)
            self.game.result_labels.append(label)
            amt_color = "darkgreen" if amount >= 0 else "darkred"

            bet_label = Label(self.font,
                              120,
                              "{:+}".format(amount),
                              amt_color, {"bottomleft": bl},
                              bg=prepare.FELT_GREEN)
            move_ani = Animation(bottom=bl[1] - 150,
                                 duration=total_ani_time,
                                 round_values=True)
            move_ani.start(bet_label.rect)
            self.animations.add(move_ani)
            self.fade_labels.append(bet_label)
            hand.bet.chips = []
            hand.bet.stacks = []

        payout_duration = 1000
        center = self.game.player.chip_pile.rect.center
        for pile in win_piles:
            self.winnings.append(pile)
            for stack in pile.stacks:
                ani = Animation(left=center[0],
                                bottom=center[1],
                                duration=payout_duration,
                                round_values=True)
                ani.start(stack.rect)
                self.animations.add(ani)
        center = self.game.chip_rack.rect.center
        for loss_pile in loss_piles:
            self.losses.append(loss_pile)
            for stack in loss_pile.stacks:
                ani = Animation(left=center[0],
                                bottom=center[1],
                                duration=payout_duration,
                                round_values=True)
                ani.start(stack.rect)
                self.animations.add(ani)
        pay_ani = Task(self.game.player.chip_pile.add_chips,
                       payout_duration,
                       args=[payout])
        remove_chips = Task(self.remove_chips, payout_duration)
        end_it = Task(self.end_state, total_ani_time)
        self.animations.add(pay_ani, remove_chips, end_it)

    def remove_chips(self):
        self.winnings = []
        self.losses = []

    def end_state(self):
        self.next = "End Round"
        self.done = True

    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.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 blinker in self.game.result_labels:
            blinker.update(dt)
        self.animations.update(dt)
        for fader in self.fade_labels:
            fader.image.set_alpha(self.alpha)
        if self.window:
            self.window.update(mouse_pos)
            if self.window.done:
                self.window = None
        else:
            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)
        for fader in self.fade_labels:
            fader.draw(surface)
        self.draw_advisor(surface)
        self.game.player.chip_pile.draw(surface)
        for pile in self.winnings:
            pile.draw(surface)
        for pile_ in self.losses:
            pile_.draw(surface)
        self.window and self.window.draw(surface)
Ejemplo n.º 7
0
class Bingo(statemachine.StateMachine):
    """State to represent a bing game"""
    name = "bingo"
    show_in_lobby = True

    def __init__(self):
        """Initialise the bingo game"""
        #
        self.verbose = False
        self.sound_muted = prepare.ARGS['debug']
        #
        self.screen_rect = pg.Rect((0, 0), prepare.RENDER_SIZE)
        self.auto_pick = S['debug-auto-pick']
        #
        self.ui = common.ClickableGroup()
        #
        self.lobby_button = NeonButton(S['lobby-position'], 'Lobby', self.return_to_lobby)
        self.new_game_button = NeonButton(S['new-game-position'], 'New', lambda x: self.restart_game(None, None))
        #
        # The controls to allow selection of different numbers of cards
        self.card_selector = cardselector.CardSelector('card-selector', self)
        self.card_selector.linkEvent(events.E_NUM_CARDS_CHANGED, self.change_number_of_cards)
        self.ui.append(self.card_selector.ui)
        #
        self.create_card_collection()
        self.ui.extend(self.cards)
        #
        self.winning_pattern = patterns.PATTERNS[0]
        #
        self.pattern_buttons = common.DrawableGroup()
        self.debug_buttons = common.DrawableGroup()
        self.buttons = common.DrawableGroup([self.pattern_buttons])
        #
        if prepare.DEBUG:
            self.buttons.append(self.debug_buttons)
        #
        super(Bingo, self).__init__()
        #
        # The machine for picking balls
        self.ball_machine = ballmachine.BallMachine('ball-machine', self)
        self.ball_machine.start_machine()
        self.ui.append(self.ball_machine.buttons)
        #
        self.all_cards = common.DrawableGroup()
        self.all_cards.extend(self.cards)
        self.all_cards.extend(self.dealer_cards)
        #
        B.linkEvent(events.E_PLAYER_PICKED, self.player_picked)
        B.linkEvent(events.E_PLAYER_UNPICKED, self.player_unpicked)
        B.linkEvent(events.E_CARD_COMPLETE, self.card_completed)
        #
        self.current_pick_sound = 0
        self.last_pick_time = 0

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

        :return: collections.OrderedDict
        """
        stats = OrderedDict([("games played", 0),
                             ("cards won", 0),
                             ("cards lost", 0),
                             ("total lost", 0),
                             ("total won", 0),
                             ("time played", '00:00:00'),
                             ("_last squares", [])])
        return stats

    def startup(self, current_time, persistent):
        """This method will be called each time the state resumes."""
        self.persist = persistent
        self.casino_player = self.persist["casino_player"]
        self.casino_player.current_game = self.name
        #
        self.casino_player.increase('games played')
        self.cards.set_card_numbers(self.casino_player.get('_last squares', []))
        self.money_display.set_money(self.casino_player.cash)
        self.time_started = time.time()

    def get_event(self, event, scale=(1,1)):
        """Check for events"""
        super(Bingo, self).get_event(event, scale)
        self.lobby_button.get_event(event)
        self.new_game_button.get_event(event)
        #
        if event.type == pg.QUIT:
            if prepare.ARGS['straight']:
                pg.quit()
                sys.exit()
            else:
                self.done = True
                self.next = "lobby"
        elif event.type in (pg.MOUSEBUTTONDOWN, pg.MOUSEMOTION):
            #
            self.ui.process_events(event, scale)
            self.bonus_buttons.process_events(event, scale)
            #
            pos = tools.scaled_mouse_pos(scale, event.pos)
        elif event.type == pg.KEYUP:
            if event.key == pg.K_ESCAPE:
                self.done = True
                self.next = "lobby"
            elif event.key == pg.K_SPACE:
                self.next_chip(None, None)
            elif event.key == pg.K_m:
                #self.persist["music_handler"].mute_unmute_music()
                self.sound_muted = not self.sound_muted
            elif event.key == pg.K_f:
                for card in self.cards:
                    self.add_generator('flash-labels', card.flash_labels())

    def return_to_lobby(self, arg):
        """Return to the lobby screen"""
        self.game_started = False
        self.done = True
        self.next = "lobby"
        self.casino_player.set('_last squares', self.cards.get_card_numbers())
        self.casino_player.cash = self.money_display.amount
        self.casino_player.increase_time('time played', time.time() - self.time_started)

    def drawUI(self, surface, scale):
        """Update the main surface once per frame"""
        mouse_pos = tools.scaled_mouse_pos(scale, pg.mouse.get_pos())
        self.lobby_button.update(mouse_pos)
        self.new_game_button.update(mouse_pos)
        #
        surface.fill(S['table-color'])
        #
        self.lobby_button.draw(surface)
        self.new_game_button.draw(surface)
        self.all_cards.draw(surface)
        self.ball_machine.draw(surface)
        self.buttons.draw(surface)
        self.card_selector.draw(surface)
        self.money_display.draw(surface)
        self.bonus_display.draw(surface)
        self.bonus_buttons.draw(surface)

    def initUI(self):
        """Initialise the UI display"""
        #
        # Buttons that show the winning patterns
        x, y = S['winning-pattern-position']
        for idx, pattern in enumerate(patterns.PATTERNS):
            dx, dy = S['winning-pattern-buttons'][pattern.name]
            new_button = patterns.PatternButton(
                idx, (x + dx, y + dy),
                'bingo-wide-red-button', 'bingo-wide-red-button-off', 'winning-pattern',
                pattern.name,
                pattern == self.winning_pattern, S,
                scale=S['winning-pattern-scale']
            )
            new_button.linkEvent(common.E_MOUSE_CLICK, self.change_pattern, pattern)
            new_button.pattern = pattern
            self.pattern_buttons.append(new_button)
        self.ui.extend(self.pattern_buttons)
        #
        # Simple generator to flash the potentially winning squares
        self.add_generator('potential-winners', self.flash_potential_winners())
        #
        # Display of the money the player has
        self.money_display = moneydisplay.MoneyDisplay(
            'money-display', S['money-position'], 0, self
        )
        prepare.BROADCASTER.linkEvent(events.E_SPEND_MONEY, self.spend_money)
        #
        # Button for next chip
        self.next_chip_button = common.ImageOnOffButton(
                'next-chip', S['next-chip-position'],
                'bingo-next-chip-on', 'bingo-next-chip-off', 'next-chip',
                'Next Chip (SPC)', True,
                S, scale=S['next-chip-scale']
        )
        self.next_chip_button.linkEvent(common.E_MOUSE_CLICK, self.next_chip)
        self.ui.append(self.next_chip_button)
        self.buttons.append(self.next_chip_button)
        #
        # Menu bar
        self.menu_bar = common.NamedSprite(
            'bingo-menu-bar', S['menu-bar-position'], scale=S['menu-bar-scale']
        )
        self.buttons.append(self.menu_bar)
        #
        self.bonus_display = bonusdisplay.BonusDisplay(
            'bonus-display', S['bonus-light-position'], self)
        #
        self.bonus_buttons = bonusbuttons.BonusButtonsDisplay(
            'bonus-buttons', S['bonus-buttons-position'], self
        )
        self.bonus_display.linkEvent(
            events.E_BONUS_REACHED,
            lambda o, a: self.bonus_buttons.pick_new_button()
        )
        #
        # Debugging buttons
        if prepare.DEBUG and S['show-debug-buttons']:
            self.debug_buttons.append(common.ImageOnOffButton(
                'auto-pick', S['debug-auto-pick-position'],
                'bingo-yellow-button', 'bingo-yellow-off-button', 'small-button',
                'Auto pick',
                S['debug-auto-pick'],
                S, scale=S['small-button-scale']
            ))
            self.debug_buttons[-1].linkEvent(common.E_MOUSE_CLICK, self.toggle_auto_pick)
            #
            self.debug_buttons.append(common.ImageButton(
                'restart', S['debug-restart-position'],
                'bingo-yellow-button', 'small-button',
                'Restart',
                S, scale=S['small-button-scale']
            ))
            self.debug_buttons[-1].linkEvent(common.E_MOUSE_CLICK, self.restart_game)
            #
            self.debug_buttons.append(common.ImageButton(
                'next-ball', S['debug-next-ball-position'],
                'bingo-yellow-button', 'small-button',
                'Next Ball',
                S, scale=S['small-button-scale']
            ))
            self.debug_buttons[-1].linkEvent(common.E_MOUSE_CLICK, self.next_ball)
            #
            self.debug_buttons.append(common.ImageButton(
                'new-cards', S['debug-new-cards-position'],
                'bingo-yellow-button', 'small-button',
                'New Cards',
                S, scale=S['small-button-scale']
            ))
            self.debug_buttons[-1].linkEvent(common.E_MOUSE_CLICK, self.draw_new_cards)
            self.ui.extend(self.debug_buttons)

    def spend_money(self, amount, arg):
        """Money has been spent"""
        self.log.info('Money has been spent {1} by {0}'.format(arg, amount))
        self.money_display.add_money(amount)
        if amount < 0:
            self.play_sound('bingo-pay-money')
            self.casino_player.increase('total lost', -amount)
        else:
            self.casino_player.increase('total won', amount)

    def change_pattern(self, obj, pattern):
        """Change the winning pattern"""
        self.log.info('Changing pattern to {0}'.format(pattern.name))
        #
        # Account for the random factor
        if pattern.name == "Random":
            self.add_generator(
                'randomize-buttons',
                self.randomly_highlight_buttons(
                    self.pattern_buttons[-1],
                    self.pattern_buttons[:-1],
                    S['randomize-button-number'], S['randomize-button-delay'],
                    lambda b: self.change_pattern(None, b.pattern)
                )
            )
            return
        #
        self.winning_pattern = pattern
        self.highlight_patterns(self.winning_pattern, one_shot=True)
        #
        # Clear all flashing squares
        for card in self.all_cards:
            card.potential_winning_squares = []
            for square in card.squares.values():
                square.is_focused = False
        #
        # Update UI
        for button in self.pattern_buttons:
            button.state = (button.pattern == self.winning_pattern)

    def toggle_auto_pick(self, obj, arg):
        """Toggle whether we are auto-picking numbers"""
        self.log.debug('Toggling auto-pick')
        self.auto_pick = not self.auto_pick
        self.debug_buttons[0].state = self.auto_pick

    def restart_game(self, obj, arg):
        """Restart the game"""
        self.log.info('Restart game')
        self.ball_machine.reset_machine(self.ball_machine.interval)
        self.cards.reset()
        self.dealer_cards.reset()
        self.current_pick_sound = 0
        self.last_pick_time = 0
        self.casino_player.increase('games played')

    def next_ball(self, obj, arg):
        """Move on to the next ball

        This is a debugging method - no using the normal UI

        """
        self.ball_machine.call_next_ball()

    def next_chip(self, obj, arg):
        """Move on to the next ball"""
        if self.next_chip_button.state:
            self.ball_machine.call_next_ball()
            self.add_generator('next-chip-animation', self.animate_next_chip())

    def animate_next_chip(self):
        """Animate the button after choosing another chip"""
        self.next_chip_button.state = False
        yield S['next-chip-delay'] * 1000
        self.next_chip_button.state = True

    def draw_new_cards(self, obj,  arg):
        """Draw a new set of cards"""
        self.log.debug('Drawing new set of cards')
        self.cards.draw_new_numbers()
        self.cards.reset()

    def create_card_collection(self):
        """Return a new card collection"""
        number = self.card_selector.number_of_cards
        self.cards = playercard.PlayerCardCollection(
            'player-card',
            S['player-cards-position'],
            S['player-card-offsets'][number],
            self
        )
        dx, dy = S['dealer-card-offset']
        dealer_offsets = [(dx + x, dy +y) for x, y in S['player-card-offsets'][number]]
        self.dealer_cards = dealercard.DealerCardCollection(
            'dealer-card',
            S['player-cards-position'],
            dealer_offsets,
            self
        )

    def change_number_of_cards(self, number, arg=None):
        """Change the number of cards in play"""
        self.log.info('Changing the number of cards to {0}'.format(number))
        #
        # Store off the old card number to reuse
        self.casino_player.set('_last squares', self.cards.get_card_numbers())
        #
        # Remove old cards
        for card in self.cards:
            self.all_cards.remove(card)
            self.ui.remove(card)
        for card in self.dealer_cards:
            self.all_cards.remove(card)
        #
        # Create new cards
        self.create_card_collection()
        self.cards.set_card_numbers(self.casino_player.get('_last squares', []))
        #
        self.all_cards.extend(self.cards)
        self.all_cards.extend(self.dealer_cards)
        self.ui.extend(self.cards)
        self.restart_game(None, None)

    def highlight_patterns(self, pattern, one_shot):
        """Test method to cycle through the winning patterns"""
        self.log.debug('Creating new highlight pattern generators')
        for card in self.cards:
            self.add_generator(
                'highlight-patterns-card-%s' % card.name,
                self.highlight_pattern(card, pattern, one_shot)
            )

    def highlight_pattern(self, card, pattern, one_shot):
        """Highlight a particular pattern on a card"""
        for squares in pattern.get_matches(card):
            for square in squares:
                square.highlighted_state = bingocard.S_GOOD
            card.set_dirty()
            yield 100
            for square in squares:
                square.highlighted_state = bingocard.S_NONE
            card.set_dirty()
            yield 10
        #
        if not one_shot:
            self.add_generator('highlight', self.highlight_pattern(card, pattern, one_shot=False))

    def ball_picked(self, ball):
        """A ball was picked"""
        # Turn off the button to prevent the player from accidentally choosing another
        # ball at the same time
        self.add_generator('next-chip-animation', self.animate_next_chip())
        #
        # If auto-picking then update the cards
        auto_pick_cards = list(self.dealer_cards)
        if self.auto_pick:
            auto_pick_cards.extend(self.cards)
        for card in auto_pick_cards:
            card.call_square(ball.number)
        #
        # Highlight the card labels
        for card in self.all_cards:
            card.highlight_column(ball.letter)

    def player_picked(self, square, arg):
        """The player picked a square"""
        if not square.card.is_active:
            return
        #
        self.bonus_display.add_bonus()
        #
        # Check to see if we created a new potentially winning square
        called_squares = list(square.card.called_squares)
        prior_called_squares = list(called_squares)
        prior_called_squares.remove(square.text)
        #
        _, winners = self.winning_pattern.get_number_to_go_and_winners(square.card, called_squares)
        _, prior_winners = self.winning_pattern.get_number_to_go_and_winners(square.card, prior_called_squares)
        self.log.debug('{0} / {1}'.format(winners, prior_winners))
        #
        if len(winners) > len(prior_winners):
            self.play_sound('bingo-potential-winner')
        #
        # Increment sound if we did this quickly
        if time.time() - self.last_pick_time < S['player-pick-interval']:
            self.current_pick_sound = min(self.current_pick_sound + 1, len(S['player-pick-sounds']) - 1)
        else:
            self.current_pick_sound = 0
        self.last_pick_time = time.time()
        self.play_sound(S['player-pick-sounds'][self.current_pick_sound])
        #
        self.log.info('Player picked {0}'.format(square))

    def player_unpicked(self, square, arg):
        """The player unpicked a square"""
        self.log.info('Player unpicked {0}'.format(square))
        self.play_sound('bingo-unpick')

    def flash_potential_winners(self):
        """Flash the squares that are potential winners"""
        while True:
            for state, delay in S['card-focus-flash-timing']:
                for card in self.all_cards:
                    potential_squares = card.potential_winning_squares
                    if potential_squares:
                        for square in potential_squares:
                            square.is_focused = state
                        card.set_dirty()
                yield delay * 1000

    def play_sound(self, name):
        """Play a named sound - respects the mute settings"""
        if not self.sound_muted:
            prepare.SFX[name].play()

    def get_missing_squares(self, squares):
        """Return a list of the numbers that have not been called"""
        return [square for square in squares if square.text not in self.ball_machine.called_balls]

    def card_completed(self, card, arg):
        """A card was completed"""
        self.log.info('Card {0} owned by {1} was completed'.format(card.index, card.card_owner))
        #
        if card.card_owner == bingocard.T_PLAYER:
            self.casino_player.increase('cards won' if card.card_state == bingocard.S_WON else 'cards lost')
        else:
            self.casino_player.increase('cards won' if card.card_state == bingocard.S_LOST else 'cards lost')
        #
        # Find the matching card from the dealer or player and deactivate it
        other_card = self.cards[card.index] if card.card_owner == bingocard.T_DEALER else self.dealer_cards[card.index]
        other_card.active = False
        other_card.set_card_state(bingocard.S_LOST)
        #
        # Check for all cards done
        for item in self.cards:
            if item.active and item != card:
                return
        else:
            for item in self.cards:
                self.add_generator('flash-labels', item.flash_labels())

    def randomly_highlight_buttons(self, source_button, buttons, number_of_times, delay, final_callback, speed_up=None,
                                   states=(False, True)):
        """Randomly highlight buttons in a group and then call the callback when complete"""
        false_state, true_state = states
        last_chosen = None
        if source_button:
            source_button.state = true_state
        #
        # Turn all buttons off
        for button in buttons:
            button.state = false_state
        #
        for i in range(number_of_times):
            #
            # Choose one to highlight, but not the last one
            while True:
                chosen = random.choice(buttons)
                if chosen != last_chosen:
                    break
            #
            # Highlight it
            self.log.debug('Setting to button {0}, {1}'.format(buttons.index(chosen), chosen.name))
            chosen.state = true_state
            if last_chosen:
                last_chosen.state = false_state
            last_chosen = chosen
            #
            self.play_sound('bingo-beep')
            #
            if i != number_of_times - 1:
                yield delay
            #
            # Shortern delay
            delay *= speed_up if speed_up else S['randomize-button-speed-up']
        #
        if source_button:
            source_button.state = false_state
        #
        final_callback(chosen)

    def pause_machine(self, delay):
        """Pause the ball machine for a certain length of time"""
        self.ball_machine.pause()

        def unpause():
            yield delay * 1000
            self.ball_machine.unpause()

        self.add_generator('un-pause', unpause())

    def double_up(self):
        """Double up all cards"""
        for card in self.cards:
            card.double_down()

    def slow_machine(self):
        """Slow the machine down"""
        self.ball_machine.change_speed(None, self.ball_machine.speed_transitions[0])

    def start_auto_pick(self, delay):
        """Temporarily auto pick the numbers"""
        self.auto_pick = True

        def unauto():
            yield delay * 1000
            self.auto_pick = False

        self.add_generator('un-auto', unauto())

    def win_card(self):
        """Win one of the cards"""
        possible_cards = [card for card in self.cards if card.active]
        if possible_cards:
            card = random.choice(possible_cards)
            card.set_card_state(bingocard.S_WON)
            self.play_sound(card.card_success_sound)
            B.processEvent((events.E_CARD_COMPLETE, card))
            card.active = False
Ejemplo n.º 8
0
class Dealing(BlackjackState):
    def __init__(self):
        super(Dealing, 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,
                                       None,
                                       bindings=[pg.K_ESCAPE])

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

    def flip_card(self, card):
        card.face_up = True

    def make_card_animations(self):
        g = self.game
        self.animations = pg.sprite.Group()
        deal_delay = 0
        for i in range(2):
            card = g.deck.draw_card()
            destination = g.current_player_hand.slots[-1]
            dest_x, dest_y = destination.topleft
            dur = get_distance(destination.center, card.pos) * 20 // card.speed
            ani = Animation(x=dest_x,
                            y=dest_y,
                            duration=dur,
                            delay=deal_delay,
                            round_values=True)
            ani2 = Task(self.play_deal_sound, deal_delay)
            ani3 = Task(self.flip_card, deal_delay + dur, args=(card, ))
            g.current_player_hand.cards.append(card)
            if not i % 2:
                g.player.add_slot(g.current_player_hand)
            ani.start(card.rect)
            self.animations.add(ani, ani2, ani3)
            deal_delay += dur
        for i in range(2):
            card = g.deck.draw_card()
            destination = g.dealer.hand.slots[-1]
            dest_x, dest_y = destination.topleft
            dur = get_distance(destination.center, card.pos) * 20 // card.speed
            ani = Animation(x=dest_x,
                            y=dest_y,
                            duration=dur,
                            delay=deal_delay,
                            round_values=True)
            ani2 = Task(self.play_deal_sound, deal_delay)
            ani.start(card.rect)
            g.dealer.hand.cards.append(card)
            g.dealer.add_slot()
            self.animations.add(ani, ani2)
            if i:
                ani3 = Task(self.flip_card, deal_delay + dur, args=(card, ))
                self.animations.add(ani3)
            deal_delay += dur

    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.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)
        if self.window:
            self.window.update(mouse_pos)
            if self.window.done:
                self.window = None
        else:
            self.lobby_button.update(mouse_pos)
            if self.animations:
                self.animations.update(dt)
            else:
                self.next = "Player Turn"
                self.done = True

    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.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)
        g.player.chip_pile.draw(surface)
        self.draw_advisor(surface)
        self.window and self.window.draw(surface)
Ejemplo n.º 9
0
class Betting(BlackjackState):
    def __init__(self):
        super(Betting, self).__init__()
        self.make_buttons()
        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, None, self.buttons, bindings=[pg.K_ESCAPE])

    def back_to_lobby(self, *args):
        player = self.game.player
        for hand in player.hands:
            player.chip_pile.add_chips(cash_to_chips(hand.bet.get_chip_total()))
        self.leave_state()

    def startup(self, game):
        self.game = game
        if self.game.quick_bet and (self.game.quick_bet <= self.game.player.chip_pile.get_chip_total()):
            chips = self.game.player.chip_pile.withdraw_chips(self.game.quick_bet)
            self.game.current_player_hand.bet.add_chips(chips)
            self.deal()
        elif self.game.advisor_active:
            self.game.advisor.queue_text("Click chips in your chip pile to place bet", dismiss_after=3000)
            self.game.advisor.queue_text("Click chips in pot to remove from bet", dismiss_after=3000)

    def make_buttons(self):
        self.buttons = ButtonGroup()
        side_margin = 10
        vert_space = 15
        left = self.screen_rect.right-(NeonButton.width + side_margin)
        top = self.screen_rect.bottom-((NeonButton.height*5)+vert_space*4)
        self.deal_button = NeonButton((left, top), "Deal", self.deal, None, self.buttons)

    def deal(self, *args):
        bets = [x.bet.get_chip_total() for x in self.game.player.hands]
        self.game.last_bet = max(bets)
        self.game.quick_bet = 0
        self.next = "Dealing"
        self.game.casino_player.increase("games played")
        self.game.advisor.empty()
        self.done = True

    def get_event(self, event, scale):
        self.game.get_event(event)
        if event.type == pg.QUIT:
            self.back_to_lobby()
        elif event.type == pg.MOUSEBUTTONDOWN:
            pos = tools.scaled_mouse_pos(scale, event.pos)
            if not self.game.moving_stacks and event.button == 1:
                new_movers = self.game.player.chip_pile.grab_chips(pos)
                self.last_click = pg.time.get_ticks()
                if new_movers:
                    self.play_chip_sound()
                    self.game.moving_stacks.append(new_movers)
                for hand in self.game.player.hands:
                    unbet_stack = hand.bet.grab_chips(pos)
                    if unbet_stack:
                        self.play_chip_sound()
                        self.game.player.chip_pile.add_chips(unbet_stack.chips)

        elif event.type == pg.MOUSEBUTTONUP:
            now = pg.time.get_ticks()
            span = now - self.last_click
            pos = tools.scaled_mouse_pos(scale, event.pos)
            if self.game.moving_stacks and event.button == 1:
                for stack in self.game.moving_stacks:
                    stack.rect.bottomleft = pos
                    if self.game.chip_rack.rect.collidepoint(pos):
                        self.play_chip_sound()
                        self.game.player.chip_pile.add_chips(self.game.chip_rack.break_chips(stack.chips))
                    elif span > 300 and self.game.player.chip_pile.rect.collidepoint(pos):
                        self.play_chip_sound()
                        self.game.player.chip_pile.add_chips(stack.chips)
                    else:
                        self.play_chip_sound()
                        self.game.current_player_hand.bet.add_chips(stack.chips)
                self.game.moving_stacks = []
        if self.window:
            self.window.get_event(event)
        else:
            self.lobby_button.get_event(event)
            self.deal_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)
        bets = [x.bet.get_chip_total() for x in self.game.player.hands]
        self.deal_button.visible = any(bets) and not self.game.moving_stacks

        if self.window:
            self.window.update(mouse_pos)
            if self.window.done:
                self.window = None
        else:
            self.lobby_button.update(mouse_pos)
            self.deal_button.update(mouse_pos)
        for stack in self.game.moving_stacks:
            x, y = mouse_pos
            stack.rect.bottomleft = (x - (self.game.chip_size[0] // 2),
                                         y + 6)

    def draw(self, surface):
        g = self.game
        surface.fill(prepare.FELT_GREEN)
        for label in g.labels:
            label.draw(surface)
        g.player.draw_hands(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)
        for stack in g.moving_stacks:
            stack.draw(surface)
        self.buttons.draw(surface)
        self.draw_advisor(surface)
        self.window and self.window.draw(surface)
Ejemplo n.º 10
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)
Ejemplo n.º 11
0
class ShowResults(BlackjackState):
    def __init__(self):
        super(ShowResults, 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.coin_sound = prepare.SFX["coins"]

    def startup(self, game):
        self.game = game
        self.game.result_labels = []
        self.fade_labels = []
        self.alpha = 255
        total_ani_time = 2000
        fade_ani = Animation(alpha=0, duration=total_ani_time)
        fade_ani.start(self)
        self.animations.add(fade_ani)
        self.game.tally_hands()
        payout = self.game.pay_out()
        if payout:
            self.coin_sound.play()
        hands = self.game.player.hands
        if len(hands) >2:
            text_size = 64
        elif len(hands) == 2:
            text_size = 80
        else:
            text_size = 96
        win_piles = []
        loss_piles = []
        self.winnings = []
        self.losses = []
        for hand in hands:
            amount = hand.bet.get_chip_total()
            hand.bet_amount  = amount
            bl = hand.bet.stacks[0].rect.bottomleft
            if hand.blackjack:
                text, color = "Blackjack", "gold3"
                text_size -= 8
                chips = cash_to_chips(int(amount * 2.5))
                amount = int(amount * 1.5)
                win_piles.append(BetPile(bl, self.game.chip_size, chips))
            elif hand.winner:
                text, color = "Win", "gold3"
                chips = cash_to_chips(amount * 2)
                win_piles.append(BetPile(bl, self.game.chip_size, chips))
            elif hand.push:
                text, color = "Push", "gold3"
                chips = cash_to_chips(amount)
                win_piles.append(BetPile(bl, self.game.chip_size, chips))
            elif hand.busted:
                text, color = "Bust", "darkred"
                chips = cash_to_chips(amount)
                loss_piles.append(BetPile(bl, self.game.chip_size, chips))
                amount *= -1
            else:
                text, color = "Loss", "darkred"
                chips = cash_to_chips(amount)
                loss_piles.append(BetPile(bl, self.game.chip_size, chips))
                amount *= -1
            centerx = (hand.slots[0].left + hand.slots[-1].right) // 2
            centery = hand.slots[0].centery
            label = Blinker(self.font, text_size, text, color,
                                  {"center": (centerx, centery)},
                                  450)
            self.game.result_labels.append(label)
            amt_color = "darkgreen" if amount >= 0 else "darkred"

            bet_label = Label(self.font, 120, "{:+}".format(amount), amt_color,
                                      {"bottomleft": bl}, bg=prepare.FELT_GREEN)
            move_ani = Animation(bottom=bl[1]-150, duration=total_ani_time, round_values=True)
            move_ani.start(bet_label.rect)
            self.animations.add(move_ani)
            self.fade_labels.append(bet_label)
            hand.bet.chips = []
            hand.bet.stacks = []

        payout_duration = 1000
        center = self.game.player.chip_pile.rect.center
        for pile in win_piles:
            self.winnings.append(pile)
            for stack in pile.stacks:
                ani = Animation(left=center[0], bottom=center[1], duration=payout_duration, round_values=True)
                ani.start(stack.rect)
                self.animations.add(ani)
        center = self.game.chip_rack.rect.center
        for loss_pile in loss_piles:
            self.losses.append(loss_pile)
            for stack in loss_pile.stacks:
                ani = Animation(left=center[0], bottom=center[1], duration=payout_duration, round_values=True)
                ani.start(stack.rect)
                self.animations.add(ani)
        pay_ani = Task(self.game.player.chip_pile.add_chips, payout_duration, args=[payout])
        remove_chips = Task(self.remove_chips, payout_duration)
        end_it = Task(self.end_state, total_ani_time)
        self.animations.add(pay_ani, remove_chips, end_it)

    def remove_chips(self):
        self.winnings = []
        self.losses = []

    def end_state(self):
        self.next = "End Round"
        self.done = True

    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.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 blinker in self.game.result_labels:
            blinker.update(dt)
        self.animations.update(dt)
        for fader in self.fade_labels:
            fader.image.set_alpha(self.alpha)
        if self.window:
            self.window.update(mouse_pos)
            if self.window.done:
                self.window = None
        else:
            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)
        for fader in self.fade_labels:
            fader.draw(surface)
        self.draw_advisor(surface)
        self.game.player.chip_pile.draw(surface)
        for pile in self.winnings:
            pile.draw(surface)
        for pile_ in self.losses:
            pile_.draw(surface)
        self.window and self.window.draw(surface)
Ejemplo n.º 12
0
class DealerTurn(BlackjackState):
    def __init__(self):
        super(DealerTurn, 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])

    def startup(self, game):
        self.game = game
        g = game
        if all([hand.busted for hand in g.player.hands]):
            g.dealer.hand.final = True
            self.state = "End Round"
        delay = 1000
        while not g.dealer.hand.final:
            hand_score = g.dealer.hand.best_score()
            if hand_score is None:
                g.dealer.hand.busted = True
                g.dealer.hand.final = True
            elif hand_score == 21 and len(g.dealer.hand.cards) == 2:
                g.dealer.hand.blackjack = True
                g.dealer.hand.final = True
            elif hand_score < 17:
                self.hit(g.dealer.hand, delay)
                delay += 1000
            else:
                g.dealer.hand.final = True

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

    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.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)
        if self.window:
            self.window.update(mouse_pos)
            if self.window.done:
                self.window = None
        else:
            self.lobby_button.update(mouse_pos)
            self.animations.update(dt)
            if not self.animations:
                self.next = "Show Results"
                self.done = True

    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)
        self.draw_advisor(surface)
        self.game.player.chip_pile.draw(surface)
        self.window and self.window.draw(surface)
Ejemplo n.º 13
0
class Dealing(BlackjackState):
    def __init__(self):
        super(Dealing, 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, None, bindings=[pg.K_ESCAPE])

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

    def flip_card(self, card):
        card.face_up = True

    def make_card_animations(self):
        g = self.game
        self.animations = pg.sprite.Group()
        deal_delay = 0
        for i in range(2):
            card = g.deck.draw_card()
            destination = g.current_player_hand.slots[-1]
            dest_x, dest_y = destination.topleft
            dur = get_distance(destination.center, card.pos) * 20 // card.speed
            ani = Animation(x=dest_x, y=dest_y, duration=dur,
                                    delay=deal_delay, round_values=True)
            ani2 = Task(self.play_deal_sound, deal_delay)
            ani3 = Task(self.flip_card, deal_delay + dur, args=(card,))
            g.current_player_hand.cards.append(card)
            if not i % 2:
                g.player.add_slot(g.current_player_hand)
            ani.start(card.rect)
            self.animations.add(ani, ani2, ani3)
            deal_delay += dur
        for i in range(2):
            card = g.deck.draw_card()
            destination = g.dealer.hand.slots[-1]
            dest_x, dest_y = destination.topleft
            dur = get_distance(destination.center, card.pos) * 20 // card.speed
            ani = Animation(x=dest_x, y=dest_y, duration=dur,
                                    delay=deal_delay, round_values=True)
            ani2 = Task(self.play_deal_sound, deal_delay)
            ani.start(card.rect)
            g.dealer.hand.cards.append(card)
            g.dealer.add_slot()
            self.animations.add(ani, ani2)
            if i:
                ani3 = Task(self.flip_card, deal_delay + dur, args=(card,))
                self.animations.add(ani3)
            deal_delay += dur

    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.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)
        if self.window:
            self.window.update(mouse_pos)
            if self.window.done:
                self.window = None
        else:
            self.lobby_button.update(mouse_pos)
            if self.animations:
                self.animations.update(dt)
            else:
                self.next = "Player Turn"
                self.done = True

    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.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)
        g.player.chip_pile.draw(surface)
        self.draw_advisor(surface)
        self.window and self.window.draw(surface)
Ejemplo n.º 14
0
class Bingo(statemachine.StateMachine):
    """State to represent a bing game"""
    name = "bingo"
    show_in_lobby = True

    def __init__(self):
        """Initialise the bingo game"""
        #
        self.verbose = False
        self.sound_muted = prepare.ARGS['debug']
        #
        self.screen_rect = pg.Rect((0, 0), prepare.RENDER_SIZE)
        self.auto_pick = S['debug-auto-pick']
        #
        self.ui = common.ClickableGroup()
        #
        self.lobby_button = NeonButton(S['lobby-position'], 'Lobby',
                                       self.return_to_lobby)
        self.new_game_button = NeonButton(
            S['new-game-position'], 'New',
            lambda x: self.restart_game(None, None))
        #
        # The controls to allow selection of different numbers of cards
        self.card_selector = cardselector.CardSelector('card-selector', self)
        self.card_selector.linkEvent(events.E_NUM_CARDS_CHANGED,
                                     self.change_number_of_cards)
        self.ui.append(self.card_selector.ui)
        #
        self.create_card_collection()
        self.ui.extend(self.cards)
        #
        self.winning_pattern = patterns.PATTERNS[0]
        #
        self.pattern_buttons = common.DrawableGroup()
        self.debug_buttons = common.DrawableGroup()
        self.buttons = common.DrawableGroup([self.pattern_buttons])
        #
        if prepare.DEBUG:
            self.buttons.append(self.debug_buttons)
        #
        super(Bingo, self).__init__()
        #
        # The machine for picking balls
        self.ball_machine = ballmachine.BallMachine('ball-machine', self)
        self.ball_machine.start_machine()
        self.ui.append(self.ball_machine.buttons)
        #
        self.all_cards = common.DrawableGroup()
        self.all_cards.extend(self.cards)
        self.all_cards.extend(self.dealer_cards)
        #
        B.linkEvent(events.E_PLAYER_PICKED, self.player_picked)
        B.linkEvent(events.E_PLAYER_UNPICKED, self.player_unpicked)
        B.linkEvent(events.E_CARD_COMPLETE, self.card_completed)
        #
        self.current_pick_sound = 0
        self.last_pick_time = 0

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

        :return: collections.OrderedDict
        """
        stats = OrderedDict([("games played", 0), ("cards won", 0),
                             ("cards lost", 0), ("total lost", 0),
                             ("total won", 0), ("time played", '00:00:00'),
                             ("_last squares", [])])
        return stats

    def startup(self, current_time, persistent):
        """This method will be called each time the state resumes."""
        self.persist = persistent
        self.casino_player = self.persist["casino_player"]
        self.casino_player.current_game = self.name
        #
        self.casino_player.increase('games played')
        self.cards.set_card_numbers(self.casino_player.get(
            '_last squares', []))
        self.money_display.set_money(self.casino_player.cash)
        self.time_started = time.time()

    def get_event(self, event, scale=(1, 1)):
        """Check for events"""
        super(Bingo, self).get_event(event, scale)
        self.lobby_button.get_event(event)
        self.new_game_button.get_event(event)
        #
        if event.type == pg.QUIT:
            if prepare.ARGS['straight']:
                pg.quit()
                sys.exit()
            else:
                self.done = True
                self.next = "lobby"
        elif event.type in (pg.MOUSEBUTTONDOWN, pg.MOUSEMOTION):
            #
            self.ui.process_events(event, scale)
            self.bonus_buttons.process_events(event, scale)
            #
            pos = tools.scaled_mouse_pos(scale, event.pos)
        elif event.type == pg.KEYUP:
            if event.key == pg.K_ESCAPE:
                self.done = True
                self.next = "lobby"
            elif event.key == pg.K_SPACE:
                self.next_chip(None, None)
            elif event.key == pg.K_m:
                #self.persist["music_handler"].mute_unmute_music()
                self.sound_muted = not self.sound_muted
            elif event.key == pg.K_f:
                for card in self.cards:
                    self.add_generator('flash-labels', card.flash_labels())

    def return_to_lobby(self, arg):
        """Return to the lobby screen"""
        self.game_started = False
        self.done = True
        self.next = "lobby"
        self.casino_player.set('_last squares', self.cards.get_card_numbers())
        self.casino_player.cash = self.money_display.amount
        self.casino_player.increase_time('time played',
                                         time.time() - self.time_started)

    def drawUI(self, surface, scale):
        """Update the main surface once per frame"""
        mouse_pos = tools.scaled_mouse_pos(scale, pg.mouse.get_pos())
        self.lobby_button.update(mouse_pos)
        self.new_game_button.update(mouse_pos)
        #
        surface.fill(S['table-color'])
        #
        self.lobby_button.draw(surface)
        self.new_game_button.draw(surface)
        self.all_cards.draw(surface)
        self.ball_machine.draw(surface)
        self.buttons.draw(surface)
        self.card_selector.draw(surface)
        self.money_display.draw(surface)
        self.bonus_display.draw(surface)
        self.bonus_buttons.draw(surface)

    def initUI(self):
        """Initialise the UI display"""
        #
        # Buttons that show the winning patterns
        x, y = S['winning-pattern-position']
        for idx, pattern in enumerate(patterns.PATTERNS):
            dx, dy = S['winning-pattern-buttons'][pattern.name]
            new_button = patterns.PatternButton(
                idx, (x + dx, y + dy),
                'bingo-wide-red-button',
                'bingo-wide-red-button-off',
                'winning-pattern',
                pattern.name,
                pattern == self.winning_pattern,
                S,
                scale=S['winning-pattern-scale'])
            new_button.linkEvent(common.E_MOUSE_CLICK, self.change_pattern,
                                 pattern)
            new_button.pattern = pattern
            self.pattern_buttons.append(new_button)
        self.ui.extend(self.pattern_buttons)
        #
        # Simple generator to flash the potentially winning squares
        self.add_generator('potential-winners', self.flash_potential_winners())
        #
        # Display of the money the player has
        self.money_display = moneydisplay.MoneyDisplay('money-display',
                                                       S['money-position'], 0,
                                                       self)
        prepare.BROADCASTER.linkEvent(events.E_SPEND_MONEY, self.spend_money)
        #
        # Button for next chip
        self.next_chip_button = common.ImageOnOffButton(
            'next-chip',
            S['next-chip-position'],
            'bingo-next-chip-on',
            'bingo-next-chip-off',
            'next-chip',
            'Next Chip (SPC)',
            True,
            S,
            scale=S['next-chip-scale'])
        self.next_chip_button.linkEvent(common.E_MOUSE_CLICK, self.next_chip)
        self.ui.append(self.next_chip_button)
        self.buttons.append(self.next_chip_button)
        #
        # Menu bar
        self.menu_bar = common.NamedSprite('bingo-menu-bar',
                                           S['menu-bar-position'],
                                           scale=S['menu-bar-scale'])
        self.buttons.append(self.menu_bar)
        #
        self.bonus_display = bonusdisplay.BonusDisplay(
            'bonus-display', S['bonus-light-position'], self)
        #
        self.bonus_buttons = bonusbuttons.BonusButtonsDisplay(
            'bonus-buttons', S['bonus-buttons-position'], self)
        self.bonus_display.linkEvent(
            events.E_BONUS_REACHED,
            lambda o, a: self.bonus_buttons.pick_new_button())
        #
        # Debugging buttons
        if prepare.DEBUG and S['show-debug-buttons']:
            self.debug_buttons.append(
                common.ImageOnOffButton('auto-pick',
                                        S['debug-auto-pick-position'],
                                        'bingo-yellow-button',
                                        'bingo-yellow-off-button',
                                        'small-button',
                                        'Auto pick',
                                        S['debug-auto-pick'],
                                        S,
                                        scale=S['small-button-scale']))
            self.debug_buttons[-1].linkEvent(common.E_MOUSE_CLICK,
                                             self.toggle_auto_pick)
            #
            self.debug_buttons.append(
                common.ImageButton('restart',
                                   S['debug-restart-position'],
                                   'bingo-yellow-button',
                                   'small-button',
                                   'Restart',
                                   S,
                                   scale=S['small-button-scale']))
            self.debug_buttons[-1].linkEvent(common.E_MOUSE_CLICK,
                                             self.restart_game)
            #
            self.debug_buttons.append(
                common.ImageButton('next-ball',
                                   S['debug-next-ball-position'],
                                   'bingo-yellow-button',
                                   'small-button',
                                   'Next Ball',
                                   S,
                                   scale=S['small-button-scale']))
            self.debug_buttons[-1].linkEvent(common.E_MOUSE_CLICK,
                                             self.next_ball)
            #
            self.debug_buttons.append(
                common.ImageButton('new-cards',
                                   S['debug-new-cards-position'],
                                   'bingo-yellow-button',
                                   'small-button',
                                   'New Cards',
                                   S,
                                   scale=S['small-button-scale']))
            self.debug_buttons[-1].linkEvent(common.E_MOUSE_CLICK,
                                             self.draw_new_cards)
            self.ui.extend(self.debug_buttons)

    def spend_money(self, amount, arg):
        """Money has been spent"""
        self.log.info('Money has been spent {1} by {0}'.format(arg, amount))
        self.money_display.add_money(amount)
        if amount < 0:
            self.play_sound('bingo-pay-money')
            self.casino_player.increase('total lost', -amount)
        else:
            self.casino_player.increase('total won', amount)

    def change_pattern(self, obj, pattern):
        """Change the winning pattern"""
        self.log.info('Changing pattern to {0}'.format(pattern.name))
        #
        # Account for the random factor
        if pattern.name == "Random":
            self.add_generator(
                'randomize-buttons',
                self.randomly_highlight_buttons(
                    self.pattern_buttons[-1], self.pattern_buttons[:-1],
                    S['randomize-button-number'], S['randomize-button-delay'],
                    lambda b: self.change_pattern(None, b.pattern)))
            return
        #
        self.winning_pattern = pattern
        self.highlight_patterns(self.winning_pattern, one_shot=True)
        #
        # Clear all flashing squares
        for card in self.all_cards:
            card.potential_winning_squares = []
            for square in card.squares.values():
                square.is_focused = False
        #
        # Update UI
        for button in self.pattern_buttons:
            button.state = (button.pattern == self.winning_pattern)

    def toggle_auto_pick(self, obj, arg):
        """Toggle whether we are auto-picking numbers"""
        self.log.debug('Toggling auto-pick')
        self.auto_pick = not self.auto_pick
        self.debug_buttons[0].state = self.auto_pick

    def restart_game(self, obj, arg):
        """Restart the game"""
        self.log.info('Restart game')
        self.ball_machine.reset_machine(self.ball_machine.interval)
        self.cards.reset()
        self.dealer_cards.reset()
        self.current_pick_sound = 0
        self.last_pick_time = 0
        self.casino_player.increase('games played')

    def next_ball(self, obj, arg):
        """Move on to the next ball

        This is a debugging method - no using the normal UI

        """
        self.ball_machine.call_next_ball()

    def next_chip(self, obj, arg):
        """Move on to the next ball"""
        if self.next_chip_button.state:
            self.ball_machine.call_next_ball()
            self.add_generator('next-chip-animation', self.animate_next_chip())

    def animate_next_chip(self):
        """Animate the button after choosing another chip"""
        self.next_chip_button.state = False
        yield S['next-chip-delay'] * 1000
        self.next_chip_button.state = True

    def draw_new_cards(self, obj, arg):
        """Draw a new set of cards"""
        self.log.debug('Drawing new set of cards')
        self.cards.draw_new_numbers()
        self.cards.reset()

    def create_card_collection(self):
        """Return a new card collection"""
        number = self.card_selector.number_of_cards
        self.cards = playercard.PlayerCardCollection(
            'player-card', S['player-cards-position'],
            S['player-card-offsets'][number], self)
        dx, dy = S['dealer-card-offset']
        dealer_offsets = [(dx + x, dy + y)
                          for x, y in S['player-card-offsets'][number]]
        self.dealer_cards = dealercard.DealerCardCollection(
            'dealer-card', S['player-cards-position'], dealer_offsets, self)

    def change_number_of_cards(self, number, arg=None):
        """Change the number of cards in play"""
        self.log.info('Changing the number of cards to {0}'.format(number))
        #
        # Store off the old card number to reuse
        self.casino_player.set('_last squares', self.cards.get_card_numbers())
        #
        # Remove old cards
        for card in self.cards:
            self.all_cards.remove(card)
            self.ui.remove(card)
        for card in self.dealer_cards:
            self.all_cards.remove(card)
        #
        # Create new cards
        self.create_card_collection()
        self.cards.set_card_numbers(self.casino_player.get(
            '_last squares', []))
        #
        self.all_cards.extend(self.cards)
        self.all_cards.extend(self.dealer_cards)
        self.ui.extend(self.cards)
        self.restart_game(None, None)

    def highlight_patterns(self, pattern, one_shot):
        """Test method to cycle through the winning patterns"""
        self.log.debug('Creating new highlight pattern generators')
        for card in self.cards:
            self.add_generator('highlight-patterns-card-%s' % card.name,
                               self.highlight_pattern(card, pattern, one_shot))

    def highlight_pattern(self, card, pattern, one_shot):
        """Highlight a particular pattern on a card"""
        for squares in pattern.get_matches(card):
            for square in squares:
                square.highlighted_state = bingocard.S_GOOD
            card.set_dirty()
            yield 100
            for square in squares:
                square.highlighted_state = bingocard.S_NONE
            card.set_dirty()
            yield 10
        #
        if not one_shot:
            self.add_generator(
                'highlight',
                self.highlight_pattern(card, pattern, one_shot=False))

    def ball_picked(self, ball):
        """A ball was picked"""
        # Turn off the button to prevent the player from accidentally choosing another
        # ball at the same time
        self.add_generator('next-chip-animation', self.animate_next_chip())
        #
        # If auto-picking then update the cards
        auto_pick_cards = list(self.dealer_cards)
        if self.auto_pick:
            auto_pick_cards.extend(self.cards)
        for card in auto_pick_cards:
            card.call_square(ball.number)
        #
        # Highlight the card labels
        for card in self.all_cards:
            card.highlight_column(ball.letter)

    def player_picked(self, square, arg):
        """The player picked a square"""
        if not square.card.is_active:
            return
        #
        self.bonus_display.add_bonus()
        #
        # Check to see if we created a new potentially winning square
        called_squares = list(square.card.called_squares)
        prior_called_squares = list(called_squares)
        prior_called_squares.remove(square.text)
        #
        _, winners = self.winning_pattern.get_number_to_go_and_winners(
            square.card, called_squares)
        _, prior_winners = self.winning_pattern.get_number_to_go_and_winners(
            square.card, prior_called_squares)
        self.log.debug('{0} / {1}'.format(winners, prior_winners))
        #
        if len(winners) > len(prior_winners):
            self.play_sound('bingo-potential-winner')
        #
        # Increment sound if we did this quickly
        if time.time() - self.last_pick_time < S['player-pick-interval']:
            self.current_pick_sound = min(self.current_pick_sound + 1,
                                          len(S['player-pick-sounds']) - 1)
        else:
            self.current_pick_sound = 0
        self.last_pick_time = time.time()
        self.play_sound(S['player-pick-sounds'][self.current_pick_sound])
        #
        self.log.info('Player picked {0}'.format(square))

    def player_unpicked(self, square, arg):
        """The player unpicked a square"""
        self.log.info('Player unpicked {0}'.format(square))
        self.play_sound('bingo-unpick')

    def flash_potential_winners(self):
        """Flash the squares that are potential winners"""
        while True:
            for state, delay in S['card-focus-flash-timing']:
                for card in self.all_cards:
                    potential_squares = card.potential_winning_squares
                    if potential_squares:
                        for square in potential_squares:
                            square.is_focused = state
                        card.set_dirty()
                yield delay * 1000

    def play_sound(self, name):
        """Play a named sound - respects the mute settings"""
        if not self.sound_muted:
            prepare.SFX[name].play()

    def get_missing_squares(self, squares):
        """Return a list of the numbers that have not been called"""
        return [
            square for square in squares
            if square.text not in self.ball_machine.called_balls
        ]

    def card_completed(self, card, arg):
        """A card was completed"""
        self.log.info('Card {0} owned by {1} was completed'.format(
            card.index, card.card_owner))
        #
        if card.card_owner == bingocard.T_PLAYER:
            self.casino_player.increase('cards won' if card.card_state ==
                                        bingocard.S_WON else 'cards lost')
        else:
            self.casino_player.increase('cards won' if card.card_state ==
                                        bingocard.S_LOST else 'cards lost')
        #
        # Find the matching card from the dealer or player and deactivate it
        other_card = self.cards[
            card.
            index] if card.card_owner == bingocard.T_DEALER else self.dealer_cards[
                card.index]
        other_card.active = False
        other_card.set_card_state(bingocard.S_LOST)
        #
        # Check for all cards done
        for item in self.cards:
            if item.active and item != card:
                return
        else:
            for item in self.cards:
                self.add_generator('flash-labels', item.flash_labels())

    def randomly_highlight_buttons(self,
                                   source_button,
                                   buttons,
                                   number_of_times,
                                   delay,
                                   final_callback,
                                   speed_up=None,
                                   states=(False, True)):
        """Randomly highlight buttons in a group and then call the callback when complete"""
        false_state, true_state = states
        last_chosen = None
        if source_button:
            source_button.state = true_state
        #
        # Turn all buttons off
        for button in buttons:
            button.state = false_state
        #
        for i in range(number_of_times):
            #
            # Choose one to highlight, but not the last one
            while True:
                chosen = random.choice(buttons)
                if chosen != last_chosen:
                    break
            #
            # Highlight it
            self.log.debug('Setting to button {0}, {1}'.format(
                buttons.index(chosen), chosen.name))
            chosen.state = true_state
            if last_chosen:
                last_chosen.state = false_state
            last_chosen = chosen
            #
            self.play_sound('bingo-beep')
            #
            if i != number_of_times - 1:
                yield delay
            #
            # Shortern delay
            delay *= speed_up if speed_up else S['randomize-button-speed-up']
        #
        if source_button:
            source_button.state = false_state
        #
        final_callback(chosen)

    def pause_machine(self, delay):
        """Pause the ball machine for a certain length of time"""
        self.ball_machine.pause()

        def unpause():
            yield delay * 1000
            self.ball_machine.unpause()

        self.add_generator('un-pause', unpause())

    def double_up(self):
        """Double up all cards"""
        for card in self.cards:
            card.double_down()

    def slow_machine(self):
        """Slow the machine down"""
        self.ball_machine.change_speed(None,
                                       self.ball_machine.speed_transitions[0])

    def start_auto_pick(self, delay):
        """Temporarily auto pick the numbers"""
        self.auto_pick = True

        def unauto():
            yield delay * 1000
            self.auto_pick = False

        self.add_generator('un-auto', unauto())

    def win_card(self):
        """Win one of the cards"""
        possible_cards = [card for card in self.cards if card.active]
        if possible_cards:
            card = random.choice(possible_cards)
            card.set_card_state(bingocard.S_WON)
            self.play_sound(card.card_success_sound)
            B.processEvent((events.E_CARD_COMPLETE, card))
            card.active = False
Ejemplo n.º 15
0
class CreditsScreen(data.state.State):
    """
    This is the main state governing the credits screen.
    """
    name = 'credits'

    def __init__(self):
        super(CreditsScreen, self).__init__()
        self.screen = pg.Rect((0, 0), prepare.RENDER_SIZE)
        self.next = "lobby"
        self.font = prepare.FONTS["Saniretro"]
        self.dev_names = DEVELOPERS
        self.artist_names = ARTISTS
        self.assets_names = ASSETS_NAMES
        self.software_names = SOFTWARE
        self.zipper_blocks = []
        self.zipper_block = None
        self.chip_curtain = None
        pos = (self.screen.centerx - (NeonButton.width // 2),
               self.screen.bottom - NeonButton.height - 10)
        self.done_button = NeonButton(pos, "Lobby", self.back_to_lobby)
        self.use_music_handler = False

    def back_to_lobby(self, *args):
        self.done = True
        pg.mixer.stop()

    def make_groups(self, names, group_size=5):
        return [
            names[i:i + group_size] for i in range(0, len(names), group_size)
        ]

    def make_titles_blocks(self, title_name_pairs):
        titles = []
        zipper_blocks = []
        for pair in title_name_pairs:
            title_text, names = pair
            title = SlotReelTitle((self.screen.centerx, 20),
                                  title_text,
                                  initial_move=(0, -120))
            grouped = self.make_groups(names)
            for group in grouped:
                block = ZipperBlock(self.font, group, (700, 230))
                zipper_blocks.append(block)
                titles.append(title)
        return iter(titles), iter(zipper_blocks)

    def startup(self, current_time, persistent):
        """
        Prepare title, spinners, and zipper blocks.  Names are randomized each
        time so that no single dev is always first in the credits.
        """
        self.persist = persistent
        self.zipper_blocks = []
        dev_names = self.dev_names[:]
        artist_names = self.artist_names[:]
        assets_names = self.assets_names[:]
        software_names = self.software_names[:]
        for names in (dev_names, artist_names, assets_names):
            random.shuffle(names)
        self.titles, self.zipper_blocks = self.make_titles_blocks([
            ("Developers", dev_names), ("Artists", artist_names),
            ("Assets", assets_names), ("Software", software_names)
        ])
        self.title = next(self.titles)
        self.zipper_block = next(self.zipper_blocks)
        spots = [(self.title.rect.left - 100, self.title.rect.centery),
                 (self.title.rect.right + 100, self.title.rect.centery)]
        self.spinners = pg.sprite.Group()
        Spinner(spots[0], "black", self.spinners)
        Spinner(spots[1], "black", self.spinners, reverse=True)
        self.chip_curtain = None
        self.title.startup()

    def get_event(self, event, scale=(1, 1)):
        """
        Set the state to done on Xing; pressing escape; or clicking the
        lobby button.
        """
        if event.type == pg.QUIT:
            self.back_to_lobby()
        elif event.type == pg.KEYUP and event.key == pg.K_ESCAPE:
            self.back_to_lobby()
        self.done_button.get_event(event)

    def switch_blocks(self):
        """
        Switch to the next zipper block and title.  If all blocks have been
        used, initialize the chip_curtain.
        """
        try:
            rect = self.title.rect
            self.zipper_block = next(self.zipper_blocks)
            self.title = next(self.titles)
            if self.title.rect != rect:
                rect = self.title.rect
                spots = [(rect.x - 100, rect.centery),
                         (rect.right + 100, rect.centery)]
                self.spinners.empty()
                Spinner(spots[0], "blue", self.spinners)
                Spinner(spots[1], "blue", self.spinners, reverse=True)
                self.title.startup()
        except StopIteration:
            self.end_titles = []

            self.zipper_block = None
            self.title = None
            self.spinners.empty()
            self.back_to_lobby()

    def update(self, surface, keys, current_time, dt, scale):
        """Update all elements and then draw the state."""
        mouse_pos = tools.scaled_mouse_pos(scale)
        self.done_button.update(mouse_pos)
        if self.title:
            if self.title.moving:
                for spinner in self.spinners:
                    spinner.rect.move_ip(self.title.move_speed)
            self.title.update()

        if self.zipper_block and self.title.spun_out:
            self.zipper_block.update(dt)
            if self.zipper_block.done:
                self.switch_blocks()
        if self.chip_curtain:
            self.chip_curtain.update(dt)
            if self.chip_curtain.done:
                self.done = True
        self.spinners.update(dt)
        self.draw(surface)

    def draw(self, surface):
        """Render all currently active elements to the target surface."""
        surface.fill(prepare.BACKGROUND_BASE)
        if self.title:
            self.title.draw(surface)
        self.spinners.draw(surface)
        if self.zipper_block:
            self.zipper_block.draw(surface)
        if self.chip_curtain:
            self.chip_curtain.draw(surface)
        self.done_button.draw(surface)