6820b157598ebf42edefde880791327655c4035b
[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, neighbors):
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, neighbors):
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 = "underground"
49
50 class Tunnel(Tile):
51
52     @classmethod
53     def image(cls, neighbors):
54         connections = len([x for x in neighbors if 'walk' in x['behaviour']])
55         # simple cases
56         if connections == 0:
57             # return single point tunnel
58             pass
59         elif connections == 4:
60             # crossroads
61             pass
62         elif connections == 3:
63             # 3 point connector, rotated correctly
64             pass
65         elif connections == 1:
66             # 1 point connector, roatated correctly
67             pass
68         elif connections == 2:
69             # Need to distinguish pass-through or corner, and
70             # rotate correctly
71             pass
72         cls.IMG = os.path.join('tunnel', 'tunnel_none')
73         return super(Tunnel, cls).image(neighbors)
74         
75
76 TILES = {
77     "cwall": Wall, # rename this everywhere
78     "floor": Floor,
79     "tunnel": Tunnel,
80     "underground": Underground,
81 }
82
83 class LevelLoader(ResourceLoader):
84     """ Level loader. """
85
86     EXTNS = ['json']
87     TYPE = 'level'
88
89     def _load(self, level_path):
90         f = open(level_path, 'r')
91         level_data = json.load(f)
92         f.close()
93         self._height = len(level_data['tiles'])
94         self._width = len(level_data['tiles'][0])
95         self._tiles = level_data['tiles']
96         self._tileset = level_data['tileset']
97         # Consistency check, so we can assume things are correct
98         # in the level renderer
99         for row, row_data in enumerate(self._tiles):
100             if len(row_data) != self._width:
101                 raise RuntimeError("Incorrect len for row %d" % row)
102         for tile in TILES.values():
103             tile.TILESET = self._tileset
104         self._load_tile_images()
105         return level_data
106
107     def _load_tile_images(self):
108         """Load all the tile images"""
109         height = len(self._tiles)
110         width = len(self._tiles[0])
111         for y, row_data in enumerate(self._tiles):
112             for x, tile in enumerate(row_data):
113                 # simplist case
114                 # 4 -connected neighbors
115                 neighborhood = [self._tiles[y][x-1] if x > 0 else None,
116                                 self._tiles[y][x+1] if x < width - 1 else None,
117                                 self._tiles[y-1][x] if y > 0 else None,
118                                 self._tiles[y+1][x] if y < height- 1 else None,
119                                ]
120                 for layer in ['floor', 'tunnels']:
121                     neighbors = [x[layer] if x else None for x in neighborhood]
122                     tile['%s image' % layer] = \
123                             TILES[tile[layer]['base']].image(neighbors)
124
125
126 levels = LevelLoader('levels')