Improved lasers, implemented the weight indicator, created a level 2 with the symbol blocks, deleted the much too difficult level 3 and the no-content level 2, made proper links between the levels, created an end screen.

This commit is contained in:
Niels G. W. Serup 2012-11-15 18:36:50 +01:00
parent 9b7d4279ce
commit a3aeb127af
48 changed files with 567 additions and 434 deletions

View File

@ -88,7 +88,7 @@ class Block(worldobject.WorldObject):
obj.holding = self
self.holder = obj
if hasattr(self, 'img_str'):
self.img = self.level.imgs[self.img_str + '_lifted']
self.img = self.level.imgs[self.img_str + '-lifted']
# self.orig_alpha = self.orig_alphas['lifted']
def draw(self, window):

View File

@ -138,3 +138,6 @@ class Game(object):
self.menu.draw(self.window)
pygame.display.flip()
def quit(self):
self.running = False

View File

@ -65,39 +65,53 @@ class Laser(worldobject.WorldObject):
self.x1d += x1de
self.y1d += y1de
self.start_dark = 0
# self.start_dark = 0
self.surf = pygame.Surface(self.level.game.window.get_size(),
pygame.SRCALPHA)
# self.surf = pygame.Surface(self.level.game.window.get_size(),
# pygame.SRCALPHA)
self.load()
def update(self, e, t, dt):
self.start_dark = (t % 200) / 100
# self.start_dark = (t % 200) / 100
worldobject.WorldObject.update(self, e, t, dt)
def load(self):
self.img_horizontal = self.level.imgs['laser_beam_horizontal']
self.img_vertical = self.level.imgs['laser_beam_vertical']
def draw(self, window):
self.surf.fill((0, 0, 0, 0))
# self.surf.fill((0, 0, 0, 0))
colors = [(155, 0, 0), (255, 0, 0)]
c = self.start_dark
# colors = [(155, 0, 0), (255, 0, 0)]
# c = self.start_dark
if self.x0d != self.x1d:
length = self.x1d - self.x0d
for i in range(0, length, 8):
x0d = self.x0d + i
pygame.draw.line(self.surf, colors[c],
(x0d - self.level.camera_x,
self.y0d - self.level.camera_y),
(x0d + min(8, length - i) - self.level.camera_x,
self.y1d - self.level.camera_y), 2)
c ^= 1
x0d = self.x0d + i + 2
window.blit(self.img_horizontal,
(x0d - self.level.camera_x,
self.y0d - self.level.camera_y),
self.blit_area)
# pygame.draw.line(self.surf, colors[c],
# (x0d - self.level.camera_x,
# self.y0d - self.level.camera_y),
# (x0d + min(8, length - i) - self.level.camera_x,
# self.y1d - self.level.camera_y), 2)
# c ^= 1
else:
length = self.y1d - self.y0d
for i in range(0, length, 8):
y0d = self.y0d + i
pygame.draw.line(self.surf, colors[c],
(self.x0d - self.level.camera_x,
y0d - self.level.camera_y),
(self.x0d - self.level.camera_x,
y0d + min(8, length - i) - self.level.camera_y), 2)
c ^= 1
y0d = self.y0d + i + 2
window.blit(self.img_vertical,
(self.x0d - self.level.camera_x,
y0d - self.level.camera_y),
self.blit_area)
# pygame.draw.line(self.surf, colors[c],
# (self.x0d - self.level.camera_x,
# y0d - self.level.camera_y),
# (self.x0d - self.level.camera_x,
# y0d + min(8, length - i) - self.level.camera_y), 2)
# c ^= 1
window.blit(self.surf, (0, 0))
# window.blit(self.surf, (0, 0))

View File

