@ -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 )
self . dimensions = 11 , 20
# 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 ( ) :
self . tiles . append (
tile . Tile ( self , i * 64 , ( j + 4 ) * 48 , self . imgs [ ' indoor %d ' % random . randint ( 1 , 6 ) ] ) )
level . Level . __init__ ( self , game , graphics_dir ,
size = ( 64 * 17 , 48 * 21 ) , paused = paused )
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
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 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 ) )
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 . 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 * ( 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 ) ) )
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_init_pos ( )
self , self . imgs [ ' elevator_bottom ' ] , 64 * 7 , 48 * 7 ) )
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 . 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 . update = self . update2
self . _start_time = pygame . time . get_ticks ( )
fadeout . Fadeout ( self . game , self . goto_next_level , duration = 1500 )
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 )
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
for laser in self . lasers :
laser . update ( e , t , dt )
def draw ( self , window ) :
self . _blit_background ( window )
def goto_next_level ( self ) :
self . game . goto_level ( 4 )
for obj in self . _sorted_objs ( self . bottom_objects ) :
try :
obj . draw ( window )
except IndexError :
print ( " Skipping frames ... " )
def restart ( self ) :
for obj in self . objects :
obj . reset_pos ( )
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