Exemple #1
0
class Mapview(pygame.sprite.DirtySprite, Tempsprites):
    def __init__(self, frontend, *args):
        self._layer = 0
        super(pygame.sprite.DirtySprite, self).__init__()
        self.frontend = frontend
        size = self.frontend.mapw
        self.tilesize = self.frontend.mapscale
        self.rect = pygame.Rect(50,65, self.frontend.mapw, self.frontend.mapw)
        self.background = self.frontend.screen.subsurface(self.frontend.screensize).copy()
        self.image  = pygame.Surface((size, size))
        self.backgrounds = {}
        self.mapw = self.frontend.mapw
        Tempsprites.__init__(self)
        self.dialog = FloatDialog(self.frontend.rightwindow_rect, self.frontend, layer=1)
        self._addtemp('rightwindow', self.dialog)
        if self.frontend.mode == 'editor':
            self.loadmap({})
        else:
            loc = self.frontend.game.player.location()
            mapname = loc['map']
            self.loadmap(load_yaml('maps', mapname))


    def tileimage(self, x, y, scale):
        tile = self.gamemap.tile(x,y)
        tileimage = pygame.Surface((16, 16))
        backgroundpath = tile.background()
        if backgroundpath:
            backgroundimage = self.frontend.tilemaps.get_by_path(backgroundpath)
        else:
            backgroundimage = pygame.Surface((scale, scale))
        if backgroundpath and (tile.revealed() or self.frontend.mode == 'editor'):
            tileimage.blit(backgroundimage,(0,0))
            tileimage = pygame.transform.smoothscale(tileimage, (scale, scale))
            if self.frontend.mode == 'editor':
                tileimage.blit(render_text('%sX%s' %(x,y), size=(self.tilesize/2), color=(0,0,0), font=pygame.font.Font(None,16) ), (self.tilesize/2,self.tilesize/2))
        else:
            if self.frontend.mode == 'editor':
                if y%2 == 0 and x%2 == 0 or y%2 == 1 and x%2 == 1:
                    r, t = 255, 0
                else:
                    r, t = 0, 255
                backgroundimage.fill((r,r,r,0))
                backgroundimage.blit(render_text('%sX%s' %(x,y), size=(self.tilesize/2), color=(t,t,t), font=pygame.font.Font(None,16) ), (1,1))
                tileimage =backgroundimage
            else:
                tileimage.fill((0,0,0,0))
        return tileimage

    def tileicons(self, x, y, scn_x, scn_y, scale):
        rect = pygame.Rect(scn_x, scn_y, scale, scale)
        if self.frontend.mode != 'editor':
            if not self.gamemap.tile(x,y).get('revealed', False):
                return
            player = self.frontend.game.player
            loc = player.location()
            if loc['x'] == x and loc['y'] == y and not 'player' in self.frontend.sprites:
                playerbtn = ButtonSprite(
                    self.frontend.tilemaps,
                    rect,
                    self.frontend.eventstack,
                    onclick = self.click,
                    onclick_params = [(scn_x,scn_y)],
                    animations = player.getsubtree('animations'),
                    layer=self._layer+2,
                    fps=5,
                    mouseover=player.displayname(),
                    frontend=self.frontend)
                self.frontend.sprites['player'] = playerbtn
        scn_x = 50+(self.tilesize*x)
        scn_y = 65+(self.tilesize*y)
        npc = None
        animations = {'view':[]}
        for objtype, item in self.gamemap.tile_objects(x,y):
            if objtype != 'npc':
                animations['view'] += item.get('animations/view')
            else:
                npc = ButtonSprite(
                    self.frontend.tilemaps,
                    rect,
                    self.frontend.eventstack,
                    onclick = self.click,
                    onclick_params = [(scn_x,scn_y)],
                    animations = item.getsubtree('animations'),
                    layer=self._layer+2,
                    fps=5,
                    mouseover=item.displayname(),
                    frontend=self.frontend)
        if animations['view'] and npc is None:
            itemsprite = ButtonSprite(
                self.frontend.tilemaps,
                rect,
                self.frontend.eventstack,
                onclick = self.click,
                onclick_params = [(scn_x,scn_y)],
                animations = animations,
                layer=self._layer+1,
                fps=3,
                frontend=self.frontend)
            self._addtemp(make_hash(), itemsprite)
        if npc is not None and not npc.get_hash() in self.frontend.sprites:
            self.frontend.sprites[npc.get_hash()] = npc
            if not npc in self.frontend.game.characters: 
                self.frontend.game.characters.append(npc)

    def update(self):
        self.loadmap(self.gamemap())


    def zoomicons(self, x, y, scn_x, scn_y):
        objlist = list(self.gamemap.tile_objects(x,y))
        n = len(objlist)
        if not n:
            return
        col, row = 0, 0
        if n%2 != 0:
            n += 1
        colcount = n/2
        if n < 4:
            scale = int(128/n)
        else:
            scale = int(128/colcount)
        for objtype,item in objlist:
            s_x = scn_x + col*scale
            s_y = scn_y + row*scale
            rect = pygame.Rect(s_x, s_y, scale, scale)
            if objtype != 'money':
                animations = item.getsubtree('animations')
                name=item.displayname()
            else:
                animations = item
                name='Money'
            itemsprite = ButtonSprite(
            self.frontend.tilemaps,
            rect,
            self.frontend.eventstack,
            onclick = self.targetclick,
            onclick_params = [x,y,objtype, item],
            animations = animations,
            layer=self._layer+2,
            mouseover=name,
            fps=5,
            frontend=self.frontend)
            if objtype == 'npc':
                itemsprite.setanimation('stand')
            else:
                itemsprite.setanimation('view')
            self._addtemp(make_hash(), itemsprite)
            col += 1
            if col == colcount:
                col = 0
                row += 1
    
    def targetclick(self,x,y,objtype, item):
        minx, miny = self.frontend.rightwindow_rect.x + 10, self.frontend.rightwindow_rect.y + 10
        if self.frontend.mode == 'editor':
            rmBtn = Button('Remove',
            self.removefromtile,
            [x,y,objtype,item],
            self.frontend.eventstack,
            self.frontend.imagecache,
            pos=(minx,miny + 185)
            )
            self._addtemp(make_hash(), rmBtn)

    def removefromtile(self,x,y,objtype,item):
        self.gamemap.removefromtile(x,y,item,objtype)
        self.tile = self.gamemap.tile(x,y)
        self._rmtemp()
        self.updatetile(x, y)

    def delete(self):
        self.frontend.eventstack.unregister_event(self.clickhash)
        del self.frontend.sprites['rightwindow']
        self._rmtemp()
        self.kill()
        self.frontend.screen.blit(self.background, (0,0))

    def registerclickevent(self):
        self.clickhash = self.frontend.eventstack.register_event("button1", self, self.click)
        if self.frontend.mode != 'editor':
            self.frontend.eventstack.register_event("keydown", self, self.keydown)
            self.has_focus = True

    def maploadsavename(self):
        name = self.gamemap.get('name','Enter map displayname here')
        self.mapname = TextInput(
            pygame.Rect(50, self.frontend.mapw+70, self.mapw /2,25),
            16, self.frontend.eventstack, 
            prompt=self.gamemap.get('name',name))
        mapload = Button('Load', self.load, [], self.frontend.eventstack,self.frontend.imagecache, pos=(self.mapw/2 + 50,self.frontend.mapw+67))
        mapsave = Button('Save', self.save, [], self.frontend.eventstack,self.frontend.imagecache, pos=(self.mapw/2 + 150,self.frontend.mapw+67))
        self._addtemp('mapname', self.mapname)
        self._addtemp('mapload', mapload)
        self._addtemp('mapsave', mapsave)        

    def loadmap(self, data, reload=False):
        if reload:
            self._rmtemp()
        self.registerclickevent()
        self.gamemap = GameMap(data)
        self.gamemap.initialize(data=data)
        if self.frontend.mode == 'editor':
            self.maploadsavename()
        for x in range(0,20):
            for y in range(0,20):
                scn_x = 50+(self.tilesize*x)
                scn_y = 65+(self.tilesize*y)
                self.image.blit(self.tileimage(x,y, self.tilesize),(self.tilesize*x, self.tilesize*y))
                self.tileicons(x,y, scn_x, scn_y, self.tilesize)

    def load(self):
        self._addtemp('te_mapselector',MapSelector(self.rect, self.frontend, self.loadmap))
        self.frontend.draw() 

    def save(self):
        if self.mapname.text:
            self.gamemap.put('name', self.mapname.text)
        filename = self.gamemap.save_to_file('maps')
        messages.error('Saved to: %s' % os.path.basename(filename))

    def player_can_goto(self, x, y):
        loc = self.frontend.game.player.location()
        xdiff = loc['x'] - x
        ydiff = loc['y'] - y
        distance = hypot(xdiff, ydiff)
        return distance <= 1.5 and self.gamemap.tile(x,y).canenter()

    def player_controls(self, x,y, surface):
        minx, miny = self.frontend.rightwindow_rect.x + 10, self.frontend.rightwindow_rect.y + 10
        maxx, maxy = minx + self.frontend.rightwindow_rect.w - 10, self.frontend.rightwindow_rect.h - 10
        if self.player_can_goto(x, y):
             player_go_here = Button('Go Here', 
                                    self.goto, 
                                    ['player', x, y],
                                    self.frontend.eventstack,
                                    self.frontend.imagecache,
                                    pos=(minx +180,miny + 10))
             self._addtemp('player_go_here', player_go_here)

    def keydown(self, event):
        messages.message('Processing event '+event.unicode)
        loc = self.frontend.game.player.location()
        x = loc['x']
        y = loc['y']
        if event.key == K_LEFT or event.unicode.upper() == 'A':
            x -= 1
        elif event.key == K_RIGHT or event.unicode.upper() == 'D':
            x += 1
        elif event.key == K_UP or event.unicode.upper() == 'W':
            y -= 1
        elif event.key == K_DOWN or event.unicode.upper() == 'S':
            y += 1
        else:
            return False
        if self.player_can_goto(x, y):
            self.goto('player', x, y)
        return True

    def goto(self, charname, x, y):
        sprite = self.frontend.sprites[charname]
        scn_x = 50+(self.tilesize*x)
        scn_y = 65+(self.tilesize*y)
        sprite.onarive = self.arrive_at
        sprite.onarive_params = [charname,x,y]
        sprite.goto = (scn_x, scn_y)

    def arrive_at(self, charname, x, y):
        if charname == 'player':
            self.frontend.game.player.moveto(self.gamemap, x,y)
            self.frontend.game.player.savetoslot()
        else:
            for char in self.frontend.game.characters:
                if char.get_hash() == charname:
                    char.moveto(self.gamemap, x, y)
                    char.savetoslot('characters')
                    break
        self.gamemap.savetoslot('maps')



    def tile_editor(self, x, y, surface):
        surface.blit(render_text('Edit tile', color=(255,0,0)),(280,10))
        minx, miny = self.frontend.rightwindow_rect.x + 10, self.frontend.rightwindow_rect.y + 10
        maxx, maxy = minx + self.frontend.rightwindow_rect.w - 10, self.frontend.rightwindow_rect.h - 10
        te_canenter = checkboxbtn('Player can enter tile ?', self.canenter, (x,y), self.frontend.eventstack,self.frontend.imagecache, pos=(minx + 180,miny + 60))
        te_revealed = checkboxbtn('Tile has been revealed ?', self.revealed, (x,y), self.frontend.eventstack,self.frontend.imagecache, pos=(minx + 180,miny + 90))
        te_canenter.checked = self.gamemap.tile(x,y).canenter()
        te_revealed.checked = self.gamemap.tile(x,y).revealed()
        if self.tile.background():
            self._addtemp('te_rotate', Button('Rotate background', 
                self.rotate, (x,y), self.frontend.eventstack,self.frontend.imagecache, pos=(minx + 180, miny + 120)))
        self._addtemp('te_canenter', te_canenter)
        self._addtemp('te_revealed', te_revealed)
        self._addtemp('te_set_background', Button('Set Background', 
            self.selectbg, (x,y), self.frontend.eventstack,self.frontend.imagecache, pos=(minx + 180, miny + 30)))
        if self.tile.background() and self.tile.canenter():
            te_additem = Button('Add Item', self.additem, [x,y], self.frontend.eventstack,self.frontend.imagecache, pos=(minx,miny + 160))
            te_addnpc = Button('Add NPC', self.addnpc, [x,y], self.frontend.eventstack,self.frontend.imagecache, pos=(minx + 120,miny + 160))
            te_onenter = Button('Events/OnEnter', self.onenter, [x,y], self.frontend.eventstack,self.frontend.imagecache, pos=(minx + 250,miny + 160))
            self._addtemp('te_additem', te_additem)
            self._addtemp('te_addnpc', te_addnpc)
            self._addtemp('te_onenter', te_onenter)
        te_clone_tile = Button('Clone Tile', self.clonetile, [x,y], self.frontend.eventstack,self.frontend.imagecache, pos=(minx,miny + 200))
        self._addtemp('te_clone', te_clone_tile)
        clone_coords = TextInput(
            pygame.Rect(minx + 150,  miny + 200, 100,25),
            16, self.frontend.eventstack, 
            prompt='%sx%s' %(x,y), layer=3)
        self._addtemp('te_clone_coords', clone_coords)
        debug(self.frontend.sprites)

    def clonetile(self, x,y):
        target=self.frontend.sprites['te_clone_coords'].text
        tx, ty = target.split('x')
        tx, ty = int(tx), int(ty)
        for iy in range(y,ty +1):
            for ix in range(x,tx +1):
                self.gamemap.copy_tile(x,y,ix,iy)
        self.updatetile(x, y)

    def selectlist(self, dirname,action, x, y):
        self._rmtemp()
        itemlist = []
        for itemfile in file_list(dirname):
            itemfile = os.path.basename(itemfile)
            itemlist.append(Item(load_yaml(dirname,itemfile)))
        c = ContainerDialog(self.rect,
            self.frontend,
            'Add %s' % dirname,
            self._layer + 1,
            items=itemlist,
            onclose=action,
            onclose_parms=[x,y],
            onselect=action,
            onselect_parms=[x,y],
            animation='view',
            can_add=False,
            can_remove=False)
        self._addtemp('te_listmanager' , c)

    def additem(self, x, y):
        self.selectlist('items', self.newitem, x, y)


    def addnpc(self, x, y):
        self.selectlist('characters', self.newnpc, x, y)

    def onenter(self,x,y):
        default = default_text
        data = self.gamemap.tile(x,y).get('events/onenter', default)
        data = editsnippet('\n'.join(data))
        tile = self.gamemap.tile(x,y)
        tile.put('events/onenter',data.split('\n'))
        self.gamemap.load_tile(x,y,tile)
        self.tile = self.gamemap.tile(x,y)
        self.updatetile(x, y)

    def newnpc(self, item, x,y):
        self._rmtemp()
        if item is not None:
            self.gamemap.addtotile( x, y, item, 'npc')
            debug(self.gamemap())
        self.tile = self.gamemap.tile(x,y)
        self.updatetile(x, y)

    def newitem(self, item,x,y):
        self._rmtemp()
        if item is not None:
            self.gamemap.addtotile( x, y, item, 'items')
        self.tile = self.gamemap.tile(x,y)
        self.updatetile(x, y)

    def selectbg(self, x, y):
        self._addtemp('te_tileselector',TileSelector(self.rect, self.frontend, self.setbg, (x,y)))

    def setbg(self, bgpath, x, y):
        map_x, map_y = x, y
        self.tile = self.gamemap.tile(map_x,map_y)
        self.tile.put('background', bgpath)
        self.updatetile(x,y) 
        x = x*self.tilesize+50
        y = y*self.tilesize+65
        self.click((x,y))

    def rotate(self, x,y):
        bgpath = imagepath(self.tile.background())
        rot = int(bgpath[3])
        if rot == 270:
            rot = 0
        else:
            rot += 90
        bgpath = [bgpath[0], bgpath[1], bgpath[2], str(rot)]
        bgpath = ':'.join([str(I) for I in bgpath])
        self.setbg(bgpath, x, y)


    def canenter(self, x, y):
        self.tile.canenter(self.frontend.sprites['te_canenter'].checked)
        self.updatetile(x, y)

    def revealed(self, x, y):
        self.tile.put('/revealed', self.frontend.sprites['te_canenter'].checked)
        self.updatetile(x, y)

    def updatetile(self, x, y):
        self.gamemap.load_tile(x,y,self.tile)
        self.loadmap(self.gamemap())
        self.dialog = FloatDialog(self.frontend.rightwindow_rect, self.frontend, layer=1)
        self._addtemp('rightwindow', self.dialog)
        zoomimage = self.tileimage(x, y, 128)
        self.dialog.image.blit(zoomimage, (15,15))
        self.zoomicons(x, y, self.frontend.rightwindow_rect.x + 15,self.frontend.rightwindow_rect.y + 15)
        if self.frontend.mode == 'editor':
            self.maploadsavename()
            self.tile_editor(x,y, self.dialog.image)
        else:
            self.player_controls(x,y, self.dialog.image)

    def click(self, pos):
        self._rmtemp()
        x, y = pos
        x = x - 50
        y = y - 65
        map_x = int(x / self.tilesize)
        map_y = int(y / self.tilesize)
        self.tile = self.gamemap.tile(map_x, map_y)
        if self.tile.get('revealed', False) or self.frontend.mode == 'editor':
            self.updatetile(map_x, map_y)