@ -39,6 +39,8 @@ import boulder
import lever
import trigger
import worldobject
import level_bonus
import fadeout
import logic.teleportermap
import logic.rollingstone
@ -516,12 +518,17 @@ class Level1(level.Level):
if self.task_completions == self.solution
else lambda *v: None],
anim='lever_updown', toggling=False))
self.objects.append(
trigger.Trigger(self, 64 * door_x, 48 * 4,
[self.game.goto_level],
self.imgs['indoor1'],
[self.player]))
door.activate(1)
self._next_level_trigger = trigger.Trigger(
self,
64 * door_x, 48 * 4,
[lambda setting: self.goto_next_level()],
self.imgs['hole'],
[self.player],
visible=False)
self.objects.append(self._next_level_trigger)
if random.randint(0, 1):
for i in range(3):
self.objects.append(
@ -533,6 +540,26 @@ class Level1(level.Level):
CompletionBlock(self, 64 * (door_x - 3 - i), 48 * 4,
self.solution[i], i + 1))
### Link to bonus level
bonus = level_bonus.Level(self.game, self.graphics_dir)
def goto_bonus():
self._update = self.update
self.update = lambda *args: None
def g():
self.update = self._update
bonus.enter(self)
fadeout.Fadeout(self.game, g)
self.objects.append(
lever.Lever(
self, 64 * 39, 48 * 39,
[lambda setting: goto_bonus()],
toggling=False,
anim='lever_updown'))
# DRAW THE BACKGROUND
self.draw_background()
@ -553,6 +580,13 @@ class Level1(level.Level):
for obj in self.objects:
obj.reset_pos()
def goto_next_level(self):
print(333)
self.objects.remove(self._next_level_trigger)
self._old_player_update = self.player.update
self.player.update = lambda e, t, dt: self._old_player_update([], t, dt)
fadeout.Fadeout(self.game, lambda: self.game.goto_level(2), duration=1500)
class CompletionBlock(block.Block):
def __init__(self, level, x, y, task, number):
self.__dict__.update(locals())

View File

