diff options
Diffstat (limited to 'gui/tmxmap.py')
-rw-r--r-- | gui/tmxmap.py | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/gui/tmxmap.py b/gui/tmxmap.py new file mode 100644 index 0000000..800868e --- /dev/null +++ b/gui/tmxmap.py @@ -0,0 +1,175 @@ + +# import pytmx +import zipfile +from itertools import cycle, islice +try: + import cPickle as pickle +except ImportError: + import pickle + +from kivy.core.image import Image as CoreImage +from kivy.uix.widget import Widget +from kivy.uix.image import Image +from kivy.graphics.texture import Texture +from kivy.animation import Animation +from kivy.properties import (StringProperty, ObjectProperty, + NumericProperty, DictProperty) +from kivy.logger import Logger + +from pathfind import breadth_first_search +import net.mapserv as mapserv + + +def kivy_image_loader(filename, colorkey, **kwargs): + texture = CoreImage(filename).texture + + def loader(rect, flags): + x, y, w, h = rect + t = texture.get_region(x, + texture.height - y - h, + w, h) + + if flags.flipped_diagonally: + t.flip_horizontal() + t.flip_vertical() + elif flags.flipped_vertically: + t.flip_vertical() + elif flags.flipped_horizontally: + t.flip_horizontal() + + return t + + return loader + + +def create_map_texture(map_data, tile_size=4): + map_size = len(map_data[0]), len(map_data) + texture = Texture.create(size=(map_size[0] * tile_size, + map_size[1] * tile_size), + colorfmt='rgb') + + c = cycle('\x45\x46\x47') + s = islice(c, 3 * 4000) + buf = b''.join(s) + + for y, row in enumerate(map_data): + for x, cell in enumerate(row): + if cell > 0: + continue + + texture.blit_buffer(buf, size=(tile_size, tile_size), + colorfmt='rgb', + pos=(x * tile_size, y * tile_size)) + + texture.flip_vertical() + + return texture + + +class BeingWidget(Widget): + anim = ObjectProperty(None) + name = StringProperty() + + +class MapWidget(Image): + tile_size = NumericProperty(32) + player = ObjectProperty() + collisions = ObjectProperty(None) + current_attacks = DictProperty() + beings = DictProperty() + maps = {} + + def load_map(self, name, *args): + if name not in self.maps: + Logger.info("Caching map %s", name) + zf = zipfile.ZipFile('mapdb.zip', 'r') + self.maps[name] = pickle.load(zf.open(name + '.pickle')) + zf.close() + # m = pytmx.TiledMap(filename=filename) + # data = m.get_layer_by_name('Collision').data + texture = create_map_texture(self.maps[name]['collisions'], + self.tile_size) + self.texture = texture + self.size = texture.size + self.collisions = self.maps[name]['collisions'] + + def to_game_coords(self, pos): + ts = self.tile_size + height = len(self.collisions) + x = int(pos[0] // ts) + y = height - int(pos[1] // ts) - 1 + return x, y + + def from_game_coords(self, pos): + ts = self.tile_size + height = len(self.collisions) + x = pos[0] * ts + y = (height - pos[1] - 1) * ts + return x, y + + def move_being(self, being, gx, gy, speed=150): + ts = self.tile_size + ox = int(being.x // ts) + oy = int(being.y // ts) + gy = len(self.collisions) - gy - 1 + + try: + path = breadth_first_search(self.collisions, + (ox, oy), (gx, gy)) + except KeyError: + path = [] + + if being.anim: + being.anim.stop(being) + + being.anim = Animation(x=being.x, y=being.y, duration=0) + + for i in range(len(path) - 1): + cx, cy = path[i + 1] + px, py = path[i] + distance = max(abs(cx - px), abs(cy - py)) + being.anim += Animation(x=cx * ts, y=cy * ts, + duration=distance * speed / 1000.) + + being.anim.start(being) + + def get_attack_points(self, *bind_args): + points = [] + try: + player_id = mapserv.server.char_id + except AttributeError: + player_id = 0 + for (id1, id2) in self.current_attacks: + try: + # Temporary workaround + if id1 == player_id: + x1, y1 = self.player.pos + else: + x1, y1 = self.beings[id1].pos + if id2 == player_id: + x2, y2 = self.player.pos + else: + x2, y2 = self.beings[id2].pos + points.extend([x1, y1, x2, y2]) + except: + pass + + return points + + def get_attack_endpoints(self, *bind_args): + points = [] + try: + player_id = mapserv.server.char_id + except AttributeError: + player_id = 0 + for (_, target) in self.current_attacks: + try: + if target == player_id: + x, y = self.player.pos + else: + x, y = self.beings[target].pos + points.extend([x, y]) + except: + pass + + return points |