Commits

Szymon Wróblewski committed 0e03ed0 Draft

Imported from SVN by Bitbucket

  • Participants

Comments (0)

Files changed (25)

File BrickGame/src/BrickGame.py

+import os.path
+#!/usr/bin/env python
+#
+# Brick game
+# platform for simple games
+#
+# Released under the GNU General Public License
+
+VERSION = "0.3"
+
+try:
+    import os
+    import random
+    import re
+    import string
+    import sys
+
+    import pygame
+    from pygame.locals import *
+
+    import data_make
+    import imgs
+    from screen import Screen
+    from input import Keyboard
+    from timer import Timers
+except ImportError, err:
+    print "Couldn't load module.", err
+    sys.exit(2)
+
+class Modules(object): # TODO make this class works
+    def __init__(self, path, screen):
+        self.screen = screen
+        self.current = None
+        # adding game modules search path
+        sys.path.append(os.path.abspath(path))
+        # loading modules
+        print "loading modules"+'<'*10
+        files = os.listdir(path)
+        mod = re.compile("_game\.py$", re.IGNORECASE)
+        files = filter(mod.search, files)
+        print "files:", files
+        moduleNames = map(lambda f: os.path.splitext(f)[0], files)
+        modules = map(__import__, moduleNames)
+        print "modules:", modules
+        self.modules = filter(self._test, modules)
+        print "filtered modules:", self.modules
+        
+    def _test(self, module):
+        try:
+            if module.name and module.info and module.Game:
+                if issubclass(module.Game, object):
+                    return True
+        except (AttributeError, TypeError):
+            pass
+        return False
+
+    def list(self):
+        pass
+
+    def step(self):
+        try:
+            self.module.step()
+        except AttributeError:
+            pass
+
+class Interface(object):
+    def __init__(self, screen):
+        self.screen = screen
+        self._score = 0
+        self._level = 0
+        self._speed = False
+
+    def __getattr__(self, name):
+        if self._displays.has_key(name):
+            return self._displays[name]
+        else:
+            raise AttributeError, name
+
+class UI(object):
+    def __init__(self, screen):
+        self.screen = screen
+        self.screen.textareas.main.align('c')
+        self.screen.textareas.main.put("> Brick Game <")
+        self.screen.textareas.score.align('r0')
+        self.screen.textareas.score.put("0")
+        self.screen.indicators.score.state = 1
+        self.screen.displays.main.clear(0)
+        self.screen.displays.main.visibility(True, 0)
+        i = 0
+        for c in range(0x33, 0xcc, 0x08):
+            self.screen.displays.main.fill((0, i, 10, 1), 0x81, c << 8, 0)
+            i += 1
+        self.screen.displays.main.put_text((2,5,5,1), 'Brick', 0xffffff, 0)
+        self.screen.displays.main.put_text((4,6,4,1), 'Game', 0xffffff, 0)
+        self.screen.displays.main.put_text((0,8,10,1), 'written in', 0xffffff, 0)
+        self.screen.displays.main.put_text((1,9,8,1), 'Python &', 0xffffff, 0)
+        self.screen.displays.main.put_text((2,10,6,1), 'Pygame', 0xffffff, 0)
+
+class GI(object):
+    """Game Interface
+
+    """
+    def __init__(self):
+        pass
+
+class Game(object):
+    def __init__(self):
+        sys.path.append(os.path.abspath('.'))
+        config = data_make.load()
+        self.screen = Screen(config)
+        try:
+            self.modules = Modules('Games', self.screen)
+        except:
+            pass
+        #self.interface = Interface(self.screen)
+        self.clock = pygame.time.Clock()
+        pygame.mouse.set_visible(True)
+        self.mouse_focus = False
+        self._pause = False
+        self._fps = 120 #2*2*2*3*5
+        self._running = True
+        self.timers = Timers(self._fps)
+        self.timers.add_new("ta_move", self.screen.textareas.move, 10, type='s')
+        self.timers.add_new("pause", lambda:self.screen.indicators.state('pause'), 2, None, 's')
+        #self.timers.add_new("focus_test", self.focusTest, 2, type='s')
+        #print self.timers.listType('s')
+        sys_keys = {
+            #(key, KEYUP/KEYDOWN): (func, modifiers expected, modifiers allowed)
+            (K_p, KEYDOWN): (self.pause, KMOD_CTRL),
+            (K_i, KEYDOWN): (self.edit, KMOD_CTRL),
+            #(K_e, KEYDOWN): (lambda:self.screen.textareas[0].edit(not bool(self.screen.textareas[0].edit())), KMOD_CTRL),
+            (K_q, KEYDOWN): (self.stop, KMOD_CTRL),
+            (K_r, KEYDOWN): (lambda:self.screen.displays.main.fill((random.randint(0,8), random.randint(0, 18), random.randint(1,10), random.randint(1, 20)), 0x81, random.randint(0, 0xffffff), 0), None),
+            (K_t, KEYDOWN): (lambda:self.screen.displays.main.put_text((random.randint(0,8), random.randint(0, 18), random.randint(1,10), random.randint(1, 20)), 'test', random.randint(0, 0xffffff), 0), None),
+            (K_l, KEYDOWN): (self.test, KMOD_CTRL),
+            (K_c, KEYDOWN): (self.compile_conf, KMOD_CTRL),
+        }
+        self.keyboard = Keyboard(sys_keys, {})
+        self.rects = (
+        #    (self.screen.textarea1, Rect(self.screen.textarea1)),
+        )
+        self.clicked = -1
+        self.pos = [0,0]
+        self.editing = False # <<<<<<<<<<<
+        #self.test()
+        self.ui = UI(self.screen)
+        self.run()
+
+    def fps(self, fps = None):
+        """set frame rate
+
+        fps is frame rate value
+        Return old frame rate
+        """
+        tmp = self._fps
+        if fps:
+            self._fps = fps
+        return tmp
+
+    def mouse(self, event):
+        for i in  range(len(self.rects)):
+            if self.rects[i][1].collidepoint(*event.pos):
+                try:
+                    if event.type in (MOUSEBUTTONDOWN, MOUSEBUTTONUP):
+                        if event.button == 1:
+                            self.rects[i][0].on_mouse_click(event.pos)
+                    elif event.type == MOUSEMOTION:
+                        if event.buttons[0]:
+                            print (event.pos[0]-self.pos[0], event.pos[1]-self.pos[1])
+                            self.rects[i][0].on_mouse_move(event.pos,
+                                (event.pos[0]-self.pos[0], event.pos[1]-self.pos[1]))
+                except AttributeError:
+                    pass
+                else:
+                    self.clicked = i
+                    break
+
+    def test(self):
+        try:
+            test = __import__('test')
+            test.test(self.screen)
+        except:
+            pass
+
+    def compile_conf(self):
+        try:
+            cfg = __import__('config')
+            data_make.pack(cfg.config, 'config.dat')
+            print 'new config.dat created'
+        except ImportError:
+            print 'No config.py file found'
+
+    def pause(self, state=None):
+        if state is None:
+            self._pause = not self._pause
+        else:
+            self._pause = bool(state)
+        if self._pause == True:
+            self.screen.indicators.state('pause', True)
+            self.timers.unpause("pause")
+        else:
+            self.timers.pause("pause")
+            self.screen.indicators.state('pause', False)
+
+    def stop(self):
+        self._running = False
+
+    def edit(self, action=''):
+        if action == True and self.editing == False:
+            print "Input mode"+'<'*10
+            self.editing = True
+            self.keyboard.mode('i', self.edit)
+            self.screen.textareas.main.edit(True)
+            self.timers.pause("ta_move")
+            #self.timers.add_new("ta_blink", self.screen.textareas.main.blink, 3, type='s')
+        elif action == False and self.editing == True:
+            pass
+        else:
+            print "editing:", action
+            #self.screen.textareas.main.replace(str[0]+' ')
+            self.screen.textareas.main.edit(str[1])
+
+    def run(self):
+        while self._running:
+            for event in pygame.event.get():
+                if event.type == QUIT:
+                    return
+                if event.type == ACTIVEEVENT:
+                    if event.state in (2, 6): # APPINPUTFOCUS and APPACTIVE
+                        if event.gain == 0:
+                            #prev_fps, self._fps = self._fps, 2
+                            #self.timers.add_new(lambda:self.screen.indicators.state('pause'), 2)
+                            self.prev_fps, self._fps = self._fps, 10
+                            self.timers.add_new("pause", lambda:self.screen.indicators.state('pause'), 10, 0, 's')
+                            print ">> Lost input focus <<"
+                        else:
+                            self._fps = self.prev_fps
+                            self.timers.add_new("pause", lambda:self.screen.indicators.state('pause'), 10, None, 's')
+                            self.screen.indicators.state('pause', False)
+                            print ">> Gain input focus <<"
+                elif event.type in (KEYDOWN, KEYUP):
+                    self.keyboard.process(event.type, event.key, event.mod)
+            self.screen.update()
+            self.timers.tick()
+            self.clock.tick(self._fps)
+
+if __name__ == '__main__':
+    try:
+        cfg = __import__('config')
+        data_make.pack(cfg.config)
+        print 'new_config.dat created'
+    except ImportError:
+        pass
+    g = Game()