@ -1,53 +1,168 @@
#!/usr/bin/env python.
# -*- coding: utf-8 -*-
# This file is part of A Robot's Conundrum
#
# A Robot's Conundrum 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.
#
# A Robot's Conundrum 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
# A Robot's Conundrum. If not, see <http://www.gnu.org/licenses/>.
#
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
#
# level2.py
# --------------------
# date created : Fri Oct 12 2012
# copyright : (C) 2012 Niels G. W. Serup
# maintained by : Niels G. W. Serup <ngws@metanohi.name>
"""
The second level.
"""
from __future__ import print_function
import os
import pygame
import random
import re
import itertools
import worldobject
import level
import player
import trigger
import tile
import block
import boulder
import lever
import level_bonus
import fadeout
from weight_indicator import WeightIndicator
import logic.colourboxes
def is_sorted(xs):
return all(a <= b for a, b in itertools.izip(xs[:-1], xs[1:]))
class Level2(level.Level):
def __init__(self, game, graphics_dir, paused=False):
level.Level.__init__(self, game, graphics_dir, size=(64*5, 48*5),
level.Level.__init__(self, game, graphics_dir, size=(64*21, 48*20),
paused=paused)
self.dimensions = 5, 5
self.dimensions = 21, 20
for i in range(self.dimensions[0]):
for j in range(self.dimensions[1]):
self.tiles.append(
tile.Tile(self, i*64, (j + 1)*48,
self.imgs['indoor%d' % random.randint(1, 6)]))
self.task_start = (1, 6)
for i, j in self._positions():
self.tiles.append(
tile.Tile(self, i * 64, (j + 4) * 48, self.imgs['ground1']))
self.sort_poss = []
for x in range(12):
self.sort_poss.append(((x + 2) * 64, 6 * 48))
self.tiles.append(
tile.Tile(self, (x + 2) * 64, 6 * 48, self.imgs['indoor1']))
self.symbolblocks = []
for x in range(12):
b = block.Block(self, 64 * (x + 2), 48 * 10,
self.imgs['symbolblock%02d' % (x + 1)], movable=True)
self.symbolblocks.append(b)
random.shuffle(self.symbolblocks)
for i in range(len(self.symbolblocks)):
self.symbolblocks[i].n = i
random.shuffle(self.symbolblocks)
self.objects.extend(self.symbolblocks)
self.weighing_poss = ((7 * 64, 12 * 48), (9 * 64, 12 * 48))
for x, y in self.weighing_poss:
self.tiles.append(
tile.Tile(self, x, y, self.imgs['indoor3']))
self.objects.append(
trigger.Trigger(self,
x, y,
[self.weigh],
self.imgs['hole'],
self.symbolblocks,
visible=False,
no_stop=True))
self.draw_background()
bonus = level_bonus.Level(self.game, self.graphics_dir)
self.weight_ind = WeightIndicator(self, 8, 8, 0, links=[])
self.objects.append(self.weight_ind)
top = self.dimensions[0]
for i in range(top):
if i % 3 == 0:
self.objects.append(block.Block(
self, i * 64, 48 * 3,
self.imgs['wall'],
width=2 if i == top - 2 else 3,
blit_area=(0, 0, 160, 192) if i == top - 2 else None))
self.objects.append(block.InvisBlock(self, i * 64,
self.size[1]))
for i in range(self.dimensions[1]):
self.objects.append(block.InvisBlock(self, - 64, i * 48))
self.objects.append(block.InvisBlock(self, self.size[0], i * 48))
self.bottom_objects.append(worldobject.WithBackground(
self, self.imgs['elevator_top'], 64 * (self.task_start[0] + 1), 48 * (self.task_start[1] + 10)))
self.elevator = worldobject.WithBackground(
self, self.imgs['elevator'], 64 * (self.task_start[0] + 1), 48 * (self.task_start[1] + 11), 48)
self.bottom_objects.append(self.elevator)
self._next_level_trigger = trigger.Trigger(
self, 64 * (self.task_start[0] + 2), 48 * (self.task_start[1] + 10), [lambda _: self.try_goto_next_level()],
self.imgs['hole'],
[self.player], visible=False, no_stop=True)
self.objects.append(self._next_level_trigger)
self.bottom_objects.append(worldobject.WithBackground(
self, self.imgs['elevator_bottom'], 64 * (self.task_start[0] + 1), 48 * (self.task_start[1] + 12)))
def f():
self._update = self.update
self.update = lambda *args: None
def g():
self.update = self._update
bonus.enter(self)
fadeout.Fadeout(self.game, g)
self.objects.append(
lever.Lever(
self, 64 * 2, 48 * 3,
[lambda setting: f()],
toggling=False,
anim='lever_updown'))
self.player.set_pos(64 * 2, 48 * 1)
self.player.set_pos(64 * 1, 48 * 4)
self.player.set_init_pos()
def weigh(self, x):
a, b = None, None
for bl in self.symbolblocks:
if (bl.x, bl.y) == self.weighing_poss[0]:
a = bl.n
elif (bl.x, bl.y) == self.weighing_poss[1]:
b = bl.n
if a is not None and b is not None:
self.weight_ind.change_state(-1 if a < b else 1 if a > b else 0)
def can_go(self):
calc = [None for i in range(12)]
for bl in self.symbolblocks:
p = (bl.x, bl.y)
if p in self.sort_poss:
calc[self.sort_poss.index(p)] = bl.n
return not None in calc and (is_sorted(calc) or is_sorted(calc[::-1]))
def try_goto_next_level(self):
if not self.can_go():
return
self.objects.remove(self._next_level_trigger)
self._old_player_update = self.player.update
self.player.update = lambda e, t, dt: self._old_player_update([], t, dt)
self.update = self.update2
self._start_time = pygame.time.get_ticks()
fadeout.Fadeout(self.game, self.goto_next_level, duration=1500)
def update2(self, e, t, dt):
level.Level.update(self, e, t, dt)
start_offset = (t - self._start_time) / 25
self.elevator.z_px = 48 - start_offset
self.player.y = 48 * (self.task_start[1] + 10) - start_offset
def goto_next_level(self):
self.game.goto_level(3)
def restart(self):
for obj in self.objects:

View File

@ -1,25 +1,23 @@
#!/usr/bin/env python.
# -*- coding: utf-8 -*-
# This file is part of A Robot's Conundrum
# This file is part of A Robot's Conundrum.
#
# A Robot's Conundrum 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.
#
# A Robot's Conundrum 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.
# A Robot's Conundrum 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
# A Robot's Conundrum. If not, see <http://www.gnu.org/licenses/>.
#
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
#
# level3.py
# level3.py
# --------------------
# date created : Wed Aug 8 2012
# date created : Fri Aug 10 2012
# copyright : (C) 2012 Niels G. W. Serup
# maintained by : Niels G. W. Serup <ngws@metanohi.name>
@ -35,53 +33,82 @@ import random
import re
import itertools
import worldobject
import level
import player
import trigger
import tile
import block
import lever
from mirror import Mirror
from laser import Laser
import misc
import worldobject
import fadeout
import logic.colourboxes
import logic.lasermirror as lm
from logic.direction import *
class Level3(level.Level):
def __init__(self, game, graphics_dir, paused=False):
level.Level.__init__(self, game, graphics_dir, size=(64*11, 48*20),
paused=paused)
level.Level.__init__(self, game, graphics_dir,
size=(64 * 17, 48 * 21), paused=paused)
self.dimensions = 11, 20
self.dimensions = 17, 17
# for i in range(self.dimensions[0]):
# for j in range(self.dimensions[1]):
# self.tiles.append(
# tile.Tile(self, i*64, j*48, self.imgs['ground1']))
self.task_start = (1, 6)
# Abstract "boxes", actually colour fields
boxes = []
for i in range(4):
boxes.extend([(0, 0, 0)] * i + box + [(0, 0, 0)] * (3 - i)
for box in logic.colourboxes.generate_colour_boxes(1, 3))
boxes.extend(logic.colourboxes.generate_random_box(4, 2) for _ in range(20))
boxes.extend([(0, 0, 0)] * 4 for _ in range(10))
random.shuffle(boxes)
pos_colour = {}
for i, j in self._positions():
not_ok_pos = set(itertools.product(range(7, 10), range(1, 4)))
for i, j in filter(lambda p: p not in not_ok_pos, self._positions()):
self.tiles.append(
tile.Tile(self, i * 64, (j + 4) * 48, self.imgs['indoor%d' % random.randint(1, 6)]))
for box, (x, y) in zip(boxes, itertools.product(range(7), range(6))):
# self.tiles.append(tile.Tile(self, 64 * (x + self.task_start[0] + 1),
# 48 * (y + self.task_start[1] + 1),
# self.imgs['indoor%d' % random.randint(1, 6)]))
pos_colour[(x, y)] = box
tile.Tile(self, i * 64, (j + 4) * 48, self.imgs[
('indoor%d' % random.randint(1, 6))
if random.randrange(6) != 0 else 'ground1']))
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.dimensions[0]
for i in range(top):
if i % 3 == 0:
@ -93,81 +120,172 @@ class Level3(level.Level):
self.objects.append(block.InvisBlock(self, i * 64,
self.size[1]))
for i in range(self.dimensions[1]):
self.objects.append(block.InvisBlock(self, - 64, i * 48))
self.objects.append(block.InvisBlock(self, self.size[0], i * 48))
self.objects.append(block.InvisBlock(self, - 64, (i + 4) * 48))
self.objects.append(block.InvisBlock(self, self.size[0], (i + 4) * 48))
action_blocks = list(itertools.chain(*
[(block.ActionBlock(self, 64 * self.task_start[0],
48 * (i + 1 + self.task_start[1]),
movable=True),
block.ActionBlock(self, 64 * (self.task_start[0] + 8),
48 * (i + 1 + self.task_start[1]),
movable=True))
for i in range(6)]))
self.objects.extend(action_blocks)
wells = [block.ColorWell(self, self.task_start[0] * 64, self.task_start[1] * 48),
block.ColorWell(self, (self.task_start[0] + 8) * 64, self.task_start[1] * 48),
block.ColorWell(self, self.task_start[0] * 64, (self.task_start[1] + 7) * 48),
block.ColorWell(self, (self.task_start[0] + 8) * 64, (self.task_start[1] + 7) * 48),
]
self.objects.extend(wells)
self.wells = wells
self.generate_lasers()
self.bottom_objects.append(worldobject.WithBackground(
self, self.imgs['elevator_top'], 64 * (self.task_start[0] + 3), 48 * (self.task_start[1] + 10)))
self, self.imgs['elevator_top'], 64 * 7, 48 * 5))
self.elevator = worldobject.WithBackground(
self, self.imgs['elevator'], 64 * (self.task_start[0] + 3), 48 * (self.task_start[1] + 11), 48)
self, self.imgs['elevator'], 64 * 7, 48 * 6, 48 * 3,
(0, 0, 256, 192 - 24 - 48 * 2))
self.bottom_objects.append(self.elevator)
self._next_level_trigger = trigger.Trigger(
self, 64 * (self.task_start[0] + 4), 48 * (self.task_start[1] + 10), [lambda _: self.try_goto_next_level()],
self.imgs['hole'],
[self.player], visible=False, no_stop=True)
self.objects.append(self._next_level_trigger)
self.bottom_objects.append(worldobject.WithBackground(
self, self.imgs['elevator_bottom'], 64 * (self.task_start[0] + 3), 48 * (self.task_start[1] + 12)))
self, self.imgs['elevator_bottom'], 64 * 7, 48 * 7))
def update_wells(block):
cur_boxes = []
for block in action_blocks:
box = pos_colour.get((block.x / 64 - self.task_start[0] - 1,
block.y / 48 - self.task_start[1] - 1))
if box:
cur_boxes.append(box)
if not cur_boxes:
well_colours = [(0, 0, 0)] * len(wells)
else:
well_colours = logic.colourboxes.get_colours(cur_boxes)
for well, color in zip(wells, well_colours):
well.set_colour(*color)
for b in action_blocks:
b.action = update_wells
self.player.set_pos(64 * 5, 48 * 4)
self.player.set_pos(64 * 8, 48 * 5)
self.player.set_init_pos()
def try_goto_next_level(self):
# if not all(well.well_colour == (255, 255, 255)
# for well in self.wells):
# return
self.objects.remove(self._next_level_trigger)
self._old_player_update = self.player.update
self.player.update = lambda e, t, dt: self._old_player_update([], t, dt)
self.update = self.update2
self._start_time = pygame.time.get_ticks()
fadeout.Fadeout(self.game, self.goto_next_level, duration=1500)
def update2(self, e, t, dt):
level.Level.update(self, e, t, dt)
start_offset = (t - self._start_time) / 25
self.elevator.z_px = 48 - start_offset
self.player.y = 48 * (self.task_start[1] + 10) - start_offset
def goto_next_level(self):
self.game.goto_level(4)
self.on_completion()
def on_completion(self):
# End game here.
fadeout.Fadeout(self.game, lambda: self.game.goto_level(4), duration=5000)
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):
self.update2(e, t, dt)
start_offset = (t - self._start_time) / 25
if start_offset >= 96:
start_offset = 96
self.player.y = 48 * 7 - start_offset
self.elevator.z_px = 48 * 3 - start_offset
self.elevator.blit_area = (0, 0, 256, 192 - 24 - 48 * 2 + start_offset)
if start_offset == 96:
self.update = self.update2
self.player.update = self._old_player_update
def update2(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)
for obj in self._sorted_objs(self.bottom_objects):
try:
obj.draw(window)
except IndexError:
print("Skipping frames ...")
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

