Add placeholder underground tile types
[koperkapel.git] / koperkapel / loaders / levelloader.py
1 """Loader a level, using the pygame-zero ResourceLoader infrastructure"""
2
3 import os
4 import json
5
6 from pgzero.loaders import images, ResourceLoader
7 import os
8 import random
9 from pygame.transform import rotate
10
11 class Tile:
12     IMG = None
13     TILESET = None
14
15     @classmethod
16     def image(cls):
17         if cls.IMG is None or cls.TILESET is None:
18             raise NotImplementedError()
19         return images.load(os.path.join(cls.TILESET, cls.IMG))
20
21 class RandomizedTile(Tile):
22     IMGDIR = None
23     TILESET = None
24     ROTATE = None
25
26     @classmethod
27     def image(cls):
28         if cls.IMGDIR is None or cls.TILESET is None:
29             raise NotImplementedError()
30
31         imgdir = os.path.join(os.path.dirname(__file__), '..', 'images',
32                 cls.TILESET, cls.IMGDIR)
33         imgpath = os.path.splitext(random.choice(os.listdir(imgdir)))[0]
34         img = images.load(os.path.join(cls.TILESET, cls.IMGDIR, imgpath))
35
36         if cls.ROTATE:
37             img = rotate(img, 90 * random.randint(0, 3))
38
39         return img
40
41 class Floor(RandomizedTile):
42     IMGDIR = "floor"
43
44 class Wall(RandomizedTile):
45     IMGDIR = "wall"
46
47 class Underground(RandomizedTile):
48     IMGDIR = "wall"
49
50 class Tunnel(RandomizedTile):
51     IMGDIR = "floor"
52
53 TILES = {
54     "cwall": Wall, # rename this everywhere
55     "floor": Floor,
56     "tunnel": Tunnel,
57     "underground": Underground,
58 }
59
60 class LevelLoader(ResourceLoader):
61     """ Level loader. """
62
63     EXTNS = ['json']
64     TYPE = 'level'
65
66     def _load(self, level_path):
67         f = open(level_path, 'r')
68         level_data = json.load(f)
69         f.close()
70         self._height = len(level_data['tiles'])
71         self._width = len(level_data['tiles'][0])
72         self._tiles = level_data['tiles']
73         self._tileset = level_data['tileset']
74         # Consistency check, so we can assume things are correct
75         # in the level renderer
76         for row, row_data in enumerate(self._tiles):
77             if len(row_data) != self._width:
78                 raise RuntimeError("Incorrect len for row %d" % row)
79         for tile in TILES.values():
80             tile.TILESET = self._tileset
81         self._load_tile_images()
82         return level_data
83
84     def _load_tile_images(self):
85         """Load all the tile images"""
86         for row_data in self._tiles:
87             for tile in row_data:
88                 for layer in ['floor', 'tunnels']:
89                     tile['%s image' % layer] = TILES[tile[layer]['base']].image()
90
91
92 levels = LevelLoader('levels')