Codebase list sugar-memorize-activity / debian/34+git20091021.837e6c6b-1 game.py
debian/34+git20091021.837e6c6b-1

Tree @debian/34+git20091021.837e6c6b-1 (Download .tar.gz)

game.py @debian/34+git20091021.837e6c6b-1raw · history · blame

#    Copyright (C) 2006, 2007, 2008 One Laptop Per Child
#
#    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 2 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, write to the Free Software
#    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

import logging
import gobject
from os.path import join

from gettext import gettext as _
from gobject import SIGNAL_RUN_FIRST, TYPE_PYOBJECT, GObject, timeout_add
from gobject import source_remove

from model import Model
from audio import Audio            
import theme

_logger = logging.getLogger('memorize-activity')

SERVICE = 'org.laptop.Memorize'
IFACE = SERVICE
PATH = '/org/laptop/Memorize'


class MemorizeGame(GObject):
    
    __gsignals__ = {
        'reset_scoreboard': (SIGNAL_RUN_FIRST, None, []),
        'reset_table': (SIGNAL_RUN_FIRST, None, []),
        'load_mode': (SIGNAL_RUN_FIRST, None, [TYPE_PYOBJECT]),
        'load_game': (SIGNAL_RUN_FIRST, None, 2 * [TYPE_PYOBJECT]),
        'change_game': (SIGNAL_RUN_FIRST, None, 2 * [TYPE_PYOBJECT]),
        'change_game_signal': (SIGNAL_RUN_FIRST, None, 5 * [TYPE_PYOBJECT]),
        'set-border': (SIGNAL_RUN_FIRST, None, 3 * [TYPE_PYOBJECT]),
        'flip-card': (SIGNAL_RUN_FIRST, None, [int, bool]),
        'flip-card-signal': (SIGNAL_RUN_FIRST, None, [int]),
        'cement-card': (SIGNAL_RUN_FIRST, None, [int]),
        'flop-card': (SIGNAL_RUN_FIRST, None, [int]),
        'highlight-card': (SIGNAL_RUN_FIRST, None, 2 * [TYPE_PYOBJECT]),
        'add_buddy': (SIGNAL_RUN_FIRST, None, 2 * [TYPE_PYOBJECT]),
        'rem_buddy': (SIGNAL_RUN_FIRST, None, [TYPE_PYOBJECT]),
        'increase-score': (SIGNAL_RUN_FIRST, None, [TYPE_PYOBJECT]),
        'wait_mode_buddy': (SIGNAL_RUN_FIRST, None, 2 * [TYPE_PYOBJECT]),
        'msg_buddy': (SIGNAL_RUN_FIRST, None, 2 * [TYPE_PYOBJECT]),
        'change-turn': (SIGNAL_RUN_FIRST, None, [TYPE_PYOBJECT]),
        }
    
    def __init__(self):
        gobject.GObject.__init__(self)
        self.myself = None
        self.players_score = {}
        self.players = []
        self.waiting_players = []
        self.current_player = None
        self.last_flipped = -1
        self.last_highlight = 1
        self._flop_card_timeout = -1
        self.messenger = None
        self.sentitive = True

        self.model = Model()
        self.flip_block = False
        self._flop_cards = None

        self.audio = Audio()

    def load_game(self, game_name, size, mode):
        self.set_load_mode('Loading game')   
        if self.model.read(game_name) == 0:
            self.model.def_grid(size)
            self.model.data['running'] = 'False'
            self.model.data['mode'] = mode
            logging.debug(' Read setup file %r: %r ',
                          game_name, self.model.grid)
            self.emit('load_game', self.model.data, self.model.grid)
        else:
            logging.error(' Reading setup file %s', game_name)
    
    def load_remote(self, grid, data, mode, signal = False):
        self.set_load_mode(_('Loading game...'))
        self.model.grid = grid
        self.model.data = data
        self.model.data['mode'] = mode
        self.emit('reset_scoreboard')
        if not signal:
            self.emit('change_game_signal', 
                      mode, 
                      self.get_grid(), 
                      self.model.data, 
                      self.waiting_players, 
                      self.model.data['game_file'])
        self.emit('change_game', self.model.data, self.get_grid())
        for buddy in self.players:
            self.players_score[buddy] = 0
        self.current_player = None
        self.last_flipped = -1
        self.last_highlight = 1
        self.change_turn()
        self.model.data['running'] = 'False'
        
        for card in self.model.grid:
            if card['state'] == '1':           
                self.emit('flip-card', self.model.grid.index(card), False)
                self.last_flipped = self.model.grid.index(card)
            elif card['state'] != '0':  
                stroke_color, fill_color = card['state'].split(',')
                self.emit('flip-card', self.model.grid.index(card), False)
                self.emit('set-border', self.model.grid.index(card),
                          stroke_color, fill_color)
        
    def add_buddy(self, buddy, score = 0):
        _logger.debug('Buddy %r was added to game', buddy.props.nick)
        self.players.append(buddy)
        self.players_score[buddy] = score
        self.emit('add_buddy', buddy, score)
        logging.debug(str(buddy))
            
        if self.current_player == None:
            self.current_player = buddy
            self.change_turn()
    
    def rem_buddy(self, buddy):
        _logger.debug('Buddy %r was removed from game', buddy.props.nick)
        if self.current_player == buddy and len(self.players) >= 2:
            if self.last_flipped != -1:
                self.emit('flop-card', self.last_flipped)
                self.model.grid[self.last_flipped]['state'] = '0'
                self.last_flipped = -1
            self.change_turn()
        index = self.players.index(buddy)    
        del self.players[index]
        del (self.players_score[buddy])
        self.emit('rem_buddy', buddy)
    
    def buddy_message(self, buddy, text):
        self.emit('msg_buddy', buddy, text)

    def update_turn(self):
        self.set_sensitive(self.current_player == self.myself)
        self.emit('change-turn', self.current_player)   

    def change_turn(self):
        if len(self.players) <= 1:
            self.current_player = self.players[0]
        if self.current_player == None:
            self.current_player = self.players[0]
        elif self.current_player == self.players[-1]:
            self.current_player = self.players[0]
        else:
            next_player = self.players.index(self.current_player) + 1
            self.current_player =  self.players[next_player]
        self.update_turn()

    def card_overflipped(self, widget, identifier):        
        if self._flop_cards and identifier in self._flop_cards:
            self.card_flipped(widget, identifier)

    def card_flipped(self, widget, identifier, signal = False):        
        if self._flop_cards:
            source_remove(self._flop_card_timeout)
            self.flop_card(self._flop_cards[0], self._flop_cards[1])

        # Check if is my turn
        if (not self.sentitive and not signal) or \
                self.last_flipped == identifier:
            return
        
        # Handle groups if needed
        if self.model.data.get('divided') == '1':
            if self.last_flipped == -1 and identifier \
                    >= (len(self.model.grid)/2):
                return
            if self.last_flipped != -1 and identifier \
                    < (len(self.model.grid)/2):
                return
            
        # do not process flips when flipping back
        if self.flip_block:
            return
        else:
            self.flip_block = True
            
        self.model.data['running'] = 'True'

        def flip_card(full_animation):
            self.emit('flip-card', identifier, full_animation)
            if not signal:
                self.emit('flip-card-signal', identifier)

        snd = self.model.grid[identifier].get('snd', None)
        if snd != None:
            sound_file = join(self.model.data.get('pathsnd'), snd)
            self.audio.play(sound_file)
                
        # First card case
        if self.last_flipped == -1:
            flip_card(full_animation=True)

            self.last_flipped = identifier
            self.model.grid[identifier]['state'] = '1'         
            self.flip_block = False

        # Second card case
        else:
            # Pair matched
            pair_key_1 = self.model.grid[self.last_flipped]['pairkey']
            pair_key_2 = self.model.grid[identifier]['pairkey']
            
            if pair_key_1 == pair_key_2:
                flip_card(full_animation=False)

                stroke_color, fill_color = \
                        self.current_player.props.color.split(',')
                self.emit('set-border', identifier, stroke_color, fill_color)
                self.emit('set-border', self.last_flipped, 
                          stroke_color, fill_color)
                
                self.increase_point(self.current_player)
                self.model.grid[identifier]['state'] = \
                        self.current_player.props.color
                self.model.grid[self.last_flipped]['state'] = \
                        self.current_player.props.color
                self.flip_block = False        

                self.emit('cement-card', identifier)
                self.emit('cement-card', self.last_flipped)

            # Pair didn't match
            else:
                flip_card(full_animation=True)

                self.model.grid[identifier]['state'] = '1'
                self.set_sensitive(False)
                self._flop_cards = (identifier, self.last_flipped)
                self._flop_card_timeout = timeout_add(theme.FLOP_BACK_TIMEOUT,
                        self.flop_card, identifier, self.last_flipped)
            self.last_flipped = -1
                
    def flop_card(self, identifier, identifier2):
        self._flop_card_timeout = -1
        self._flop_cards = None

        self.emit('flop-card', identifier)
        self.model.grid[identifier]['state'] = '0'
        self.emit('flop-card', identifier2)
        self.model.grid[identifier2]['state'] = '0'
        
        #if self.model.data['divided'] == '1':
        #    self.card_highlighted(widget, -1, False)
        self.set_sensitive(True)
        self.flip_block = False
        self.change_turn()

    def card_highlighted(self, widget, identifier, mouse):
        self.emit('highlight-card', self.last_highlight, False)
        self.last_highlight = identifier
       
        if identifier == -1 or not self.sentitive:
            return

        if self.model.data['divided'] == '1':
            if self.last_flipped == -1 and identifier \
                    >= (len(self.model.grid)/2):
                return
            if self.last_flipped != -1 and identifier \
                    < (len(self.model.grid)/2):
                return

        if mouse and self.model.grid[identifier]['state'] == '0' or not mouse:
            self.emit('highlight-card', identifier, True)

    
    def increase_point(self, buddy, inc=1):
        self.players_score[buddy] += inc
        for i_ in range(inc):
            self.emit('increase-score', buddy)
        
    def get_grid(self):
        return self.model.grid

    def collect_data(self):
        for player, score  in self.players_score.items():
            index = self.players.index(player)
            score = self.players_score[player]
            self.model.data[str(index)] = str(score)
        return self.model.data
    
    def change_game(self, widget, game_name, size, mode,
                    title = None, color= None):
        if mode in ['file', 'demo']:
            if self.model.read(game_name) != 0:
                logging.error(' Reading setup file %s', game_name)
                return
        if size == None:
            size = int(self.model.data['size'])
        self.model.def_grid(size)
        
        if title != None:
            self.model.data['title'] = title
        if color != None:
            self.model.data['color'] = color
        self.load_remote(self.model.grid, self.model.data, mode, False)
            
    def reset_game(self, size = None):
        if size == None:
            size = int(self.model.data['size'])
        self.model.def_grid(size)    
        self.load_remote(self.model.grid, self.model.data, False) 
        
    def set_load_mode(self, msg):
        self.emit('load_mode', msg)      
    
    def set_messenger(self, messenger):
        self.messenger = messenger
 
    def set_sensitive(self, status):
        self.sentitive = status
        if not status:
            self.emit('highlight-card', self.last_highlight, False)

    def get_sensitive(self):
        return self.sentitive
    
    def get_current_player(self):
        return self.current_player
    
    def get_players_data(self):
        data = []
        for player, score  in self.players_score.items():
            data.append([player.props.key, player.props.nick,
                         player.props.color, score])
        return data

    def set_wait_list(self, wait_list):
        self.waiting_players = wait_list
        for w in wait_list:
            for p in self.players:
                if  w[0] == p.props.key:
                    list.remove(w)
                    for i_ in range(w[3]):
                        self.increase_point(p)

    def set_myself(self, buddy):
        self.myself = buddy

    def add_to_waiting_list(self, buddy):
        self.players.remove(buddy)
        self.waiting_players.append(buddy)
        self.emit('wait_mode_buddy', buddy, True)

    def rem_to_waiting_list(self, buddy):
        self.waiting_players.remove(buddy)
        self.players.append(buddy)
        self.emit('wait_mode_buddy', buddy, False)
        
    def load_waiting_list(self, wait_list):
        for buddy in wait_list:
            self.add_to_waiting_list(buddy)
            
    def empty_waiting_list(self):
        for buddy in self.waiting_players:
            self.rem_to_waiting_list(buddy)