Exemplo n.º 1
0
    def __init__(self):
        self.active = True
        self.group = pg.sprite.Group()
        self.frames = pg.sprite.Group()
        self.advisor = Advisor(self.group, self.frames)
        self.advisor.active = True
        self.images = {
            'back': prepare.GFX["advisor_back"],
            'front': prepare.GFX["advisor_front"],
            'back_dim': prepare.GFX["advisor_back_dim"],
            'front_dim': prepare.GFX["advisor_front_dim"],
        }

        self.rect = self.get_rect()
        self.button = Button(self.rect, call=self.toggle_active)

        # Just testing to ensure it works...
        self.advisor.queue_text("Welcome to Keno!", dismiss_after=2500)
Exemplo n.º 2
0
class KenoAdvisor(object):
    def __init__(self):
        self.active = True
        self.group = pg.sprite.Group()
        self.frames = pg.sprite.Group()
        self.advisor = Advisor(self.group, self.frames)
        self.advisor.active = True
        self.images = {
            'back': prepare.GFX["advisor_back"],
            'front': prepare.GFX["advisor_front"],
            'back_dim': prepare.GFX["advisor_back_dim"],
            'front_dim': prepare.GFX["advisor_front_dim"],
        }

        self.rect = self.get_rect()
        self.button = Button(self.rect, call=self.toggle_active)

        # Just testing to ensure it works...
        self.advisor.queue_text("Welcome to Keno!", dismiss_after=2500)

    def get_rect(self):
        return self.images['back'].get_rect().union(
            self.images['front'].get_rect())

    def toggle_active(self):
        self.active = not self.active

    def update(self, dt):
        if self.active:
            self.frames.update(dt)

    def draw(self, surface):
        if self.active:
            surface.blit(self.images['back'], (0, 0))
            self.group.draw(surface)
            surface.blit(self.images['front'], (0, 0))
        else:
            surface.blit(self.images['back_dim'], (0, 0))
            surface.blit(self.images['front_dim'], (0, 0))
Exemplo n.º 3
0
class KenoAdvisor(object):

    def __init__(self):
        self.active = True
        self.group  = pg.sprite.Group()
        self.frames = pg.sprite.Group()
        self.advisor= Advisor(self.group, self.frames)
        self.advisor.active = True
        self.images = {
            'back'      : prepare.GFX["advisor_back"],
            'front'     : prepare.GFX["advisor_front"],
            'back_dim'  : prepare.GFX["advisor_back_dim"],
            'front_dim' : prepare.GFX["advisor_front_dim"],
        }

        self.rect   = self.get_rect()
        self.button = Button(self.rect, call=self.toggle_active)

        # Just testing to ensure it works...
        self.advisor.queue_text("Welcome to Keno!", dismiss_after=2500)

    def get_rect(self):
        return self.images['back'].get_rect().union(self.images['front'].get_rect())

    def toggle_active(self):
        self.active = not self.active

    def update(self, dt):
        if self.active:
            self.frames.update(dt)

    def draw(self, surface):
        if self.active:
            surface.blit(self.images['back'], (0,0))
            self.group.draw(surface)
            surface.blit(self.images['front'], (0,0))
        else:
            surface.blit(self.images['back_dim'], (0,0))
            surface.blit(self.images['front_dim'], (0,0))
Exemplo n.º 4
0
    def __init__(self):
        self.active = True
        self.group  = pg.sprite.Group()
        self.frames = pg.sprite.Group()
        self.advisor= Advisor(self.group, self.frames)
        self.advisor.active = True
        self.images = {
            'back'      : prepare.GFX["advisor_back"],
            'front'     : prepare.GFX["advisor_front"],
            'back_dim'  : prepare.GFX["advisor_back_dim"],
            'front_dim' : prepare.GFX["advisor_front_dim"],
        }

        self.rect   = self.get_rect()
        self.button = Button(self.rect, call=self.toggle_active)

        # Just testing to ensure it works...
        self.advisor.queue_text("Welcome to Keno!", dismiss_after=2500)
Exemplo n.º 5
0
    def startup(self, now, persistent):
        self.now = now
        self.persist = persistent
        self.casino_player = self.persist['casino_player']
        self.get_stats_from_casino_player()

        # declared here to appease pycharm's syntax checking.
        # will be filled in when configuration is loaded
        self.betting_areas = dict()
        self.dealer_hand = None
        self.player_hand = None
        self.player_chips = None
        self.house_chips = None
        self.shoe = None

        # baccarat only: move out later
        self.confirm_button_rect = None

        self.interested_events = [
            ('SNAP_STACK', self.on_snap_stack),
            ('RETURN_STACK', self.on_return_stack),
            ('SNAP_STACK_MOTION', self.on_snap_stack_motion),
            ('PICKUP_STACK', self.on_pickup_stack),
            ('DROP_STACK', self.on_drop_stack),
            ('PICKUP_STACK_MOTION', self.on_pickup_stack_motion),
        ]

        names = ["cardshove{}".format(x) for x in (1, 3, 4)]
        self.shove_sounds = [prepare.SFX[name] for name in names]
        names = ["cardplace{}".format(x) for x in (2, 3, 4)]
        self.deal_sounds = [prepare.SFX[name] for name in names]
        names = ["chipsstack{}".format(x) for x in (3, 5, 6)]
        self.chip_sounds = [prepare.SFX[name] for name in names]

        self._allow_exit = True
        self._enable_chips = False
        self._mouse_tooltip = None
        self._background = None
        self._hovered_sprite = None
        self._clicked_sprite = None
        self._hovered_chip_area = None
        self._grabbed_stack = False
        self._locked_advice = None

        self.font = pg.font.Font(prepare.FONTS["Saniretro"], 64)
        self.large_font = pg.font.Font(prepare.FONTS["Saniretro"], 120)
        self.button_font = pg.font.Font(prepare.FONTS["Saniretro"], 48)

        self.hud = SpriteGroup()
        self.bets = MetaGroup()
        self.metagroup = MetaGroup()
        self.metagroup.add(self.bets)
        self.animations = pg.sprite.Group()

        self._advisor = Advisor(self.hud, self.animations)
        self._advisor.queue_text('Welcome to Baccarat', 3000)

        self.hud.add(NeonButton('lobby', (540, 938, 0, 0), self.goto_lobby))

        spr = Sprite()
        spr.image = prepare.GFX['baccarat-menu-front']
        spr.rect = spr.image.get_rect()
        self.hud.add(spr, layer=1)

        spr = Sprite()
        spr.image = prepare.GFX['baccarat-menu-back']
        spr.rect = spr.image.get_rect()
        self.hud.add(spr, layer=-100)

        self.remove_animations = partial(remove_animations_of, self.animations)

        self.metagroup.add(self.hud)

        self.reload_config()
        self.link_events()
        self.cash_in()
        self.new_round()