File BrickGame/src/Fonts/_font1_.png

Added
New image

File BrickGame/src/Fonts/_font2_.png

Added
New image

File BrickGame/src/Games/__init__.py

Empty file added.

File BrickGame/src/Games/snake_game.py

+# BrickGame module
+
+#from BrickGame import *
+from pygame.locals import *
+
+__all__ = ['Game', 'name', 'info']
+
+name = 'Snake'
+info = 'Simple snake game'
+
+class Game(object):
+    keys = {
+        (K_UP, KEYDOWN): (lambda:self.move('u'), None),
+        (K_DOWN, KEYDOWN): (lambda:self.move('d'), None),
+        (K_LEFT, KEYDOWN): (lambda:self.move('l'), None),
+        (K_RIGHT, KEYDOWN): (lambda:self.move('r'), None),
+    }
+    def __init__(self, screen, timers):
+        self.screen = screen
+        self.timers = timers
+        self.snake = list()
+        self.level = 0
+        self.length = 3
+        self.lives = 3
+        
+    def load_level(self):
+        self.snake.extend([(5,9), (5,10), (5,11)])
+
+    def move(self, direction):
+        pass
+
+    def step(self):
+        pass

File BrickGame/src/Images/_screen_.png

Added
New image

File BrickGame/src/Images/icon.bmp

Added
New image

File BrickGame/src/__init__.py

Empty file added.

File BrickGame/src/config.py

+config = {
+    'screen' : {
+        'image' : ('screen6.png', 0x00ff00),
+    }
+}

File BrickGame/src/data_make.py

+#!/usr/bin/env python
+"""
+data_make is a module packing data used by BrickGame
+"""
+
+import cPickle
+from default_config import config
+
+__all__ = ('pack', 'load')
+
+err = 'Error while {0} configuration file:'
+
+def pack(data=config, file_name='new_config.dat'):
+    f = open(file_name, 'wb')
+    cPickle.dump(data, f, -1)
+    del f
+
+def load(file_name=None):
+    try:
+        f = open(('config.dat' if file_name is None else file_name), 'rb')
+        data = cPickle.load(f)
+        del f
+        for k, v in data.iteritems():
+            if config.has_key(k):
+                    config[k].update(v)
+            else:
+                config[k] = v
+    except IOError, detail:
+        if file_name is not None:
+            print err.format('loading'), detail
+    except TypeError, detail:
+        print err.format('processing'), detail
+    return config

File BrickGame/src/default_config.py

+config = {
+# ----- Game setup ---------------------------------------------------
+    'paths' : {
+        'images' : 'Images',
+        'fonts' : 'Fonts',
+        'modules' : 'Games',
+        'music' : 'Music',
+        'sounds' : 'Sounds',
+    },
+    'screen' : {
+        # screen size
+        'size' : (158, 260),
+        # name : (file name, colorkey)
+        'icon' : ('icon.bmp', None),
+        'image' : ('_screen_.png', 0x00ff00),
+    },
+    'fonts': {
+        # name : (filename, width, height, colorkey, additional chars)
+        'ta_font' : ('_font1_.png', 11, 15, 0x00ff00, 1),
+        'disp_font' : ('_font2_.png', 10, 10, 0x00ff00, 25),
+        # font backgroung must be 0x000000,
+    },
+# ----- UI components setup ------------------------------------------
+    'textareas' : {
+        # name : (position, size in chars, text color, font name)
+        'main' : ((2, 231), (14, 1), 0x00ff00, 'ta_font'),
+        'score' : ((65, 5), (8, 1), 0x00ff00, 'ta_font'),
+        'speed' : ((121, 92), (2, 1), 0x00ff00, 'ta_font'),
+        'level' : ((121, 118), (2, 1), 0x00ff00, 'ta_font'),
+    },
+    'displays' : {
+        # name : (position, size in chars, default color, layers, font index)
+        'main' : ((6, 24), (10, 20), 0x00ff00, 3, 'disp_font'),
+        'lives' : ((110, 40), (4, 4), 0x00ff00, 2, 'disp_font'),
+        'extra' : ((110, 194), (4, 3), 0x00ff00, 2, 'disp_font'),
+    },
+    'indicators' : {
+        # background color when indicator turned off
+        'bg_color' : 0x2a2a2a,
+        # name, color, rect
+        'score': (0x00ff00, (34, 5, 29, 7)),
+        'hiscore' : (0xff0000, (8, 5, 55, 7)),
+        'lines' : (0x00ff00, (36, 14, 27, 7)),
+        'pause' : (0x00ff00, (116, 179, 31, 9)),
+        'rotate' : (0x00ff00, (114, 136, 35, 7)),
+        'r1' : (0x00ff00, (128, 147, 4, 8)),
+        'r2' : (0x00ff00, (133, 145, 4, 8)),
+        'gameA' : (0x00ff00, (116, 158, 31, 7)),
+        'gameB' : (0x00ff00, (116, 167, 31, 7)),
+        'sound' : (0x00ff00, (6, 14, 7, 7)),
+        's1' : (0x00ff00, (15, 14, 3, 7)),
+        's2' : (0x00ff00, (20, 14, 5, 7)),
+        's3' : (0x00ff00, (27, 14, 4, 7)),
+        'next' : (0x00ff00, (114, 23, 23, 7)),
+        'lives' : (0x00ff00, (114, 32, 27, 7)),
+        'speed' : (0x00ff00, (117, 84, 29, 7)),
+        'level' : (0x00ff00, (117, 110, 29, 7)),
+    }
+}
+
+# Additional info
+# colorkey - None or RGB value
+# filename - Only file name (without folder names like 'Images')

