""" Copyright 2008 Ben Sarsgard This file is part of PallidumZ. PallidumZ is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. PallidumZ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with PallidumZ. If not, see . """ import copy import math from enum import Enum from pygame.sprite import Sprite from helpers import * import game.board.Features from game.board.Features import * class Node(object): Directions = Enum('N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW') Types = Enum('Floor', 'Terrain', 'Object', 'Actor') def __init__(self, parent, sprite=None): self.parent = parent self.sprite = sprite self.neighbors = {} def MatchTiles(self): if isinstance(self.sprite, game.board.Features.Wall): self.sprite.directions = [] for key in self.neighbors.keys(): if self.neighbors[key].sprite.__class__ == self.sprite.__class__: print "Matched %s %s" % (self.sprite.__class__, key) self.sprite.directions.append(key) self.sprite.RefreshImage() class Layer(Node): Projections = Enum('BirdsEye', 'Isometric') def __init__(self, width, height, tile_width, tile_height, projection, parent=None, scale=1, fill=None): Node.__init__(self, parent=parent) self.scale = scale self.width = width self.height = height self.tile_width = tile_width self.tile_height = tile_height self.tile_aspect = float(tile_width) / float(tile_height) self.projection = projection self.children = [] self.contents = [] for yy in xrange(0, height): self.contents.append([]) for xx in xrange(0, width): node = Node(parent=self, sprite=copy.copy(fill)) self.MatchNode(node, (xx, yy)) self.contents[yy].append(node) def __len__(self): return len(self.contents) def __getitem__(self, key): return self.contents[key] def __setitem__(self, key, value): self.contents[key] = value def MatchNode(self, node, xy): xx = xy[0] yy = xy[1] if xx > 0: node.neighbors[Node.Directions.W] = self.contents[yy][xx-1] self.contents[yy][xx-1].neighbors[Node.Directions.E] = node #self.contents[yy][xx-1].MatchTiles() if yy > 0: node.neighbors[Node.Directions.NW] = self.contents[yy-1][xx-1] self.contents[yy-1][xx-1].neighbors[Node.Directions.SE] = node #self.contents[yy-1][xx-1].MatchTiles() if yy > 0: node.neighbors[Node.Directions.N] = self.contents[yy-1][xx] self.contents[yy-1][xx].neighbors[Node.Directions.S] = node #self.contents[yy-1][xx].MatchTiles() if xx < self.width - 1: node.neighbors[Node.Directions.NE] = self.contents[yy-1][xx+1] self.contents[yy-1][xx+1].neighbors[Node.Directions.SW] = node #self.contents[yy-1][xx+1].MatchTiles() #node.MatchTiles() def AddSprite(self, xy, sprite): #self.MatchNode(node, xy) self.contents[xy[1]][xy[0]].sprite = sprite def AddChild(self, scale=1, fill=None): child = Layer(self.width / scale, self.height / scale, self.tile_width * scale, self.tile_height * scale, self.projection, parent=self, scale=scale, fill=fill) self.children.append(child) return child def Draw(self, view, offset, mini_map, tile_group): for yy in xrange(self.height): for xx in xrange(self.width): origin = self.GetOrigin(view) self.DrawTile((xx,yy), view, origin, offset, mini_map, tile_group) def DrawTile(self, pos, view, origin, offset, mini_map, tile_group): # draw the mini map xx,yy = pos if self[yy][xx].sprite is not None: if self[yy][xx].sprite.color is not None: mini_map_color = self[yy][xx].sprite.color pygame.draw.line(mini_map, mini_map_color, (math.floor(xx * self.scale), math.floor(yy * self.scale)), (math.ceil((xx + 1) * self.scale) - 1, math.ceil((yy + 1) * self.scale) - 1)) # top_left = # top_right = (math.floor((xx + 1) * self.scale - 1), math.floor(yy * self.scale)) # bot_right = # bot_left = (math.floor(xx * self.scale), math.floor((yy + 1) * self.scale - 1)) # pygame.draw.lines(mini_map, mini_map_color, True, [top_left, top_right, bot_right, bot_left]) if self[yy][xx].sprite.image is not None: # draw the tile draw_x, draw_y = self.GetScreenPositionForTile((xx, yy), view, origin, offset) if -self.tile_width <= draw_x < view[0] and -self.tile_height <= draw_y < view[1]: # it's in the view port # vertically snap to bottom of tile if self.scale != 1: print "dy=%i, sh=%i, th=%i, ny=%i" % (draw_y, self[yy][xx].sprite.image.get_height(), self.tile_height, self[yy][xx].sprite.image.get_height() - self.tile_height) draw_y -= self[yy][xx].sprite.image.get_height() - self.tile_height # horizontally center draw_x -= int((self[yy][xx].sprite.image.get_width() - self.tile_width) / 2) self[yy][xx].sprite.rect = pygame.Rect(draw_x, draw_y, self[yy][xx].sprite.image.get_width(), self[yy][xx].sprite.image.get_height()) tile_group.add(self[yy][xx].sprite) for child in self.children: for child_yy in xrange(yy / child.scale, (yy + 1) / child.scale): for child_xx in xrange(xx / child.scale, (xx + 1) / child.scale): child.DrawTile((child_xx,child_yy), view, origin, offset, mini_map, tile_group) def GetOrigin(self, view): # get the raw offset for the origin 0,0 tile if self.projection == Layer.Projections.BirdsEye: origin_x = 0 origin_y = 0 elif self.projection == Layer.Projections.Isometric: origin_x = view[0] / 2# - (self.tile_width / 2) origin_y = self.tile_height#view_height / 2 - (self.tile_height / 2) return origin_x, origin_y def GetScreenPositionForTile(self, map_pos, view, origin, offset, delta=None): if self.projection == Layer.Projections.BirdsEye: screen_x = origin[0] + map_pos[0] * self.tile_width screen_y = origin[1] + map_pos[1] * self.tile_height if delta is not None: screen_x += delta[0] screen_y += delta[1] elif self.projection == Layer.Projections.Isometric: map_pos = (map_pos[0] - offset[0] / self.scale, map_pos[1] - offset[1] / self.scale) screen_x = origin[0] - (map_pos[1] * self.tile_width / 2) + (map_pos[0] * self.tile_width / 2) - (self.tile_width / 2) screen_y = origin[1] + (map_pos[1] * self.tile_height / 2) + (map_pos[0] * self.tile_height / 2) if delta is not None: iso_delta_x = (delta[0] - delta[1]) / 2 * self.tile_aspect iso_delta_y = (delta[1] / 2) + (delta[0] / 2) screen_x += iso_delta_x screen_y += iso_delta_y return screen_x, screen_y def GetTileAtScreenPosition(self, screen_pos, view, offset): origin_x, origin_y = self.GetOrigin(view) map_x_screen = screen_pos[0] - origin_x map_y_screen = screen_pos[1] - origin_y if self.projection == Layer.Projections.BirdsEye: map_x = map_x_screen / self.tile_width map_y = map_y_screen / self.tile_height map_delta_x = map_x_screen % self.tile_width map_delta_y = map_y_screen % self.tile_height elif self.projection == Layer.Projections.Isometric: map_x_raw = map_y_screen + int(map_x_screen / self.tile_aspect) map_y_raw = map_y_screen - int(map_x_screen / self.tile_aspect) map_x = map_x_raw / self.tile_height map_y = map_y_raw / self.tile_height map_delta_x = map_x_raw % self.tile_height map_delta_y = map_y_raw % self.tile_height map_x += offset[0] / self.scale map_y += offset[1] / self.scale return map_x, map_y, map_delta_x, map_delta_y