# HG changeset patch # User Goffi # Date 1276845572 -28800 # Node ID 63c9067a1499462ad02f8c4eb4a0abd218a460b0 # Parent dd556233a1b1828335cd29513206ca6d000dde6d Tarot game: invalid cards management - tarot plugin: card validity check, new signal tarotGameInvalidCards - wix: when an invalid cards signal is received, the cards are back in the hand, and the state change so the player as to play again. diff -r dd556233a1b1 -r 63c9067a1499 frontends/quick_frontend/quick_app.py --- a/frontends/quick_frontend/quick_app.py Thu Jun 03 17:43:49 2010 +0930 +++ b/frontends/quick_frontend/quick_app.py Fri Jun 18 15:19:32 2010 +0800 @@ -55,6 +55,7 @@ self.bridge.register("tarotGameYourTurn", self.tarotMyTurn) self.bridge.register("tarotGameScore", self.tarotScore) self.bridge.register("tarotGameCardsPlayed", self.tarotCardsPlayed) + self.bridge.register("tarotGameInvalidCards", self.tarotInvalidCards) self.bridge.register("subscribe", self.subscribe) self.bridge.register("paramUpdate", self.paramUpdate) self.bridge.register("contactDeleted", self.contactDeleted) @@ -324,6 +325,13 @@ if self.chat_wins.has_key(room_jid): self.chat_wins[room_jid].getGame("Tarot").cardsPlayed(player, cards) + def tarotInvalidCards(self, room_jid, phase, played_cards, invalid_cards, profile): + if not self.__check_profile(profile): + return + debug (_("Cards played are not valid: %s") % invalid_cards) + if self.chat_wins.has_key(room_jid): + self.chat_wins[room_jid].getGame("Tarot").invalidCards(phase, played_cards, invalid_cards) + def subscribe(self, type, raw_jid, profile): """Called when a subsciption management signal is received""" if not self.__check_profile(profile): diff -r dd556233a1b1 -r 63c9067a1499 frontends/wix/card_game.py --- a/frontends/wix/card_game.py Thu Jun 03 17:43:49 2010 +0930 +++ b/frontends/wix/card_game.py Fri Jun 18 15:19:32 2010 +0800 @@ -193,6 +193,29 @@ self.played[player] = pl_cards[0] self.Refresh() + def invalidCards(self, phase, played_cards, invalid_cards): + """Invalid cards have been played + @param phase: phase of the game + @param played_cards: all the cards played + @param invalid_cards: cards which are invalid""" + + if phase == "play": + self.state = "play" + elif phase == "ecart": + self.state = "ecart" + else: + error ('INTERNAL ERROR: unmanaged game phase') + + for suit, value in played_cards: + self.hand.append(self.cards[suit, value]) + + self._recalc_ori() + self.Refresh() + self.hand.sort() + wx.MessageDialog(self, _("Cards played are invalid !"), _("Error"), wx.OK | wx.ICON_ERROR).ShowModal() + + + def _is_on_hand(self, pos_x, pos_y): """Return True if the coordinate are on the hand cards""" diff -r dd556233a1b1 -r 63c9067a1499 plugins/plugin_misc_tarot.py --- a/plugins/plugin_misc_tarot.py Thu Jun 03 17:43:49 2010 +0930 +++ b/plugins/plugin_misc_tarot.py Fri Jun 18 15:19:32 2010 +0800 @@ -132,6 +132,7 @@ host.bridge.addSignal("tarotGameCardsPlayed", ".communication", signature='ssa(ss)s') #args: room_jid, player, type ["chien", "poignée",...], cards, data[dict], profile host.bridge.addSignal("tarotGameYourTurn", ".communication", signature='ss') #args: room_jid, profile host.bridge.addSignal("tarotGameScore", ".communication", signature='ssasass') #args: room_jid, xml_data, winners (list of nicks), loosers (list of nicks), profile + host.bridge.addSignal("tarotGameInvalidCards", ".communication", signature='ssa(ss)a(ss)s') #args: room_jid, game phase, played_cards, invalid_cards, profile self.deck_ordered = [] for value in ['excuse']+map(str,range(1,22)): self.deck_ordered.append(Card(("atout",value))) @@ -207,6 +208,19 @@ score_elt.addChild(looser_elt) return score_elt + def __invalid_cards_elt(self, played_cards, invalid_cards, game_phase): + """Create a element for invalid_cards error + @param list_cards: list of Card + @param game_phase: phase of the game ['ecart', 'play']""" + error_elt = domish.Element(('','error')) + played_elt = self.__card_list_to_xml(played_cards, 'played') + invalid_elt = self.__card_list_to_xml(invalid_cards, 'invalid') + error_elt['type'] = 'invalid_cards' + error_elt['phase'] = game_phase + error_elt.addChild(played_elt) + error_elt.addChild(invalid_elt) + return error_elt + def __next_player(self, game_data, next_pl = None): """Increment player number & return player name @param next_pl: if given, then next_player is forced to this one @@ -325,8 +339,6 @@ if game_data['contrat'] == "Garde Contre": for card in game_data['chien']: check_score+=card.points - if ( score + check_score != 91 ): - pdb.set_trace() assert (score + check_score == 91) point_limit = None @@ -373,6 +385,63 @@ return (scores_str, winners, loosers) + def __invalid_cards(self, game_data, cards): + """Checks that the player has the right to play what he wants to + @param game_data: Game data + @param cards: cards the player want to play + @return forbidden_cards cards or empty list if cards are ok""" + forbidden_cards = [] + if game_data['stage'] == 'ecart': + for card in cards: + if card.bout or card.value=="roi": + forbidden_cards.append(card) + #TODO: manage case where atouts (trumps) are in the dog + elif game_data['stage'] == 'play': + biggest_atout = None + suit_asked = None + players = game_data['players'] + players_data = game_data['players_data'] + idx = players.index(game_data['first_player']) + current_idx = game_data['current_player'] + current_player = players[current_idx] + if idx == current_idx: + #the player is the first to play, he can play what he wants + return forbidden_cards + while (idx != current_idx): + player = players[idx] + played_card = players_data[player]['played'] + if not suit_asked and played_card.value != "excuse": + suit_asked = played_card.suit + if played_card.suit == "atout" and played_card > biggest_atout: + biggest_atout = played_card + idx = (idx + 1) % len(players) + has_suit = False #True if there is one card of the asked suit in the hand of the player + has_atout = False + biggest_hand_atout = None + + for hand_card in game_data['hand'][current_player]: + if hand_card.suit == suit_asked: + has_suit = True + if hand_card.suit == "atout": + has_atout = True + if hand_card.suit == "atout" and hand_card > biggest_hand_atout: + biggest_hand_atout = hand_card + + assert len(cards) == 1 + card = cards[0] + if card.suit != suit_asked and has_suit and card.value != "excuse": + forbidden_cards.append(card) + return forbidden_cards + if card.suit != suit_asked and card.suit != "atout" and has_atout: + forbidden_cards.append(card) + return forbidden_cards + if card.suit == "atout" and card < biggest_atout and biggest_hand_atout > biggest_atout and card.value != "excuse": + forbidden_cards.append(card) + else: + error(_('Internal error: unmanaged game stage')) + return forbidden_cards + + def __start_play(self, room_jid, game_data, profile): """Start the game (tell to the first player after dealer to play""" game_data['stage'] = "play" @@ -584,10 +653,17 @@ elif elt.name == 'cards_played': if game_data['stage'] == "ecart": - #TODO: check validity of écart (no king, no oulder, cards must be in player hand) #TODO: show atouts (trumps) if player put some in écart assert (game_data['attaquant'] == elt['player']) #TODO: throw an xml error here list_cards = Card.from_tuples(self.__xml_to_list(elt)) + #we now check validity of card + invalid_cards = self.__invalid_cards(game_data, list_cards) + if invalid_cards: + mess = self.createGameElt(jid.JID(room_jid.userhost()+'/'+elt['player'])) + mess.firstChildElement().addChild(self.__invalid_cards_elt(list_cards, invalid_cards, game_data['stage'])) + self.host.profiles[profile].xmlstream.send(mess) + return + #FIXME: gof: manage Garde Sans & Garde Contre cases players_data[elt['player']]['levees'].extend(list_cards) #we add the chien to attaquant's levées for card in list_cards: @@ -602,7 +678,13 @@ if mess_elt['type'] == 'groupchat': self.host.bridge.tarotGameCardsPlayed(room_jid.userhost(), elt['player'], self.__xml_to_list(elt), profile) else: - #TODO: check card validity and send error mess if necessary + #we first check validity of card + invalid_cards = self.__invalid_cards(game_data, cards) + if invalid_cards: + mess = self.createGameElt(jid.JID(room_jid.userhost()+'/'+current_player)) + mess.firstChildElement().addChild(self.__invalid_cards_elt(cards, invalid_cards, game_data['stage'])) + self.host.profiles[profile].xmlstream.send(mess) + return #the card played is ok, we forward it to everybody #first we remove it from the hand and put in on the table game_data['hand'][current_player].remove(cards[0]) @@ -657,6 +739,15 @@ form = data_form.Form.fromElement(form_elt) xml_data = XMLTools.dataForm2xml(form) self.host.bridge.tarotGameScore(room_jid.userhost(), xml_data, winners, loosers, profile) + elif elt.name == 'error': + if elt['type'] == 'invalid_cards': + played_cards = self.__xml_to_list(elt.elements(name='played',uri='').next()) + invalid_cards = self.__xml_to_list(elt.elements(name='invalid',uri='').next()) + self.host.bridge.tarotGameInvalidCards(room_jid.userhost(), elt['phase'], played_cards, invalid_cards, profile) + else: + error (_('Unmanaged error type: %s') % elt['type']) + else: + error (_('Unmanaged card game element: %s') % elt.name) def getHandler(self, profile): return CardGameHandler(self)