File BrickGame/src/game.ico

Added
New image

File BrickGame/src/imgs.py

+digits = (
+    (# 0
+        (0x81, 0x81, 0x81),
+        (0x81, None, 0x81),
+        (0x81, None, 0x81),
+        (0x81, None, 0x81),
+        (0x81, 0x81, 0x81),
+    ),
+    (# 1
+        (None, 0x81, None),
+        (0x81, 0x81, None),
+        (None, 0x81, None),
+        (None, 0x81, None),
+        (None, 0x81, None),
+    ),
+    (# 2
+        (0x81, 0x81, 0x81),
+        (None, None, 0x81),
+        (0x81, 0x81, 0x81),
+        (0x81, None, None),
+        (0x81, 0x81, 0x81),
+    ),
+    (# 3
+        (0x81, 0x81, 0x81),
+        (None, None, 0x81),
+        (0x81, 0x81, 0x81),
+        (None, None, 0x81),
+        (0x81, 0x81, 0x81),
+    ),
+    (# 4
+        (0x81, None, 0x81),
+        (0x81, None, 0x81),
+        (0x81, 0x81, 0x81),
+        (None, None, 0x81),
+        (None, None, 0x81),
+
+    ),
+    (# 5
+        (0x81, 0x81, 0x81),
+        (0x81, None, None),
+        (0x81, 0x81, 0x81),
+        (None, None, 0x81),
+        (0x81, 0x81, 0x81),
+    ),
+    (# 6
+        (0x81, 0x81, 0x81),
+        (0x81, None, None),
+        (0x81, 0x81, 0x81),
+        (0x81, None, 0x81),
+        (0x81, 0x81, 0x81),
+    ),
+    (# 7
+        (0x81, 0x81, 0x81),
+        (0x81, None, 0x81),
+        (None, None, 0x81),
+        (None, None, 0x81),
+        (None, None, 0x81),
+    ),
+    (# 8
+        (0x81, 0x81, 0x81),
+        (0x81, None, 0x81),
+        (0x81, 0x91, 0x81),
+        (0x81, None, 0x81),
+        (0x81, 0x81, 0x81),
+    ),
+    (# 9
+        (0x81, 0x81, 0x81),
+        (0x81, None, 0x81),
+        (0x81, 0x91, 0x81),
+        (None, None, 0x81),
+        (0x81, 0x81, 0x81),
+    ),
+)

File BrickGame/src/input/__init__.py

+from keyboard import Keyboard

File BrickGame/src/input/keyboard.py

+from pygame.locals import *
+
+class Keyboard(object):
+    def __init__(self, sys, ui):
+        """Initialize Keyboard processing class
+
+        sys, ui - dictionaries containing key sets
+                  {(key, action): (function, modifiers)}
+                   key: key activating selected function
+                   action: KEYDOWN / KEYUP action
+                   function: function called when key is pressed / released
+                   modifiers: keys like CTRL, ALT, etc. holded to call function
+                  sys key set is always active
+                  ui key set is active only when Keyboard is in ui mode
+                  (which is default)
+        """
+        self.sys_key_set = sys
+        self.ui_key_set = ui
+        self.game_key_set = {}
+        self.input_mode = 'u' # u - UI, i - input, g - game
+        self.str = ""
+        self.cur = 0
+        self.uppercase = {
+            '`':'~', '1':'!', '2':'@', '3':'#', '4':'$', '5':'%', '6':'^',
+            '7':'&', '8':'*', '9':'(', '0':')', '-':'_', '=':'+', '[':'{',
+            ']':'}', ';':':', '\'':'"', '\\':'|', ',':'<', '.':'>', '/':'?'
+        }
+        self.keypad = {
+            K_KP_PERIOD:'.', K_KP_DIVIDE:'/', K_KP_MULTIPLY:'*',
+            K_KP_MINUS:'-', K_KP_PLUS:'+'
+        }
+
+    def game_keys(self, game_keys):
+        """Load game key set
+
+        game_keys - dictionary similar to ui key set
+                    game key set is activated when game_keys are loaded
+        """
+        if game_keys is not None:
+            self.game_key_set = game_keys
+        self.input_mode = 'g'
+
+    def mode(self, mode=None):
+        """Set Keyboard mode
+
+        mode - one of None, 'u', 'g', 'i'
+               None: nothing is changed, function returns current mode
+               'u': UI mode, ui key set is activated
+               'g': game mode, game key set is activated
+               'i': input mode, ui and game key sets are disactivated to allow
+                    user text input
+
+        return - previous mode
+        """
+        prev = self.input_mode
+        if mode is not None:
+            self.input_mode = mode
+        return prev
+
+    def get_input(self):
+        if self.input_mode == 'i':
+            return (self.str, self.cur)
+        else:
+            return None
+
+    def process(self, type, key, mod):
+        """Process pressed key
+
+        type - KEYDOWN or KEYUP
+        key  - pressed key
+        mod  - active modifiers while pressing key
+        """
+        try:
+            a = self.sys_key_set[(key, type)]
+            if a[1] == None or mod & a[1]:
+                a[0]()
+            else:
+                raise KeyError
+        except KeyError:
+            try: # ui and game are not taking care of modifiers
+                if self.input_mode == 'u':
+                    self.ui_key_set[(key, type)]()
+                elif self.input_mode == 'g':
+                    self.game_key_set[(key, type)]()
+                elif self.input_mode == 'i' and type == KEYDOWN and self.cur > 0:
+                    if key == K_BACKSPACE and len(self.str) > 0:
+                        self.str = self.str[:self.cur-1] + self.str[self.cur:]
+                        self.cur -= 1
+                    elif key == K_LEFT and self.cur > 0:
+                        self.cur -= 1
+                    elif key == K_RIGHT and self.cur <= len(self.str):
+                        self.cur += 1
+                    elif key == K_HOME:
+                        self.cur = 0
+                    elif key == K_END:
+                        self.cur = len(self.str) + 1
+                    elif K_SPACE <= key <= 125: # '{'
+                        if mod & (KMOD_SHIFT | KMOD_CAPS):
+                            if K_a <= key <= K_z:
+                                c = chr(key).upper()
+                            else:
+                                c = self.uppercase[chr(key)]
+                        else:
+                             c = chr(key)
+                        self.str = self.str[:self.cur] + c + self.str[self.cur:]
+                        self.cur += 1
+                    elif K_KP0 <= key <= K_KP_PLUS:
+                        if mod & KMOD_NUM:
+                            if K_KP0 <= key <= K_KP9:
+                                c = chr(key - 208)
+                            elif K_KP_PERIOD <= key <= K_KP_PLUS:
+                                c = self.keypad[key]
+                            self.str = self.str[:self.cur] + c + self.str[self.cur:]
+                            self.cur += 1
+                    print "str:", self.str, self.cur
+            except KeyError:
+                print "key:", type, key, mod

