view browser_side/card_game.py @ 38:7bea2ae0c4fb

Tarot game: center_panel layout + chien can now be showed + fixed click event inheritance + card selection first draft
author Goffi <goffi@goffi.org>
date Thu, 19 May 2011 02:00:59 +0200
parents b306aa090438
children 305e81c7a32c
line wrap: on
line source

#!/usr/bin/python
# -*- coding: utf-8 -*-

"""
Libervia: a Salut à Toi frontend
Copyright (C) 2011  Jérôme Poisson (goffi@goffi.org)

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""

import pyjd # this is dummy in pyjs
from pyjamas.ui.AbsolutePanel import AbsolutePanel
from pyjamas.ui.VerticalPanel import VerticalPanel
from pyjamas.ui.HorizontalPanel import HorizontalPanel
from pyjamas.ui.DockPanel import DockPanel
from pyjamas.ui.SimplePanel import SimplePanel
from pyjamas.ui.DialogBox import DialogBox
from pyjamas.ui.ListBox import ListBox
from pyjamas.ui.Image import Image
from pyjamas.ui.Label import Label
from pyjamas.ui.Button import Button
from pyjamas.ui.ClickListener import ClickHandler
from pyjamas.ui.MouseListener import MouseHandler
from pyjamas.ui import HasAlignment
from pyjamas import Window
from pyjamas import DOM

from pyjamas.dnd import makeDraggable
from pyjamas.ui.DragWidget import DragWidget, DragContainer
from jid import JID
from tools import html_sanitize
from datetime import datetime
from time import time
from games import TarotCard



CARD_WIDTH = 74
CARD_HEIGHT = 136
CARD_DELTA_Y = 10
MIN_WIDTH = 950 #Minimum size of the panel
MIN_HEIGHT = 500

class ContratChooser(DialogBox):

    def __init__(self, parent):
        """
        Dialog asking to choose the contrat
        """
        self._parent = parent
        DialogBox.__init__(self, modal=False, centered=True)

        content = VerticalPanel()
        content.setWidth('100%')
        self.contrats_list = ListBox()
        self.contrats_list.setVisibleItemCount(5)
        self.contrats_list.setWidth("100%")
        self.contrats_list.setStyleName('contratsChooser')
        for contrat in ['Passe', 'Petite', 'Garde', 'Garde Sans', 'Garde Contre']:
            self.contrats_list.addItem(contrat)
        self.contrats_list.setSelectedIndex(0)
        content.add(self.contrats_list)
        button_panel = HorizontalPanel()
        self.choose_button = Button("Choose", self.onChoose)
        button_panel.add(self.choose_button)
        content.add(button_panel)
        self.setHTML("Please select your contrat")
        self.setWidget(content)	
    
    def onChoose(self):
        self.hide()
        self._parent.contratSelected(self.contrats_list.getSelectedItemText()[0])

class CardWidget(TarotCard, Image, MouseHandler):
    """This class is used to represent a card, graphically and logically"""

    def __init__(self, parent, file):
        """@param file: path of the PNG file"""
        self._parent = parent
        Image.__init__(self,file)
        root_name = file[file.rfind("/")+1:-4]
        suit,value = root_name.split('_')
        TarotCard.__init__(self, (suit, value))
        MouseHandler.__init__(self)
        self.addMouseListener(self)

    def onMouseEnter(self, sender):
        if self._parent.state == "ecart":
            DOM.setStyleAttribute(self.getElement(), "top", "0px")

    def onMouseLeave(self, sender):
        DOM.setStyleAttribute(self.getElement(), "top", "%dpx" % CARD_DELTA_Y)

class CardPanel(DockPanel, ClickHandler):

    def __init__(self, parent, referee, players, player_nick):
        DockPanel.__init__(self)
        ClickHandler.__init__(self)
        self._parent = parent
        self._autoplay = None #XXX: use 0 to activate fake play, None else
        self.referee = referee
        self.players = players
        self.played = {}
        for player in players:
            self.played[player] = None
        self.player_nick = player_nick
        self.bottom_nick = self.player_nick
        idx = self.players.index(self.player_nick)
        idx = (idx + 1) % len(self.players)
        self.right_nick = self.players[idx]
        idx = (idx + 1) % len(self.players)
        self.top_nick = self.players[idx]
        idx = (idx + 1) % len(self.players)
        self.left_nick = self.players[idx]
        self.bottom_nick = player_nick
        self.selected = [] #Card choosed by the player (e.g. during ecart)
        self.hand_size = 13 #number of cards in a hand
        self.hand = []
        self.to_show = []
        self.state = None
        self.setSize("%dpx" % MIN_WIDTH, "%dpx" % MIN_HEIGHT)
        self.setStyleName("cardPanel")
        
        # Now we set up the layout
        _label = Label(self.top_nick)
        _label.setStyleName('cardGamePlayerNick')
        self.add(_label, DockPanel.NORTH)
        self.setCellWidth(_label, '100%')
        self.setCellHorizontalAlignment(_label, HasAlignment.ALIGN_CENTER) 
        
        
        self.hand_panel = AbsolutePanel()
        self.add(self.hand_panel, DockPanel.SOUTH)
        self.setCellWidth(self.hand_panel, '100%')
        self.setCellHorizontalAlignment(self.hand_panel, HasAlignment.ALIGN_CENTER)


        _label = Label(self.left_nick)
        _label.setStyleName('cardGamePlayerNick')
        self.add(_label, DockPanel.WEST)
        self.setCellHeight(_label, '100%')
        self.setCellVerticalAlignment(_label, HasAlignment.ALIGN_MIDDLE) 


        _label = Label(self.right_nick)
        _label.setStyleName('cardGamePlayerNick')
        self.add(_label, DockPanel.EAST)
        self.setCellHeight(_label, '100%')
        self.setCellHorizontalAlignment(_label, HasAlignment.ALIGN_RIGHT) 
        self.setCellVerticalAlignment(_label, HasAlignment.ALIGN_MIDDLE) 
        

        self.center_panel = DockPanel()
        self.inner_left = SimplePanel()
        self.center_panel.add(self.inner_left, DockPanel.WEST)
        self.center_panel.setCellHeight(self.inner_left, '100%')
        self.center_panel.setCellHorizontalAlignment(self.inner_left, HasAlignment.ALIGN_RIGHT)
        self.center_panel.setCellVerticalAlignment(self.inner_left, HasAlignment.ALIGN_MIDDLE)

        self.inner_right = SimplePanel()
        self.center_panel.add(self.inner_right, DockPanel.EAST)
        self.center_panel.setCellHeight(self.inner_right, '100%')
        self.center_panel.setCellVerticalAlignment(self.inner_right, HasAlignment.ALIGN_MIDDLE)
        
        self.inner_top = SimplePanel()
        self.center_panel.add(self.inner_top, DockPanel.NORTH)
        self.center_panel.setCellWidth(self.inner_top, '100%')
        self.center_panel.setCellHorizontalAlignment(self.inner_top, HasAlignment.ALIGN_CENTER)
        self.center_panel.setCellVerticalAlignment(self.inner_top, HasAlignment.ALIGN_BOTTOM)
        
        self.inner_bottom = SimplePanel()
        self.center_panel.add(self.inner_bottom, DockPanel.SOUTH)
        self.center_panel.setCellWidth(self.inner_bottom, '100%')
        self.center_panel.setCellHorizontalAlignment(self.inner_bottom, HasAlignment.ALIGN_CENTER)
        self.center_panel.setCellVerticalAlignment(self.inner_bottom, HasAlignment.ALIGN_TOP)
        
        self.inner_center = SimplePanel()
        self.center_panel.add(self.inner_center, DockPanel.CENTER)
        self.center_panel.setCellHorizontalAlignment(self.inner_center, HasAlignment.ALIGN_CENTER)
        self.center_panel.setCellVerticalAlignment(self.inner_center, HasAlignment.ALIGN_MIDDLE)

        self.add(self.center_panel, DockPanel.CENTER)
        self.setCellWidth(self.center_panel, '100%')
        self.setCellHeight(self.center_panel, '100%')
        self.setCellVerticalAlignment(self.center_panel, HasAlignment.ALIGN_MIDDLE)
        self.setCellHorizontalAlignment(self.center_panel, HasAlignment.ALIGN_CENTER)


        """for side in zip(['left', 'top', 'right'],
                        [DockPanel.WEST, DockPanel.NORTH, DockPanel.EAST]):
            _nick = getattr(self, "%s_nick" % side[0])
            _label = Label(_nick)
            _label.setStyleName('cardGamePlayerNick')
            self.add(_label, side[1])"""
        self.loadCards()
        self.mouse_over_card = None #contain the card to highlight
        self.visible_size = CARD_WIDTH/2 #number of pixels visible for cards
        self.addClickListener(self)


    def loadCards(self, dir):
        """Load all the cards in memory
        @param dir: directory where the PNG files are"""
        def _getTarotCardsPathsCb(paths):
            for file in paths:
                card = CardWidget(self, file)
                self.cards[(card.suit, card.value)]=card
                self.deck.append(card)
            self._parent.host.bridge.call('tarotGameReady', None, self.player_nick, self.referee)
        self.cards={}
        self.deck=[]
        self.cards["atout"]={} #As Tarot is a french game, it's more handy & logical to keep french names
        self.cards["pique"]={} #spade
        self.cards["coeur"]={} #heart
        self.cards["carreau"]={} #diamond
        self.cards["trefle"]={} #club
        self._parent.host.bridge.call('getTarotCardsPaths', _getTarotCardsPathsCb)

    def onClick(self, sender):
        if self.state == "chien":
            self.to_show = []
            self.state = "wait"
            self.updateToShow()
        elif self.state == "wait_for_ecart":
            self.state = "ecart"
            self.hand.extend(self.to_show)
            self.hand.sort()
            self.to_show = []
            self.updateToShow()
            self.updateHand()

    def tarotGameNew(self, hand):
        """Start a new game, with given hand"""
        for suit, value in hand:
            self.hand.append(self.cards[(suit, value)])
        self.hand.sort()
        self.state = "init"
        self.updateHand()

    def updateHand(self):
        """Show the cards in the hand in the hand_panel (SOUTH panel)"""
        self.hand_panel.clear()
        self.hand_panel.setSize("%dpx" % (self.visible_size * (len(self.hand)+1)), "%dpx" % (CARD_HEIGHT + CARD_DELTA_Y + 10))
        x_pos = 0
        y_pos = CARD_DELTA_Y
        for card in self.hand:
            self.hand_panel.add(card, x_pos, y_pos)
            x_pos+=self.visible_size
   
    def updateToShow(self):
        """Show cards in the center panel"""
        if not self.to_show:
            _widget = self.inner_center.getWidget()
            if _widget: 
                self.inner_center.remove(_widget)
            return
        panel = AbsolutePanel()
        panel.setSize("%dpx" % ((CARD_WIDTH + 5) * len(self.to_show) - 5), "%dpx" % (CARD_HEIGHT))
        x_pos = 0
        y_pos = 0
        for card in self.to_show:
            panel.add(card, x_pos, y_pos)
            x_pos+=CARD_WIDTH + 5
        self.inner_center.setWidget(panel)


    def tarotGameChooseContrat(self, xml_data):
        """Called when the player as to select his contrat
        @param xml_data: SàT xml representation of the form"""
        #for the moment we cheat a little bit and make our own dialog box
        #but XMLUI must be user ASAP, as in other frontends
        contrat_chooser = ContratChooser(self)
        contrat_chooser.show()

    def contratSelected(self, contrat):
        """Must be called when the contrat is selected
        @param contrat: one of the valid contrat value"""
        print "Contrat choosed:", contrat
        self._parent.host.bridge.call('tarotGameContratChoosed', None, self.player_nick, self.referee, contrat or 'Passe')



    def tarotGameShowCards(self, game_stage, cards, data):
        """Display cards in the middle of the game (to show for e.g. chien ou poignée)"""
        self.to_show = []
        for suit, value in cards:
            self.to_show.append(self.cards[(suit, value)])
        self.updateToShow()
        if game_stage == "chien" and data['attaquant'] == self.player_nick:
            self.state = "wait_for_ecart"
        else:
            self.state = "chien"