view plugins/plugin_misc_tarot.py @ 90:4020931569b8

Tarot Game: session initialization
author Goffi <goffi@goffi.org>
date Sun, 23 May 2010 16:39:05 +0930
parents 23caf1051099
children 39c672544593
line wrap: on
line source

#!/usr/bin/python
# -*- coding: utf-8 -*-

"""
SAT plugin for managing xep-0045
Copyright (C) 2009, 2010  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 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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""

from logging import debug, info, warning, error
from twisted.words.xish import domish
from twisted.internet import protocol, defer, threads, reactor
from twisted.words.protocols.jabber import client, jid, xmlstream
from twisted.words.protocols.jabber import error as jab_error
from twisted.words.protocols.jabber.xmlstream import IQ
import os.path
import pdb
import random

from zope.interface import implements

from wokkel import disco, iwokkel, muc

from base64 import b64decode
from hashlib import sha1
from time import sleep

try:
    from twisted.words.protocols.xmlstream import XMPPHandler
except ImportError:
    from wokkel.subprotocols import XMPPHandler

MESSAGE = '/message'
NS_CG = 'http://www.goffi.org/protocol/card_game'
CG_TAG = 'card_game'
CG_REQUEST = MESSAGE + '/' + CG_TAG + '[@xmlns="' + NS_CG + '"]'

PLUGIN_INFO = {
"name": "Tarot cards plugin",
"import_name": "Tarot",
"type": "Misc",
"protocols": [],
"dependencies": ["XEP_0045"],
"main": "Tarot",
"handler": "yes",
"description": _("""Implementation of Tarot card game""")
}

class Tarot():

    def __init__(self, host):
        info(_("Plugin Tarot initialization"))
        self.host = host
        self.games={}
        host.bridge.addMethod("tarotGameCreate", ".communication", in_sign='sass', out_sign='', method=self.createGame) #args: room_jid, players, profile
        host.bridge.addMethod("tarotGameReady", ".communication", in_sign='sss', out_sign='', method=self.newPlayerReady) #args: user, referee, profile
        host.bridge.addSignal("tarotGameStarted", ".communication", signature='ssass') #args: room_jid, referee, players, profile
        host.bridge.addSignal("tarotGameNew", ".communication", signature='sa(ss)s') #args: room_jid, hand, profile
        self.deck_ordered = []
        for value in map(str,range(1,22))+['excuse']:
            self.deck_ordered.append(("atout",value))
        for family in ["pique", "coeur", "carreau", "trefle"]:
            for value in map(str,range(1,11))+["valet","cavalier","dame","roi"]:
                self.deck_ordered.append((family, value))

    def createGameElt(self, to_jid):
        elt = domish.Element(('jabber:client','message'))
        elt["to"] = to_jid.full()
        elt.addElement((NS_CG, CG_TAG))
        return elt

    def __hand_to_xml(self, hand):
        """Convert a hand (list of tuples) to domish element"""
        hand_elt = domish.Element(('','hand'))
        for family, value in hand:
            card_elt = domish.Element(('','card'))
            card_elt['family'] = family
            card_elt['value'] = value
            hand_elt.addChild(card_elt) 
        return hand_elt

    def __xml_to_hand(self, hand_elt):
        """Convert a hand domish element to a list of tuples"""
        hand = []
        assert (hand_elt.name == 'hand')
        for card in hand_elt.elements():
            hand.append((card['family'], card['value']))
        return hand

    def __create_started_elt(self, players):
        """Create a game_started domish element"""
        started_elt = domish.Element(('','started'))
        idx = 0
        for player in players:
            player_elt = domish.Element(('','player'))
            player_elt.addContent(player)
            player_elt['index'] = str(idx)
            idx+=1
            started_elt.addChild(player_elt)
        return started_elt

    def createGame(self, room_jid_param, players, profile_key='@DEFAULT@'):
        """Create a new game"""
        debug (_("Creating Tarot game"))
        room_jid = jid.JID(room_jid_param)
        profile = self.host.memory.getProfileName(profile_key)
        if not profile:
            error (_("profile %s is unknown") % profile_key)
            return
        if False: #gof: self.games.has_key(room_jid):
            warning (_("Tarot game already started in room %s") % room_jid.userhost())
        else:
            status = {}
            for player in players:
                status[player] = "init"
            self.games[room_jid.userhost()] = {'players':players, 'status':status, 'profile':profile, 'hand_size':18, 'player_start':0}
            for player in players:
                mess = self.createGameElt(jid.JID(room_jid.userhost()+'/'+player))
                mess.firstChildElement().addChild(self.__create_started_elt(players))
                self.host.profiles[profile].xmlstream.send(mess)

    def newPlayerReady(self, user, referee, profile_key='@DEFAULT@'):
        """Must be called when player is ready to start a new game"""
        profile = self.host.memory.getProfileName(profile_key)
        if not profile:
            error (_("profile %s is unknown") % profile_key)
            return
        debug ('new player ready: %s' % profile)
        mess = self.createGameElt(jid.JID(referee))
        mess.firstChildElement().addElement('player_ready', content=user)
        self.host.profiles[profile].xmlstream.send(mess)


    def newGame(self, room_jid):
        """Launch a new round"""
        debug (_('new Tarot game'))
        deck = self.deck_ordered[:]
        random.shuffle(deck)
        profile = self.games[room_jid.userhost()]['profile']
        players = self.games[room_jid.userhost()]['players']
        hand = self.games[room_jid.userhost()]['hand'] = {}
        hand_size = self.games[room_jid.userhost()]['hand_size']
        chien = self.games[room_jid.userhost()]['chien'] = []
        for i in range(4): #TODO: distribute according to real Tarot rules (3 by 3 counter-clockwise, 1 card at once to chien)
            hand[players[i]] = deck[0:hand_size]
            del deck[0:hand_size]
        chien = deck[:]
        del(deck[:])

        for player in players:
            to_jid = jid.JID(room_jid.userhost()+"/"+player) #FIXME: gof:
            mess = self.createGameElt(to_jid)
            mess.firstChildElement().addChild(self.__hand_to_xml(hand[player]))
            self.host.profiles[profile].xmlstream.send(mess)
            

    def card_game_cmd(self, mess_elt, profile):
        print "\n\nCARD GAME command received (profile=%s): %s" % (profile, mess_elt.toXml())
        room_jid = jid.JID(mess_elt['from'])
        game_elt = mess_elt.firstChildElement()
        for elt in game_elt.elements(): #new game created
            if elt.name == 'started':
                players = []
                for player in elt.elements():
                    players.append(unicode(player))
                self.host.bridge.tarotGameStarted(room_jid.userhost(), room_jid.full(), players, profile)
            elif elt.name == 'player_ready':
                player = unicode(elt)
                status = self.games[room_jid.userhost()]['status']
                nb_players = len(self.games[room_jid.userhost()]['players'])
                status[player] = 'ready'
                debug (_('Player %(player)s is ready to start [status: %(status)s]') % {'player':player, 'status':status})
                if status.values().count('ready') == 2: #gof: nb_players: #everybody is ready, we can start the game
                    self.newGame(room_jid)
            
            elif elt.name == 'hand': #a new hand has been received
                self.host.bridge.tarotGameNew(room_jid.userhost(), self.__xml_to_hand(elt), profile)
            

    def getHandler(self, profile):
            return CardGameHandler(self)
   


class CardGameHandler (XMPPHandler):
    implements(iwokkel.IDisco)
   
    def __init__(self, plugin_parent):
        self.plugin_parent = plugin_parent
        self.host = plugin_parent.host

    def connectionInitialized(self):
        print "gof: ajout d'observer", CG_REQUEST
        self.xmlstream.addObserver(CG_REQUEST, self.plugin_parent.card_game_cmd, profile = self.parent.profile)

    def getDiscoInfo(self, requestor, target, nodeIdentifier=''):
        return [disco.DiscoFeature(NS_CB)]

    def getDiscoItems(self, requestor, target, nodeIdentifier=''):
        return []