# This file is part of ROBOTGAME # # ROBOTGAME is free software: you can redistribute it and/or modify it under the # terms of the GNU General Public License as published by the Free Software # Foundation, either version 3 of the License, or (at your option) any later # version. # # ROBOTGAME is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR # A PARTICULAR PURPOSE. See the GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along with # ROBOTGAME. If not, see . # # ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' # # level1.py # -------------------- # date created : Fri Aug 10 2012 # copyright : (C) 2012 Niels G. W. Serup # maintained by : Niels G. W. Serup """ The fourth level. """ from __future__ import print_function import os import pygame import random import re import itertools import level import player import tile import block import lever from mirror import Mirror from laser import Laser import misc import worldobject import logic.lasermirror as lm from logic.direction import * class Level4(level.Level): def __init__(self, game, graphics_dir, paused=False): level.Level.__init__(self, game, graphics_dir, size=(64 * 16, 48 * 20), paused=paused) self.dimensions = 16, 16 for i in range(self.dimensions[0]): for j in range(self.dimensions[1]): self.tiles.append( tile.Tile(self, i*64, (j+4)*48, self.imgs['indoor%d' % random.randint(1, 6)])) self.draw_background() self.playfield = lm.generate_simple_playfield(16) self.target_blocks = [] for (x, y), t in self.playfield.items(): x1, y1 = 64 * x, 48 * (y + 4) if isinstance(t, lm.Source): self.objects.append( block.LaserSource(self, x1, y1, t.direction)) continue def mir(b, x1, y1): def f(x, y): def g(setting): self.playfield[(x, y)] = lm.MirrorLeft \ if self.playfield[(x, y)] is lm.MirrorRight \ else lm.MirrorRight self.generate_lasers() return g return Mirror(self, x, y, b, links=[f(x, y)]) def targ(): b = block.LaserTarget(self, x, y) self.target_blocks.append(b) return b self.objects.append({ lm.MirrorLeft: lambda: mir(True, x1, y1), lm.MirrorRight: lambda: mir(False, x1, y1), lm.Lever: lambda: lever.Lever( self, x1, y1, [lambda setting: self.generate_lasers], toggling=True, anim='lever_leftright' if x in (0, 15) else 'lever_updown'), lm.Target: targ, lm.Blocker: lambda: block.Block(self, x1, y1, self.imgs['block1'], movable=False) }[t]()) mirrors = list(filter(lambda obj: isinstance(obj, Mirror), self.objects)) levers = list(filter(lambda obj: isinstance(obj, lever.Lever), self.objects)) random.shuffle(levers) for l in levers: m = min(mirrors, key=lambda m: misc.manhattan_dist( (m.x, m.y), (l.x, l.y))) mirrors.remove(m) l.links.insert(0, (lambda m: lambda setting: m.rotate())(m)) top = self.size[0] / 64 for i in range(top): if not i % 3: self.objects.append(block.Block( self, i * 64, 48 * 3, self.imgs['wall'], width=1 if i == top - 1 else 3, blit_area=(0, 0, 96, 192) if i == top - 1 else None)) self.objects.append(block.InvisBlock(self, i * 64, self.size[1])) for i in range(self.size[1] / 48): self.objects.append(block.InvisBlock(self, - 64, i * 48)) self.objects.append(block.InvisBlock(self, self.size[0], i * 48)) self.generate_lasers() self.player.set_pos(64 * 7, 48 * 5) self.player.set_init_pos() def on_completion(self): # End game here. print('Well done.') def restart(self): for obj in self.objects: obj.reset_pos() def generate_lasers(self): lasers = lm.generate_lasers(self.playfield) self.lasers_orig = list(itertools.chain(*lasers)) self.lasers = [] for laser in lasers: laser = iter(laser) self.lasers.append(Laser(self, next(laser), first_laser=True)) self.lasers.extend(Laser(self, line) for line in laser) for b in self.target_blocks: b.new_playfield_update() if all(b.glows for b in self.target_blocks): self.on_completion() def update(self, e, t, dt): level.Level.update(self, e, t, dt) for laser in self.lasers: laser.update(e, t, dt) def draw(self, window): self._blit_background(window) objs = self._sorted_objs(self.objects + self.lasers) objs = self._after_sort(itertools.groupby( objs, lambda obj: obj.y + obj.z)) for obj in objs: obj.draw(window) self.darkness.draw(window) def _after_sort(self, objss): n_objs = [] for c, objs in objss: n_objs.extend(self._after_sort_line(list(objs))) return n_objs def _after_sort_line(self, objs): is_special = lambda obj: type(obj) in \ (Mirror, Laser, block.LaserSource, block.LaserTarget) specials, nonspecials = (filter(is_special, objs), filter(lambda obj: not is_special(obj), objs)) return nonspecials + self._sort_line_specials(specials) def _sort_line_specials(self, objs): mirrors = filter(lambda obj: isinstance(obj, Mirror), objs) lasers = filter(lambda obj: isinstance(obj, Laser), objs) sources = filter(lambda obj: isinstance(obj, block.LaserSource), objs) targets = filter(lambda obj: isinstance(obj, block.LaserTarget), objs) lasers_back = set(lasers) sep_ords = [] for obj in itertools.chain(mirrors, targets): before, after = [], [] for laser in _hit_lasers(obj, lasers): lasers_back.discard(laser) if _obj_is_behind_laser(obj, laser): after.append(laser) else: before.append(laser) sep_ords.append(before + [obj] + after) points = set((obj.x0, obj.y0) for obj in itertools.chain(mirrors, targets)) for laser in filter(lambda laser: (laser.x0, laser.y0) in points and (laser.x1, laser.y1) in points, lasers): # print(laser) xs, ys = filter(lambda sep_ord: laser in sep_ord, sep_ords) sep_ords.remove(xs) sep_ords.remove(ys) xs, ys, nobjs = iter(xs), iter(ys), [] while True: x = next(xs) if x is laser: break nobjs.append(x) while True: x = next(ys) if x is laser: break nobjs.append(x) nobjs.append(laser) nobjs.extend(xs) nobjs.extend(ys) sep_ords.append(nobjs) objs = list(itertools.chain(*sep_ords)) + list(lasers_back) \ + sources return objs def _hit_lasers(obj, lasers): p = (obj.x0, obj.y0) return filter(lambda laser: (laser.x0, laser.y0) == p or (laser.x1, laser.y1) == p, lasers) def _obj_is_behind_laser(obj, laser): return (_mirror_is_behind_laser if isinstance(obj, Mirror) else _target_is_behind_laser)(obj, laser) def _mirror_is_behind_laser(mirror, laser): return \ laser.y0 == laser.y1 \ and ( (mirror.left_up and ( (laser.x0 == mirror.x0 and laser.x1 > mirror.x0) or (laser.x1 == mirror.x0 and laser.x0 > mirror.x0) ) ) \ or \ (not mirror.left_up and ( (laser.x0 == mirror.x0 and laser.x1 < mirror.x0) or (laser.x1 == mirror.x0 and laser.x0 < mirror.x0) ) ) ) def _target_is_behind_laser(target, laser): return laser.x0 != laser.x1