Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Aguiar <alanjas@hotmail.com>2012-09-04 03:49:31 (GMT)
committer Alan Aguiar <alanjas@hotmail.com>2012-09-04 03:49:31 (GMT)
commit4455753b87e4301f1085bb144bebc232d11648df (patch)
treec009dd42072e6ae90bd65b5acc5d18dbd55e5461
parent57cab2144a667f7998c6e22243b4202e5d433219 (diff)
add all files v1v1
-rw-r--r--Jump.py1032
-rwxr-xr-xMANIFEST110
-rw-r--r--NEWS0
-rw-r--r--activity.py9
-rw-r--r--activity/activity.info7
-rw-r--r--activity/jump.svg69
-rw-r--r--data/0.oggbin0 -> 22962 bytes
-rw-r--r--data/0.pngbin0 -> 3147 bytes
-rw-r--r--data/0_alpha.pngbin0 -> 780 bytes
-rw-r--r--data/1.oggbin0 -> 22765 bytes
-rw-r--r--data/1.pngbin0 -> 4777 bytes
-rw-r--r--data/10.pngbin0 -> 3107 bytes
-rw-r--r--data/11.pngbin0 -> 2772 bytes
-rw-r--r--data/12.pngbin0 -> 2772 bytes
-rw-r--r--data/13.pngbin0 -> 2936 bytes
-rw-r--r--data/14.pngbin0 -> 2967 bytes
-rw-r--r--data/15.pngbin0 -> 2967 bytes
-rw-r--r--data/16.pngbin0 -> 2840 bytes
-rw-r--r--data/17.pngbin0 -> 3147 bytes
-rw-r--r--data/18.pngbin0 -> 3562 bytes
-rw-r--r--data/19.pngbin0 -> 2533 bytes
-rw-r--r--data/2.oggbin0 -> 20910 bytes
-rw-r--r--data/2.pngbin0 -> 3665 bytes
-rw-r--r--data/20.pngbin0 -> 2724 bytes
-rw-r--r--data/21.pngbin0 -> 3483 bytes
-rw-r--r--data/22.pngbin0 -> 2759 bytes
-rw-r--r--data/23.pngbin0 -> 3022 bytes
-rw-r--r--data/24.pngbin0 -> 4678 bytes
-rw-r--r--data/25.pngbin0 -> 814 bytes
-rw-r--r--data/3.oggbin0 -> 19948 bytes
-rw-r--r--data/3.pngbin0 -> 3617 bytes
-rw-r--r--data/4.oggbin0 -> 23874 bytes
-rw-r--r--data/4.pngbin0 -> 2871 bytes
-rw-r--r--data/5.oggbin0 -> 22270 bytes
-rw-r--r--data/5.pngbin0 -> 3107 bytes
-rw-r--r--data/6.oggbin0 -> 32386 bytes
-rw-r--r--data/6.pngbin0 -> 3107 bytes
-rw-r--r--data/7.oggbin0 -> 33957 bytes
-rw-r--r--data/7.pngbin0 -> 3218 bytes
-rw-r--r--data/8.pngbin0 -> 3617 bytes
-rw-r--r--data/9.pngbin0 -> 2871 bytes
-rw-r--r--data/Arrow.pngbin0 -> 2367 bytes
-rw-r--r--data/Arrow1.pngbin0 -> 2367 bytes
-rw-r--r--data/Arrow2.pngbin0 -> 2373 bytes
-rw-r--r--data/Arrow3.pngbin0 -> 2781 bytes
-rw-r--r--data/Arrow4.pngbin0 -> 2783 bytes
-rw-r--r--data/Background2.pngbin0 -> 208974 bytes
-rw-r--r--data/Flag01.pngbin0 -> 340 bytes
-rw-r--r--data/Flag02.pngbin0 -> 341 bytes
-rw-r--r--data/Flag03.pngbin0 -> 340 bytes
-rw-r--r--data/Flag04.pngbin0 -> 342 bytes
-rw-r--r--data/Flag05.pngbin0 -> 342 bytes
-rw-r--r--data/Flag06.pngbin0 -> 339 bytes
-rw-r--r--data/Flag07.pngbin0 -> 315 bytes
-rw-r--r--data/HelpOff.pngbin0 -> 885 bytes
-rw-r--r--data/HelpOn.pngbin0 -> 1384 bytes
-rw-r--r--data/Instructions.pngbin0 -> 59624 bytes
-rw-r--r--data/NewBoard.pngbin0 -> 2159 bytes
-rw-r--r--data/NewBoardOn.pngbin0 -> 3288 bytes
-rw-r--r--data/S01.pngbin0 -> 4050 bytes
-rw-r--r--data/S02.pngbin0 -> 3561 bytes
-rw-r--r--data/S03.pngbin0 -> 3965 bytes
-rw-r--r--data/S04.pngbin0 -> 2038 bytes
-rw-r--r--data/S05.pngbin0 -> 2739 bytes
-rw-r--r--data/S06.pngbin0 -> 2544 bytes
-rw-r--r--data/S07.pngbin0 -> 3143 bytes
-rw-r--r--data/S08.pngbin0 -> 3324 bytes
-rw-r--r--data/S09.pngbin0 -> 2453 bytes
-rw-r--r--data/S10.pngbin0 -> 3947 bytes
-rw-r--r--data/S11.pngbin0 -> 2703 bytes
-rw-r--r--data/S12.pngbin0 -> 3809 bytes
-rw-r--r--data/S13.pngbin0 -> 2236 bytes
-rw-r--r--data/S14.pngbin0 -> 4420 bytes
-rw-r--r--data/S15.pngbin0 -> 1966 bytes
-rw-r--r--data/S16.pngbin0 -> 3665 bytes
-rw-r--r--data/S17.pngbin0 -> 2435 bytes
-rw-r--r--data/S18.pngbin0 -> 3683 bytes
-rw-r--r--data/S19.pngbin0 -> 4109 bytes
-rw-r--r--data/S20.pngbin0 -> 4052 bytes
-rw-r--r--data/S21.pngbin0 -> 2673 bytes
-rw-r--r--data/S22.pngbin0 -> 1643 bytes
-rw-r--r--data/S23.pngbin0 -> 2616 bytes
-rw-r--r--data/S24.pngbin0 -> 2010 bytes
-rw-r--r--data/S25.pngbin0 -> 3112 bytes
-rw-r--r--data/S26.pngbin0 -> 1962 bytes
-rw-r--r--data/S27.pngbin0 -> 4021 bytes
-rw-r--r--data/S28.pngbin0 -> 1659 bytes
-rw-r--r--data/S29.pngbin0 -> 3439 bytes
-rw-r--r--data/S30.pngbin0 -> 2668 bytes
-rw-r--r--data/S31.pngbin0 -> 4023 bytes
-rw-r--r--data/S32.pngbin0 -> 4519 bytes
-rw-r--r--data/S33.pngbin0 -> 4078 bytes
-rw-r--r--data/S34.pngbin0 -> 3938 bytes
-rw-r--r--data/S35.pngbin0 -> 3724 bytes
-rw-r--r--data/S36.pngbin0 -> 4283 bytes
-rw-r--r--data/blank.pngbin0 -> 221 bytes
-rw-r--r--data/drop.oggbin0 -> 6514 bytes
-rw-r--r--data/newboard.oggbin0 -> 11156 bytes
-rw-r--r--data/pop1.oggbin0 -> 8894 bytes
-rw-r--r--helpers.py20
-rw-r--r--levelBase.py14
-rw-r--r--marble.txt1
-rw-r--r--olpcgames/__init__.py34
-rw-r--r--olpcgames/activity.py142
-rw-r--r--olpcgames/camera.py235
-rw-r--r--olpcgames/canvas.py117
-rw-r--r--olpcgames/eventwrap.py152
-rw-r--r--olpcgames/gtkEvent.py259
-rw-r--r--olpcgames/mesh.py330
-rw-r--r--olpcgames/pangofont.py288
-rw-r--r--olpcgames/tubeconn.py107
-rw-r--r--olpcgames/util.py40
-rw-r--r--olpcgames/video.py71
113 files changed, 3037 insertions, 0 deletions
diff --git a/Jump.py b/Jump.py
new file mode 100644
index 0000000..1be0c91
--- /dev/null
+++ b/Jump.py
@@ -0,0 +1,1032 @@
+#! /usr/bin/env python
+
+'''Authored by Joshua Seaver and Bimal Sadhwani with a big big nod to Natalie Rusk who did the original code in Logo.
+Version .22 added mouse cursor, alpha overlay on whole screen...partially done
+Josh added sound integration---annoying???
+This is the version with a wooden board and a restart button in the lower left and text about marbles left and moves left
+Note too that olpcgames and eventwrap are not enabled...7
+Finally, it would be a good idea to clean out all of the commented out functions that are not being used.'''
+
+#added code for alpha freezing screen: to add - the moves left code and then check if no moves left bring up the screen.
+#-----------------------------------------------------------------------------------------------------------------------
+# IMPORT MODULES
+#-----------------------------------------------------------------------------------------------------------------------
+import sys, pygame
+import random
+from pygame.locals import *
+import levelBase
+from helpers import *
+#from olpcgames import *
+
+#-----------------------------------------------------------------------------------------------------------------------
+# INITIALIZE
+#-----------------------------------------------------------------------------------------------------------------------
+
+pygame.init()
+#eventwrap.install()
+
+#-----------------------------------------------------------------------------------------------------------------------
+# CLASS DEFINITIONS
+#-----------------------------------------------------------------------------------------------------------------------
+BROWN_COLOR = (88, 47, 27)
+doneTest = 0
+global myMatrix
+
+myMatrix = [[2,2,1,1,1,2,2],
+ [2,2,1,1,1,2,2],
+ [1,1,1,1,1,1,1],
+ [1,1,1,0,1,1,1],
+ [1,1,1,1,1,1,1],
+ [2,2,1,1,1,2,2],
+ [2,2,1,1,1,2,2]]
+global myMatrix_colors
+myMatrix_colors=[[0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0]]
+ #[0,0,0,0,0,0,0],
+ #[0,0,0,0,0,0,0]]
+
+myMatrixGridSize = len(myMatrix[0])
+marblesLeft = 0
+movesLeft = 0
+_font = 'VeraSe.ttf'
+color=(0,0,0)
+#color=(255,255,255)
+play_var=0
+button1=None
+helpoff=None
+count=0
+marbleColor=0
+special_x=0
+special_y=0
+next_marble=0
+def load_image(name, colorkey=None):
+
+ fullname = os.path.join('data', name)
+
+ try:
+ image = pygame.image.load(fullname)
+ except pygame.error, message:
+ print 'Cannot load image:', fullname
+ raise SystemExit, message
+ image = image.convert()
+ #image.set_colorkey((0,0,0))
+ image.set_colorkey((255,255,255))
+ return image, image.get_rect()
+
+def load_sound(name):
+
+ """loads a sound file (.ogg) in memory"""
+ class NoneSound:
+ def play(self): pass
+ if not pygame.mixer or not pygame.mixer.get_init():
+ return NoneSound()
+ fullname = os.path.join('data', name)
+ try:
+ sound = pygame.mixer.Sound(fullname)
+ except pygame.error, message:
+ print 'Cannot load sound:', fullname
+ raise SystemExit, message
+ return sound
+
+class board(levelBase.Level):
+
+ def __init__(self):
+ self.RESERVED = 0
+ self.EMPTY = 1
+ self.MARBLE = 2
+
+ def getLayout(self):
+ return [[0,0,2,2,2,0,0],\
+ [0,2,2,2,2,2,0],\
+ [2,2,2,2,2,2,2],\
+ [2,2,2,2,2,2,2],\
+ [2,2,2,2,2,2,2],\
+ [0,2,2,2,2,2,0],\
+ [0,0,2,2,2,0,0]]
+
+
+#need to somehow load in random marble images from data folder
+
+class Marble(pygame.sprite.Sprite):
+
+ def __init__(self, rect=None):
+ pygame.sprite.Sprite.__init__(self)
+ marbleColor = random.random()
+ marbleColor = marbleColor * 10
+ marbleColor = int(marbleColor)
+ if marbleColor > 23:
+ marbleColor = 23
+ pngLoad = str(marbleColor)
+ pngLoad = pngLoad + '.png'
+ self.image, self.rect = load_image(pngLoad,-1)
+
+ if rect != None:
+ self.rect = rect
+
+class simple_button(pygame.sprite.Sprite):
+
+ def __init__(self,x,y,pic,sound):
+ pygame.sprite.Sprite.__init__(self)
+ self.image, self.rect = load_image(pic)
+ self.status = self.down = self.up = 0
+ self.ypos = self.rect.top = y
+ self.xpos = self.rect.left = x
+ self.pressSound = load_sound('newboard.ogg')
+
+ def press(self):
+ self.status = 1
+ self.pressSound.play()
+
+ def unpress(self):
+ self.status = 0
+
+ def update(self):
+ if self.down:
+ self.press()
+ self.down = 0
+ self.screen.blit(self.background,(0,0))
+ elif self.up:
+ self.unpress()
+ self.up = 0
+
+ def is_focused(self):
+ return self.rect.collidepoint(pygame.mouse.get_pos())
+
+class SolitaireMain:
+ def __init__(self, width=1200,height=825):
+ self.width = width
+ self.height = height
+ self.screen = pygame.display.set_mode((self.width, self.height))
+ self.font = pygame.font.Font(None, 50)
+ a=pygame.image.load("data/0.png").convert()
+ a.set_colorkey(color)
+ b=pygame.image.load("data/1.png").convert()
+ b.set_colorkey(color)
+ c=pygame.image.load("data/2.png").convert()
+ c.set_colorkey(color)
+ d=pygame.image.load("data/3.png").convert()
+ d.set_colorkey(color)
+ e=pygame.image.load("data/4.png").convert()
+ e.set_colorkey(color)
+ f=pygame.image.load("data/5.png").convert()
+ f.set_colorkey(color)
+ g=pygame.image.load("data/6.png").convert()
+ g.set_colorkey(color)
+ h=pygame.image.load("data/7.png").convert()
+ h.set_colorkey(color)
+ i=pygame.image.load("data/8.png").convert()
+ i.set_colorkey(color)
+ j=pygame.image.load("data/9.png").convert()
+ j.set_colorkey(color)
+ k=pygame.image.load("data/10.png").convert()
+ k.set_colorkey(color)
+ l=pygame.image.load("data/11.png").convert()
+ l.set_colorkey(color)
+ m=pygame.image.load("data/12.png").convert()
+ m.set_colorkey(color)
+ n=pygame.image.load("data/13.png").convert()
+ n.set_colorkey(color)
+ o=pygame.image.load("data/14.png").convert()
+ o.set_colorkey(color)
+ p=pygame.image.load("data/15.png").convert()
+ p.set_colorkey(color)
+ q=pygame.image.load("data/16.png").convert()
+ q.set_colorkey(color)
+ r=pygame.image.load("data/17.png").convert()
+ r.set_colorkey(color)
+ s=pygame.image.load("data/18.png").convert()
+ s.set_colorkey(color)
+ t=pygame.image.load("data/19.png").convert()
+ t.set_colorkey(color)
+ u=pygame.image.load("data/20.png").convert()
+ u.set_colorkey(color)
+ v=pygame.image.load("data/21.png").convert()
+ v.set_colorkey(color)
+ w=pygame.image.load("data/22.png").convert()
+ w.set_colorkey(color)
+ x=pygame.image.load("data/23.png").convert()
+ x.set_colorkey(color)
+ y=pygame.image.load("data/24.png").convert()
+ y.set_colorkey(color)
+ bl=pygame.image.load("data/blank.png")
+ z=pygame.image.load("data/25.png")
+
+
+ self.marble_images=[]
+ self.marble_images.append(a)
+ self.marble_images.append(b)
+ self.marble_images.append(c)
+ self.marble_images.append(d)
+ self.marble_images.append(e)
+ self.marble_images.append(f)
+ self.marble_images.append(g)
+ self.marble_images.append(h)
+ self.marble_images.append(i)
+ self.marble_images.append(j)
+ self.marble_images.append(k)
+ self.marble_images.append(l)
+ self.marble_images.append(m)
+ self.marble_images.append(n)
+ self.marble_images.append(o)
+ self.marble_images.append(p)
+ self.marble_images.append(q)
+ self.marble_images.append(r)
+ self.marble_images.append(s)
+ self.marble_images.append(t)
+ self.marble_images.append(u)
+ self.marble_images.append(v)
+ self.marble_images.append(w)
+ self.marble_images.append(x)
+ self.marble_images.append(y)
+ self.marble_images.append(bl)#number25
+ self.marble_images.append(z)
+
+ #special marbles
+ a=pygame.image.load("data/S08.png").convert()
+ b=pygame.image.load("data/S21.png").convert()
+ c=pygame.image.load("data/S03.png").convert()
+ d=pygame.image.load("data/S04.png").convert()
+ e=pygame.image.load("data/S05.png").convert()
+ f=pygame.image.load("data/S06.png").convert()
+ g=pygame.image.load("data/S07.png").convert()
+ h=pygame.image.load("data/S08.png").convert()
+ i=pygame.image.load("data/S09.png").convert()
+ j=pygame.image.load("data/S10.png").convert()
+ k=pygame.image.load("data/S11.png").convert()
+ l=pygame.image.load("data/S12.png").convert()
+ m=pygame.image.load("data/S13.png").convert()
+ n=pygame.image.load("data/S14.png").convert()
+ o=pygame.image.load("data/S15.png").convert()
+ p=pygame.image.load("data/S16.png").convert()
+ q=pygame.image.load("data/S17.png").convert()
+ r=pygame.image.load("data/S18.png").convert()
+ s=pygame.image.load("data/S19.png").convert()
+ t=pygame.image.load("data/S20.png").convert()
+ u=pygame.image.load("data/S21.png").convert()
+ v=pygame.image.load("data/S22.png").convert()
+ w=pygame.image.load("data/S23.png").convert()
+ x=pygame.image.load("data/S24.png").convert()
+ y=pygame.image.load("data/S25.png").convert()
+ z=pygame.image.load("data/S26.png").convert()
+ aa=pygame.image.load("data/S27.png").convert()
+ ab=pygame.image.load("data/S28.png").convert()
+ ac=pygame.image.load("data/S29.png").convert()
+ ad=pygame.image.load("data/S30.png").convert()
+ ae=pygame.image.load("data/S31.png").convert()
+ af=pygame.image.load("data/S32.png").convert()
+ ag=pygame.image.load("data/S33.png").convert()
+ ah=pygame.image.load("data/S34.png").convert()
+ ai=pygame.image.load("data/S35.png").convert()
+ aj=pygame.image.load("data/S36.png").convert()
+
+ self.special_marbles=[]
+ self.special_marbles.append(a)
+ self.special_marbles.append(b)
+ self.special_marbles.append(c)
+ self.special_marbles.append(d)
+ self.special_marbles.append(e)
+ self.special_marbles.append(f)
+ self.special_marbles.append(g)
+ self.special_marbles.append(h)
+ self.special_marbles.append(i)
+ self.special_marbles.append(j)
+ self.special_marbles.append(k)
+ self.special_marbles.append(l)
+ self.special_marbles.append(m)
+ self.special_marbles.append(n)
+ self.special_marbles.append(o)
+ self.special_marbles.append(p)
+ self.special_marbles.append(q)
+ self.special_marbles.append(r)
+ self.special_marbles.append(s)
+ self.special_marbles.append(t)
+ self.special_marbles.append(u)
+ self.special_marbles.append(v)
+ self.special_marbles.append(w)
+ self.special_marbles.append(x)
+ self.special_marbles.append(y)
+ self.special_marbles.append(z)
+ self.special_marbles.append(aa)
+ self.special_marbles.append(ab)
+ self.special_marbles.append(ac)
+ self.special_marbles.append(ad)
+ self.special_marbles.append(ae)
+ self.special_marbles.append(af) #no 31
+ self.special_marbles.append(bl) #no 32
+ self.special_marbles.append(ag)
+ self.special_marbles.append(ah)
+ self.special_marbles.append(ai)
+ self.special_marbles.append(aj)
+
+ #call reset funnction
+ self.reset()
+ self.helpscreen = pygame.image.load("data/Instructions.png")
+ self.flags=[]
+ self.flags.append(pygame.image.load("data/Flag01.png").convert())
+ self.flags.append(pygame.image.load("data/Flag02.png").convert())
+ self.flags.append(pygame.image.load("data/Flag03.png").convert())
+ self.flags.append(pygame.image.load("data/Flag04.png").convert())
+ self.flags.append(pygame.image.load("data/Flag05.png").convert())
+ self.flags.append(pygame.image.load("data/Flag06.png").convert())
+ self.flags.append(pygame.image.load("data/Flag07.png").convert())
+
+
+ self.level_sounds=[]
+ self.level_sounds.append(load_sound('0.ogg'))
+ self.level_sounds.append(load_sound('1.ogg'))
+ self.level_sounds.append(load_sound('2.ogg'))
+ self.level_sounds.append(load_sound('3.ogg'))
+ self.level_sounds.append(load_sound('4.ogg'))
+ self.level_sounds.append(load_sound('5.ogg'))
+ self.level_sounds.append(load_sound('6.ogg'))
+ self.level_sounds.append(load_sound('7.ogg'))
+
+ def reset(self):
+ global marbleColor
+ #intialisation of Number for the first time ..keep a balnk png.
+ self.updated_text=32
+ self.updated_moves=4
+ self.Number=25# 26 #25
+ self.pressed=False
+ self.selected= False
+ self.initial_x=0
+ self.initial_y=0
+
+ self.final_x=0
+ self.final_y=0
+ self.OutofRange=True
+
+ self.clickedOnce=False
+ self.attached=False
+ self.picked=False
+ marbleColor=0
+ def reset_board(self):
+
+ global myMatrix
+ myMatrix=[[2,2,1,1,1,2,2],
+ [2,2,1,1,1,2,2],
+ [1,1,1,1,1,1,1],
+ [1,1,1,0,1,1,1],
+ [1,1,1,1,1,1,1],
+ [2,2,1,1,1,2,2],
+ [2,2,1,1,1,2,2]]
+
+ global myMatrix_colors
+ myMatrix_colors=[[0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0]]
+
+
+ def checkValidMovement(self):
+ global marbleColor
+ temp=pygame.mouse.get_pos()
+ #print temp
+ x=temp[0]
+ y=temp[1]
+ x=x-300
+
+ x/=90
+ y-=120
+
+ y/=90
+
+ if(x>=0 and x<=6 and y>=0 and y<=6):
+
+ if(myMatrix[y][x]==0):
+ self.final_x=y
+ self.final_y=x
+ else:
+ self.OutofRange=True
+ self.final_x=0
+ self.final_y=0
+
+
+ if(self.initial_x ==0 and self.initial_y ==0):
+ self.OutofRange=False
+
+ w=self.initial_x
+ x=self.initial_y
+ self.wInput=self.initial_x
+ self.xInput=self.initial_y
+
+ y=self.final_x
+ z=self.final_y
+
+ self.yInput=self.final_x
+ self.zInput=self.final_y
+ neighborState = 99
+ neighborStateRow = 99
+ neighborStateColumn = 99
+ validJump = 99
+ self.matrixPosStart=myMatrix[w][x]
+ self.matrixPosEnd=myMatrix[y][z]
+
+ if w == y:
+ if x > z:
+ neighborStateRow = w
+ neighborStateColumn = x - 1
+ neighborState = myMatrix[neighborStateRow][neighborStateColumn]
+ if (self.xInput - self.zInput) > 2:
+ validJump = 0
+ else:
+ validJump = 1
+ elif x<z:
+ neighborStateRow = w
+ neighborStateColumn = x + 1
+ neighborState = myMatrix[neighborStateRow][neighborStateColumn]
+ if (self.zInput - self.xInput) > 2:
+ validJump = 0
+ else:
+ validJump = 1
+ elif x==z:
+
+ if w > y:
+ neighborStateRow = w - 1
+ neighborStateColumn = x
+ neighborState = myMatrix[neighborStateRow][neighborStateColumn]
+ if (self.wInput - self.yInput) > 2:
+ validJump = 0
+ else:
+ validJump = 1
+ elif w<y:
+ neighborStateRow = w + 1
+ neighborStateColumn = x
+ neighborState = myMatrix[neighborStateRow][neighborStateColumn]
+ if (self.yInput - self.wInput) > 2:
+ validJump = 0
+ else:
+ validJump = 1
+
+ if(validJump==99 and self.initial_x>0 and self.initial_y>0):
+ self.OutofRange=True
+
+ if self.matrixPosStart != 2 and self.matrixPosEnd == 0 and neighborState == 1 and validJump == 1:
+ myMatrix[w][x] = 0
+ myMatrix[neighborStateRow][neighborStateColumn] = 0
+ myMatrix[y][z] = 1
+ myMatrix_colors[y][z]=myMatrix_colors[w][x]
+ #test playing sound here
+ moveSound = load_sound('drop.ogg')
+ moveSound.play()
+
+ else:
+ if(self.OutofRange==True):
+ myMatrix[w][x]=1
+
+ self.screen.blit(self.background,(0,0))
+ row=106
+ for k in range(7):
+ start=292
+ for i in range(7):
+ self.pngNumber=myMatrix_colors[k][i]
+
+ if(myMatrix[k][i]==1):
+ if self.pngNumber==marbleColor:
+ self.screen.blit(self.marble_images[self.pngNumber],(start,row))
+ else:
+
+ self.pngNumber-=100
+ self.screen.blit(self.special_marbles[self.pngNumber],(start,row))
+
+ start+=90
+ row+=90
+
+ #reseting the values back
+ self.OutofRange=True
+ self.initial_x=0
+ self.initial_y=0
+ self.update_moves()
+ self.display()
+
+ def changePosition(self):
+ global marbleColor,special_x,special_y
+ self.x=pygame.mouse.get_pos()
+ x=self.x[0]
+ y=self.x[1]
+ x=(x/90)-(300/90)
+ y=(y/90)-(120/90)
+ #self.Number=0
+
+ #print "marble color is :",marbleColor
+ if(x>=0 and x<7 and y>=0 and y<7):
+ if self.pressed==False and myMatrix[y][x]==1:
+ myMatrix[y][x]=0
+ self.Number=myMatrix_colors[y][x]
+
+ if self.Number>=100:
+ special_x=y
+ special_y=x
+
+ self.initial_x=y
+ self.initial_y=x
+
+ self.selected=True
+ self.pressed=True
+ if self.Number==marbleColor:
+ self.marble_rect=self.marble_images[self.Number].get_rect()
+ elif self.Number==25:
+ self.marble_rect=self.marble_images[self.Number].get_rect()
+ else:
+ self.marble_rect=self.special_marbles[self.Number-100].get_rect()
+
+ self.marble_rect.center=pygame.mouse.get_pos()
+ self.screen.blit(self.background,(0,0))
+
+
+ row=106
+ for k in range(7):
+ start=292
+ for i in range(7):
+ self.pngNumber=myMatrix_colors[k][i]
+
+ if(myMatrix[k][i]==1):
+
+ if self.pngNumber==marbleColor:
+ self.screen.blit(self.marble_images[self.pngNumber],(start,row))
+
+ else:
+ self.pngNumber-=100
+
+ self.screen.blit(self.special_marbles[self.pngNumber],(start,row))
+ start+=90
+ row+=90
+
+
+ if self.Number==marbleColor:
+ self.screen.blit(self.marble_images[self.Number],self.marble_rect)
+ elif self.Number==25:
+ self.screen.blit(self.marble_images[self.Number],self.marble_rect)
+ else:
+
+ self.screen.blit(self.special_marbles[self.Number-100],self.marble_rect)
+
+ def moving(self):
+ row=90
+ self.screen.blit(self.background,self.marble_rect,self.marble_rect)
+
+ self.marble_rect.center=pygame.mouse.get_pos()
+ self.screen.blit(self.marble_images[self.Number],self.marble_rect)
+ def noMoreMoves(self):
+ global button1
+ rollover_once=0
+ run=1
+ self.alphasurface = pygame.Surface((1280,825))
+ self.alphasurface.convert()
+ self.alphasurfacerect = pygame.Rect(0,0,1280,825)
+ self.alphasurface.fill((100,100,100))
+ self.alphasurface.set_alpha(200)
+ self.screen.blit(self.background, (0,0))
+ row=106
+ for k in range(7):
+ start=292
+ for i in range(7):
+ self.pngNumber=myMatrix_colors[k][i]
+ if(myMatrix[k][i]==1):
+ if self.pngNumber==marbleColor:
+ self.screen.blit(self.marble_images[self.pngNumber],(start,row))
+ else:
+ self.pngNumber-=100
+ self.screen.blit(self.special_marbles[self.pngNumber],(start,row))
+ start+=90
+ row+=90
+
+ self.display()
+ self.screen.blit(self.alphasurface,self.alphasurfacerect)
+
+ while run:
+ for event in pygame.event.get():
+
+ if event.type == QUIT or (event.type == KEYDOWN and
+ event.key in [K_ESCAPE]):sys.exit()
+
+
+ elif event.type == MOUSEBUTTONDOWN:
+ if button1.is_focused():
+ button1.press()
+ elif event.type == MOUSEBUTTONUP:
+ if button1.status == 1:
+ button1.unpress()
+ self.play_var = 1
+ run = 0
+
+ if self.play_var==1:
+ self.play_var=0
+ self.reset()
+ self.reset_board()
+ self.SuperLooper()
+
+ if (button1.rect.collidepoint(pygame.mouse.get_pos()) and rollover_once==0):
+ rollover_once=1
+ self.allsprites.remove(button1)
+ button1 = simple_button(31,614,'NewBoardOn.png',None)
+ self.allsprites=pygame.sprite.RenderPlain(button1)
+ self.allsprites.draw(self.screen)
+ elif not (button1.rect.collidepoint(pygame.mouse.get_pos())):
+ rollover_once=0
+ button1 = simple_button(31,614,'NewBoard.png',None)
+ self.allsprites=pygame.sprite.RenderPlain(button1)
+ self.allsprites.draw(self.screen)
+ pygame.display.update()
+
+ def SuperLooper(self):
+
+ global button1,helpoff,marbleColor,next_marble,count
+ rollover_once=0
+ run=1
+ self.background = pygame.image.load("data/Background2.png")
+ self.play_var=0
+ self.help_var=0
+ self.play_sound=False
+ self.pickedSound=0
+ pygame.mouse.set_cursor((32, 32), (0, 0), (0, 0, 0, 0, 0, 0, 0, 0, 31, 255, 255, 224, 31, 255, 255, 248, 31, 255, 255, 248, 31, 255, 255, 248, 31, 255, 255, 248, 31, 255, 255, 248, 31, 255, 255, 240, 31, 252, 0, 0, 31, 254, 0, 0, 31, 255, 0, 0, 31, 255, 128, 0, 31, 255, 192, 0, 31, 191, 224, 0, 31, 159, 240, 0, 31, 143, 248, 0, 31, 135, 252, 0, 31, 131, 254, 0, 31, 129, 255, 0, 31, 128, 255, 128, 31, 128, 127, 192, 31, 128, 63, 224, 31, 128, 31, 240, 31, 128, 15, 248, 31, 128, 7, 248, 31, 128, 3, 248, 31, 128, 1, 248, 15, 0, 0, 248, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0), (0, 0, 0, 0, 127, 255, 255, 248, 127, 255, 255, 252, 127, 255, 255, 254, 127, 255, 255, 254, 127, 255, 255, 254, 127, 255, 255, 254, 127, 255, 255, 254, 127, 255, 255, 252, 127, 255, 255, 252, 127, 255, 255, 240, 127, 255, 192, 0, 127, 255, 224, 0, 127, 255, 240, 0, 127, 255, 248, 0, 127, 255, 252, 0, 127, 255, 254, 0, 127, 255, 255, 0, 127, 255, 255, 128, 127, 239, 255, 192, 127, 231, 255, 224, 127, 227, 255, 240, 127, 225, 255, 248, 127, 224, 255, 252, 127, 224, 127, 254, 127, 224, 63, 254, 127, 224, 31, 254, 127, 192, 15, 254, 127, 192, 7, 254, 63, 128, 3, 252, 15, 0, 1, 248, 0, 0, 0, 0))
+ group=[]
+ empty=()
+ self.displaying_arrow=False
+ self.screen.blit(self.background, (0,0))
+
+ button1 = simple_button(31,614,'NewBoard.png',None)
+ self.allsprites=pygame.sprite.RenderPlain(button1)
+ self.allsprites.empty()
+ self.allsprites.draw(self.screen)
+ helpoff=simple_button(970,614,'HelpOff.png',None)
+ self.allspritess=pygame.sprite.RenderPlain(helpoff)
+ self.LoadSprites()
+ self.marble_rect=self.marble_images[self.Number].get_rect()
+ self.marble_rect.center=pygame.mouse.get_pos()
+
+ #onscreen text
+ marble_text = self.font.render(str(self.updated_text), 1, BROWN_COLOR)
+ marble_textpos = marble_text.get_rect(topleft=(1000,50))
+ #self.screen.blit(marble_text, marble_textpos)
+
+ self.screen.blit(self.special_marbles[next_marble-1],(1067,45))
+
+ self.rollover_images=[]
+ self.rollover_images.append(pygame.image.load("data/Arrow1.png"))
+ self.rollover_images.append(pygame.image.load("data/Arrow2.png"))
+ self.rollover_images.append(pygame.image.load("data/Arrow3.png"))
+ self.rollover_images.append(pygame.image.load("data/Arrow4.png"))
+ pygame.display.update()
+
+ while run:
+ #condition for checking for mouse arrows
+ if(self.updated_text==32):
+ if (self.displaying_arrow==False and pygame.mouse.get_pos()[0]>=550 and pygame.mouse.get_pos()[0]<=625
+ and pygame.mouse.get_pos()[1]>=550 and pygame.mouse.get_pos()[1]<=625):
+ self.screen.blit(self.rollover_images[3],(520,380))
+ self.displaying_arrow=True
+
+ if (self.displaying_arrow==False and pygame.mouse.get_pos()[0]>=550 and pygame.mouse.get_pos()[0]<=625
+ and pygame.mouse.get_pos()[1]>=175 and pygame.mouse.get_pos()[1]<=275):
+ self.screen.blit(self.rollover_images[2],(550,200))
+ self.displaying_arrow=True
+
+ if (self.displaying_arrow==False and pygame.mouse.get_pos()[0]>=400 and pygame.mouse.get_pos()[0]<=450
+ and pygame.mouse.get_pos()[1]>=375 and pygame.mouse.get_pos()[1]<=425):
+ self.screen.blit(self.rollover_images[1],(400,350))
+ self.displaying_arrow=True
+
+ if (self.displaying_arrow==False and pygame.mouse.get_pos()[0]>=700 and pygame.mouse.get_pos()[0]<=800
+ and pygame.mouse.get_pos()[1]>=375 and pygame.mouse.get_pos()[1]<=450):
+ self.screen.blit(self.rollover_images[0],(550,350))
+ self.displaying_arrow=True
+
+
+ if (button1.rect.collidepoint(pygame.mouse.get_pos()) and rollover_once==0):
+ rollover_once=1
+ self.allsprites.remove(button1)
+ button1 = simple_button(31,614,'NewBoardOn.png',None)
+ self.allsprites=pygame.sprite.RenderPlain(button1)
+ self.allsprites.draw(self.screen)
+
+ elif not (button1.rect.collidepoint(pygame.mouse.get_pos())):
+ rollover_once=0
+ self.allsprites.empty()
+ button1 = simple_button(31,614,'NewBoard.png',None)
+ self.allsprites=pygame.sprite.RenderPlain(button1)
+ self.allsprites.draw(self.screen)
+
+ if (helpoff.rect.collidepoint(pygame.mouse.get_pos()) and rollover_onces==0):
+ rollover_onces=1
+ self.allspritess.remove(button1)
+ helpoff = simple_button(970,614,'HelpOn.png',None)
+ self.allspritess=pygame.sprite.RenderPlain(helpoff)
+ self.allspritess.draw(self.screen)
+
+ elif not (helpoff.rect.collidepoint(pygame.mouse.get_pos())):
+
+ rollover_onces=0
+ helpoff = simple_button(970,614,'HelpOff.png',None)
+ self.allspritess=pygame.sprite.RenderPlain(helpoff)
+ self.allspritess.draw(self.screen)
+ temp_pos=pygame.mouse.get_pressed()
+ if temp_pos[0]==0 and self.selected==True and self.pressed==True:
+ self.pressed=False
+ self.selected=False
+ self.checkValidMovement()
+ self.Number=25#26 25
+ self.picked=False
+ self.displaying_arrow=False
+ '''Change the cursor to an arrow'''
+ pygame.mouse.set_cursor((32, 32), (0, 0), (0, 0, 0, 0, 0, 0, 0, 0, 31, 255, 255, 224, 31, 255, 255, 248, 31, 255, 255, 248, 31, 255, 255, 248, 31, 255, 255, 248, 31, 255, 255, 248, 31, 255, 255, 240, 31, 252, 0, 0, 31, 254, 0, 0, 31, 255, 0, 0, 31, 255, 128, 0, 31, 255, 192, 0, 31, 191, 224, 0, 31, 159, 240, 0, 31, 143, 248, 0, 31, 135, 252, 0, 31, 131, 254, 0, 31, 129, 255, 0, 31, 128, 255, 128, 31, 128, 127, 192, 31, 128, 63, 224, 31, 128, 31, 240, 31, 128, 15, 248, 31, 128, 7, 248, 31, 128, 3, 248, 31, 128, 1, 248, 15, 0, 0, 248, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0), (0, 0, 0, 0, 127, 255, 255, 248, 127, 255, 255, 252, 127, 255, 255, 254, 127, 255, 255, 254, 127, 255, 255, 254, 127, 255, 255, 254, 127, 255, 255, 254, 127, 255, 255, 252, 127, 255, 255, 252, 127, 255, 255, 240, 127, 255, 192, 0, 127, 255, 224, 0, 127, 255, 240, 0, 127, 255, 248, 0, 127, 255, 252, 0, 127, 255, 254, 0, 127, 255, 255, 0, 127, 255, 255, 128, 127, 239, 255, 192, 127, 231, 255, 224, 127, 227, 255, 240, 127, 225, 255, 248, 127, 224, 255, 252, 127, 224, 127, 254, 127, 224, 63, 254, 127, 224, 31, 254, 127, 192, 15, 254, 127, 192, 7, 254, 63, 128, 3, 252, 15, 0, 1, 248, 0, 0, 0, 0))
+ self.pickedSound=0
+
+ if temp_pos[0]==1 : #and self.picked==False:
+ '''Change the cursor to an X'''
+ pygame.mouse.set_cursor((32, 32), (0, 0), (0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 16, 62, 0, 0, 120, 63, 0, 0, 252, 63, 128, 1, 252, 31, 192, 3, 248, 15, 224, 7, 240, 7, 240, 15, 224, 3, 248, 31, 192, 1, 252, 63, 128, 0, 254, 127, 0, 0, 127, 254, 0, 0, 63, 252, 0, 0, 31, 248, 0, 0, 15, 240, 0, 0, 15, 240, 0, 0, 31, 248, 0, 0, 63, 252, 0, 0, 127, 254, 0, 0, 254, 127, 0, 1, 252, 63, 128, 3, 248, 31, 192, 7, 240, 15, 224, 15, 224, 7, 240, 31, 192, 3, 248, 63, 128, 1, 252, 63, 0, 0, 252, 30, 0, 0, 124, 8, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0), (28, 0, 0, 16, 62, 0, 0, 124, 127, 0, 0, 254, 255, 128, 1, 254, 255, 192, 3, 255, 255, 224, 7, 254, 127, 240, 15, 254, 63, 248, 31, 252, 31, 252, 63, 248, 15, 254, 127, 240, 7, 255, 255, 224, 3, 255, 255, 192, 1, 255, 255, 128, 0, 255, 255, 0, 0, 127, 254, 0, 0, 63, 252, 0, 0, 63, 252, 0, 0, 127, 254, 0, 0, 255, 255, 0, 1, 255, 255, 128, 3, 255, 255, 192, 7, 255, 255, 224, 15, 254, 127, 240, 31, 252, 63, 248, 63, 248, 31, 252, 127, 240, 15, 254, 127, 224, 7, 255, 255, 192, 3, 255, 127, 128, 1, 255, 127, 0, 0, 254, 62, 0, 0, 124, 8, 0, 0, 56))
+ self.picked=True
+ pickedSound = load_sound('pop1.ogg')
+ if self.pickedSound == 0:
+ pickedSound.play()
+ self.pickedSound=1
+ self.changePosition()
+ self.display()
+
+ for event in pygame.event.get():
+ if event.type == QUIT or (event.type == KEYDOWN and
+ event.key in [K_ESCAPE]):sys.exit()
+
+
+ elif event.type == MOUSEBUTTONDOWN:
+ if button1.is_focused():
+ button1.press()
+ elif helpoff.is_focused():
+ helpoff.press()
+ elif event.type == MOUSEBUTTONUP:
+ if button1.status == 1:
+ button1.unpress()
+ self.play_var = 1
+ run=0
+ elif helpoff.status == 1:
+ helpoff.unpress()
+ self.help_var = 1
+ #run=0
+
+ if self.play_var==1:
+ self.play_var=0
+ self.reset()
+ self.reset_board()
+ self.SuperLooper()
+ if self.help_var==1:
+ self.help_var=0
+ self.help_screen()
+
+ pygame.display.update()
+
+ if self.updated_text==28 and self.play_sound==False and count==0:
+ self.level_sounds[0].play()
+ count+=1
+ self.play_sound=True
+ elif self.updated_text==24 and self.play_sound==False and count==1:
+ self.level_sounds[1].play()
+ self.play_sound=False
+ count+=1
+ elif self.updated_text==20 and self.play_sound==False and count==2:
+ self.level_sounds[2].play()
+ self.play_sound=True
+ count+=1
+ elif self.updated_text==16 and self.play_sound==False and count==3:
+ self.level_sounds[3].play()
+ self.play_sound=True
+ count+=1
+ elif self.updated_text==12 and self.play_sound==False and count==4:
+ self.level_sounds[4].play()
+ self.play_sound=True
+ count+=1
+ elif self.updated_text==8 and self.play_sound==False and count==5:
+ self.level_sounds[5].play()
+ self.play_sound=True
+ count+=1
+ elif self.updated_text==4 and self.play_sound==False and count==6:
+ self.level_sounds[6].play()
+ self.play_sound=True
+ count+=1
+
+ if self.updated_moves==0:
+ if self.updated_text==1:
+ self.level_sounds[7].play()
+ f = open("marble.txt","r")
+ number=f.readline()
+ f.close()
+ number=int(number)
+ if number>=0:
+ p=open("marble.txt","w")
+ number+=1
+ number=str(number)
+ p.write(number)
+ p.close()
+ run=0
+ self.noMoreMoves()
+
+ def help_screen(self):
+
+ run=True
+ self.alphasurface = pygame.Surface((1280,825))
+ self.alphasurface.convert()
+ self.alphasurfacerect = pygame.Rect(0,0,1280,825)
+ self.alphasurface.fill((100,100,100))
+ self.alphasurface.set_alpha(200)
+ self.screen.blit(self.alphasurface,self.alphasurfacerect)
+ self.screen.blit(self.helpscreen,(0,0))
+ pygame.display.update()
+ while run:
+
+ for event in pygame.event.get():
+
+ if event.type == KEYDOWN or event.type == MOUSEBUTTONDOWN:
+ run =0
+
+
+ def update_moves(self):
+ marblesLeft = 0
+ movesLeft = 0
+ i = 0
+ while i < myMatrixGridSize: # should eventually be length of rows
+ j = 0
+ while j < myMatrixGridSize: # should eventually be length of columns
+ m = myMatrix[i][j]
+ if m == 1: # there is a marble in the slot
+ marblesLeft = marblesLeft + 1
+ boundsCheck = i - 1
+ if boundsCheck >= 0:
+ mn = myMatrix[i -1][j]
+ if mn == 0: # no move directly above
+ pass
+ else:
+ pass
+ boundsCheck = i - 2
+ if boundsCheck >= 0:
+ mn = myMatrix[i - 2][j]
+ mn2 = myMatrix[i - 1][j]
+ if mn == 0 and mn2 == 1:
+ #print "There is a move above."
+ movesLeft = movesLeft + 1
+ else:
+ pass
+ else: # there is a move above, but is the slot above that empty
+ pass
+ boundsCheck = i + 1
+ if boundsCheck < myMatrixGridSize: # needs to be drawn from the number of rows eventually
+ mn = myMatrix[i + 1][j]
+ if mn == 0: # no move directly below
+ pass
+ else:
+ pass
+ boundsCheck = i + 2
+ if boundsCheck < myMatrixGridSize:
+ mn = myMatrix[i + 2][j]
+ mn2 = myMatrix[i + 1][j]
+ if mn == 0 and mn2 == 1:
+ movesLeft = movesLeft + 1
+ else:
+ pass
+ else: # there is a move below, but is the slot below that empty
+ pass
+ boundsCheck = j - 1
+ if boundsCheck >= 0: # needs to be drawn from the number of rows eventually
+ mn = myMatrix[i][j - 1]
+ if mn == 0: # no move directly to the left
+ pass
+ else:
+ pass
+ boundsCheck = j - 2
+ if boundsCheck >= 0:
+ mn = myMatrix[i][j - 2]
+ mn2 = myMatrix[i][j - 1]
+ if mn == 0 and mn2 == 1:
+ movesLeft = movesLeft + 1
+ else:
+ pass
+ else: # there is a move below, but is the slot below that empty
+ pass
+ #check right
+ boundsCheck = j + 1
+ if boundsCheck < myMatrixGridSize: # needs to be drawn from the number of rows eventually
+ mn = myMatrix[i][j + 1]
+ if mn == 0: # no move directly to the right
+ pass
+ else:
+ pass
+ boundsCheck = j + 2
+ if boundsCheck < myMatrixGridSize:
+ mn = myMatrix[i][j + 2]
+ mn2 = myMatrix[i][j + 1]
+ if mn == 0 and mn2 == 1:
+ movesLeft = movesLeft + 1
+ else:
+ pass
+ else: # there is a move below, but is the slot below that empty
+ pass
+ else: # There is no marble in the slot
+ pass
+
+
+ j = j + 1
+ i = i + 1
+
+ self.updated_text=marblesLeft
+
+ self.updated_moves= movesLeft
+ return
+
+ def display(self):
+ global button1,helpoff,next_marble
+ marble_text = self.font.render(str(self.updated_text), 1, BROWN_COLOR)
+ marble_textpos = marble_text.get_rect(topleft=(1000,50))
+ #self.screen.blit(marble_text, marble_textpos)
+ #flag conditions
+ if(self.updated_text<=28 and self.updated_text>24):# and count==0):
+ self.screen.blit(self.flags[0],(1038,110))
+
+ elif(self.updated_text<=24 and self.updated_text>20):# and count==2):
+ self.screen.blit(self.flags[1], (1038,110))
+ self.play_sound=False
+ elif(self.updated_text<=20 and self.updated_text>16):
+ self.screen.blit(self.flags[2], (1038,110))
+ self.play_sound=False
+ elif(self.updated_text<=16 and self.updated_text>12):
+ self.screen.blit(self.flags[3],(1038,110))
+ self.play_sound=False
+ elif(self.updated_text<=12 and self.updated_text>8):
+ self.screen.blit(self.flags[4],(1038,110))
+ self.play_sound=False
+ elif(self.updated_text<=8 and self.updated_text>4):
+ self.screen.blit(self.flags[5],(1038,110))
+ self.play_sound=False
+ elif(self.updated_text<=4 and self.updated_text>1):
+ self.screen.blit(self.flags[6], (1038,110))
+ self.play_sound=False
+
+ self.screen.blit(self.special_marbles[next_marble-1],(1067,45))
+ self.allsprites.draw(self.screen)
+ if self.updated_moves>0:
+ self.allspritess.draw(self.screen)
+
+ def LoadSprites(self):
+ global marbleColor,next_marble
+ """Create the Marbles group"""
+ n=7
+ row=106 #120
+
+ marbleColor = random.randrange(0,23)
+ f = open("marble.txt","r")
+ number=f.readline()
+ f.close()
+ number=int(number)
+ if number>32:
+ number=32
+
+ next_marble=number+1
+ j=0
+ start=292
+ row=106
+ if number>0:
+ while j !=(number):
+ pngNumber=j
+ xtemp = random.randrange(0,7)
+ ytemp = random.randrange(0,7)
+ print pngNumber,xtemp,ytemp
+
+ if(myMatrix[xtemp][ytemp]==1):
+ myMatrix_colors[xtemp][ytemp]=pngNumber+100
+ self.screen.blit(self.special_marbles[pngNumber],(start+(ytemp*90),row+(xtemp*90)))
+ myMatrix[xtemp][ytemp]=3
+ j+=1
+
+ row=106
+ #function for generating the dots using matrix method
+ for k in range(7):
+ start=292
+ for i in range(7):
+ if(myMatrix[k][i]==1):
+ pngNumber=marbleColor
+ myMatrix_colors[k][i]=pngNumber
+ self.screen.blit(self.marble_images[pngNumber],(start,row))
+ start+=90
+ row+=90
+
+
+ for k in range(7):
+ for i in range(7):
+ if(myMatrix[k][i]==3):
+ myMatrix[k][i]=1
+
+
+
+def main():
+ MainWindow = SolitaireMain()
+ MainWindow.SuperLooper()
+
+if __name__=="__main__":
+ main() \ No newline at end of file
diff --git a/MANIFEST b/MANIFEST
new file mode 100755
index 0000000..3309c6c
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,110 @@
+marble.txt
+activity.py
+helpers.py
+levelBase.py
+Jump.py
+olpcgames/canvas.py
+olpcgames/video.py
+olpcgames/gtkEvent.py
+olpcgames/__init__.py
+olpcgames/eventwrap.py
+olpcgames/util.py
+olpcgames/camera.py
+olpcgames/tubeconn.py
+olpcgames/pangofont.py
+olpcgames/activity.py
+olpcgames/eventwrap.py
+olpcgames/mesh.py
+data/blank.png
+data/0.png
+data/1.png
+data/2.png
+data/3.png
+data/4.png
+data/5.png
+data/6.png
+data/7.png
+data/8.png
+data/9.png
+data/10.png
+data/11.png
+data/12.png
+data/13.png
+data/14.png
+data/15.png
+data/16.png
+data/17.png
+data/18.png
+data/19.png
+data/20.png
+data/21.png
+data/22.png
+data/23.png
+data/24.png
+data/25.png
+data/S01.png
+data/S02.png
+data/S03.png
+data/S04.png
+data/S05.png
+data/S06.png
+data/S07.png
+data/S08.png
+data/S09.png
+data/S10.png
+data/S11.png
+data/S12.png
+data/S13.png
+data/S14.png
+data/S15.png
+data/S16.png
+data/S17.png
+data/S18.png
+data/S19.png
+data/S20.png
+data/S21.png
+data/S22.png
+data/S23.png
+data/S24.png
+data/S25.png
+data/S26.png
+data/S27.png
+data/S28.png
+data/S29.png
+data/S30.png
+data/S31.png
+data/S32.png
+data/S33.png
+data/S34.png
+data/S35.png
+data/S36.png
+data/0_alpha.png
+data/newboard.ogg
+data/pop1.ogg
+data/drop.ogg
+data/Background2.png
+data/HelpOff.png
+data/HelpOn.png
+data/NewBoard.png
+data/NewBoardOn.png
+data/Instructions.png
+data/Flag01.png
+data/Flag02.png
+data/Flag03.png
+data/Flag04.png
+data/Flag05.png
+data/Flag06.png
+data/Flag07.png
+data/0.ogg
+data/1.ogg
+data/2.ogg
+data/3.ogg
+data/4.ogg
+data/5.ogg
+data/6.ogg
+data/7.ogg
+data/Arrow.png
+data/Arrow1.png
+data/Arrow2.png
+data/Arrow3.png
+data/Arrow4.png
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/NEWS
diff --git a/activity.py b/activity.py
new file mode 100644
index 0000000..0d46d17
--- /dev/null
+++ b/activity.py
@@ -0,0 +1,9 @@
+import olpcgames
+
+# Class name must match 'class' property in activity/activity.info:
+class JumpActivity(olpcgames.PyGameActivity):
+ """An example of using a Pygame game as a Sugar activity."""
+
+ game_name = 'Jump' # game_name must match name of your Pygame module
+ game_title = 'Jump'
+ game_size = (1200,825) \ No newline at end of file
diff --git a/activity/activity.info b/activity/activity.info
new file mode 100644
index 0000000..7a8f993
--- /dev/null
+++ b/activity/activity.info
@@ -0,0 +1,7 @@
+[Activity]
+name = Jump
+activity_version = 1
+host_version = 1
+service_name = net.coderanger.olpc.JumpActivity
+icon = jump
+class = activity.JumpActivity \ No newline at end of file
diff --git a/activity/jump.svg b/activity/jump.svg
new file mode 100644
index 0000000..1c8cc2e
--- /dev/null
+++ b/activity/jump.svg
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 12.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 51448) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
+ <!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
+ <!ENTITY ns_extend "http://ns.adobe.com/Extensibility/1.0/">
+ <!ENTITY ns_ai "http://ns.adobe.com/AdobeIllustrator/10.0/">
+ <!ENTITY ns_graphs "http://ns.adobe.com/Graphs/1.0/">
+ <!ENTITY ns_vars "http://ns.adobe.com/Variables/1.0/">
+ <!ENTITY ns_imrep "http://ns.adobe.com/ImageReplacement/1.0/">
+ <!ENTITY ns_sfw "http://ns.adobe.com/SaveForWeb/1.0/">
+ <!ENTITY ns_custom "http://ns.adobe.com/GenericCustomNamespace/1.0/">
+ <!ENTITY ns_adobe_xpath "http://ns.adobe.com/XPath/1.0/">
+ <!ENTITY ns_svg "http://www.w3.org/2000/svg">
+ <!ENTITY ns_xlink "http://www.w3.org/1999/xlink">
+ <!ENTITY stroke_color "#000000">
+ <!ENTITY fill_color "#AAAAAA">
+]>
+<svg version="1.1"
+ xmlns:x="&ns_extend;" xmlns:i="&ns_ai;" xmlns:graph="&ns_graphs;" i:viewOrigin="-2.1357 52" i:rulerOrigin="0 0" i:pageBounds="0 50 50 0"
+ xmlns="&ns_svg;" xmlns:xlink="&ns_xlink;" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
+ width="54.136" height="54" viewBox="0 0 54.136 54" overflow="visible" enable-background="new 0 0 54.136 54"
+ xml:space="preserve">
+<metadata>
+ <variableSets xmlns="http://ns.adobe.com/Variables/1.0/">
+ <variableSet varSetName="binding1" locked="none">
+ <variables></variables>
+ <v:sampleDataSets xmlns:v="http://ns.adobe.com/Variables/1.0/" xmlns="http://ns.adobe.com/GenericCustomNamespace/1.0/">
+ </v:sampleDataSets>
+ </variableSet>
+ </variableSets>
+</metadata>
+<g id="Layer_1" i:knockout="Off" i:layer="yes" i:dimmedPercent="50" i:rgbTrio="#4F008000FFFF">
+ <circle fill="none" stroke="&stroke_color;" stroke-width="4.5" cx="27.137" cy="27" r="22.311"/>
+ <circle i:knockout="Off" fill="&fill_color;" cx="27.136" cy="27" r="20.701"/>
+ <circle fill="&stroke_color;" cx="11.052" cy="26.751" r="2.051"/>
+ <circle fill="&stroke_color;" cx="16.329" cy="26.751" r="2.051"/>
+ <circle fill="&stroke_color;" cx="21.608" cy="26.751" r="2.05"/>
+ <circle fill="&stroke_color;" cx="26.886" cy="26.751" r="2.05"/>
+ <circle fill="&stroke_color;" cx="32.163" cy="26.751" r="2.051"/>
+ <circle fill="&stroke_color;" cx="37.442" cy="26.751" r="2.05"/>
+ <circle fill="&stroke_color;" cx="42.721" cy="26.751" r="2.05"/>
+ <circle fill="&stroke_color;" cx="11.052" cy="31.991" r="2.051"/>
+ <circle fill="&stroke_color;" cx="16.329" cy="31.991" r="2.051"/>
+ <circle fill="&stroke_color;" cx="21.608" cy="31.991" r="2.05"/>
+ <circle fill="&stroke_color;" cx="26.886" cy="31.991" r="2.05"/>
+ <circle fill="&stroke_color;" cx="32.163" cy="31.991" r="2.051"/>
+ <circle fill="&stroke_color;" cx="37.442" cy="31.991" r="2.05"/>
+ <circle fill="&stroke_color;" cx="42.721" cy="31.991" r="2.05"/>
+ <circle fill="&stroke_color;" cx="11.052" cy="21.511" r="2.051"/>
+ <circle fill="&stroke_color;" cx="16.329" cy="21.511" r="2.051"/>
+ <circle fill="&stroke_color;" cx="21.608" cy="21.511" r="2.05"/>
+ <circle fill="&stroke_color;" cx="26.886" cy="21.511" r="2.05"/>
+ <circle fill="&stroke_color;" cx="32.163" cy="21.511" r="2.051"/>
+ <circle fill="&stroke_color;" cx="37.442" cy="21.511" r="2.05"/>
+ <circle fill="&stroke_color;" cx="42.721" cy="21.511" r="2.05"/>
+ <circle fill="&stroke_color;" cx="21.608" cy="16.271" r="2.05"/>
+ <circle fill="&stroke_color;" cx="26.886" cy="16.271" r="2.05"/>
+ <circle fill="&stroke_color;" cx="32.163" cy="16.271" r="2.051"/>
+ <circle fill="&stroke_color;" cx="21.608" cy="37.23" r="2.05"/>
+ <circle fill="&stroke_color;" cx="26.886" cy="37.23" r="2.05"/>
+ <circle fill="&stroke_color;" cx="32.163" cy="37.23" r="2.051"/>
+ <circle fill="&stroke_color;" cx="21.608" cy="42.471" r="2.05"/>
+ <circle fill="&stroke_color;" cx="26.886" cy="42.471" r="2.05"/>
+ <circle fill="&stroke_color;" cx="32.163" cy="42.471" r="2.051"/>
+ <circle fill="&stroke_color;" cx="21.608" cy="11.03" r="2.05"/>
+ <circle fill="&stroke_color;" cx="26.886" cy="11.03" r="2.05"/>
+ <circle fill="&stroke_color;" cx="32.163" cy="11.03" r="2.051"/>
+</g>
+</svg>
diff --git a/data/0.ogg b/data/0.ogg
new file mode 100644
index 0000000..28a5fa8
--- /dev/null
+++ b/data/0.ogg
Binary files differ
diff --git a/data/0.png b/data/0.png
new file mode 100644
index 0000000..184ce59
--- /dev/null
+++ b/data/0.png
Binary files differ
diff --git a/data/0_alpha.png b/data/0_alpha.png
new file mode 100644
index 0000000..e144de5
--- /dev/null
+++ b/data/0_alpha.png
Binary files differ
diff --git a/data/1.ogg b/data/1.ogg
new file mode 100644
index 0000000..7c9e1c2
--- /dev/null
+++ b/data/1.ogg
Binary files differ
diff --git a/data/1.png b/data/1.png
new file mode 100644
index 0000000..fad7186
--- /dev/null
+++ b/data/1.png
Binary files differ
diff --git a/data/10.png b/data/10.png
new file mode 100644
index 0000000..9af741d
--- /dev/null
+++ b/data/10.png
Binary files differ
diff --git a/data/11.png b/data/11.png
new file mode 100644
index 0000000..6548817
--- /dev/null
+++ b/data/11.png
Binary files differ
diff --git a/data/12.png b/data/12.png
new file mode 100644
index 0000000..6548817
--- /dev/null
+++ b/data/12.png
Binary files differ
diff --git a/data/13.png b/data/13.png
new file mode 100644
index 0000000..c7b46f7
--- /dev/null
+++ b/data/13.png
Binary files differ
diff --git a/data/14.png b/data/14.png
new file mode 100644
index 0000000..c83f800
--- /dev/null
+++ b/data/14.png
Binary files differ
diff --git a/data/15.png b/data/15.png
new file mode 100644
index 0000000..635067f
--- /dev/null
+++ b/data/15.png
Binary files differ
diff --git a/data/16.png b/data/16.png
new file mode 100644
index 0000000..0d09e35
--- /dev/null
+++ b/data/16.png
Binary files differ
diff --git a/data/17.png b/data/17.png
new file mode 100644
index 0000000..184ce59
--- /dev/null
+++ b/data/17.png
Binary files differ
diff --git a/data/18.png b/data/18.png
new file mode 100644
index 0000000..a7ee9d4
--- /dev/null
+++ b/data/18.png
Binary files differ
diff --git a/data/19.png b/data/19.png
new file mode 100644
index 0000000..93da1c9
--- /dev/null
+++ b/data/19.png
Binary files differ
diff --git a/data/2.ogg b/data/2.ogg
new file mode 100644
index 0000000..bdc43b2
--- /dev/null
+++ b/data/2.ogg
Binary files differ
diff --git a/data/2.png b/data/2.png
new file mode 100644
index 0000000..07b1da2
--- /dev/null
+++ b/data/2.png
Binary files differ
diff --git a/data/20.png b/data/20.png
new file mode 100644
index 0000000..8e50fad
--- /dev/null
+++ b/data/20.png
Binary files differ
diff --git a/data/21.png b/data/21.png
new file mode 100644
index 0000000..6fe83f5
--- /dev/null
+++ b/data/21.png
Binary files differ
diff --git a/data/22.png b/data/22.png
new file mode 100644
index 0000000..53b8136
--- /dev/null
+++ b/data/22.png
Binary files differ
diff --git a/data/23.png b/data/23.png
new file mode 100644
index 0000000..6759a96
--- /dev/null
+++ b/data/23.png
Binary files differ
diff --git a/data/24.png b/data/24.png
new file mode 100644
index 0000000..91ceddb
--- /dev/null
+++ b/data/24.png
Binary files differ
diff --git a/data/25.png b/data/25.png
new file mode 100644
index 0000000..5db9598
--- /dev/null
+++ b/data/25.png
Binary files differ
diff --git a/data/3.ogg b/data/3.ogg
new file mode 100644
index 0000000..b54f8a3
--- /dev/null
+++ b/data/3.ogg
Binary files differ
diff --git a/data/3.png b/data/3.png
new file mode 100644
index 0000000..7372c2b
--- /dev/null
+++ b/data/3.png
Binary files differ
diff --git a/data/4.ogg b/data/4.ogg
new file mode 100644
index 0000000..0b3958a
--- /dev/null
+++ b/data/4.ogg
Binary files differ
diff --git a/data/4.png b/data/4.png
new file mode 100644
index 0000000..5f948ae
--- /dev/null
+++ b/data/4.png
Binary files differ
diff --git a/data/5.ogg b/data/5.ogg
new file mode 100644
index 0000000..233cb50
--- /dev/null
+++ b/data/5.ogg
Binary files differ
diff --git a/data/5.png b/data/5.png
new file mode 100644
index 0000000..9af741d
--- /dev/null
+++ b/data/5.png
Binary files differ
diff --git a/data/6.ogg b/data/6.ogg
new file mode 100644
index 0000000..565029b
--- /dev/null
+++ b/data/6.ogg
Binary files differ
diff --git a/data/6.png b/data/6.png
new file mode 100644
index 0000000..9af741d
--- /dev/null
+++ b/data/6.png
Binary files differ
diff --git a/data/7.ogg b/data/7.ogg
new file mode 100644
index 0000000..51f7b8d
--- /dev/null
+++ b/data/7.ogg
Binary files differ
diff --git a/data/7.png b/data/7.png
new file mode 100644
index 0000000..89f0c88
--- /dev/null
+++ b/data/7.png
Binary files differ
diff --git a/data/8.png b/data/8.png
new file mode 100644
index 0000000..7372c2b
--- /dev/null
+++ b/data/8.png
Binary files differ
diff --git a/data/9.png b/data/9.png
new file mode 100644
index 0000000..5f948ae
--- /dev/null
+++ b/data/9.png
Binary files differ
diff --git a/data/Arrow.png b/data/Arrow.png
new file mode 100644
index 0000000..eb01f89
--- /dev/null
+++ b/data/Arrow.png
Binary files differ
diff --git a/data/Arrow1.png b/data/Arrow1.png
new file mode 100644
index 0000000..eb01f89
--- /dev/null
+++ b/data/Arrow1.png
Binary files differ
diff --git a/data/Arrow2.png b/data/Arrow2.png
new file mode 100644
index 0000000..3c2cb7a
--- /dev/null
+++ b/data/Arrow2.png
Binary files differ
diff --git a/data/Arrow3.png b/data/Arrow3.png
new file mode 100644
index 0000000..bb532ae
--- /dev/null
+++ b/data/Arrow3.png
Binary files differ
diff --git a/data/Arrow4.png b/data/Arrow4.png
new file mode 100644
index 0000000..0ed3da4
--- /dev/null
+++ b/data/Arrow4.png
Binary files differ
diff --git a/data/Background2.png b/data/Background2.png
new file mode 100644
index 0000000..7e1a6e9
--- /dev/null
+++ b/data/Background2.png
Binary files differ
diff --git a/data/Flag01.png b/data/Flag01.png
new file mode 100644
index 0000000..6b9bb99
--- /dev/null
+++ b/data/Flag01.png
Binary files differ
diff --git a/data/Flag02.png b/data/Flag02.png
new file mode 100644
index 0000000..95ee911
--- /dev/null
+++ b/data/Flag02.png
Binary files differ
diff --git a/data/Flag03.png b/data/Flag03.png
new file mode 100644
index 0000000..0b726af
--- /dev/null
+++ b/data/Flag03.png
Binary files differ
diff --git a/data/Flag04.png b/data/Flag04.png
new file mode 100644
index 0000000..30d8022
--- /dev/null
+++ b/data/Flag04.png
Binary files differ
diff --git a/data/Flag05.png b/data/Flag05.png
new file mode 100644
index 0000000..a0e0263
--- /dev/null
+++ b/data/Flag05.png
Binary files differ
diff --git a/data/Flag06.png b/data/Flag06.png
new file mode 100644
index 0000000..136bd17
--- /dev/null
+++ b/data/Flag06.png
Binary files differ
diff --git a/data/Flag07.png b/data/Flag07.png
new file mode 100644
index 0000000..b18447c
--- /dev/null
+++ b/data/Flag07.png
Binary files differ
diff --git a/data/HelpOff.png b/data/HelpOff.png
new file mode 100644
index 0000000..b975d8d
--- /dev/null
+++ b/data/HelpOff.png
Binary files differ
diff --git a/data/HelpOn.png b/data/HelpOn.png
new file mode 100644
index 0000000..61e9f46
--- /dev/null
+++ b/data/HelpOn.png
Binary files differ
diff --git a/data/Instructions.png b/data/Instructions.png
new file mode 100644
index 0000000..e8a9ae0
--- /dev/null
+++ b/data/Instructions.png
Binary files differ
diff --git a/data/NewBoard.png b/data/NewBoard.png
new file mode 100644
index 0000000..b170ab4
--- /dev/null
+++ b/data/NewBoard.png
Binary files differ
diff --git a/data/NewBoardOn.png b/data/NewBoardOn.png
new file mode 100644
index 0000000..4c219b0
--- /dev/null
+++ b/data/NewBoardOn.png
Binary files differ
diff --git a/data/S01.png b/data/S01.png
new file mode 100644
index 0000000..968985d
--- /dev/null
+++ b/data/S01.png
Binary files differ
diff --git a/data/S02.png b/data/S02.png
new file mode 100644
index 0000000..39f035a
--- /dev/null
+++ b/data/S02.png
Binary files differ
diff --git a/data/S03.png b/data/S03.png
new file mode 100644
index 0000000..bf9bf79
--- /dev/null
+++ b/data/S03.png
Binary files differ
diff --git a/data/S04.png b/data/S04.png
new file mode 100644
index 0000000..ceacd44
--- /dev/null
+++ b/data/S04.png
Binary files differ
diff --git a/data/S05.png b/data/S05.png
new file mode 100644
index 0000000..248e4b4
--- /dev/null
+++ b/data/S05.png
Binary files differ
diff --git a/data/S06.png b/data/S06.png
new file mode 100644
index 0000000..f6b7e81
--- /dev/null
+++ b/data/S06.png
Binary files differ
diff --git a/data/S07.png b/data/S07.png
new file mode 100644
index 0000000..3ce3911
--- /dev/null
+++ b/data/S07.png
Binary files differ
diff --git a/data/S08.png b/data/S08.png
new file mode 100644
index 0000000..8bc02de
--- /dev/null
+++ b/data/S08.png
Binary files differ
diff --git a/data/S09.png b/data/S09.png
new file mode 100644
index 0000000..3b1b0ae
--- /dev/null
+++ b/data/S09.png
Binary files differ
diff --git a/data/S10.png b/data/S10.png
new file mode 100644
index 0000000..168298a
--- /dev/null
+++ b/data/S10.png
Binary files differ
diff --git a/data/S11.png b/data/S11.png
new file mode 100644
index 0000000..b56be08
--- /dev/null
+++ b/data/S11.png
Binary files differ
diff --git a/data/S12.png b/data/S12.png
new file mode 100644
index 0000000..70af8fe
--- /dev/null
+++ b/data/S12.png
Binary files differ
diff --git a/data/S13.png b/data/S13.png
new file mode 100644
index 0000000..32dd87e
--- /dev/null
+++ b/data/S13.png
Binary files differ
diff --git a/data/S14.png b/data/S14.png
new file mode 100644
index 0000000..ca4c7dd
--- /dev/null
+++ b/data/S14.png
Binary files differ
diff --git a/data/S15.png b/data/S15.png
new file mode 100644
index 0000000..9640c3d
--- /dev/null
+++ b/data/S15.png
Binary files differ
diff --git a/data/S16.png b/data/S16.png
new file mode 100644
index 0000000..0f56134
--- /dev/null
+++ b/data/S16.png
Binary files differ
diff --git a/data/S17.png b/data/S17.png
new file mode 100644
index 0000000..c3665e4
--- /dev/null
+++ b/data/S17.png
Binary files differ
diff --git a/data/S18.png b/data/S18.png
new file mode 100644
index 0000000..d6dee5b
--- /dev/null
+++ b/data/S18.png
Binary files differ
diff --git a/data/S19.png b/data/S19.png
new file mode 100644
index 0000000..d75b8a9
--- /dev/null
+++ b/data/S19.png
Binary files differ
diff --git a/data/S20.png b/data/S20.png
new file mode 100644
index 0000000..feef881
--- /dev/null
+++ b/data/S20.png
Binary files differ
diff --git a/data/S21.png b/data/S21.png
new file mode 100644
index 0000000..f672945
--- /dev/null
+++ b/data/S21.png
Binary files differ
diff --git a/data/S22.png b/data/S22.png
new file mode 100644
index 0000000..8e39c3e
--- /dev/null
+++ b/data/S22.png
Binary files differ
diff --git a/data/S23.png b/data/S23.png
new file mode 100644
index 0000000..1587c90
--- /dev/null
+++ b/data/S23.png
Binary files differ
diff --git a/data/S24.png b/data/S24.png
new file mode 100644
index 0000000..4c326df
--- /dev/null
+++ b/data/S24.png
Binary files differ
diff --git a/data/S25.png b/data/S25.png
new file mode 100644
index 0000000..5fb7a39
--- /dev/null
+++ b/data/S25.png
Binary files differ
diff --git a/data/S26.png b/data/S26.png
new file mode 100644
index 0000000..78c468e
--- /dev/null
+++ b/data/S26.png
Binary files differ
diff --git a/data/S27.png b/data/S27.png
new file mode 100644
index 0000000..305bb02
--- /dev/null
+++ b/data/S27.png
Binary files differ
diff --git a/data/S28.png b/data/S28.png
new file mode 100644
index 0000000..ee3c3b8
--- /dev/null
+++ b/data/S28.png
Binary files differ
diff --git a/data/S29.png b/data/S29.png
new file mode 100644
index 0000000..4b24418
--- /dev/null
+++ b/data/S29.png
Binary files differ
diff --git a/data/S30.png b/data/S30.png
new file mode 100644
index 0000000..ca0c025
--- /dev/null
+++ b/data/S30.png
Binary files differ
diff --git a/data/S31.png b/data/S31.png
new file mode 100644
index 0000000..65bac0e
--- /dev/null
+++ b/data/S31.png
Binary files differ
diff --git a/data/S32.png b/data/S32.png
new file mode 100644
index 0000000..972d31f
--- /dev/null
+++ b/data/S32.png
Binary files differ
diff --git a/data/S33.png b/data/S33.png
new file mode 100644
index 0000000..78f2a25
--- /dev/null
+++ b/data/S33.png
Binary files differ
diff --git a/data/S34.png b/data/S34.png
new file mode 100644
index 0000000..4a97b40
--- /dev/null
+++ b/data/S34.png
Binary files differ
diff --git a/data/S35.png b/data/S35.png
new file mode 100644
index 0000000..9e1e6ad
--- /dev/null
+++ b/data/S35.png
Binary files differ
diff --git a/data/S36.png b/data/S36.png
new file mode 100644
index 0000000..7dff40a
--- /dev/null
+++ b/data/S36.png
Binary files differ
diff --git a/data/blank.png b/data/blank.png
new file mode 100644
index 0000000..c0c70d9
--- /dev/null
+++ b/data/blank.png
Binary files differ
diff --git a/data/drop.ogg b/data/drop.ogg
new file mode 100644
index 0000000..338c83d
--- /dev/null
+++ b/data/drop.ogg
Binary files differ
diff --git a/data/newboard.ogg b/data/newboard.ogg
new file mode 100644
index 0000000..b4f211f
--- /dev/null
+++ b/data/newboard.ogg
Binary files differ
diff --git a/data/pop1.ogg b/data/pop1.ogg
new file mode 100644
index 0000000..2127e1f
--- /dev/null
+++ b/data/pop1.ogg
Binary files differ
diff --git a/helpers.py b/helpers.py
new file mode 100644
index 0000000..dd4ffff
--- /dev/null
+++ b/helpers.py
@@ -0,0 +1,20 @@
+#! /usr/bin/env python
+
+import os, sys
+import pygame
+from pygame.locals import *
+
+def load_image(name, colorkey=None):
+ fullname = os.path.join('data')
+ fullname = os.path.join(fullname, name)
+ try:
+ image = pygame.image.load(fullname)
+ except pygame.error, message:
+ print 'Cannot load image:', fullname
+ raise SystemExit, message
+ image = image.convert()
+ if colorkey is not None:
+ if colorkey is -1:
+ colorkey = image.get_at((0,0))
+ image.set_colorkey(colorkey, RLEACCEL)
+ return image, image.get_rect() \ No newline at end of file
diff --git a/levelBase.py b/levelBase.py
new file mode 100644
index 0000000..6ae2393
--- /dev/null
+++ b/levelBase.py
@@ -0,0 +1,14 @@
+#! /usr/bin/env python
+
+class Level:
+ """The Base Class for Levels"""
+ def getLayout(self):
+ """Get the Layout of the level"""
+ """Returns a [][] list"""
+ pass
+ def getImages(self):
+ """Get a list of all the images used by the level"""
+ """Returns a list of all the images used. The indices
+ in the layout refer to sprites in the list returned by
+ this function"""
+ pass \ No newline at end of file
diff --git a/marble.txt b/marble.txt
new file mode 100644
index 0000000..c227083
--- /dev/null
+++ b/marble.txt
@@ -0,0 +1 @@
+0 \ No newline at end of file
diff --git a/olpcgames/__init__.py b/olpcgames/__init__.py
new file mode 100644
index 0000000..547976c
--- /dev/null
+++ b/olpcgames/__init__.py
@@ -0,0 +1,34 @@
+"""Wrapper/adaptation system for writing/porting PyGame games to OLPC/Sugar
+
+The wrapper system attempts to substitute various pieces of the PyGame
+implementation in order to make code written without knowledge of the
+OLPC/Sugar environment run "naturally" under the GTK environment of
+Sugar. It also provides some convenience mechanisms for dealing with
+e.g. the Camera and Mesh Network system.
+
+Considerations for Developers:
+
+PyGame programs running under OLPCGames will generally not have
+"hardware" surfaces, and will not be able to have a reduced-resolution
+full-screen view to optimise rendering. The PyGame code will run in
+a secondary thread, with the main GTK UI running in the primary thread.
+A third "mainloop" thread will occasionally be created to handle the
+GStreamer interface to the camera.
+"""
+# XXX handle configurations that are not running under Sugar and
+# report proper errors to describe the problem, rather than letting the
+# particular errors propagate outward.
+# XXX allow use of a particular feature within the library without needing
+# to be running under sugar. e.g. allow importing mesh or camera without
+# needing to import the activity machinery.
+from olpcgames.canvas import *
+try:
+ from olpcgames.activity import *
+except ImportError, err:
+ PyGameActivity = None
+from olpcgames import camera
+from olpcgames import pangofont
+from olpcgames import mesh
+
+ACTIVITY = None
+widget = None
diff --git a/olpcgames/activity.py b/olpcgames/activity.py
new file mode 100644
index 0000000..9510e08
--- /dev/null
+++ b/olpcgames/activity.py
@@ -0,0 +1,142 @@
+"""Embeds the Canvas widget into a Sugar-specific Activity environment"""
+import pygtk
+pygtk.require('2.0')
+import gtk
+import gtk.gdk
+
+from sugar.activity import activity
+from sugar.graphics import style
+from olpcgames.canvas import PyGameCanvas
+from olpcgames import mesh
+
+import logging
+log = logging.getLogger( 'activity' )
+#log.setLevel( logging.DEBUG )
+
+__all__ = ['PyGameActivity']
+
+class PyGameActivity(activity.Activity):
+ """PyGame-specific activity type, provides boilerplate toolbar, creates canvas
+
+ Subclass Overrides:
+
+ game_name -- specifies a fully-qualified name for the game's main-loop
+ format like so:
+ 'package.module:main'
+ if not function name is provided, "main" is assumed.
+ game_handler -- alternate specification via direct reference to a main-loop
+ function
+
+ game_size -- two-value tuple specifying the size of the display in pixels,
+ this is currently static, so once the window is created it cannot be
+ changed.
+
+ If None, use the bulk of the screen for the PyGame surface based on
+ the values reported by the gtk.gdk functions. Note that None is
+ *not* the default value.
+
+ game_title -- title to be displayed in the Sugar Shell UI
+
+ pygame_mode -- chooses the rendering engine used for handling the
+ PyGame drawing mode, 'SDL' chooses the standard PyGame renderer,
+ 'Cairo' chooses the experimental pygamecairo renderer.
+
+ PYGAME_CANVAS_CLASS -- normally PyGameCanvas, but can be overridden
+ if you want to provide a different canvas class, e.g. to provide a different
+ internal layout. Note: only used where pygame_mode == 'SDL'
+
+ The Activity, once created, will be made available as olpcgames.ACTIVITY,
+ and that access mechanism should allow code to test for the presence of the
+ activity before accessing Sugar-specific functionality.
+
+ XXX Note that currently the toolbar and window layout are hard-coded into
+ this super-class, with no easy way of overriding without completely rewriting
+ the __init__ method. We should allow for customising both the UI layout and
+ the toolbar contents/layout/connection.
+ """
+ game_name = None
+ game_title = 'PyGame Game'
+ game_handler = None
+ game_size = (16 * style.GRID_CELL_SIZE,
+ 11 * style.GRID_CELL_SIZE)
+ pygame_mode = 'SDL'
+
+ def __init__(self, handle):
+ """Initialise the Activity with the activity-description handle"""
+ super(PyGameActivity, self).__init__(handle)
+ self.make_global()
+ if self.game_size is None:
+ width,height = gtk.gdk.screen_width(), gtk.gdk.screen_height()
+ log.info( 'Total screen size: %s %s', width,height)
+ # for now just fudge it...
+ self.game_size = width, height - (1*style.GRID_CELL_SIZE)
+ self.set_title(self.game_title)
+ toolbar = self.build_toolbar()
+ log.warn( 'Toolbar size: %s', toolbar.get_size_request())
+
+ canvas = self.build_canvas()
+
+ def make_global( self ):
+ """Hack to make olpcgames.ACTIVITY point to us
+
+ Also makes pygame.display.set_caption == self.set_title
+ """
+ import weakref, olpcgames
+ assert not olpcgames.ACTIVITY, """Activity.make_global called twice, have you created two Activity instances in a single process?"""
+ olpcgames.ACTIVITY = weakref.proxy( self )
+
+ def build_toolbar( self ):
+ """Build our Activity toolbar for the Sugar system
+
+ This is a customisation point for those games which want to
+ provide custom toolbars when running under Sugar.
+ """
+ toolbar = activity.ActivityToolbar(self)
+ toolbar.show()
+ self.set_toolbox(toolbar)
+ def shared_cb(*args, **kwargs):
+ mesh.activity_shared(self)
+ def joined_cb(*args, **kwargs):
+ mesh.activity_joined(self)
+ self.connect("shared", shared_cb)
+ self.connect("joined", joined_cb)
+
+ if self.get_shared():
+ # if set at this point, it means we've already joined (i.e.,
+ # launched from Neighborhood)
+ joined_cb()
+
+ toolbar.title.unset_flags(gtk.CAN_FOCUS)
+ return toolbar
+
+ PYGAME_CANVAS_CLASS = PyGameCanvas
+ def build_canvas( self ):
+ """Construct the PyGame or PyGameCairo canvas for drawing"""
+ assert self.game_handler or self.game_name, 'You must specify a handler module (%r)'%(self.game_handler or self.game_name)
+
+ if self.pygame_mode != 'Cairo':
+ self._pgc = self.PYGAME_CANVAS_CLASS(*self.game_size)
+ self.set_canvas(self._pgc)
+ self._pgc.grab_focus()
+ self._pgc.connect_game(self.game_handler or self.game_name)
+ gtk.gdk.threads_init()
+ return self._pgc
+ else:
+ import hippo
+ self._drawarea = gtk.DrawingArea()
+ canvas = hippo.Canvas()
+ canvas.grab_focus()
+ self.set_canvas(canvas)
+ self.show_all()
+
+ import pygamecairo
+ pygamecairo.install()
+
+ pygamecairo.display.init(canvas)
+ app = self.game_handler or self.game_name
+ if ':' not in app:
+ app += ':main'
+ mod_name, fn_name = app.split(':')
+ mod = __import__(mod_name, globals(), locals(), [])
+ fn = getattr(mod, fn_name)
+ fn()
diff --git a/olpcgames/camera.py b/olpcgames/camera.py
new file mode 100644
index 0000000..b71c360
--- /dev/null
+++ b/olpcgames/camera.py
@@ -0,0 +1,235 @@
+"""Accesses OLPC Camera functionality via gstreamer
+
+Depends upon:
+ pygame
+ python-gstreamer
+"""
+import threading
+import logging
+import time
+import os
+import pygame
+import gst
+from olpcgames.util import get_activity_root
+
+log = logging.getLogger( 'camera' )
+#log.setLevel( logging.DEBUG )
+
+CAMERA_LOAD = 9917
+CAMERA_LOAD_FAIL = 9918
+
+class CameraSprite(object):
+ """Create gstreamer surface for the camera."""
+ def __init__(self, x, y):
+ import olpcgames
+ if olpcgames.widget:
+ self._init_video(olpcgames.widget, x, y)
+
+ def _init_video(self, widget, x, y):
+ from olpcgames import video
+ self._vid = video.VideoWidget()
+ widget._fixed.put(self._vid, x, y)
+ self._vid.show()
+
+ self.player = video.Player(self._vid)
+ self.player.play()
+
+class Camera(object):
+ """A class representing a still-picture camera
+
+ Produces a simple gstreamer bus that terminates in a filesink, that is,
+ it stores the results in a file. When a picture is "snapped" the gstreamer
+ stream is iterated until it finishes processing and then the file can be
+ read.
+
+ There are two APIs available, a synchronous API which can potentially
+ stall your activity's GUI (and is NOT recommended) and an
+ asynchronous API which returns immediately and delivers the captured
+ camera image via a Pygame event. To be clear, it is recommended
+ that you use the snap_async method, *not* the snap method.
+
+ Note:
+
+ The Camera class is simply a convenience wrapper around a fairly
+ straightforward gstreamer bus. If you have more involved
+ requirements for your camera manipulations you will probably
+ find it easier to write your own camera implementation than to
+ use this one. Basically we provide here the "normal" use case of
+ snapping a picture into a pygame image.
+ """
+ _aliases = {
+ 'camera': 'v4l2src',
+ 'test': 'videotestsrc',
+ 'testing': 'videotestsrc',
+ 'png': 'pngenc',
+ 'jpeg': 'jpegenc',
+ 'jpg': 'jpegenc',
+ }
+ def __init__(self, source='camera', format='png', filename='snap.png', directory = None):
+ """Initialises the Camera's internal description
+
+ source -- the gstreamer source for the video to capture, useful values:
+ 'v4l2src','camera' -- the camera
+ 'videotestsrc','test' -- test pattern generator source
+ format -- the gstreamer encoder to use for the capture, useful values:
+ 'pngenc','png' -- PNG format graphic
+ 'jpegenc','jpg','jpeg' -- JPEG format graphic
+ filename -- the filename to use for the capture
+ directory -- the directory in which to create the temporary file, defaults
+ to get_activity_root() + 'tmp'
+ """
+ self.source = self._aliases.get( source, source )
+ self.format = self._aliases.get( format, format )
+ self.filename = filename
+ self.directory = directory
+ SNAP_PIPELINE = '%(source)s ! ffmpegcolorspace ! %(format)s ! filesink location="%(filename)s"'
+ def _create_pipe( self ):
+ """Method to create the cstreamer pipe from our settings"""
+ if not self.directory:
+ path = os.path.join( get_activity_root(), 'tmp' )
+ try:
+ os.makedirs( path )
+ log.info( 'Created temporary directory: %s', path )
+ except (OSError,IOError), err:
+ pass
+ else:
+ path = self.directory
+ filename = os.path.join( path, self.filename )
+ format = self.format
+ source = self.source
+ pipeline = self.SNAP_PIPELINE % locals()
+ log.debug( 'Background thread processing: %s', pipeline )
+ return filename, gst.parse_launch(pipeline)
+
+ def snap(self):
+ """Snap a picture via the camera by iterating gstreamer until finished
+
+ Note: this is an unsafe implementation, it will cause the whole
+ activity to hang if the operation happens to fail! It is strongly
+ recommended that you use snap_async instead of snap!
+ """
+ log.debug( 'Starting snap' )
+ filename, pipe = self._create_pipe()
+ pipe.set_state(gst.STATE_PLAYING)
+ bus = pipe.get_bus()
+ tmp = False
+ while True:
+ event = self.bus.poll(gst.MESSAGE_STATE_CHANGED, 5)
+ if event:
+ old, new, pending = event.parse_state_changed()
+ if pending == gst.STATE_VOID_PENDING:
+ if tmp:
+ break
+ else:
+ tmp = True
+ else:
+ break
+ log.log( 'Ending snap, loading: %s', filename )
+ return self._load_and_clean( filename )
+ def _load_and_clean( self, filename ):
+ """Use pygame to load given filename, delete after loading/attempt"""
+ try:
+ log.info( 'Loading snapshot file: %s', filename )
+ return pygame.image.load(filename)
+ finally:
+ try:
+ os.remove( filename )
+ except (IOError,OSError), err:
+ pass
+ def snap_async( self, token=None ):
+ """Snap a picture asynchronously generating event on success/failure
+
+ token -- passed back as attribute of the event which signals that capture
+ is finished
+
+ We return two types of events CAMERA_LOAD and CAMERA_LOAD_FAIL,
+ depending on whether we succeed or not. Attributes of the events which
+ are returned:
+
+ token -- as passed to this method
+ filename -- the filename in our temporary directory we used to store
+ the file temporarily
+ image -- pygame image.load result if successful, None otherwise
+ err -- Exception instance if failed, None otherwise
+
+ Basically identical to the snap method, save that it posts a message
+ to the event bus in eventwrap instead of blocking and returning...
+ """
+ log.debug( 'beginning async snap')
+ t = threading.Thread(target=self._background_snap, args=(token,))
+ t.start()
+ log.debug( 'background thread started for gstreamer' )
+ return token
+
+ def _background_snap(
+ self,
+ token = None,
+ ):
+ """Process gst messages until pipe is finished
+
+ pipe -- gstreamer pipe definition for parse_launch, normally it will
+ produce a file into which the camera should store an image
+
+ We consider pipe to be finished when we have had two "state changed"
+ gstreamer events where the pending state is VOID, the first for when
+ we begin playing, the second for when we finish.
+ """
+ log.debug( 'Background thread kicking off gstreamer capture begun' )
+ from olpcgames import eventwrap
+ from pygame.event import Event
+ filename, pipe = self._create_pipe()
+ bus = pipe.get_bus()
+ bus.add_signal_watch()
+ def _background_snap_onmessage( bus, message ):
+ """Handle messages from the picture-snapping bus"""
+ log.debug( 'Message handler for gst messages: %s', message )
+ t = message.type
+ if t == gst.MESSAGE_EOS:
+ pipe.set_state(gst.STATE_NULL)
+ try:
+ image = self._load_and_clean( filename )
+ success = True
+ except Exception, err:
+ success = False
+ image = None
+ else:
+ err = None
+ log.debug( 'Success loading file %r', token )
+ eventwrap.post(Event(
+ CAMERA_LOAD,
+ filename=filename,
+ success = success,
+ token = token,
+ image=image,
+ err=err
+ ))
+
+ elif t == gst.MESSAGE_ERROR:
+ log.warn( 'Failure loading file %r: %s', token, message )
+ pipe.set_state(gst.STATE_NULL)
+ err, debug = message.parse_error()
+ eventwrap.post(Event(
+ CAMERA_LOAD_FAIL,
+ filename=filename,
+ success = False,
+ token = token,
+ image=None,
+ err=err
+ ))
+ return False
+ bus.connect('message', _background_snap_onmessage)
+ pipe.set_state(gst.STATE_PLAYING)
+
+def snap():
+ """Dump a snapshot from the camera to a pygame surface in background thread
+
+ See Camera.snap
+ """
+ return Camera().snap()
+
+def snap_async( token=None, **named ):
+ """Dump snapshot from camera return asynchronously as event in Pygame
+
+ See Camera.snap_async
+ """
+ return Camera(**named).snap_async( token )
diff --git a/olpcgames/canvas.py b/olpcgames/canvas.py
new file mode 100644
index 0000000..9b00823
--- /dev/null
+++ b/olpcgames/canvas.py
@@ -0,0 +1,117 @@
+"""Implements bridge connection between Sugar/GTK and PyGame"""
+import os
+import sys
+import threading
+from pprint import pprint
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+import gobject
+import pygame
+
+from olpcgames import gtkEvent, video
+
+__all__ = ['PyGameCanvas']
+
+class PyGameCanvas(gtk.EventBox):
+ """Canvas providing bridge methods to run PyGame in GTK
+
+ The PyGameCanvas creates a secondary thread in which the Pygame instance will
+ live, providing synthetic PyGame events to that thread via a Queue. The GUI
+ connection is done by having the PyGame canvas use a GTK Port object as it's
+ window pointer, it draws to that X-level window in order to produce output.
+ """
+ def __init__(self, width, height):
+ """Initializes the Canvas Object
+
+ width,height -- passed to the inner EventBox in order to request a given size,
+ the Socket is the only child of this EventBox, and the PyGame commands
+ will be writing to the Window ID of the socket. The internal EventBox is
+ centered via an Alignment instance within the PyGameCanvas instance.
+
+ XXX Should refactor so that the internal setup can be controlled by the
+ sub-class, e.g. to get size from the host window, or something similar.
+ """
+ # Build the main widget
+ super(PyGameCanvas,self).__init__()
+
+ # Build the sub-widgets
+ self._align = gtk.Alignment(0.5, 0.5)
+ self._inner_evb = gtk.EventBox()
+ self._socket = gtk.Socket()
+
+
+ # Add internal widgets
+ self._inner_evb.set_size_request(width, height)
+ self._inner_evb.add(self._socket)
+ self._socket.show()
+
+ self._align.add(self._inner_evb)
+ self._inner_evb.show()
+
+ self._align.show()
+
+ self.add(self._align)
+
+ # Construct a gtkEvent.Translator
+ self._translator = gtkEvent.Translator(self, self._inner_evb)
+
+ # <Cue Thus Spract Zarathustra>
+ self.set_flags(gtk.CAN_FOCUS)
+ self.show()
+ def build_widgets( self ):
+ """Build our internal widgets/layout mechansims
+
+ This is a customisation point for sub-classes
+ """
+
+ def connect_game(self, app):
+ """Imports the given main-loop and starts processing in secondary thread
+
+ app -- fully-qualified Python path-name for the game's main-loop, with
+ name within module as :functionname, if no : character is present then
+ :main will be assumed.
+
+ Side effects:
+
+ Sets the SDL_WINDOWID variable to our socket's window ID
+ Calls PyGame init
+ Causes the gtkEvent.Translator to "hook" PyGame
+ Creates and starts secondary thread for Game/PyGame event processing.
+ """
+ # Setup the embedding
+ os.environ['SDL_WINDOWID'] = str(self._socket.get_id())
+ #print 'Socket ID=%s'%os.environ['SDL_WINDOWID']
+ pygame.init()
+
+ self._translator.hook_pygame()
+
+ # Load the modules
+ # NOTE: This is delayed because pygame.init() must come after the embedding is up
+ if ':' not in app:
+ app += ':main'
+ mod_name, fn_name = app.split(':')
+ mod = __import__(mod_name, globals(), locals(), [])
+ fn = getattr(mod, fn_name)
+
+ # Start Pygame
+ self.__thread = threading.Thread(target=self._start, args=[fn])
+ self.__thread.start()
+
+ def _start(self, fn):
+ """The method that actually runs in the background thread"""
+ import olpcgames
+ olpcgames.widget = self
+ try:
+ import sugar.activity.activity,os
+ except ImportError, err:
+ log.info( """Running outside Sugar""" )
+ else:
+ os.chdir(sugar.activity.activity.get_bundle_path())
+
+ try:
+ fn()
+ finally:
+ gtk.main_quit()
+
diff --git a/olpcgames/eventwrap.py b/olpcgames/eventwrap.py
new file mode 100644
index 0000000..7a01c7b
--- /dev/null
+++ b/olpcgames/eventwrap.py
@@ -0,0 +1,152 @@
+"""Converts from GTK to Pygame events
+
+Provides methods which will be substituted into Pygame in order to
+provide the synthetic events that we will feed into the Pygame queue.
+These methods are registered by the "install" method.
+"""
+import pygame
+import gtk
+import Queue
+import thread
+
+# This module reuses Pygame's Event, but
+# reimplements the event queue.
+from pygame.event import Event, event_name, pump as pygame_pump
+
+#print "Initializing own event.py"
+
+# Install myself on top of pygame.event
+def install():
+ """Installs this module (eventwrap) as an in-place replacement for the pygame.event module.
+
+ Use install() when you need to interact with Pygame code written
+ without reference to the olpcgames wrapper mechanisms to have the
+ code use this module's event queue.
+
+ XXX Really, use it everywhere you want to use olpcgames, as olpcgames
+ registers the handler itself, so you will always wind up with it registered when
+ you use olpcgames (the gtkEvent.Translator.hook_pygame method calls it).
+ """
+ import eventwrap,pygame
+ pygame.event = eventwrap
+ import sys
+ sys.modules["pygame.event"] = eventwrap
+
+
+# Event queue:
+g_events = Queue.Queue()
+
+# Set of blocked events as set by set
+g_blocked = set()
+g_blockedlock = thread.allocate_lock()
+g_blockAll = False
+
+def pump():
+ """Handle any window manager and other external events that aren't passed to the user. Call this periodically (once a frame) if you don't call get(), poll() or wait()."""
+ pygame_pump()
+
+def get():
+ """Get a list of all pending events. (Unlike pygame, there's no option to filter by event type; you should use set_blocked() if you don't want to see certain events.)"""
+ pump()
+ eventlist = []
+ try:
+ while True:
+ eventlist.append(g_events.get(block=False))
+ except Queue.Empty:
+ pass
+
+ return eventlist
+
+def poll():
+ """Get the next pending event if exists. Otherwise, return pygame.NOEVENT."""
+ pump()
+ try:
+ return g_events.get(block=False)
+ except Queue.Empty:
+ return Event(pygame.NOEVENT)
+
+
+def wait():
+ """Get the next pending event, waiting if none."""
+ pump()
+ return g_events.get(block=True)
+
+def peek(types=None):
+ """True if there is any pending event. (Unlike pygame, there's no option to
+ filter by event type)"""
+ return not g_events.empty()
+
+def clear():
+ """Dunno why you would do this, but throws every event out of the queue"""
+ try:
+ while True:
+ g_events.get(block=False)
+ except Queue.Empty:
+ pass
+
+def set_blocked(item):
+ g_blockedlock.acquire()
+ try:
+ # FIXME: we do not currently know how to block all event types when
+ # you set_blocked(none).
+ [g_blocked.add(x) for x in makeseq(item)]
+ finally:
+ g_blockedlock.release()
+
+def set_allowed(item):
+ g_blockedlock.acquire()
+ try:
+ if item is None:
+ # Allow all events when you set_allowed(none). Strange, eh?
+ # Pygame is a wonderful API.
+ g_blocked.clear()
+ else:
+ [g_blocked.remove(x) for x in makeseq(item)]
+ finally:
+ g_blockedlock.release()
+
+def get_blocked(*args, **kwargs):
+ g_blockedlock.acquire()
+ try:
+ blocked = frozenset(g_blocked)
+ return blocked
+ finally:
+ g_blockedlock.release()
+
+def set_grab(grabbing):
+ # We don't do this.
+ pass
+
+def get_grab():
+ # We don't do this.
+ return False
+
+def post(event):
+ #print "posting on own"
+ g_blockedlock.acquire()
+ try:
+ if event.type not in g_blocked:
+ g_events.put(event, block=False)
+ finally:
+ g_blockedlock.release()
+
+def makeseq(obj):
+ """Accept either a scalar object or a sequence, and return a sequence
+ over which we can iterate. If we were passed a sequence, return it
+ unchanged. If we were passed a scalar, return a tuple containing only
+ that scalar. This allows the caller to easily support one-or-many.
+ """
+ # Strings are the exception because you can iterate over their chars
+ # -- yet, for all the purposes I've ever cared about, I want to treat
+ # a string as a scalar.
+ if isinstance(obj, basestring):
+ return (obj,)
+ try:
+ # Except as noted above, if you can get an iter() from an object,
+ # it's a collection.
+ iter(obj)
+ return obj
+ except TypeError:
+ # obj is a scalar. Wrap it in a tuple so we can iterate over the
+ # one item.
+ return (obj,)
diff --git a/olpcgames/gtkEvent.py b/olpcgames/gtkEvent.py
new file mode 100644
index 0000000..4e5693b
--- /dev/null
+++ b/olpcgames/gtkEvent.py
@@ -0,0 +1,259 @@
+"""gtkEvent.py: translate GTK events into Pygame events."""
+import pygtk
+pygtk.require('2.0')
+import gtk
+import gobject
+import pygame
+import pygame.event as Pevent
+#PCevent = Pevent
+from olpcgames import eventwrap as PCevent
+
+class MockEvent(object):
+ """Used to inject key-repeat events."""
+
+ def __init__(self, keyval):
+ self.keyval = keyval
+
+class Translator(object):
+ """Utility class to translate GTK events into Pygame events
+
+ The Translator object interprets incoming GTK events and generates
+ Pygame events in the eventwrap module's queue as a result.
+ It also handles generating Pygame style key-repeat events
+ by synthesizing them via a GTK timer.
+ """
+ key_trans = {
+ 'Alt_L': pygame.K_LALT,
+ 'Alt_R': pygame.K_RALT,
+ 'Control_L': pygame.K_LCTRL,
+ 'Control_R': pygame.K_RCTRL,
+ 'Shift_L': pygame.K_LSHIFT,
+ 'Shift_R': pygame.K_RSHIFT,
+ 'Super_L': pygame.K_LSUPER,
+ 'Super_R': pygame.K_RSUPER,
+ 'KP_Page_Up' : pygame.K_KP9,
+ 'KP_Page_Down' : pygame.K_KP3,
+ 'KP_End' : pygame.K_KP1,
+ 'KP_Home' : pygame.K_KP7,
+ 'KP_Up' : pygame.K_KP8,
+ 'KP_Down' : pygame.K_KP2,
+ 'KP_Left' : pygame.K_KP4,
+ 'KP_Right' : pygame.K_KP6,
+
+ }
+
+ mod_map = {
+ pygame.K_LALT: pygame.KMOD_LALT,
+ pygame.K_RALT: pygame.KMOD_RALT,
+ pygame.K_LCTRL: pygame.KMOD_LCTRL,
+ pygame.K_RCTRL: pygame.KMOD_RCTRL,
+ pygame.K_LSHIFT: pygame.KMOD_LSHIFT,
+ pygame.K_RSHIFT: pygame.KMOD_RSHIFT,
+ }
+
+ def __init__(self, mainwindow, mouselistener=None):
+ """Initialise the Translator with the windows to which to listen"""
+ # _inner_evb is Mouselistener
+ self._mainwindow = mainwindow
+ if mouselistener is None:
+ mouselistener = mainwindow
+
+ self._inner_evb = mouselistener
+
+ # Need to set our X event masks so we see mouse motion and stuff --
+ mainwindow.set_events(
+ gtk.gdk.KEY_PRESS_MASK | \
+ gtk.gdk.KEY_RELEASE_MASK \
+ )
+
+ self._inner_evb.set_events(
+ gtk.gdk.POINTER_MOTION_MASK | \
+ gtk.gdk.POINTER_MOTION_HINT_MASK | \
+ gtk.gdk.BUTTON_MOTION_MASK | \
+ gtk.gdk.BUTTON_PRESS_MASK | \
+ gtk.gdk.BUTTON_RELEASE_MASK
+ )
+
+ # Callback functions to link the event systems
+ mainwindow.connect('unrealize', self._quit)
+ mainwindow.connect('key_press_event', self._keydown)
+ mainwindow.connect('key_release_event', self._keyup)
+ self._inner_evb.connect('button_press_event', self._mousedown)
+ self._inner_evb.connect('button_release_event', self._mouseup)
+ self._inner_evb.connect('motion-notify-event', self._mousemove)
+
+ # You might need to do this
+ self._inner_evb.set_flags(gtk.CAN_FOCUS)
+
+ # Internal data
+ self.__stopped = False
+ self.__keystate = [0] * 323
+ self.__button_state = [0,0,0]
+ self.__mouse_pos = (0,0)
+ self.__repeat = (None, None)
+ self.__held = set()
+ self.__held_time_left = {}
+ self.__held_last_time = {}
+ self.__tick_id = None
+
+ #print "translator initialized"
+
+ def hook_pygame(self):
+ """Hook the various Pygame features so that we implement the event APIs"""
+ # Pygame should be initialized. Hijack their key and mouse methods
+ pygame.key.get_pressed = self._get_pressed
+ pygame.key.set_repeat = self._set_repeat
+ pygame.mouse.get_pressed = self._get_mouse_pressed
+ pygame.mouse.get_pos = self._get_mouse_pos
+ import eventwrap
+ eventwrap.install()
+
+ def _quit(self, data=None):
+ self.__stopped = True
+ PCevent.post(Pevent.Event(pygame.QUIT))
+
+ def _keydown(self, widget, event):
+ key = event.keyval
+ if key in self.__held:
+ return True
+ else:
+ if self.__repeat[0] is not None:
+ self.__held_last_time[key] = pygame.time.get_ticks()
+ self.__held_time_left[key] = self.__repeat[0]
+ self.__held.add(key)
+
+ return self._keyevent(widget, event, pygame.KEYDOWN)
+
+ def _keyup(self, widget, event):
+ key = event.keyval
+ if self.__repeat[0] is not None:
+ if key in self.__held:
+ # This is possibly false if set_repeat() is called with a key held
+ del self.__held_time_left[key]
+ del self.__held_last_time[key]
+ self.__held.discard(key)
+
+ return self._keyevent(widget, event, pygame.KEYUP)
+
+ def _keymods(self):
+ """Extract the keymods as they stand currently."""
+ mod = 0
+ for key_val, mod_val in self.mod_map.iteritems():
+ mod |= self.__keystate[key_val] and mod_val
+ return mod
+
+
+ def _keyevent(self, widget, event, type):
+ key = gtk.gdk.keyval_name(event.keyval)
+ if key is None:
+ # No idea what this key is.
+ return False
+
+ keycode = None
+ if key in self.key_trans:
+ keycode = self.key_trans[key]
+ elif hasattr(pygame, 'K_'+key.upper()):
+ keycode = getattr(pygame, 'K_'+key.upper())
+ elif hasattr(pygame, 'K_'+key.lower()):
+ keycode = getattr(pygame, 'K_'+key.lower())
+ else:
+ print 'Key %s unrecognized'%key
+
+ if keycode is not None:
+ if type == pygame.KEYDOWN:
+ mod = self._keymods()
+ self.__keystate[keycode] = type == pygame.KEYDOWN
+ if type == pygame.KEYUP:
+ mod = self._keymods()
+ ukey = gtk.gdk.keyval_to_unicode(event.keyval)
+ evt = Pevent.Event(type, key=keycode, unicode=ukey, mod=mod)
+ self._post(evt)
+ return True
+
+ def _get_pressed(self):
+ """Retrieve map/array of which keys are currently depressed (held down)"""
+ return self.__keystate
+
+ def _get_mouse_pressed(self):
+ """Return three-element array of which mouse-buttons are currently depressed (held down)"""
+ return self.__button_state
+
+ def _mousedown(self, widget, event):
+ self.__button_state[event.button-1] = 1
+ return self._mouseevent(widget, event, pygame.MOUSEBUTTONDOWN)
+
+ def _mouseup(self, widget, event):
+ self.__button_state[event.button-1] = 0
+ return self._mouseevent(widget, event, pygame.MOUSEBUTTONUP)
+
+ def _mouseevent(self, widget, event, type):
+
+ evt = Pevent.Event(type,
+ button=event.button,
+ pos=(event.x, event.y))
+ self._post(evt)
+ return True
+
+ def _mousemove(self, widget, event):
+ # From http://www.learningpython.com/2006/07/25/writing-a-custom-widget-using-pygtk/
+ # if this is a hint, then let's get all the necessary
+ # information, if not it's all we need.
+ if event.is_hint:
+ x, y, state = event.window.get_pointer()
+ else:
+ x = event.x
+ y = event.y
+ state = event.state
+
+ rel = (x - self.__mouse_pos[0],
+ y - self.__mouse_pos[1])
+ self.__mouse_pos = (x, y)
+
+ self.__button_state = [
+ state & gtk.gdk.BUTTON1_MASK and 1 or 0,
+ state & gtk.gdk.BUTTON2_MASK and 1 or 0,
+ state & gtk.gdk.BUTTON3_MASK and 1 or 0,
+ ]
+
+ evt = Pevent.Event(pygame.MOUSEMOTION,
+ pos=self.__mouse_pos,
+ rel=rel,
+ buttons=self.__button_state)
+ self._post(evt)
+ return True
+
+ def _tick(self):
+ """Generate synthetic events for held-down keys"""
+ cur_time = pygame.time.get_ticks()
+ for key in self.__held:
+ delta = cur_time - self.__held_last_time[key]
+ self.__held_last_time[key] = cur_time
+
+ self.__held_time_left[key] -= delta
+ if self.__held_time_left[key] <= 0:
+ self.__held_time_left[key] = self.__repeat[1]
+ self._keyevent(None, MockEvent(key), pygame.KEYDOWN)
+
+ return True
+
+ def _set_repeat(self, delay=None, interval=None):
+ """Set the key-repetition frequency for held-down keys"""
+ if delay is not None and self.__repeat[0] is None:
+ self.__tick_id = gobject.timeout_add(10, self._tick)
+ elif delay is None and self.__repeat[0] is not None:
+ gobject.source_remove(self.__tick_id)
+ self.__repeat = (delay, interval)
+
+ def _get_mouse_pos(self):
+ """Retrieve the current mouse position as a two-tuple of integers"""
+ return self.__mouse_pos
+
+ def _post(self, evt):
+ try:
+ PCevent.post(evt)
+ except pygame.error, e:
+ if str(e) == 'Event queue full':
+ print "Event queue full!"
+ pass
+ else:
+ raise e
diff --git a/olpcgames/mesh.py b/olpcgames/mesh.py
new file mode 100644
index 0000000..b229bc0
--- /dev/null
+++ b/olpcgames/mesh.py
@@ -0,0 +1,330 @@
+'''mesh.py: utilities for wrapping the mesh and making it accessible to Pygame'''
+import logging
+log = logging.getLogger( 'olpcgames.mesh' )
+try:
+ from sugar.presence.tubeconn import TubeConnection
+except ImportError, err:
+ TubeConnection = object
+try:
+ from dbus.gobject_service import ExportedGObject
+except ImportError, err:
+ ExportedGObject = object
+from dbus.service import method, signal
+
+try:
+ import telepathy
+except ImportError, err:
+ telepathy = None
+try:
+ import sugar.presence.presenceservice
+except ImportError, err:
+ sugar = None
+
+DBUS_IFACE="org.laptop.games.pygame"
+DBUS_PATH="/org/laptop/games/pygame"
+DBUS_SERVICE = None
+
+
+### NEW PYGAME EVENTS ###
+
+'''The tube connection was started. (i.e., the user clicked Share or started
+the activity from the Neighborhood screen).
+Event properties:
+ id: a unique identifier for this connection. (shouldn't be needed for anything)'''
+CONNECT = 9912
+
+'''A participant joined the activity. This will trigger for the local user
+as well as any arriving remote users.
+Event properties:
+ handle: the arriving user's handle.'''
+PARTICIPANT_ADD = 9913
+
+'''A participant quit the activity.
+Event properties:
+ handle: the departing user's handle.'''
+PARTICIPANT_REMOVE = 9914
+
+'''A message was sent to you.
+Event properties:
+ content: the content of the message (a string)
+ handle: the handle of the sending user.'''
+MESSAGE_UNI = 9915
+
+'''A message was sent to everyone.
+Event properties:
+ content: the content of the message (a string)
+ handle: the handle of the sending user.'''
+MESSAGE_MULTI = 9916
+
+
+# Private objects for useful purposes!
+pygametubes = []
+text_chan, tubes_chan = (None, None)
+conn = None
+initiating = False
+
+def activity_shared(activity):
+ '''Called when the user clicks Share.'''
+
+ global initiating
+ initiating = True
+
+ _setup(activity)
+
+
+ log.debug('This is my activity: making a tube...')
+ channel = tubes_chan[telepathy.CHANNEL_TYPE_TUBES]
+ if hasattr( channel, 'OfferDBUSTube' ):
+ id = channel.OfferDBusTube(
+ telepathy.TUBE_TYPE_DBUS, DBUS_SERVICE, {})
+ else:
+ id = channel.OfferTube(
+ telepathy.TUBE_TYPE_DBUS, DBUS_SERVICE, {})
+
+
+def activity_joined(activity):
+ '''Called at the startup of our Activity, when the user started it via Neighborhood intending to join an existing activity.'''
+
+ # Find out who's already in the shared activity:
+ log.debug('Joined an existing shared activity')
+
+ for buddy in activity._shared_activity.get_joined_buddies():
+ log.debug('Buddy %s is already in the activity' % buddy.props.nick)
+
+
+ global initiating
+ initiating = False
+
+ _setup(activity)
+
+ tubes_chan[telepathy.CHANNEL_TYPE_TUBES].ListTubes(
+ reply_handler=_list_tubes_reply_cb,
+ error_handler=_list_tubes_error_cb)
+
+
+def _getConn():
+ pservice = sugar.presence.presenceservice.get_instance()
+ name, path = pservice.get_preferred_connection()
+ global conn
+ conn = telepathy.client.Connection(name, path)
+ return conn
+
+
+
+def _setup(activity):
+ '''Determines text and tube channels for the current Activity. If no tube
+channel present, creates one. Updates text_chan and tubes_chan.
+
+setup(sugar.activity.Activity, telepathy.client.Connection)'''
+ global text_chan, tubes_chan, DBUS_SERVICE
+ if not DBUS_SERVICE:
+ DBUS_SERVICE = activity.get_bundle_id()
+ if not activity.get_shared():
+ log.error('Failed to share or join activity')
+ raise "Failure"
+
+ bus_name, conn_path, channel_paths = activity._shared_activity.get_channels()
+ _getConn()
+
+ # Work out what our room is called and whether we have Tubes already
+ room = None
+ tubes_chan = None
+ text_chan = None
+ for channel_path in channel_paths:
+ channel = telepathy.client.Channel(bus_name, channel_path)
+ htype, handle = channel.GetHandle()
+ if htype == telepathy.HANDLE_TYPE_ROOM:
+ log.debug('Found our room: it has handle#%d "%s"',
+ handle, conn.InspectHandles(htype, [handle])[0])
+ room = handle
+ ctype = channel.GetChannelType()
+ if ctype == telepathy.CHANNEL_TYPE_TUBES:
+ log.debug('Found our Tubes channel at %s', channel_path)
+ tubes_chan = channel
+ elif ctype == telepathy.CHANNEL_TYPE_TEXT:
+ log.debug('Found our Text channel at %s', channel_path)
+ text_chan = channel
+
+ if room is None:
+ log.error("Presence service didn't create a room")
+ raise "Failure"
+ if text_chan is None:
+ log.error("Presence service didn't create a text channel")
+ raise "Failure"
+
+ # Make sure we have a Tubes channel - PS doesn't yet provide one
+ if tubes_chan is None:
+ log.debug("Didn't find our Tubes channel, requesting one...")
+ tubes_chan = conn.request_channel(telepathy.CHANNEL_TYPE_TUBES,
+ telepathy.HANDLE_TYPE_ROOM, room, True)
+
+ tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal('NewTube',
+ new_tube_cb)
+
+ return (text_chan, tubes_chan)
+
+
+
+def new_tube_cb(id, initiator, type, service, params, state):
+ log.debug("New_tube_cb called: %s %s %s" % (id, initiator, type))
+ if (type == telepathy.TUBE_TYPE_DBUS and service == DBUS_SERVICE):
+ if state == telepathy.TUBE_STATE_LOCAL_PENDING:
+ channel = tubes_chan[telepathy.CHANNEL_TYPE_TUBES]
+ if hasattr( channel, 'AcceptDBUSTube' ):
+ channel.AcceptDBUSTube( id )
+ else:
+ channel.AcceptTube(id)
+
+ tube_conn = TubeConnection(conn,
+ tubes_chan[telepathy.CHANNEL_TYPE_TUBES],
+ id, group_iface=text_chan[telepathy.CHANNEL_INTERFACE_GROUP])
+
+ global pygametubes, initiating
+ pygametubes.append(PygameTube(tube_conn, initiating, len(pygametubes)))
+
+
+def _list_tubes_reply_cb(tubes):
+ for tube_info in tubes:
+ new_tube_cb(*tube_info)
+
+def _list_tubes_error_cb(e):
+ log.error('ListTubes() failed: %s', e)
+
+
+
+def get_buddy(dbus_handle):
+ """Get a Buddy from a handle."""
+ log.debug('Trying to find owner of handle %u...', dbus_handle)
+ cs_handle = instance().tube.bus_name_to_handle[dbus_handle]
+ group = text_chan[telepathy.CHANNEL_INTERFACE_GROUP]
+ my_csh = group.GetSelfHandle()
+ log.debug('My handle in that group is %u', my_csh)
+ if my_csh == cs_handle:
+ handle = conn.GetSelfHandle()
+ log.debug('CS handle %u belongs to me, %u', cs_handle, handle)
+ elif group.GetGroupFlags() & telepathy.CHANNEL_GROUP_FLAG_CHANNEL_SPECIFIC_HANDLES:
+ handle = group.GetHandleOwners([cs_handle])[0]
+ log.debug('CS handle %u belongs to %u', cs_handle, handle)
+ else:
+ handle = cs_handle
+ log.debug('non-CS handle %u belongs to itself', handle)
+
+ # XXX: we're assuming that we have Buddy objects for all contacts -
+ # this might break when the server becomes scalable.
+ pservice = sugar.presence.presenceservice.get_instance()
+ name, path = pservice.get_preferred_connection()
+ return pservice.get_buddy_by_telepathy_handle(name, path, handle)
+
+
+def instance(idx=0):
+ return pygametubes[idx]
+
+import eventwrap,pygame.event as PEvent
+
+class PygameTube(ExportedGObject):
+ '''The object whose instance is shared across D-bus
+
+ Call instance() to get the instance of this object for your activity service.
+ Its 'tube' property contains the underlying D-bus Connection.
+ '''
+ def __init__(self, tube, is_initiator, tube_id):
+ super(PygameTube, self).__init__(tube, DBUS_PATH)
+ self.tube = tube
+ self.is_initiator = is_initiator
+ self.entered = False
+ self.ordered_bus_names = []
+ eventwrap.post(PEvent.Event(CONNECT, id=tube_id))
+
+ if not self.is_initiator:
+ self.tube.add_signal_receiver(self.new_participant_cb, 'NewParticipants', DBUS_IFACE, path=DBUS_PATH)
+ self.tube.watch_participants(self.participant_change_cb)
+ self.tube.add_signal_receiver(self.broadcast_cb, 'Broadcast', DBUS_IFACE, path=DBUS_PATH, sender_keyword='sender')
+
+ def participant_change_cb(self, added, removed):
+ def nick(buddy):
+ if buddy is not None:
+ return buddy.props.nick
+ else:
+ return 'Unknown'
+
+ for handle, bus_name in added:
+ dbus_handle = self.tube.participants[handle]
+ self.ordered_bus_names.append(dbus_handle)
+ eventwrap.post(PEvent.Event(PARTICIPANT_ADD, handle=dbus_handle))
+
+ for handle, bus_name in removed:
+ dbus_handle = self.tube.participants[handle]
+ self.ordered_bus_names.remove(dbus_handle)
+ eventwrap.post(PEvent.Event(PARTICIPANT_REMOVE, handle=dbus_handle))
+
+ if self.is_initiator:
+ if not self.entered:
+ # Initiator will broadcast a new ordered_bus_names each time
+ # a participant joins.
+ self.ordered_bus_names = [self.tube.get_unique_name()]
+ self.NewParticipants(self.ordered_bus_names)
+
+ self.entered = True
+
+ @signal(dbus_interface=DBUS_IFACE, signature='as')
+ def NewParticipants(self, ordered_bus_names):
+ '''This is the NewParticipants signal, sent when the authoritative list of ordered_bus_names changes.'''
+ log.debug("sending NewParticipants: %s" % ordered_bus_names)
+ pass
+
+ @signal(dbus_interface=DBUS_IFACE, signature='s')
+ def Broadcast(self, content):
+ '''This is the Broadcast signal; it sends a message to all other activity participants.'''
+ pass
+
+ @method(dbus_interface=DBUS_IFACE, in_signature='s', out_signature='', sender_keyword='sender')
+ def Tell(self, content, sender=None):
+ '''This is the targeted-message interface; called when a message is received that was sent directly to me.'''
+ eventwrap.post(PEvent.Event(MESSAGE_UNI, handle=sender, content=content))
+
+ def broadcast_cb(self, content, sender=None):
+ '''This is the Broadcast callback, fired when someone sends a Broadcast signal along the bus.'''
+ eventwrap.post(PEvent.Event(MESSAGE_MULTI, handle=sender, content=content))
+
+ def new_participant_cb(self, new_bus_names):
+ '''This is the NewParticipants callback, fired when someone joins or leaves.'''
+ log.debug("new participant. new bus names %s, old %s" % (new_bus_names, self.ordered_bus_names))
+ if self.ordered_bus_names != new_bus_names:
+ log.warn("ordered bus names out of sync with server, resyncing")
+ self.ordered_bus_names = new_bus_names
+
+def send_to(handle, content=""):
+ '''Sends the given message to the given buddy identified by handle.'''
+ remote_proxy = dbus_get_object(handle, DBUS_PATH)
+ remote_proxy.Tell(content, reply_handler=dbus_msg, error_handler=dbus_err)
+
+def dbus_msg():
+ log.debug("async reply to send_to")
+def dbus_err(e):
+ log.error("async error: %s" % e)
+
+def broadcast(content=""):
+ '''Sends the given message to all participants.'''
+ instance().Broadcast(content)
+
+def my_handle():
+ '''Returns the handle of this user.'''
+ return instance().tube.get_unique_name()
+
+def get_participants():
+ '''Returns the list of active participants, in order of arrival.
+ List is maintained by the activity creator; if that person leaves it may not stay in sync.'''
+ return instance().ordered_bus_names[:]
+
+def dbus_get_object(handle, path):
+ '''Get a D-bus object from another participant.
+
+ This is how you can communicate with other participants using
+ arbitrary D-bus objects without having to manage the participants
+ yourself.
+
+ Simply define a D-bus class with an interface and path that you
+ choose; when you want a reference to the corresponding remote
+ object on a participant, call this method.
+ '''
+ return instance().tube.get_object(handle, path)
diff --git a/olpcgames/pangofont.py b/olpcgames/pangofont.py
new file mode 100644
index 0000000..c104674
--- /dev/null
+++ b/olpcgames/pangofont.py
@@ -0,0 +1,288 @@
+"""Implement Pygame's font interface using Pango for international support
+
+Depends on:
+
+ pygtk (to get the pango context)
+ pycairo (for the pango rendering context)
+ python-pango (obviously)
+ pygame (obviously)
+"""
+import pango
+import logging
+import cairo
+import pangocairo
+import pygame.rect, pygame.image
+import gtk
+import struct
+from pygame import surface
+
+log = logging.getLogger( 'pangofont' )
+#log.setLevel( logging.DEBUG )
+
+# Install myself on top of pygame.font
+def install():
+ """Replace Pygame's font module with this module"""
+ log.info( 'installing' )
+ from olpcgames import pangofont
+ import pygame
+ pygame.font = pangofont
+ import sys
+ sys.modules["pygame.font"] = pangofont
+
+class PangoFont(object):
+ """Base class for a pygame.font.Font-like object drawn by Pango."""
+ def __init__(self, family=None, size=None, bold=False, italic=False, fd=None):
+ """If you know what pango.FontDescription (fd) you want, pass it in as
+ 'fd'. Otherwise, specify any number of family, size, bold, or italic,
+ and we will try to match something up for you."""
+
+ # Always set the FontDescription (FIXME - only set it if the user wants
+ # to change something?)
+ if fd is None:
+ fd = pango.FontDescription()
+ if family is not None:
+ fd.set_family(family)
+ if size is not None:
+ fd.set_size(size*1000)
+
+ if bold:
+ fd.set_weight(pango.WEIGHT_BOLD)
+ if italic:
+ fd.set_style(pango.STYLE_OBLIQUE)
+
+ self.fd = fd
+
+ def render(self, text, antialias=True, color=(255,255,255), background=None):
+ """Render the font onto a new Surface and return it.
+ We ignore 'antialias' and use system settings.
+
+ text -- (unicode) string with the text to render
+ antialias -- attempt to antialias the text or not
+ color -- three or four-tuple of 0-255 values specifying rendering
+ colour for the text
+ background -- three or four-tuple of 0-255 values specifying rendering
+ colour for the background, or None for trasparent background
+
+ returns a pygame image instance
+ """
+ log.info( 'render: %r, antialias = %s, color=%s, background=%s', text, antialias, color, background )
+
+ # create layout
+ layout = pango.Layout(gtk.gdk.pango_context_get())
+ layout.set_font_description(self.fd)
+ layout.set_text(text)
+
+ # determine pixel size
+ (logical, ink) = layout.get_pixel_extents()
+ ink = pygame.rect.Rect(ink)
+
+ # Create a new Cairo ImageSurface
+ csrf = cairo.ImageSurface(cairo.FORMAT_ARGB32, ink.w, ink.h)
+ cctx = pangocairo.CairoContext(cairo.Context(csrf))
+
+ # Mangle the colors on little-endian machines. The reason for this
+ # is that Cairo writes native-endian 32-bit ARGB values whereas
+ # Pygame expects endian-independent values in whatever format. So we
+ # tell our users not to expect transparency here (avoiding the A issue)
+ # and we swizzle all the colors around.
+ big_endian = struct.pack( '=i', 1 ) == struct.pack( '>i', 1 )
+ if hasattr(csrf,'get_data'):
+ swap = True
+ else:
+ swap = False
+ log.debug( 'big_endian: %s swap: %s', big_endian, swap )
+ def mangle_color(color):
+ """Mange a colour depending on endian-ness, and swap-necessity
+
+ This implementation has only been tested on an AMD64
+ machine with a get_data implementation (rather than
+ a get_data_as_rgba implementation).
+ """
+ r,g,b = color[:3]
+ if len(color) > 3:
+ a = color[3]
+ else:
+ a = 255.0
+ if swap and not big_endian:
+ return map(_fixColorBase, (b,g,r,a) )
+ return map(_fixColorBase, (r,g,b,a) )
+
+ # render onto it
+ if background is not None:
+ background = mangle_color( background )
+ cctx.set_source_rgba(*background)
+ cctx.paint()
+
+ log.debug( 'incoming color: %s', color )
+ color = mangle_color( color )
+ log.debug( ' translated color: %s', color )
+
+ cctx.new_path()
+ cctx.layout_path(layout)
+ cctx.set_source_rgba(*color)
+ cctx.fill()
+
+ # Create and return a new Pygame Image derived from the Cairo Surface
+ if big_endian:
+ # You see, in big-endian-world, we can just use the RGB values
+ format = "ARGB"
+ else:
+ # But with little endian, we've already swapped R and B in
+ # mangle_color, so now just move the A
+ format = "RGBA"
+ if hasattr(csrf,'get_data'):
+ data = csrf.get_data()
+ else:
+ # XXX little-endian here, check on a big-endian machine
+ data = csrf.get_data_as_rgba()
+ format = 'RGBA' # XXX wrong, what's with all the silly swapping!
+ return pygame.image.fromstring(str(data), (ink.w,ink.h), format)
+
+class SysFont(PangoFont):
+ """Construct a PangoFont from a font description (name), size in pixels,
+ bold, and italic designation. Similar to SysFont from Pygame."""
+ def __init__(self, name, size, bold=False, italic=False):
+ fd = pango.FontDescription(name)
+ fd.set_absolute_size(size*pango.SCALE)
+ if bold:
+ fd.set_weight(pango.WEIGHT_BOLD)
+ if italic:
+ fd.set_style(pango.STYLE_OBLIQUE)
+ super(SysFont, self).__init__(fd=fd)
+
+# originally defined a new class, no reason for that...
+NotImplemented = NotImplementedError
+
+class Font(PangoFont):
+ """Abstract class, do not use"""
+ def __init__(self, *args, **kwargs):
+ raise NotImplementedError("PangoFont doesn't support Font directly, use SysFont or .fontByDesc")
+
+def match_font(name,bold=False,italic=False):
+ """Stub, does not work, use fontByDesc instead"""
+ raise NotImplementedError("PangoFont doesn't support match_font directly, use SysFont or .fontByDesc")
+
+def fontByDesc(desc="",bold=False,italic=False):
+ """Constructs a FontDescription from the given string representation.
+The format of the string representation is:
+
+ "[FAMILY-LIST] [STYLE-OPTIONS] [SIZE]"
+
+where FAMILY-LIST is a comma separated list of families optionally terminated by a comma, STYLE_OPTIONS is a whitespace separated list of words where each WORD describes one of style, variant, weight, or stretch, and SIZE is an decimal number (size in points). For example the following are all valid string representations:
+
+ "sans bold 12"
+ "serif,monospace bold italic condensed 16"
+ "normal 10"
+
+The commonly available font families are: Normal, Sans, Serif and Monospace. The available styles are:
+Normal the font is upright.
+Oblique the font is slanted, but in a roman style.
+Italic the font is slanted in an italic style.
+
+The available weights are:
+Ultra-Light the ultralight weight (= 200)
+Light the light weight (=300)
+Normal the default weight (= 400)
+Bold the bold weight (= 700)
+Ultra-Bold the ultra-bold weight (= 800)
+Heavy the heavy weight (= 900)
+
+The available variants are:
+Normal
+Small-Caps
+
+The available stretch styles are:
+Ultra-Condensed the smallest width
+Extra-Condensed
+Condensed
+Semi-Condensed
+Normal the normal width
+Semi-Expanded
+Expanded
+Extra-Expanded
+Ultra-Expanded the widest width
+ """
+ fd = pango.FontDescription(name)
+ if bold:
+ fd.set_weight(pango.WEIGHT_BOLD)
+ if italic:
+ fd.set_style(pango.STYLE_OBLIQUE)
+ return PangoFont(fd=fd)
+
+def get_init():
+ """Return boolean indicating whether we are initialised
+
+ Always returns True
+ """
+ return True
+
+def init():
+ """Initialise the module (null operation)"""
+ pass
+
+def quit():
+ """De-initialise the module (null operation)"""
+ pass
+
+def get_default_font():
+ """Return default-font specification to be passed to e.g. fontByDesc"""
+ return "sans"
+
+def get_fonts():
+ """Return the set of all fonts available (currently just 3 generic types)"""
+ return ["sans","serif","monospace"]
+
+
+def stdcolor(color):
+ """Produce a 4-element 0.0-1.0 color value from input"""
+ def fixlen(color):
+ if len(color) == 3:
+ return tuple(color) + (255,)
+ elif len(color) == 4:
+ return color
+ else:
+ raise TypeError("What sort of color is this: %s" % (color,))
+ return [_fixColorBase(x) for x in fixlen(color)]
+def _fixColorBase( v ):
+ """Return a properly clamped colour in floating-point space"""
+ return max((0,min((v,255.0))))/255.0
+
+if __name__ == "__main__":
+ # Simple testing code...
+ logging.basicConfig()
+ from pygame import image,display, event, sprite
+ import pygame
+ import pygame.event
+ def main():
+ display.init()
+ maxX,maxY = display.list_modes()[0]
+ screen = display.set_mode( (maxX/2, maxY/2 ) )
+ background = pygame.Surface(screen.get_size())
+ background = background.convert()
+ background.fill((0, 0,0))
+
+ screen.blit(background, (0, 0))
+ display.flip()
+
+ clock = pygame.time.Clock()
+
+ font = PangoFont( size=30, family='monospace' )
+ text1 = font.render( 'red', color=(255,0,0) )
+ text2 = font.render( 'green', color=(0,255,0) )
+ text3 = font.render( 'blue', color=(0,0,255) )
+ text4 = font.render( 'blue-trans', color=(0,0,255,128) )
+ text5 = font.render( 'cyan-trans', color=(0,255,255,128) )
+ while 1:
+ clock.tick( 60 )
+ for event in pygame.event.get():
+ log.debug( 'event: %s', event )
+ if event.type == pygame.QUIT:
+ return True
+ screen.blit( text1, (20,20 ))
+ screen.blit( text2, (20,80 ))
+ screen.blit( text3, (20,140 ))
+ screen.blit( text4, (200,20 ))
+ screen.blit( text5, (200,80 ))
+ display.flip()
+ main()
+
diff --git a/olpcgames/tubeconn.py b/olpcgames/tubeconn.py
new file mode 100644
index 0000000..4aa702f
--- /dev/null
+++ b/olpcgames/tubeconn.py
@@ -0,0 +1,107 @@
+# This should eventually land in telepathy-python, so has the same license:
+
+# Copyright (C) 2007 Collabora Ltd. <http://www.collabora.co.uk/>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+__all__ = ('TubeConnection',)
+__docformat__ = 'reStructuredText'
+
+
+import logging
+
+from dbus.connection import Connection
+
+
+logger = logging.getLogger('telepathy.tubeconn')
+
+
+class TubeConnection(Connection):
+
+ def __new__(cls, conn, tubes_iface, tube_id, address=None,
+ group_iface=None, mainloop=None):
+ if address is None:
+ address = tubes_iface.GetDBusServerAddress(tube_id)
+ self = super(TubeConnection, cls).__new__(cls, address,
+ mainloop=mainloop)
+
+ self._tubes_iface = tubes_iface
+ self.tube_id = tube_id
+ self.participants = {}
+ self.bus_name_to_handle = {}
+ self._mapping_watches = []
+
+ if group_iface is None:
+ method = conn.GetSelfHandle
+ else:
+ method = group_iface.GetSelfHandle
+ method(reply_handler=self._on_get_self_handle_reply,
+ error_handler=self._on_get_self_handle_error)
+
+ return self
+
+ def _on_get_self_handle_reply(self, handle):
+ self.self_handle = handle
+ match = self._tubes_iface.connect_to_signal('DBusNamesChanged',
+ self._on_dbus_names_changed)
+ self._tubes_iface.GetDBusNames(self.tube_id,
+ reply_handler=self._on_get_dbus_names_reply,
+ error_handler=self._on_get_dbus_names_error)
+ self._dbus_names_changed_match = match
+
+ def _on_get_self_handle_error(self, e):
+ logging.basicConfig()
+ logger.error('GetSelfHandle failed: %s', e)
+
+ def close(self):
+ self._dbus_names_changed_match.remove()
+ self._on_dbus_names_changed(self.tube_id, (), self.participants.keys())
+ super(TubeConnection, self).close()
+
+ def _on_get_dbus_names_reply(self, names):
+ self._on_dbus_names_changed(self.tube_id, names, ())
+
+ def _on_get_dbus_names_error(self, e):
+ logging.basicConfig()
+ logger.error('GetDBusNames failed: %s', e)
+
+ def _on_dbus_names_changed(self, tube_id, added, removed):
+ if tube_id == self.tube_id:
+ for handle, bus_name in added:
+ if handle == self.self_handle:
+ # I've just joined - set my unique name
+ self.set_unique_name(bus_name)
+ self.participants[handle] = bus_name
+ self.bus_name_to_handle[bus_name] = handle
+
+ # call the callback while the removed people are still in
+ # participants, so their bus names are available
+ for callback in self._mapping_watches:
+ callback(added, removed)
+
+ for handle in removed:
+ bus_name = self.participants.pop(handle, None)
+ self.bus_name_to_handle.pop(bus_name, None)
+
+ def watch_participants(self, callback):
+ self._mapping_watches.append(callback)
+ if self.participants:
+ # GetDBusNames already returned: fake a participant add event
+ # immediately
+ added = []
+ for k, v in self.participants.iteritems():
+ added.append((k, v))
+ callback(added, [])
diff --git a/olpcgames/util.py b/olpcgames/util.py
new file mode 100644
index 0000000..57d0456
--- /dev/null
+++ b/olpcgames/util.py
@@ -0,0 +1,40 @@
+"""Abstraction layer for working outside the Sugar environment"""
+import logging
+log = logging.getLogger( 'olpcgames.util' )
+import os.path
+
+NON_SUGAR_ROOT = '~/.olpcgames/'
+
+try:
+ from sugar.activity.activity import get_bundle_path as _get_bundle_path
+ def get_bundle_path( ):
+ """Retrieve bundle path from activity with fix for silly registration bug"""
+ path = _get_bundle_path()
+ if path.endswith( '.activity.activity' ):
+ log.warn( '''Found double .activity suffix in bundle path, truncating: %s''', path )
+ path = path[:-9]
+ return path
+except ImportError:
+ log.warn( '''Do not appear to be running under Sugar, stubbing-in get_bundle_path''' )
+ def get_bundle_path():
+ """Retrieve a substitute data-path for non OLPC systems"""
+ return os.path.expanduser( NON_SUGAR_ROOT )
+
+def get_activity_root( ):
+ """Return the activity root for data storage operations
+
+ If the activity is present, returns the activity's root,
+ otherwise returns NON_SUGAR_ROOT as the directory.
+ """
+ import olpcgames
+ if olpcgames.ACTIVITY:
+ return olpcgames.ACTIVITY.get_activity_root()
+ else:
+ return os.path.expanduser( NON_SUGAR_ROOT )
+
+def data_path(file_name):
+ """Return the full path to a file in the data sub-directory of the bundle"""
+ return os.path.join(get_bundle_path(), 'data', file_name)
+def tmp_path(file_name):
+ """Return the full path to a file in the temporary directory"""
+ return os.path.join(get_activity_root(), 'tmp', file_name)
diff --git a/olpcgames/video.py b/olpcgames/video.py
new file mode 100644
index 0000000..c6e0272
--- /dev/null
+++ b/olpcgames/video.py
@@ -0,0 +1,71 @@
+"""Video widget for displaying a gstreamer pipe"""
+import logging
+log = logging.getLogger( 'olpcgames.video' )
+import os
+import signal
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+import gst
+
+class VideoWidget(gtk.DrawingArea):
+ """A custom widget to render GStreamer video."""
+
+ def __init__(self, x=160, y=120):
+ super(VideoWidget, self).__init__()
+ self._imagesink = None
+ self.unset_flags(gtk.DOUBLE_BUFFERED)
+ self.set_size_request(x,y)
+
+ def do_expose_event(self, event):
+ if self._imagesink:
+ self._imagesink.expose()
+ return False
+ else:
+ return True
+
+ def set_sink(self, sink):
+ assert self.window.xid
+ self._imagesink = sink
+ self._imagesink.set_xwindow_id(self.window.xid)
+
+#pipe_desc = 'v4l2src ! video/x-raw-yuv,width=160,height=120 ! ffmpegcolorspace ! xvimagesink'
+pipe_desc = 'v4l2src ! ffmpegcolorspace ! video/x-raw-yuv ! xvimagesink'
+class Player(object):
+ def __init__(self, videowidget):
+ self._playing = False
+ self._videowidget = videowidget
+
+ self._pipeline = gst.parse_launch(pipe_desc)
+
+ bus = self._pipeline.get_bus()
+ bus.enable_sync_message_emission()
+ bus.add_signal_watch()
+ bus.connect('sync-message::element', self.on_sync_message)
+ bus.connect('message', self.on_message)
+
+ def play(self):
+ if self._playing == False:
+ self._pipeline.set_state(gst.STATE_PLAYING)
+ self._playing = True
+
+ def pause(self):
+ if self._playing == True:
+ self._pipeline.set_state(gst.STATE_PAUSED)
+ self._playing = False
+
+ def on_sync_message(self, bus, message):
+ if message.structure is None:
+ return
+ if message.structure.get_name() == 'prepare-xwindow-id':
+ self._videowidget.set_sink(message.src)
+
+ def on_message(self, bus, message):
+ t = message.type
+ if t == gst.MESSAGE_ERROR:
+ err, debug = message.parse_error()
+ log.debug("Video error: (%s) %s" ,err, debug)
+ self._playing = False
+ gtk.main_quit()
+