View File

@ -15,275 +15,37 @@
#
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
#
# level1.py
# level4.py
# --------------------
# date created : Fri Aug 10 2012
# copyright : (C) 2012 Niels G. W. Serup
# maintained by : Niels G. W. Serup <ngws@metanohi.name>
# date created : Thu Nov 15 2012
# copyright : (C) 2012 Sakse Dalum
# maintained by : Sakse Dalum <don_s@hongabar.org>
"""
The fourth level.
The final level.
"""
from __future__ import print_function
import os
import pygame
import random
import re
import itertools
import os.path
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 * 17, 48 * 21), paused=paused)
self.dimensions = 17, 17
not_ok_pos = set(itertools.product(range(7, 10), range(1, 4)))
for i, j in filter(lambda p: p not in not_ok_pos, self._positions()):
self.tiles.append(
tile.Tile(self, i * 64, (j + 4) * 48, self.imgs[
('indoor%d' % random.randint(1, 6))
if random.randrange(6) != 0 else 'ground1']))
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.dimensions[0]
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.dimensions[1]):
self.objects.append(block.InvisBlock(self, - 64, (i + 4) * 48))
self.objects.append(block.InvisBlock(self, self.size[0], (i + 4) * 48))
self.generate_lasers()
self.bottom_objects.append(worldobject.WithBackground(
self, self.imgs['elevator_top'], 64 * 7, 48 * 5))
self.elevator = worldobject.WithBackground(
self, self.imgs['elevator'], 64 * 7, 48 * 6, 48 * 3,
(0, 0, 256, 192 - 24 - 48 * 2))
self.bottom_objects.append(self.elevator)
self.bottom_objects.append(worldobject.WithBackground(
self, self.imgs['elevator_bottom'], 64 * 7, 48 * 7))
self.player.set_pos(64 * 8, 48 * 5)
self.player.set_init_pos()
self._old_player_update = self.player.update
self.player.update = lambda e, t, dt: self._old_player_update([], t, dt)
self._start_time = pygame.time.get_ticks()
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()
self.background_img = pygame.image.load(os.path.join(self.graphics_dir,
'main_menu.png'))
self.background_img = pygame.transform.smoothscale(
self.background_img, self.game.window.get_size())
self.background_img = pygame.transform.rotate(
self.background_img, 180)
def update(self, e, t, dt):
self.update2(e, t, dt)
start_offset = (t - self._start_time) / 25
if start_offset >= 96:
start_offset = 96
self.player.y = 48 * 7 - start_offset
self.elevator.z_px = 48 * 3 - start_offset
self.elevator.blit_area = (0, 0, 256, 192 - 24 - 48 * 2 + start_offset)
if start_offset == 96:
self.update = self.update2
self.player.update = self._old_player_update
def update2(self, e, t, dt):
level.Level.update(self, e, t, dt)
for laser in self.lasers:
laser.update(e, t, dt)
if not self.paused:
for event in e:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
self.game.quit()
def draw(self, window):
self._blit_background(window)
for obj in self._sorted_objs(self.bottom_objects):
try:
obj.draw(window)
except IndexError:
print("Skipping frames ...")
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
window.blit(self.background_img, (0, 0))