File BrickGame/src/screen/__init__.py

+from screen import Screen

File BrickGame/src/screen/display.py

+import pygame
+
+class Display(object): # FIXME rendering objects on layers
+    """Multi layer display
+
+    class
+
+    layers order:
+                  screen
+        layer  0 -------- (system layer, not for game use)
+           nr  1 --------
+               2 --------
+
+    colors 0x000000 and 0xfeeffe can't be used
+    """
+    def __init__(self, position, size, default_color, layers, image, font):
+        """Initialize display
+
+        position - position on the screen in pixels (x, y)
+        size - size in chars (w, h)
+        default_color - color used while filling display when no color specified
+        layers - amount of display layers
+        image - Screen background image
+        font - Font class object
+        bg - Screen background image
+        """
+        self.size = size
+        self.def_color = default_color
+        self.font = font
+        self.layers = layers
+        self.rect = pygame.Rect(position, (self.size[0]*self.font.width,
+                                           self.size[1]*self.font.height))
+        print "Display self.rect", self.rect
+        self.image = image.subsurface(self.rect)
+        self.visible = [False]*self.layers
+        self.surface = pygame.Surface(self.rect.size)
+        self.surface.convert()
+        #self.surface.fill(0x000000)
+        self.surface.set_colorkey(0x000000)
+        self.dispRect = pygame.Rect((0, 0), self.size)
+        self.buffer = []
+        for l in range(self.layers):
+            s = pygame.Surface(self.rect.size)
+            s.convert()
+            s.fill(0xfeeffe)
+            s.set_colorkey(0xfeeffe)
+            self.buffer.append(s)
+        self.changed = []
+
+    def _layers_p(self, layers):
+        if layers is None:
+            layers = range(self.layers)
+        else:
+            try:
+                layers[0]
+            except TypeError:
+                layers = [layers]
+            except IndexError:
+                return None
+        return layers
+
+    def clear(self, layers=None):
+        """Clear layer(s)
+
+        layer - layer number (default all layers)
+        """
+        print "clearing" + '<' * 10
+        layers = self._layers_p(layers)
+        if layers is not None:
+            changed = 0
+            for layer in layers:
+                self.buffer[layer].fill(0xfeeffe)
+                #self.visible[layer] = False
+                print "clearing layer", layer
+                if self.visible[layer]:
+                    changed += 1
+            if changed > 0:
+                self.changed.append(self.dispRect)
+
+    def visibility(self, vis, layers=None):
+        """Change layer(s) visibility status
+
+        vis - layer visibility
+        layers - layer to change (default all layers)
+        """
+        layers = self._layers_p(layers)
+        if layers is not None:
+            changed = 0
+            vis = bool(vis)
+            for layer in layers:
+                if self.visible[layer] != vis:
+                    self.visible[layer] = vis
+                    changed += 1
+            if changed > 0:
+                self.changed.append(self.dispRect)
+
+    def fill(self, rect, char, color=None, layer=None):
+        """Fill part of display
+
+        rect - pygame recstyle object counted in chars
+        char - index of font char (None -> transparent)
+        color - filling color (default default_color)
+        layer - layer number (default lowermost)
+        """
+        print "filling" + '<' * 10
+        rect = pygame.Rect(rect)
+        print rect
+        rect = rect.clip(self.dispRect)
+        print "after clip:", rect
+        if layer is None:
+            layer = self.layers - 1
+        if self.visible[layer]:
+            self.changed.append(rect)
+            print "filling layer", layer, rect
+        if char is None:
+            self.buffer[layer].fill(0xfeeffe, self.convert_rect(rect))
+        else:
+            if type(char) == type(str()):
+                char = ord(char)
+            if color is None:
+                color = self.def_color
+            r = self.convert_rect(rect)
+            #tmp_s = pygame.Surface((r.width, self.font.height))
+            #tmp_s.set_colorkey(0x000000)
+            #self.buffer[layer].blit(self.image, r.topleft, r)
+            #tmp_s.blit(self.buffer[layerS], (0,0), r)
+            for i in range(rect.bottom-rect.top):
+                self.font.put(self.buffer[layer], (r.left, r.top+i*self.font.height), (char,)*rect.width, color)
+                #self.font.put(tmp_s, (0, 0), (char,)*rect.width, color)
+                #self.buffer[layer].blit(tmp_s, (r.left, r.top+i*self.font.height))
+                #print " > ({3}) fill with: {0} color: 0x{1:06x} at: {2}".format((char,)*rect.width, color, (r.left, r.top+i*self.font.height), i)
+                print " > (%d) fill with: '%s' color: 0x%06x at: %s" % (i, (char,)*rect.width, color, (r.left, r.top+i*self.font.height))
+
+    def copy(self, rect, pos, layerS=None, layerD=None):
+        """Copy part of display to another place
+
+        rect - pygame recstyle object counted in chars
+        pos - destination position counted in chars
+        layerS - source layer (default lowermost)
+        layerD - destination layer (default source layer)
+        """
+        rect = pygame.Rect(rect)
+        nrect = pygame.Rect(rect)
+        nrect.topleft = pos
+        nrect.clamp_ip(self.dispRect)
+        if layerS is None:
+            layerS = self.layers - 1
+        if layerD is None:
+            layerD = layerS
+        if self.visible[layerD]:
+            self.changed.append(nrect)
+        r = self.convert_rect(rect)
+        tmp_s = pygame.Surface(r.size)
+        tmp_s.convert()
+        tmp_s.set_colorkey(0xfeeffe)
+        tmp_s.blit(self.buffer[layerS], (0,0), r)
+        r = self.convert_rect(nrect)
+        self.buffer[layerD].blit(tmp_s, r.topleft)
+
+    def put_text(self, rect, text, color=None, layer=None):
+        """Put text on display
+
+        rect - pygame recstyle object counted in chars defining textarea
+        text - text to put
+        color - text color (default default_color)
+        layer - layer number (default lowermost)
+        """
+        print "writting" + '<' * 10
+        rect = pygame.Rect(rect)
+        rect = rect.clip(self.dispRect)
+        if layer is None:
+            layer = self.layers - 1
+        if self.visible[layer]:
+            self.changed.append(rect)
+            print "writting layer", layer, rect
+        if color is None:
+            color = self.def_color
+        lines = 0
+        for line in text.split('\n'):
+            print " > line: '%s'" % line
+            print " > spliting line: %d lines" % (len(line) / rect.width + 1)
+            for i in range(len(line) / rect.width + 1):
+                print "  * step:", i
+                if lines >= rect.height:
+                    print "  ! lines(%d) >= rect.height(%d) exiting func" % (lines, rect.height)
+                    return
+                r = self.convert_rect(rect)
+                self.font.put_text(self.buffer[layer], (r.left, r.top+lines*self.font.height), line[i*rect.width:(i+1)*rect.width], color)
+                #print "  * put text: '{0}' color: 0x{1:06x} at: {2}".format(line[i*rect.width:(i+1)*rect.width], color, (r.left, r.top+i*self.font.height))
+                print "  * put text: '%s' color: 0x%06x at: %s" % (line[i*rect.width:(i+1)*rect.width], color, (r.left, r.top+i*self.font.height))
+                lines += 1
+
+    def map_data(self, rect, data, color=None, layer=None):
+        """Put data on display
+
+        rect - pygame recstyle object counted in chars defining textarea
+        data - 2 dimensional list containing char codes
+        color - data color (default default_color)
+        layer - layer number (default lowermost)
+        """
+        print "mapping data" + '<' * 10
+        rect = pygame.Rect(rect)
+        rect = rect.clip(self.dispRect)
+        if layer is None:
+            layer = self.layers - 1
+        if self.visible[layer]:
+            self.changed.append(rect)
+            print "writting layer", layer, rect
+        if color is None:
+            color = self.def_color
+        r = self.convert_rect(rect)
+        #tmp_st = pygame.Surface(r.size)
+        #tmp_st.set_colorkey(0x000000)
+        #tmp_st.fill(0xfeeffe)
+        #tmp_si = pygame.Surface(r.size)
+        #tmp_si.set_colorkey(0xfeeffe)
+        #self.buffer[layer].blit(self.image, r.topleft, r)
+        #tmp_si.blit(self.image, (0, 0), r)
+        for y in range(rect.height):
+            self.font.put(self.buffer[layer], (r.left, r.top+y*self.font.height), data[y][:rect.width], color)
+            #self.font.put(tmp_st, (0, y*self.font.height), data[y][:rect.width], color)
+            print "  * ({3}) put: {0} color: 0x{1:06x} at: {2}".format(data[y][:rect.width], color, (r.left, r.top+y*self.font.height), y)
+        #tmp_si.blit(tmp_st, (0, 0))
+        #self.buffer[layer].blit(tmp_si, r.topleft)
+
+    def elem(self, el):
+        """Generate ASCII code from graphic element index"""
+        return chr(el + 0x80)
+
+    def convert_rect(self, rect):
+        """Convert rect counted in chars to rect counted in pixels"""
+        return pygame.Rect(rect.left * self.font.width,
+                           rect.top * self.font.height,
+                           rect.width * self.font.width,
+                           rect.height * self.font.height)
+
+    def update(self):
+        """Refresh display"""
+        if len(self.changed) > 0:
+            print "updating"+'<'*10
+            if len(self.changed) == 1:
+                changed = self.changed
+            else:
+                changed = []
+                print "processing rects"
+                while len(self.changed) > 0:
+                    print "len(self.changed):", len(self.changed)
+                    rect = self.changed[0]
+                    print " * del first key:", rect
+                    del self.changed[0]
+                    cl = rect.collidelistall(self.changed)
+                    print " * colide list:", cl
+                    if len(cl) > 0:
+                        changed.append(rect.unionall([self.changed[r] for r in cl]))
+                        print " * changed after union:", changed
+                        for r in sorted(cl, reverse = True):
+                            print "  > del key:", r, ",", self.changed[r]
+                            del self.changed[r]
+                    else:
+                        changed.append(rect)
+                        print " * changed without union:", changed
+                else:
+                    print " * loop end"
+            print "changed:", changed
+            for ch in changed:
+                rect = self.convert_rect(ch)
+                #rect = pygame.Rect(0,0,0,0).unionall([r for r,l in self.changed])
+                #rect = self.convert_rect(rect)
+                print "update Display:", rect
+                for l in reversed(range(self.layers)):
+                    print " > layer", l
+                    if self.visible[l] == True:
+                        print "  * visible, refresh rect:", rect
+                        self.surface.fill(0x000000, rect)
+                        self.surface.blit(self.buffer[l], rect.topleft, rect)
+                        #self.surface.fill(random.randint(0, 0xffffff), rect)
+                pygame.display.get_surface().blit(self.image, self.rect.move(rect.topleft), rect)
+                pygame.display.get_surface().blit(self.surface, self.rect.move(rect.topleft), rect) #FIXME update part of screen
+                pygame.display.update(self.rect)
+            self.changed = []
+
+class Displays(object):
+    def __init__(self, image, fonts, data = {}):
+        """Initialize all Display classes
+
+        image - Screen background image
+        fonts - Fonts object
+        data - list of lists of atributes
+        """
+        self._displays = {}
+        self._image = image
+        self._fonts = fonts
+        for item in data.iteritems():
+            self.add_new(*item)
+
+    def add_new(self, name, data):
+        """Add new Display
+
+        data - list of atributes
+        """
+        self._displays[name] = Display(image=self._image, font=self._fonts[data[-1]], *data[:-1])
+
+    def update(self):
+        """Refresh all Displays"""
+        for disp in self._displays.itervalues():
+            disp.update()
+
+    def __getitem__(self, name):
+        return self._displays[name]
+
+    def __getattr__(self, name):
+        if self._displays.has_key(name):
+            return self._displays[name]
+        else:
+            raise AttributeError, name

