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
This commit is contained in:
parent
5ef7999fa7
commit
e597a804d9
7 changed files with 183 additions and 198 deletions
|
|
@ -25,7 +25,8 @@ from urwid_satext import sat_widgets
|
|||
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 @@ class Chat(PrimitivusWidget, QuickChat):
|
|||
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 @@ class Chat(PrimitivusWidget, QuickChat):
|
|||
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 @@ class Chat(PrimitivusWidget, QuickChat):
|
|||
|
||||
|
||||
quick_widgets.register(QuickChat, Chat)
|
||||
quick_widgets.register(quick_games.Tarot, game_tarot.TarotGame)
|
||||
|
|
|
|||
348
frontends/src/primitivus/game_tarot.py
Normal file
348
frontends/src/primitivus/game_tarot.py
Normal file
|
|
@ -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()
|
||||
|
|
@ -45,7 +45,6 @@ from os.path import join
|
|||
import signal
|
||||
|
||||
|
||||
|
||||
class EditBar(sat_widgets.ModalEdit):
|
||||
"""
|
||||
The modal edit bar where you would enter messages and commands.
|
||||
|
|
@ -676,7 +675,7 @@ class PrimitivusApp(QuickApp, InputHistory):
|
|||
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:
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ from sat.tools.misc import TriggerManager
|
|||
|
||||
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 @@ class QuickApp(object):
|
|||
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 @@ class QuickApp(object):
|
|||
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.
|
||||
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ class QuickChat(quick_widgets.QuickWidget):
|
|||
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 @@ class QuickChat(quick_widgets.QuickWidget):
|
|||
"""
|
||||
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 @@ class QuickChat(quick_widgets.QuickWidget):
|
|||
"""
|
||||
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)
|
||||
|
|
|
|||
158
frontends/src/quick_frontend/quick_game_tarot.py
Normal file
158
frontends/src/quick_frontend/quick_game_tarot.py
Normal file
|
|
@ -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()
|
||||
|
||||
106
frontends/src/quick_frontend/quick_games.py
Normal file
106
frontends/src/quick_frontend/quick_games.py
Normal file
|
|
@ -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")
|
||||
Loading…
Reference in a new issue