Exemplo n.º 6
0
class TableGame(data.state.State):
    """Supports vegas style card games with chips and cards
    """
    name = 'table game base'

    def startup(self, now, persistent):
        self.now = now
        self.persist = persistent
        self.casino_player = self.persist['casino_player']
        self.get_stats_from_casino_player()

        # declared here to appease pycharm's syntax checking.
        # will be filled in when configuration is loaded
        self.betting_areas = dict()
        self.dealer_hand = None
        self.player_hand = None
        self.player_chips = None
        self.house_chips = None
        self.shoe = None

        # baccarat only: move out later
        self.confirm_button_rect = None

        self.interested_events = [
            ('SNAP_STACK', self.on_snap_stack),
            ('RETURN_STACK', self.on_return_stack),
            ('SNAP_STACK_MOTION', self.on_snap_stack_motion),
            ('PICKUP_STACK', self.on_pickup_stack),
            ('DROP_STACK', self.on_drop_stack),
            ('PICKUP_STACK_MOTION', self.on_pickup_stack_motion),
        ]

        names = ["cardshove{}".format(x) for x in (1, 3, 4)]
        self.shove_sounds = [prepare.SFX[name] for name in names]
        names = ["cardplace{}".format(x) for x in (2, 3, 4)]
        self.deal_sounds = [prepare.SFX[name] for name in names]
        names = ["chipsstack{}".format(x) for x in (3, 5, 6)]
        self.chip_sounds = [prepare.SFX[name] for name in names]

        self._allow_exit = True
        self._enable_chips = False
        self._mouse_tooltip = None
        self._background = None
        self._hovered_sprite = None
        self._clicked_sprite = None
        self._hovered_chip_area = None
        self._grabbed_stack = False
        self._locked_advice = None

        self.font = pg.font.Font(prepare.FONTS["Saniretro"], 64)
        self.large_font = pg.font.Font(prepare.FONTS["Saniretro"], 120)
        self.button_font = pg.font.Font(prepare.FONTS["Saniretro"], 48)

        self.hud = SpriteGroup()
        self.bets = MetaGroup()
        self.metagroup = MetaGroup()
        self.metagroup.add(self.bets)
        self.animations = pg.sprite.Group()

        self._advisor = Advisor(self.hud, self.animations)
        self._advisor.queue_text('Welcome to Baccarat', 3000)

        self.hud.add(NeonButton('lobby', (540, 938, 0, 0), self.goto_lobby))

        spr = Sprite()
        spr.image = prepare.GFX['baccarat-menu-front']
        spr.rect = spr.image.get_rect()
        self.hud.add(spr, layer=1)

        spr = Sprite()
        spr.image = prepare.GFX['baccarat-menu-back']
        spr.rect = spr.image.get_rect()
        self.hud.add(spr, layer=-100)

        self.remove_animations = partial(remove_animations_of, self.animations)

        self.metagroup.add(self.hud)

        self.reload_config()
        self.link_events()
        self.cash_in()
        self.new_round()

    def reload_config(self):
        raise NotImplementedError

    def new_round(self):
        raise NotImplementedError

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

        :return: collections.OrderedDict
        """
        raise NotImplementedError

    def render_background(self, size):
        """Render the background

        Subclasses must implement this

        :param size: (width, height) in pixels
        :return: pygame.surface.Surface
        """
        raise NotImplementedError

    def get_stats_from_casino_player(self):
        """Get stats for game and set them.  Will set defaults if needed.
        """
        self.stats = self.casino_player.stats.get(self.name, None)
        if self.stats is None:
            raise RuntimeError

    def set_casino_player_states(self):
        # to deal with the awkward new stats system
        for key, value in self.stats.items():
            print(key, value)
            self.casino_player.set(key, value)

    def cleanup(self):
        self.unlink_events()
        self.set_casino_player_states()
        return super(TableGame, self).cleanup()

    def link_events(self):
        for name, f in self.interested_events:
            B.linkEvent(name, f)

    def unlink_events(self):
        for name, f in self.interested_events:
            B.unlinkEvent(name, f)

    def on_pickup_stack(self, *args):
        """When a stack of chips is picked up
        """
        self._grabbed_stack = True

        self._locked_advice = None
        self._advisor.empty()
        self._advisor.queue_text('Place chips into a betting area', 0)

    def on_drop_stack(self, *args):
        """When a stack of chips is dropped anywhere
        """

        # this is a hack until i have a proper metagroup
        def remove(owner, chips):
            owner.remove(chips)
            if owner is not self.player_chips:
                if owner.value == 0:
                    self.bets.remove(owner)

        # clear the light areas under chips/betting areas
        if self._hovered_chip_area is not None:
            self.clear_area_highlight()

        self._grabbed_stack = False

        d = args[0]
        position = d['position']
        owner = d['object']
        chips = d['chips']

        needs_advice = not self.bets.groups()

        # this value is used to determine where to
        # return chips if this bet wins
        if not hasattr(owner, 'origin'):
            owner.origin = owner

        if self._hovered_chip_area is not None:
            self.clear_area_highlight()

        self._advisor.empty()

        # check if chip is dropped onto a bet pile or player chips
        areas = chain(self.bets.groups(), [self.player_chips])
        for area in areas:
            if area is owner:
                continue

            if area.rect.collidepoint(position):
                remove(owner, chips)
                area.extend(chips)
                area.ignore_until_away = True
                self.clear_background()

                if not self.bets.groups():
                    self.hide_bet_confirm_button()

                return True, area

        # place chips in betting area
        for area in self.betting_areas.values():
            if area.rect.collidepoint(position):
                remove(owner, chips)
                bet = self.place_bet(area.hand, owner.origin, chips)
                bet.origin = owner.origin
                bet.rect.bottomleft = position

                # TODO: should not be hardcoded
                bet.rect.x -= 32
                self.clear_background()

                if bet.result is None:
                    payout = self.options['tie_payout']
                    msg = 'Ties pay {} to 1'.format(payout)
                    self._advisor.queue_text(msg, 3000)

                if bet.result is self.dealer_hand:
                    com = int(self.options['commission'] * 100)
                    msg = 'There is a {}% commission on dealer bets'.format(
                        com)
                    self._advisor.push_text(msg, 3000)

                if needs_advice:
                    # TODO: remove from baseclass
                    self.show_bet_confirm_button()

                return True, bet

        # place chips in the house chips
        if self.house_chips.rect.collidepoint(position):
            remove(owner, chips)
            new_chips = list()
            for chip in chips:
                for value in make_change(chip.value, break_down=True):
                    chip = Chip(value)
                    chip.rect.center = self.house_chips.rect.center
                    new_chips.append(chip)
            self.player_chips.extend(new_chips)

    def on_pickup_stack_motion(self, *args):
        """When mouse is hovering over a stack or moving it
        """
        chips, position = args[0]

        self.on_snap_stack_motion(*args)

        # check if mouse is hovering over betting area
        areas = chain(self.betting_areas.values(), [self.player_chips])
        if self._hovered_chip_area is None:
            for area in areas:
                if area.drop_rect.collidepoint(position):
                    self._hovered_chip_area = area
                    sprite = getattr(area, 'sprite', None)
                    if sprite is None:
                        sprite = Sprite()
                        sprite.rect = area.drop_rect.copy()
                        sprite.image = pg.Surface(sprite.rect.size)
                        sprite.image.fill((255, 255, 255))
                        area.sprite = sprite

                    self.hud.add(sprite)
                    self.remove_animations(sprite.image)
                    ani = Animation(set_alpha=48,
                                    initial=0,
                                    duration=500,
                                    transition='out_quint')
                    ani.start(sprite.image)
                    self.animations.add(ani)

        # handle when mouse moves outside previously hovered area
        elif not self._hovered_chip_area.drop_rect.collidepoint(position):
            self.clear_area_highlight()

    def on_snap_stack(self, *args):
        """When chips snap to cursor for first time
        """
        value = TextSprite('', self.large_font)
        self._mouse_tooltip = value
        self.hud.add(value, layer=100)

        # essentially just updates the tool tip value
        self.on_snap_stack_motion(*args)

        if self._locked_advice is None:
            self._advisor.empty()
            sprite = self._advisor.queue_text('Click to grab chips', 0)
            self._locked_advice = sprite

    def on_return_stack(self, *args):
        """When a stack of chips was previously snapped, but not any longer
        """
        # remove money tooltip
        self.hud.remove(self._mouse_tooltip)
        self._mouse_tooltip = None

        # remove 'click to grab chips' message
        if self._locked_advice is not None:
            self._advisor.dismiss(self._locked_advice)
            self._locked_advice = None

    def on_snap_stack_motion(self, *args):
        """When snapped stack is moved around
        """
        chips, position = args[0]
        amount = str(chips_to_cash(chips))
        sprite = self._mouse_tooltip
        sprite.text = "${}".format(amount)
        self.update_tooltip(sprite, position)

    def update_tooltip(self, sprite, position):
        sprite.rect.midleft = position
        sprite.rect.x += 30

    def clear_area_highlight(self):
        self.remove_animations(self._hovered_chip_area.sprite.image)

        ani = Animation(set_alpha=0,
                        initial=self._hovered_chip_area.sprite.image.get_alpha,
                        duration=500,
                        transition='out_quint')

        ani.callback = self._hovered_chip_area.sprite.kill
        ani.start(self._hovered_chip_area.sprite.image)
        self.animations.add(ani)

        self._hovered_chip_area = None

    def get_event(self, event, scale=(1, 1)):
        if event.type == pg.KEYDOWN:
            if event.key == pg.K_ESCAPE:
                self.goto_lobby()
                return

        if event.type == pg.MOUSEMOTION:
            pos = tools.scaled_mouse_pos(scale)
            sprite = self._clicked_sprite
            if sprite is not None:
                sprite.pressed = sprite.rect.collidepoint(pos)

            for sprite in self.hud.sprites():
                if self._hovered_sprite is None:
                    if hasattr(sprite, 'on_mouse_enter'):
                        if sprite.rect.collidepoint(pos):
                            self._hovered_sprite = sprite
                            sprite.on_mouse_enter(pos)

                elif sprite is self._hovered_sprite:
                    if hasattr(sprite, 'on_mouse_leave'):
                        if not sprite.rect.collidepoint(pos):
                            self._hovered_sprite = None
                            sprite.on_mouse_leave(pos)

        elif event.type == pg.MOUSEBUTTONDOWN:
            if event.button == 1:
                pos = tools.scaled_mouse_pos(scale)
                for sprite in self.hud.sprites():
                    if hasattr(sprite, 'on_mouse_click'):
                        if sprite.rect.collidepoint(pos):
                            sprite.pressed = True
                            self._clicked_sprite = sprite

        elif event.type == pg.MOUSEBUTTONUP:
            pos = tools.scaled_mouse_pos(scale)
            sprite = self._clicked_sprite
            if sprite is not None:
                if sprite.rect.collidepoint(pos):
                    sprite.pressed = False
                    sprite.on_mouse_click(pos)
                self._clicked_sprite = None

        if self._enable_chips:
            self.player_chips.get_event(event, scale)
            for bet in self.bets.groups():
                bet.get_event(event, scale)

    def delay(self, amount, callback, args=None, kwargs=None):
        """Convenience function to delay a function call

        :param amount: milliseconds to wait until callback is called
        :param callback: function to call
        :param args: arguments to pass to callback
        :param kwargs: keywords to pass to callback
        :return: Task instance
        """
        task = Task(callback, amount, 1, args, kwargs)
        self.animations.add(task)
        return task

    def deal_card(self, hand):
        """Shortcut to draw card from shoe and add to a hand

        :param hand: Deck instance
        :return: Card instance
        """
        sound = choice(self.deal_sounds)
        sound.set_volume(1)
        self.delay(100, sound.play)

        sound = choice(self.shove_sounds)
        sound.set_volume(.20)
        sound.play()

        card = self.shoe.pop()
        hand.add(card)

        return card

    def place_bet_with_amount(self, result, owner, amount):
        """Shortcut to place a bet with amount of wager

        :param result: Deck or None
        :param owner: ChipsPile instance
        :param amount: amount to wager in cash (not chips)
        :return: ChipsPile instance
        """
        chips = owner.withdraw_chips(amount)
        return self.place_bet(result, owner, chips)

    def place_bet(self, result, owner, chips):
        """Shortcut to place a bet with chips

        :param result: Deck or None
        :param owner: ChipsPile instance
        :param chips: Chips to wager with
        :return: ChipsPile instance
        """
        choice(self.chip_sounds).play()
        bet = ChipPile((600, 800, 200, 200))
        bet.extend(chips)
        bet.owner = owner
        bet.result = result
        self.bets.add(bet)
        return bet

    def goto_lobby(self, *args):
        """Try to exit to the lobby

        Player will be automatically cashed out if ok
        """
        if self._allow_exit:
            self.quit()

    def do_quit(self, *args):
        """Try to exit to the lobby

        Player will be automatically cashed out if ok
        """
        self.cash_out()
        self.done = True
        self.next = 'lobby'

    def cash_in(self):
        """Change player's cash to chips
        """
        chips = cash_to_chips(self.casino_player.stats['cash'])
        self.casino_player.stats['cash'] = 0
        self.player_chips.extend(chips)

    def cash_out(self):
        """Change player's chips to cash.  Includes any bets on table.
        """
        cash = self.player_chips.value
        for bet in self.bets.groups():
            if bet.origin is self.player_chips:
                bet.kill_me = True
                cash += bet.value
                bet.empty()
        self.casino_player.stats['cash'] = cash
        self.player_chips.empty()

    def get_bet_totals(self):
        """Get totals of all bets on the table

        :return: Totals of all bets on the table
        :rtype: Dict
        """
        totals = defaultdict(int)
        for name, area in self.betting_areas.items():
            for bet in self.bets.groups():
                if bet.result is area.hand:
                    result = bet.result
                    if result is None:
                        result = 'tie'
                    else:
                        result = name
                    totals[result] += bet.value
        return totals

    def clear_background(self):
        """Force the background to be redrawn
        """
        self._background = None

    def update(self, surface, keys, current_time, dt, scale):
        if self._background is None:
            image = self.render_background(surface.get_size())
            surface.blit(image, (0, 0))
            self._background = image

        self.animations.update(dt)
        self.metagroup.update(dt)
        self.metagroup.clear(surface, self._background)
        self.metagroup.draw(surface)
Exemplo n.º 7
0
    def startup(self, now, persistent):
        self.now = now
        self.persist = persistent
        self.casino_player = self.persist['casino_player']
        self.get_stats_from_casino_player()

        # declared here to appease pycharm's syntax checking.
        # will be filled in when configuration is loaded
        self.betting_areas = dict()
        self.dealer_hand = None
        self.player_hand = None
        self.player_chips = None
        self.house_chips = None
        self.shoe = None

        # baccarat only: move out later
        self.confirm_button_rect = None

        self.interested_events = [
            ('SNAP_STACK', self.on_snap_stack),
            ('RETURN_STACK', self.on_return_stack),
            ('SNAP_STACK_MOTION', self.on_snap_stack_motion),
            ('PICKUP_STACK', self.on_pickup_stack),
            ('DROP_STACK', self.on_drop_stack),
            ('PICKUP_STACK_MOTION', self.on_pickup_stack_motion),
        ]

        names = ["cardshove{}".format(x) for x in (1, 3, 4)]
        self.shove_sounds = [prepare.SFX[name] for name in names]
        names = ["cardplace{}".format(x) for x in (2, 3, 4)]
        self.deal_sounds = [prepare.SFX[name] for name in names]
        names = ["chipsstack{}".format(x) for x in (3, 5, 6)]
        self.chip_sounds = [prepare.SFX[name] for name in names]

        self._allow_exit = True
        self._enable_chips = False
        self._mouse_tooltip = None
        self._background = None
        self._hovered_sprite = None
        self._clicked_sprite = None
        self._hovered_chip_area = None
        self._grabbed_stack = False
        self._locked_advice = None

        self.font = pg.font.Font(prepare.FONTS["Saniretro"], 64)
        self.large_font = pg.font.Font(prepare.FONTS["Saniretro"], 120)
        self.button_font = pg.font.Font(prepare.FONTS["Saniretro"], 48)

        self.hud = SpriteGroup()
        self.bets = MetaGroup()
        self.metagroup = MetaGroup()
        self.metagroup.add(self.bets)
        self.animations = pg.sprite.Group()

        self._advisor = Advisor(self.hud, self.animations)
        self._advisor.queue_text('Welcome to Baccarat', 3000)

        self.hud.add(NeonButton('lobby', (540, 938, 0, 0), self.goto_lobby))

        spr = Sprite()
        spr.image = prepare.GFX['baccarat-menu-front']
        spr.rect = spr.image.get_rect()
        self.hud.add(spr, layer=1)

        spr = Sprite()
        spr.image = prepare.GFX['baccarat-menu-back']
        spr.rect = spr.image.get_rect()
        self.hud.add(spr, layer=-100)

        self.remove_animations = partial(remove_animations_of, self.animations)

        self.metagroup.add(self.hud)

        self.reload_config()
        self.link_events()
        self.cash_in()
        self.new_round()
Exemplo n.º 8
0
class TableGame(data.state.State):
    """Supports vegas style card games with chips and cards
    """
    name = 'table game base'

    def startup(self, now, persistent):
        self.now = now
        self.persist = persistent
        self.casino_player = self.persist['casino_player']
        self.get_stats_from_casino_player()

        # declared here to appease pycharm's syntax checking.
        # will be filled in when configuration is loaded
        self.betting_areas = dict()
        self.dealer_hand = None
        self.player_hand = None
        self.player_chips = None
        self.house_chips = None
        self.shoe = None

        # baccarat only: move out later
        self.confirm_button_rect = None

        self.interested_events = [
            ('SNAP_STACK', self.on_snap_stack),
            ('RETURN_STACK', self.on_return_stack),
            ('SNAP_STACK_MOTION', self.on_snap_stack_motion),
            ('PICKUP_STACK', self.on_pickup_stack),
            ('DROP_STACK', self.on_drop_stack),
            ('PICKUP_STACK_MOTION', self.on_pickup_stack_motion),
        ]

        names = ["cardshove{}".format(x) for x in (1, 3, 4)]
        self.shove_sounds = [prepare.SFX[name] for name in names]
        names = ["cardplace{}".format(x) for x in (2, 3, 4)]
        self.deal_sounds = [prepare.SFX[name] for name in names]
        names = ["chipsstack{}".format(x) for x in (3, 5, 6)]
        self.chip_sounds = [prepare.SFX[name] for name in names]

        self._allow_exit = True
        self._enable_chips = False
        self._mouse_tooltip = None
        self._background = None
        self._hovered_sprite = None
        self._clicked_sprite = None
        self._hovered_chip_area = None
        self._grabbed_stack = False
        self._locked_advice = None

        self.font = pg.font.Font(prepare.FONTS["Saniretro"], 64)
        self.large_font = pg.font.Font(prepare.FONTS["Saniretro"], 120)
        self.button_font = pg.font.Font(prepare.FONTS["Saniretro"], 48)

        self.hud = SpriteGroup()
        self.bets = MetaGroup()
        self.metagroup = MetaGroup()
        self.metagroup.add(self.bets)
        self.animations = pg.sprite.Group()

        self._advisor = Advisor(self.hud, self.animations)
        self._advisor.queue_text('Welcome to Baccarat', 3000)

        self.hud.add(NeonButton('lobby', (540, 938, 0, 0), self.goto_lobby))

        spr = Sprite()
        spr.image = prepare.GFX['baccarat-menu-front']
        spr.rect = spr.image.get_rect()
        self.hud.add(spr, layer=1)

        spr = Sprite()
        spr.image = prepare.GFX['baccarat-menu-back']
        spr.rect = spr.image.get_rect()
        self.hud.add(spr, layer=-100)

        self.remove_animations = partial(remove_animations_of, self.animations)

        self.metagroup.add(self.hud)

        self.reload_config()
        self.link_events()
        self.cash_in()
        self.new_round()

    def reload_config(self):
        raise NotImplementedError

    def new_round(self):
        raise NotImplementedError

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

        :return: collections.OrderedDict
        """
        raise NotImplementedError

    def render_background(self, size):
        """Render the background

        Subclasses must implement this

        :param size: (width, height) in pixels
        :return: pygame.surface.Surface
        """
        raise NotImplementedError

    def get_stats_from_casino_player(self):
        """Get stats for game and set them.  Will set defaults if needed.
        """
        self.stats = self.casino_player.stats.get(self.name, None)
        if self.stats is None:
            raise RuntimeError

    def set_casino_player_states(self):
        # to deal with the awkward new stats system
        for key, value in self.stats.items():
            print(key, value)
            self.casino_player.set(key, value)

    def cleanup(self):
        self.unlink_events()
        self.set_casino_player_states()
        return super(TableGame, self).cleanup()

    def link_events(self):
        for name, f in self.interested_events:
            B.linkEvent(name, f)

    def unlink_events(self):
        for name, f in self.interested_events:
            B.unlinkEvent(name, f)

    def on_pickup_stack(self, *args):
        """When a stack of chips is picked up
        """
        self._grabbed_stack = True

        self._locked_advice = None
        self._advisor.empty()
        self._advisor.queue_text('Place chips into a betting area', 0)

    def on_drop_stack(self, *args):
        """When a stack of chips is dropped anywhere
        """
        # this is a hack until i have a proper metagroup
        def remove(owner, chips):
            owner.remove(chips)
            if owner is not self.player_chips:
                if owner.value == 0:
                    self.bets.remove(owner)

        # clear the light areas under chips/betting areas
        if self._hovered_chip_area is not None:
            self.clear_area_highlight()

        self._grabbed_stack = False

        d = args[0]
        position = d['position']
        owner = d['object']
        chips = d['chips']

        needs_advice = not self.bets.groups()

        # this value is used to determine where to
        # return chips if this bet wins
        if not hasattr(owner, 'origin'):
            owner.origin = owner

        if self._hovered_chip_area is not None:
            self.clear_area_highlight()

        self._advisor.empty()

        # check if chip is dropped onto a bet pile or player chips
        areas = chain(self.bets.groups(), [self.player_chips])
        for area in areas:
            if area is owner:
                continue

            if area.rect.collidepoint(position):
                remove(owner, chips)
                area.extend(chips)
                area.ignore_until_away = True
                self.clear_background()

                if not self.bets.groups():
                    self.hide_bet_confirm_button()

                return True, area

        # place chips in betting area
        for area in self.betting_areas.values():
            if area.rect.collidepoint(position):
                remove(owner, chips)
                bet = self.place_bet(area.hand, owner.origin, chips)
                bet.origin = owner.origin
                bet.rect.bottomleft = position

                # TODO: should not be hardcoded
                bet.rect.x -= 32
                self.clear_background()

                if bet.result is None:
                    payout = self.options['tie_payout']
                    msg = 'Ties pay {} to 1'.format(payout)
                    self._advisor.queue_text(msg, 3000)

                if bet.result is self.dealer_hand:
                    com = int(self.options['commission'] * 100)
                    msg = 'There is a {}% commission on dealer bets'.format(com)
                    self._advisor.push_text(msg, 3000)

                if needs_advice:
                    # TODO: remove from baseclass
                    self.show_bet_confirm_button()

                return True, bet

        # place chips in the house chips
        if self.house_chips.rect.collidepoint(position):
            remove(owner, chips)
            new_chips = list()
            for chip in chips:
                for value in make_change(chip.value, break_down=True):
                    chip = Chip(value)
                    chip.rect.center = self.house_chips.rect.center
                    new_chips.append(chip)
            self.player_chips.extend(new_chips)

    def on_pickup_stack_motion(self, *args):
        """When mouse is hovering over a stack or moving it
        """
        chips, position = args[0]

        self.on_snap_stack_motion(*args)

        # check if mouse is hovering over betting area
        areas = chain(self.betting_areas.values(), [self.player_chips])
        if self._hovered_chip_area is None:
            for area in areas:
                if area.drop_rect.collidepoint(position):
                    self._hovered_chip_area = area
                    sprite = getattr(area, 'sprite', None)
                    if sprite is None:
                        sprite = Sprite()
                        sprite.rect = area.drop_rect.copy()
                        sprite.image = pg.Surface(sprite.rect.size)
                        sprite.image.fill((255, 255, 255))
                        area.sprite = sprite

                    self.hud.add(sprite)
                    self.remove_animations(sprite.image)
                    ani = Animation(set_alpha=48, initial=0,
                                    duration=500, transition='out_quint')
                    ani.start(sprite.image)
                    self.animations.add(ani)

        # handle when mouse moves outside previously hovered area
        elif not self._hovered_chip_area.drop_rect.collidepoint(position):
            self.clear_area_highlight()

    def on_snap_stack(self, *args):
        """When chips snap to cursor for first time
        """
        value = TextSprite('', self.large_font)
        self._mouse_tooltip = value
        self.hud.add(value, layer=100)

        # essentially just updates the tool tip value
        self.on_snap_stack_motion(*args)

        if self._locked_advice is None:
            self._advisor.empty()
            sprite = self._advisor.queue_text('Click to grab chips', 0)
            self._locked_advice = sprite

    def on_return_stack(self, *args):
        """When a stack of chips was previously snapped, but not any longer
        """
        # remove money tooltip
        self.hud.remove(self._mouse_tooltip)
        self._mouse_tooltip = None

        # remove 'click to grab chips' message
        if self._locked_advice is not None:
            self._advisor.dismiss(self._locked_advice)
            self._locked_advice = None

    def on_snap_stack_motion(self, *args):
        """When snapped stack is moved around
        """
        chips, position = args[0]
        amount = str(chips_to_cash(chips))
        sprite = self._mouse_tooltip
        sprite.text = "${}".format(amount)
        self.update_tooltip(sprite, position)

    def update_tooltip(self, sprite, position):
        sprite.rect.midleft = position
        sprite.rect.x += 30

    def clear_area_highlight(self):
        self.remove_animations(self._hovered_chip_area.sprite.image)

        ani = Animation(
            set_alpha=0,
            initial=self._hovered_chip_area.sprite.image.get_alpha,
            duration=500, transition='out_quint')

        ani.callback = self._hovered_chip_area.sprite.kill
        ani.start(self._hovered_chip_area.sprite.image)
        self.animations.add(ani)

        self._hovered_chip_area = None

    def get_event(self, event, scale=(1, 1)):
        if event.type == pg.KEYDOWN:
            if event.key == pg.K_ESCAPE:
                self.goto_lobby()
                return

        if event.type == pg.MOUSEMOTION:
            pos = tools.scaled_mouse_pos(scale)
            sprite = self._clicked_sprite
            if sprite is not None:
                sprite.pressed = sprite.rect.collidepoint(pos)

            for sprite in self.hud.sprites():
                if self._hovered_sprite is None:
                    if hasattr(sprite, 'on_mouse_enter'):
                        if sprite.rect.collidepoint(pos):
                            self._hovered_sprite = sprite
                            sprite.on_mouse_enter(pos)

                elif sprite is self._hovered_sprite:
                    if hasattr(sprite, 'on_mouse_leave'):
                        if not sprite.rect.collidepoint(pos):
                            self._hovered_sprite = None
                            sprite.on_mouse_leave(pos)

        elif event.type == pg.MOUSEBUTTONDOWN:
            if event.button == 1:
                pos = tools.scaled_mouse_pos(scale)
                for sprite in self.hud.sprites():
                    if hasattr(sprite, 'on_mouse_click'):
                        if sprite.rect.collidepoint(pos):
                            sprite.pressed = True
                            self._clicked_sprite = sprite

        elif event.type == pg.MOUSEBUTTONUP:
            pos = tools.scaled_mouse_pos(scale)
            sprite = self._clicked_sprite
            if sprite is not None:
                if sprite.rect.collidepoint(pos):
                    sprite.pressed = False
                    sprite.on_mouse_click(pos)
                self._clicked_sprite = None

        if self._enable_chips:
            self.player_chips.get_event(event, scale)
            for bet in self.bets.groups():
                bet.get_event(event, scale)

    def delay(self, amount, callback, args=None, kwargs=None):
        """Convenience function to delay a function call

        :param amount: milliseconds to wait until callback is called
        :param callback: function to call
        :param args: arguments to pass to callback
        :param kwargs: keywords to pass to callback
        :return: Task instance
        """
        task = Task(callback, amount, 1, args, kwargs)
        self.animations.add(task)
        return task

    def deal_card(self, hand):
        """Shortcut to draw card from shoe and add to a hand

        :param hand: Deck instance
        :return: Card instance
        """
        sound = choice(self.deal_sounds)
        sound.set_volume(1)
        self.delay(100, sound.play)

        sound = choice(self.shove_sounds)
        sound.set_volume(.20)
        sound.play()

        card = self.shoe.pop()
        hand.add(card)

        return card

    def place_bet_with_amount(self, result, owner, amount):
        """Shortcut to place a bet with amount of wager

        :param result: Deck or None
        :param owner: ChipsPile instance
        :param amount: amount to wager in cash (not chips)
        :return: ChipsPile instance
        """
        chips = owner.withdraw_chips(amount)
        return self.place_bet(result, owner, chips)

    def place_bet(self, result, owner, chips):
        """Shortcut to place a bet with chips

        :param result: Deck or None
        :param owner: ChipsPile instance
        :param chips: Chips to wager with
        :return: ChipsPile instance
        """
        choice(self.chip_sounds).play()
        bet = ChipPile((600, 800, 200, 200))
        bet.extend(chips)
        bet.owner = owner
        bet.result = result
        self.bets.add(bet)
        return bet

    def goto_lobby(self, *args):
        """Try to exit to the lobby

        Player will be automatically cashed out if ok
        """
        if self._allow_exit:
            self.quit()

    def do_quit(self, *args):
        """Try to exit to the lobby

        Player will be automatically cashed out if ok
        """
        self.cash_out()
        self.done = True
        self.next = 'lobby'

    def cash_in(self):
        """Change player's cash to chips
        """
        chips = cash_to_chips(self.casino_player.stats['cash'])
        self.casino_player.stats['cash'] = 0
        self.player_chips.extend(chips)

    def cash_out(self):
        """Change player's chips to cash.  Includes any bets on table.
        """
        cash = self.player_chips.value
        for bet in self.bets.groups():
            if bet.origin is self.player_chips:
                bet.kill_me = True
                cash += bet.value
                bet.empty()
        self.casino_player.stats['cash'] = cash
        self.player_chips.empty()

    def get_bet_totals(self):
        """Get totals of all bets on the table

        :return: Totals of all bets on the table
        :rtype: Dict
        """
        totals = defaultdict(int)
        for name, area in self.betting_areas.items():
            for bet in self.bets.groups():
                if bet.result is area.hand:
                    result = bet.result
                    if result is None:
                        result = 'tie'
                    else:
                        result = name
                    totals[result] += bet.value
        return totals

    def clear_background(self):
        """Force the background to be redrawn
        """
        self._background = None

    def update(self, surface, keys, current_time, dt, scale):
        if self._background is None:
            image = self.render_background(surface.get_size())
            surface.blit(image, (0, 0))
            self._background = image

        self.animations.update(dt)
        self.metagroup.update(dt)
        self.metagroup.clear(surface, self._background)
        self.metagroup.draw(surface)