File BrickGame/src/screen/font.py

+import os
+
+from .utils import load_image
+
+class Font(object):
+    def __init__(self, filename, width, height, colorkey, add_chars=0):
+        """Initialize bitmap font class
+
+        filename - filename of image with chars
+        width, height - width, height of char in pixels
+        colorkey - color used when drawing font
+        add_chars - aditional characters
+
+        Image must be organised in 16x6 matrix of chars.
+        When you specified add_chars height of matrix can be
+        larger (>=7) to store additional characters
+        """
+        self.font = load_image(filename, colorkey)[0]
+        self.width, self.height = width, height
+        self.additional_chars = add_chars
+
+    def put_text(self, surface, pos, text, color):
+        """Put text on surface
+
+        surface - destination surface
+        pos - position of text in pixels
+        text - putting text
+        color - text color
+        """
+        if type(text) != type(str()):
+            text = str(text)
+        data = map(ord, text)
+        a = 0
+        surface.fill(color, (pos[0], pos[1], len(data)*self.width, self.height))
+        for c in data:
+            if c < 32 or c > 127 + self.additional_chars:
+                c = 32
+            c -= 32
+            c2 = c % 16
+            c1 = c / 16
+            clip = (c2 * self.width, c1 * self.height, self.width, self.height)
+            surface.blit(self.font, (pos[0]+a*self.width, pos[1]), clip)
+            a += 1
+
+    def put(self, surface, pos, data, color):
+        """Put data on surface
+
+        surface - destination surface
+        pos - position of text in pixels
+        data - iterable object containing char codes
+        color - text color
+        """
+        if type(data) == type(str()):
+            data = map(ord, data)
+        a = 0
+        for c in data:
+            if c is not None or 32 <= c <= (127 + self.additional_chars):
+                c -= 32
+                c2 = c % 16
+                c1 = c / 16
+                clip = (c2 * self.width, c1 * self.height, self.width, self.height)
+                surface.fill(color, (pos[0]+a*self.width, pos[1], self.width, self.height))
+                surface.blit(self.font, (pos[0]+a*self.width, pos[1]), clip)
+            a += 1
+        #pygame.display.update((self.data[item][0][0], self.data[item][0][1],
+        #    len(self.data[item][1])*self.width, self.height))
+
+class Fonts(object):
+    def __init__(self, path, data = {}):
+        self._fonts = {}
+        self._path = path
+        for item in data.iteritems():
+            self.add_new(*item)
+
+    def add_new(self, name, data):
+        self._fonts[name] = Font(os.path.join(self._path, data[0]), *data[1:])
+
+    def update(self):
+        for font in self._fonts:
+            font.update()
+
+    def __getitem__(self, name):
+        return self._fonts[name]
+
+    def __getattr__(self, name):
+        if self._fonts.has_key(name):
+            return self._fonts[name]
+        else:
+            raise AttributeError, name

