comparison frontends/src/primitivus/game_tarot.py @ 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 frontends/src/primitivus/card_game.py@c0f15e52695a
children 069ad98b360d
comparison
equal deleted inserted replaced
1359:83127a4c89ce 1360:8ea8fa13c351
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3
4 # Primitivus: a SAT frontend
5 # Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Jérôme Poisson (goffi@goffi.org)
6
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
11
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Affero General Public License for more details.
16
17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20 from sat.core.i18n import _
21 import urwid
22 from urwid_satext import sat_widgets
23 from sat_frontends.tools.games import TarotCard
24 from sat_frontends.quick_frontend.quick_game_tarot import QuickTarotGame
25 from sat_frontends.primitivus import xmlui
26 from sat_frontends.primitivus.keys import action_key_map as a_key
27
28
29 class CardDisplayer(urwid.Text):
30 """Show a card"""
31 signals = ['click']
32
33 def __init__(self, card):
34 self.__selected = False
35 self.card = card
36 urwid.Text.__init__(self, card.getAttrText())
37
38 def selectable(self):
39 return True
40
41 def keypress(self, size, key):
42 if key == a_key['CARD_SELECT']:
43 self.select(not self.__selected)
44 self._emit('click')
45 return key
46
47 def mouse_event(self, size, event, button, x, y, focus):
48 if urwid.is_mouse_event(event) and button == 1:
49 self.select(not self.__selected)
50 self._emit('click')
51 return True
52
53 return False
54
55 def select(self, state=True):
56 self.__selected = state
57 attr, txt = self.card.getAttrText()
58 if self.__selected:
59 attr += '_selected'
60 self.set_text((attr, txt))
61 self._invalidate()
62
63 def isSelected(self):
64 return self.__selected
65
66 def getCard(self):
67 return self.card
68
69 def render(self, size, focus=False):
70 canvas = urwid.CompositeCanvas(urwid.Text.render(self, size, focus))
71 if focus:
72 canvas.set_cursor((0, 0))
73 return canvas
74
75
76 class Hand(urwid.WidgetWrap):
77 """Used to display several cards, and manage a hand"""
78 signals = ['click']
79
80 def __init__(self, hand=[], selectable=False, on_click=None, user_data=None):
81 """@param hand: list of Card"""
82 self.__selectable = selectable
83 self.columns = urwid.Columns([], dividechars=1)
84 if on_click:
85 urwid.connect_signal(self, 'click', on_click, user_data)
86 if hand:
87 self.update(hand)
88 urwid.WidgetWrap.__init__(self, self.columns)
89
90 def selectable(self):
91 return self.__selectable
92
93 def keypress(self, size, key):
94
95 if CardDisplayer in [wid.__class__ for wid in self.columns.widget_list]:
96 return self.columns.keypress(size, key)
97 else:
98 #No card displayed, we still have to manage the clicks
99 if key == a_key['CARD_SELECT']:
100 self._emit('click', None)
101 return key
102
103 def getSelected(self):
104 """Return a list of selected cards"""
105 _selected = []
106 for wid in self.columns.widget_list:
107 if isinstance(wid, CardDisplayer) and wid.isSelected():
108 _selected.append(wid.getCard())
109 return _selected
110
111 def update(self, hand):
112 """Update the hand displayed in this widget
113 @param hand: list of Card"""
114 try:
115 del self.columns.widget_list[:]
116 del self.columns.column_types[:]
117 except IndexError:
118 pass
119 self.columns.contents.append((urwid.Text(''), ('weight', 1, False)))
120 for card in hand:
121 widget = CardDisplayer(card)
122 self.columns.widget_list.append(widget)
123 self.columns.column_types.append(('fixed', 3))
124 urwid.connect_signal(widget, 'click', self.__onClick)
125 self.columns.contents.append((urwid.Text(''), ('weight', 1, False)))
126 self.columns.focus_position = 1
127
128 def __onClick(self, card_wid):
129 self._emit('click', card_wid)
130
131
132 class Card(TarotCard):
133 """This class is used to represent a card, logically
134 and give a text representation with attributes"""
135 SIZE = 3 # size of a displayed card
136
137 def __init__(self, suit, value):
138 """@param file: path of the PNG file"""
139 TarotCard.__init__(self, (suit, value))
140
141 def getAttrText(self):
142 """return text representation of the card with attributes"""
143 try:
144 value = "%02i" % int(self.value)
145 except ValueError:
146 value = self.value[0].upper() + self.value[1]
147 if self.suit == "atout":
148 if self.value == "excuse":
149 suit = 'c'
150 else:
151 suit = 'A'
152 color = 'neutral'
153 elif self.suit == "pique":
154 suit = u'♠'
155 color = 'black'
156 elif self.suit == "trefle":
157 suit = u'♣'
158 color = 'black'
159 elif self.suit == "coeur":
160 suit = u'♥'
161 color = 'red'
162 elif self.suit == "carreau":
163 suit = u'♦'
164 color = 'red'
165 if self.bout:
166 color = 'special'
167 return ('card_%s' % color, u"%s%s" % (value, suit))
168
169 def getWidget(self):
170 """Return a widget representing the card"""
171 return CardDisplayer(self)
172
173
174 class Table(urwid.FlowWidget):
175 """Represent the cards currently on the table"""
176
177 def __init__(self):
178 self.top = self.left = self.bottom = self.right = None
179
180 def putCard(self, location, card):
181 """Put a card on the table
182 @param location: where to put the card (top, left, bottom or right)
183 @param card: Card to play or None"""
184 assert location in ['top', 'left', 'bottom', 'right']
185 assert isinstance(card, Card) or card == None
186 if [getattr(self, place) for place in ['top', 'left', 'bottom', 'right']].count(None) == 0:
187 #If the table is full of card, we remove them
188 self.top = self.left = self.bottom = self.right = None
189 setattr(self, location, card)
190 self._invalidate()
191
192 def rows(self, size, focus=False):
193 return self.display_widget(size, focus).rows(size, focus)
194
195 def render(self, size, focus=False):
196 return self.display_widget(size, focus).render(size, focus)
197
198 def display_widget(self, size, focus):
199 cards = {}
200 max_col, = size
201 separator = " - "
202 margin = max((max_col - Card.SIZE) / 2, 0) * ' '
203 margin_center = max((max_col - Card.SIZE * 2 - len(separator)) / 2, 0) * ' '
204 for location in ['top', 'left', 'bottom', 'right']:
205 card = getattr(self, location)
206 cards[location] = card.getAttrText() if card else Card.SIZE * ' '
207 render_wid = [urwid.Text([margin, cards['top']]),
208 urwid.Text([margin_center, cards['left'], separator, cards['right']]),
209 urwid.Text([margin, cards['bottom']])]
210 return urwid.Pile(render_wid)
211
212
213 class TarotGame(QuickTarotGame, urwid.WidgetWrap):
214 """Widget for card games"""
215
216 def __init__(self, parent, referee, players):
217 QuickTarotGame.__init__(self, parent, referee, players)
218 self.loadCards()
219 self.top = urwid.Pile([urwid.Padding(urwid.Text(self.top_nick), 'center')])
220 #self.parent.host.debug()
221 self.table = Table()
222 self.center = urwid.Columns([('fixed', len(self.left_nick), urwid.Filler(urwid.Text(self.left_nick))),
223 urwid.Filler(self.table),
224 ('fixed', len(self.right_nick), urwid.Filler(urwid.Text(self.right_nick)))
225 ])
226 """urwid.Pile([urwid.Padding(self.top_card_wid,'center'),
227 urwid.Columns([('fixed',len(self.left_nick),urwid.Text(self.left_nick)),
228 urwid.Padding(self.center_cards_wid,'center'),
229 ('fixed',len(self.right_nick),urwid.Text(self.right_nick))
230 ]),
231 urwid.Padding(self.bottom_card_wid,'center')
232 ])"""
233 self.hand_wid = Hand(selectable=True, on_click=self.onClick)
234 self.main_frame = urwid.Frame(self.center, header=self.top, footer=self.hand_wid, focus_part='footer')
235 urwid.WidgetWrap.__init__(self, self.main_frame)
236 self.parent.host.bridge.tarotGameReady(self.player_nick, referee, self.parent.profile)
237
238 def loadCards(self):
239 """Load all the cards in memory"""
240 QuickTarotGame.loadCards(self)
241 for value in map(str, range(1, 22)) + ['excuse']:
242 card = Card('atout', value)
243 self.cards[card.suit, card.value] = card
244 self.deck.append(card)
245 for suit in ["pique", "coeur", "carreau", "trefle"]:
246 for value in map(str, range(1, 11)) + ["valet", "cavalier", "dame", "roi"]:
247 card = Card(suit, value)
248 self.cards[card.suit, card.value] = card
249 self.deck.append(card)
250
251 def tarotGameNewHandler(self, hand):
252 """Start a new game, with given hand"""
253 if hand is []: # reset the display after the scores have been showed
254 self.resetRound()
255 for location in ['top', 'left', 'bottom', 'right']:
256 self.table.putCard(location, None)
257 self.parent.host.redraw()
258 self.parent.host.bridge.tarotGameReady(self.player_nick, self.referee, self.parent.profile)
259 return
260 QuickTarotGame.tarotGameNewHandler(self, hand)
261 self.hand_wid.update(self.hand)
262 self.parent.host.redraw()
263
264 def tarotGameChooseContratHandler(self, xml_data):
265 """Called when the player has to select his contrat
266 @param xml_data: SàT xml representation of the form"""
267 form = xmlui.create(self.parent.host, xml_data, title=_('Please choose your contrat'), flags=['NO_CANCEL'], profile=self.parent.profile)
268 form.show(valign='top')
269
270 def tarotGameShowCardsHandler(self, game_stage, cards, data):
271 """Display cards in the middle of the game (to show for e.g. chien ou poignée)"""
272 QuickTarotGame.tarotGameShowCardsHandler(self, game_stage, cards, data)
273 self.center.widget_list[1] = urwid.Filler(Hand(self.to_show))
274 self.parent.host.redraw()
275
276 def tarotGameYourTurnHandler(self):
277 QuickTarotGame.tarotGameYourTurnHandler(self)
278
279 def tarotGameScoreHandler(self, xml_data, winners, loosers):
280 """Called when the round is over, display the scores
281 @param xml_data: SàT xml representation of the form"""
282 if not winners and not loosers:
283 title = _("Draw game")
284 else:
285 title = _('You win \o/') if self.player_nick in winners else _('You loose :(')
286 form = xmlui.create(self.parent.host, xml_data, title=title, flags=['NO_CANCEL'], profile=self.parent.profile)
287 form.show()
288
289 def tarotGameInvalidCardsHandler(self, phase, played_cards, invalid_cards):
290 """Invalid cards have been played
291 @param phase: phase of the game
292 @param played_cards: all the cards played
293 @param invalid_cards: cards which are invalid"""
294 QuickTarotGame.tarotGameInvalidCardsHandler(self, phase, played_cards, invalid_cards)
295 self.hand_wid.update(self.hand)
296 if self._autoplay == None: # No dialog if there is autoplay
297 self.parent.host.notify(_('Cards played are invalid !'))
298 self.parent.host.redraw()
299
300 def tarotGameCardsPlayedHandler(self, player, cards):
301 """A card has been played by player"""
302 QuickTarotGame.tarotGameCardsPlayedHandler(self, player, cards)
303 self.table.putCard(self.getPlayerLocation(player), self.played[player])
304 self._checkState()
305 self.parent.host.redraw()
306
307 def _checkState(self):
308 if isinstance(self.center.widget_list[1].original_widget, Hand): # if we have a hand displayed
309 self.center.widget_list[1] = urwid.Filler(self.table) # we show again the table
310 if self.state == "chien":
311 self.to_show = []
312 self.state = "wait"
313 elif self.state == "wait_for_ecart":
314 self.state = "ecart"
315 self.hand.extend(self.to_show)
316 self.hand.sort()
317 self.to_show = []
318 self.hand_wid.update(self.hand)
319
320 ##EVENTS##
321 def onClick(self, hand, card_wid):
322 """Called when user do an action on the hand"""
323 if not self.state in ['play', 'ecart', 'wait_for_ecart']:
324 #it's not our turn, we ignore the click
325 card_wid.select(False)
326 return
327 self._checkState()
328 if self.state == "ecart":
329 if len(self.hand_wid.getSelected()) == 6:
330 pop_up_widget = sat_widgets.ConfirmDialog(_("Do you put these cards in chien ?"), yes_cb=self.onEcartDone, no_cb=self.parent.host.removePopUp)
331 self.parent.host.showPopUp(pop_up_widget)
332 elif self.state == "play":
333 card = card_wid.getCard()
334 self.parent.host.bridge.tarotGamePlayCards(self.player_nick, self.referee, [(card.suit, card.value)], self.parent.profile)
335 self.hand.remove(card)
336 self.hand_wid.update(self.hand)
337 self.state = "wait"
338
339 def onEcartDone(self, button):
340 """Called when player has finished his écart"""
341 ecart = []
342 for card in self.hand_wid.getSelected():
343 ecart.append((card.suit, card.value))
344 self.hand.remove(card)
345 self.hand_wid.update(self.hand)
346 self.parent.host.bridge.tarotGamePlayCards(self.player_nick, self.referee, ecart, self.parent.profile)
347 self.state = "wait"
348 self.parent.host.removePopUp()