Mercurial > libervia-backend
comparison src/plugins/plugin_misc_tarot.py @ 683:75e4f5e2cc65
plugins radiocol, card_game, quiz: code factorization
author | souliane <souliane@mailoo.org> |
---|---|
date | Wed, 23 Oct 2013 12:45:13 +0200 |
parents | 2805fa3f4bdf |
children | f610864eb7a5 |
comparison
equal
deleted
inserted
replaced
682:2805fa3f4bdf | 683:75e4f5e2cc65 |
---|---|
26 | 26 |
27 from wokkel import disco, iwokkel, data_form | 27 from wokkel import disco, iwokkel, data_form |
28 from sat.tools.xml_tools import dataForm2XML | 28 from sat.tools.xml_tools import dataForm2XML |
29 | 29 |
30 from sat.tools.frontends.games import TarotCard | 30 from sat.tools.frontends.games import TarotCard |
31 from sat.tools.plugins.games import RoomGame | |
31 from time import time | 32 from time import time |
32 | 33 |
33 try: | 34 try: |
34 from twisted.words.protocols.xmlstream import XMPPHandler | 35 from twisted.words.protocols.xmlstream import XMPPHandler |
35 except ImportError: | 36 except ImportError: |
50 "handler": "yes", | 51 "handler": "yes", |
51 "description": _("""Implementation of Tarot card game""") | 52 "description": _("""Implementation of Tarot card game""") |
52 } | 53 } |
53 | 54 |
54 | 55 |
55 class Tarot(object): | 56 class Tarot(RoomGame): |
56 | 57 |
57 def __init__(self, host): | 58 def __init__(self, host): |
58 info(_("Plugin Tarot initialization")) | 59 info(_("Plugin Tarot initialization")) |
59 self.host = host | 60 RoomGame.__init__(self, host, PLUGIN_INFO, (NS_CG, CG_TAG), player_init_data={'score': 0}, |
60 self.games = {} | 61 options={'hand_size': 18, 'init_player': 0, 'current_player': None, 'contrat': None, 'stage': None}) |
61 self.waiting_inv = {} # Invitation waiting for people to join to launch a game | |
62 self.contrats = [_('Passe'), _('Petite'), _('Garde'), _('Garde Sans'), _('Garde Contre')] | 62 self.contrats = [_('Passe'), _('Petite'), _('Garde'), _('Garde Sans'), _('Garde Contre')] |
63 host.bridge.addMethod("tarotGameLaunch", ".plugin", in_sign='ass', out_sign='', method=self.launchGame) # args: room_jid, players, profile | 63 host.bridge.addMethod("tarotGameLaunch", ".plugin", in_sign='ass', out_sign='', method=self.prepareRoom) # args: room_jid, players, profile |
64 host.bridge.addMethod("tarotGameCreate", ".plugin", in_sign='sass', out_sign='', method=self.createGame) # args: room_jid, players, profile | 64 host.bridge.addMethod("tarotGameCreate", ".plugin", in_sign='sass', out_sign='', method=self.createGame) # args: room_jid, players, profile |
65 host.bridge.addMethod("tarotGameReady", ".plugin", in_sign='sss', out_sign='', method=self.newPlayerReady) # args: player, referee, profile | 65 host.bridge.addMethod("tarotGameReady", ".plugin", in_sign='sss', out_sign='', method=self.playerReady) # args: player, referee, profile |
66 host.bridge.addMethod("tarotGameContratChoosed", ".plugin", in_sign='ssss', out_sign='', method=self.contratChoosed) # args: player, referee, contrat, profile | 66 host.bridge.addMethod("tarotGameContratChoosed", ".plugin", in_sign='ssss', out_sign='', method=self.contratChoosed) # args: player, referee, contrat, profile |
67 host.bridge.addMethod("tarotGamePlayCards", ".plugin", in_sign='ssa(ss)s', out_sign='', method=self.play_cards) # args: player, referee, cards, profile | 67 host.bridge.addMethod("tarotGamePlayCards", ".plugin", in_sign='ssa(ss)s', out_sign='', method=self.play_cards) # args: player, referee, cards, profile |
68 host.bridge.addSignal("tarotGameStarted", ".plugin", signature='ssass') # args: room_jid, referee, players, profile | 68 host.bridge.addSignal("tarotGameStarted", ".plugin", signature='ssass') # args: room_jid, referee, players, profile |
69 host.bridge.addSignal("tarotGameNew", ".plugin", signature='sa(ss)s') # args: room_jid, hand, profile | 69 host.bridge.addSignal("tarotGameNew", ".plugin", signature='sa(ss)s') # args: room_jid, hand, profile |
70 host.bridge.addSignal("tarotGameChooseContrat", ".plugin", signature='sss') # args: room_jid, xml_data, profile | 70 host.bridge.addSignal("tarotGameChooseContrat", ".plugin", signature='sss') # args: room_jid, xml_data, profile |
79 self.deck_ordered.append(TarotCard(("atout", value))) | 79 self.deck_ordered.append(TarotCard(("atout", value))) |
80 for suit in ["pique", "coeur", "carreau", "trefle"]: | 80 for suit in ["pique", "coeur", "carreau", "trefle"]: |
81 for value in map(str, range(1, 11)) + ["valet", "cavalier", "dame", "roi"]: | 81 for value in map(str, range(1, 11)) + ["valet", "cavalier", "dame", "roi"]: |
82 self.deck_ordered.append(TarotCard((suit, value))) | 82 self.deck_ordered.append(TarotCard((suit, value))) |
83 | 83 |
84 def createGameElt(self, to_jid, type="normal"): | |
85 type = "normal" if to_jid.resource else "groupchat" | |
86 elt = domish.Element((None, 'message')) | |
87 elt["to"] = to_jid.full() | |
88 elt["type"] = type | |
89 elt.addElement((NS_CG, CG_TAG)) | |
90 return elt | |
91 | |
92 def __card_list_to_xml(self, cards_list, elt_name): | 84 def __card_list_to_xml(self, cards_list, elt_name): |
93 """Convert a card list to domish element""" | 85 """Convert a card list to domish element""" |
94 cards_list_elt = domish.Element((None, elt_name)) | 86 cards_list_elt = domish.Element((None, elt_name)) |
95 for card in cards_list: | 87 for card in cards_list: |
96 card_elt = domish.Element((None, 'card')) | 88 card_elt = domish.Element((None, 'card')) |
103 """Convert a domish element with cards to a list of tuples""" | 95 """Convert a domish element with cards to a list of tuples""" |
104 cards_list = [] | 96 cards_list = [] |
105 for card in cards_list_elt.elements(): | 97 for card in cards_list_elt.elements(): |
106 cards_list.append((card['suit'], card['value'])) | 98 cards_list.append((card['suit'], card['value'])) |
107 return cards_list | 99 return cards_list |
108 | |
109 def __create_started_elt(self, players): | |
110 """Create a game_started domish element""" | |
111 started_elt = domish.Element((None, 'started')) | |
112 idx = 0 | |
113 for player in players: | |
114 player_elt = domish.Element((None, 'player')) | |
115 player_elt.addContent(player) | |
116 player_elt['index'] = str(idx) | |
117 idx += 1 | |
118 started_elt.addChild(player_elt) | |
119 return started_elt | |
120 | 100 |
121 def __ask_contrat(self): | 101 def __ask_contrat(self): |
122 """Create a element for asking contrat""" | 102 """Create a element for asking contrat""" |
123 contrat_elt = domish.Element((None, 'contrat')) | 103 contrat_elt = domish.Element((None, 'contrat')) |
124 form = data_form.Form('form', title=_('contrat selection')) | 104 form = data_form.Form('form', title=_('contrat selection')) |
402 to_jid = jid.JID(room_jid.userhost() + "/" + next_player) # FIXME: gof: | 382 to_jid = jid.JID(room_jid.userhost() + "/" + next_player) # FIXME: gof: |
403 mess = self.createGameElt(to_jid) | 383 mess = self.createGameElt(to_jid) |
404 yourturn_elt = mess.firstChildElement().addElement('your_turn') | 384 yourturn_elt = mess.firstChildElement().addElement('your_turn') |
405 self.host.profiles[profile].xmlstream.send(mess) | 385 self.host.profiles[profile].xmlstream.send(mess) |
406 | 386 |
407 def userJoinedTrigger(self, room, user, profile): | |
408 """This trigger is used to check if we are waiting people in this room, | |
409 and to create a game if everybody is here""" | |
410 _room_jid = room.occupantJID.userhostJID() | |
411 if _room_jid in self.waiting_inv and len(room.roster) == 4: | |
412 #When we have 4 people in the room, we create the game | |
413 #TODO: check people identity | |
414 players = room.roster.keys() | |
415 del self.waiting_inv[_room_jid] | |
416 self.createGame(_room_jid.userhost(), players, profile_key=profile) | |
417 return True | |
418 | |
419 def launchGame(self, players, profile_key='@NONE@'): | |
420 """Launch a game: helper method to create a room, invite players, and create the tarot game | |
421 @param players: list for players jid""" | |
422 debug(_('Launching tarot game')) | |
423 profile = self.host.memory.getProfileName(profile_key) | |
424 if not profile: | |
425 error(_("Unknown profile")) | |
426 return | |
427 | |
428 def tarotRoomJoined(room): | |
429 _room = room.occupantJID.userhostJID() | |
430 for player in players: | |
431 self.host.plugins["XEP-0249"].invite(jid.JID(player), room.occupantJID.userhostJID(), {"game": "Tarot"}, profile) | |
432 self.waiting_inv[_room] = (time(), players) # TODO: remove invitation waiting for too long, using the time data | |
433 | |
434 def after_init(ignore): | |
435 room_name = "sat_tarot_%s" % self.host.plugins["XEP-0045"].getUniqueName(profile_key) | |
436 print "\n\n===> room_name:", room_name | |
437 #muc_service = self.host.memory.getServerServiceEntity("conference", "text", profile) | |
438 muc_service = None | |
439 for service in self.host.memory.getServerServiceEntities("conference", "text", profile): | |
440 if not ".irc." in service.userhost(): | |
441 #FIXME: | |
442 #This awfull ugly hack is here to avoid an issue with openfire: the irc gateway | |
443 #use "conference/text" identity (instead of "conference/irc"), there is certainly a better way | |
444 #to manage this, but this hack fill do it for test purpose | |
445 muc_service = service | |
446 break | |
447 if not muc_service: | |
448 error(_("Can't find a MUC service")) | |
449 return | |
450 | |
451 _jid, xmlstream = self.host.getJidNStream(profile) | |
452 d = self.host.plugins["XEP-0045"].join(jid.JID("%s@%s" % (room_name, muc_service.userhost())), _jid.user, {}, profile).addCallback(tarotRoomJoined) | |
453 | |
454 client = self.host.getClient(profile) | |
455 if not client: | |
456 error(_('No client for this profile key: %s') % profile_key) | |
457 return | |
458 client.client_initialized.addCallback(after_init) | |
459 | |
460 def createGame(self, room_jid_param, players, profile_key='@NONE@'): | |
461 """Create a new game | |
462 @param room_jid_param: jid of the room | |
463 @param players: list of players nick (nick must exist in the room) | |
464 @param profile_key: %(doc_profile_key)s""" | |
465 debug(_("Creating Tarot game")) | |
466 room_jid = jid.JID(room_jid_param) | |
467 profile = self.host.memory.getProfileName(profile_key) | |
468 if not profile: | |
469 error(_("profile %s is unknown") % profile_key) | |
470 return | |
471 if room_jid in self.games: | |
472 warning(_("Tarot game already started in room %s") % room_jid.userhost()) | |
473 else: | |
474 room_nick = self.host.plugins["XEP-0045"].getRoomNick(room_jid.userhost(), profile) | |
475 if not room_nick: | |
476 error('Internal error') | |
477 return | |
478 referee = room_jid.userhost() + '/' + room_nick | |
479 status = {} | |
480 players_data = {} | |
481 for player in players: | |
482 players_data[player] = {'score': 0} | |
483 status[player] = "init" | |
484 self.games[room_jid.userhost()] = {'referee': referee, 'players': players, 'status': status, 'players_data': players_data, 'hand_size': 18, 'init_player': 0, 'current_player': None, 'contrat': None, 'stage': None} | |
485 for player in players: | |
486 mess = self.createGameElt(jid.JID(room_jid.userhost() + '/' + player)) | |
487 mess.firstChildElement().addChild(self.__create_started_elt(players)) | |
488 self.host.profiles[profile].xmlstream.send(mess) | |
489 | |
490 def newPlayerReady(self, player, referee, profile_key='@NONE@'): | |
491 """Must be called when player is ready to start a new game""" | |
492 profile = self.host.memory.getProfileName(profile_key) | |
493 if not profile: | |
494 error(_("profile %s is unknown") % profile_key) | |
495 return | |
496 debug('new player ready: %s' % profile) | |
497 mess = self.createGameElt(jid.JID(referee)) | |
498 ready_elt = mess.firstChildElement().addElement('player_ready') | |
499 ready_elt['player'] = player | |
500 self.host.profiles[profile].xmlstream.send(mess) | |
501 | |
502 def contratChoosed(self, player, referee, contrat, profile_key='@NONE@'): | 387 def contratChoosed(self, player, referee, contrat, profile_key='@NONE@'): |
503 """Must be call by player when the contrat is selected | 388 """Must be call by player when the contrat is selected |
504 @param player: player's name | 389 @param player: player's name |
505 @param referee: arbiter jid | 390 @param referee: arbiter jid |
506 @contrat: contrat choosed (must be the exact same string than in the give list options) | 391 @contrat: contrat choosed (must be the exact same string than in the give list options) |
531 mess = self.createGameElt(jid.JID(referee)) | 416 mess = self.createGameElt(jid.JID(referee)) |
532 playcard_elt = mess.firstChildElement().addChild(self.__card_list_to_xml(TarotCard.from_tuples(cards), 'cards_played')) | 417 playcard_elt = mess.firstChildElement().addChild(self.__card_list_to_xml(TarotCard.from_tuples(cards), 'cards_played')) |
533 playcard_elt['player'] = player | 418 playcard_elt['player'] = player |
534 self.host.profiles[profile].xmlstream.send(mess) | 419 self.host.profiles[profile].xmlstream.send(mess) |
535 | 420 |
536 def newGame(self, room_jid, profile): | 421 def newRound(self, room_jid, profile): |
537 """Launch a new round""" | |
538 debug(_('new Tarot game')) | |
539 deck = self.deck_ordered[:] | |
540 random.shuffle(deck) | |
541 game_data = self.games[room_jid.userhost()] | 422 game_data = self.games[room_jid.userhost()] |
542 players = game_data['players'] | 423 players = game_data['players'] |
543 players_data = game_data['players_data'] | |
544 current_player = game_data['current_player'] | |
545 game_data['stage'] = "init" | |
546 game_data['first_player'] = None # first player for the current trick | 424 game_data['first_player'] = None # first player for the current trick |
547 game_data['contrat'] = None | 425 game_data['contrat'] = None |
426 common_data = {'contrat': None, | |
427 'levees': [], # cards won | |
428 'played': None, # card on the table | |
429 'wait_for_low': None # Used when a player wait for a low card because of excuse | |
430 } | |
431 | |
548 hand = game_data['hand'] = {} | 432 hand = game_data['hand'] = {} |
549 hand_size = game_data['hand_size'] | 433 hand_size = game_data['hand_size'] |
550 chien = game_data['chien'] = [] | 434 chien = game_data['chien'] = [] |
435 deck = self.deck_ordered[:] | |
436 random.shuffle(deck) | |
551 for i in range(4): | 437 for i in range(4): |
552 hand[players[i]] = deck[0:hand_size] | 438 hand[players[i]] = deck[0:hand_size] |
553 del deck[0:hand_size] | 439 del deck[0:hand_size] |
554 chien.extend(deck) | 440 chien.extend(deck) |
555 del(deck[:]) | 441 del(deck[:]) |
556 | 442 msg_elts = {} |
557 for player in players: | 443 for player in players: |
558 to_jid = jid.JID(room_jid.userhost() + "/" + player) # FIXME: gof: | 444 msg_elts[player] = self.__card_list_to_xml(hand[player], 'hand') |
559 mess = self.createGameElt(to_jid) | 445 |
560 mess.firstChildElement().addChild(self.__card_list_to_xml(hand[player], 'hand')) | 446 RoomGame.newRound(self, room_jid, (common_data, msg_elts), profile) |
561 self.host.profiles[profile].xmlstream.send(mess) | |
562 players_data[player]['contrat'] = None | |
563 players_data[player]['levees'] = [] # cards won | |
564 players_data[player]['played'] = None # card on the table | |
565 players_data[player]['wait_for_low'] = None # Used when a player wait for a low card because of excuse | |
566 | 447 |
567 pl_idx = game_data['current_player'] = (game_data['init_player'] + 1) % len(players) # the player after the dealer start | 448 pl_idx = game_data['current_player'] = (game_data['init_player'] + 1) % len(players) # the player after the dealer start |
568 player = players[pl_idx] | 449 player = players[pl_idx] |
569 to_jid = jid.JID(room_jid.userhost() + "/" + player) # FIXME: gof: | 450 to_jid = jid.JID(room_jid.userhost() + "/" + player) # FIXME: gof: |
570 mess = self.createGameElt(to_jid) | 451 mess = self.createGameElt(to_jid) |
571 mess.firstChildElement().addChild(self.__ask_contrat()) | 452 mess.firstChildElement().addChild(self.__ask_contrat()) |
572 self.host.profiles[profile].xmlstream.send(mess) | 453 self.host.profiles[profile].xmlstream.send(mess) |
573 | 454 |
574 def card_game_cmd(self, mess_elt, profile): | 455 def card_game_cmd(self, mess_elt, profile): |
456 """ | |
457 @param mess_elt: instance of twisted.words.xish.domish.Element | |
458 """ | |
575 from_jid = jid.JID(mess_elt['from']) | 459 from_jid = jid.JID(mess_elt['from']) |
576 room_jid = jid.JID(from_jid.userhost()) | 460 room_jid = jid.JID(from_jid.userhost()) |
577 game_elt = mess_elt.firstChildElement() | 461 game_elt = mess_elt.firstChildElement() |
578 game_data = self.games[room_jid.userhost()] | 462 game_data = self.games[room_jid.userhost()] |
579 players_data = game_data['players_data'] | 463 players_data = game_data['players_data'] |
591 status = self.games[room_jid.userhost()]['status'] | 475 status = self.games[room_jid.userhost()]['status'] |
592 nb_players = len(self.games[room_jid.userhost()]['players']) | 476 nb_players = len(self.games[room_jid.userhost()]['players']) |
593 status[player] = 'ready' | 477 status[player] = 'ready' |
594 debug(_('Player %(player)s is ready to start [status: %(status)s]') % {'player': player, 'status': status}) | 478 debug(_('Player %(player)s is ready to start [status: %(status)s]') % {'player': player, 'status': status}) |
595 if status.values().count('ready') == nb_players: # everybody is ready, we can start the game | 479 if status.values().count('ready') == nb_players: # everybody is ready, we can start the game |
596 self.newGame(room_jid, profile) | 480 self.newRound(room_jid, profile) |
597 | 481 |
598 elif elt.name == 'hand': # a new hand has been received | 482 elif elt.name == 'hand': # a new hand has been received |
599 self.host.bridge.tarotGameNew(room_jid.userhost(), self.__xml_to_list(elt), profile) | 483 self.host.bridge.tarotGameNew(room_jid.userhost(), self.__xml_to_list(elt), profile) |
600 | 484 |
601 elif elt.name == 'contrat': # it's time to choose contrat | 485 elif elt.name == 'contrat': # it's time to choose contrat |