File BrickGame/src/screen/indicator.py

+import pygame
+
+class Indicator(object):
+    def __init__(self, color, rect):
+        self.state = 0
+        self.color = color
+        self.rect = rect
+        self.changed = True
+
+    def __setattr__(self, name, value):
+        if name != 'changed':
+            object.__setattr__(self, name, value)
+            object.__setattr__(self, 'changed', True)
+        else:
+            object.__setattr__(self, name, value)
+
+class Indicators(object):
+    def __init__(self, image, off_color, data={}):
+        self.screen = pygame.display.get_surface()
+        self.image = image
+        self.bgcolor = off_color
+        self.indicators = {}
+        self.changed = []
+        for name, item in data.iteritems():
+            self.add_new(name, item)
+
+    def add_new(self, name, data):
+        #self.changed.append(name)
+        if not self.indicators.has_key(name):
+            self.indicators[name] = Indicator(*data)
+
+    def state(self, name, st=None):
+        if not self.indicators.has_key(name):
+            raise ValueError, "There is no item named '%s'" % (name)
+        self.changed.append(name)
+        if st is not None:
+            self.indicators[name].state = st
+        else:
+            self.indicators[name].state = int(not self.indicators[name].state)
+        return self.indicators[name].state
+
+    def color(self, name, color):
+        if not self.indicators.has_key(name):
+            raise ValueError, "There is no item named '%s'" % (name)
+        self.changed.append(name)
+        old_color = self.indicators[name].color
+        self.indicators[name].color = color
+        return old_color
+
+    def update(self):
+        for item in self.indicators.itervalues():
+            if item.changed == True:
+                color = item.color if item.state else self.bgcolor
+                self.screen.fill(color, item.rect)
+                self.screen.blit(self.image, item.rect, item.rect)
+                pygame.display.update(item.rect)
+                item.changed = False
+        #self.changed = []
+
+    def __getitem__(self, name):
+        return self.indicators[name]
+
+    def __getattr__(self, name):
+        if self.indicators.has_key(name):
+            return self.indicators[name]
+        else:
+            raise AttributeError, name

File BrickGame/src/screen/screen.py

+"""Main screen package class
+
+Set up pygame window and all screen components
+"""
+import pygame
+import os
+
+from font import Fonts
+from textarea import Textareas
+from display import Displays
+from indicator import Indicators
+from .utils import load_image
+
+class Screen(object):
+    """Screen base class.
+
+    """
+    def __init__(self, config):
+        pygame.display.init()
+        icon = pygame.image.load(os.path.join(config['paths']['images'],
+                                              config['screen']['icon'][0]))
+        pygame.display.set_icon(icon)
+        screen = pygame.display.set_mode(config['screen']['size'])
+        pygame.display.set_caption('BrickGame', 'BGame')
+        self.image = load_image(os.path.join(config['paths']['images'],
+                                             config['screen']['image'][0]),
+                                config['screen']['image'][1])[0]
+        screen.blit(self.image, (0, 0))
+        pygame.display.flip()
+        self.fonts = Fonts(config['paths']['fonts'], config['fonts'])
+        self.textareas = Textareas(self.fonts, config['textareas'])
+        self.displays = Displays(self.image, self.fonts, config['displays'])
+        self.indicators = Indicators(self.image,
+                                     config['indicators'].pop('bg_color'),
+                                     config['indicators'])
+
+    def __del__(self):
+        pygame.display.quit()
+
+    def destroy(self):
+        pygame.display.quit()
+
+    def update(self):
+        """Refresh all used objects"""
+        self.indicators.update()
+        self.textareas.update()
+        self.displays.update()

File BrickGame/src/screen/textarea.py