View File

@ -42,24 +42,33 @@ import fadeout
class Level(level.Level):
def __init__(self, game, graphics_dir, paused=False):
level.Level.__init__(self, game, graphics_dir, size=(64*20, 48*20),
level.Level.__init__(self, game, graphics_dir, size=(64*21, 48*20),
paused=paused)
self.dimensions = 20, 20
self.dimensions = 21, 20
for i in range(self.dimensions[0]):
for j in range(self.dimensions[1]):
self.tiles.append(
tile.Tile(self, (i+1)*64, j*48, self.imgs['indoor%d' % random.randint(1, 6)]))
for i, j in self._positions():
self.tiles.append(
tile.Tile(self, i * 64, (j + 4) * 48, self.imgs['ground1']))
self.draw_background()
top = self.dimensions[0]
for i in range(top):
if i % 3 == 0:
self.objects.append(block.Block(
self, i * 64, 48 * 3,
self.imgs['wall'],
width=2 if i == top - 2 else 3,
blit_area=(0, 0, 160, 192) if i == top - 2 else None))
self.objects.append(block.InvisBlock(self, i * 64,
self.size[1]))
for i in range(self.dimensions[1]):
self.objects.append(block.InvisBlock(self, - 64, i * 48))
self.objects.append(block.InvisBlock(self, self.size[0], i * 48))
for x, y in misc.pick_random_elements(
list(itertools.product(range(2, 20), range(2, 20))), 150):
self.objects.append(block.Block(self, 64 * x, 48 * y,
self.imgs['block1'], movable=True))
def f():
def go_back():
self._update = self.update
self.update = lambda *args: None
def g():
@ -69,12 +78,17 @@ class Level(level.Level):
self.objects.append(
lever.Lever(
self, 64, 48,
[lambda setting: f()],
self, 0, 48 * 4,
[lambda setting: go_back()],
toggling=False,
anim='lever_updown'))
self.player.set_pos(64 * 1, 48 * 2)
for x, y in misc.pick_random_elements(
list(itertools.product(range(2, 19), range(2, 14))), 150):
self.objects.append(block.Block(self, 64 * x, 48 * (4 + y),
self.imgs['block1'], movable=True))
self.player.set_pos(0, 48 * 5)
self.player.set_init_pos()
def enter(self, root_level):

View File

@ -42,11 +42,11 @@ class Loader(object):
self.directory, 'tiles', '%s.png' % o))
for o in range(1, 13):
for i in range(16, 19):
self.imgs['symbol%02d-%04d' % (o, i)] = (
for i in ('', '-lifted', '-down'):
s = 'symbolblock%02d%s' % (o, i)
self.imgs[s] = (
pygame.image.load(os.path.join(
self.directory, 'symbols', 'blocks',
'block%02d-%04d.png' % (o, i))))
self.directory, 'symbols', 'blocks', s + '.png')))
for o in range(13, 18):
for i in range(16, 20):
self.imgs['symbol%02d-%04d' % (o, i)] = (
@ -58,9 +58,10 @@ class Loader(object):
self.imgs['indoor%d' % o] = pygame.image.load(os.path.join(
self.directory, 'tiles', 'indoor', 'ground%02d.png' % o))
l = ['block1', 'block1_lifted', 'block3', '../lasertarget',
l = ['block1', 'block1-lifted', 'block3', '../lasertarget',
'../lasersource_up', '../lasersource_down', '../lasersource_right',
'../lasertarget_glow']
'../lasertarget_glow', '../laser_beam_horizontal',
'../laser_beam_vertical']
for o in l:
self.imgs[os.path.basename(o)] = pygame.image.load(os.path.join(
self.directory, 'blocks', '%s.png' % o))
@ -127,6 +128,7 @@ class Loader(object):
('elevating_column', 'elevating_column'),
('mirror', 'mirror'),
('weight_indicator', 'weight_indicator'),
('door', 'door')]
):

