Reorganise tiles so we can potentially create tilesets
[koperkapel.git] / koperkapel / generators / maps.py
1 """ Procedural map generation for levels """
2
3 import random
4 import math
5 import json
6 import os
7
8 i = random.randint(0,100)
9
10
11 ATTRIBUTE_MAP = {
12     '#': {'base': 'cwall', 
13           'behaviour': [],
14          },
15     ' ': {'base': 'floor',
16           'behaviour': ['walk', 'fly'],
17          },
18 }
19
20
21 class LevelGenerator:
22     width = 0
23     height = 0
24     rooms = 0
25     map = None
26     min_room_size = 0
27     max_room_size = 0
28     dist_from_edge = 0
29     dist_from_other_rooms = 0
30     regions = None
31     region = 0
32     region_size_in_tiles = 0
33
34     def __init__(self, width, height, rooms, min_room_size, max_room_size, dist_from_edge,
35                  dist_from_other_rooms, region_size_in_tiles):
36         """ Initialize the level parameters
37         """
38         self.width = width
39         self.height = height
40         self.rooms = rooms
41         self.min_room_size = min_room_size
42         self.max_room_size = max_room_size
43         self.dist_from_edge = dist_from_edge
44         self.dist_from_other_rooms = dist_from_other_rooms
45         self.region_size_in_tiles = region_size_in_tiles
46
47     def generate(self):
48         """ Generate a random level map
49         """
50         self.generate_regions()
51         row = ['#' for x in range(self.width * self.region_size_in_tiles)]
52         self.map = [row[:] for x in range(self.height * self.region_size_in_tiles)]
53         regions_selected = random.sample(range(self.region), min(self.region, self.rooms))
54         print('Regions: %s' % str(regions_selected))
55         for region in regions_selected:
56             self.generate_room(region)
57
58     def generate_regions(self):
59         """ Generate a random level region map
60         """
61         row = ['#' for x in range(self.width)]
62         self.regions = [row[:] for x in range(self.height)]
63         for h in range(self.height):
64             for w in range(self.width):
65                 random_number = random.randint(0, 2)
66                 if w == h == 0:
67                     self.regions[h][w] = self.region
68                     self.region += 1
69                 elif h == 0:
70                     if random_number > 1:
71                         try:
72                             self.regions[h][w] = self.regions[h][w - 1]
73                         except:
74                             print(h, w)
75                             raise
76                     else:
77                         self.regions[h][w] = self.region
78                         self.region += 1
79                 elif w == 0:
80                     if random_number > 1:
81                         self.regions[h][w] = self.regions[h - 1][w]
82                     else:
83                         self.regions[h][w] = self.region
84                         self.region += 1
85                 else:
86                     if random_number > 1:
87                         self.regions[h][w] = self.regions[h - 1][w]
88                     elif random_number > 0:
89                         self.regions[h][w] = self.regions[h][w - 1]
90                     else:
91                         self.regions[h][w] = self.region
92                         self.region += 1
93
94     def generate_room(self, region_selected):
95         """
96         """
97         for h in range(self.height):
98             for w in range(self.width):
99                 if self.regions[h][w] == region_selected:
100                     if w == 0:
101                         w_dist = self.dist_from_other_rooms
102                     elif self.regions[h][w-1] == region_selected:
103                         w_dist = 0
104                     else:
105                         w_dist = self.dist_from_other_rooms
106
107                     if w + 1 == self.width:
108                         e_dist = self.region_size_in_tiles - self.dist_from_other_rooms
109                     elif self.regions[h][w+1] == region_selected:
110                         e_dist = self.region_size_in_tiles
111                     else:
112                         e_dist = self.region_size_in_tiles - self.dist_from_other_rooms
113
114                     if h == 0:
115                         n_dist = self.dist_from_other_rooms
116                     elif self.regions[h-1][w] == region_selected:
117                         n_dist = 0
118                     else:
119                         n_dist = self.dist_from_other_rooms
120
121                     if h + 1 == self.height:
122                         s_dist = self.region_size_in_tiles - self.dist_from_other_rooms
123                     elif self.regions[h+1][w] == region_selected:
124                         s_dist = self.region_size_in_tiles
125                     else:
126                         s_dist = self.region_size_in_tiles - self.dist_from_other_rooms
127
128                     for wt in range(w_dist, e_dist):
129                         for ht in range(n_dist, s_dist):
130                             self.map[h * self.region_size_in_tiles + ht][w * self.region_size_in_tiles + wt] = ' '
131
132     def display(self):
133         file = open('map.txt', 'w')
134         for l in self.map:
135             print(''.join(l))
136             file.write(''.join(l))
137             file.write('\n')
138         file.close()
139         self._to_json()
140         for l in self.regions:
141             print(l)
142
143     def _to_json(self):
144         level = {}
145         level['tileset'] = 'dungeon'
146         level['tiles'] = []
147         for l in self.map:
148             row = []
149             for t in l:
150                 row.append(ATTRIBUTE_MAP[t])
151             level['tiles'].append(row)
152         name = os.path.join(os.path.dirname(__file__), '..', 'levels', 'map.json')
153         # FIXME: Do a lot better here 
154         # Crude hack so the level is written into the levels folder
155         f = open(name, 'w')
156         json.dump(level, f)
157         f.close()
158
159
160 if __name__ == '__main__':
161     while True:
162         level = LevelGenerator(width=8, height=5, rooms=12, min_room_size=5, max_room_size=20,
163                                dist_from_edge=2, dist_from_other_rooms=1, region_size_in_tiles=6)
164         level.generate()
165         level.display()
166         input("Press Enter to continue...")