+import pygame
+
+class Textarea(object):
+    def __init__(self, position, size, color, font):
+        """Initialize textarea
+
+        position - position of textarea on the screen in pixels (x, y)
+        size - size of textarea in chars (w, h)
+        color - textarea color
+        font - Font class object
+        """
+        self.size = size
+        self._color, self.font = color, font
+        self.rect = pygame.Rect(position, (self.size[0]*self.font.width,
+                                           self.size[1]*self.font.height))
+        #self.surface = pygame.display.get_surface().subsurface(self.rect)
+        self.surface = pygame.Surface(self.rect.size)
+        self.surface.convert()
+        self.surface.set_colorkey(0x000000)
+        self.str = ""
+        self.prev_str = ""
+        self.space = " *** "
+        self.mode = 'l '
+        self.cursor_v = False
+        self.move_allowed = True
+        self.changed = ''
+        self.counter = -size[0]
+        self.editing = False
+        self.prev_edit = 0
+        self.cursor_c = chr(0x81)
+
+    def put(self, text):
+        """Add text to textarea"""
+        if type(text) != type(''):
+            text = str(text)
+        self.str += text
+        self.changed += 't'
+
+    def replace(self, text):
+        """Replace text in textarea"""
+        if type(text) != type(''):
+            text = str(text)
+        self.str = text
+        self.changed += 't'
+
+    def align(self, mode):
+        """Text align
+
+        mode -  2 chars string describing align mode
+            mode[0] -  one of [l, c, r] - first letter of [left, center, right]
+            mode[1] -  fill character
+        """
+        self.mode = mode
+        self.changed += 't'
+
+    def color(self, color):
+        """Set text color"""
+        self._color = color
+
+    def clear(self):
+        """Clear textarea"""
+        self.str = ""
+        self.counter = 0
+        self.changed += 't'
+
+    def move(self, dir=1): # -1 <= dir <= 1
+        if self.move_allowed == True:
+        #if self.editing == False:
+            prev = self.counter
+            self.counter += dir
+            if self.counter >= len(self.str) + len(self.space):
+                self.counter = 0
+            elif self.counter < 0:
+                if prev >= 0:
+                    self.counter = len(self.str) + len(self.space);
+            self.changed += 't'
+
+    def move_allow(self, allow=None):
+        """Allow/disallow Textarea movement
+
+        allow - boolean value determining Textarea movement
+                (if None returns current state without any change)
+        """
+        prev = self.move_allowed
+        if allow is not None:
+            self.move_allowed = allow
+        return prev
+
+    def edit(self, edit):
+        """Turn editing mode on/off, move cursor
+
+        action - what to do:
+                 <bool> - start/end editing mode
+                 <int> - set cursor position
+        """
+        if edit is None:
+            return self.editing
+        elif edit == False:
+            print "edit mode disabled"
+            self.editing = False
+            self.str = self.prev_str
+            self.counter = 0
+            self.prev_str = ""
+            self.prev_edit = 0
+            self.cursor_v = False
+            self.move_allowed = True
+        elif edit == True:
+            print "edit mode enabled"
+            self.prev_str = self.str
+            self.str = ""
+            self.mode = 'l '
+            self.editing = 0 #len(self.str) - 1 #????????
+            self.prev_edit = 0
+            self.counter = 0 #len(self.str) - self.size[0]
+            self.cursor_v = True
+            self.move_allowed = False
+        elif self.editing != False: # <<<-----------------
+            print "editing:", edit
+            self.prev_edit = self.editing
+            ln = len(self.str)
+            w = self.size[0]
+            if ln <= w:
+                self.editing = edit
+                self.changed +='c'
+            else:
+                if edit == ln - 1:
+                    self.counter = ln - w
+                    self.editing = w - 1
+                    self.changed += 'tc'
+                elif ln - edit < w / 2 + 1:
+                    self.editing = w - (ln - edit)
+                    self.changed += 'c'
+                elif len - edit >= w / 2 + 1 and edit >= w / 2:
+                    self.counter = edit - w / 2
+                    self.changed += 't'
+                elif edit < w / 2:
+                    self.editing = edit
+                    self.changed += 'c'
+            print " * changed:", self.changed
+            print " * counter:", self.counter
+            print " * cursor:", self.editing
+
+    def blink(self):
+        self.cursor_v = not self.cursor_v
+        self.changed = 'c'
+
+    def update(self):
+        if 't' in self.changed and self.editing == False:
+            if len(self.str) <= self.size[0]:
+                if len(self.mode) == 1:
+                    self.mode += ' '
+                if self.mode[0] == 'l':
+                    self.font.put_text(self.surface, (0, 0), self.str.ljust(self.size[0], self.mode[1]), self._color)
+                elif self.mode[0] == 'c':
+                    self.font.put_text(self.surface, (0, 0), self.str.center(self.size[0], self.mode[1]), self._color)
+                elif self.mode[0] == 'r':
+                    self.font.put_text(self.surface, (0, 0), self.str.rjust(self.size[0], self.mode[1]), self._color)
+            else:
+                if self.size[1] == 1: # scroll message
+                    if self.counter < 0:
+                        current = 0
+                    else:
+                        current = self.counter
+                    tmp = self.str + self.space + self.str + self.space
+                    self.font.put_text(self.surface, (0, 0), tmp[current:self.size[0]+current],
+                        self._color)
+                else:
+                    lines = list()
+                    for line in self.str.split('\n'):
+                        while len(line) > self.size[0]: # spliting line to fit in textarea
+                            lines.append(line[:self.size[0]])
+                            line = line[self.size[0]:]
+                        else:
+                            lines.append(line)
+                    l = 0
+                    while l in range(self.size[0]) and l < len(lines): # add not visible lines visibility <-----
+                        self.font.put_text(self.surface, (0, self.font.height*l),
+                                      lines[l], self._color)
+                        l += 1
+        elif 't' in self.changed and self.editing == True:
+            self.font.put_text(self.surface, (0, 0), self.str[self.counter:self.counter+self.size[0]].ljust(self.size[0]), self._color)
+        if 'c' in self.changed and self.editing != False:
+            if self.prev_edit != self.editing:
+                self.font.put_text(self.surface, (self.prev_edit*self.font.width, 0), self.str[self.prev_edit], self._color)
+            if self.cursor_v == True:
+                self.font.put_text(self.surface, (self.editing*self.font.width, 0), self.cursor_c, self._color)
+            else:
+                self.font.put_text(self.surface, (self.editing*self.font.width, 0), self.str[self.editing], self._color)
+        if self.changed:
+            pygame.display.get_surface().blit(self.surface, self.rect)
+            pygame.display.update(self.rect)
+        self.changed = ''
+
+class Textareas(object):
+    def __init__(self, fonts, data={}):
+        """Initialize all Textarea classes
+
+        fonts - Fonts object
+        data - dict of name and lists of atributes
+        """
+        self.textareas = {}
+        self.fonts = fonts
+        for item in data.iteritems():
+            self.add_new(*item)
+
+    def add_new(self, name, data):
+        """Add new Textarea
+
+        name - Teaxtarea name
+        data - list of atributes
+        """
+        if not self.textareas.has_key(name):
+            self.textareas[name] = Textarea(font = self.fonts[data[-1]], *data[:-1])
+
+    def move(self):
+        """Move all Textareas"""
+        for ta in self.textareas.itervalues():
+            ta.move()
+
+    def update(self):
+        """Refresh all Textareas"""
+        for ta in self.textareas.itervalues():
+            ta.update()
+
+    def __getitem__(self, name):
+        return self.textareas[name]
+
+    def __getattr__(self, name):
+        if self.textareas.has_key(name):
+            return self.textareas[name]
+        else:
+            raise AttributeError, name

File BrickGame/src/setup.py

+from distutils.core import setup
+import py2exe
+import sys
+import os
+
+origIsSystemDLL = py2exe.build_exe.isSystemDLL
+def isSystemDLL(pathname):
+        if os.path.basename(pathname).lower() in ("msvcr71.dll",):
+                return 0
+        return origIsSystemDLL(pathname)
+py2exe.build_exe.isSystemDLL = isSystemDLL
+
+# If run without args, build executables, in quiet mode.
+if len(sys.argv) == 1:
+    sys.argv.append("py2exe")
+    #sys.argv.append("-q")
+
+class Target:
+    def __init__(self, **kw):
+        self.__dict__.update(kw)
+        # for the versioninfo resources
+        self.version = "0.1.0"
+        self.company_name = "No Company"
+        self.copyright = "no copyright"
+        self.name = "py2exe sample file"
+
+game = Target(
+    version = "0.1.0",
+    name = "Brick Game",
+    description = "Brick Game",
+    script = "BrickGame.py",
+    icon_resources = [(1, "game.ico")],
+    dest_base = "BrickGame"
+)
+
+game_c = Target(
+    version = "2.1.0",
+    name = "Brick Game",
+    description = "Brick Game with console",
+    script = "BrickGame.py",
+    icon_resources = [(1, "game.ico")],
+    dest_base = "BrickGame_console"
+)
+
+excludes = ["doctest", "pdb", "unittest", "difflib", "inspect"]
+includes = ["pygame.locals", "pygame.event", "pygame.rect"]
+packages = ["pygame"]
+
+options = {
+    "compressed": True,
+    "optimize": 2,
+    "ascii": 1,
+    "bundle_files": 1,
+    "excludes": excludes,
+    #"includes": includes,
+    "packages": packages,
+    "dist_dir": "..\dist"
+}
+
+setup(
+    options = {
+        "py2exe": options
+    },
+    data_files=[
+        ("Fonts", ('Fonts\\_font1_.png', 'Fonts\\_font2_.png')),
+        ("Images", ('Images\\icon.bmp', 'Images\\_screen_.png')),
+    ],
+    zipfile = None,
+    console = [game_c],
+    windows = [game],
+    )

File BrickGame/src/test.py