Exemplo n.º 9
0
class BlackjackGame(object):
    """Represents a single game of blackjack."""
    draw_group = pg.sprite.Group()
    move_animations = pg.sprite.Group()
    advisor = Advisor(draw_group, move_animations)
    advisor.active = True
    advisor_back = prepare.GFX["advisor_back"]
    advisor_front = prepare.GFX["advisor_front"]
    advisor_back_dim = prepare.GFX["advisor_back_dim"]
    advisor_front_dim = prepare.GFX["advisor_front_dim"]
    font = prepare.FONTS["Saniretro"]
    result_font = prepare.FONTS["Saniretro"]
    deal_sounds = [
        prepare.SFX[name]
        for name in ["cardplace{}".format(x) for x in (2, 3, 4)]
    ]
    chip_sounds = [
        prepare.SFX[name]
        for name in ["chipsstack{}".format(x) for x in (3, 5, 6)]
    ]
    chip_size = (48, 30)
    screen_rect = pg.Rect((0, 0), prepare.RENDER_SIZE)
    advisor_active = True

    def __init__(self, casino_player, player_cash, chips=None, chip_pile=None):
        self.deck = Deck((20, 100), prepare.CARD_SIZE, 40)
        self.dealer = Dealer()
        self.chip_rack = ChipRack((1100, 130), self.chip_size)
        self.moving_stacks = []
        self.casino_player = casino_player
        self.player = Player(self.chip_size, player_cash, chips, chip_pile)
        self.labels = self.make_labels()
        self.current_player_hand = self.player.hands[0]
        self.quick_bet = 0
        self.last_bet = 0
        rect = self.advisor_back.get_rect().union(
            self.advisor_front.get_rect())
        self.advisor_button = Button(rect, call=self.toggle_advisor)

    def make_labels(self):
        labels_info = [("Drop chips in chip rack", 36, "antiquewhite", 100, {
            "midtop":
            (self.chip_rack.rect.centerx, self.chip_rack.rect.bottom + 5)
        }),
                       ("to make change", 36, "antiquewhite", 100, {
                           "midtop": (self.chip_rack.rect.centerx,
                                      self.chip_rack.rect.bottom + 60)
                       }),
                       ("Blackjack Pays 3 to 2", 64, "gold3", 120, {
                           "midtop": (580, 300)
                       }),
                       ("Dealer must draw to 16 and stand on 17", 48,
                        "antiquewhite", 100, {
                            "midtop": (580, 240)
                        })]
        labels = []
        for info in labels_info:
            label = Label(self.font,
                          info[1],
                          info[0],
                          info[2],
                          info[4],
                          bg=prepare.FELT_GREEN)
            label.image.set_alpha(info[3])
            labels.append(label)
        return labels

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

    def tally_hands(self):
        """
        Calculate result of each player hand and set appropriate
        flag for each hand.
        """
        if self.dealer.hand.blackjack:
            for hand in self.player.hands:
                hand.loser = True
        elif self.dealer.hand.busted:
            for hand in self.player.hands:
                if not hand.busted and not hand.blackjack:
                    hand.winner = True
        else:
            d_score = self.dealer.hand.best_score()
            for hand in self.player.hands:
                if not hand.busted:
                    p_score = hand.best_score()
                    if p_score == 21 and len(hand.cards) == 2:
                        hand.blackjack = True
                    elif p_score < d_score:
                        hand.loser = True
                    elif p_score == d_score:
                        hand.push = True
                    else:
                        hand.winner = True

    def pay_out(self):
        """
        Calculate player win amounts, update stats and return chips
        totalling total win amount.
        """
        cash = 0
        for hand in self.player.hands:
            bet = hand.bet.get_chip_total()
            self.casino_player.increase("hands played")
            self.casino_player.increase("total bets", bet)
            if hand.busted:
                self.casino_player.increase("busts")
                self.casino_player.increase("hands lost")
            elif hand.loser:
                self.casino_player.increase("hands lost")
            elif hand.blackjack:
                cash += int(bet * 2.5)
                self.casino_player.increase("blackjacks")
                self.casino_player.increase("hands won")
            elif hand.winner:
                cash += bet * 2
                self.casino_player.increase("hands won")
            elif hand.push:
                cash += bet
                self.casino_player.increase("pushes")

        self.casino_player.increase("total winnings", cash)
        chips = cash_to_chips(cash, self.chip_size)
        return chips

    def get_event(self, event):
        self.advisor_button.get_event(event)

    def update(self, dt, mouse_pos):
        self.advisor_button.update(mouse_pos)
        total_text = "Chip Total:  ${}".format(
            self.player.chip_pile.get_chip_total())
        screen = self.screen_rect
        self.chip_total_label = Label(
            self.font, 48, total_text, "gold3",
            {"bottomleft": (screen.left + 3, screen.bottom - 3)})
        self.chip_rack.update()
        if self.advisor_active:
            self.move_animations.update(dt)
Exemplo n.º 10
0
class GutsState(object):
    font = prepare.FONTS["Saniretro"]
    deal_sounds = [prepare.SFX["cardshove{}".format(x)] for x in (1, 3, 4)]
    flip_sounds = [prepare.SFX["cardplace{}".format(x)] for x in (2, 3, 4)]
    cha_ching = prepare.SFX["coins"]
    screen_rect = pg.Rect((0, 0), prepare.RENDER_SIZE)
    money_icon = MoneyIcon((0, screen_rect.bottom - 75))
    draw_group = pg.sprite.Group()
    move_animations = pg.sprite.Group()
    advisor = Advisor(draw_group, move_animations)
    advisor.active = True
    advisor_back = prepare.GFX["advisor_back"]
    advisor_front = prepare.GFX["advisor_front"]
    advisor_back_dim = prepare.GFX["advisor_back_dim"]
    advisor_front_dim = prepare.GFX["advisor_front_dim"]
    advisor_active = True
    window = None

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

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

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

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

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

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

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

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

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

    def update(self, dt, scale):
        pass

    def get_event(self, event):
        pass

    def draw(self, surface):
        pass

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

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

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

    def play_pass_sound(self):
        choice(self.fold_sounds).play()