Mercurial > libervia-backend
changeset 1360:8ea8fa13c351 frontends_multi_profiles
frontends (quick_frontend, primitivus): fixes room games:
- add quick_frontend.quick_games for registering the signals and registering the UI classes
- rename the signals handlers to fit the convention (e.g.: tarotGameScoreHandler)
- rename card_game to game_tarot, quick_card_game to quick_game_tarot, CardGame to TarotGame
author | souliane <souliane@mailoo.org> |
---|---|
date | Wed, 11 Mar 2015 12:43:48 +0100 |
parents | 83127a4c89ce |
children | d3e9848b9574 |
files | frontends/src/primitivus/card_game.py frontends/src/primitivus/chat.py frontends/src/primitivus/game_tarot.py frontends/src/primitivus/primitivus frontends/src/quick_frontend/quick_app.py frontends/src/quick_frontend/quick_card_game.py frontends/src/quick_frontend/quick_chat.py frontends/src/quick_frontend/quick_game_tarot.py frontends/src/quick_frontend/quick_games.py |
diffstat | 9 files changed, 650 insertions(+), 665 deletions(-) [+] |
line wrap: on
line diff
--- a/frontends/src/primitivus/card_game.py Wed Mar 11 12:36:22 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,354 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Primitivus: a SAT frontend -# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 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/>. - -from sat.core.i18n import _ -import urwid -from urwid_satext import sat_widgets -from sat_frontends.tools.games import TarotCard -from sat_frontends.quick_frontend.quick_card_game import QuickCardGame -from sat_frontends.primitivus import xmlui -from sat_frontends.primitivus.keys import action_key_map as a_key - - -class CardDisplayer(urwid.Text): - """Show a card""" - signals = ['click'] - - def __init__(self, card): - self.__selected = False - self.card = card - urwid.Text.__init__(self, card.getAttrText()) - - def selectable(self): - return True - - def keypress(self, size, key): - if key == a_key['CARD_SELECT']: - self.select(not self.__selected) - self._emit('click') - return key - - def mouse_event(self, size, event, button, x, y, focus): - if urwid.is_mouse_event(event) and button == 1: - self.select(not self.__selected) - self._emit('click') - return True - - return False - - def select(self, state=True): - self.__selected = state - attr, txt = self.card.getAttrText() - if self.__selected: - attr += '_selected' - self.set_text((attr, txt)) - self._invalidate() - - def isSelected(self): - return self.__selected - - def getCard(self): - return self.card - - def render(self, size, focus=False): - canvas = urwid.CompositeCanvas(urwid.Text.render(self, size, focus)) - if focus: - canvas.set_cursor((0, 0)) - return canvas - - -class Hand(urwid.WidgetWrap): - """Used to display several cards, and manage a hand""" - signals = ['click'] - - def __init__(self, hand=[], selectable=False, on_click=None, user_data=None): - """@param hand: list of Card""" - self.__selectable = selectable - self.columns = urwid.Columns([], dividechars=1) - if on_click: - urwid.connect_signal(self, 'click', on_click, user_data) - if hand: - self.update(hand) - urwid.WidgetWrap.__init__(self, self.columns) - - def selectable(self): - return self.__selectable - - def keypress(self, size, key): - - if CardDisplayer in [wid.__class__ for wid in self.columns.widget_list]: - return self.columns.keypress(size, key) - else: - #No card displayed, we still have to manage the clicks - if key == a_key['CARD_SELECT']: - self._emit('click', None) - return key - - def getSelected(self): - """Return a list of selected cards""" - _selected = [] - for wid in self.columns.widget_list: - if isinstance(wid, CardDisplayer) and wid.isSelected(): - _selected.append(wid.getCard()) - return _selected - - def update(self, hand): - """Update the hand displayed in this widget - @param hand: list of Card""" - try: - del self.columns.widget_list[:] - del self.columns.column_types[:] - except IndexError: - pass - self.columns.contents.append((urwid.Text(''), ('weight', 1, False))) - for card in hand: - widget = CardDisplayer(card) - self.columns.widget_list.append(widget) - self.columns.column_types.append(('fixed', 3)) - urwid.connect_signal(widget, 'click', self.__onClick) - self.columns.contents.append((urwid.Text(''), ('weight', 1, False))) - self.columns.focus_position = 1 - - def __onClick(self, card_wid): - self._emit('click', card_wid) - - -class Card(TarotCard): - """This class is used to represent a card, logically - and give a text representation with attributes""" - SIZE = 3 # size of a displayed card - - 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)) - - def getWidget(self): - """Return a widget representing the card""" - return CardDisplayer(self) - - -class Table(urwid.FlowWidget): - """Represent the cards currently on the table""" - - def __init__(self): - self.top = self.left = self.bottom = self.right = None - - def putCard(self, location, card): - """Put a card on the table - @param location: where to put the card (top, left, bottom or right) - @param card: Card to play or None""" - assert location in ['top', 'left', 'bottom', 'right'] - assert isinstance(card, Card) or card == None - if [getattr(self, place) for place in ['top', 'left', 'bottom', 'right']].count(None) == 0: - #If the table is full of card, we remove them - self.top = self.left = self.bottom = self.right = None - setattr(self, location, card) - self._invalidate() - - def rows(self, size, focus=False): - return self.display_widget(size, focus).rows(size, focus) - - def render(self, size, focus=False): - return self.display_widget(size, focus).render(size, focus) - - def display_widget(self, size, focus): - cards = {} - max_col, = size - separator = " - " - margin = max((max_col - Card.SIZE) / 2, 0) * ' ' - margin_center = max((max_col - Card.SIZE * 2 - len(separator)) / 2, 0) * ' ' - for location in ['top', 'left', 'bottom', 'right']: - card = getattr(self, location) - cards[location] = card.getAttrText() if card else Card.SIZE * ' ' - render_wid = [urwid.Text([margin, cards['top']]), - urwid.Text([margin_center, cards['left'], separator, cards['right']]), - urwid.Text([margin, cards['bottom']])] - return urwid.Pile(render_wid) - - -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.parent.host.debug() - self.table = Table() - self.center = urwid.Columns([('fixed', len(self.left_nick), urwid.Filler(urwid.Text(self.left_nick))), - urwid.Filler(self.table), - ('fixed', len(self.right_nick), urwid.Filler(urwid.Text(self.right_nick))) - ]) - """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') - ])""" - self.hand_wid = Hand(selectable=True, on_click=self.onClick) - self.main_frame = urwid.Frame(self.center, header=self.top, footer=self.hand_wid, focus_part='footer') - urwid.WidgetWrap.__init__(self, self.main_frame) - self.parent.host.bridge.tarotGameReady(player_nick, referee, 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""" - if hand is []: # reset the display after the scores have been showed - self.resetRound() - for location in ['top', 'left', 'bottom', 'right']: - self.table.putCard(location, None) - self.parent.host.redraw() - self.parent.host.bridge.tarotGameReady(self.player_nick, self.referee, self.parent.host.profile) - return - 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 has to select his contrat - @param xml_data: SàT xml representation of the form""" - form = xmlui.create(self.parent.host, xml_data, title=_('Please choose your contrat'), flags=['NO_CANCEL']) - form.show(valign='top') - - def showCards(self, game_stage, cards, data): - """Display cards in the middle of the game (to show for e.g. chien ou poignée)""" - QuickCardGame.showCards(self, game_stage, cards, data) - self.center.widget_list[1] = urwid.Filler(Hand(self.to_show)) - self.parent.host.redraw() - - def myTurn(self): - QuickCardGame.myTurn(self) - - def showScores(self, xml_data, winners, loosers): - """Called when the round is over, display the scores - @param xml_data: SàT xml representation of the form""" - if not winners and not loosers: - title = _("Draw game") - else: - title = _('You win \o/') if self.player_nick in winners else _('You loose :(') - form = xmlui.create(self.parent.host, xml_data, title=title, flags=['NO_CANCEL']) - form.show() - - 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""" - QuickCardGame.invalidCards(self, phase, played_cards, invalid_cards) - self.hand_wid.update(self.hand) - if self._autoplay == None: # No dialog if there is autoplay - self.parent.host.notify(_('Cards played are invalid !')) - self.parent.host.redraw() - - def cardsPlayed(self, player, cards): - """A card has been played by player""" - QuickCardGame.cardsPlayed(self, player, cards) - self.table.putCard(self.getPlayerLocation(player), self.played[player]) - self._checkState() - self.parent.host.redraw() - - def _checkState(self): - if isinstance(self.center.widget_list[1].original_widget, Hand): # if we have a hand displayed - self.center.widget_list[1] = urwid.Filler(self.table) # we show again the table - if self.state == "chien": - self.to_show = [] - self.state = "wait" - elif self.state == "wait_for_ecart": - self.state = "ecart" - self.hand.extend(self.to_show) - self.hand.sort() - self.to_show = [] - self.hand_wid.update(self.hand) - - ##EVENTS## - def onClick(self, hand, card_wid): - """Called when user do an action on the hand""" - if not self.state in ['play', 'ecart', 'wait_for_ecart']: - #it's not our turn, we ignore the click - card_wid.select(False) - return - self._checkState() - if self.state == "ecart": - if len(self.hand_wid.getSelected()) == 6: - pop_up_widget = sat_widgets.ConfirmDialog(_("Do you put these cards in chien ?"), yes_cb=self.onEcartDone, no_cb=self.parent.host.removePopUp) - self.parent.host.showPopUp(pop_up_widget) - elif self.state == "play": - card = card_wid.getCard() - self.parent.host.bridge.tarotGamePlayCards(self.player_nick, self.referee, [(card.suit, card.value)], self.parent.host.profile) - self.hand.remove(card) - self.hand_wid.update(self.hand) - self.state = "wait" - - def onEcartDone(self, button): - """Called when player has finished his écart""" - ecart = [] - for card in self.hand_wid.getSelected(): - ecart.append((card.suit, card.value)) - self.hand.remove(card) - self.hand_wid.update(self.hand) - self.parent.host.bridge.tarotGamePlayCards(self.player_nick, self.referee, ecart, self.parent.host.profile) - self.state = "wait" - self.parent.host.removePopUp()
--- a/frontends/src/primitivus/chat.py Wed Mar 11 12:36:22 2015 +0100 +++ b/frontends/src/primitivus/chat.py Wed Mar 11 12:43:48 2015 +0100 @@ -25,7 +25,8 @@ from urwid_satext.files_management import FileDialog from sat_frontends.quick_frontend import quick_widgets from sat_frontends.quick_frontend.quick_chat import QuickChat -from sat_frontends.primitivus.card_game import CardGame +from sat_frontends.quick_frontend import quick_games +from sat_frontends.primitivus import game_tarot from sat_frontends.primitivus.constants import Const as C from sat_frontends.primitivus.keys import action_key_map as a_key from sat_frontends.primitivus.widget import PrimitivusWidget @@ -197,13 +198,21 @@ self.chat_colums.contents.remove((widget, options)) break - def _appendGamePanel(self, widget): + def addGamePanel(self, widget): + """Insert a game panel to this Chat dialog. + + @param widget (Widget): the game panel + """ assert (len(self.pile.contents) == 1) - self.pile.contents.insert(0,(widget,('weight', 1))) - self.pile.contents.insert(1,(urwid.Filler(urwid.Divider('-'),('fixed', 1)))) + self.pile.contents.insert(0, (widget, ('weight', 1))) + self.pile.contents.insert(1, (urwid.Filler(urwid.Divider('-'), ('fixed', 1)))) self.host.redraw() - def _removeGamePanel(self): + def removeGamePanel(self, widget): + """Remove the game panel from this Chat dialog. + + @param widget (Widget): the game panel + """ assert (len(self.pile.contents) == 3) del self.pile.contents[0] self.host.redraw() @@ -333,18 +342,6 @@ elif self.getUserNick().lower() in msg.lower(): self.host.x_notify.sendNotification(_("Primitivus: %(user)s mentioned you in room '%(room)s'") % {'user': from_jid, 'room': self.target}) - def startGame(self, game_type, referee, players): - """Configure the chat window to start a game""" - if game_type=="Tarot": - self.tarot_wid = CardGame(self, referee, players, self.nick) - self._appendGamePanel(self.tarot_wid) - - 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): # TODO: move this to plugin_misc_tarot with dynamic menu @@ -379,3 +376,4 @@ quick_widgets.register(QuickChat, Chat) +quick_widgets.register(quick_games.Tarot, game_tarot.TarotGame)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/frontends/src/primitivus/game_tarot.py Wed Mar 11 12:43:48 2015 +0100 @@ -0,0 +1,348 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Primitivus: a SAT frontend +# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 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/>. + +from sat.core.i18n import _ +import urwid +from urwid_satext import sat_widgets +from sat_frontends.tools.games import TarotCard +from sat_frontends.quick_frontend.quick_game_tarot import QuickTarotGame +from sat_frontends.primitivus import xmlui +from sat_frontends.primitivus.keys import action_key_map as a_key + + +class CardDisplayer(urwid.Text): + """Show a card""" + signals = ['click'] + + def __init__(self, card): + self.__selected = False + self.card = card + urwid.Text.__init__(self, card.getAttrText()) + + def selectable(self): + return True + + def keypress(self, size, key): + if key == a_key['CARD_SELECT']: + self.select(not self.__selected) + self._emit('click') + return key + + def mouse_event(self, size, event, button, x, y, focus): + if urwid.is_mouse_event(event) and button == 1: + self.select(not self.__selected) + self._emit('click') + return True + + return False + + def select(self, state=True): + self.__selected = state + attr, txt = self.card.getAttrText() + if self.__selected: + attr += '_selected' + self.set_text((attr, txt)) + self._invalidate() + + def isSelected(self): + return self.__selected + + def getCard(self): + return self.card + + def render(self, size, focus=False): + canvas = urwid.CompositeCanvas(urwid.Text.render(self, size, focus)) + if focus: + canvas.set_cursor((0, 0)) + return canvas + + +class Hand(urwid.WidgetWrap): + """Used to display several cards, and manage a hand""" + signals = ['click'] + + def __init__(self, hand=[], selectable=False, on_click=None, user_data=None): + """@param hand: list of Card""" + self.__selectable = selectable + self.columns = urwid.Columns([], dividechars=1) + if on_click: + urwid.connect_signal(self, 'click', on_click, user_data) + if hand: + self.update(hand) + urwid.WidgetWrap.__init__(self, self.columns) + + def selectable(self): + return self.__selectable + + def keypress(self, size, key): + + if CardDisplayer in [wid.__class__ for wid in self.columns.widget_list]: + return self.columns.keypress(size, key) + else: + #No card displayed, we still have to manage the clicks + if key == a_key['CARD_SELECT']: + self._emit('click', None) + return key + + def getSelected(self): + """Return a list of selected cards""" + _selected = [] + for wid in self.columns.widget_list: + if isinstance(wid, CardDisplayer) and wid.isSelected(): + _selected.append(wid.getCard()) + return _selected + + def update(self, hand): + """Update the hand displayed in this widget + @param hand: list of Card""" + try: + del self.columns.widget_list[:] + del self.columns.column_types[:] + except IndexError: + pass + self.columns.contents.append((urwid.Text(''), ('weight', 1, False))) + for card in hand: + widget = CardDisplayer(card) + self.columns.widget_list.append(widget) + self.columns.column_types.append(('fixed', 3)) + urwid.connect_signal(widget, 'click', self.__onClick) + self.columns.contents.append((urwid.Text(''), ('weight', 1, False))) + self.columns.focus_position = 1 + + def __onClick(self, card_wid): + self._emit('click', card_wid) + + +class Card(TarotCard): + """This class is used to represent a card, logically + and give a text representation with attributes""" + SIZE = 3 # size of a displayed card + + 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)) + + def getWidget(self): + """Return a widget representing the card""" + return CardDisplayer(self) + + +class Table(urwid.FlowWidget): + """Represent the cards currently on the table""" + + def __init__(self): + self.top = self.left = self.bottom = self.right = None + + def putCard(self, location, card): + """Put a card on the table + @param location: where to put the card (top, left, bottom or right) + @param card: Card to play or None""" + assert location in ['top', 'left', 'bottom', 'right'] + assert isinstance(card, Card) or card == None + if [getattr(self, place) for place in ['top', 'left', 'bottom', 'right']].count(None) == 0: + #If the table is full of card, we remove them + self.top = self.left = self.bottom = self.right = None + setattr(self, location, card) + self._invalidate() + + def rows(self, size, focus=False): + return self.display_widget(size, focus).rows(size, focus) + + def render(self, size, focus=False): + return self.display_widget(size, focus).render(size, focus) + + def display_widget(self, size, focus): + cards = {} + max_col, = size + separator = " - " + margin = max((max_col - Card.SIZE) / 2, 0) * ' ' + margin_center = max((max_col - Card.SIZE * 2 - len(separator)) / 2, 0) * ' ' + for location in ['top', 'left', 'bottom', 'right']: + card = getattr(self, location) + cards[location] = card.getAttrText() if card else Card.SIZE * ' ' + render_wid = [urwid.Text([margin, cards['top']]), + urwid.Text([margin_center, cards['left'], separator, cards['right']]), + urwid.Text([margin, cards['bottom']])] + return urwid.Pile(render_wid) + + +class TarotGame(QuickTarotGame, urwid.WidgetWrap): + """Widget for card games""" + + def __init__(self, parent, referee, players): + QuickTarotGame.__init__(self, parent, referee, players) + self.loadCards() + self.top = urwid.Pile([urwid.Padding(urwid.Text(self.top_nick), 'center')]) + #self.parent.host.debug() + self.table = Table() + self.center = urwid.Columns([('fixed', len(self.left_nick), urwid.Filler(urwid.Text(self.left_nick))), + urwid.Filler(self.table), + ('fixed', len(self.right_nick), urwid.Filler(urwid.Text(self.right_nick))) + ]) + """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') + ])""" + self.hand_wid = Hand(selectable=True, on_click=self.onClick) + self.main_frame = urwid.Frame(self.center, header=self.top, footer=self.hand_wid, focus_part='footer') + urwid.WidgetWrap.__init__(self, self.main_frame) + self.parent.host.bridge.tarotGameReady(self.player_nick, referee, self.parent.profile) + + def loadCards(self): + """Load all the cards in memory""" + QuickTarotGame.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 tarotGameNewHandler(self, hand): + """Start a new game, with given hand""" + if hand is []: # reset the display after the scores have been showed + self.resetRound() + for location in ['top', 'left', 'bottom', 'right']: + self.table.putCard(location, None) + self.parent.host.redraw() + self.parent.host.bridge.tarotGameReady(self.player_nick, self.referee, self.parent.profile) + return + QuickTarotGame.tarotGameNewHandler(self, hand) + self.hand_wid.update(self.hand) + self.parent.host.redraw() + + def tarotGameChooseContratHandler(self, xml_data): + """Called when the player has to select his contrat + @param xml_data: SàT xml representation of the form""" + form = xmlui.create(self.parent.host, xml_data, title=_('Please choose your contrat'), flags=['NO_CANCEL'], profile=self.parent.profile) + form.show(valign='top') + + def tarotGameShowCardsHandler(self, game_stage, cards, data): + """Display cards in the middle of the game (to show for e.g. chien ou poignée)""" + QuickTarotGame.tarotGameShowCardsHandler(self, game_stage, cards, data) + self.center.widget_list[1] = urwid.Filler(Hand(self.to_show)) + self.parent.host.redraw() + + def tarotGameYourTurnHandler(self): + QuickTarotGame.tarotGameYourTurnHandler(self) + + def tarotGameScoreHandler(self, xml_data, winners, loosers): + """Called when the round is over, display the scores + @param xml_data: SàT xml representation of the form""" + if not winners and not loosers: + title = _("Draw game") + else: + title = _('You win \o/') if self.player_nick in winners else _('You loose :(') + form = xmlui.create(self.parent.host, xml_data, title=title, flags=['NO_CANCEL'], profile=self.parent.profile) + form.show() + + def tarotGameInvalidCardsHandler(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""" + QuickTarotGame.tarotGameInvalidCardsHandler(self, phase, played_cards, invalid_cards) + self.hand_wid.update(self.hand) + if self._autoplay == None: # No dialog if there is autoplay + self.parent.host.notify(_('Cards played are invalid !')) + self.parent.host.redraw() + + def tarotGameCardsPlayedHandler(self, player, cards): + """A card has been played by player""" + QuickTarotGame.tarotGameCardsPlayedHandler(self, player, cards) + self.table.putCard(self.getPlayerLocation(player), self.played[player]) + self._checkState() + self.parent.host.redraw() + + def _checkState(self): + if isinstance(self.center.widget_list[1].original_widget, Hand): # if we have a hand displayed + self.center.widget_list[1] = urwid.Filler(self.table) # we show again the table + if self.state == "chien": + self.to_show = [] + self.state = "wait" + elif self.state == "wait_for_ecart": + self.state = "ecart" + self.hand.extend(self.to_show) + self.hand.sort() + self.to_show = [] + self.hand_wid.update(self.hand) + + ##EVENTS## + def onClick(self, hand, card_wid): + """Called when user do an action on the hand""" + if not self.state in ['play', 'ecart', 'wait_for_ecart']: + #it's not our turn, we ignore the click + card_wid.select(False) + return + self._checkState() + if self.state == "ecart": + if len(self.hand_wid.getSelected()) == 6: + pop_up_widget = sat_widgets.ConfirmDialog(_("Do you put these cards in chien ?"), yes_cb=self.onEcartDone, no_cb=self.parent.host.removePopUp) + self.parent.host.showPopUp(pop_up_widget) + elif self.state == "play": + card = card_wid.getCard() + self.parent.host.bridge.tarotGamePlayCards(self.player_nick, self.referee, [(card.suit, card.value)], self.parent.profile) + self.hand.remove(card) + self.hand_wid.update(self.hand) + self.state = "wait" + + def onEcartDone(self, button): + """Called when player has finished his écart""" + ecart = [] + for card in self.hand_wid.getSelected(): + ecart.append((card.suit, card.value)) + self.hand.remove(card) + self.hand_wid.update(self.hand) + self.parent.host.bridge.tarotGamePlayCards(self.player_nick, self.referee, ecart, self.parent.profile) + self.state = "wait" + self.parent.host.removePopUp()
--- a/frontends/src/primitivus/primitivus Wed Mar 11 12:36:22 2015 +0100 +++ b/frontends/src/primitivus/primitivus Wed Mar 11 12:43:48 2015 +0100 @@ -45,7 +45,6 @@ import signal - class EditBar(sat_widgets.ModalEdit): """ The modal edit bar where you would enter messages and commands. @@ -676,7 +675,7 @@ title = _('Registration') misc['target'] = data['target'] misc['action_back'] = self.bridge.gatewayRegister - ui = xmlui.create(self, title=title, xml_data = data['xml'], misc = misc) + ui = xmlui.create(self, title=title, xml_data=data['xml'], misc=misc, profile=profile) if data['type'] == 'registration': ui.show('popup') else:
--- a/frontends/src/quick_frontend/quick_app.py Wed Mar 11 12:36:22 2015 +0100 +++ b/frontends/src/quick_frontend/quick_app.py Wed Mar 11 12:43:48 2015 +0100 @@ -26,7 +26,7 @@ from sat_frontends.tools import jid from sat_frontends.quick_frontend.quick_widgets import QuickWidgetsManager -from sat_frontends.quick_frontend import quick_chat +from sat_frontends.quick_frontend import quick_chat, quick_games from sat_frontends.quick_frontend.constants import Const as C import sys @@ -252,25 +252,14 @@ self.registerSignal("roomUserLeft", iface="plugin") self.registerSignal("roomUserChangedNick", iface="plugin") self.registerSignal("roomNewSubject", iface="plugin") - self.registerSignal("tarotGameStarted", iface="plugin") - self.registerSignal("tarotGameNew", iface="plugin") - self.registerSignal("tarotGameChooseContrat", iface="plugin") - self.registerSignal("tarotGameShowCards", iface="plugin") - self.registerSignal("tarotGameYourTurn", iface="plugin") - self.registerSignal("tarotGameScore", iface="plugin") - self.registerSignal("tarotGameCardsPlayed", iface="plugin") - self.registerSignal("tarotGameInvalidCards", iface="plugin") - self.registerSignal("quizGameStarted", iface="plugin") - self.registerSignal("quizGameNew", iface="plugin") - self.registerSignal("quizGameQuestion", iface="plugin") - self.registerSignal("quizGamePlayerBuzzed", iface="plugin") - self.registerSignal("quizGamePlayerSays", iface="plugin") - self.registerSignal("quizGameAnswerResult", iface="plugin") - self.registerSignal("quizGameTimerExpired", iface="plugin") - self.registerSignal("quizGameTimerRestarted", iface="plugin") self.registerSignal("chatStateReceived", iface="plugin") self.registerSignal("personalEvent", iface="plugin") + # FIXME: do it dynamically + quick_games.Tarot.registerSignals(self) + quick_games.Quiz.registerSignals(self) + quick_games.Radiocol.registerSignals(self) + self.current_action_ids = set() # FIXME: to be removed self.current_action_ids_cb = {} # FIXME: to be removed self.media_dir = self.bridge.getConfig('', 'media_dir') @@ -576,107 +565,6 @@ chat_widget.setSubject(subject) log.debug("new subject for room [%(room_jid)s]: %(subject)s" % {'room_jid': room_jid, "subject": subject}) - def tarotGameStartedHandler(self, room_jid_s, referee, players, profile): - log.debug(_("Tarot Game Started \o/")) - room_jid = jid.JID(room_jid_s) - chat_widget = self.widgets.getOrCreateWidget(quick_chat.QuickChat, room_jid, type_=C.CHAT_GROUP, profile=profile) - chat_widget.startGame("Tarot", referee, players) - log.debug("new Tarot game started by [%(referee)s] in room [%(room_jid)s] with %(players)s" % {'referee': referee, 'room_jid': room_jid, 'players': [str(player) for player in players]}) - - def tarotGameNewHandler(self, room_jid_s, hand, profile): - log.debug(_("New Tarot Game")) - chat_widget = self.widgets.getWidget(quick_chat.QuickChat, jid.JID(room_jid_s), profile) - if chat_widget: - chat_widget.getGame("Tarot").newGame(hand) - - def tarotGameChooseContratHandler(self, room_jid_s, xml_data, profile): - """Called when the player has to select his contrat""" - log.debug(_("Tarot: need to select a contrat")) - chat_widget = self.widgets.getWidget(quick_chat.QuickChat, jid.JID(room_jid_s), profile) - if chat_widget: - chat_widget.getGame("Tarot").chooseContrat(xml_data) - - def tarotGameShowCardsHandler(self, room_jid_s, game_stage, cards, data, profile): - log.debug(_("Show cards")) - chat_widget = self.widgets.getWidget(quick_chat.QuickChat, jid.JID(room_jid_s), profile) - if chat_widget: - chat_widget.getGame("Tarot").showCards(game_stage, cards, data) - - def tarotGameYourTurnHandler(self, room_jid_s, profile): - log.debug(_("My turn to play")) - chat_widget = self.widgets.getWidget(quick_chat.QuickChat, jid.JID(room_jid_s), profile) - if chat_widget: - chat_widget.getGame("Tarot").myTurn() - - def tarotGameScoreHandler(self, room_jid_s, xml_data, winners, loosers, profile): - """Called when the game is finished and the score are updated""" - log.debug(_("Tarot: score received")) - chat_widget = self.widgets.getWidget(quick_chat.QuickChat, jid.JID(room_jid_s), profile) - if chat_widget: - chat_widget.getGame("Tarot").showScores(xml_data, winners, loosers) - - def tarotGameCardsPlayedHandler(self, room_jid_s, player, cards, profile): - log.debug(_("Card(s) played (%(player)s): %(cards)s") % {"player": player, "cards": cards}) - chat_widget = self.widgets.getWidget(quick_chat.QuickChat, jid.JID(room_jid_s), profile) - if chat_widget: - chat_widget.getGame("Tarot").cardsPlayed(player, cards) - - def tarotGameInvalidCardsHandler(self, room_jid_s, phase, played_cards, invalid_cards, profile): - log.debug(_("Cards played are not valid: %s") % invalid_cards) - chat_widget = self.widgets.getWidget(quick_chat.QuickChat, jid.JID(room_jid_s), profile) - if chat_widget: - chat_widget.getGame("Tarot").invalidCards(phase, played_cards, invalid_cards) - - def quizGameStartedHandler(self, room_jid_s, referee, players, profile): - log.debug(_("Quiz Game Started \o/")) - chat_widget = self.widgets.getWidget(quick_chat.QuickChat, jid.JID(room_jid_s), profile) - if chat_widget: - chat_widget.startGame("Quiz", referee, players) - log.debug(_("new Quiz game started by [%(referee)s] in room [%(room_jid)s] with %(players)s") % {'referee': referee, 'room_jid': room_jid_s, 'players': [str(player) for player in players]}) - - def quizGameNewHandler(self, room_jid_s, data, profile): - log.debug(_("New Quiz Game")) - chat_widget = self.widgets.getWidget(quick_chat.QuickChat, jid.JID(room_jid_s), profile) - if chat_widget: - chat_widget.getGame("Quiz").quizGameNewHandler(data) - - def quizGameQuestionHandler(self, room_jid_s, question_id, question, timer, profile): - """Called when a new question is asked""" - log.debug(_(u"Quiz: new question: %s") % question) - chat_widget = self.widgets.getWidget(quick_chat.QuickChat, jid.JID(room_jid_s), profile) - if chat_widget: - chat_widget.getGame("Quiz").quizGameQuestionHandler(question_id, question, timer) - - def quizGamePlayerBuzzedHandler(self, room_jid_s, player, pause, profile): - """Called when a player pushed the buzzer""" - chat_widget = self.widgets.getWidget(quick_chat.QuickChat, jid.JID(room_jid_s), profile) - if chat_widget: - chat_widget.getGame("Quiz").quizGamePlayerBuzzedHandler(player, pause) - - def quizGamePlayerSaysHandler(self, room_jid_s, player, text, delay, profile): - """Called when a player say something""" - chat_widget = self.widgets.getWidget(quick_chat.QuickChat, jid.JID(room_jid_s), profile) - if chat_widget: - chat_widget.getGame("Quiz").quizGamePlayerSaysHandler(player, text, delay) - - def quizGameAnswerResultHandler(self, room_jid_s, player, good_answer, score, profile): - """Called when a player say something""" - chat_widget = self.widgets.getWidget(quick_chat.QuickChat, jid.JID(room_jid_s), profile) - if chat_widget: - chat_widget.getGame("Quiz").quizGameAnswerResultHandler(player, good_answer, score) - - def quizGameTimerExpiredHandler(self, room_jid_s, profile): - """Called when nobody answered the question in time""" - chat_widget = self.widgets.getWidget(quick_chat.QuickChat, jid.JID(room_jid_s), profile) - if chat_widget: - chat_widget.getGame("Quiz").quizGameTimerExpiredHandler() - - def quizGameTimerRestartedHandler(self, room_jid_s, time_left, profile): - """Called when the question is not answered, and we still have time""" - chat_widget = self.widgets.getWidget(quick_chat.QuickChat, jid.JID(room_jid_s), profile) - if chat_widget: - chat_widget.getGame("Quiz").quizGameTimerRestartedHandler(time_left) - def chatStateReceivedHandler(self, from_jid_s, state, profile): """Called when a new chat state is received.
--- a/frontends/src/quick_frontend/quick_card_game.py Wed Mar 11 12:36:22 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,164 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# helper class for making a SAT frontend -# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 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/>. - -from sat.core.log import getLogger -log = getLogger(__name__) -from sat_frontends.tools.jid import JID - - - -class QuickCardGame(object): - - def __init__(self, parent, referee, players, player_nick): - self._autoplay = None #XXX: use 0 to activate fake play, None else - 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 resetRound(self): - """Reset the game's variables to be reatty to start the next round""" - del self.selected[:] - del self.hand[:] - del self.to_show[:] - self.state = None - for pl in self.played: - self.played[pl] = None - - def getPlayerLocation(self, nick): - """return player location (top,bottom,left or right)""" - for location in ['top','left','bottom','right']: - if getattr(self,'%s_nick' % location) == nick: - return location - assert(False) - - 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" - self.__fakePlay() - - def __fakePlay(self): - """Convenience method for stupid autoplay - /!\ don't forgot to comment any interactive dialog for invalid card""" - if self._autoplay == None: - return - if self._autoplay >= len(self.hand): - self._autoplay = 0 - card = self.hand[self._autoplay] - self.parent.host.bridge.tarotGamePlayCards(self.player_nick, self.referee, [(card.suit, card.value)], self.parent.host.profile) - del self.hand[self._autoplay] - self.state = "wait" - self._autoplay+=1 - - def showScores(self, xml_data, winners, loosers): - """Called at the end of a game - @param xml_data: SàT xml representation of the scores - @param winners: list of winners' nicks - @param loosers: list of loosers' nicks""" - 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: #FIXME - 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: - log.error ('INTERNAL ERROR: unmanaged game phase') - - for suit, value in played_cards: - self.hand.append(self.cards[suit, value]) - - self.hand.sort() - self.__fakePlay() -
--- a/frontends/src/quick_frontend/quick_chat.py Wed Mar 11 12:36:22 2015 +0100 +++ b/frontends/src/quick_frontend/quick_chat.py Wed Mar 11 12:43:48 2015 +0100 @@ -48,6 +48,7 @@ self.id = "" # FIXME: to be removed self.nick = None self.occupants = set() + self.games = {} def __str__(self): return u"Chat Widget [target: {}, type: {}, profile: {}]".format(self.target, self.type, self.profile) @@ -227,16 +228,6 @@ """ 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 - log.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 - log.warning(_('getGame is not implemented in this frontend')) - def updateChatState(self, from_jid, state): """Set the chat state (XEP-0085) of the contact. @@ -244,4 +235,19 @@ """ raise NotImplementedError + def addGamePanel(self, widget): + """Insert a game panel to this Chat dialog. + + @param widget (Widget): the game panel + """ + raise NotImplementedError + + def removeGamePanel(self, widget): + """Remove the game panel from this Chat dialog. + + @param widget (Widget): the game panel + """ + raise NotImplementedError + + quick_widgets.register(QuickChat)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/frontends/src/quick_frontend/quick_game_tarot.py Wed Mar 11 12:43:48 2015 +0100 @@ -0,0 +1,158 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# helper class for making a SAT frontend +# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 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/>. + +from sat.core.log import getLogger +log = getLogger(__name__) +from sat_frontends.tools.jid import JID + + +class QuickTarotGame(object): + + def __init__(self, parent, referee, players): + self._autoplay = None #XXX: use 0 to activate fake play, None else + self.parent = parent + self.referee = referee + self.players = players + self.played = {} + for player in players: + self.played[player] = None + self.player_nick = parent.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(self.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 resetRound(self): + """Reset the game's variables to be reatty to start the next round""" + del self.selected[:] + del self.hand[:] + del self.to_show[:] + self.state = None + for pl in self.played: + self.played[pl] = None + + def getPlayerLocation(self, nick): + """return player location (top,bottom,left or right)""" + for location in ['top','left','bottom','right']: + if getattr(self,'%s_nick' % location) == nick: + return location + assert(False) + + 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 tarotGameNewHandler(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 tarotGameChooseContratHandler(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 tarotGameShowCardsHandler(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 tarotGameYourTurnHandler(self): + """Called when we have to play :)""" + if self.state == "chien": + self.to_show = [] + self.state = "play" + self.__fakePlay() + + def __fakePlay(self): + """Convenience method for stupid autoplay + /!\ don't forgot to comment any interactive dialog for invalid card""" + if self._autoplay == None: + return + if self._autoplay >= len(self.hand): + self._autoplay = 0 + card = self.hand[self._autoplay] + self.parent.host.bridge.tarotGamePlayCards(self.player_nick, self.referee, [(card.suit, card.value)], self.parent.profile) + del self.hand[self._autoplay] + self.state = "wait" + self._autoplay+=1 + + def tarotGameScoreHandler(self, xml_data, winners, loosers): + """Called at the end of a game + @param xml_data: SàT xml representation of the scores + @param winners: list of winners' nicks + @param loosers: list of loosers' nicks""" + raise NotImplementedError + + def tarotGameCardsPlayedHandler(self, player, cards): + """A card has been played by player""" + if self.to_show: + self.to_show = [] + pl_cards = [] + if self.played[player] != None: #FIXME + 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 tarotGameInvalidCardsHandler(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: + log.error ('INTERNAL ERROR: unmanaged game phase') + + for suit, value in played_cards: + self.hand.append(self.cards[suit, value]) + + self.hand.sort() + self.__fakePlay() +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/frontends/src/quick_frontend/quick_games.py Wed Mar 11 12:43:48 2015 +0100 @@ -0,0 +1,106 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# helper class for making a SAT frontend +# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 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/>. + +from sat.core.log import getLogger +log = getLogger(__name__) + +from sat.core.i18n import _ + +from sat_frontends.tools import jid +from sat_frontends.quick_frontend.constants import Const as C + +import quick_chat + + +class RoomGame(object): + _game_name = None + _signal_prefix = None + _signal_suffixes = None + + @classmethod + def registerSignals(cls, host): + + def make_handler(suffix, signal): + def handler(*args): + if suffix in ("Started", "Players"): + return cls.startedHandler(host, suffix, *args) + return cls.genericHandler(host, signal, *args) + return handler + + for suffix in cls._signal_suffixes: + signal = cls._signal_prefix + suffix + host.registerSignal(signal, handler=make_handler(suffix, signal), iface="plugin") + + @classmethod + def startedHandler(cls, host, suffix, *args): + room_jid, args, profile = jid.JID(args[0]), args[1:-1], args[-1] + referee, players, args = args[0], args[1], args[2:] + chat_widget = host.widgets.getOrCreateWidget(quick_chat.QuickChat, room_jid, type_=C.CHAT_GROUP, profile=profile) + + # self.occupants_panel.updateSpecials(players, SYMBOLS[self._game_name.lower()]) # FIXME + if suffix == "Players" or chat_widget.nick not in players: + return # waiting for other players to join, or not playing + if cls._game_name in chat_widget.games: + return # game panel is already there + real_class = host.widgets.getRealClass(cls) + if real_class == cls: + host.showDialog(_(u"A {game} activity between {players} has been started, but you couldn't take part because your client doesn't support it.").format(game=cls._game_name, players=', '.join(players)), + _(u"{game} Game").format(game=cls._game_name)) + return + panel = real_class(chat_widget, referee, players, *args) + chat_widget.games[cls._game_name] = panel + chat_widget.addGamePanel(panel) + + @classmethod + def genericHandler(cls, host, signal, *args): + room_jid, args, profile = jid.JID(args[0]), args[1:-1], args[-1] + chat_widget = host.widgets.getWidget(quick_chat.QuickChat, room_jid, profile) + if chat_widget: + try: + game_panel = chat_widget.games[cls._game_name] + except KeyError: + log.error("TODO: better game synchronisation - received signal %s but no panel is found" % signal) + return + else: + getattr(game_panel, "%sHandler" % signal)(*args) + + +class Tarot(RoomGame): + _game_name = "Tarot" + _signal_prefix = "tarotGame" + _signal_suffixes = ("Started", "Players", "New", "ChooseContrat", + "ShowCards", "YourTurn", "Score", "CardsPlayed", + "InvalidCards", + ) + + +class Quiz(RoomGame): + _game_name = "Quiz" + _signal_prefix = "quizGame" + _signal_suffixes = ("Started", "New", "Question", "PlayerBuzzed", + "PlayerSays", "AnswerResult", "TimerExpired", + "TimerRestarted", + ) + + +class Radiocol(RoomGame): + _game_name = "Radiocol" + _signal_prefix = "radiocol" + _signal_suffixes = ("Started", "Players", "SongRejected", "Preload", + "Play", "NoUpload", "UploadOk")