+def test(screen):
+    # pola tekstowe (main, score, speed, level)
+    screen.textareas.main.replace('Bardzo dlugi przykladowy tekst')
+    screen.textareas.score.put(123)
+    screen.textareas.score.align('r0')
+    screen.textareas.score.color(0xff0000)
+    screen.textareas.speed.put(1)
+    screen.textareas.speed.align('r0')
+    screen.textareas.level.put(4)
+    screen.textareas.level.align('r0')
+    # kontrolki (score, hiscore, lines, pause, rotate, r1, r2, gameA, gameB,
+    #            sound, s1, s2, s3, next, lives, speed, level)
+    screen.indicators.hiscore.state = 1
+    screen.indicators.lives.state = 1
+    screen.indicators.speed.state = 1
+    screen.indicators.level.state = 1
+    # wyswietlacze (main, lives, extra)
+    screen.displays.main.clear()
+    screen.displays.main.visibility(True, [0, 2])
+    screen.displays.main.fill((3,6,5,5), 0x81, 0x00ffff, 0)
+    screen.displays.main.fill((0,0,3,3), 0x82, 0xff00ff, 0)
+    screen.displays.main.put_text((3,10,10,4), 'tes t\nabc\n1234567890123456789', 0xffffff, 0)
+    screen.displays.main.copy((1,1,3,3), (3,3), 0)
+    screen.displays.main.copy((3,10,2,2), (7,5), 2, 0)
+    screen.displays.main.put_text((0, 17, 5, 2), 'abcd', 0xff0000, 2)
+    screen.displays.main.map_data((0, 15, 3, 5), imgs.digits[0], layer=0)
+    screen.displays.main.fill((0, 17, 10, 3), 0x82, 0xffffff, 2)
+    screen.displays.lives.clear()
+    screen.displays.lives.visibility(True, 1)
+    screen.displays.lives.fill((0,0,5,5), 0x81, 0x00ffff)
+    screen.displays.extra.clear()
+    screen.displays.extra.visibility(True)
+    screen.displays.extra.fill((0, 0, 4, 3), 0x83, 0xffaa00)
+    screen.displays.extra.map_data((0, 0, 4, 3),((0x8E,0x8B,0x8B,0x8F),(0x8A,None,None,0x8A),(0x8C,0x8B,0x8B,0x8D)))

File BrickGame/src/timer.py

+class Timers(object): # TODO counter for maxFps multiplicity
+    def __init__(self, maxFps):
+        """Initialize timers
+
+        maxFps - game frame rate
+        """
+        self.maxFps = maxFps
+        self.timers = {}
+        self.counter = 0 # counter for ticks
+        self.counter2 = 0 # counter for maxFps multiplicity
+
+    def add_new(self, name, func, fps, rep=0, type='g'):
+        """Add new timer
+
+        name - timer name
+        func - function to run with specified frame rate
+        fps  - frame rate
+        rep  - amount of repetitions
+                0   - run forever
+               >0   - repeat x times
+               <0   - repeat x times when started (created in paused mode)
+               None - run forever when started (created in paused mode)
+        type - timer type
+               s - system timer
+               g - game timer (deleted when game module ends)
+        """
+        #if type(name) != type(''):
+        #    raise TypeError, "timer name must be string"
+        if not callable(func):
+            raise ValueError, "non callable object '%s'" % func.func_name
+        if self.maxFps%fps != 0:
+            raise ValueError, "maxFps=%d must be divisible by fps=%d"%(self.maxFps, fps)
+        if type[0] not in ('g', 's'):
+            raise ValueError, "timer type must be s(system) or g(game)"
+        if type == 'g' and self.timers.has_key(name):
+            raise ValueError, "can't overwrite system timer"
+        self.timers[name] = [func, self.maxFps/fps, rep, type[0]]
+
+    def modify(self, name, func=None, fps=None, rep=False):
+        """Modify timer
+
+        name - timer name
+        func - function to run with specified frame rate (default previous value)
+        fps  - frame rate (default previous value)
+        rep  - amount of repetitions (default previous value)
+                0   - run forever
+               >0   - repeat x times
+               <0   - repeat x times when started (created in paused mode)
+               None - run forever when started (created in paused mode)
+        """
+        tmp_t = self.timers[name]
+        if func is None:
+            func = tmp_t[0]
+        if fps is None:
+            fps = tmp_t[1]
+        if rep == False:
+            rep = tmp_t[2]
+        self.add_new(name, func, fps, rep, tmp_t[3])
+
+    def rem(self, names):
+        """Remove timer
+
+        names - names list or single name used as argument when adding timer
+        """
+        if type(names) == type(str()):
+            names = (names,)
+        for name in names:
+            try:
+                del self.timers[name]
+            except KeyError:
+                pass
+
+    def switch(self, names):
+        """Pause/Unpause timer
+
+        names - names used as argument when adding timer
+        """
+        if type(names) == type(str()):
+            names = (names,)
+        for name in names:
+            try:
+                v = self.timers[name]
+                if v[2] == 0:
+                    v[2] = None
+                elif v[2] is None:
+                    v[2] = 0
+                else:
+                    v[2] = -v[2]
+            except KeyError:
+                pass
+
+    def pause(self, names):
+        """Pause timer
+
+        names - names used as argument when adding timer
+        """
+        if type(names) == type(str()):
+            names = (names,)
+        for name in names:
+            try:
+                v = self.timers[name]
+                if v[2] == 0:
+                    v[2] = None
+                elif v[2] is not None:
+                    v[2] = -abs(v[2])
+            except KeyError:
+                pass
+
+    def unpause(self, names):
+        """Unause timer
+
+        names - names used as argument when adding timer
+        """
+        if type(names) == type(str()):
+            names = (names,)
+        for name in names:
+            try:
+                v = self.timers[name]
+                if v[2] is None:
+                    v[2] = 0
+                else:
+                    v[2] = abs(v[2])
+            except KeyError:
+                pass
+
+    def list_type(self, type):
+        """Generate list of timers with scpecified type
+
+        type - timer type (s / g)
+
+        return - list of timers names
+        """
+        return [k for k,v in self.timers.iteritems() if v[3] == type]
+
+    def tick(self):
+        for k in self.timers.keys():
+            v = self.timers[k]
+            if self.counter % v[1] == 0 and v[2] > -1:
+                v[0]()
+                if v[2] > 1:
+                    v[2] -= 1
+                elif v[2] == 1:
+                    del self.timers[k]
+        self.counter += 1
+        if self.counter == self.maxFps:
+            self.counter = 0
+            self.counter2 += 1
+            if self.counter2 > 100:
+                self.counter2 = 0
+
+    def __getitem__(self, name):
+        return tuple(self.timers[name])

File BrickGame/src/utils.py

+import pygame
+
+def load_image(name, colorkey=None):
+    """load an image
+
+    This will load image and convert pixel format.
+    If colorkey is -1 then transparent pixel will
+    be top left pixel from image. Returns Surface.
+    """
+    #fullname = os.path.join('Images', name)
+    try:
+        image = pygame.image.load(name)
+        if image.get_alpha() is None:
+            image = image.convert()
+        else:
+            image = image.convert_alpha()
+        if colorkey is not None:
+            if colorkey is -1:
+                colorkey = image.get_at((0,0))
+            image.set_colorkey(colorkey, pygame.RLEACCEL)
+    except pygame.error, message:
+        print "Couldn't load image.", name
+        raise SystemExit, message
+    return image, image.get_rect()
+
+def load_sound(name):
+    class NoneSound:
+        def play(self): pass
+    if not pygame.mixer:
+        return NoneSound()
+    #fullname = os.path.join('data', name)
+    try:
+        sound = pygame.mixer.Sound(name)
+    except pygame.error, message:
+        print "Couldn't load sound.", name
+        raise SystemExit, message
+    return sound