junglejourney

view tools/maps/make_maps.py @ 230:f7b16fb00dda

Added tools created in an experimental map making repository.
author David Boddie <david@boddie.org.uk>
date Sun Feb 05 00:28:07 2012 +0100
parents
children e24e7d33b5e7
line source
1 #!/usr/bin/env python
3 import os, sys
4 import Image
5 import series
6 from tileimages import blank, tile_size, leaf1, leaf2, visited, flowers, \
7 flowers2, leaf4, leaf6, flowers3, leaf5, leaf3, \
8 exit, final_exit1, final_exit2, item_size, player, \
9 treasure_images
11 image_sets = {
12 100: [blank, flowers, leaf1, leaf2, exit],
13 239: [blank, flowers2, leaf6, leaf4, exit],
14 183: [blank, flowers2, leaf6, leaf4, exit],
15 144: [blank, flowers3, leaf5, leaf3, exit, final_exit1, final_exit2]
16 }
18 default_image_set = [blank, flowers, leaf1, leaf2]
20 tile_values_map = [0, 1, 0, 0, 0, 0, 2, 3, 4, 5, 6]
22 class Mapper:
24 start_rooms = {100: (5, 5), 36: (0, 0), 44: (9, 7), 4: (7, 0), 5: (5, 10),
25 8: (0, 8), 10: (0, 10), 17: (7, 10), 26: (0, 9),
26 33: (10, 0), 127: (0, 0), 144: (10, 8), 183: (5, 1),
27 239: (3, 8)}
28 exit_rooms = {100: (7, 0), 36: (7, 0), 4: (5, 10), 5: (9, 6),
29 8: (3, 0), 10: (10, 2), 17: (9, 0), 26: (10, 4),
30 33: (2, 10), 144: (0, 10), 183: (3, 9), 239: (9, 0)}
31 key_rooms = {100: (1, 0), 17: (0, 0), 26: (9, 0), 33: (10, 6), 144: (1, 4),
32 183: (10, 6), 239: (5, 2)}
33 extra_life_rooms = {17: (2, 0), 26: (9, 4)}
35 levels = {100: 0, 183: 1, 239: 2, 144: 3}
37 treasure_table = [6, 5, 7, 1, 1, 5, 2, 7, 6, 2, 1, 7, 1, 7, 8, 7,
38 0, 7, 6, 7, 7, 7, 5, 0, 6, 3, 7, 7, 5, 7, 5, 0]
40 treasure_x = [3, 2, 4, 8, 2, 5, 4, 1, 3, 8, 6, 5, 7, 1, 7, 6]
41 treasure_y = [1, 3, 7, 7, 2, 3, 6, 1, 4, 6, 8, 5, 5, 4, 8, 2]
43 exit_room_offsets = [35, 66, 63, 56, 34, 44, 64, 33, 36, 55, 65, 53,
44 45, 46, 54, 43]
46 def __init__(self, map_width, map_height, room_width, room_height, seed,
47 image, images, wall_tile, floor_tiles):
49 self.map_width = map_width
50 self.map_height = map_height
51 self.room_width = room_width
52 self.room_height = room_height
53 self.rooms = {}
54 self.exits = {}
55 self.visited = set()
56 self.seed = seed
57 self.image = image
58 self.images = images
59 self.wall_tile = wall_tile
60 self.floor_tiles = floor_tiles
62 self.add_objects()
64 def add_objects(self):
66 self.objects = []
68 first = (self.seed + 1) & 31
69 second = (self.seed + 2) & 31
70 gen = series.unlimited_values(first, second)
72 # Find the level associated with the seed used for the map.
73 level = self.levels.get(self.seed, 0)
75 k = 0
76 for i in range(self.map_height):
78 for j in range(self.map_width):
80 if self.key_rooms.get(self.seed, ()) == (j, i):
82 self.objects.append(5)
84 else:
86 item = gen.next() & 15
87 if item == 0:
88 self.objects.append(0)
89 else:
90 treasure = self.treasure_table[(item + k) & 31]
91 if 0 <= treasure <= 3:
92 if treasure <= level + 1:
93 self.objects.append(treasure + 1)
94 else:
95 self.objects.append(0)
96 else:
97 self.objects.append(treasure + 1)
99 k += 1
101 def make_room(self, i, j):
103 first = j
104 second = self.seed - i
106 gen = series.unlimited_values(first, second)
107 for k in range(10):
108 gen.next()
110 special_rooms = {self.start_rooms.get(self.seed, ()): 7,
111 self.exit_rooms.get(self.seed, ()): 7,
112 self.key_rooms.get(self.seed, ()): 1}
114 if (j, i) in special_rooms:
116 x = y = 1
117 while True:
118 if (x, y) in [(1, 1), (1, 8), (8, 1), (8, 8)]:
119 yield special_rooms[(j, i)]
121 elif (j, i) == self.exit_rooms.get(self.seed, ()):
122 position = self.exit_room_offsets[(i ^ j) & 15]
123 if x == position % 10 and y == position / 10:
124 yield 8
125 else:
126 yield 0
128 else:
129 yield 0
131 x += 1
132 if x == 9:
133 x = 1
134 y += 1
136 else:
137 while True:
138 yield (gen.next() % 9) & 7
140 def top_exit(self, i, j):
142 if i == 0:
143 return True
144 elif i & 7 == j & 7:
145 return False
147 return ((i ^ j) + i) == j
149 def right_exit(self, i, j):
151 if j == self.map_width - 1:
152 return True
154 return self.left_exit(i, j + 1)
156 def bottom_exit(self, i, j):
158 if i == self.map_height - 1:
159 return True
161 return self.top_exit(i + 1, j)
163 def left_exit(self, i, j):
165 if j == 0:
166 return True
167 elif i & 3 == j & 3:
168 return False
170 return ((i | j) ^ j) == i
172 def make_room_image(self, i, j):
174 im = Image.new("P", (self.room_width * tile_size[0],
175 self.room_height * tile_size[1]), 0)
177 rows, exits = self.read_room((j, i))
179 for y in range(0, self.room_height):
180 for x in range(0, self.room_width):
182 value = rows[y][x]
183 im.paste(self.images[value], (x * tile_size[0], y * tile_size[1]))
185 item, x, y = self.item_for_room(rows, i, j)
186 if item is not None:
188 im.paste(treasure_images[item],
189 (x * tile_size[0],
190 y * tile_size[1] + (tile_size[1] - item_size[1])/2))
192 return im
194 def item_for_room(self, rows, i, j):
196 item = self.objects[i * self.map_height + j]
197 if item != 0:
199 item -= 1
200 k = ((i ^ j) + item) & 15
201 a = 15
202 while a >= 0:
204 x, y = self.treasure_x[k], self.treasure_y[k]
206 if rows[y][x] & 0x7f == 0:
208 return item, x, y
209 break
211 if k > 0:
212 k -= 1
213 else:
214 k = 15
215 a -= 1
217 return None, 0, 0
219 def read_room(self, room):
221 gen = self.make_room(room[1], room[0])
223 if self.rooms.has_key(room):
224 rows = self.rooms[room]
225 exits = self.exits[room]
226 else:
227 exits = []
228 exits.append(self.top_exit(room[1], room[0]))
229 exits.append(self.right_exit(room[1], room[0]))
230 exits.append(self.bottom_exit(room[1], room[0]))
231 exits.append(self.left_exit(room[1], room[0]))
233 rows = []
234 cx = self.room_width/2 - 2
235 cy = self.room_height/2 - 2
237 if exits[0]:
238 rows.append([self.wall_tile]*self.room_width)
239 else:
240 rows.append([self.wall_tile]*cx + [0]*(self.room_width - 2*cx) + [self.wall_tile]*cx)
242 if self.levels.get(self.seed) == 3 and room == (2, 0):
244 rows[-1][4] = 5
245 rows[-1][5] = 6
247 for ry in range(1, self.room_height - 1):
248 row = []
249 if exits[3] or ry < cy or ry > self.room_height - cy - 1:
250 row.append(self.wall_tile)
251 else:
252 row.append(0)
254 for rx in range(1, self.room_width - 1):
255 row.append(tile_values_map[gen.next()])
257 if exits[1] or ry < cy or ry > self.room_height - cy - 1:
258 row.append(self.wall_tile)
259 else:
260 row.append(0)
261 rows.append(row)
263 if exits[2]:
264 rows.append([self.wall_tile]*self.room_width)
265 else:
266 rows.append([self.wall_tile]*cx + [0]*(self.room_width - 2*cx) + [self.wall_tile]*cx)
268 self.rooms[room] = rows
269 self.exits[room] = exits
271 return rows, exits
273 def find_map_extent(self, room, x = None, y = None):
275 rows, exits = self.read_room(room)
277 if x is None:
278 x = self.room_width/2 - 1
279 y = self.room_height/2 - 1
281 places = [(x, y)]
283 # Use a recursive algorithm to explore the room, but don't recursively
284 # call this function until we leave the room.
286 while places:
288 x, y = places.pop()
290 if rows[y][x] not in self.floor_tiles:
291 # The square has already been visited, so backtrack.
292 continue
293 else:
294 # Mark this room as visited.
295 self.visited.add(room)
296 #self.image.paste(visited,
297 # ((room[0] * self.room_width + x) * tile_size[0] + room[0] + 3 * tile_size[0]/8,
298 # (room[1] * self.room_height + y) * tile_size[1] + room[1] + 3 * tile_size[1]/8))
300 # Mark this square as visited.
301 rows[y][x] = rows[y][x] | 0x80
303 # Try to move to adjacent squares.
304 if x > 0:
305 if rows[y][x-1] in self.floor_tiles:
306 places.append((x - 1, y))
307 elif room[0] > 0:
308 self.find_map_extent((room[0] - 1, room[1]),
309 self.room_width - 1, y)
311 if x < self.room_width - 1:
312 if rows[y][x+1] in self.floor_tiles:
313 places.append((x + 1, y))
314 elif room[0] < self.map_width - 1:
315 self.find_map_extent((room[0] + 1, room[1]), 0, y)
317 if y > 0:
318 if rows[y-1][x] in self.floor_tiles:
319 places.append((x, y - 1))
320 elif room[1] > 0:
321 self.find_map_extent((room[0], room[1] - 1),
322 x, self.room_height - 1)
324 if y < self.room_height - 1:
325 if rows[y+1][x] in self.floor_tiles:
326 places.append((x, y + 1))
327 elif room[1] < self.map_height - 1:
328 self.find_map_extent((room[0], room[1] + 1), x, 0)
330 def fade(image, x0, y0, w, h):
332 for i in range(h):
334 y = y0 + i
335 x = x0 + y % 2
336 while x < x0 + w:
337 image.putpixel((x, y), 0)
338 x += 2
340 def select_images(seed):
342 images = image_sets.get(seed, default_image_set)
343 wall_tile = 2
344 floor_tiles = []
346 for i in range(len(images)):
347 if images[i] in (blank,):
348 floor_tiles.append(i)
350 return images, wall_tile, floor_tiles
352 def make_map(name, width, height, room_width, room_height, seed):
354 images, wall_tile, floor_tiles = select_images(seed)
356 im = Image.new("P", (width * room_width * tile_size[0] + (width - 1),
357 height * room_height * tile_size[1] + (height - 1)), 7)
358 #im.putpalette((0,0,0, 255,0,0, 0,255,0, 255,255,0, 0,0,255, 255,0,255, 0,255,255, 255,255,255))
359 black = (0,0,0)
360 red = (255,0,0)
361 green = (0,255,0)
362 yellow = (255,255,0)
363 blue = (0,0,255)
364 magenta = (255,0,255)
365 cyan = (0,255,255)
366 white = (255,255,255)
367 im.putpalette(black + red + green + yellow + blue + magenta + cyan + white)
368 room_palettes = [1, 6, 5, 7]
370 mapper = Mapper(width, height, room_width, room_height, seed, im, images,
371 wall_tile, floor_tiles)
373 for i in range(height):
374 for j in range(width):
376 room_image = mapper.make_room_image(i, j)
378 # Change the palette for this room.
379 room_string = room_image.tostring()
381 # Replace logical colour 1 with 1, 3, 5 or 7.
382 new_colour = room_palettes[(i ^ j) & 3]
383 if new_colour != 1:
384 room_string = room_string.replace("\x01", chr(new_colour))
386 room_image = Image.fromstring("P", (room_width * tile_size[0],
387 room_height * tile_size[1]),
388 room_string)
390 im.paste(room_image, (j * room_width * tile_size[0] + j,
391 i * room_height * tile_size[1] + i))
393 start_room = mapper.start_rooms.get(seed)
395 if start_room:
397 mapper.find_map_extent(start_room)
399 mapper.image.paste(player,
400 (int((start_room[0] + 0.5) * mapper.room_width * tile_size[0]) + start_room[0] - tile_size[0]/4,
401 int((start_room[1] + 0.5) * mapper.room_height * tile_size[1]) + start_room[1] - tile_size[1]/2))
403 for i in range(height):
404 for j in range(width):
406 if (j,i) not in mapper.visited:
408 fade(im, j * room_width * tile_size[0] + j,
409 i * room_height * tile_size[1] + i,
410 room_width * tile_size[0],
411 room_height * tile_size[1])
413 im.save(name)
416 if __name__ == "__main__":
418 if len(sys.argv) != 5:
420 sys.stderr.write("Usage: %s <width> <height> <seed> <file name>\n\n" % sys.argv[0])
421 sys.stderr.write("For the release version of Jungle Journey, use a value of 11\n"
422 "for both width and height, and one of 100, 239, 183 or 144\n"
423 "for the seed value.\n")
424 sys.exit(1)
426 width = int(sys.argv[1])
427 height = int(sys.argv[2])
428 seed = int(sys.argv[3])
429 name = sys.argv[4]
430 room_width = 10
431 room_height = 10
433 start_room = (width/2, height/2)
434 stem, suffix = os.path.splitext(name)
436 make_map("%s-%02x%s" % (stem, seed, suffix),
437 width, height, room_width, room_height, seed)
439 print "Created %s-%02x%s" % (stem, seed, suffix)
441 sys.exit()