View File

@ -0,0 +1,71 @@
# This file is part of A Robot's Conundrum.
#
# A Robot's Conundrum 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.
#
# A Robot's Conundrum 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
# A Robot's Conundrum. If not, see <http://www.gnu.org/licenses/>.
#
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
#
# weight_indicator.py
# --------------------
# date created : Thu Nov 15 2012
# copyright : (C) 2012 Niels G. W. Serup
# maintained by : Niels G. W. Serup <ngws@metanohi.name>
"""
A weight indicator for drawing.
"""
import pygame
import worldobject
class WeightIndicator(worldobject.WorldObject):
def __init__(self, level, x0, y0, state=0, links=[]):
self.__dict__.update(locals())
self.xd, self.yd = self.x0 * 64, (self.y0 + 4) * 48
worldobject.WorldObject.__init__(self, level, self.xd, self.yd)
self.in_rotation = False
self.frame = self.state_to_frame(self.state)
def state_to_frame(self, state):
return state * 9 + 9
def change_state(self, new_state):
if self.in_rotation or new_state == self.state:
return
self.in_rotation = True
self.start_frame = self.frame
self.goal_state = new_state
self.goal_frame = self.state_to_frame(new_state)
self.start_time = pygame.time.get_ticks()
def update(self, e, t, dt):
if self.in_rotation:
d = (t - self.start_time) / 1000.0
self.frame = min(18, int(self.start_frame
+ (self.goal_frame - self.start_frame)
* d))
if self.frame == self.goal_frame:
self.in_rotation = False
self.state = self.goal_state
for link in self.links:
link(self.state)
worldobject.WorldObject.update(self, e, t, dt)
def draw(self, window):
self.img = self.level.imgs['weight_indicator'][self.frame]
window.blit(self.img, (self.xd - 32 - self.level.camera_x,
self.yd - self.img.get_size()[1] + 24
- self.level.camera_y))

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 210 B

After

Width:  |  Height:  |  Size: 210 B

View File

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB