Mercurial > mhrok
changeset 30:4c1f8ab0d145
Make mhrok a package, not module
| author | Radomir Dopieralski <sheep-devel@sheep.art.pl> |
|---|---|
| date | Sat, 10 Mar 2012 11:36:49 +0100 |
| parents | 1dbbcefea978 |
| children | a4e5d09fac09 |
| files | mhrok.png mhrok.py mhrok/__init__.py mhrok/mhrok.png run_mhrok.py |
| diffstat | 5 files changed, 487 insertions(+), 481 deletions(-) [+] |
line wrap: on
line diff
--- a/mhrok.py Sat Mar 10 10:20:41 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,481 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - - -import pkgutil -try: - import cStringIO as StringIO -except ImportError: - import StringIO -import random - -import pygame -from pygame import locals as pg - - -DX = [-1, 0, 1, 0] -DY = [0, -1, 0, 1] - - -class Shadow(pygame.sprite.Sprite): - def __init__(self, frames, owner): - super(Shadow, self).__init__() - self.image = frames[20].copy() - self.image.set_alpha(128) - self.rect = self.image.get_rect() - self.owner = owner - - def update(self): - self.rect.center = self.owner.rect.center - -class Vision(pygame.sprite.DirtySprite): - def __init__(self, owner, radius): - super(Vision, self).__init__() - self.owner = owner - self.blendmode = pg.BLEND_RGBA_MIN - self.dirty = 2 - self.images = {} - for r in xrange(40, 65): - self.images[r] = self.get_image(r) - self.radius = radius - self.set_radius(radius) - self.rooms = [] - - def set_radius(self, radius): - self.current_radius = radius - self.image = self.images[radius] - self.rect = self.image.get_rect() - self.rect.center = self.owner.rect.center - - def get_image(self, radius): - image = pygame.Surface((radius*5/2, radius*2), pg.SRCALPHA) - image.fill((255, 255, 255, 255)) - for r in xrange(radius, radius-25, -1): - pygame.draw.ellipse( - image, - (255, 255, 255, max(0, min(255, (r-radius+25) * 10))), - (radius*5/4-r*5/4, radius-r, 2*r*5/4, 2*r), 0) - return image - - def update(self): - if self.current_radius > self.radius: - self.set_radius(max(self.current_radius - 4, self.radius)) - elif self.current_radius < self.radius: - self.set_radius(min(self.current_radius + 4, self.radius)) - self.rect.center = self.owner.rect.center - - -class MobSprite(pygame.sprite.Sprite): - def __init__(self, frames, (x, y), animation): - super(MobSprite, self).__init__() - self.animation = animation - self.frames = frames - self.image = self.frames[0] - self.rect = self.image.get_rect() - self.frame = 0 - self.rect.move_ip(4 + 20 * x, 12 * y) - self.depth = self.rect.bottom - self.direction = None - - def update(self): - self.frame = (self.frame + 1) % len(self.animation) - self.image = self.frames[self.animation[self.frame]] - if self.direction is not None: - self.rect.move_ip((DX[self.direction]*5, DY[self.direction]*3)) - self.depth = self.rect.bottom - -class Mob(object): - Sprite = MobSprite - - def __init__(self, (x, y)): - self.pos = x, y - - def make_sprite(self, tiles): - self.sprite = self.Sprite(tiles, self.pos, self.animation) - shadow = Shadow(tiles, self.sprite) - return self.sprite, shadow, None - - def control(self, level): - direction = random.choice([None, 0, 1, 2, 3]) - if direction is not None: - x, y = self.pos - target = x + DX[direction], y + DY[direction] - for mob in level.mobs: - if mob.pos == target: - self.sprite.direction = None - return - if not level[target]: - direction = None - else: - self.pos = target - self.sprite.direction = direction - - -class Bat(Mob): - animation = [25, 26] - - -class Chest(Mob): - animation = [27] - - def control(self, level): - pass - - -class Skeleton(Mob): - animation = [35, 35, 35, 36, 36, 36, 35, 35, 35, 37, 37, 37] - - -class Teddybear(Mob): - animation = [30, 30, 30, 31, 31, 31, 30, 30, 30, 32, 32, 32] - - -class PlayerSprite(pygame.sprite.Sprite): - def __init__(self, frames, (x, y)): - super(PlayerSprite, self).__init__() - self.direction = 0 - self.frames = frames - self.image = self.frames[0] - self.animation = self.stand_animation(self.direction) - self.rect = self.image.get_rect() - self.rect.move_ip(4 + 20 * x, 12 * y) - self.depth = self.rect.bottom - - def update(self): - if self.animation: - try: - self.animation.next() - except StopIteration: - self.animation = None - - def walk_animation(self, direction): - frames = [ - [5, 6, 5, 7], - [10, 11, 10, 12], - [15, 16, 15, 16], - [0, 1, 0, 2], - ][direction] - for frame in frames: - yield None - self.rect.move_ip((DX[direction]*5, DY[direction]*3)) - self.image = self.frames[frame] - self.depth = self.rect.bottom - - def stand_animation(self, direction): - yield None - frame = [5, 10, 15, 0][direction] - self.image = self.frames[frame] - - def set_animation(self, animation): - self.animation = animation - try: - self.animation.next() - except StopIteration: - self.animation = None - -class Player(object): - def place(self, (x, y)): - self.pos = x, y - self.direction = 3 - self.sprite = None - - def make_sprite(self, tiles): - self.sprite = PlayerSprite(tiles, self.pos) - shadow = Shadow(tiles, self.sprite) - self.vision = Vision(self.sprite, 64) - return self.sprite, shadow, self.vision - - def walk(self, level, direction): - self.direction = direction - x, y = self.pos - target = x + DX[direction], y + DY[direction] - if not level[target]: - return False - for mob in level.mobs: - if mob.pos == target: - return False - self.sprite.set_animation(self.sprite.walk_animation(direction)) - self.pos = target - return True - - def control(self, level): - room = level.find_room(*self.pos) - if room: - self.vision.radius = 64 - if room not in level.lit_rooms: - level.lit_rooms.append(room) - self.vision.rooms.append(room) - else: - self.vision.radius = 40 - keys = pygame.key.get_pressed() - - if keys[pg.K_UP]: - return self.walk(level, 1) - elif keys[pg.K_LEFT]: - return self.walk(level, 0) - elif keys[pg.K_DOWN]: - return self.walk(level, 3) - elif keys[pg.K_RIGHT]: - return self.walk(level, 2) - else: - self.sprite.set_animation( - self.sprite.stand_animation(self.direction)) - return False - return True - - -class SortedUpdates(pygame.sprite.RenderUpdates): - """Sprite group with a depth for controlling drawing order.""" - - def sprites(self): - return sorted(self.spritedict.keys(), - key=lambda sprite: getattr(sprite, "depth", 0)) - - -class Level(object): - def __init__(self, pc): - self.pc = pc - self.mobs = [pc] - self.width = 31 - self.height = 38 - - self.lit_rooms = [] - self.map = [[0] * self.width for y in xrange(self.height)] - - areas = [ - ((0, 0), (9, 11)), ((11, 0), (9, 11)), ((22, 0), (9, 11)), - ((0, 13), (9, 11)), ((11, 13), (9, 11)), ((22, 13), (9, 11)), - ((0, 26), (9, 11)), ((11, 26), (9, 11)), ((22, 26), (9, 11)), - ] - - rooms = [] - r = random.randint - for (x, y), (w, h) in areas: - width = r(1, w/2) * 2 - height = r(1, h/2) * 2 - x_offset = r(0, (w - width)/2) * 2 - y_offset = r(0, (h - height)/2) * 2 - rooms.append(((x + x_offset, y + y_offset), (width, height))) - - random.shuffle(rooms) - - for room, next_room in zip(rooms, rooms[1:]): - (x, y), (w, h) = room - (nx, ny), (nw, nh) = next_room - x1 = nx + r(0, nw/2) * 2 - y1 = ny + r(0, nh/2) * 2 - x2 = x + r(0, w/2) * 2 - y2 = y + r(0, h/2) * 2 - self.path((x1, y1), (x2, y2), 2) - - for room in rooms: - (x, y), (w, h) = room - self.fill((x, y), (w + 1, h + 1), 1) - for i in xrange(r(0, 2)): - self[r(x, x+w), r(y, y+h)] = 3 - for i in xrange(r(1, 3)): - self[r(x, x+w), r(y, y+h)] = 4 - for i in xrange(r(1, 4)): - MobClass = random.choice([Bat, Chest, Teddybear, Skeleton]) - self.mobs.append(MobClass((r(x, x + w), r(y, y + h)))) - self[r(x, x+w), r(y, y+h)] = 5 - - (x, y), (w, h) = random.choice(rooms) - self.pc.place((r(x, x+w), r(y, y+h))) - self.rooms = rooms - - - def __getitem__(self, (x, y)): - if self.width > x >= 0 and self.height > y >= 0: - return self.map[y][x] - - def __setitem__(self, (x, y), value): - if self.width > x >= 0 and self.height > y >= 0: - self.map[y][x] = value - - def fill(self, (sx, sy), (width, height), fill): - for y in xrange(sy, sy + height): - for x in xrange(sx, sx + width): - self[x, y] = fill - - def path(self, (sx, sy), (ex, ey), fill): - for x in xrange(sx, ex, 1 if sx < ex else -1): - if self[x, sy]: - return - self[x, sy] = fill - for y in xrange(sy, ey, 1 if sy < ey else -1): - if self[ex, y]: - return - self[ex, y] = fill - - def find_room(self, x, y): - for room in self.rooms: - (rx, ry), (rw, rh) = room - if rx <= x <= rx + rw and ry <= y <= ry + rh: - return room - - def render_background(self, tiles): - background = pygame.Surface((self.width * 20 + 20, self.height * 12 + 20)) - background.fill((16, 8, 0)) - blood = tiles[21].copy() - blood.set_alpha(220) - blood2 = tiles[22].copy() - blood2.set_alpha(220) - for y, row in enumerate(self.map): - for x, square in enumerate(row): - pos = x * 20 + 4, y * 12 - border = 0 - if square == 1: - background.blit(tiles[23], pos) - border = 4 - elif square == 2: - background.blit(tiles[33], pos) - border = 24 - elif square == 3: - background.blit(tiles[23], pos) - background.blit(blood, pos) - border = 4 - elif square == 4: - background.blit(tiles[23], pos) - background.blit(blood2, pos) - border = 4 - elif square == 5: - background.blit(tiles[38], pos) - border = 4 - elif square < 0: - background.blit(tiles[39 - square], pos) - border = 24 - if border: - if not self[x - 1, y]: - background.blit(tiles[5 + border], pos) - if not self[x + 1, y]: - background.blit(tiles[15 + border], pos) - if not self[x, y - 1]: - background.blit(tiles[border], pos) - if not self[x, y + 1]: - background.blit(tiles[10 + border], pos) - - return background - - def render_sprites(self, tiles): - sprites = SortedUpdates() - shadows = pygame.sprite.RenderUpdates() - visions = pygame.sprite.LayeredDirty() - for mob in self.mobs: - sprite, shadow, vision = mob.make_sprite(tiles) - if sprite: - sprites.add(sprite) - if shadow: - shadows.add(shadow) - if vision: - visions.add(vision) - return sprites, shadows, visions - - -class Display(object): - def __init__(self): - pygame.display.init() - self.screen = pygame.display.set_mode((640, 480)) - pygame.display.set_caption('Mhrok') - self.first_draw = True - self.tiles = load_tiles('mhrok.png', 32, 32) - self.background = pygame.Surface(self.screen.get_size()) - self.fog = pygame.Surface(self.screen.get_size(), pg.SRCALPHA) - self.fog.fill((0, 0, 0, 255)) - self.memory = pygame.Surface(self.screen.get_size(), pg.SRCALPHA) - self.memory.fill((0, 0, 0, 255)) - self.dirty = [] - - def render_level(self, level): - (self.sprites, - self.shadows, self.visions) = level.render_sprites(self.tiles) - self.background.blit(level.render_background(self.tiles), (0, 0)) - - def light_room(self, room): - (rx, ry), (rw, rh) = room - mx = rx * 20 + 6 - my = ry * 12 + 12 - mw = (rw+1) * 20 + 12 - mh = (rh+1) * 12 + 12 - darkroom = self.background.subsurface((mx, my, mw, mh)) - darkroom.set_alpha(16) - rect = self.memory.blit(darkroom, (mx, my)) - self.fog.blit(self.memory, (mx, my), rect) - self.dirty.append(rect) - - def draw(self): - if self.first_draw: - self.screen.blit(self.background, (0, 0)) - self.shadows.draw(self.screen) - self.sprites.draw(self.screen) - self.visions.draw(self.fog) - self.screen.blit(self.fog, (0, 0)) - self.dirty = [self.background.get_rect()] - self.first_draw = False - else: - self.screen.blit(self.background, (0, 0)) - self.visions.clear(self.fog, self.memory) - self.sprites.clear(self.screen, self.background) - self.shadows.draw(self.screen) - self.sprites.draw(self.screen) - self.dirty.extend(self.visions.draw(self.fog)) - self.screen.blit(self.fog, (0, 0)) - pygame.display.update(self.dirty) - self.dirty = [] - - def update(self): - self.sprites.update() - self.shadows.update() - self.visions.update() - for vision in self.visions: - while vision.rooms: - room = vision.rooms.pop() - self.light_room(room) - - -class Game(object): - def __init__(self): - self.display = Display() - self.clock = pygame.time.Clock() - self.game_over = False - - self.pc = Player() - self.level = Level(self.pc) - self.display.render_level(self.level) - - def main(self): - while not self.game_over: - self.clock.tick(15) - self.display.update() - self.display.draw() - for event in pygame.event.get(): - if event.type == pg.QUIT or ( - event.type == pg.KEYDOWN and - event.key == pg.K_ESCAPE): - self.game_over = True - if self.pc.sprite.animation is None: - if self.pc.control(self.level): - for mob in self.level.mobs: - if mob == self.pc: - continue - mob.control(self.level) - else: - for mob in self.level.mobs: - if mob == self.pc: - continue - mob.sprite.direction = None - - -def load_tiles(filename, width, height): - f = StringIO.StringIO(pkgutil.get_data('mhrok', filename)) - image = pygame.image.load(f, filename).convert() - image_width, image_height = image.get_size() - tiles = [] - for x in range(image_width/width): - for y in range(image_height/height): - rect = (x * width, y * height, width, height) - tiles.append(image.subsurface(rect)) - return tiles - -if __name__ == '__main__': - Game().main()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mhrok/__init__.py Sat Mar 10 11:36:49 2012 +0100 @@ -0,0 +1,481 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + + +import pkgutil +try: + import cStringIO as StringIO +except ImportError: + import StringIO +import random + +import pygame +from pygame import locals as pg + + +DX = [-1, 0, 1, 0] +DY = [ 0, -1, 0, 1] + + +class Shadow(pygame.sprite.Sprite): + def __init__(self, frames, owner): + super(Shadow, self).__init__() + self.image = frames[20].copy() + self.image.set_alpha(128) + self.rect = self.image.get_rect() + self.owner = owner + + def update(self): + self.rect.center = self.owner.rect.center + +class Vision(pygame.sprite.DirtySprite): + def __init__(self, owner, radius): + super(Vision, self).__init__() + self.owner = owner + self.blendmode = pg.BLEND_RGBA_MIN + self.dirty = 2 + self.images = {} + for r in xrange(40, 65): + self.images[r] = self.get_image(r) + self.radius = radius + self.set_radius(radius) + self.rooms = [] + + def set_radius(self, radius): + self.current_radius = radius + self.image = self.images[radius] + self.rect = self.image.get_rect() + self.rect.center = self.owner.rect.center + + def get_image(self, radius): + image = pygame.Surface((radius*5/2, radius*2), pg.SRCALPHA) + image.fill((255, 255, 255, 255)) + for r in xrange(radius, radius-25, -1): + pygame.draw.ellipse( + image, + (255, 255, 255, max(0, min(255, (r-radius+25) * 10))), + (radius*5/4-r*5/4, radius-r, 2*r*5/4, 2*r), 0) + return image + + def update(self): + if self.current_radius > self.radius: + self.set_radius(max(self.current_radius - 4, self.radius)) + elif self.current_radius < self.radius: + self.set_radius(min(self.current_radius + 4, self.radius)) + self.rect.center = self.owner.rect.center + + +class MobSprite(pygame.sprite.Sprite): + def __init__(self, frames, (x, y), animation): + super(MobSprite, self).__init__() + self.animation = animation + self.frames = frames + self.image = self.frames[0] + self.rect = self.image.get_rect() + self.frame = 0 + self.rect.move_ip(4 + 20 * x, 12 * y) + self.depth = self.rect.bottom + self.direction = None + + def update(self): + self.frame = (self.frame + 1) % len(self.animation) + self.image = self.frames[self.animation[self.frame]] + if self.direction is not None: + self.rect.move_ip((DX[self.direction]*5, DY[self.direction]*3)) + self.depth = self.rect.bottom + +class Mob(object): + Sprite = MobSprite + + def __init__(self, (x, y)): + self.pos = x, y + + def make_sprite(self, tiles): + self.sprite = self.Sprite(tiles, self.pos, self.animation) + shadow = Shadow(tiles, self.sprite) + return self.sprite, shadow, None + + def control(self, level): + direction = random.choice([None, 0, 1, 2, 3]) + if direction is not None: + x, y = self.pos + target = x + DX[direction], y + DY[direction] + for mob in level.mobs: + if mob.pos == target: + self.sprite.direction = None + return + if not level[target]: + direction = None + else: + self.pos = target + self.sprite.direction = direction + + +class Bat(Mob): + animation = [25, 26] + + +class Chest(Mob): + animation = [27] + + def control(self, level): + pass + + +class Skeleton(Mob): + animation = [35, 35, 35, 36, 36, 36, 35, 35, 35, 37, 37, 37] + + +class Teddybear(Mob): + animation = [30, 30, 30, 31, 31, 31, 30, 30, 30, 32, 32, 32] + + +class PlayerSprite(pygame.sprite.Sprite): + def __init__(self, frames, (x, y)): + super(PlayerSprite, self).__init__() + self.direction = 0 + self.frames = frames + self.image = self.frames[0] + self.animation = self.stand_animation(self.direction) + self.rect = self.image.get_rect() + self.rect.move_ip(4 + 20 * x, 12 * y) + self.depth = self.rect.bottom + + def update(self): + if self.animation: + try: + self.animation.next() + except StopIteration: + self.animation = None + + def walk_animation(self, direction): + frames = [ + [5, 6, 5, 7], + [10, 11, 10, 12], + [15, 16, 15, 16], + [0, 1, 0, 2], + ][direction] + for frame in frames: + yield None + self.rect.move_ip((DX[direction]*5, DY[direction]*3)) + self.image = self.frames[frame] + self.depth = self.rect.bottom + + def stand_animation(self, direction): + yield None + frame = [5, 10, 15, 0][direction] + self.image = self.frames[frame] + + def set_animation(self, animation): + self.animation = animation + try: + self.animation.next() + except StopIteration: + self.animation = None + +class Player(object): + def place(self, (x, y)): + self.pos = x, y + self.direction = 3 + self.sprite = None + + def make_sprite(self, tiles): + self.sprite = PlayerSprite(tiles, self.pos) + shadow = Shadow(tiles, self.sprite) + self.vision = Vision(self.sprite, 64) + return self.sprite, shadow, self.vision + + def walk(self, level, direction): + self.direction = direction + x, y = self.pos + target = x + DX[direction], y + DY[direction] + if not level[target]: + return False + for mob in level.mobs: + if mob.pos == target: + return False + self.sprite.set_animation(self.sprite.walk_animation(direction)) + self.pos = target + return True + + def control(self, level): + room = level.find_room(*self.pos) + if room: + self.vision.radius = 64 + if room not in level.lit_rooms: + level.lit_rooms.append(room) + self.vision.rooms.append(room) + else: + self.vision.radius = 40 + keys = pygame.key.get_pressed() + + if keys[pg.K_UP]: + return self.walk(level, 1) + elif keys[pg.K_LEFT]: + return self.walk(level, 0) + elif keys[pg.K_DOWN]: + return self.walk(level, 3) + elif keys[pg.K_RIGHT]: + return self.walk(level, 2) + else: + self.sprite.set_animation( + self.sprite.stand_animation(self.direction)) + return False + return True + + +class SortedUpdates(pygame.sprite.RenderUpdates): + """Sprite group with a depth for controlling drawing order.""" + + def sprites(self): + return sorted(self.spritedict.keys(), + key=lambda sprite: getattr(sprite, "depth", 0)) + + +class Level(object): + def __init__(self, pc): + self.pc = pc + self.mobs = [pc] + self.width = 31 + self.height = 38 + + self.lit_rooms = [] + self.map = [[0] * self.width for y in xrange(self.height)] + + areas = [ + ((0, 0), (9, 11)), ((11, 0), (9, 11)), ((22, 0), (9, 11)), + ((0, 13), (9, 11)), ((11, 13), (9, 11)), ((22, 13), (9, 11)), + ((0, 26), (9, 11)), ((11, 26), (9, 11)), ((22, 26), (9, 11)), + ] + + rooms = [] + r = random.randint + for (x, y), (w, h) in areas: + width = r(1, w/2) * 2 + height = r(1, h/2) * 2 + x_offset = r(0, (w - width)/2) * 2 + y_offset = r(0, (h - height)/2) * 2 + rooms.append(((x + x_offset, y + y_offset), (width, height))) + + random.shuffle(rooms) + + for room, next_room in zip(rooms, rooms[1:]): + (x, y), (w, h) = room + (nx, ny), (nw, nh) = next_room + x1 = nx + r(0, nw/2) * 2 + y1 = ny + r(0, nh/2) * 2 + x2 = x + r(0, w/2) * 2 + y2 = y + r(0, h/2) * 2 + self.path((x1, y1), (x2, y2), 2) + + for room in rooms: + (x, y), (w, h) = room + self.fill((x, y), (w + 1, h + 1), 1) + for i in xrange(r(0, 2)): + self[r(x, x+w), r(y, y+h)] = 3 + for i in xrange(r(1, 3)): + self[r(x, x+w), r(y, y+h)] = 4 + for i in xrange(r(1, 4)): + MobClass = random.choice([Bat, Chest, Teddybear, Skeleton]) + self.mobs.append(MobClass((r(x, x + w), r(y, y + h)))) + self[r(x, x+w), r(y, y+h)] = 5 + + (x, y), (w, h) = random.choice(rooms) + self.pc.place((r(x, x+w), r(y, y+h))) + self.rooms = rooms + + + def __getitem__(self, (x, y)): + if self.width > x >= 0 and self.height > y >= 0: + return self.map[y][x] + + def __setitem__(self, (x, y), value): + if self.width > x >= 0 and self.height > y >= 0: + self.map[y][x] = value + + def fill(self, (sx, sy), (width, height), fill): + for y in xrange(sy, sy + height): + for x in xrange(sx, sx + width): + self[x, y] = fill + + def path(self, (sx, sy), (ex, ey), fill): + for x in xrange(sx, ex, 1 if sx < ex else -1): + if self[x, sy]: + return + self[x, sy] = fill + for y in xrange(sy, ey, 1 if sy < ey else -1): + if self[ex, y]: + return + self[ex, y] = fill + + def find_room(self, x, y): + for room in self.rooms: + (rx, ry), (rw, rh) = room + if rx <= x <= rx + rw and ry <= y <= ry + rh: + return room + + def render_background(self, tiles): + background = pygame.Surface((self.width * 20 + 20, self.height * 12 + 20)) + background.fill((16, 8, 0)) + blood = tiles[21].copy() + blood.set_alpha(220) + blood2 = tiles[22].copy() + blood2.set_alpha(220) + for y, row in enumerate(self.map): + for x, square in enumerate(row): + pos = x * 20 + 4, y * 12 + border = 0 + if square == 1: + background.blit(tiles[23], pos) + border = 4 + elif square == 2: + background.blit(tiles[33], pos) + border = 24 + elif square == 3: + background.blit(tiles[23], pos) + background.blit(blood, pos) + border = 4 + elif square == 4: + background.blit(tiles[23], pos) + background.blit(blood2, pos) + border = 4 + elif square == 5: + background.blit(tiles[38], pos) + border = 4 + elif square < 0: + background.blit(tiles[39 - square], pos) + border = 24 + if border: + if not self[x - 1, y]: + background.blit(tiles[5 + border], pos) + if not self[x + 1, y]: + background.blit(tiles[15 + border], pos) + if not self[x, y - 1]: + background.blit(tiles[border], pos) + if not self[x, y + 1]: + background.blit(tiles[10 + border], pos) + + return background + + def render_sprites(self, tiles): + sprites = SortedUpdates() + shadows = pygame.sprite.RenderUpdates() + visions = pygame.sprite.LayeredDirty() + for mob in self.mobs: + sprite, shadow, vision = mob.make_sprite(tiles) + if sprite: + sprites.add(sprite) + if shadow: + shadows.add(shadow) + if vision: + visions.add(vision) + return sprites, shadows, visions + + +class Display(object): + def __init__(self): + pygame.display.init() + self.screen = pygame.display.set_mode((640, 480)) + pygame.display.set_caption('Mhrok') + self.first_draw = True + self.tiles = load_tiles('mhrok.png', 32, 32) + self.background = pygame.Surface(self.screen.get_size()) + self.fog = pygame.Surface(self.screen.get_size(), pg.SRCALPHA) + self.fog.fill((0, 0, 0, 255)) + self.memory = pygame.Surface(self.screen.get_size(), pg.SRCALPHA) + self.memory.fill((0, 0, 0, 255)) + self.dirty = [] + + def render_level(self, level): + (self.sprites, + self.shadows, self.visions) = level.render_sprites(self.tiles) + self.background.blit(level.render_background(self.tiles), (0, 0)) + + def light_room(self, room): + (rx, ry), (rw, rh) = room + mx = rx * 20 + 6 + my = ry * 12 + 12 + mw = (rw+1) * 20 + 12 + mh = (rh+1) * 12 + 12 + darkroom = self.background.subsurface((mx, my, mw, mh)) + darkroom.set_alpha(32) + rect = self.memory.blit(darkroom, (mx, my)) + self.fog.blit(self.memory, (mx, my), rect) + self.dirty.append(rect) + + def draw(self): + if self.first_draw: + self.screen.blit(self.background, (0, 0)) + self.shadows.draw(self.screen) + self.sprites.draw(self.screen) + self.visions.draw(self.fog) + self.screen.blit(self.fog, (0, 0)) + self.dirty = [self.background.get_rect()] + self.first_draw = False + else: + self.screen.blit(self.background, (0, 0)) + self.visions.clear(self.fog, self.memory) + self.sprites.clear(self.screen, self.background) + self.shadows.draw(self.screen) + self.sprites.draw(self.screen) + self.dirty.extend(self.visions.draw(self.fog)) + self.screen.blit(self.fog, (0, 0)) + pygame.display.update(self.dirty) + self.dirty = [] + + def update(self): + self.sprites.update() + self.shadows.update() + self.visions.update() + for vision in self.visions: + while vision.rooms: + room = vision.rooms.pop() + self.light_room(room) + + +class Game(object): + def __init__(self): + self.display = Display() + self.clock = pygame.time.Clock() + self.game_over = False + + self.pc = Player() + self.level = Level(self.pc) + self.display.render_level(self.level) + + def main(self): + while not self.game_over: + self.clock.tick(15) + self.display.update() + self.display.draw() + for event in pygame.event.get(): + if event.type == pg.QUIT or ( + event.type == pg.KEYDOWN and + event.key == pg.K_ESCAPE): + self.game_over = True + if self.pc.sprite.animation is None: + if self.pc.control(self.level): + for mob in self.level.mobs: + if mob == self.pc: + continue + mob.control(self.level) + else: + for mob in self.level.mobs: + if mob == self.pc: + continue + mob.sprite.direction = None + + +def load_tiles(filename, width, height): + f = StringIO.StringIO(pkgutil.get_data('mhrok', filename)) + image = pygame.image.load(f, filename).convert() + image_width, image_height = image.get_size() + tiles = [] + for x in range(image_width/width): + for y in range(image_height/height): + rect = (x * width, y * height, width, height) + tiles.append(image.subsurface(rect)) + return tiles + +if __name__ == '__main__': + Game().main()
