# HG changeset patch # User Goffi # Date 1280144624 -28800 # Node ID 80661755ea8d772edc7c51d7f1774780c186433a # Parent 119f45746fde476de6814e0bb0f874e68b224e3c Primitivus: Tarot card game implementation - quick frontend: card_game added - wix: card_game splitted with quick frontend - tools: new game library - primitivus: new card_game widget (not finished yet) - primitivus: SàT XML UI management: first draft diff -r 119f45746fde -r 80661755ea8d frontends/primitivus/card_game.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/frontends/primitivus/card_game.py Mon Jul 26 19:43:44 2010 +0800 @@ -0,0 +1,149 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Primitivus: a SAT frontend +Copyright (C) 2009, 2010 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 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +""" + +import urwid +from tools.games import TarotCard +from quick_frontend.quick_card_game import QuickCardGame +from xmlui import XMLUI + +class Hand(urwid.WidgetWrap): + """Used to display several cards, and manage a hand""" + + def __init__(self): + self.columns = urwid.Columns([]) + urwid.WidgetWrap.__init__(self, self.columns) + + def update(self, hand): + """Update the hand displayed in this widget""" + del self.columns.widget_list[:] + del self.columns.column_types[:] + for card in hand: + self.columns.widget_list.append(urwid.Text(card.getAttrText())) + self.columns.column_types.append(('weight',1)) + + + + +class Card(TarotCard): + """This class is used to represent a card, logically + and give a text representation with attributes""" + + def __init__(self, suit, value): + """@param file: path of the PNG file""" + TarotCard.__init__(self, (suit, value)) + + def getAttrText(self): + """return text representation of the card with attributes""" + try: + value = "%02i" % int(self.value) + except ValueError: + value = self.value[0].upper()+self.value[1] + if self.suit == "atout": + if self.value == "excuse": + suit = 'c' + else: + suit = 'A' + color = 'neutral' + elif self.suit == "pique": + suit = u'♠' + color = 'black' + elif self.suit == "trefle": + suit = u'♣' + color = 'black' + elif self.suit == "coeur": + suit = u'♥' + color = 'red' + elif self.suit == "carreau": + suit = u'♦' + color = 'red' + if self.bout: + color = 'special' + return ('card_%s' % color,u"%s%s" % (value,suit)) + +class CardGame(QuickCardGame,urwid.WidgetWrap): + """Widget for card games""" + + def __init__(self, parent, referee, players, player_nick): + QuickCardGame.__init__(self, parent, referee, players, player_nick) + self.loadCards() + self.top = urwid.Pile([urwid.Padding(urwid.Text(self.top_nick), 'center')]) + self.top_card_wid = urwid.Text('') + self.center_cards_wid = urwid.Text(' - ') + self.bottom_card_wid = urwid.Text('') + center = urwid.Pile([urwid.Padding(self.top_card_wid,'center'), + urwid.Columns([('fixed',len(self.left_nick),urwid.Text(self.left_nick)), + urwid.Padding(self.center_cards_wid,'center'), + ('fixed',len(self.right_nick),urwid.Text(self.right_nick)) + ]), + urwid.Padding(self.bottom_card_wid,'center') + ]) + body = urwid.Filler(center) + self.hand_wid = Hand() + self.main_frame = urwid.Frame(body,header=self.top, footer=self.hand_wid) + urwid.WidgetWrap.__init__(self,self.main_frame) + self.parent.host.bridge.tarotGameReady(player_nick, referee, profile_key = self.parent.host.profile) + + def loadCards(self): + """Load all the cards in memory""" + QuickCardGame.loadCards(self) + for value in map(str,range(1,22))+['excuse']: + card = Card('atout',value) + self.cards[card.suit, card.value]=card + self.deck.append(card) + for suit in ["pique", "coeur", "carreau", "trefle"]: + for value in map(str,range(1,11))+["valet","cavalier","dame","roi"]: + card = Card(suit,value) + self.cards[card.suit, card.value]=card + self.deck.append(card) + + def newGame(self, hand): + """Start a new game, with given hand""" + QuickCardGame.newGame(self, hand) + self.hand_wid.update(self.hand) + self.parent.host.redraw() + + def contratSelected(self, data): + """Called when the contrat has been choosed + @param data: form result""" + contrat = data[0][1] + QuickCardGame.contratSelected(self, contrat) + + def chooseContrat(self, xml_data): + """Called when the player as to select his contrat + @param xml_data: SàT xml representation of the form""" + misc = {'callback': self.contratSelected} + form = XMLUI(self.parent.host, xml_data, title = _('Please choose your contrat'), options = ['NO_CANCEL'], misc = misc) + form.show() + + """def selectable(self): + return True + + def keypress(self, size, key): + return key + + def render(self, size, focus=False): + return self.display_widget(size, focus).render(size, focus) + + def display_widget(self, size, focus): + (maxcol,maxrow) = size + + return self.main_frame""" + diff -r 119f45746fde -r 80661755ea8d frontends/primitivus/chat.py --- a/frontends/primitivus/chat.py Thu Jul 22 22:47:29 2010 +0800 +++ b/frontends/primitivus/chat.py Mon Jul 26 19:43:44 2010 +0800 @@ -25,6 +25,7 @@ import custom_widgets import time from tools.jid import JID +from card_game import CardGame class ChatText(urwid.FlowWidget): @@ -79,8 +80,10 @@ self.content = urwid.SimpleListWalker([]) self.text_list = urwid.ListBox(self.content) self.chat_widget = urwid.Frame(self.text_list) - self.columns = urwid.Columns([('weight', 8, self.chat_widget)]) - urwid.WidgetWrap.__init__(self, self.__getDecoration(self.columns)) + self.chat_colums = urwid.Columns([('weight', 8, self.chat_widget)]) + self.chat_colums = urwid.Columns([('weight', 8, self.chat_widget)]) + self.pile = urwid.Pile([self.chat_colums]) + urwid.WidgetWrap.__init__(self, self.__getDecoration(self.pile)) self.setType(type) self.day_change = time.strptime(time.strftime("%a %b %d 00:00:00 %Y")) #struct_time of day changing time self.show_timestamp = True @@ -91,7 +94,7 @@ def keypress(self, size, key): if key == "meta p": #user wants to (un)hide the presents panel if self.type == 'group': - widgets = self.columns.widget_list + widgets = self.chat_colums.widget_list if self.present_panel in widgets: self.__removePresentPanel() else: @@ -135,7 +138,7 @@ if type == 'one2one': self.historyPrint(profile=self.host.profile) elif type == 'group': - if len(self.columns.widget_list) == 1: + if len(self.chat_colums.widget_list) == 1: present_widget = self.__buildPresentList() self.present_panel = custom_widgets.VerticalSeparator(present_widget) self.__appendPresentPanel() @@ -144,10 +147,11 @@ return custom_widgets.LabelLine(widget, custom_widgets.SurroundedText(unicode(self.target))) def showDecoration(self, show=True): + """Show/Hide the decoration around the chat window""" if show: - main_widget = self.__getDecoration(self.columns) + main_widget = self.__getDecoration(self.pile) else: - main_widget = self.columns + main_widget = self.pile self._w = main_widget @@ -156,13 +160,28 @@ return self.present_wid def __appendPresentPanel(self): - self.columns.widget_list.append(self.present_panel) - self.columns.column_types.append(('weight', 2)) + self.chat_colums.widget_list.append(self.present_panel) + self.chat_colums.column_types.append(('weight', 2)) def __removePresentPanel(self): - self.columns.set_focus(0) #necessary as the focus change to the next object, we can go out of range if we are on the last object of self.columns - self.columns.widget_list.remove(self.present_panel) - del self.columns.column_types[-1] + self.chat_colums.set_focus(0) #necessary as the focus change to the next object, we can go out of range if we are on the last object of self.chat_colums + self.chat_colums.widget_list.remove(self.present_panel) + del self.chat_colums.column_types[-1] + + def __appendGamePanel(self, widget): + assert (len(self.pile.widget_list) == 1) + self.pile.widget_list.insert(0,widget) + self.pile.item_types.insert(0,('weight', 1)) + self.pile.widget_list.insert(1,urwid.Filler(urwid.Divider('-'))) + self.pile.item_types.insert(1,('fixed', 1)) + self.host.redraw() + + def __removeGamePanel(self): + assert (len(self.pile.widget_list) == 3) + self.pile.set_focus(0) #necessary as the focus change to the next object, we can go out of range if we are on the last object of self.chat_colums + del self.pile.widget_list[0] + del self.pile.item_types[0] + self.host.redraw() def setSubject(self, subject, wrap='space'): """Set title for a group chat""" @@ -209,11 +228,25 @@ self.content.append(ChatText(self, timestamp or None, my_jid, from_jid, msg)) self.text_list.set_focus(len(self.content)-1) self.host.redraw() + + def startGame(self, game_type, referee, players): + """Configure the chat window to start a game""" + if game_type=="Tarot": + try: + self.tarot_wid = CardGame(self, referee, players, self.nick) + self.__appendGamePanel(self.tarot_wid) + except e: + self.host.debug() + + def getGame(self, game_type): + """Return class managing the game type""" + #TODO: check that the game is launched, and manage errors + if game_type=="Tarot": + return self.tarot_wid #MENU EVENTS# def onTarotRequest(self, menu): if len(self.occupants) != 4: - self.host.debug() self.host.showPopUp(custom_widgets.Alert(_("Can't start game"), _("You need to be exactly 4 peoples in the room to start a Tarot game"), ok_cb=self.host.removePopUp)) else: self.host.bridge.tarotGameCreate(self.id, list(self.occupants), self.host.profile) diff -r 119f45746fde -r 80661755ea8d frontends/primitivus/custom_widgets.py --- a/frontends/primitivus/custom_widgets.py Thu Jul 22 22:47:29 2010 +0800 +++ b/frontends/primitivus/custom_widgets.py Mon Jul 26 19:43:44 2010 +0800 @@ -23,7 +23,6 @@ from urwid.escape import utf8decode class Password(urwid.Edit): - toto=0 """Edit box which doesn't show what is entered (show '*' or other char instead)""" def __init__(self, *args, **kwargs): @@ -47,11 +46,6 @@ super(Password,self).insert_text(text) def render(self, size, focus=False): - Password.toto+=1 - if Password.toto==30: - import os,pdb - os.system('reset') - pdb.set_trace() return super(Password, self).render(size, focus) class AdvancedEdit(urwid.Edit): diff -r 119f45746fde -r 80661755ea8d frontends/primitivus/primitivus --- a/frontends/primitivus/primitivus Thu Jul 22 22:47:29 2010 +0800 +++ b/frontends/primitivus/primitivus Mon Jul 26 19:43:44 2010 +0800 @@ -69,6 +69,14 @@ ('selected_menu', 'light gray,bold', 'dark green'), ('menuitem', 'light gray,bold', 'dark red'), ('menuitem_focus', 'light gray,bold', 'dark green'), + ('card_neutral', 'dark gray', 'white', 'standout,underline'), + ('card_neutral_selected', 'dark gray', 'dark green', 'standout,underline'), + ('card_special', 'brown', 'white', 'standout,underline'), + ('card_special_selected', 'brown', 'dark green', 'standout,underline'), + ('card_red', 'dark red', 'white', 'standout,underline'), + ('card_red_selected', 'dark red', 'dark green', 'standout,underline'), + ('card_black', 'black', 'white', 'standout,underline'), + ('card_black_selected', 'black', 'dark green', 'standout,underline'), ] class ChatList(QuickChatList): @@ -205,7 +213,7 @@ if contact: assert(len(self.center_part.widget_list)==2) self.center_part.widget_list[1] = self.chat_wins[contact] - self.menu_roller.addMenu(_('Chat Menu'), self.chat_wins[contact].getMenu()) + self.menu_roller.addMenu(_('Chat menu'), self.chat_wins[contact].getMenu()) def onTextEntered(self, editBar): """Called when text is entered in the main edit bar""" diff -r 119f45746fde -r 80661755ea8d frontends/primitivus/xmlui.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/frontends/primitivus/xmlui.py Mon Jul 26 19:43:44 2010 +0800 @@ -0,0 +1,196 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Primitivus: a SAT frontend +Copyright (C) 2009, 2010 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 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +""" + +import urwid +import custom_widgets +from xml.dom import minidom + +class Pairs(urwid.WidgetWrap): + + def __init__(self, weight_0='1', weight_1='1'): + self.idx = 0 + self.weight_0 = weight_0 + self.weight_1 = weight_1 + columns = urwid.Columns([urwid.Text(''), urwid.Text('')]) + #XXX: empty Text hack needed because Pile doesn't support empty list + urwid.WidgetWrap.__init__(self,columns) + + def append(self, widget): + pile = self._w.widget_list[self.idx] + if pile.__class__ == urwid.Text: + self._w.widget_list[self.idx] = urwid.Pile([widget]) + else: + pile.widget_list.append(widget) + pile.item_types.append(('weight',getattr(self,'weight_'+str(self.idx)))) + self.idx = (self.idx + 1) % 2 + + +class XMLUI(urwid.WidgetWrap): + + def __init__(self, host, xml_data, title = None, options = [], misc={}): + self.host = host + self.title = title + self.options = options + self.misc = misc + self.ctrl_list = {} # usefull to access ctrl + widget = self.constructUI(xml_data) + urwid.WidgetWrap.__init__(self,widget) + + def __parseElems(self, node, parent): + """Parse elements inside a tags, and add them to the parent""" + for elem in node.childNodes: + if elem.nodeName != "elem": + message=_("Unmanaged tag") + error(message) + raise Exception(message) + id = elem.getAttribute("id") + name = elem.getAttribute("name") + type = elem.getAttribute("type") + value = elem.getAttribute("value") if elem.hasAttribute('value') else u'' + if type=="empty": + ctrl = urwid.Text('') + elif type=="text": + try: + value = elem.childNodes[0].wholeText + except KeyError: + warning (_("text node has no child !")) + ctrl = urwid.Text(value) + elif type=="label": + ctrl = urwid.Text(value+": ") + elif type=="string": + ctrl = urwid.Edit(edit_text = value) + self.ctrl_list[name] = ({'type':type, 'control':ctrl}) + elif type=="password": + ctrl = custom_widgets.Password(edit_text = value) + self.ctrl_list[name] = ({'type':type, 'control':ctrl}) + elif type=="textbox": + ctrl = urwid.Edit(edit_text = value, multiline=True) + self.ctrl_list[name] = ({'type':type, 'control':ctrl}) + elif type=="list": + style=[] if elem.getAttribute("multi")=='yes' else ['single'] + ctrl = custom_widgets.List(options=[option.getAttribute("value") for option in elem.getElementsByTagName("option")], style=style) + self.ctrl_list[name] = ({'type':type, 'control':ctrl}) + elif type=="button": + callback_id = elem.getAttribute("callback_id") + ctrl = urwid.Button(value, on_press=self.onButtonPress) + ctrl.param_id = (callback_id,[field.getAttribute('name') for field in elem.getElementsByTagName("field_back")]) + else: + error(_("FIXME FIXME FIXME: type [%s] is not implemented") % type) #FIXME ! + raise NotImplementedError + parent.append(ctrl) + + def __parseChilds(self, current, elem, wanted = ['layout']): + """Recursively parse childNodes of an elemen + @param current: widget container with 'append' method + @param elem: element from which childs will be parsed + @param wanted: list of tag names that can be present in the childs to be SàT XMLUI compliant""" + for node in elem.childNodes: + if wanted and not node.nodeName in wanted: + raise Exception("Invalid XMLUI") #TODO: make a custom exception + if node.nodeName == "layout": + type = node.getAttribute('type') + if type == "tabs": + raise NotImplementedError + self.__parseChilds(current, None, node, ['category']) + else: + if type == "vertical": + pass + elif type == "pairs": + pairs = Pairs() + current.append(pairs) + current = pairs + else: + warning(_("Unknown layout, using default one")) + self.__parseElems(node, current) + elif node.nodeName == "category": + raise NotImplementedError + """name = node.getAttribute('name') + if not node.nodeName in wanted or not name or not isinstance(parent,wx.Notebook): + raise Exception("Invalid XMLUI") #TODO: make a custom exception + notebook = parent + tab_panel = wx.Panel(notebook, -1) + tab_panel.sizer = wx.BoxSizer(wx.VERTICAL) + tab_panel.SetSizer(tab_panel.sizer) + notebook.AddPage(tab_panel, name) + self.__parseChilds(tab_panel, None, node, ['layout'])""" + + else: + message=_("Unknown tag") + error(message) + raise Exception(message) #TODO: raise a custom exception here + + def constructUI(self, xml_data): + + list_box = urwid.ListBox(urwid.SimpleListWalker([])) + + cat_dom = minidom.parseString(xml_data.encode('utf-8')) + top= cat_dom.documentElement + self.type = top.getAttribute("type") + if not self.title: + self.title = top.getAttribute("title") #TODO: manage title + if top.nodeName != "sat_xmlui" or not self.type in ['form', 'param', 'window']: + raise Exception("Invalid XMLUI") #TODO: make a custom exception + + self.__parseChilds(list_box.body, cat_dom.documentElement) + + if self.type == 'form': + buttons = [] + buttons.append(urwid.Button(_('Submit'),self.onFormSubmitted)) + if not 'NO_CANCEL' in self.options: + buttons.append(urwid.Button(_('Cancel'),self.onFormCancelled)) + max_len = max([len(button.get_label()) for button in buttons]) + grid_wid = urwid.GridFlow(buttons,max_len+4,1,0,'center') + list_box.body.append(grid_wid) + + + return list_box + + def show(self): + """Show the constructed UI""" + decorated = custom_widgets.LabelLine(self, custom_widgets.SurroundedText(self.title or '')) + self.host.showPopUp(decorated) + self.host.redraw() + + + ##EVENTS## + + def onButtonPress(self, button): + self.host.debug() + + def onFormSubmitted(self, button): + data = [] + for ctrl_name in self.ctrl_list: + ctrl = self.ctrl_list[ctrl_name] + if isinstance(ctrl['control'], custom_widgets.List): + data.append((ctrl_name, ctrl['control'].getSelectedValue())) + else: + data.append((ctrl_name, ctrl['control'].get_edit_text())) + if self.misc.has_key('action_back'): #FIXME FIXME FIXME: WTF ! Must be cleaned + raise NotImplementedError + self.host.debug() + elif self.misc.has_key('callback'): + self.misc['callback'](data) + else: + warning (_("The form data is not sent back, the type is not managed properly")) + self.host.removePopUp() + + def onFormCancelled(self, button): + self.host.removePopUp() diff -r 119f45746fde -r 80661755ea8d frontends/quick_frontend/quick_app.py --- a/frontends/quick_frontend/quick_app.py Thu Jul 22 22:47:29 2010 +0800 +++ b/frontends/quick_frontend/quick_app.py Mon Jul 26 19:43:44 2010 +0800 @@ -297,7 +297,7 @@ self.chat_wins[room_jid].getGame("Tarot").newGame(hand) def tarotChooseContrat(self, room_jid, xml_data, profile): - """Called when the player has too select his contrat""" + """Called when the player has to select his contrat""" if not self.check_profile(profile): return debug (_("Tarot: need to select a contrat")) diff -r 119f45746fde -r 80661755ea8d frontends/quick_frontend/quick_card_game.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/frontends/quick_frontend/quick_card_game.py Mon Jul 26 19:43:44 2010 +0800 @@ -0,0 +1,131 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +helper class for making a SAT frontend +Copyright (C) 2009, 2010 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 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +""" + +from logging import debug, info, error +from tools.jid import JID + + + +class QuickCardGame(): + + def __init__(self, parent, referee, players, player_nick): + self.parent = parent + self.referee = referee + self.players = players + self.played = {} + for player in players: + self.played[player] = None + self.player_nick = player_nick + self.bottom_nick = unicode(self.player_nick) + idx = self.players.index(self.player_nick) + idx = (idx + 1) % len(self.players) + self.right_nick = unicode(self.players[idx]) + idx = (idx + 1) % len(self.players) + self.top_nick = unicode(self.players[idx]) + idx = (idx + 1) % len(self.players) + self.left_nick = unicode(self.players[idx]) + self.bottom_nick = unicode(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 + + def loadCards(self): + """Load all the cards in memory + @param dir: directory where the PNG files are""" + 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 + + def newGame(self, hand): + """Start a new game, with given hand""" + assert (len(self.hand) == 0) + for suit, value in hand: + self.hand.append(self.cards[suit, value]) + self.hand.sort() + self.state = "init" + + def contratSelected(self, contrat): + """Called when the contrat has been choosed + @param data: form result""" + self.parent.host.bridge.tarotGameContratChoosed(self.player_nick, self.referee, contrat or 'Passe', self.parent.host.profile) + + def chooseContrat(self, xml_data): + """Called when the player as to select his contrat + @param xml_data: SàT xml representation of the form""" + raise NotImplementedError + + def showCards(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]) + if game_stage == "chien" and data['attaquant'] == self.player_nick: + self.state = "wait_for_ecart" + else: + self.state = "chien" + + def MyTurn(self): + """Called when we have to play :)""" + if self.state == "chien": + self.to_show = [] + self.state = "play" + + def showScores(self, xml_data, winners, loosers): + """Called when the player as to select hist contrat + @param xml_data: SàT xml representation of the form""" + raise NotImplementedError + + def cardsPlayed(self, player, cards): + """A card has been played by player""" + if self.to_show: + self.to_show = [] + pl_cards = [] + if self.played[player] != None: #gof: à supprimer + for pl in self.played: + self.played[pl] = None + for suit, value in cards: + pl_cards.append(self.cards[suit, value]) + self.played[player] = pl_cards[0] + + def invalidCards(self, phase, played_cards, invalid_cards): + """Invalid cards have been played + @param phase: phase of the game + @param played_cards: all the cards played + @param invalid_cards: cards which are invalid""" + + if phase == "play": + self.state = "play" + elif phase == "ecart": + self.state = "ecart" + else: + error ('INTERNAL ERROR: unmanaged game phase') + + for suit, value in played_cards: + self.hand.append(self.cards[suit, value]) + + self.hand.sort() + diff -r 119f45746fde -r 80661755ea8d frontends/quick_frontend/quick_chat.py --- a/frontends/quick_frontend/quick_chat.py Thu Jul 22 22:47:29 2010 +0800 +++ b/frontends/quick_frontend/quick_chat.py Mon Jul 26 19:43:44 2010 +0800 @@ -19,7 +19,7 @@ along with this program. If not, see . """ -from logging import debug, info, error +from logging import debug, info, warning, error from tools.jid import JID @@ -92,3 +92,12 @@ """Print message in chat window. Must be implemented by child class""" raise NotImplementedError + def startGame(self, game_type, referee, players): + """Configure the chat window to start a game""" + #No need to raise an error as game are not mandatory + warning(_('startGame is not implemented in this frontend')) + + def getGame(self, game_type): + """Return class managing the game type""" + #No need to raise an error as game are not mandatory + warning(_('getGame is not implemented in this frontend')) diff -r 119f45746fde -r 80661755ea8d frontends/wix/card_game.py --- a/frontends/wix/card_game.py Thu Jul 22 22:47:29 2010 +0800 +++ b/frontends/wix/card_game.py Mon Jul 26 19:43:44 2010 +0800 @@ -27,6 +27,7 @@ from logging import debug, info, error from tools.jid import JID from tools.games import TarotCard +from quick_frontend.quick_card_game import QuickCardGame from xmlui import XMLUI CARD_WIDTH = 74 @@ -34,16 +35,16 @@ MIN_WIDTH = 950 #Minimum size of the panel MIN_HEIGHT = 500 -class wxCard(TarotCard): +class WxCard(TarotCard): """This class is used to represent a card, graphically and logically""" def __init__(self, file): """@param file: path of the PNG file""" self.bitmap = wx.Image(file).ConvertToBitmap() root_name = os.path.splitext(os.path.basename(file))[0] - self.suit,self.value=root_name.split('_') - TarotCard.__init__(self, (self.suit, self.value)) - print "Carte:",self.suit, self.value #, self.bout + suit,value = root_name.split('_') + TarotCard.__init__(self, (suit, value)) + print "Carte:",suit, value #, self.bout def draw(self, dc, x, y): """Draw the card on the device context @@ -53,32 +54,15 @@ dc.DrawBitmap(self.bitmap, x, y, True) -class CardPanel(wx.Panel): +class CardPanel(QuickCardGame,wx.Panel): """This class is used to display the cards""" def __init__(self, parent, referee, players, player_nick): + QuickCardGame.__init__(self, parent, referee, players, player_nick) wx.Panel.__init__(self, parent) - self.parent = parent - 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.SetMinSize(wx.Size(MIN_WIDTH, MIN_HEIGHT)) - self.load_cards("/home/goffi/dev/divers/images/cards/") + self.loadCards("/home/goffi/dev/divers/images/cards/") self.mouse_over_card = None #contain the card to highlight - self.selected = [] #Card choosed by the player (e.g. during ecart) - self.hand_size = 13 #number of cards in a hand self.visible_size = CARD_WIDTH/2 #number of pixels visible for cards self.hand = [] self.to_show = [] @@ -90,33 +74,18 @@ self.Bind(wx.EVT_LEFT_UP, self.onMouseClick) self.parent.host.bridge.tarotGameReady(player_nick, referee, profile_key = self.parent.host.profile) - def load_cards(self, dir): + def loadCards(self, dir): """Load all the cards in memory @param dir: directory where the PNG files are""" - 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 + QuickCardGame.loadCards(self) for file in glob.glob(dir+'/*_*.png'): - card = wxCard(file) + card = WxCard(file) self.cards[card.suit, card.value]=card self.deck.append(card) - """for value in map(str,range(1,22))+['excuse']: - self.idx_cards.append(self.cards["atout",value]) - for suit in ["pique", "coeur", "carreau", "trefle"]: - for value in map(str,range(1,11))+["valet","cavalier","dame","roi"]: - self.idx_cards.append(self.cards[suit, value])""" #XXX: no need to sort the cards ! def newGame(self, hand): """Start a new game, with given hand""" - assert (len(self.hand) == 0) - for suit, value in hand: - self.hand.append(self.cards[suit, value]) - self.hand.sort() - self.state = "init" + QuickCardGame.newGame(self, hand) self._recalc_ori() self.Refresh() @@ -125,30 +94,14 @@ @param data: form result""" debug (_("Contrat choosed")) contrat = data[0][1] - self.parent.host.bridge.tarotGameContratChoosed(self.player_nick, self.referee, contrat or 'Passe', self.parent.host.profile) + QuickCardGame.contratSelected(self, contrat) def chooseContrat(self, xml_data): - """Called when the player as to select hist contrat + """Called when the player as to select his contrat @param xml_data: SàT xml representation of the form""" misc = {'callback': self.contratSelected} form = XMLUI(self.parent.host, xml_data, title = _('Please choose your contrat'), options = ['NO_CANCEL'], misc = misc) - def showCards(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]) - if game_stage == "chien" and data['attaquant'] == self.player_nick: - self.state = "wait_for_ecart" - else: - self.state = "chien" - - def MyTurn(self): - """Called when we have to play :)""" - if self.state == "chien": - self.to_show = [] - self.state = "play" - def showScores(self, xml_data, winners, loosers): """Called when the player as to select hist contrat @param xml_data: SàT xml representation of the form""" @@ -156,15 +109,7 @@ def cardsPlayed(self, player, cards): """A card has been played by player""" - if self.to_show: - self.to_show = [] - pl_cards = [] - if self.played[player] != None: #gof: à supprimer - for pl in self.played: - self.played[pl] = None - for suit, value in cards: - pl_cards.append(self.cards[suit, value]) - self.played[player] = pl_cards[0] + QuickCardGame.cardsPlayed(self, player, cards) self.Refresh() def invalidCards(self, phase, played_cards, invalid_cards): @@ -172,25 +117,12 @@ @param phase: phase of the game @param played_cards: all the cards played @param invalid_cards: cards which are invalid""" + QuickCardGame.invalidCards(self, phase, played_cards, invalid_cards) - if phase == "play": - self.state = "play" - elif phase == "ecart": - self.state = "ecart" - else: - error ('INTERNAL ERROR: unmanaged game phase') - - for suit, value in played_cards: - self.hand.append(self.cards[suit, value]) - self._recalc_ori() self.Refresh() - self.hand.sort() wx.MessageDialog(self, _("Cards played are invalid !"), _("Error"), wx.OK | wx.ICON_ERROR).ShowModal() - - - def _is_on_hand(self, pos_x, pos_y): """Return True if the coordinate are on the hand cards""" if pos_x > self.orig_x and pos_y > self.orig_y \