Start work on gate trap
[erdslangetjie.git] / erdslangetjie / level.py
1 # The level object
2
3 import os
4 from data import load_image, load, filepath
5
6 WALL = '.'
7 FLOOR = ' '
8 ENTRY = 'E'
9 EXIT = 'X'
10 GATE = 'G'
11 BUTTON = 'B'
12
13
14 class Level(object):
15
16     def __init__(self, levelfile):
17         self._data = []
18         self.exit_pos = []
19         self.enter_pos = None
20         self._tiles = []
21         self._changed = []
22         self._gates = {}
23         self._buttons = {}
24         # Because of how kivy's coordinate system works,
25         # we reverse the lines so things match up between
26         # the file and the display (top of file == top of display)
27         for line in reversed(levelfile.readlines()):
28             self._data.append(list(line.strip('\n')))
29
30     def load_tiles(self):
31         """Load the list of tiles for the level"""
32         self._tiles = []
33         self._gates = {}
34         self._buttons = {}
35         self.exit_pos = []
36         self._changed = []
37         self.enter_pos = None
38         for j, line in enumerate(self._data):
39             tile_line = []
40             for i, c in enumerate(line):
41                 if c == FLOOR:
42                     tile_line.append(load_image('tiles/floor.png'))
43                 elif c == WALL:
44                     tile_line.append(self._get_wall_tile(i, j))
45                 elif c == ENTRY:
46                     if self.enter_pos:
47                         raise RuntimeError('Multiple entry points')
48                     self.enter_pos = (i, j)
49                     tile_line.append(load_image('tiles/entry.png'))
50                 elif c == EXIT:
51                     self.exit_pos.append((i, j))
52                     tile_line.append(load_image('tiles/door.png'))
53                 elif c == GATE:
54                     tile_line.append('tiles/gate_down.png')
55                     self._gates[(i, j)] = -1  # down
56                 elif c == BUTTON:
57                     tile_line.append('tiles/button.png')
58                     self._buttons[(i, j)] = 'active'
59             self._tiles.append(tile_line)
60
61     def get_tiles(self):
62         return self._tiles
63
64     def get_single_tile(self, pos):
65         return self._tiles[pos[1]][pos[0]]
66
67     def get_size(self):
68         return len(self._tiles[0]), len(self._tiles)
69
70     def at_exit(self, pos):
71         return pos in self.exit_pos
72
73     def _get_wall_tile(self, x, y):
74         # Is the neighbour in this direction also a wall?
75         left = right = top = bottom = False
76         if x == 0:
77             left = True
78         elif self._data[y][x - 1] == WALL:
79             left = True
80         if x == len(self._data[0]) - 1:
81             right = True
82         elif self._data[y][x + 1] == WALL:
83             right = True
84         if y == 0:
85             top = True
86         elif self._data[y - 1][x] == WALL:
87             top = True
88         if y == len(self._data) - 1:
89             bottom = True
90         elif self._data[y + 1][x] == WALL:
91             bottom = True
92         if top and bottom and left and right:
93             return load_image('tiles/cwall.png')
94         elif bottom and left and right:
95             return load_image('tiles/bottom_wall.png')
96         elif top and left and right:
97             return load_image('tiles/top_wall.png')
98         elif top and bottom and right:
99             return load_image('tiles/left_wall.png')
100         elif top and bottom and left:
101             return load_image('tiles/right_wall.png')
102         elif top and bottom:
103             return load_image('tiles/vert_wall.png')
104         elif left and right:
105             return load_image('tiles/horiz_wall.png')
106         elif left and top:
107             return load_image('tiles/corner_lt.png')
108         elif left and bottom:
109             return load_image('tiles/corner_lb.png')
110         elif right and top:
111             return load_image('tiles/corner_rt.png')
112         elif right and bottom:
113             return load_image('tiles/corner_rb.png')
114         elif top:
115             return load_image('tiles/end_top.png')
116         elif bottom:
117             return load_image('tiles/end_bottom.png')
118         elif left:
119             return load_image('tiles/end_right.png')
120         elif right:
121             return load_image('tiles/end_left.png')
122         return load_image('tiles/pillar.png')
123
124     def blocked(self, pos):
125         if pos[0] < 0:
126             return True
127         if pos[1] < 0:
128             return True
129         try:
130             tile = self._data[pos[1]][pos[0]]
131         except IndexError:
132             return True
133         if tile == WALL or tile == ENTRY:
134             return True
135         if tile == GATE:
136             if self._gates[pos] != 'down':
137                 return True
138         return False
139
140     def is_gate(self, pos):
141         return self._data[pos[1]][pos[0]] == GATE
142
143     def is_button(self, pos):
144         return self._data[pos[1]][pos[0]] == BUTTON
145
146     def trigger_button(self, pos):
147         if not self.is_button(pos):
148             return False
149         if not self._buttons[pos] == 'active':
150             return False
151         # Find the closest gate down gate and trigger it
152         gate_pos = pos
153
154         self._changed.append((pos, self.get_single_tile(pos)))
155         self._changed.append((gate_pos, self.get_single_tile(pos)))
156
157     def damage_gate(self, pos):
158         if not self.is_gate(pos):
159             return False
160         if self._gates[pos] == -1 or self._gates[pos] == 0:
161             return False
162         self._gates[pos] = self._gates[pos] - 1
163         self._fix_gate_tile(pos)
164         self._changed.append((pos, self.get_single_tile(pos)))
165         return True
166
167     def get_changed_tiles(self):
168         ret = self._changed[:]
169         self._changed = []
170         return ret
171
172
173 class LevelList(object):
174
175     LEVELS = 'level_list'
176
177     def __init__(self):
178         self.levels = []
179         level_list = load(self.LEVELS)
180         for line in level_list:
181             line = line.strip()
182             if os.path.exists(filepath(line)):
183                 level_file = load(line)
184                 self.levels.append(Level(level_file))
185                 level_file.close()
186             else:
187                 print 'Level list includes non-existant level %s' % line
188         level_list.close()
189         self._cur_level = 0
190
191     def get_current_level(self):
192         if self._cur_level < len(self.levels):
193             return self.levels[self._cur_level]
194         else:
195             return None
196
197     def advance_to_next_level(self):
198         self._cur_level += 1
199         return self.get_current_level()
200
201     def reset(self):
202         self._cur_level = 0