# Tricky Mirrors # mirrors.py - (c) Goetz Schwandtner # schwandtner@googlemail.com # 07-2006, 08-2008 import appuifw from graphics import * import e32 from key_codes import * import random,math VERSION=u'1.0' WIDTH,HEIGHT=8,10 class Keyboard(object): def __init__(self,onevent=lambda:None): self._keyboard_state={} self._downs={} self._onevent=onevent def handle_event(self,event): if event['type'] == appuifw.EEventKeyDown: code=event['scancode'] if not self.is_down(code): self._downs[code]=self._downs.get(code,0)+1 self._keyboard_state[code]=1 elif event['type'] == appuifw.EEventKeyUp: self._keyboard_state[event['scancode']]=0 self._onevent() def is_down(self,scancode): return self._keyboard_state.get(scancode,0) def pressed(self,scancode): if self._downs.get(scancode,0): self._downs[scancode]-=1 return True return False keyboard=Keyboard() appuifw.app.screen='full' # appuifw.app.orientation='portrait' img=None def handle_redraw(rect): if img: canvas.blit(img) appuifw.app.body=canvas=appuifw.Canvas( event_callback=keyboard.handle_event, redraw_callback=handle_redraw) img=Image.new(canvas.size) class CoordGrid(object): def __init__(self,size_py,size_px,width=WIDTH,height=HEIGHT): self.w,self.h=width,height self.comp_x,self.comp_y=size_px/self.w,size_py/self.h self.cx,self.cy=0,0 def isCursor(self,x,y): return self.cx==x and self.cy==y def toScrC(self,x,y): return x*self.comp_x,y*self.comp_y def l(self): self.cx=(self.cx-1+self.w)%self.w def r(self): self.cx=(self.cx+1+self.w)%self.w def u(self): self.cy=(self.cy-1+self.h)%self.h def d(self): self.cy=(self.cy+1+self.h)%self.h (w,h)=canvas.size grid=CoordGrid(h,w) class FieldComp(object): _wmark,_wsel,_wtile=5,2,1 def __init__(self,y,x,grid): self.x,self.y=x,y self.marked=False self._g=grid self._ptx,self._pty=self._g.toScrC(x,y) self._pbx,self._pby=self._g.toScrC(x+1,y+1) self.recpt=[None,None,None,None] def reset(self): pass def action(self,dir): pass def draw(self,img): img.rectangle((self._ptx+FieldComp._wtile,self._pty+FieldComp._wtile,self._pbx-FieldComp._wtile,self._pby-FieldComp._wtile), fill=0x000040) if self._g.isCursor(self.x,self.y): img.rectangle((self._ptx+FieldComp._wsel,self._pty+FieldComp._wsel,self._pbx-FieldComp._wsel,self._pby-FieldComp._wsel), fill=0x700000) if self.marked: img.rectangle((self._ptx+FieldComp._wmark,self._pty+FieldComp._wmark,self._pbx-FieldComp._wmark,self._pby-FieldComp._wmark), fill=0x000070) class Wall(FieldComp): def __init__(self,y,x,grid): FieldComp.__init__(self,y,x,grid) self.marked=False def draw(self,img): FieldComp.draw(self,img) img.rectangle((self._ptx+FieldComp._wmark,self._pty+FieldComp._wmark,self._pbx-FieldComp._wmark,self._pby-FieldComp._wmark), outline=0x606060,width=2*FieldComp._wmark) class LaserColor(object): MINVAL=0xF0F060 MAXVAL=0xFA0000 INCR=0x020000-0x001808 def __init__(self): self.reset() def reset(self): self.val=LaserColor.MINVAL self.doIncrease=False def inc(self): self.doIncrease=True def step(self): if self.doIncrease: self.doIncrease=False if self.valLaserColor.MINVAL: self.val=self.val-LaserColor.INCR LASERCOLOR=LaserColor() class LaserComp(FieldComp): _wl=8 def __init__(self,y,x,grid): FieldComp.__init__(self,y,x,grid) self._ltx,self._lty=(self._ptx+self._pbx-LaserComp._wl)/2,(self._pty+self._pby-LaserComp._wl)/2 self._lbx,self._lby=self._ltx+LaserComp._wl,self._lty+LaserComp._wl self._lcx,self._lcy=(self._ltx+self._lbx)/2,(self._lty+self._lby)/2 self.reset() def reset(self): self.act=[False,False,False,False] self.perf=[False,False,False,False] def draw(self,img): FieldComp.draw(self,img) if self.act[0]: img.rectangle((self._lcx,self._lty,self._pbx,self._lby), fill=LASERCOLOR.val) if self.act[1]: img.rectangle((self._ltx,self._pty,self._lbx,self._lcy), fill=LASERCOLOR.val) if self.act[2]: img.rectangle((self._ptx,self._lty,self._lcx,self._lby), fill=LASERCOLOR.val) if self.act[3]: img.rectangle((self._ltx,self._lcy,self._lbx,self._pby), fill=LASERCOLOR.val) def action(self,dir): if not(self.perf[dir]): self.perf[dir]=True self.act[dir]=True newdir=(dir+2)%4 self.act[newdir]=True if not self.recpt[newdir] is None: self.recpt[newdir].action(dir) class Laser(LaserComp): _ld=8 BACKCOLOR=0x30A030 def __init__(self,y,x,grid,dir,acthandler=None): LaserComp.__init__(self,y,x,grid) self.dir=dir self._start=math.pi/2*((dir+3)%4-2) self._end=math.pi/2*((dir+1)%4-2) self.active=False self.recpt.append(acthandler) def draw(self,img): LaserComp.draw(self,img) if self.active: img.pieslice((self._ptx+Laser._ld,self._pty+Laser._ld,self._pbx-Laser._ld,self._pby-Laser._ld),self._end,self._start,fill=LASERCOLOR.val) else: img.pieslice((self._ptx+Laser._ld,self._pty+Laser._ld,self._pbx-Laser._ld,self._pby-Laser._ld),self._end,self._start,fill=0x606090) img.pieslice((self._ptx+Laser._ld,self._pty+Laser._ld,self._pbx-Laser._ld,self._pby-Laser._ld),self._start,self._end,fill=self.BACKCOLOR) def action(self,dir): if dir==4: self.active=True else: self.act[dir]=True if (dir==self.dir) and self.active: if not self.recpt[4] is None: self.recpt[4].action() def reactivate(self): if self.active: self.act[self.dir]=True if not self.recpt[self.dir] is None: self.recpt[self.dir].action((self.dir+2)%4) class ALaser(Laser): BACKCOLOR=0x3030A0 def auto(self): self.active=not self.active class FLaser(ALaser): BACKCOLOR=0xA03030 def auto(self): pass class LaserTarget(LaserComp): _bdr=8 cnt=0 COLMIN=0x204020 COLMAX=0x20B020 COLDECR=0x004000 def __init__(self,y,x,grid): LaserComp.__init__(self,y,x,grid) self.destroyed=False self.col=LaserTarget.COLMAX LaserTarget.cnt=LaserTarget.cnt+1 def draw(self,img): LaserComp.draw(self,img) if not self.destroyed: img.ellipse((self._ptx+LaserTarget._bdr,self._pty+LaserTarget._bdr,self._pbx-LaserTarget._bdr,self._pby-LaserTarget._bdr),fill=self.col) def action(self,dir): if self.destroyed: LaserComp.action(self,dir) else: self.act[dir]=True if self.col>LaserTarget.COLMIN: self.col=self.col-LaserTarget.COLDECR else: self.destroyed=True LaserTarget.cnt=LaserTarget.cnt-1 LaserComp.action(self,dir) class Bomb(LaserComp): COLOFF=0x707070 COLON1=0x903030 COLON2=0xFF5050 COLEX=0x000000 def __init__(self,y,x,grid): LaserComp.__init__(self,y,x,grid) self.ticking=-1 def draw(self,img): LaserComp.draw(self,img) if self.ticking<0: col=Bomb.COLOFF elif self.ticking==0: col=Bomb.COLEX elif self.ticking%2==1: col=Bomb.COLON2 else: col=Bomb.COLON1 if self.ticking in (0,1): img.rectangle((self._ptx+FieldComp._wtile,self._pty+FieldComp._wtile,self._pbx-FieldComp._wtile,self._pby-FieldComp._wtile), fill=col) else: bdr=3 img.ellipse((self._ptx+bdr,self._pty+bdr,self._pbx-bdr,self._pby-bdr),fill=0x206020) img.ellipse(((self._ptx+self._pbx)/2-2*bdr,(self._pty+self._pby)/2-2*bdr,(self._ptx+self._pbx)/2+2*bdr,(self._pty+self._pby)/2+2*bdr),fill=col) def auto(self): if self.ticking==0: timer.destroyed=True elif self.ticking>0: self.ticking-=1 def action(self,dir): self.act[dir]=True if self.ticking<0: self.ticking=5 class Teleport(LaserComp): _bdr=8 def __init__(self,y,x,grid,target=None): LaserComp.__init__(self,y,x,grid) self.target=target def draw(self,img): LaserComp.draw(self,img) for i in range(5): img.ellipse((self._ptx+LaserTarget._bdr+2*i,self._pty+LaserTarget._bdr+2*i,self._pbx-LaserTarget._bdr-2*i,self._pby-LaserTarget._bdr-2*i),fill=0x6060D0-0x101020*i) def action(self,dir): self.act[dir]=True if not self.target is None: self.target.taction(dir) def taction(self,dir): if not(self.perf[dir]): self.perf[dir]=True newdir=(dir+2)%4 self.act[newdir]=True if not self.recpt[newdir] is None: self.recpt[newdir].action(dir) class Mirror(LaserComp): OUTCOLOR=0xA0A0A0 FILLCOLOR=0x5050A0 PINCOLOR=0x80F080 def __init__(self,y,x,grid,dir=0): LaserComp.__init__(self,y,x,grid) self.dir=dir def action(self,dir): self.act[dir]=True l=self.actionlist[self.dir][dir] for ac in l: if not self.perf[ac]: self.perf[ac]=True self.act[ac]=True if not self.recpt[ac] is None: self.recpt[ac].action((ac+2)%4) def turn(self,dir=4): if dir==4: self.dir=(self.dir+1)%4 elif dir==-1: self.dir=(self.dir+3)%4 else: self.dir=dir class FlatMirror(Mirror): actionlist=(((),(1,),(),(3,)),((3,),(2,),(1,),(0,)),((0,),(),(2,),()),((1,),(0,),(3,),(2,))) _bdr=8 def __init__(self,y,x,grid,dir=0): Mirror.__init__(self,y,x,grid,dir) self._wx=(self._pbx-self._ptx-2*FlatMirror._bdr)*math.sqrt(.5)/2 self._wy=(self._pby-self._pty-2*FlatMirror._bdr)*math.sqrt(.5)/2 self._pmx,self._pmy=(self._pbx+self._ptx)/2,(self._pby+self._pty)/2 self._mcoords=((self._ptx+FlatMirror._bdr,self._pmy,self._pbx-FlatMirror._bdr,self._pmy),(self._pmx-self._wx,self._pmy+self._wy,self._pmx+self._wx,self._pmy-self._wy),(self._pmx,self._pty+FlatMirror._bdr,self._pmx,self._pby-FlatMirror._bdr),(self._pmx-self._wx,self._pmy-self._wy,self._pmx+self._wx,self._pmy+self._wy)) def draw(self,img): Mirror.draw(self,img) img.line(self._mcoords[self.dir],width=10,outline=self.OUTCOLOR) img.line(self._mcoords[self.dir],width=8,outline=self.FILLCOLOR) img.point((self._lcx,self._lcy),width=6,outline=self.PINCOLOR) class FFlatMirror(FlatMirror): PINCOLOR=0xF08080 def __init__(self,y,x,grid,dir=0): FlatMirror.__init__(self,y,x,grid,dir) def turn(self, dir=4): pass class AFlatMirror(FlatMirror): PINCOLOR=0x8080F0 def __init__(self,y,x,grid,dir=0): FlatMirror.__init__(self,y,x,grid,dir) def turn(self, dir=4): pass def auto(self, dir=4): FlatMirror.turn(self,dir) class TriMirror(Mirror): actionlist=(((1,),(0,2),(1,),(3,)),((0,),(2,),(1,3),(2,)),((3,),(1,),(3,),(0,2)),((1,3),(0,),(2,),(0,))) def __init__(self,y,x,grid,dir=0): Mirror.__init__(self,y,x,grid,dir) d,x,y=8,self._lcx,self._lcy self._mcoords=((x,y-d,x-2*d,y+d,x+2*d,y+d),(x-d,y,x+d,y-2*d,x+d,y+2*d),(x,y+d,x+2*d,y-d,x-2*d,y-d),(x+d,y,x-d,y-2*d,x-d,y+2*d)) def draw(self,img): Mirror.draw(self,img) img.polygon(self._mcoords[self.dir],outline=self.OUTCOLOR,fill=self.FILLCOLOR) img.point((self._lcx,self._lcy),width=6,outline=self.PINCOLOR) class FTriMirror(TriMirror): PINCOLOR=0xF08080 def __init__(self,y,x,grid,dir=0): TriMirror.__init__(self,y,x,grid,dir) def turn(self, dir=4): pass class ATriMirror(TriMirror): PINCOLOR=0x8080F0 def __init__(self,y,x,grid,dir=0): TriMirror.__init__(self,y,x,grid,dir) def turn(self, dir=4): pass def auto(self, dir=4): TriMirror.turn(self,dir) class Timer(object): LASERINTRVL=2 AUTOINTRVL=2 def __init__(self): self.cnt=0 self.destroyed=False def action(self): LASERCOLOR.inc() def step(self): res=False self.cnt=self.cnt+1 if self.cnt%Timer.AUTOINTRVL==0: gf.runAutos() res=True if self.cnt%Timer.LASERINTRVL==0: gf.reactivate() if LASERCOLOR.step(): self.destroyed=True res=True return res timer=Timer() class Gamefield(object): NUMLEVELS=9 def __init__(self,level=1): self.dirty=True self.fa=[[LaserComp(y,x,grid) for x in range(WIDTH)] for y in range(HEIGHT)] LaserTarget.cnt=0 self.setFA(level) for y in range(HEIGHT): for x in range(WIDTH): self.link(x,y) appuifw.note(u'Level '+unicode(level)+u':\n'+self.note) def link(self,x,y): if x0: self.fa[y][x].recpt[1]=self.fa[y-1][x] if x>0: self.fa[y][x].recpt[2]=self.fa[y][x-1] if y1 and sys.argv[1]: # self.level=int(sys.argv[1]) global gf self.startLevel() def quit(self): if appuifw.query(u"Quit Tricky Mirrors?",'query'): self.running=0 def startLevel(self): global gf LASERCOLOR.reset() timer.cnt=-1 timer.destroyed=False gf=Gamefield(self.level) def selectLevel(self): l=appuifw.query(u"Select level",'number',self.level) if not l is None: if l<1 or l>gf.NUMLEVELS: l=1 self.level=l self.startLevel() def mainLoop(self): global gf while self.running: if gf.dirty: img.clear(0x000030) gf.draw(img) handle_redraw(()) e32.ao_sleep(0.2) if LaserTarget.cnt==0: appuifw.note(u'Level completed! :-)') if self.level < gf.NUMLEVELS: self.level=self.level+1 self.startLevel() else: appuifw.note(u'You have finished the last level!') self.about() self.quit() if self.running: self.level=1 self.startLevel() self.dirty=timer.step() if timer.destroyed: if appuifw.query(u'Boom!\nRestart level?','query'): self.startLevel() else: self.quit() if keyboard.pressed(EScancodeLeftArrow): grid.l() gf.dirty=True if keyboard.pressed(EScancodeRightArrow): grid.r() gf.dirty=True if keyboard.pressed(EScancodeDownArrow): grid.d() gf.dirty=True if keyboard.pressed(EScancodeUpArrow): grid.u() gf.dirty=True if keyboard.pressed(EScancodeSelect): fld=gf.fa[grid.cy][grid.cx] if isinstance(fld, Laser) and not isinstance(fld, ALaser): fld.active=not fld.active gf.reactivate() elif isinstance(fld, Mirror): fld.turn() gf.reactivate() def about(self): appuifw.note(u'Tricky Mirrors V'+VERSION+u' \n (c) 07-2006, 08-2008 Goetz Schwandtner\nschwandtner@googlemail.com') #global: m=Main() m.mainLoop() appuifw.app.set_exit()