Mercurial > rrr
changeset 5:6666dbf909be
Fractal level generator
| author | Radomir Dopieralski <sheep-devel@sheep.art.pl> |
|---|---|
| date | Mon, 01 Apr 2013 21:44:59 +0200 |
| parents | c290a652a783 |
| children | c98a36b9393e |
| files | rrr/display_curses.py rrr/level.py run.py |
| diffstat | 3 files changed, 111 insertions(+), 45 deletions(-) [+] |
line wrap: on
line diff
--- a/rrr/display_curses.py Sun Mar 31 23:55:41 2013 +0200 +++ b/rrr/display_curses.py Mon Apr 01 21:44:59 2013 +0200 @@ -23,6 +23,7 @@ self.map.keypad(1) self.map.immedok(0) self.map.leaveok(0) + self.map.scrollok(0) self.sidebar = curses.newwin(maxy - 1, 16, 1, maxx - 16) self.sidebar.immedok(0) self.sidebar.scrollok(1) @@ -39,6 +40,7 @@ curses.init_pair(4, curses.COLOR_MAGENTA, curses.COLOR_BLACK) curses.init_pair(5, curses.COLOR_RED, curses.COLOR_BLACK) curses.init_pair(6, curses.COLOR_CYAN, curses.COLOR_BLACK) + curses.init_pair(7, curses.COLOR_BLUE, curses.COLOR_BLACK) self.colors.update({ 'gray': curses.color_pair(0), 'white': curses.color_pair(0) | curses.A_BOLD, @@ -51,6 +53,9 @@ 'maroon': curses.color_pair(5), 'aqua': curses.color_pair(6) | curses.A_BOLD, 'cyan': curses.color_pair(6), + 'blue': curses.color_pair(7) | curses.A_BOLD, + 'navy': curses.color_pair(7), + 'pink': curses.color_pair(4) | curses.A_BOLD, 'magenta': curses.color_pair(4), }) @@ -81,12 +86,13 @@ 'KEY_B2': ("wait", None), '5': ("wait", None), 'KEY_ESC': ("esc", None), + '\x1b': ("esc", None), ' ': ("more", None), } def message(self, message, color='green'): - self.sidebar.addstr(message, self.colors[color]) + self.sidebar.addstr(message + '\n', self.colors[color]) def map_draw(self, (x, y), char, color=0): x -= self.xmap @@ -94,8 +100,12 @@ if not (0 <= x < self.maxmapx and 0 <= y < self.maxmapy): return c = ord(char) | self.colors[color] - self.map.addch(y, x, c) - + try: + self.map.addch(y, x, c) + except curses.error: + # For some reason it throws an error when drawing the character + # in the lower right corner of the map window. We ignore it here. + pass def stats_draw(self, stats): self.stats.clear() @@ -134,10 +144,9 @@ return True def clear(self): - self.msg.clear() + self.sidebar.clear() self.map.clear() - self.inv.clear() - self.stat.clear() + self.stats.clear() def refresh(self): self.sidebar.noutrefresh()
--- a/rrr/level.py Sun Mar 31 23:55:41 2013 +0200 +++ b/rrr/level.py Mon Apr 01 21:44:59 2013 +0200 @@ -1,34 +1,86 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +import random +import math + + +TERRAIN = [ + { + 'name': 'invalid', + 'symbol': '?', + 'color': 'magenta', + 'opaque': True, + 'block': True, + }, + { + 'name': 'ground', + 'symbol': '.', + 'color': 'black', + 'opaque': False, + 'block': False, + }, + { + 'name': 'ground', + 'symbol': '.', + 'color': 'gray', + 'opaque': False, + 'block': False, + }, + { + 'name': 'rocks', + 'symbol': ':', + 'color': 'gray', + 'opaque': False, + 'block': False, + }, + { + 'name': 'wall', + 'symbol': '#', + 'color': 'gray', + 'opaque': True, + 'block': True, + }, + +] + class Level(object): - def __init__(self): - self.map = [ - '...#############', - '...#...........#', - '#..#...........#', - '#..#...........#', - '#..............#', - '#..............#', - '#....####......#', - '#....#.........#', - '#....#.........#', - '#....######....#', - '#..............#', - '#..............#', - '#..............#', - '###########.#..#', - '#...........#..#', - '################', + def __init__(self, width, height): + self.width = width + self.height = height + self.explored = set() + self.map = self.fractal_fill([1, 1, 2, 2, 2, 3, 3, 4, 4]) + + def fractal_fill(self, gradient): + max_power = int(math.ceil(math.log(max(self.width, self.height), 2))) + frac = [[0] * 2**max_power for y in xrange(2**max_power)] + frac[0][0] = 4 + for i in xrange(max_power + 1): + size = 2 ** i + for y in xrange(size - 1, -1, -1): + for x in xrange(size - 1, -1, -1): + frac[y][x] = max(0, min(len(gradient) - 1, + frac[y // 2][x // 2] + random.choice([-1, 0, 1]) + )) + return [ + [gradient[cell] for cell in row[:self.width]] + for row in frac[:self.height] ] - def is_opaque(self, (x, y)): - if not (0<=x<16 and 0<=y<16): - return True - return self.map[y][x] == '#' + def is_opaque(self, pos): + t = self.get_terrain(pos) + return t['opaque'] + + def get_char(self, pos): + t = self.get_terrain(pos) + return t['symbol'], t['color'] - def get_char(self, (x, y)): - if not (0<=x<16 and 0<=y<16): - return 'X' - return self.map[y][x] - + def get_terrain(self, (x, y)): + if not (0 <= x < self.width and 0 <= y < self.height): + t = TERRAIN[0] + else: + try: + t = TERRAIN[self.map[y][x]] + except IndexError: + t = TERRAIN[0] + return t
--- a/run.py Sun Mar 31 23:55:41 2013 +0200 +++ b/run.py Mon Apr 01 21:44:59 2013 +0200 @@ -11,7 +11,7 @@ def main(stdscr): display = Display(stdscr) light = Light() - level = Level() + level = Level(64, 64) x, y = 0, 0 display.stats_draw('HP 100/100') display.message('Hello world!') @@ -19,23 +19,28 @@ display.center_map((x, y)) lit = set() while True: - for p in lit: - display.map_draw(p, level.get_char(p), 'magenta') - lit = light.cast((x, y), 12, level.is_opaque) + oldlit = lit + if display.scroll_map((x, y)): + display.map.clear() + for p in level.explored: + ch, c = level.get_char(p) + display.map_draw(p, ch, 'magenta') + lit = light.cast((x, y), 8, level.is_opaque) + level.explored |= lit + for p in oldlit - lit: + ch, c = level.get_char(p) + display.map_draw(p, ch, 'magenta') for p in lit: - c = level.get_char(p) - if c == '.': - color = 'black' - else: - color = 'gray' - display.map_draw(p, c, color) + ch, c = level.get_char(p) + display.map_draw(p, ch, c) display.map_draw((x, y), '@', 'white') display.refresh() command, params = display.get_command() if command == 'arrow': dx, dy = params - x += dx - y += dy + if not level.get_terrain((x + dx, y + dy))['block']: + x += dx + y += dy elif command == 'key' and params == 'q': raise SystemExit()
