Updated filenames and file contents to fit the title of the game. Made proper readme.
This commit is contained in:
3
arobotsconundrum/__init__.py
Normal file
3
arobotsconundrum/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
# init file.
|
||||
|
||||
import game
|
||||
317
arobotsconundrum/block.py
Normal file
317
arobotsconundrum/block.py
Normal file
@@ -0,0 +1,317 @@
|
||||
# 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/>.
|
||||
#
|
||||
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
|
||||
#
|
||||
# block.py
|
||||
# --------------------
|
||||
# date created : Tue Aug 7 2012
|
||||
# copyright : (C) 2012 Sakse Dalum
|
||||
# maintained by : Sakse Dalum <don_s@hongabar.org>
|
||||
|
||||
"""
|
||||
A generic block. And other block derivatives.
|
||||
"""
|
||||
|
||||
import pygame
|
||||
import itertools
|
||||
|
||||
import worldobject
|
||||
import copy
|
||||
|
||||
class Block(worldobject.WorldObject):
|
||||
def __init__(self, level, x, y, img_str='block1',
|
||||
movable=False, visible=True,
|
||||
width=1, height=1, blit_area=None,
|
||||
blocking=True, z=0):
|
||||
self.__dict__.update(locals())
|
||||
worldobject.WorldObject.__init__(self, level, x, y, z=z,
|
||||
movable=movable, visible=visible,
|
||||
blit_area=blit_area, blocking=blocking)
|
||||
|
||||
for i in range(width):
|
||||
for j in range(height):
|
||||
if width != 1 or height != 1:
|
||||
self.level.objects.append(
|
||||
InvisBlock(self.level,
|
||||
self.x + 64 * i,
|
||||
self.y - 48 * j))
|
||||
|
||||
self.load()
|
||||
|
||||
# self.orig_alphas = {
|
||||
# 'normal':
|
||||
# pygame.surfarray.array_alpha(self.level.imgs[self.img_str]),
|
||||
# 'lifted':
|
||||
# pygame.surfarray.array_alpha(
|
||||
# self.level.imgs[self.img_str + '_lifted'])}
|
||||
|
||||
# self.orig_alpha = self.orig_alphas['normal']
|
||||
|
||||
def load(self):
|
||||
if not isinstance(self.img_str, str):
|
||||
self.img_str = self.level.reverse_imgs[self.img_str]
|
||||
|
||||
self.img = self.level.imgs[self.img_str]
|
||||
|
||||
# def update_alpha(self):
|
||||
# be_opaque = not (self.y + self.z >= self.level.player.move_y
|
||||
# + self.level.player.move_z)
|
||||
# if be_opaque and not self.is_currently_opaque:
|
||||
# self.is_currently_opaque = True
|
||||
# self.set_alpha(1)
|
||||
# elif not be_opaque and self.is_currently_opaque:
|
||||
# self.is_currently_opaque = False
|
||||
# self.set_alpha(0.5)
|
||||
|
||||
def use(self, obj):
|
||||
if self.movable:
|
||||
if obj == self.holder:
|
||||
obj.holding = None
|
||||
self.holder = None
|
||||
if hasattr(self, 'img_str'):
|
||||
self.img = self.level.imgs[self.img_str]
|
||||
# self.orig_alpha = self.orig_alphas['normal']
|
||||
else:
|
||||
obj.holding = self
|
||||
self.holder = obj
|
||||
if hasattr(self, 'img_str'):
|
||||
self.img = self.level.imgs[self.img_str + '_lifted']
|
||||
# self.orig_alpha = self.orig_alphas['lifted']
|
||||
|
||||
def draw(self, window):
|
||||
if self.visible:
|
||||
window.blit(self.img, (self.x - 32 - self.level.camera_x,
|
||||
self.y - self.img.get_size()[1] + 24
|
||||
- self.level.camera_y), self.blit_area)
|
||||
|
||||
|
||||
class InvisBlock(Block):
|
||||
def __init__(self, level, x, y):
|
||||
self.__dict__.update(locals())
|
||||
worldobject.WorldObject.__init__(self, level, x, y, visible=False)
|
||||
|
||||
|
||||
class ArrowBlock(Block):
|
||||
def __init__(self, level, x, y, direction, movable=True, is_up=True):
|
||||
self.__dict__.update(locals())
|
||||
worldobject.WorldObject.__init__(self, level, x, y,
|
||||
direction=direction, movable=movable)
|
||||
|
||||
self.frame = 0
|
||||
self.anim_speed = 15
|
||||
self.setting = False
|
||||
|
||||
if direction == (1, 0):
|
||||
self.anim = 'arrow_right'
|
||||
if direction == (-1, 0):
|
||||
self.anim = 'arrow_left'
|
||||
if direction == (0, -1):
|
||||
self.anim = 'arrow_up'
|
||||
if direction == (0, 1):
|
||||
self.anim = 'arrow_down'
|
||||
self.img_str = self.anim
|
||||
|
||||
def activate(self, setting):
|
||||
self.movable = True
|
||||
if not self.share_tile(worldobject.WorldObject):
|
||||
self.is_up = not setting
|
||||
self.movable = False
|
||||
|
||||
def update(self, e, t, dt):
|
||||
# Update the animation
|
||||
if not self.is_up:
|
||||
self.frame = min(self.frame + self.anim_speed * dt,
|
||||
len(self.level.imgs[self.anim]) - 1)
|
||||
else:
|
||||
self.frame = max(self.frame - self.anim_speed * dt,
|
||||
0)
|
||||
|
||||
if self.frame == len(self.level.imgs[self.anim]) - 1:
|
||||
self.movable = self.blocking = False
|
||||
self.z = -48
|
||||
if self.holder:
|
||||
self.holder.holding = None
|
||||
self.holder = None
|
||||
else:
|
||||
self.movable = self.blocking = True
|
||||
self.z = 0
|
||||
|
||||
worldobject.WorldObject.update(self, e, t, dt)
|
||||
|
||||
def draw(self, window):
|
||||
if not self.holder:
|
||||
self.img = self.level.imgs[self.anim][int(self.frame)]
|
||||
Block.draw(self, window)
|
||||
|
||||
class RisingBlock(Block):
|
||||
def __init__(self, level, x, y, movable=False, is_up=True):
|
||||
self.__dict__.update(locals())
|
||||
worldobject.WorldObject.__init__(self, level, x, y, movable=movable)
|
||||
|
||||
self.frame = 0
|
||||
self.anim_speed = 15
|
||||
self.setting = [0, 0]
|
||||
|
||||
self.init_setting = self.setting
|
||||
|
||||
self.anim = 'arrow_right'
|
||||
|
||||
def set_init_pos(self):
|
||||
worldobject.WorldObject.set_init_pos(self)
|
||||
self.init_setting = [self.setting[0], self.setting[1]]
|
||||
|
||||
def reset_pos(self):
|
||||
worldobject.WorldObject.reset_pos(self)
|
||||
self.setting = [self.init_setting[0], self.init_setting[1]]
|
||||
self.is_up = self.setting[1] == self.setting[0]
|
||||
|
||||
def activate(self, setting):
|
||||
if setting in [2, 3]:
|
||||
self.setting[1] = setting - 2
|
||||
else:
|
||||
self.setting[0] = setting
|
||||
if not self.share_tile(worldobject.WorldObject):
|
||||
self.is_up = self.setting[1] == self.setting[0]
|
||||
|
||||
def update(self, e, t, dt):
|
||||
# Update the animation
|
||||
if not self.is_up:
|
||||
self.frame = min(self.frame + self.anim_speed * dt,
|
||||
len(self.level.imgs[self.anim]) - 1)
|
||||
else:
|
||||
self.frame = max(self.frame - self.anim_speed * dt,
|
||||
0)
|
||||
|
||||
if self.frame == len(self.level.imgs[self.anim]) - 1:
|
||||
self.blocking = False
|
||||
self.z = -48
|
||||
else:
|
||||
self.blocking = True
|
||||
self.z = 0
|
||||
|
||||
worldobject.WorldObject.update(self, e, t, dt)
|
||||
|
||||
def draw(self, window):
|
||||
self.img = self.level.imgs[self.anim][int(self.frame)]
|
||||
Block.draw(self, window)
|
||||
|
||||
|
||||
class ActionBlock(Block):
|
||||
def __init__(self, level, x, y, action=None, movable=True):
|
||||
self.__dict__.update(locals())
|
||||
Block.__init__(
|
||||
self, level, x, y, 'block1', movable=movable)
|
||||
self._last_pos = None
|
||||
|
||||
def update(self, e, t, dt):
|
||||
if (self.x, self.y) != self._last_pos and not self.is_moving:
|
||||
self.action(self)
|
||||
self._last_pos = self.x, self.y
|
||||
|
||||
worldobject.WorldObject.update(self, e, t, dt)
|
||||
|
||||
class ColorWell(Block):
|
||||
def __init__(self, level, x, y, img_str='well'):
|
||||
self.__dict__.update(locals())
|
||||
worldobject.WorldObject.__init__(
|
||||
self, level, x, y, movable=False)
|
||||
|
||||
Block.load(self)
|
||||
|
||||
self.col_img = pygame.Surface((32, 32))
|
||||
|
||||
def set_colour(self, r, g, b):
|
||||
self.well_colour = r * 255, g * 255, b * 255
|
||||
self.col_img.fill(self.well_colour)
|
||||
|
||||
def draw(self, window):
|
||||
if self.visible:
|
||||
window.blit(self.col_img, (self.x - self.level.camera_x + 16,
|
||||
self.y - self.img.get_size()[1] + 52
|
||||
- self.level.camera_y))
|
||||
Block.draw(self, window)
|
||||
|
||||
class Door(Block):
|
||||
def __init__(self, level, x, y, movable=False, setting=False):
|
||||
self.__dict__.update(locals())
|
||||
worldobject.WorldObject.__init__(self, level, x, y,
|
||||
z=32, movable=movable)
|
||||
|
||||
self.frame = 0
|
||||
self.anim_speed = 15
|
||||
|
||||
self.init_setting = self.setting
|
||||
|
||||
self.anim = 'door'
|
||||
|
||||
self.level.objects.append(InvisBlock(self.level, self.x + 64, self.y))
|
||||
self.level.objects.append(InvisBlock(self.level, self.x - 64, self.y))
|
||||
|
||||
def set_init_pos(self):
|
||||
worldobject.WorldObject.set_init_pos(self)
|
||||
self.init_setting = self.setting
|
||||
|
||||
def reset_pos(self):
|
||||
worldobject.WorldObject.reset_pos(self)
|
||||
self.setting = self.init_setting
|
||||
|
||||
def activate(self, setting):
|
||||
self.setting = setting
|
||||
|
||||
def update(self, e, t, dt):
|
||||
# Update the animation
|
||||
if self.setting:
|
||||
self.frame = min(self.frame + self.anim_speed * dt,
|
||||
len(self.level.imgs[self.anim]) - 1)
|
||||
else:
|
||||
self.frame = max(self.frame - self.anim_speed * dt,
|
||||
0)
|
||||
|
||||
if self.frame == len(self.level.imgs[self.anim]) - 1:
|
||||
self.blocking = False
|
||||
else:
|
||||
self.blocking = True
|
||||
|
||||
worldobject.WorldObject.update(self, e, t, dt)
|
||||
|
||||
def draw(self, window):
|
||||
self.img = self.level.imgs[self.anim][int(self.frame)]
|
||||
if self.visible:
|
||||
window.blit(self.img, (self.x - (32 + 64) - self.level.camera_x,
|
||||
self.y - self.img.get_size()[1] + 24
|
||||
- self.level.camera_y))
|
||||
|
||||
class LaserSource(Block):
|
||||
def __init__(self, level, x1, y1, source_direction):
|
||||
self.__dict__.update(locals())
|
||||
Block.__init__(self, level, x1, y1,
|
||||
'lasersource_' + source_direction.to_str(),
|
||||
movable=False)
|
||||
|
||||
class LaserTarget(Block):
|
||||
def __init__(self, level, x0, y0):
|
||||
self.__dict__.update(locals())
|
||||
self.xd, self.yd = self.x0 * 64, (self.y0 + 4) * 48
|
||||
Block.__init__(self, level, self.xd, self.yd,
|
||||
'lasertarget', movable=False)
|
||||
self.glows = False
|
||||
|
||||
def new_playfield_update(self):
|
||||
self.glows, self.img_str = (True, 'lasertarget_glow') \
|
||||
if (self.x0, self.y0) in itertools.chain(*self.level.lasers_orig) \
|
||||
else (False, 'lasertarget')
|
||||
self.load()
|
||||
|
||||
99
arobotsconundrum/boulder.py
Normal file
99
arobotsconundrum/boulder.py
Normal file
@@ -0,0 +1,99 @@
|
||||
# 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/>.
|
||||
#
|
||||
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
|
||||
#
|
||||
# boulder.py
|
||||
# --------------------
|
||||
# date created : Wed Aug 8 2012
|
||||
# copyright : (C) 2012 Sakse Dalum
|
||||
# maintained by : Sakse Dalum <don_s@hongabar.org>
|
||||
|
||||
"""
|
||||
A rolling boulder.
|
||||
"""
|
||||
|
||||
import pygame
|
||||
|
||||
import worldobject
|
||||
import block
|
||||
import player
|
||||
|
||||
class Boulder(worldobject.WorldObject):
|
||||
def __init__(self, level, x, y, direction=(1, 0),
|
||||
movable=True, rolling=False):
|
||||
self.__dict__.update(locals())
|
||||
worldobject.WorldObject.__init__(self, level, x, y, direction=direction,
|
||||
movable=movable, speed=4)
|
||||
|
||||
self.falling = False
|
||||
|
||||
self.anim = 'boulder_right'
|
||||
self.frame = 0
|
||||
self.anim_speed = 60
|
||||
|
||||
self.ignore_list.append(player.Player)
|
||||
|
||||
def fall(self, setting):
|
||||
if setting and not self.falling:
|
||||
self.frame = 0
|
||||
self.falling = True
|
||||
|
||||
def activate(self, setting):
|
||||
self.rolling = True
|
||||
|
||||
def reset_pos(self):
|
||||
worldobject.WorldObject.reset_pos(self)
|
||||
self.frame = 0
|
||||
self.rolling = False
|
||||
self.falling = False
|
||||
|
||||
def update(self, e, t, dt):
|
||||
# Update the animation
|
||||
if self.rolling:
|
||||
self.frame = ((self.frame + self.anim_speed * dt) %
|
||||
len(self.level.imgs[self.anim]))
|
||||
if self.falling:
|
||||
self.frame = min(self.frame + self.anim_speed * dt,
|
||||
len(self.level.imgs[self.anim]) - 1)
|
||||
|
||||
if self.falling:
|
||||
self.anim = 'boulder_falling'
|
||||
if self.frame == len(self.level.imgs[self.anim]) - 1:
|
||||
self.reset_pos()
|
||||
elif self.direction == (1, 0):
|
||||
self.anim = 'boulder_right'
|
||||
elif self.direction == (0, 1):
|
||||
self.anim = 'boulder_down'
|
||||
elif self.direction == (-1, 0):
|
||||
self.anim = 'boulder_left'
|
||||
elif self.direction == (0, -1):
|
||||
self.anim = 'boulder_up'
|
||||
|
||||
if self.rolling and not self.falling:
|
||||
if not self.is_moving:
|
||||
tile_sharer = self.share_tile(block.ArrowBlock)
|
||||
if tile_sharer:
|
||||
self.direction = tile_sharer.direction
|
||||
if not self.move(*self.direction) and not self.is_moving:
|
||||
self.reset_pos()
|
||||
|
||||
worldobject.WorldObject.update(self, e, t, dt)
|
||||
|
||||
def draw(self, window):
|
||||
self.img = self.level.imgs[self.anim][int(self.frame)]
|
||||
window.blit(self.img, (self.x - 32 - self.level.camera_x,
|
||||
self.y - self.img.get_size()[1] + 24
|
||||
- self.level.camera_y))
|
||||
71
arobotsconundrum/fadeout.py
Normal file
71
arobotsconundrum/fadeout.py
Normal 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/>.
|
||||
#
|
||||
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
|
||||
#
|
||||
# fadeout.py
|
||||
# --------------------
|
||||
# date created : Thu Aug 9 2012
|
||||
# copyright : (C) 2012 Niels G. W. Serup
|
||||
# maintained by : Niels G. W. Serup <ngws@metanohi.name>
|
||||
|
||||
"""
|
||||
Fade out and in.
|
||||
"""
|
||||
|
||||
import os
|
||||
import pygame
|
||||
|
||||
class Fadeout(object):
|
||||
def __init__(self, game, function, duration=500):
|
||||
self.__dict__.update(locals())
|
||||
self.game.objs.append(self)
|
||||
self.img = pygame.Surface(self.game.window.get_size())
|
||||
self._start_time = pygame.time.get_ticks()
|
||||
self._middle_time = self._start_time + duration
|
||||
self._end_time = self._middle_time + duration
|
||||
self.img.set_alpha(0)
|
||||
self.img.fill((0, 0, 0))
|
||||
self._has_run = False
|
||||
|
||||
def update(self, e, t, dt):
|
||||
if t < self._middle_time:
|
||||
self.img.set_alpha(255 * (t - self._start_time) / self.duration)
|
||||
else:
|
||||
if not self._has_run:
|
||||
self.function()
|
||||
self._has_run = True
|
||||
if t < self._end_time:
|
||||
self.img.set_alpha(255 * (self.duration - (t - self._middle_time)) / self.duration)
|
||||
else:
|
||||
self.game.objs.remove(self)
|
||||
self.update = lambda *xs: None
|
||||
|
||||
def draw(self, window):
|
||||
window.blit(self.img, (0, 0))
|
||||
|
||||
class Darkness(Fadeout):
|
||||
def __init__(self, game, darkness):
|
||||
self.__dict__.update(locals())
|
||||
self.set_darkness(darkness)
|
||||
|
||||
def set_darkness(self, darkness):
|
||||
self.darkness = darkness
|
||||
self.img = pygame.Surface(self.game.window.get_size())
|
||||
self.img.set_alpha(int(darkness * 255))
|
||||
self.img.fill((0, 0, 0))
|
||||
|
||||
def update(self, *xs):
|
||||
pass
|
||||
140
arobotsconundrum/game.py
Normal file
140
arobotsconundrum/game.py
Normal file
@@ -0,0 +1,140 @@
|
||||
# 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/>.
|
||||
#
|
||||
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
|
||||
#
|
||||
# game.py
|
||||
# --------------------
|
||||
# date created : Tue Aug 7 2012
|
||||
# copyright : (C) 2012 Sakse Dalum
|
||||
# maintained by : Sakse Dalum <don_s@hongabar.org>
|
||||
|
||||
"""
|
||||
The game. Handles everything.
|
||||
"""
|
||||
|
||||
import os
|
||||
import pygame
|
||||
|
||||
import arobotsconundrum
|
||||
import jukebox
|
||||
import level
|
||||
import main_menu
|
||||
import game_menu
|
||||
import loader
|
||||
|
||||
class Game(object):
|
||||
"""Create an object to handle the game."""
|
||||
def __init__(self, window, directory, disable_music,
|
||||
running=False, speed=30, initial_goto_level=None,
|
||||
level_num=0):
|
||||
self.__dict__.update(locals())
|
||||
|
||||
self.objs = []
|
||||
|
||||
self.clock = pygame.time.Clock()
|
||||
|
||||
self.ticks = self.prev_ticks = pygame.time.get_ticks()
|
||||
|
||||
self.load()
|
||||
|
||||
def start(self):
|
||||
self.running = True
|
||||
self.run()
|
||||
|
||||
def stop(self):
|
||||
self.running = False
|
||||
|
||||
def load(self):
|
||||
graphics_dir = os.path.join(self.directory, "resources", "graphics")
|
||||
self.loader = loader.Loader(self, graphics_dir)
|
||||
self.loader.load()
|
||||
|
||||
self.level = None
|
||||
self.jukebox = jukebox.Jukebox(
|
||||
os.path.join(self.directory, "resources", "music"),
|
||||
["basshit.ogg"])
|
||||
self.jukebox.stop()
|
||||
if not self.disable_music:
|
||||
self.jukebox.play()
|
||||
|
||||
if not self.initial_goto_level:
|
||||
self.menu = main_menu.MainMenu(self, graphics_dir)
|
||||
else:
|
||||
self.goto_level(self.initial_goto_level)
|
||||
|
||||
def run(self):
|
||||
t = pygame.time.get_ticks()
|
||||
dt = 0
|
||||
while self.running:
|
||||
dt = float(pygame.time.get_ticks() - t) / 1000
|
||||
t = pygame.time.get_ticks()
|
||||
self.update(t, dt)
|
||||
self.draw()
|
||||
self.clock.tick(self.speed)
|
||||
|
||||
|
||||
def goto_level(self, level):
|
||||
if self.level in self.objs:
|
||||
self.objs.remove(self.level)
|
||||
self.level_num = level
|
||||
graphics_dir = os.path.join(self.directory, "resources", "graphics")
|
||||
|
||||
self.menu = game_menu.GameMenu(self, graphics_dir)
|
||||
|
||||
exec 'from level%d import Level%d as level' % (level, level)
|
||||
|
||||
self.level = level(self, graphics_dir)
|
||||
self.objs.insert(0, self.level)
|
||||
|
||||
def restart_level(self):
|
||||
self.goto_level(self.level_num)
|
||||
|
||||
|
||||
def update(self, t, dt):
|
||||
"""
|
||||
Update all game objects.
|
||||
"""
|
||||
# Retrieve and flush all events since last update call (this prevents
|
||||
# event "bottlenecking"/lock-ups)
|
||||
e = pygame.event.get()
|
||||
for event in e:
|
||||
# Stop the game when closing the window
|
||||
if event.type == pygame.QUIT:
|
||||
self.stop()
|
||||
|
||||
# Keep the music playing!
|
||||
if not pygame.mixer.music.get_busy() and not self.disable_music:
|
||||
self.jukebox.play()
|
||||
|
||||
# Update all objects
|
||||
for obj in self.objs[:]:
|
||||
if hasattr(obj, 'update'):
|
||||
obj.update(e, t, dt)
|
||||
|
||||
self.menu.update(e, t, dt)
|
||||
|
||||
def draw(self):
|
||||
"""
|
||||
Draw all game objects.
|
||||
"""
|
||||
self.window.fill((0, 0, 0))
|
||||
|
||||
for obj in self.objs[:]:
|
||||
if hasattr(obj, 'draw'):
|
||||
obj.draw(self.window)
|
||||
self.menu.draw(self.window)
|
||||
|
||||
pygame.display.flip()
|
||||
90
arobotsconundrum/game_menu.py
Normal file
90
arobotsconundrum/game_menu.py
Normal file
@@ -0,0 +1,90 @@
|
||||
# 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/>.
|
||||
#
|
||||
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
|
||||
#
|
||||
# game_menu.py
|
||||
# --------------------
|
||||
# date created : Tue Aug 7 2012
|
||||
# copyright : (C) 2012 Sakse Dalum
|
||||
# maintained by : Sakse Dalum <don_s@hongabar.org>
|
||||
|
||||
"""
|
||||
The in-game menu.
|
||||
"""
|
||||
|
||||
import os
|
||||
import pygame
|
||||
|
||||
class GameMenu(object):
|
||||
def __init__(self, game, img_dir, active=False, selection=0):
|
||||
self.__dict__.update(locals())
|
||||
|
||||
self.menu = ['restart_level', 'quit']
|
||||
|
||||
self.load()
|
||||
|
||||
def load(self):
|
||||
screen_size = self.game.window.get_size()
|
||||
|
||||
for item in self.menu:
|
||||
setattr(self, '%s_imgs' % item, [
|
||||
pygame.image.load(os.path.join(self.img_dir,
|
||||
'%s-%s.png' % (item, end)))
|
||||
for end in ['inactive', 'selected']])
|
||||
img_size = getattr(self, '%s_imgs' % item)[0].get_size()
|
||||
factors = (float(img_size[0]) / 1920, float(img_size[1]) / 1280)
|
||||
|
||||
setattr(self, '%s_imgs' % item, [
|
||||
pygame.transform.smoothscale(
|
||||
img,
|
||||
(int(screen_size[0]*factors[0]),
|
||||
int(screen_size[1]*factors[1])))
|
||||
for img in getattr(self, '%s_imgs' % item)])
|
||||
|
||||
def toggle_menu(self):
|
||||
self.game.level.paused = self.active = not self.active
|
||||
|
||||
def update(self, e, t, dt):
|
||||
for event in e:
|
||||
if event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_ESCAPE:
|
||||
self.toggle_menu()
|
||||
if self.active:
|
||||
if event.key in [pygame.K_SPACE, pygame.K_RETURN]:
|
||||
if self.menu[self.selection] == 'restart_level':
|
||||
#self.game.level.restart()
|
||||
self.game.restart_level()
|
||||
self.toggle_menu()
|
||||
if self.menu[self.selection] == 'quit':
|
||||
self.game.stop()
|
||||
if event.key == pygame.K_UP:
|
||||
self.selection = max(self.selection - 1, 0)
|
||||
if event.key == pygame.K_DOWN:
|
||||
self.selection = min(self.selection + 1,
|
||||
len(self.menu) - 1)
|
||||
|
||||
def draw(self, window):
|
||||
if self.active:
|
||||
screen_size = self.game.window.get_size()
|
||||
|
||||
for i in range(len(self.menu)):
|
||||
s = i == self.selection
|
||||
img = getattr(self, '%s_imgs' % self.menu[i])[s]
|
||||
window.blit(img,
|
||||
(int((screen_size[0] - img.get_size()[0]) / 2),
|
||||
int(screen_size[1] / 2)
|
||||
- (int(screen_size[1]*0.13)
|
||||
* (len(self.menu) / 2 - i))))
|
||||
45
arobotsconundrum/jukebox.py
Normal file
45
arobotsconundrum/jukebox.py
Normal file
@@ -0,0 +1,45 @@
|
||||
# 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/>.
|
||||
#
|
||||
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
|
||||
#
|
||||
# jukebox.py
|
||||
# --------------------
|
||||
# date created : Tue Aug 7 2012
|
||||
# copyright : (C) 2012 Sakse Dalum
|
||||
# maintained by : Sakse Dalum <don_s@hongabar.org>
|
||||
|
||||
"""
|
||||
The jukebox. Handles playback of background music.
|
||||
"""
|
||||
|
||||
import os
|
||||
import pygame
|
||||
|
||||
class Jukebox(object):
|
||||
"""Create an object to handle music playback."""
|
||||
def __init__(self, music_dir, music_files, volume=100, playing=True):
|
||||
self.__dict__.update(locals())
|
||||
|
||||
self.iterator = 0
|
||||
|
||||
def play(self):
|
||||
pygame.mixer.music.load(
|
||||
os.path.join(self.music_dir, self.music_files[self.iterator]))
|
||||
pygame.mixer.music.play()
|
||||
self.iterator = (self.iterator + 1) % len(self.music_files)
|
||||
|
||||
def stop(self):
|
||||
pygame.mixer.music.stop()
|
||||
103
arobotsconundrum/laser.py
Normal file
103
arobotsconundrum/laser.py
Normal file
@@ -0,0 +1,103 @@
|
||||
# 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/>.
|
||||
#
|
||||
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
|
||||
#
|
||||
# laser.py
|
||||
# --------------------
|
||||
# date created : Sun Aug 12 2012
|
||||
# copyright : (C) 2012 Niels G. W. Serup
|
||||
# maintained by : Niels G. W. Serup <ngws@metanohi.name>
|
||||
|
||||
"""
|
||||
A laser for drawing.
|
||||
"""
|
||||
|
||||
import pygame
|
||||
|
||||
import worldobject
|
||||
import arobotsconundrum.logic.lasermirror as lm
|
||||
|
||||
class Laser(worldobject.WorldObject):
|
||||
def __init__(self, level, line, first_laser=False):
|
||||
self.__dict__.update(locals())
|
||||
(self.x0, self.y0), (self.x1, self.y1) = line
|
||||
self.x0d, self.y0d, self.x1d, self.y1d \
|
||||
= self.x0 * 64, (self.y0 + 4) * 48, self.x1 * 64, (self.y1 + 4) * 48
|
||||
if self.y0d > self.y1d:
|
||||
self.y0d, self.y1d = self.y1d, self.y0d
|
||||
if self.x0d > self.x1d:
|
||||
self.x0d, self.x1d = self.x1d, self.x0d
|
||||
worldobject.WorldObject.__init__(self, level, self.x0d,
|
||||
max(self.y0d, self.y1d))
|
||||
|
||||
x0de = 31
|
||||
y0de = -48
|
||||
x1de = 31
|
||||
y1de = -48
|
||||
|
||||
if self.x0 < 0:
|
||||
x0de += 32
|
||||
if self.y0 < 0:
|
||||
y0de += 24
|
||||
if self.x1d >= self.level.size[0]:
|
||||
x1de -= 32
|
||||
if self.first_laser and self.y0 == 0 and self.y0 != self.y1:
|
||||
y0de += 6
|
||||
if self.level.playfield.get((self.x0, self.y0)) is lm.Target and self.x0 < self.x1:
|
||||
x0de += 20
|
||||
if self.level.playfield.get((self.x1, self.y1)) is lm.Target and self.x0 < self.x1:
|
||||
x1de -= 20
|
||||
self.x0d += x0de
|
||||
self.y0d += y0de
|
||||
self.x1d += x1de
|
||||
self.y1d += y1de
|
||||
|
||||
self.start_dark = 0
|
||||
|
||||
self.surf = pygame.Surface(self.level.game.window.get_size(),
|
||||
pygame.SRCALPHA)
|
||||
|
||||
def update(self, e, t, dt):
|
||||
self.start_dark = (t % 200) / 100
|
||||
worldobject.WorldObject.update(self, e, t, dt)
|
||||
|
||||
def draw(self, window):
|
||||
self.surf.fill((0, 0, 0, 0))
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
window.blit(self.surf, (0, 0))
|
||||
110
arobotsconundrum/level.py
Normal file
110
arobotsconundrum/level.py
Normal file
@@ -0,0 +1,110 @@
|
||||
# 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/>.
|
||||
#
|
||||
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
|
||||
#
|
||||
# level.py
|
||||
# --------------------
|
||||
# date created : Tue Aug 7 2012
|
||||
# copyright : (C) 2012 Sakse Dalum
|
||||
# maintained by : Sakse Dalum <don_s@hongabar.org>
|
||||
|
||||
"""
|
||||
A generic level.
|
||||
"""
|
||||
|
||||
import pygame
|
||||
import itertools
|
||||
|
||||
import player
|
||||
import fadeout
|
||||
|
||||
class Level(object):
|
||||
def __init__(self, game, graphics_dir, size=(0, 0), paused=False):
|
||||
self.__dict__.update(locals())
|
||||
|
||||
self.tiles = []
|
||||
self.objects = []
|
||||
self.bottom_objects = [] # Special tiles
|
||||
self.imgs = game.loader.imgs
|
||||
|
||||
self.reverse_imgs = (
|
||||
dict([(val, key) for (key, val)
|
||||
in self.imgs.iteritems() if not isinstance(val, list)]))
|
||||
|
||||
self.camera_x = 0
|
||||
self.camera_y = 0
|
||||
|
||||
self.player = player.Player(self, 0, 0)
|
||||
self.objects.append(self.player)
|
||||
|
||||
self.darkness = fadeout.Darkness(self.game, 0)
|
||||
|
||||
self.load()
|
||||
|
||||
def load(self):
|
||||
pass
|
||||
|
||||
def set_darkness(self, darkness):
|
||||
self.darkness.set_darkness(darkness)
|
||||
|
||||
def draw_background(self):
|
||||
self.background = pygame.Surface(self.size)
|
||||
for tile in self.tiles:
|
||||
tile.draw(self.background)
|
||||
|
||||
def restart(self):
|
||||
pass
|
||||
|
||||
def update(self, e, t, dt):
|
||||
if not self.paused:
|
||||
for obj in self.objects:
|
||||
obj.update(e, t, dt)
|
||||
if self.player.is_moving:
|
||||
obj.update_alpha()
|
||||
|
||||
screen_size = self.game.window.get_size()
|
||||
self.camera_x = max(0, min(self.size[0] - screen_size[0],
|
||||
(self.player.x - screen_size[0] / 2 + 32)))
|
||||
self.camera_y = max(0, min(self.size[1] - screen_size[1] - 48,
|
||||
(self.player.y - screen_size[1] / 2 - 24)))
|
||||
|
||||
def _positions(self):
|
||||
return ((x, y) for (y, x) in itertools.product(xrange(self.dimensions[1]),
|
||||
xrange(self.dimensions[0])))
|
||||
|
||||
def _blit_background(self, window):
|
||||
window.blit(self.background, (0 - self.camera_x, 0 - self.camera_y))
|
||||
|
||||
def _sorted_objs(self, objs=None):
|
||||
return sorted(self.objects if objs is None else objs,
|
||||
key=lambda obj: (obj.y + obj.z))
|
||||
|
||||
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 ...")
|
||||
|
||||
for obj in self._sorted_objs():
|
||||
try:
|
||||
obj.draw(window)
|
||||
except IndexError:
|
||||
print("Skipping frames ...")
|
||||
|
||||
self.darkness.draw(window)
|
||||
41
arobotsconundrum/level0.py
Normal file
41
arobotsconundrum/level0.py
Normal file
@@ -0,0 +1,41 @@
|
||||
# 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/>.
|
||||
#
|
||||
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
|
||||
#
|
||||
# level0.py
|
||||
# --------------------
|
||||
# date created : Tue Aug 7 2012
|
||||
# copyright : (C) 2012 Sakse Dalum
|
||||
# maintained by : Sakse Dalum <don_s@hongabar.org>
|
||||
|
||||
"""
|
||||
The zeroth level.
|
||||
"""
|
||||
|
||||
import pygame
|
||||
|
||||
import level
|
||||
|
||||
class Level0(level.Level):
|
||||
def update(self, e, t, dt):
|
||||
if not self.paused:
|
||||
for event in e:
|
||||
if event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_SPACE:
|
||||
self.game.goto_level(1)
|
||||
|
||||
def draw(self, window):
|
||||
window.blit(self.imgs['intro-screen'], (0, 0))
|
||||
620
arobotsconundrum/level1.py
Normal file
620
arobotsconundrum/level1.py
Normal file
@@ -0,0 +1,620 @@
|
||||
# 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/>.
|
||||
#
|
||||
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
|
||||
#
|
||||
# level1.py
|
||||
# --------------------
|
||||
# date created : Tue Aug 7 2012
|
||||
# copyright : (C) 2012 Sakse Dalum
|
||||
# maintained by : Sakse Dalum <don_s@hongabar.org>
|
||||
|
||||
"""
|
||||
The first level.
|
||||
"""
|
||||
|
||||
import os
|
||||
import pygame
|
||||
import random
|
||||
import re
|
||||
import itertools
|
||||
|
||||
import level
|
||||
import player
|
||||
import tile
|
||||
import block
|
||||
import boulder
|
||||
import lever
|
||||
import trigger
|
||||
import worldobject
|
||||
|
||||
import logic.teleportermap
|
||||
import logic.rollingstone
|
||||
import logic.colourboxes
|
||||
|
||||
class Level1(level.Level):
|
||||
def __init__(self, game, graphics_dir, paused=False):
|
||||
level.Level.__init__(self, game, graphics_dir, size=(64 * 40,
|
||||
48 * 40),
|
||||
paused=paused)
|
||||
|
||||
self.solution = range(1, 6)
|
||||
random.shuffle(self.solution)
|
||||
self.solution = self.solution[:3]
|
||||
|
||||
self.task_completions = [0, 0, 0]
|
||||
|
||||
self.set_darkness(0)
|
||||
|
||||
for i in range(self.size[0] / 64):
|
||||
for j in range(self.size[1] / 48):
|
||||
self.tiles.append(
|
||||
tile.Tile(self, i*64, j*48, self.imgs['ground1']))
|
||||
|
||||
start_pos = 7 * 64, 34 * 48
|
||||
|
||||
self.player.set_pos(*start_pos)
|
||||
self.player.set_init_pos()
|
||||
|
||||
self.objects.append(block.Block(self, start_pos[0] - 2 * 64,
|
||||
start_pos[1] + 48,
|
||||
self.imgs['spacecraft'], z=16))
|
||||
self.objects.append(block.InvisBlock(self, start_pos[0] - 2 * 64,
|
||||
start_pos[1]))
|
||||
self.objects.append(block.InvisBlock(self, start_pos[0] - 64,
|
||||
start_pos[1]))
|
||||
self.objects.append(block.InvisBlock(self, start_pos[0] - 64,
|
||||
start_pos[1] + 48))
|
||||
self.objects.append(block.InvisBlock(self, start_pos[0],
|
||||
start_pos[1] + 48))
|
||||
|
||||
self.add_tile(start_pos[0] + 4 * 64, start_pos[1] - 3 * 48,
|
||||
'indoor%d' % random.randint(1, 6), blocking=False)
|
||||
self.add_tile(start_pos[0] + 2 * 64, start_pos[1] - 7 * 48,
|
||||
'indoor%d' % random.randint(1, 6), blocking=False)
|
||||
|
||||
for i in range(self.size[0] / 64):
|
||||
if not i % 3:
|
||||
self.objects.append(block.Block(self, i * 64,
|
||||
48 * 3,
|
||||
self.imgs['wall_outside'],
|
||||
width=3))
|
||||
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))
|
||||
|
||||
|
||||
|
||||
### Task 1: Teleporters
|
||||
|
||||
task5_size = 8, 5
|
||||
task5_pos = (64 * 12, 48 * 19)
|
||||
|
||||
tmap = logic.teleportermap.generate_teleporter_map3(*task5_size)
|
||||
|
||||
for x in range(task5_size[0]):
|
||||
for y in range(task5_size[1]):
|
||||
# if not (x, y) in tmap:
|
||||
# continue
|
||||
self.add_tile(64 * (x - 6) + task5_pos[0],
|
||||
48 * (y - 4) + task5_pos[1],
|
||||
'indoor%d' % random.randint(1, 6), blocking=False)
|
||||
|
||||
for x, y in tmap:
|
||||
self.objects.append(
|
||||
trigger.Trigger(self,
|
||||
task5_pos[0] - 64 * (x - 1),
|
||||
task5_pos[1] - 48 * y,
|
||||
[lambda x: self.player.set_pos(
|
||||
task5_pos[0] + 2 * 64,
|
||||
(task5_pos[1]
|
||||
- random.randint(0, task5_size[1] - 1) * 48))],
|
||||
self.imgs['hole'],
|
||||
[self.player],
|
||||
visible=False,
|
||||
no_stop=True))
|
||||
|
||||
for i in range(task5_size[0] + 1):
|
||||
self.add_tile(task5_pos[0] - 64 * i,
|
||||
task5_pos[1] + 48,
|
||||
'moat_horizontal')
|
||||
self.add_tile(task5_pos[0] - 64 * i,
|
||||
task5_pos[1] - task5_size[1] * 48,
|
||||
'moat_horizontal')
|
||||
self.add_tile(task5_pos[0] + 64,
|
||||
task5_pos[1] + 48,
|
||||
'moat_end_horizontal_flip')
|
||||
# self.add_tile(task5_pos[0] + 64,
|
||||
# task5_pos[1] - task5_size[1] * 48,
|
||||
# 'moat_end_horizontal_flip')
|
||||
self.add_tile(task5_pos[0] - 64 * (task5_size[0] + 1),
|
||||
task5_pos[1] + 48,
|
||||
'moat_corner_south')
|
||||
self.add_tile(task5_pos[0] - 64 * (task5_size[0] + 1),
|
||||
task5_pos[1] - task5_size[1] * 48,
|
||||
'moat_corner_north')
|
||||
for i in range(task5_size[0]):
|
||||
self.add_tile(task5_pos[0] - 64 * (task5_size[0] + 1),
|
||||
task5_pos[1] - 48 * i,
|
||||
'moat_vertical')
|
||||
|
||||
self.objects.append(
|
||||
lever.Lever(self,
|
||||
task5_pos[0] - 64 * (task5_size[0]),
|
||||
task5_pos[1] - (task5_size[1] / 2) * 48,
|
||||
[lambda *x: self.complete_task(1)]))
|
||||
|
||||
### Task 2: Rolling stone
|
||||
|
||||
task2_size = 15, 10
|
||||
|
||||
task2_pos = (64 * 20, 48 * 20)
|
||||
|
||||
playfield, nsteps, directions = (
|
||||
logic.rollingstone.generate_simple_unsolved_solvable_extra(
|
||||
task2_size[0], task2_size[1], 5, 50))
|
||||
|
||||
n = 0
|
||||
c = len(playfield) / len(directions)
|
||||
ns = [k * c for k in range(len(directions))]
|
||||
arrow_blocks = []
|
||||
for i, j in playfield:
|
||||
if n in ns:
|
||||
arrow_blocks.append(
|
||||
block.ArrowBlock(self,
|
||||
task2_pos[0] + 64 * i,
|
||||
task2_pos[1] + 48 * j,
|
||||
directions[n / c].next_pos((0, 0))))
|
||||
else:
|
||||
self.objects.append(
|
||||
block.Block(self,
|
||||
task2_pos[0] + 64 * i,
|
||||
task2_pos[1] + 48 * j,
|
||||
self.imgs['block1'],
|
||||
movable=True)
|
||||
if (random.randint(0, 2) or (i, j) == (4, 0)) else
|
||||
block.Block(self,
|
||||
task2_pos[0] + 64 * i,
|
||||
task2_pos[1] + 48 * j,
|
||||
self.imgs['block3'],
|
||||
movable=False))
|
||||
n += 1
|
||||
|
||||
# arrow_blocks = []
|
||||
# n = 0
|
||||
# for i in directions:
|
||||
# arrow_blocks.append(
|
||||
# block.ArrowBlock(self,
|
||||
# task2_pos[0] + 64 * (task2_size[0] - n),
|
||||
# task2_pos[1] + 48 * (task2_size[1] + 2),
|
||||
# i.next_pos((0, 0))))
|
||||
# n += 1
|
||||
|
||||
self.objects.extend(arrow_blocks)
|
||||
self.objects.append(lever.Lever(self,
|
||||
task2_pos[0] + 64 * 3,
|
||||
task2_pos[1] - 48 * 2,
|
||||
[arrow_block.activate
|
||||
for arrow_block in arrow_blocks],
|
||||
toggling=True,
|
||||
anim='lever_updown'))
|
||||
|
||||
b = boulder.Boulder(self, task2_pos[0], task2_pos[1] - 48,
|
||||
direction=(0, 1))
|
||||
self.objects.append(b)
|
||||
|
||||
self.objects.append(lever.Lever(self,
|
||||
task2_pos[0] + 64 * 2,
|
||||
task2_pos[1] - 48 * 2,
|
||||
[b.activate],
|
||||
anim='lever_updown'))
|
||||
# Moat sides
|
||||
for i in range(-1, task2_size[1]):
|
||||
self.add_tile(task2_pos[0] - 64,
|
||||
task2_pos[1] + 48 * i,
|
||||
'moat_vertical')
|
||||
for i in range(task2_size[1] - 2):
|
||||
self.add_tile(task2_pos[0] + 64 * task2_size[0],
|
||||
task2_pos[1] + 48 * i,
|
||||
'moat_vertical')
|
||||
for i in range(6, task2_size[0]):
|
||||
self.add_tile(task2_pos[0] + 64 * i,
|
||||
task2_pos[1] - 48,
|
||||
'moat_horizontal')
|
||||
for i in range(task2_size[0] - 2):
|
||||
self.add_tile(task2_pos[0] + 64 * i,
|
||||
task2_pos[1] + 48 * task2_size[1],
|
||||
'moat_horizontal')
|
||||
# Corners
|
||||
self.add_tile(task2_pos[0] + 64 * task2_size[0],
|
||||
task2_pos[1] - 48,
|
||||
'moat_corner_north_flip')
|
||||
self.add_tile(task2_pos[0] - 64,
|
||||
task2_pos[1] + 48 * task2_size[1],
|
||||
'moat_corner_south')
|
||||
|
||||
# Start
|
||||
self.add_tile(task2_pos[0] + 64 * 2,
|
||||
task2_pos[1] - 48,
|
||||
'moat_horizontal')
|
||||
self.add_tile(task2_pos[0] + 64 * 3,
|
||||
task2_pos[1] - 48,
|
||||
'moat_end_horizontal_flip')
|
||||
self.add_tile(task2_pos[0] + 64 * 5,
|
||||
task2_pos[1] - 48,
|
||||
'moat_end_horizontal')
|
||||
self.add_tile(task2_pos[0] - 64,
|
||||
task2_pos[1] - 48 * 2,
|
||||
'moat_corner_north')
|
||||
self.add_tile(task2_pos[0],
|
||||
task2_pos[1] - 48 * 2,
|
||||
'moat_horizontal')
|
||||
self.add_tile(task2_pos[0] + 64,
|
||||
task2_pos[1] - 48 * 2,
|
||||
'moat_corner_north_flip')
|
||||
self.add_tile(task2_pos[0] + 64,
|
||||
task2_pos[1] - 48,
|
||||
'moat_corner_south')
|
||||
|
||||
# End
|
||||
self.add_tile(task2_pos[0] + 64 * task2_size[0],
|
||||
task2_pos[1] + 48 * (task2_size[1] - 2),
|
||||
'moat_corner_south')
|
||||
self.add_tile(task2_pos[0] + 64 * (task2_size[0] + 1),
|
||||
task2_pos[1] + 48 * (task2_size[1] - 2),
|
||||
'moat_corner_north_flip')
|
||||
self.add_tile(task2_pos[0] + 64 * (task2_size[0] + 1),
|
||||
task2_pos[1] + 48 * (task2_size[1] - 1),
|
||||
'moat_vertical')
|
||||
self.add_tile(task2_pos[0] + 64 * (task2_size[0] + 1),
|
||||
task2_pos[1] + 48 * (task2_size[1]),
|
||||
'moat_corner_south_flip')
|
||||
self.add_tile(task2_pos[0] + 64 * (task2_size[0]),
|
||||
task2_pos[1] + 48 * (task2_size[1]),
|
||||
'moat_end_horizontal')
|
||||
self.add_tile(task2_pos[0] + 64 * (task2_size[0] - 2),
|
||||
task2_pos[1] + 48 * (task2_size[1]),
|
||||
'moat_end_horizontal_flip')
|
||||
|
||||
self.objects.append(
|
||||
trigger.Trigger(self, task2_pos[0] + 64 * (task2_size[0]),
|
||||
task2_pos[1] + 48 * (task2_size[1] - 1),
|
||||
[self.complete_task, b.fall],
|
||||
self.imgs['hole'], [b],
|
||||
signal=[0, 2],
|
||||
toggling=True))
|
||||
|
||||
|
||||
### Task 3: Inverted bits
|
||||
|
||||
task4_pos = (64 * 26, 48 * 18)
|
||||
|
||||
b = boulder.Boulder(self, task4_pos[0] - 64, task4_pos[1] - 48 * 3,
|
||||
direction=(1, 0))
|
||||
self.objects.append(b)
|
||||
|
||||
self.objects.append(lever.Lever(self,
|
||||
task4_pos[0] - 64 * 3,
|
||||
task4_pos[1] - 48 * 3,
|
||||
[b.activate]))
|
||||
|
||||
|
||||
risingblocks = [block.RisingBlock(self, task4_pos[0] + 64 * i,
|
||||
task4_pos[1] - 48 * 3,
|
||||
is_up = False)
|
||||
for i in range(8)]
|
||||
|
||||
for i in range(8):
|
||||
r = range(8)
|
||||
r.remove(i)
|
||||
self.objects.append(risingblocks[i])
|
||||
n = random.choice(r)
|
||||
self.objects.append(lever.Lever(self,
|
||||
task4_pos[0] + 64 * i,
|
||||
task4_pos[1] - 48 * 2,
|
||||
[risingblocks[i].activate,
|
||||
risingblocks[n].activate],
|
||||
anim='lever_updown',
|
||||
toggling=True,
|
||||
signal=[0, 1]))
|
||||
for k in range(random.randint(0, 1)):
|
||||
self.objects[-1].use(self)
|
||||
self.objects[-1].set_init_pos()
|
||||
risingblocks[i].set_init_pos()
|
||||
risingblocks[n].set_init_pos()
|
||||
n = random.choice(r)
|
||||
self.objects.append(lever.Lever(self,
|
||||
task4_pos[0] + 64 * i,
|
||||
task4_pos[1],
|
||||
[risingblocks[i].activate,
|
||||
risingblocks[n].activate],
|
||||
anim='lever_updown',
|
||||
toggling=True,
|
||||
signal=[2, 3]))
|
||||
for k in range(random.randint(0, 1)):
|
||||
self.objects[-1].use(self)
|
||||
self.objects[-1].set_init_pos()
|
||||
risingblocks[i].set_init_pos()
|
||||
risingblocks[n].set_init_pos()
|
||||
|
||||
self.objects.append(trigger.Trigger(self, task4_pos[0] + 64 * 8,
|
||||
task4_pos[1] - 48 * 3,
|
||||
[self.complete_task, b.fall],
|
||||
self.imgs['hole'], [b],
|
||||
signal=[0, 3],
|
||||
toggling=True))
|
||||
|
||||
# Moat
|
||||
self.add_tile(task4_pos[0] - 64 * 2, task4_pos[1] - 48 * 4,
|
||||
'moat_corner_north')
|
||||
self.add_tile(task4_pos[0] - 64 * 2, task4_pos[1] - 48 * 3,
|
||||
'moat_vertical')
|
||||
self.add_tile(task4_pos[0] - 64 * 2, task4_pos[1] - 48 * 2,
|
||||
'moat_corner_south')
|
||||
self.add_tile(task4_pos[0] - 64, task4_pos[1] - 48 * 2,
|
||||
'moat_end_horizontal_flip')
|
||||
for i in range(10):
|
||||
self.add_tile(task4_pos[0] + 64 * (i - 1), task4_pos[1] - 48 * 4,
|
||||
'moat_horizontal')
|
||||
self.add_tile(task4_pos[0] + 64 * 9, task4_pos[1] - 48 * 4,
|
||||
'moat_corner_north_flip')
|
||||
self.add_tile(task4_pos[0] + 64 * 9, task4_pos[1] - 48 * 3,
|
||||
'moat_vertical')
|
||||
self.add_tile(task4_pos[0] + 64 * 9, task4_pos[1] - 48 * 2,
|
||||
'moat_corner_south_flip')
|
||||
self.add_tile(task4_pos[0] + 64 * 8, task4_pos[1] - 48 * 2,
|
||||
'moat_end_horizontal')
|
||||
|
||||
|
||||
### Task 4: Colour blocks
|
||||
|
||||
task3_pos = (64 * 15, 48 * 20)
|
||||
|
||||
# Abstract "boxes", actually colour fields
|
||||
boxes = logic.colourboxes.generate_colour_boxes(1, 3)
|
||||
boxes += boxes
|
||||
boxes += [logic.colourboxes.generate_random_box(1) for _ in range(3)]
|
||||
random.shuffle(boxes)
|
||||
|
||||
pos_colour = {}
|
||||
for box, (x, y) in zip(boxes, itertools.product(range(3), range(3))):
|
||||
# self.tiles.append(tile.Tile(self, x * 64 + task3_pos[0],
|
||||
# y * 48 + task3_pos[1],
|
||||
# self.imgs['ground1']))
|
||||
pos_colour[(x, y)] = box
|
||||
self.add_tile(task3_pos[0] + 64 * x, task3_pos[1] + 48 * (y + 1),
|
||||
'indoor%d' % random.randint(1, 6), blocking=False)
|
||||
|
||||
action_blocks = [block.ActionBlock(self, 64 * i + task3_pos[0],
|
||||
task3_pos[1], movable=True)
|
||||
for i in range(3)]
|
||||
self.objects.extend(action_blocks)
|
||||
|
||||
wells = [block.ColorWell(self, task3_pos[0] + 64,
|
||||
task3_pos[1] + 48 * 5)]
|
||||
self.objects.extend(wells)
|
||||
|
||||
def update_wells(block):
|
||||
cur_boxes = []
|
||||
for block in action_blocks:
|
||||
box = pos_colour.get(((block.x - task3_pos[0]) / 64,
|
||||
(block.y - task3_pos[1] - 48) / 48))
|
||||
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 i in range(len(wells)):
|
||||
wells[i].set_colour(*well_colours[i])
|
||||
|
||||
for b in action_blocks:
|
||||
b.action = update_wells
|
||||
|
||||
self.objects.append(
|
||||
lever.Lever(self,
|
||||
task3_pos[0] + 64,
|
||||
task3_pos[1] + 48 * 4,
|
||||
[lambda *x: (self.complete_task(4)
|
||||
if (len([w for w in wells
|
||||
if (w.well_colour
|
||||
== (255, 255, 255))
|
||||
])
|
||||
== len(wells))
|
||||
else lambda: None)]))
|
||||
|
||||
### Task 5: Rising columns
|
||||
task1_pos = (64 * 15, 48 * 13)
|
||||
|
||||
ws = []
|
||||
|
||||
for i in range(5):
|
||||
w1 = Wheel(self, task1_pos[0] + 64 * i, task1_pos[1] - 48 * 2)
|
||||
w2 = Wheel(self, task1_pos[0] + 64 * i, task1_pos[1],
|
||||
immitate=w1)
|
||||
self.objects.extend([w1, w2])
|
||||
self.objects.append(lever.Lever(self,
|
||||
task1_pos[0] + 64 * i,
|
||||
task1_pos[1] + 48 * 1,
|
||||
[w2.activate],
|
||||
anim='lever_updown'))
|
||||
ws.append(w2)
|
||||
self.add_tile(task1_pos[0] + 64 * i,
|
||||
task1_pos[1] - 48 * 3,
|
||||
'moat_horizontal')
|
||||
|
||||
self.objects.append(
|
||||
lever.Lever(self,
|
||||
task1_pos[0] + 64 * 5,
|
||||
task1_pos[1] + 48 * 2,
|
||||
[lambda *xs: self.complete_task(5)
|
||||
if len(ws) == len([w for w in ws if w.on])
|
||||
else lambda: None]))
|
||||
|
||||
self.add_tile(task1_pos[0] - 64,
|
||||
task1_pos[1] - 48 * 3,
|
||||
'moat_corner_north')
|
||||
self.add_tile(task1_pos[0] + 64 * 5,
|
||||
task1_pos[1] - 48 * 3,
|
||||
'moat_corner_north_flip')
|
||||
for i in range(3):
|
||||
self.add_tile(task1_pos[0] - 64,
|
||||
task1_pos[1] + 48 * (i - 2),
|
||||
'moat_vertical')
|
||||
self.add_tile(task1_pos[0] + 64 * 5,
|
||||
task1_pos[1] + 48 * (i - 2),
|
||||
'moat_vertical')
|
||||
self.add_tile(task1_pos[0] - 64,
|
||||
task1_pos[1] + 48,
|
||||
'moat_corner_south_flip')
|
||||
self.add_tile(task1_pos[0] + 64 * 5,
|
||||
task1_pos[1] + 48,
|
||||
'moat_corner_south')
|
||||
self.add_tile(task1_pos[0] - 64 * 2,
|
||||
task1_pos[1] + 48,
|
||||
'moat_horizontal')
|
||||
self.add_tile(task1_pos[0] + 64 * 6,
|
||||
task1_pos[1] + 48,
|
||||
'moat_end_horizontal_flip')
|
||||
|
||||
### Final: The door
|
||||
|
||||
door_x = 22
|
||||
|
||||
for i in range(12):
|
||||
self.add_tile(door_x * 64,
|
||||
48 * (5 + i),
|
||||
'indoor%d' % random.randint(1, 6), blocking=False)
|
||||
for i in range(7):
|
||||
self.add_tile((door_x - i - 1) * 64,
|
||||
48 * (5 + 11),
|
||||
'indoor%d' % random.randint(1, 6), blocking=False)
|
||||
|
||||
|
||||
door = block.Door(self, 64 * door_x, 48 * 4)
|
||||
self.objects.append(door)
|
||||
self.objects.append(
|
||||
lever.Lever(self, 64 * (door_x + 3), 48 * 4,
|
||||
[lambda x: door.activate(x)
|
||||
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]))
|
||||
|
||||
if random.randint(0, 1):
|
||||
for i in range(3):
|
||||
self.objects.append(
|
||||
CompletionBlock(self, 64 * (door_x - 5 + i), 48 * 4,
|
||||
self.solution[i], i + 1))
|
||||
else:
|
||||
for i in range(3):
|
||||
self.objects.append(
|
||||
CompletionBlock(self, 64 * (door_x - 3 - i), 48 * 4,
|
||||
self.solution[i], i + 1))
|
||||
|
||||
# DRAW THE BACKGROUND
|
||||
|
||||
self.draw_background()
|
||||
|
||||
def add_tile(self, x, y, img, blocking=True):
|
||||
self.tiles.append(tile.Tile(self, x, y, self.imgs[img]))
|
||||
if blocking:
|
||||
self.objects.append(block.InvisBlock(self, x, y))
|
||||
|
||||
def complete_task(self, task):
|
||||
if task == 0:
|
||||
return
|
||||
self.task_completions.append(task)
|
||||
if len(self.task_completions) > 3:
|
||||
self.task_completions = self.task_completions[-3:]
|
||||
|
||||
def restart(self):
|
||||
for obj in self.objects:
|
||||
obj.reset_pos()
|
||||
|
||||
class CompletionBlock(block.Block):
|
||||
def __init__(self, level, x, y, task, number):
|
||||
self.__dict__.update(locals())
|
||||
block.Block.__init__(self, level, x, y, blocking=False)
|
||||
|
||||
def update(self, e, t, dt):
|
||||
self.img = self.level.imgs['symbol%02d-0018' % (self.task + 12)]
|
||||
for t in range(1, 4):
|
||||
if (self.level.task_completions[-t:] == self.level.solution[:t]
|
||||
and t >= self.number):
|
||||
self.img = self.level.imgs['symbol%02d-0019' % (self.task + 12)]
|
||||
break
|
||||
|
||||
class Wheel(block.Block):
|
||||
def __init__(self, level, x, y, immitate=None):
|
||||
self.__dict__.update(locals())
|
||||
worldobject.WorldObject.__init__(self, level, x, y)
|
||||
|
||||
self.frame = 0
|
||||
self.anim_speed = 15
|
||||
self.nsettings = 5
|
||||
self.setting = random.randint(0, self.nsettings - 1)
|
||||
if self.immitate:
|
||||
self.on = self.setting == self.immitate.setting
|
||||
|
||||
self.init_setting = self.setting
|
||||
|
||||
self.anim = 'elevating_column'
|
||||
|
||||
self.anim_direction = 1
|
||||
|
||||
def set_init_pos(self):
|
||||
worldobject.WorldObject.set_init_pos(self)
|
||||
self.init_setting = self.setting
|
||||
|
||||
def reset_pos(self):
|
||||
worldobject.WorldObject.reset_pos(self)
|
||||
self.setting = self.init_setting
|
||||
|
||||
def set_direction(self, setting):
|
||||
self.anim_direction = -1 if setting else 1
|
||||
|
||||
def activate(self, setting):
|
||||
self.setting = (self.setting + 1 * self.anim_direction) % self.nsettings
|
||||
self.on = self.setting == self.immitate.setting
|
||||
|
||||
def update(self, e, t, dt):
|
||||
# Update the animation
|
||||
l = len(self.level.imgs[self.anim])
|
||||
if not (int(self.frame) == self.setting * (l - 1)
|
||||
/ (self.nsettings - 1)):
|
||||
self.frame = ((self.frame + self.anim_speed * dt) % l
|
||||
if (self.setting > 0 and self.anim_direction > 0)
|
||||
or (self.setting == self.nsettings - 1
|
||||
and self.anim_direction < 0) else
|
||||
(self.frame - self.anim_speed * dt) % l)
|
||||
|
||||
worldobject.WorldObject.update(self, e, t, dt)
|
||||
|
||||
def draw(self, window):
|
||||
self.img = self.level.imgs[self.anim][int(self.frame)]
|
||||
if self.visible:
|
||||
window.blit(self.img, (self.x - 32 - self.level.camera_x,
|
||||
self.y - self.img.get_size()[1] + 24
|
||||
- self.level.camera_y))
|
||||
54
arobotsconundrum/level2.py
Normal file
54
arobotsconundrum/level2.py
Normal file
@@ -0,0 +1,54 @@
|
||||
import os
|
||||
import pygame
|
||||
import random
|
||||
import re
|
||||
|
||||
import level
|
||||
import player
|
||||
import tile
|
||||
import block
|
||||
import boulder
|
||||
import lever
|
||||
import level_bonus
|
||||
import fadeout
|
||||
|
||||
|
||||
class Level2(level.Level):
|
||||
def __init__(self, game, graphics_dir, paused=False):
|
||||
level.Level.__init__(self, game, graphics_dir, size=(64*5, 48*5),
|
||||
paused=paused)
|
||||
|
||||
self.dimensions = 5, 5
|
||||
|
||||
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.draw_background()
|
||||
|
||||
bonus = level_bonus.Level(self.game, self.graphics_dir)
|
||||
|
||||
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_init_pos()
|
||||
|
||||
|
||||
def restart(self):
|
||||
for obj in self.objects:
|
||||
obj.reset_pos()
|
||||
173
arobotsconundrum/level3.py
Normal file
173
arobotsconundrum/level3.py
Normal file
@@ -0,0 +1,173 @@
|
||||
#!/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/>.
|
||||
#
|
||||
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
|
||||
#
|
||||
# level3.py
|
||||
# --------------------
|
||||
# date created : Wed Aug 8 2012
|
||||
# copyright : (C) 2012 Niels G. W. Serup
|
||||
# maintained by : Niels G. W. Serup <ngws@metanohi.name>
|
||||
|
||||
"""
|
||||
The third 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 lever
|
||||
import fadeout
|
||||
|
||||
import logic.colourboxes
|
||||
|
||||
|
||||
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)]))
|
||||
|
||||
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.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))
|
||||
|
||||
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.bottom_objects.append(worldobject.WithBackground(
|
||||
self, self.imgs['elevator_top'], 64 * (self.task_start[0] + 3), 48 * (self.task_start[1] + 10)))
|
||||
self.elevator = worldobject.WithBackground(
|
||||
self, self.imgs['elevator'], 64 * (self.task_start[0] + 3), 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] + 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()
|
||||
|
||||
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)
|
||||
|
||||
def restart(self):
|
||||
for obj in self.objects:
|
||||
obj.reset_pos()
|
||||
289
arobotsconundrum/level4.py
Normal file
289
arobotsconundrum/level4.py
Normal file
@@ -0,0 +1,289 @@
|
||||
# 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/>.
|
||||
#
|
||||
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
|
||||
#
|
||||
# level1.py
|
||||
# --------------------
|
||||
# date created : Fri Aug 10 2012
|
||||
# copyright : (C) 2012 Niels G. W. Serup
|
||||
# maintained by : Niels G. W. Serup <ngws@metanohi.name>
|
||||
|
||||
"""
|
||||
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 * 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()
|
||||
|
||||
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
|
||||
92
arobotsconundrum/level_bonus.py
Normal file
92
arobotsconundrum/level_bonus.py
Normal file
@@ -0,0 +1,92 @@
|
||||
# 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/>.
|
||||
#
|
||||
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
|
||||
#
|
||||
# level_bonus.py
|
||||
# --------------------
|
||||
# date created : Thu Aug 9 2012
|
||||
# copyright : (C) 2012 Niels G. W. Serup
|
||||
# maintained by : Niels G. W. Serup <ngws@metanohi.name>
|
||||
|
||||
"""
|
||||
Fun bonus level.
|
||||
"""
|
||||
|
||||
import os
|
||||
import pygame
|
||||
import random
|
||||
import re
|
||||
import itertools
|
||||
|
||||
import misc
|
||||
import level
|
||||
import player
|
||||
import tile
|
||||
import block
|
||||
import boulder
|
||||
import lever
|
||||
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),
|
||||
paused=paused)
|
||||
|
||||
self.dimensions = 20, 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)]))
|
||||
|
||||
self.draw_background()
|
||||
|
||||
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():
|
||||
self._update = self.update
|
||||
self.update = lambda *args: None
|
||||
def g():
|
||||
self.update = self._update
|
||||
self.exit()
|
||||
fadeout.Fadeout(self.game, g)
|
||||
|
||||
self.objects.append(
|
||||
lever.Lever(
|
||||
self, 64, 48,
|
||||
[lambda setting: f()],
|
||||
toggling=False,
|
||||
anim='lever_updown'))
|
||||
|
||||
self.player.set_pos(64 * 1, 48 * 2)
|
||||
self.player.set_init_pos()
|
||||
|
||||
def enter(self, root_level):
|
||||
self.__dict__.update(locals())
|
||||
self.game.objs.remove(root_level)
|
||||
self.game.objs.insert(0, self)
|
||||
self.game.level = self
|
||||
|
||||
def exit(self):
|
||||
self.game.objs.remove(self)
|
||||
self.game.objs.insert(0, self.root_level)
|
||||
|
||||
def restart(self):
|
||||
for obj in self.objects:
|
||||
obj.reset_pos()
|
||||
95
arobotsconundrum/lever.py
Normal file
95
arobotsconundrum/lever.py
Normal file
@@ -0,0 +1,95 @@
|
||||
# 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/>.
|
||||
#
|
||||
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
|
||||
#
|
||||
# lever.py
|
||||
# --------------------
|
||||
# date created : Wed Aug 8 2012
|
||||
# copyright : (C) 2012 Sakse Dalum
|
||||
# maintained by : Sakse Dalum <don_s@hongabar.org>
|
||||
|
||||
"""
|
||||
A generic lever.
|
||||
"""
|
||||
|
||||
import pygame
|
||||
|
||||
import worldobject
|
||||
|
||||
class Lever(worldobject.WorldObject):
|
||||
def __init__(self, level, x, y, links,
|
||||
anim='lever_leftright', toggling=False, signal=[0, 1],
|
||||
setting=False):
|
||||
self.__dict__.update(locals())
|
||||
worldobject.WorldObject.__init__(self, level, x, y)
|
||||
|
||||
self.init_setting = setting
|
||||
|
||||
self.at_rest = True
|
||||
|
||||
self.send_signal = False
|
||||
|
||||
self.frame = 0
|
||||
self.anim_speed = 15
|
||||
|
||||
def set_init_pos(self):
|
||||
worldobject.WorldObject.set_init_pos(self)
|
||||
self.init_setting = self.setting
|
||||
|
||||
def reset_pos(self):
|
||||
worldobject.WorldObject.reset_pos(self)
|
||||
self.setting = self.init_setting
|
||||
|
||||
def use(self, obj):
|
||||
self.setting = not self.setting
|
||||
self.at_rest = False
|
||||
self.send_signal = True
|
||||
|
||||
def update(self, e, t, dt):
|
||||
# Update the animation
|
||||
if not self.setting:
|
||||
self.frame = min(self.frame + self.anim_speed * dt,
|
||||
len(self.level.imgs[self.anim]) - 1)
|
||||
else:
|
||||
self.frame = max(self.frame - self.anim_speed * dt,
|
||||
0)
|
||||
|
||||
if not self.toggling:
|
||||
if (self.frame - self.anim_speed * dt <= 0):
|
||||
self.setting = 0
|
||||
self.at_rest = self.frame == len(self.level.imgs[self.anim]) - 1
|
||||
else:
|
||||
self.at_rest = self.frame in [len(self.level.imgs[self.anim]) - 1,
|
||||
0]
|
||||
|
||||
if (((self.frame <= int(len(self.level.imgs[self.anim]) / 3)
|
||||
and not self.toggling)
|
||||
or (self.frame <= int(len(self.level.imgs[self.anim]) / 3)
|
||||
and self.setting and self.toggling)
|
||||
or (self.frame >= int(2 * len(self.level.imgs[self.anim]) / 3)
|
||||
and not self.setting and self.toggling))
|
||||
and self.send_signal):
|
||||
for link in self.links:
|
||||
link(self.signal[self.setting])
|
||||
self.send_signal = False
|
||||
|
||||
worldobject.WorldObject.update(self, e, t, dt)
|
||||
|
||||
def draw(self, window):
|
||||
self.img = self.level.imgs[self.anim][int(self.frame)]
|
||||
window.blit(self.img, (self.x - 32 - self.level.camera_x,
|
||||
self.y - self.img.get_size()[1] + 24
|
||||
- self.level.camera_y))
|
||||
237
arobotsconundrum/loader.py
Normal file
237
arobotsconundrum/loader.py
Normal file
@@ -0,0 +1,237 @@
|
||||
# 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/>.
|
||||
#
|
||||
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
|
||||
#
|
||||
# loader.py
|
||||
# --------------------
|
||||
# date created : Fri Aug 10 2012
|
||||
# copyright : (C) 2012 Sakse Dalum
|
||||
# maintained by : Sakse Dalum <don_s@hongabar.org>
|
||||
|
||||
"""
|
||||
A loader object.
|
||||
"""
|
||||
|
||||
import pygame
|
||||
import os
|
||||
import re
|
||||
|
||||
class Loader(object):
|
||||
def __init__(self, game, directory):
|
||||
self.__dict__.update(locals())
|
||||
self.imgs = {}
|
||||
|
||||
def load(self):
|
||||
"""Load all game resources."""
|
||||
l = ['ground1', 'ground2']
|
||||
for o in l:
|
||||
self.imgs[o] = pygame.image.load(os.path.join(
|
||||
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)] = (
|
||||
pygame.image.load(os.path.join(
|
||||
self.directory, 'symbols', 'blocks',
|
||||
'block%02d-%04d.png' % (o, i))))
|
||||
for o in range(13, 18):
|
||||
for i in range(16, 20):
|
||||
self.imgs['symbol%02d-%04d' % (o, i)] = (
|
||||
pygame.image.load(os.path.join(
|
||||
self.directory, 'symbols', 'blocks',
|
||||
'block%02d-%04d.png' % (o, i))))
|
||||
|
||||
for o in range(1, 7):
|
||||
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',
|
||||
'../lasersource_up', '../lasersource_down', '../lasersource_right',
|
||||
'../lasertarget_glow']
|
||||
for o in l:
|
||||
self.imgs[os.path.basename(o)] = pygame.image.load(os.path.join(
|
||||
self.directory, 'blocks', '%s.png' % o))
|
||||
self.imgs['lasersource_left'] = pygame.transform.flip(
|
||||
self.imgs['lasersource_right'], 1, 0)
|
||||
|
||||
l = ['hole', 'well', 'wall', 'wall_outside', 'intro-screen',
|
||||
'spacecraft']
|
||||
for o in l:
|
||||
self.imgs[o] = pygame.image.load(os.path.join(
|
||||
self.directory, '%s.png' % o))
|
||||
|
||||
|
||||
# Special treatment
|
||||
screen_size = self.game.window.get_size()
|
||||
img_size = self.imgs['intro-screen'].get_size()
|
||||
factors = (float(img_size[0]) / 1920, float(img_size[1]) / 1440)
|
||||
|
||||
self.imgs['intro-screen'] = pygame.transform.smoothscale(
|
||||
self.imgs['intro-screen'],
|
||||
(int(screen_size[0]*factors[0]),
|
||||
int(screen_size[1]*factors[1])))
|
||||
|
||||
### Moat
|
||||
l = ['moat_corner_north',
|
||||
'moat_corner_south',
|
||||
'moat_corner_north_flip',
|
||||
'moat_corner_south_flip',
|
||||
'moat_end_horizontal',
|
||||
'moat_horizontal',
|
||||
'moat_vertical']
|
||||
for o in l:
|
||||
self.imgs[o] = pygame.image.load(os.path.join(
|
||||
self.directory, 'moat', '%s.png' % o))
|
||||
|
||||
# Special treatment
|
||||
self.imgs['moat_end_horizontal_flip'] = pygame.transform.flip(
|
||||
self.imgs['moat_end_horizontal'], 1, 0)
|
||||
|
||||
### Elevator
|
||||
for n, p in (('elevator', 'elevator'),
|
||||
('elevator_bottom', 'bottom_corners'),
|
||||
('elevator_top', 'top_corners')):
|
||||
self.imgs[n] = pygame.image.load(os.path.join(
|
||||
self.directory, 'elevator', p + '.png'))
|
||||
|
||||
# Load animations
|
||||
for anim, directory in (
|
||||
[('boulder_up', os.path.join('boulder', 'up')),
|
||||
('boulder_down', os.path.join('boulder', 'down')),
|
||||
('boulder_right', os.path.join('boulder', 'right')),
|
||||
('boulder_left', os.path.join('boulder', 'right')),
|
||||
('boulder_falling', os.path.join('boulder_fall')),
|
||||
|
||||
('lever_updown', os.path.join('lever', 'down-up')),
|
||||
('lever_leftright', os.path.join('lever', 'left-right')),
|
||||
|
||||
('arrow_up', os.path.join('matt', 'up')),
|
||||
('arrow_right', os.path.join('matt', 'right')),
|
||||
('arrow_down', os.path.join('matt', 'down')),
|
||||
('arrow_left', os.path.join('matt', 'right')),
|
||||
|
||||
('stairs', 'stairs'),
|
||||
('elevating_column', 'elevating_column'),
|
||||
|
||||
('mirror', 'mirror'),
|
||||
|
||||
('door', 'door')]
|
||||
):
|
||||
|
||||
self.imgs[anim] = []
|
||||
|
||||
# Find all image files for the given animation
|
||||
anim_files = []
|
||||
for root, dirs, files in os.walk(os.path.join(
|
||||
self.directory, directory)):
|
||||
for f in files:
|
||||
if re.match(r"^.*\.(png)$", '/'.join([root, f])):
|
||||
anim_files.append('/'.join([root, f]))
|
||||
|
||||
# Sort and load the files
|
||||
for f in sorted(anim_files):
|
||||
img = pygame.image.load(f)
|
||||
|
||||
# Special treatment:
|
||||
if anim in ('arrow_left',):
|
||||
img = pygame.transform.flip(img, 1, 0)
|
||||
|
||||
if (anim in ('arrow_left', 'arrow_right',
|
||||
'arrow_up', 'arrow_down')
|
||||
and len(self.imgs[anim]) >= 16):
|
||||
self.imgs[anim + '_lifted'] = img
|
||||
continue
|
||||
|
||||
self.imgs[anim].append(img)
|
||||
|
||||
####### PLAYER #######
|
||||
|
||||
for anim, directory in (
|
||||
(('idle_up', os.path.join('robot_idle', 'up')),
|
||||
('idle_down', os.path.join('robot_idle', 'down')),
|
||||
('idle_right', os.path.join('robot_idle', 'right')),
|
||||
('idle_left', os.path.join('robot_idle', 'right')),
|
||||
('carry_up', os.path.join('robot_carry', 'up')),
|
||||
('carry_down', os.path.join('robot_carry', 'down')),
|
||||
('carry_right', os.path.join('robot_carry', 'right')),
|
||||
('carry_left', os.path.join('robot_carry', 'right')),
|
||||
|
||||
# Lever
|
||||
|
||||
('lever_down_right', os.path.join('robot_lever', 'horizontal',
|
||||
'down_left')),
|
||||
('lever_down_left', os.path.join('robot_lever', 'horizontal',
|
||||
'down_left')),
|
||||
('lever_down_up', os.path.join('robot_lever', 'vertical',
|
||||
'down_down')),
|
||||
('lever_down_down', os.path.join('robot_lever', 'vertical',
|
||||
'down_down')),
|
||||
|
||||
('lever_up_right', os.path.join('robot_lever', 'horizontal',
|
||||
'up_right')),
|
||||
('lever_up_left', os.path.join('robot_lever', 'horizontal',
|
||||
'up_right')),
|
||||
('lever_up_up', os.path.join('robot_lever', 'vertical',
|
||||
'up_up')),
|
||||
('lever_up_down', os.path.join('robot_lever', 'vertical',
|
||||
'up_up')),
|
||||
|
||||
('lever_right_right', os.path.join('robot_lever', 'horizontal',
|
||||
'right_right')),
|
||||
('lever_right_left', os.path.join('robot_lever', 'horizontal',
|
||||
'right_right')),
|
||||
('lever_right_up', os.path.join('robot_lever', 'vertical',
|
||||
'left_up')),
|
||||
('lever_right_down', os.path.join('robot_lever', 'vertical',
|
||||
'right_down')),
|
||||
|
||||
('lever_left_right', os.path.join('robot_lever', 'horizontal',
|
||||
'right_right')),
|
||||
('lever_left_left', os.path.join('robot_lever', 'horizontal',
|
||||
'left_left')),
|
||||
('lever_left_up', os.path.join('robot_lever', 'vertical',
|
||||
'left_up')),
|
||||
('lever_left_down', os.path.join('robot_lever', 'vertical',
|
||||
'right_down'))
|
||||
)):
|
||||
|
||||
self.imgs['robot_' + anim] = []
|
||||
|
||||
# Find all image files for the given animation
|
||||
anim_files = []
|
||||
for root, dirs, files in os.walk(os.path.join(
|
||||
self.directory, directory)):
|
||||
for f in files:
|
||||
if re.match(r"^.*\.(png)$", '/'.join([root, f])):
|
||||
anim_files.append('/'.join([root, f]))
|
||||
|
||||
# Sort and load the files
|
||||
for f in sorted(anim_files):
|
||||
img = pygame.image.load(f)
|
||||
|
||||
# Special treatment:
|
||||
if anim in ['idle_left', 'carry_left',
|
||||
|
||||
'lever_down_right', 'lever_left_down',
|
||||
'lever_up_left', 'lever_right_up',
|
||||
'lever_left_right']:
|
||||
img = pygame.transform.flip(img, 1, 0)
|
||||
|
||||
if anim in ['lever_right_left', 'lever_left_right',
|
||||
'lever_down_up', 'lever_up_down']:
|
||||
self.imgs['robot_' + anim].insert(0, img)
|
||||
else:
|
||||
self.imgs['robot_' + anim].append(img)
|
||||
0
arobotsconundrum/logic/__init__.py
Normal file
0
arobotsconundrum/logic/__init__.py
Normal file
141
arobotsconundrum/logic/colourboxes.py
Normal file
141
arobotsconundrum/logic/colourboxes.py
Normal file
@@ -0,0 +1,141 @@
|
||||
#!/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/>.
|
||||
#
|
||||
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
|
||||
#
|
||||
# colourboxes.py
|
||||
# --------------------
|
||||
# date created : Wed Aug 8 2012
|
||||
# copyright : (C) 2012 Niels G. W. Serup
|
||||
# maintained by : Niels G. W. Serup <ngws@metanohi.name>
|
||||
|
||||
"""
|
||||
Colour boxes.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
import random
|
||||
import itertools
|
||||
|
||||
def generate_colour_boxes(nwells, nboxes):
|
||||
"""
|
||||
Generate colour boxes that can be used to make all wells white. None of the
|
||||
generated colour boxes are white.
|
||||
|
||||
Arguments:
|
||||
nwells -- number of wells
|
||||
nboxes -- maximum number of boxes needed to make all wells white.
|
||||
|
||||
Return [[(r, g, b)]]
|
||||
where r : 0|1, g : 0|1, b : 0|1
|
||||
"""
|
||||
|
||||
nbits = nwells * 3
|
||||
data = [[0 for _ in range(nboxes)] for _ in range(nbits)]
|
||||
|
||||
def insert_1(x):
|
||||
t = random.randrange(0, nboxes)
|
||||
x0, x1 = _get_oxs(x)
|
||||
for y in range(t, nboxes) + range(0, t):
|
||||
if data[x][y] == 0 and not (data[x0][y] == 1 and data[x1][y] == 1):
|
||||
data[x][y] = 1
|
||||
break
|
||||
else:
|
||||
raise Exception("Cannot maintain no 111s invariant.")
|
||||
|
||||
def insert_two_1(x):
|
||||
t = random.randrange(0, nboxes)
|
||||
x0, x1 = _get_oxs(x)
|
||||
if len(list(filter(lambda y: data[x][y] == 0 and not (data[x0][y] == 1 and data[x1][y] == 1),
|
||||
range(nboxes)))) < 2:
|
||||
return
|
||||
for _ in range(2):
|
||||
for y in range(t, nboxes) + range(0, t):
|
||||
if data[x][y] == 0 and not (data[x0][y] == 1 and data[x1][y] == 1):
|
||||
data[x][y] = 1
|
||||
break
|
||||
|
||||
for x in range(len(data)):
|
||||
insert_1(x)
|
||||
for x in range(len(data)):
|
||||
for _ in range(random.randrange(0, (nboxes + 1) / 2)):
|
||||
insert_two_1(x)
|
||||
|
||||
boxes = []
|
||||
for y in range(nboxes):
|
||||
box = []
|
||||
boxes.append(box)
|
||||
for x in range(0, nbits, 3):
|
||||
r = data[x][y]
|
||||
g = data[x + 1][y]
|
||||
b = data[x + 2][y]
|
||||
box.append((r, g, b))
|
||||
return boxes
|
||||
|
||||
def _get_oxs(x):
|
||||
return (x + 1, x + 2) if x % 3 == 0 \
|
||||
else (x - 1, x + 1) if x % 3 == 1 \
|
||||
else (x - 2, x - 1)
|
||||
|
||||
def generate_random_box(nwells, min_nonblacks=0):
|
||||
"""
|
||||
Generate a box that triggers nwells wells, with random colors except white
|
||||
(111).
|
||||
|
||||
Arguments:
|
||||
min_nonblacks -- minimum number of well colours in a box required not to be
|
||||
black.
|
||||
"""
|
||||
def gen_wc():
|
||||
wc = [random.choice((0, 1)) for i in range(3)]
|
||||
if all(b == 1 for b in wc):
|
||||
wc[random.randrange(3)] = 0
|
||||
return wc
|
||||
def gen_wc_nonblack():
|
||||
wc = gen_wc()
|
||||
if all(b == 0 for b in wc):
|
||||
wc[random.randrange(3)] = 1
|
||||
return wc
|
||||
colours = [tuple(gen_wc()) for _ in range(nwells)]
|
||||
nonblack = lambda t: any(n == 1 for n in t)
|
||||
missing_nonblacks = min_nonblacks - len(list(filter(nonblack, colours)))
|
||||
i = 0
|
||||
while missing_nonblacks > 0:
|
||||
if not nonblack(colours[i]):
|
||||
colours[i] = gen_wc_nonblack()
|
||||
missing_nonblacks -= 1
|
||||
i += 1
|
||||
return colours
|
||||
|
||||
def get_colours(boxes):
|
||||
colours = []
|
||||
for i in range(len(boxes[0])):
|
||||
r, g, b = boxes[0][i]
|
||||
for j in range(1, len(boxes)):
|
||||
r1, g1, b1 = boxes[j][i]
|
||||
r ^= r1
|
||||
g ^= g1
|
||||
b ^= b1
|
||||
colours.append((r, g, b))
|
||||
return colours
|
||||
|
||||
def makes_all_wells_white(boxes):
|
||||
"""
|
||||
Determine if the boxes make all wells white when XOR'ed together.
|
||||
"""
|
||||
return all(c == 1 for c in itertools.chain(*get_colours(boxes)))
|
||||
87
arobotsconundrum/logic/direction.py
Normal file
87
arobotsconundrum/logic/direction.py
Normal file
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# 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/>.
|
||||
#
|
||||
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
|
||||
#
|
||||
# direction.py
|
||||
# --------------------
|
||||
# date created : Tue Aug 7 2012
|
||||
# copyright : (C) 2012 Niels G. W. Serup
|
||||
# maintained by : Niels G. W. Serup <ngws@metanohi.name>
|
||||
|
||||
"""Directions."""
|
||||
|
||||
class Direction(object):
|
||||
@staticmethod
|
||||
def next_pos(pos):
|
||||
raise NotImplementedError
|
||||
|
||||
@staticmethod
|
||||
def to_str():
|
||||
raise NotImplementedError
|
||||
|
||||
@staticmethod
|
||||
def from_sakse(p):
|
||||
return {(0, -1): Up,
|
||||
(0, 1): Down,
|
||||
(-1, 0): Left,
|
||||
(1, 0): Right}[p]
|
||||
|
||||
class Up(Direction):
|
||||
@staticmethod
|
||||
def next_pos(pos):
|
||||
x, y = pos
|
||||
return x, y - 1
|
||||
|
||||
@staticmethod
|
||||
def to_str():
|
||||
return 'up'
|
||||
|
||||
class Right(Direction):
|
||||
@staticmethod
|
||||
def next_pos(pos):
|
||||
x, y = pos
|
||||
return x + 1, y
|
||||
|
||||
@staticmethod
|
||||
def to_str():
|
||||
return 'right'
|
||||
|
||||
class Down(Direction):
|
||||
@staticmethod
|
||||
def next_pos(pos):
|
||||
x, y = pos
|
||||
return x, y + 1
|
||||
|
||||
@staticmethod
|
||||
def to_str():
|
||||
return 'down'
|
||||
|
||||
class Left(Direction):
|
||||
@staticmethod
|
||||
def next_pos(pos):
|
||||
x, y = pos
|
||||
return x - 1, y
|
||||
|
||||
@staticmethod
|
||||
def to_str():
|
||||
return 'left'
|
||||
|
||||
all_directions = [Up, Right, Down, Left]
|
||||
_sp = lambda n: lambda d: all_directions[(all_directions.index(d) + n) % 4]
|
||||
succ, pred = _sp(1), _sp(-1)
|
||||
isDirection = all_directions.__contains__
|
||||
218
arobotsconundrum/logic/lasermirror.py
Normal file
218
arobotsconundrum/logic/lasermirror.py
Normal file
@@ -0,0 +1,218 @@
|
||||
#!/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/>.
|
||||
#
|
||||
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
|
||||
#
|
||||
# lasermirror.py
|
||||
# --------------------
|
||||
# date created : Tue Aug 7 2012
|
||||
# copyright : (C) 2012 Niels G. W. Serup
|
||||
# maintained by : Niels G. W. Serup <ngws@metanohi.name>
|
||||
|
||||
"""
|
||||
Management of lasers in rooms of mirrors and targets.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
import math
|
||||
import random
|
||||
import itertools
|
||||
from arobotsconundrum.logic.direction import *
|
||||
import arobotsconundrum.logic.rollingstone as rstone
|
||||
from arobotsconundrum.logic.rollingstone import Blocker
|
||||
import arobotsconundrum.misc as misc
|
||||
|
||||
class MirrorLeft(object):
|
||||
pass
|
||||
|
||||
class MirrorRight(object):
|
||||
pass
|
||||
|
||||
class Lever(object):
|
||||
pass
|
||||
|
||||
class Target(object):
|
||||
pass
|
||||
|
||||
class Source(object):
|
||||
def __init__(self, direction):
|
||||
self.__dict__.update(locals())
|
||||
|
||||
def generate_simple_playfield(nmirrors):
|
||||
"""
|
||||
Generate a completable 17x17 playfield where:
|
||||
* there are four laser sources, one in each corner
|
||||
+ the one in the upper left corner (0, 0) starts in (0, -1) heading down
|
||||
+ the one in the upper right corner (16, 0) starts in (17, 0), heading left
|
||||
+ the one in the lower right corner (16, 16) starts in (16, 17), heading up
|
||||
+ the one in the lower left corner (0, 16) starts in (-1, 16), heading right
|
||||
* there are four laser targets
|
||||
* there are nmirrors mirrors
|
||||
* there are nmirrors levers
|
||||
* all levers are at the wall
|
||||
|
||||
Return playfield : {(x, y):
|
||||
Target | MirrorLeft | MirrorRight | rstone.Blocker | Lever}
|
||||
"""
|
||||
|
||||
width, height = 17, 17
|
||||
|
||||
playfield = {(0, 0): Source(Down),
|
||||
(width - 1, 0): Source(Left),
|
||||
(width - 1, height - 1): Source(Up),
|
||||
(0, height - 1): Source(Right),
|
||||
(6, 6): Target,
|
||||
(10, 6): Target,
|
||||
(6, 10): Target,
|
||||
(10, 10): Target,
|
||||
(7, 7): rstone.Blocker,
|
||||
(7, 8): rstone.Blocker,
|
||||
(7, 9): rstone.Blocker,
|
||||
(8, 7): rstone.Blocker,
|
||||
(8, 8): rstone.Blocker,
|
||||
(8, 9): rstone.Blocker,
|
||||
(9, 7): rstone.Blocker,
|
||||
(9, 8): rstone.Blocker,
|
||||
(9, 9): rstone.Blocker,
|
||||
}
|
||||
|
||||
succs = lambda d: d
|
||||
source_direc = Up
|
||||
nlevers = nmirrors
|
||||
for missing in range(4, 0, -1):
|
||||
nm = nmirrors / missing
|
||||
nmirrors -= nm
|
||||
stone_playfield, _ = rstone.generate_simple_playfield(
|
||||
7, 7, nm, 0, False, False)
|
||||
for pos, direc in stone_playfield.items():
|
||||
playfield[_adjust(source_direc, width - 1, height - 1, *pos)] \
|
||||
= random.choice((MirrorLeft, MirrorRight))
|
||||
succs = (lambda s: lambda d: succ(s(d)))(succs)
|
||||
source_direc = succ(source_direc)
|
||||
|
||||
occup = set(playfield.keys())
|
||||
|
||||
is_empty = lambda x, y: (x, y) not in occup
|
||||
|
||||
ok_a = lambda y: is_empty(1, y)
|
||||
ok_b = lambda y: is_empty(width - 2, y)
|
||||
ok_c = lambda x: is_empty(x, 1)
|
||||
ok_d = lambda x: is_empty(x, height - 2)
|
||||
no_block = lambda x, y: \
|
||||
all((ok_a(y) if x == 0 else True,
|
||||
ok_b(y) if x == width - 1 else True,
|
||||
ok_c(x) if y == 0 else True,
|
||||
ok_d(x) if y == height - 1 else True))
|
||||
|
||||
emptys = set([(0, y) for y in filter(ok_a, range(height))]
|
||||
+ [(width - 1, y) for y in filter(ok_b, range(height))]
|
||||
+ [(x, 0) for x in filter(ok_c, range(width))]
|
||||
+ [(x, height - 1) for x in filter(ok_d, range(width))]) - occup
|
||||
emptys_full = set(itertools.product(range(width), range(height))) - occup
|
||||
|
||||
emptys = list(emptys)
|
||||
random.shuffle(emptys)
|
||||
emptys = set(emptys)
|
||||
|
||||
is_empty = lambda x, y: (x, y) in emptys_full
|
||||
|
||||
levers = []
|
||||
for _ in range(nlevers):
|
||||
while True:
|
||||
pos = next(iter(emptys))
|
||||
emptys.remove(pos)
|
||||
emptys_full.remove(pos)
|
||||
if no_block(*pos):
|
||||
playfield[pos] = Lever
|
||||
if not all(no_block(*pos) for pos in levers):
|
||||
del playfield[pos]
|
||||
else:
|
||||
levers.append(pos)
|
||||
break
|
||||
|
||||
return playfield
|
||||
|
||||
|
||||
def _adjust(source_direc, w, h, x, y):
|
||||
return {
|
||||
Up: lambda x, y: (x, y),
|
||||
Right: lambda x, y: (w - y, x),
|
||||
Down: lambda x, y: (w - x, h - y),
|
||||
Left: lambda x, y: (y, h - x),
|
||||
}[source_direc](x, y)
|
||||
|
||||
def generate_lasers(playfield):
|
||||
"""
|
||||
Generate laser paths.
|
||||
|
||||
Return [((x, y), direction), ...]
|
||||
"""
|
||||
width, height = 17, 17
|
||||
sources = ((pos, obj.direction) for pos, obj
|
||||
in filter(lambda posobj: isinstance(posobj[1], Source),
|
||||
playfield.items()))
|
||||
lasers, lasers_flat = [], set()
|
||||
def add(start, end):
|
||||
t = (min(start, end), max(start, end))
|
||||
if not t in lasers_flat:
|
||||
laser.append(t)
|
||||
lasers_flat.add(t)
|
||||
for start, direc in sources:
|
||||
end = start
|
||||
laser = []
|
||||
lasers.append(laser)
|
||||
while True:
|
||||
cur = playfield.get(end)
|
||||
if cur is Target:
|
||||
add(start, end)
|
||||
break
|
||||
if cur is Blocker:
|
||||
add(start, end)
|
||||
break
|
||||
if cur in (MirrorLeft, MirrorRight):
|
||||
if (start, end) in ((start, end) for (start, end), direc in lasers_flat):
|
||||
break
|
||||
add(start, end)
|
||||
direc = _mirror_new_direc(cur, direc)
|
||||
start = end
|
||||
new_end = direc.next_pos(end)
|
||||
if new_end[0] < 0 or new_end[1] < 0 or \
|
||||
new_end[0] >= width or new_end[1] >= height:
|
||||
add(start, new_end)
|
||||
break
|
||||
end = new_end
|
||||
return lasers
|
||||
|
||||
def _mirror_new_direc(mirror_type, old_direc):
|
||||
return {Down: (Left, Right),
|
||||
Left: (Down, Up),
|
||||
Up: (Right, Left),
|
||||
Right: (Up, Down)}[old_direc][
|
||||
0 if mirror_type is MirrorLeft else 1]
|
||||
|
||||
def print_playfield(playfield, width, height, hide_directions=False):
|
||||
text = [['·' for _ in range(width)] for _ in range(height)]
|
||||
for (x, y), val in playfield.items():
|
||||
if isDirection(val) and hide_directions:
|
||||
continue
|
||||
text[y][x] = '%' if val is rstone.Blocker \
|
||||
else 'x' if val is Mirror \
|
||||
else 'L' if val is Lever \
|
||||
else 'T' if val is Target else 'N'
|
||||
print('\n'.join(''.join(line) for line in text))
|
||||
|
||||
223
arobotsconundrum/logic/rollingstone.py
Normal file
223
arobotsconundrum/logic/rollingstone.py
Normal file
@@ -0,0 +1,223 @@
|
||||
#!/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/>.
|
||||
#
|
||||
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
|
||||
#
|
||||
# rollingstone.py
|
||||
# --------------------
|
||||
# date created : Tue Aug 7 2012
|
||||
# copyright : (C) 2012 Niels G. W. Serup
|
||||
# maintained by : Niels G. W. Serup <ngws@metanohi.name>
|
||||
|
||||
"""
|
||||
Logic for a rolling stone on a playfield of movement-stopping stones and
|
||||
direction-changing turns. Also has a pseudo-random playfield generator.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
import math
|
||||
import random
|
||||
import itertools
|
||||
|
||||
from arobotsconundrum.logic.direction import *
|
||||
import arobotsconundrum.misc as misc
|
||||
|
||||
class Blocker(object):
|
||||
pass
|
||||
|
||||
def step(playfield, width, height, old_pos, direc):
|
||||
"""
|
||||
Return a new (position, direction) tuple based on the location on the
|
||||
playfield.
|
||||
"""
|
||||
pos = direc.next_pos(old_pos)
|
||||
x, y = pos
|
||||
if playfield.get(pos) is Blocker or x < 0 or x >= width \
|
||||
or y < 0 or y >= height:
|
||||
pos = old_pos
|
||||
elif isDirection(playfield.get(pos)):
|
||||
direc = playfield[pos]
|
||||
return pos, direc
|
||||
|
||||
def reaches_goal(playfield, width, height, max_steps, start_pos, goal_pos):
|
||||
"""
|
||||
Determine if the rolling stone reaches the goal within max_steps steps.
|
||||
|
||||
playfield[start_pos] must contain either a Turn(Down) or a Turn(Right)
|
||||
object, or the rolling stone will not roll.
|
||||
"""
|
||||
pos = start_pos
|
||||
direc = playfield[pos]
|
||||
for _ in range(max_steps):
|
||||
new_pos, new_direc = step(playfield, width, height, pos, direc)
|
||||
if new_pos == goal_pos:
|
||||
return True
|
||||
if new_pos == pos:
|
||||
return False
|
||||
pos, direc = new_pos, new_direc
|
||||
return False
|
||||
|
||||
|
||||
def generate_simple_playfield(width, height, nturns, nstones,
|
||||
do_transpose=None, start_inside=True):
|
||||
"""
|
||||
Generate a completable playfield where:
|
||||
* the starting position is in the upper left corner
|
||||
* the goal is in the lower right corner
|
||||
* the playfield is completable in nturns or less
|
||||
* the playfield has at most nstones stones
|
||||
|
||||
Return (playfield : {(x, y): Direction | Blocker},
|
||||
steps : int)
|
||||
where (x, y) : (int, int)
|
||||
|
||||
The returned playfield contains Direction objects which can be used with
|
||||
the step function to move towards the goal. The solution denoted by the
|
||||
Direction objects is not necessarily the only solution.
|
||||
|
||||
'steps' is the number of steps used by the generated solution. It is not
|
||||
necessarily the lowest number of steps the playfield can be completed in.
|
||||
|
||||
This generator favours increasing the turn density the closer to the goal
|
||||
it gets.
|
||||
"""
|
||||
|
||||
min_width, min_height = _min_play_size(nturns)
|
||||
if width < min_width or height < min_height:
|
||||
nturns = min(2 * (width - 1), 2 * (height - 1) - 1)
|
||||
min_width, min_height = _min_play_size(nturns)
|
||||
|
||||
if do_transpose is None:
|
||||
do_transpose = random.choice((True, False))
|
||||
if do_transpose:
|
||||
width, height = height, width
|
||||
min_width, min_height = min_height, min_width
|
||||
|
||||
turns = [((0, 0), None)]
|
||||
stones = []
|
||||
x, y = (0, 0)
|
||||
not_allowed_y = []
|
||||
offset_x = 0
|
||||
while True:
|
||||
missing = nturns - len(turns) + 1
|
||||
if missing == 1:
|
||||
turns[-1] = (turns[-1][0], Down)
|
||||
turns.append(((x, height - 1), Right))
|
||||
break
|
||||
elif missing == 0:
|
||||
turns[-1] = ((width - 1, turns[-1][0][1]), Down)
|
||||
break
|
||||
else:
|
||||
allowed = set(range(0, height)) - set(not_allowed_y)
|
||||
if missing <= 3:
|
||||
allowed -= set((height - 1,))
|
||||
if missing == nturns:
|
||||
allowed -= set((0,))
|
||||
y1 = random.choice(list(allowed))
|
||||
turns[-1] = (turns[-1][0], Down if y1 > y else Up)
|
||||
not_allowed_y.append(y1)
|
||||
if len(not_allowed_y) == 3:
|
||||
del not_allowed_y[0]
|
||||
turns.append(((x, y1), Right))
|
||||
x1p = random.randint(0, width - min_width - offset_x)
|
||||
offset_x += x1p
|
||||
x1 = x + x1p + 1
|
||||
turns.append(((x1, y1), None))
|
||||
x, y = x1, y1
|
||||
turns.append(((width - 1, height - 1), None))
|
||||
if not start_inside:
|
||||
del turns[0]
|
||||
|
||||
if do_transpose:
|
||||
turns[:] = [((y, x), {
|
||||
Down: Right,
|
||||
Right: Down,
|
||||
Up: Left,
|
||||
}.get(d)) for ((x, y), d) in turns]
|
||||
width, height = height, width
|
||||
min_width, min_height = min_height, min_width
|
||||
|
||||
used_fields = _fields_from_turns(turns)
|
||||
playfield = {}
|
||||
del turns[-1]
|
||||
for p, d in turns:
|
||||
playfield[p] = d
|
||||
|
||||
for pos in misc.pick_random_elements(
|
||||
list(set(itertools.product(range(width), range(height)))
|
||||
- set(used_fields)), nstones):
|
||||
playfield[pos] = Blocker
|
||||
return playfield, len(used_fields) - 1
|
||||
|
||||
def generate_simple_unsolved_solvable_playfield(*args, **kwds):
|
||||
"""
|
||||
Return a tuple of a playfield without direction objects, its number of
|
||||
steps, and a list of the direction objects.
|
||||
"""
|
||||
playfield, steps = generate_simple_playfield(*args, **kwds)
|
||||
new_playfield, directions = {}, []
|
||||
for pos, val in playfield.items():
|
||||
if val is Blocker:
|
||||
new_playfield[pos] = val
|
||||
else:
|
||||
directions.append(val)
|
||||
return new_playfield, steps, directions
|
||||
|
||||
def generate_simple_unsolved_solvable_extra(*args, **kwds):
|
||||
"""
|
||||
Do the same as generate_simple_unsolved_solvable, but throw in some copies
|
||||
of the direction object not returned by that function. You probably want to
|
||||
use this in your game.
|
||||
"""
|
||||
playfield, steps, directions = generate_simple_unsolved_solvable_playfield(
|
||||
*args, **kwds)
|
||||
missing_dir = list(set(all_directions) - set(directions))[0]
|
||||
return playfield, steps, directions + \
|
||||
[missing_dir] * (len(directions) / 3) + [Right]
|
||||
|
||||
def print_playfield(playfield, width, height, hide_directions):
|
||||
text = [['·' for _ in range(width)] for _ in range(height)]
|
||||
for (x, y), val in playfield.items():
|
||||
if isDirection(val) and hide_directions:
|
||||
continue
|
||||
text[y][x] = '%' if val is Blocker else repr(val).rsplit('.', 1)[1][0] \
|
||||
if isDirection(val) else 'G'
|
||||
print('\n'.join(''.join(line) for line in text))
|
||||
|
||||
def _cells_upto(fields, start, direc, end):
|
||||
(x0, y0), (x2, y2) = start, end
|
||||
if direc in (Up, Down):
|
||||
t = -1 if direc == Up else 1
|
||||
for y in range(y0 + t, y2 + t, t):
|
||||
fields.append((x0, y))
|
||||
else:
|
||||
t = -1 if direc == Left else 1
|
||||
for x in range(x0 + t, x2 + t, t):
|
||||
fields.append((x, y0))
|
||||
|
||||
def _fields_from_turns(turns):
|
||||
fields = [(0, 0)]
|
||||
prev_pos, prev_direc = turns[0]
|
||||
for (pos, direc) in turns:
|
||||
_cells_upto(fields, prev_pos, prev_direc, pos)
|
||||
prev_pos, prev_direc = pos, direc
|
||||
return fields
|
||||
|
||||
def _min_play_size(nturns):
|
||||
return (int(math.ceil(nturns / 2.0)) + 1,
|
||||
int(math.ceil((nturns + 1) / 2.0)) + 1)
|
||||
144
arobotsconundrum/logic/teleportermap.py
Normal file
144
arobotsconundrum/logic/teleportermap.py
Normal file
@@ -0,0 +1,144 @@
|
||||
#!/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/>.
|
||||
#
|
||||
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
|
||||
#
|
||||
# teleportermap.py
|
||||
# --------------------
|
||||
# date created : Mon Aug 13 2012
|
||||
# copyright : (C) 2012 Niels G. W. Serup
|
||||
# maintained by : Niels G. W. Serup <ngws@metanohi.name>
|
||||
|
||||
"""
|
||||
Logic for a map with invisible teleporters.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
import math
|
||||
import random
|
||||
import itertools
|
||||
|
||||
from arobotsconundrum.logic.direction import *
|
||||
import arobotsconundrum.misc as misc
|
||||
|
||||
class Empty(object):
|
||||
pass
|
||||
|
||||
class Forbidden(object):
|
||||
pass
|
||||
|
||||
class StrictlyForbidden(object):
|
||||
pass
|
||||
|
||||
class Visited(object):
|
||||
pass
|
||||
|
||||
def generate_teleporter_map(width, height):
|
||||
m = [[Empty for _ in range(height)]
|
||||
for _ in range(width)]
|
||||
|
||||
def _get(p):
|
||||
if p[0] < 0 or p[0] >= width or p[1] < 0 or p[1] >= height:
|
||||
return StrictlyForbidden
|
||||
return m[p[0]][p[1]]
|
||||
|
||||
def _set(p, val):
|
||||
try:
|
||||
m[p[0]][p[1]] = val
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
def insert_random_point_on_line(x):
|
||||
t = random.randrange(height)
|
||||
for y in itertools.chain(xrange(t), xrange(t + 1, height)):
|
||||
_set((x, y), Forbidden)
|
||||
_set((x, t), Visited)
|
||||
return (x, t)
|
||||
|
||||
pos = insert_random_point_on_line(width - 1)
|
||||
|
||||
while True:
|
||||
while True:
|
||||
if pos[0] == 1 and random.randint(0, height) == 0:
|
||||
break
|
||||
t = random.randrange(4)
|
||||
found = None
|
||||
alldirs = all_directions
|
||||
if random.choice((True, False)):
|
||||
alldirs.reverse()
|
||||
for direc in alldirs[t:] + alldirs[:t]:
|
||||
npos = direc.next_pos(pos)
|
||||
if found is None and npos[0] != 0 and _get(npos) is Empty and (
|
||||
(direc is Right and
|
||||
len(filter(lambda c: c is Empty, m[pos[0]][:pos[1]] if
|
||||
opos[1] > pos[1]
|
||||
else m[pos[0]][pos[1] + 1:])) >= 2)
|
||||
or direc is not Right):
|
||||
found = npos
|
||||
_set(npos, Visited)
|
||||
else:
|
||||
if _get(npos) is Empty:
|
||||
_set(npos, Forbidden)
|
||||
if found is None:
|
||||
break
|
||||
opos = pos
|
||||
pos = found
|
||||
if pos[0] == 1:
|
||||
break
|
||||
|
||||
_set(pos, StrictlyForbidden)
|
||||
for direc in all_directions:
|
||||
npos = direc.next_pos(pos)
|
||||
if _get(npos) is Visited:
|
||||
pos = npos
|
||||
break
|
||||
for direc in all_directions:
|
||||
npos = direc.next_pos(pos)
|
||||
if _get(npos) is Forbidden:
|
||||
occup_direc = succ(succ(direc))
|
||||
if all(ndirec is occup_direc
|
||||
or _get(ndirec.next_pos(npos)) in (Forbidden, Empty)
|
||||
for ndirec in all_directions):
|
||||
_set(npos, Empty)
|
||||
|
||||
_set((0, pos[1]), Visited)
|
||||
return m
|
||||
|
||||
def generate_teleporter_map2(width, height):
|
||||
tmap = generate_teleporter_map(width, height)
|
||||
res = set()
|
||||
for y in range(len(tmap[0])):
|
||||
for x in range(len(tmap)):
|
||||
if tmap[x][y] is Visited:
|
||||
res.add((x, y))
|
||||
return res
|
||||
|
||||
def generate_teleporter_map3(width, height):
|
||||
return set(itertools.product(range(width), range(height))) \
|
||||
- generate_teleporter_map2(width, height)
|
||||
|
||||
def print_map(tmap):
|
||||
for y in range(len(tmap[0])):
|
||||
for x in range(len(tmap)):
|
||||
c = tmap[x][y]
|
||||
print({Empty: '%',
|
||||
Forbidden: '#',
|
||||
StrictlyForbidden: '!',
|
||||
Visited: '·'}[c], end='')
|
||||
print()
|
||||
|
||||
72
arobotsconundrum/main_menu.py
Normal file
72
arobotsconundrum/main_menu.py
Normal file
@@ -0,0 +1,72 @@
|
||||
# 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/>.
|
||||
#
|
||||
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
|
||||
#
|
||||
# main_menu.py
|
||||
# --------------------
|
||||
# date created : Tue Aug 7 2012
|
||||
# copyright : (C) 2012 Sakse Dalum
|
||||
# maintained by : Sakse Dalum <don_s@hongabar.org>
|
||||
|
||||
"""
|
||||
The main menu.
|
||||
"""
|
||||
|
||||
import os
|
||||
import pygame
|
||||
|
||||
import level1
|
||||
import game_menu
|
||||
|
||||
class MainMenu(object):
|
||||
def __init__(self, game, img_dir):
|
||||
self.__dict__.update(locals())
|
||||
|
||||
self.load()
|
||||
|
||||
def load(self):
|
||||
self.background_img = pygame.image.load(os.path.join(self.img_dir,
|
||||
'main_menu.png'))
|
||||
self.background_img = pygame.transform.smoothscale(
|
||||
self.background_img, self.game.window.get_size())
|
||||
|
||||
self.space_img = pygame.image.load(os.path.join(
|
||||
self.img_dir,
|
||||
'press_space_to_start.png'))
|
||||
|
||||
screen_size = self.game.window.get_size()
|
||||
img_size = self.space_img.get_size()
|
||||
factors = (float(img_size[0]) / 1920, float(img_size[1]) / 1280)
|
||||
|
||||
self.space_img = pygame.transform.smoothscale(
|
||||
self.space_img,
|
||||
(int(screen_size[0]*factors[0]),
|
||||
int(screen_size[1]*factors[1])))
|
||||
|
||||
def update(self, e, t, dt):
|
||||
for event in e:
|
||||
if event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_SPACE:
|
||||
self.game.goto_level(0)
|
||||
if event.key == pygame.K_ESCAPE:
|
||||
self.game.stop()
|
||||
|
||||
def draw(self, window):
|
||||
window.blit(self.background_img, (0, 0))
|
||||
|
||||
screen_size = self.game.window.get_size()
|
||||
window.blit(self.space_img,
|
||||
(0, screen_size[1] - self.space_img.get_size()[1]))
|
||||
69
arobotsconundrum/mirror.py
Normal file
69
arobotsconundrum/mirror.py
Normal file
@@ -0,0 +1,69 @@
|
||||
# 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/>.
|
||||
#
|
||||
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
|
||||
#
|
||||
# mirror.py
|
||||
# --------------------
|
||||
# date created : Fri Aug 10 2012
|
||||
# copyright : (C) 2012 Niels G. W. Serup
|
||||
# maintained by : Niels G. W. Serup <ngws@metanohi.name>
|
||||
|
||||
"""
|
||||
A generic mirror for drawing.
|
||||
"""
|
||||
|
||||
import pygame
|
||||
|
||||
import worldobject
|
||||
|
||||
class Mirror(worldobject.WorldObject):
|
||||
def __init__(self, level, x0, y0, left_up=True, 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.left_up_aim = self.left_up
|
||||
|
||||
self.frame = 7
|
||||
self.anim_speed = 12
|
||||
self._half_anim_len = len(self.level.imgs['mirror']) / 2
|
||||
|
||||
def rotate(self):
|
||||
if self.in_rotation:
|
||||
return
|
||||
self.in_rotation = True
|
||||
self.left_up_aim = not self.left_up_aim
|
||||
self.frame = 0
|
||||
|
||||
def update(self, e, t, dt):
|
||||
if self.in_rotation:
|
||||
top = self._half_anim_len - 1
|
||||
self.frame = min(self.frame + self.anim_speed * dt, top)
|
||||
if self.frame == top:
|
||||
self.in_rotation = False
|
||||
self.left_up = not self.left_up
|
||||
for link in self.links:
|
||||
link(self.left_up)
|
||||
|
||||
worldobject.WorldObject.update(self, e, t, dt)
|
||||
|
||||
def draw(self, window):
|
||||
fn = self.frame + 1 if not self.left_up_aim else self.frame + self._half_anim_len
|
||||
self.img = self.level.imgs['mirror'][int(fn)]
|
||||
window.blit(self.img, (self.xd - 32 - self.level.camera_x,
|
||||
self.yd - self.img.get_size()[1] + 24
|
||||
- self.level.camera_y))
|
||||
13
arobotsconundrum/misc.py
Normal file
13
arobotsconundrum/misc.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from __future__ import print_function
|
||||
import random
|
||||
|
||||
def pick_random_elements(xs, n):
|
||||
for i in range(min(n, len(xs))):
|
||||
i1 = random.randrange(i, len(xs))
|
||||
yield xs[i1]
|
||||
xs[i1] = xs[i]
|
||||
|
||||
def manhattan_dist(p0, p1):
|
||||
x0, y0 = p0
|
||||
x1, y1 = p1
|
||||
return abs(x1 - x0) + abs(y1 - y0)
|
||||
156
arobotsconundrum/player.py
Normal file
156
arobotsconundrum/player.py
Normal file
@@ -0,0 +1,156 @@
|
||||
# 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/>.
|
||||
#
|
||||
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
|
||||
#
|
||||
# player.py
|
||||
# --------------------
|
||||
# date created : Tue Aug 7 2012
|
||||
# copyright : (C) 2012 Sakse Dalum
|
||||
# maintained by : Sakse Dalum <don_s@hongabar.org>
|
||||
|
||||
"""
|
||||
The player.
|
||||
"""
|
||||
|
||||
import pygame
|
||||
import re
|
||||
import os
|
||||
|
||||
import worldobject
|
||||
import boulder
|
||||
import lever
|
||||
|
||||
class Player(worldobject.WorldObject):
|
||||
def __init__(self, level, x, y, z=1, movable=True):
|
||||
self.__dict__.update(locals())
|
||||
worldobject.WorldObject.__init__(self, level, x, y,
|
||||
z=z, movable=movable)
|
||||
|
||||
self.anim_root = 'idle'
|
||||
self.anim = 'right'
|
||||
self.frame = 0
|
||||
self.anim_speed = 15
|
||||
|
||||
self.working = False
|
||||
|
||||
self.ignore_list.append(boulder.Boulder)
|
||||
|
||||
self.imgs = dict([(k[6:], v) for (k, v) in self.level.imgs.iteritems()
|
||||
if k.startswith('robot_')])
|
||||
|
||||
def direction_as_string(self):
|
||||
if self.direction == (1, 0):
|
||||
return "right"
|
||||
if self.direction == (-1, 0):
|
||||
return "left"
|
||||
if self.direction == (0, -1):
|
||||
return "up"
|
||||
if self.direction == (0, 1):
|
||||
return "down"
|
||||
|
||||
def touch(self, touch_x, touch_y):
|
||||
for obj in self.level.objects:
|
||||
if (obj.x == self.x + touch_x * self.tile_x
|
||||
and obj.y == self.y + touch_y * self.tile_y
|
||||
and obj != self):
|
||||
|
||||
# Concerning levers
|
||||
if type(obj) == lever.Lever:
|
||||
if not obj.at_rest:
|
||||
return
|
||||
|
||||
obj.use(self)
|
||||
self.working = True
|
||||
|
||||
# List all possible combinations ...
|
||||
lever_direction = (
|
||||
'up' if obj.anim == 'lever_updown' and not obj.setting
|
||||
else
|
||||
'right' if obj.anim == 'lever_leftright'
|
||||
and not obj.setting
|
||||
else
|
||||
'down' if obj.anim == 'lever_updown' and obj.setting
|
||||
else
|
||||
'left')
|
||||
|
||||
self.anim_root = 'lever'
|
||||
self.frame = 0
|
||||
self.anim = (
|
||||
self.direction_as_string() + '_' + lever_direction)
|
||||
else:
|
||||
obj.use(self)
|
||||
|
||||
def update(self, e, t, dt):
|
||||
if not self.working:
|
||||
self.anim_root = 'carry' if self.holding else 'idle'
|
||||
|
||||
keys = pygame.key.get_pressed()
|
||||
if keys[pygame.K_UP]:
|
||||
if not self.holding and not self.is_moving:
|
||||
self.direction = (0, -1)
|
||||
self.anim = self.direction_as_string()
|
||||
self.move(0, -1)
|
||||
elif keys[pygame.K_DOWN]:
|
||||
if not self.holding and not self.is_moving:
|
||||
self.direction = (0, 1)
|
||||
self.anim = self.direction_as_string()
|
||||
self.move(0, 1)
|
||||
elif keys[pygame.K_RIGHT]:
|
||||
if not self.holding and not self.is_moving:
|
||||
self.direction = (1, 0)
|
||||
self.anim = self.direction_as_string()
|
||||
self.move(1, 0)
|
||||
elif keys[pygame.K_LEFT]:
|
||||
if not self.holding and not self.is_moving:
|
||||
self.direction = (-1, 0)
|
||||
self.anim = self.direction_as_string()
|
||||
self.move(-1, 0)
|
||||
|
||||
for event in e:
|
||||
if event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_SPACE:
|
||||
self.touch(*self.direction)
|
||||
|
||||
else:
|
||||
self.working = not (self.frame == len(
|
||||
self.imgs[self.anim_root + '_' + self.anim]) - 1)
|
||||
if not self.working:
|
||||
self.anim = self.direction_as_string()
|
||||
self.anim_root = 'carry' if self.holding else 'idle'
|
||||
|
||||
# Update the animation
|
||||
if not self.working:
|
||||
self.frame = ((self.frame + self.anim_speed * dt) %
|
||||
len(self.imgs[self.anim_root + '_' + self.anim]))
|
||||
else:
|
||||
self.frame = min(
|
||||
self.frame + self.anim_speed * dt,
|
||||
len(self.imgs[self.anim_root + '_' + self.anim]) - 1)
|
||||
|
||||
|
||||
worldobject.WorldObject.update(self, e, t, dt)
|
||||
|
||||
def draw(self, window):
|
||||
self.img = self.imgs[self.anim_root + '_' + self.anim][int(self.frame)]
|
||||
self.img.set_alpha(128)
|
||||
offset_x = (96 if self.anim_root == 'lever' and self.anim in
|
||||
['left_up', 'left_left', 'left_down', 'left_right',
|
||||
'down_right', 'up_left']
|
||||
else 32)
|
||||
window.blit(self.img, (self.x - offset_x - self.level.camera_x,
|
||||
self.y - self.img.get_size()[1] + 24
|
||||
- self.level.camera_y))
|
||||
|
||||
47
arobotsconundrum/tile.py
Normal file
47
arobotsconundrum/tile.py
Normal file
@@ -0,0 +1,47 @@
|
||||
# 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/>.
|
||||
#
|
||||
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
|
||||
#
|
||||
# tile.py
|
||||
# --------------------
|
||||
# date created : Tue Aug 7 2012
|
||||
# copyright : (C) 2012 Sakse Dalum
|
||||
# maintained by : Sakse Dalum <don_s@hongabar.org>
|
||||
|
||||
"""
|
||||
A generic tile.
|
||||
"""
|
||||
|
||||
import worldobject
|
||||
|
||||
class Tile(worldobject.WorldObject):
|
||||
def __init__(self, level, x, y, img):
|
||||
self.__dict__.update(locals())
|
||||
worldobject.WorldObject.__init__(self, level, x, y)
|
||||
|
||||
def draw(self, window):
|
||||
window.blit(self.img, (self.x - 32 - self.level.camera_x,
|
||||
self.y - self.img.get_size()[1] + 24
|
||||
- self.level.camera_y))
|
||||
|
||||
class NaiveTile(object):
|
||||
def __init__(self, x, y, img):
|
||||
self.__dict__.update(locals())
|
||||
|
||||
def draw(self, window):
|
||||
window.blit(self.img, (self.x - 32,
|
||||
self.y - self.img.get_size()[1] + 24))
|
||||
|
||||
65
arobotsconundrum/trigger.py
Normal file
65
arobotsconundrum/trigger.py
Normal file
@@ -0,0 +1,65 @@
|
||||
# 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/>.
|
||||
#
|
||||
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
|
||||
#
|
||||
# trigger.py
|
||||
# --------------------
|
||||
# date created : Thu Aug 9 2012
|
||||
# copyright : (C) 2012 Sakse Dalum
|
||||
# maintained by : Sakse Dalum <don_s@hongabar.org>
|
||||
|
||||
"""
|
||||
A generic trigger pad.
|
||||
"""
|
||||
|
||||
import pygame
|
||||
|
||||
import worldobject
|
||||
|
||||
class Trigger(worldobject.WorldObject):
|
||||
def __init__(self, level, x, y, links, img, trigger_objs,
|
||||
toggling=False, signal=[0, 1],
|
||||
setting=False, blocking=False,
|
||||
visible=True, no_stop=False):
|
||||
self.__dict__.update(locals())
|
||||
worldobject.WorldObject.__init__(self, level, x, y, z=-48,
|
||||
blocking=blocking, visible=visible)
|
||||
|
||||
self.frame = 0
|
||||
self.anim_speed = 15
|
||||
|
||||
def trigger(self, setting, obj):
|
||||
if self.setting != setting or self.no_stop:
|
||||
self.setting = setting
|
||||
|
||||
for link in self.links:
|
||||
link(self.signal[setting])
|
||||
|
||||
def update(self, e, t, dt):
|
||||
for obj in self.trigger_objs:
|
||||
if self.x == obj.x and self.y == obj.y:
|
||||
self.trigger(True, obj)
|
||||
break
|
||||
if self.toggling:
|
||||
self.trigger(False, obj)
|
||||
|
||||
worldobject.WorldObject.update(self, e, t, dt)
|
||||
|
||||
def draw(self, window):
|
||||
if self.visible:
|
||||
window.blit(self.img, (self.x - 32 - self.level.camera_x,
|
||||
self.y - self.img.get_size()[1] + 24
|
||||
- self.level.camera_y))
|
||||
154
arobotsconundrum/worldobject.py
Normal file
154
arobotsconundrum/worldobject.py
Normal file
@@ -0,0 +1,154 @@
|
||||
# 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/>.
|
||||
#
|
||||
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
|
||||
#
|
||||
# worldobject.py
|
||||
# --------------------
|
||||
# date created : Tue Aug 7 2012
|
||||
# copyright : (C) 2012 Sakse Dalum
|
||||
# maintained by : Sakse Dalum <don_s@hongabar.org>
|
||||
|
||||
"""
|
||||
A generic world object.
|
||||
"""
|
||||
|
||||
import pygame
|
||||
import numpy
|
||||
import copy
|
||||
|
||||
class WorldObject(object):
|
||||
def __init__(self, level, x, y, z=0, z_px=0, direction=(1, 0), speed=4,
|
||||
tile_x=64, tile_y=48,
|
||||
movable=False, blocking=True, is_moving=False, visible=True,
|
||||
blit_area=None):
|
||||
self.__dict__.update(locals())
|
||||
|
||||
self.init_x = self.move_x = self.x = x - (x % self.tile_x)
|
||||
self.init_y = self.move_y = self.y = y - (y % self.tile_y)
|
||||
self.init_direction = self.move_direction = self.direction
|
||||
|
||||
self.holding = None
|
||||
self.holder = None
|
||||
|
||||
self.ignore_list = [WithBackground]
|
||||
|
||||
self.is_currently_opaque = True
|
||||
|
||||
if hasattr(self, 'img'):
|
||||
self.img = copy.copy(self.img)
|
||||
|
||||
def set_pos(self, x, y):
|
||||
self.move_x = self.x = x - (x % self.tile_x)
|
||||
self.move_y = self.y = y - (y % self.tile_y)
|
||||
|
||||
def set_init_pos(self):
|
||||
self.init_x, self.init_y = self.x, self.y
|
||||
self.init_direction = self.direction
|
||||
|
||||
def reset_pos(self):
|
||||
self.x, self.y = self.move_x, self.move_y = self.init_x, self.init_y
|
||||
self.direction = self.init_direction
|
||||
|
||||
def share_tile(self, obj_type):
|
||||
for obj in self.level.objects:
|
||||
if (obj.x - (obj.x % self.tile_x) == self.x - (self.x % self.tile_x)
|
||||
and obj.y - (obj.y % self.tile_y) == self.y - (self.y
|
||||
% self.tile_y)
|
||||
and obj is not self and isinstance(obj, obj_type)):
|
||||
return obj
|
||||
return None
|
||||
|
||||
def check_move(self, move_x, move_y):
|
||||
if self.move_x == self.x and self.move_y == self.y and self.movable:
|
||||
for obj in self.level.objects:
|
||||
if (obj.x == self.x + move_x * self.tile_x
|
||||
and obj.y == self.y + move_y * self.tile_y
|
||||
and obj is not self and obj is not self.holder
|
||||
and obj is not self.holding and obj.blocking
|
||||
and type(obj) not in self.ignore_list):
|
||||
return False
|
||||
return True
|
||||
return False
|
||||
|
||||
def move(self, move_x, move_y):
|
||||
if self.check_move(move_x, move_y):
|
||||
|
||||
if self.holding:
|
||||
if not self.holding.check_move(move_x, move_y):
|
||||
return False
|
||||
|
||||
self.move_x += move_x * self.tile_x
|
||||
self.move_y += move_y * self.tile_y
|
||||
|
||||
if self.holding:
|
||||
self.holding.move(move_x, move_y)
|
||||
|
||||
self.move_direction = self.move_x, self.move_y
|
||||
|
||||
return True
|
||||
return False
|
||||
|
||||
def use(self, obj):
|
||||
pass
|
||||
|
||||
def activate(self, setting):
|
||||
pass
|
||||
|
||||
def update_alpha(self):
|
||||
pass
|
||||
|
||||
def set_alpha(self, value):
|
||||
"""
|
||||
Set the relative translucency of the per-pixel-alpha image.
|
||||
|
||||
Value between 0 - 1, where 0 is completely transparent and 1 is
|
||||
completely opaque.
|
||||
"""
|
||||
if hasattr(self, 'img') and hasattr(self, 'orig_alpha'):
|
||||
alpha = pygame.surfarray.pixels_alpha(self.img)
|
||||
alpha[:] = (self.orig_alpha * value).astype(numpy.uint8)
|
||||
|
||||
def update(self, e, t, dt):
|
||||
if self.x > self.move_x:
|
||||
self.x -= min(self.speed * dt * self.tile_x,
|
||||
abs(self.x - self.move_x))
|
||||
if self.x < self.move_x:
|
||||
self.x += min(self.speed * dt * self.tile_x,
|
||||
abs(self.x - self.move_x))
|
||||
if self.y > self.move_y:
|
||||
self.y -= min(self.speed * dt * self.tile_y,
|
||||
abs(self.y - self.move_y))
|
||||
if self.y < self.move_y:
|
||||
self.y += min(self.speed * dt * self.tile_y,
|
||||
abs(self.y - self.move_y))
|
||||
|
||||
self.is_moving = self.x != self.move_x or self.y != self.move_y
|
||||
|
||||
self.x, self.y = int(self.x), int(self.y)
|
||||
|
||||
|
||||
|
||||
|
||||
class WithBackground(WorldObject):
|
||||
def __init__(self, level, img, x, y, z_px=0, blit_area=None):
|
||||
self.__dict__.update(locals())
|
||||
WorldObject.__init__(self, level, x, y, z_px=z_px, blit_area=blit_area)
|
||||
|
||||
def draw(self, window):
|
||||
window.blit(self.img, (self.x - 32 - self.level.camera_x,
|
||||
self.y - self.img.get_size()[1] + 24
|
||||
- self.level.camera_y + self.z_px),
|
||||
self.blit_area)
|
||||
Reference in New Issue
Block a user