from os.path import basename, join
from random import random, randrange, choice, randint
from glob import glob
from array import array
from pygame import PixelArray, Surface, Color, joystick
from pygame.event import clear, Event
from pygame.image import load, save
from pygame.transform import flip, scale
from pygame.mixer import Sound, set_num_channels, get_num_channels
from pygame.locals import *
from lib.pgfw.pgfw.Game import Game
from lib.pgfw.pgfw.GameChild import GameChild
from lib.pgfw.pgfw.Animation import Animation
from lib.pgfw.pgfw.Sprite import Sprite
from lib.pgfw.pgfw.extension import (get_color_swapped_surface, get_delta,
get_busy_channel_count)
class PictureProcessing(Game):
SCALE = 3
CHANNEL_COUNT = 16
KEYBOARD, GAMEPAD = xrange(2)
def __init__(self):
Game.__init__(self)
set_num_channels(self.CHANNEL_COUNT)
self.sound_effects = SoundEffects(self)
self.glyphs = Glyphs(self)
self.levels = Levels(self)
self.interface = Interface(self)
self.title = Title(self)
self.introduction = Introduction(self)
self.ending = Ending(self)
self.subscribe(self.respond)
self.reset()
clear()
def respond(self, event):
if self.delegate.compare(event, "reset-game"):
self.reset()
def reset(self):
self.title.reset()
self.levels.reset()
self.interface.reset()
self.introduction.reset()
self.ending.reset()
def get_progress(self):
return map(int, open(self.get_resource("progress")).read().split())
def write_progress(self, level_index, swap_count, update=False):
if update:
swap_count += self.get_progress()[1]
open(self.get_resource("progress"), "w").write("%s %s\n" % (str(level_index),
str(swap_count)))
def select_text(self, texts):
return texts[self.is_gamepad_mode()]
def is_gamepad_mode(self):
return not self.check_command_line("-keyboard") and joystick.get_count()
def update(self):
self.introduction.update()
self.title.update()
self.levels.update()
self.interface.update()
self.ending.update()
class SoundEffects(GameChild):
def __init__(self, parent):
GameChild.__init__(self, parent)
effects = self.effects = []
for path in glob(join(self.get_resource("aud/effect"), "*.wav")):
effects.append(SoundEffect(self, path))
def play(self, name, volume=None):
for effect in self.effects:
if effect.name == name:
effect.play(volume=volume)
class SoundEffect(GameChild, Sound):
DEFAULT_VOLUME = .5
def __init__(self, parent, path, volume=DEFAULT_VOLUME):
GameChild.__init__(self, parent)
Sound.__init__(self, path)
self.name = basename(path).split(".")[0]
self.display_surface = self.get_display_surface()
self.set_volume(volume)
def play(self, loops=0, maxtime=0, fade_ms=0, position=None, x=None, volume=None):
channel = Sound.play(self, loops, maxtime, fade_ms)
if x is not None:
position = float(x) / self.display_surface.get_width()
if position is not None and channel is not None:
channel.set_volume(*self.get_panning(position))
return channel
def get_panning(self, position):
return 1 - max(0, ((position - .5) * 2)), \
1 + min(0, ((position - .5) * 2))
class Glyphs(GameChild):
TILE_SIZE = 8
TRANSPARENT_COLOR = (255, 0, 255)
LETTER_COLOR = (255, 255, 255)
def __init__(self, parent):
GameChild.__init__(self, parent)
sheet = load(self.get_resource("font.png")).convert()
sheet.set_colorkey(sheet.get_at((0, 0)))
tiles = self.tiles = []
for y in xrange(0, sheet.get_height(), self.TILE_SIZE):
surface = Surface([self.TILE_SIZE] * 2)
surface.set_colorkey(self.TRANSPARENT_COLOR)
surface.fill(self.TRANSPARENT_COLOR)
surface.blit(sheet, (0, -y))
surface = scale(surface, [surface.get_width() * \
PictureProcessing.SCALE] * 2)
tiles.append(surface)
def get_surface_from_text(self, text, color=None, spacing=1,
key=TRANSPARENT_COLOR, background=None):
tw, th = self.tiles[0].get_size()
surface = Surface((len(text) * tw + spacing * len(text), th))
if background is None:
surface.set_colorkey(key)
surface.fill(key)
else:
surface.fill(background)
for ii, x in enumerate(xrange(0, surface.get_width(), tw + spacing)):
surface.blit(self.get_tile(ord(text[ii]), color), (x, 0))
return surface
def get_tile(self, index, color=None):
tile = self.tiles[index]
if color is not None:
tile = tile.copy()
pixels = PixelArray(tile)
pixels.replace(self.LETTER_COLOR, color)
del pixels
return tile
class Levels(GameChild):
CLIP_SETTINGS = ((.325, 5512), (.25, 11025), (.5, 11025), (.75, 11025), (.75, 11025))
def __init__(self, parent):
GameChild.__init__(self, parent)
levels = self.levels = []
for directory in sorted(glob(join(self.get_resource("tiles"),
"[0-9]*"))):
levels.append(Level(self, directory))
def reset(self):
self.deactivate()
self.current_level = self.levels[0]
def deactivate(self):
self.active = False
self.stop_audio()
self.get_game().interface.deactivate()
def activate(self):
self.active = True
def stop_audio(self):
for level in self.levels:
level.stop_all_audio()
def get_current_level_index(self):
return self.levels.index(self.current_level)
def is_final_level(self):
return self.get_current_level_index() == len(self.levels) - 1
def load_next_level(self):
self.levels[self.get_current_level_index() + 1].load()
def update(self):
if self.active:
self.current_level.update()
class Level(GameChild):
def __init__(self, parent, directory):
GameChild.__init__(self, parent)
self.display_surface = self.get_display_surface()
tiles = self.tiles = []
original = self.original_tiles = []
for path in sorted(glob(join(directory, "*.png"))):
original.append(load(path).convert_alpha())
tiles.append(scale(original[-1], [original[-1].get_width() * \
PictureProcessing.SCALE] * 2))
colored = self.colored_tiles = {}
rects = self.tile_rects = {}
block = 0
for line in open(join(directory, "map")):
if line.strip() == "":
block += 1
elif block == 0:
fields = line.split("-")
if len(fields) == 1:
self.default_tile_index = int(fields[0])
else:
for field in line.split("-"):
digits = map(int, field.split())
if len(digits) == 1:
index = digits[0]
rects[index] = []
elif len(digits) == 3:
surface = Surface(tiles[index].get_size())
surface.fill(digits)
surface.blit(tiles[index], (0, 0))
colored[index] = surface
else:
if len(digits) == 2:
digits *= 2
rects[index].append((digits[0:2], digits[2:4]))
path = glob(join(self.get_resource("aud/level"), basename(directory) + "*"))[0]
self.full_audio = Sound(path)
self.clip_audio = None
def load(self):
self.parent.activate()
self.parent.current_level = self
self.set_audio()
self.set_swap_status()
self.parent.stop_audio()
self.clip_audio.play(-1)
self.get_game().interface.setup()
def set_audio(self):
samples = array("h", self.full_audio.get_buffer().raw)
volume, count = Levels.CLIP_SETTINGS[self.parent.get_current_level_index()]
index = randrange(0, len(samples) - count)
clip = self.clip_audio = Sound(samples[index:index + count])
clip.set_volume(volume)
def set_swap_status(self):
swap_status = self.swap_status = {}
swapped = False
indicies = set(self.tile_rects.keys() + [self.default_tile_index])
while not swapped:
available_swap_positions = indicies.copy()
for index in indicies:
if len(available_swap_positions) == 1 and \
list(available_swap_positions)[0] == index:
break
while True:
swap_status[index] = choice(list(available_swap_positions))
if swap_status[index] != index:
break
available_swap_positions.remove(swap_status[index])
if not available_swap_positions:
swapped = True
break
def stop_all_audio(self):
if self.clip_audio:
self.clip_audio.stop()
self.full_audio.stop()
def is_solved(self):
return all(index == position for index, position in self.swap_status.iteritems())
def update(self):
ds = self.display_surface
for xi, x in enumerate(xrange(0, ds.get_width(),
self.tiles[0].get_width())):
for yi, y in enumerate(xrange(0, ds.get_height(),
self.tiles[0].get_height())):
current_tile_index = self.default_tile_index
for tile_index, rects in self.tile_rects.iteritems():
found = False
for rect in rects:
if rect[0][0] <= xi <= rect[1][0] and rect[0][1] <= yi \
<= rect[1][1]:
current_tile_index = tile_index
found = True
break
if found:
break
swap_index = self.swap_status[current_tile_index]
if swap_index in self.colored_tiles.keys():
tile = self.colored_tiles[swap_index]
else:
tile = self.tiles[swap_index]
ds.blit(tile, (x, y))
class Interface(Animation):
BLINK_INTERVAL = 400
OPEN_TEXT = "ENTER: EDIT MEMORY", "A: EDIT MEMORY"
CELL_ALPHA = 240
OPEN_TEXT_OFFSET = 36
MAX_TILE_COUNT = 16
CELL_INDENT = 32
CELL_MARGIN = 56
CELL_VERTICAL_PADDING = 8
BACKGROUND = 0, 0, 0
TEXT_COLOR = 255, 255, 255
NAME_CHARACTER = "$"
CELL_INDICATOR = 16
CELL_INDICATOR_OFFSET = 2
SHADOW_COLOR = 255, 255, 255
SHADOW_OFFSET = -1, 1
SWAP_INDICATOR = 16
ADVANCE_TEXT = "PRESS ENTER", "PRESS START"
SWAP_TEXT = "ENT: SWAP", "A: SWAP"
HIDE_TEXT = "ESC: HIDE", "B: HIDE"
MOVE_TEXT = ": MOVE"
PLAY_SONG_DELAY = 1000
UNSUPPRESS_ADVANCE_DELAY = 2000
MOVE_ICONS = 24, 25, 26, 27
def __init__(self, parent):
Animation.__init__(self, parent)
ds = self.display_surface = self.get_display_surface()
glyphs = self.get_game().glyphs
open_plate = self.open_plate = Sprite(self)
open_plate.add_frame(glyphs.get_surface_from_text(self.get_game().select_text(self.OPEN_TEXT),
background=(0, 0, 0)))
open_plate.location.midbottom = ds.get_rect().centerx, ds.get_height() - \
self.OPEN_TEXT_OFFSET
self.cell_frames = cell_frames = []
tile_size = glyphs.get_tile(0).get_width()
for ii in xrange(self.MAX_TILE_COUNT):
title = ("%s%02x" % (self.NAME_CHARACTER, ii)).upper()
title_surface = glyphs.get_surface_from_text(title, self.TEXT_COLOR)
frame = Surface((self.CELL_INDENT * 2 + title_surface.get_width() + \
self.CELL_MARGIN + tile_size,
self.CELL_VERTICAL_PADDING * 2 + tile_size))
frame.fill(self.BACKGROUND)
frame.blit(title_surface, (self.CELL_INDENT, self.CELL_VERTICAL_PADDING))
cell_frames.append(Sprite(self))
cell_frames[-1].add_frame(frame)
cell_frames[-1].set_alpha(self.CELL_ALPHA)
indicator = self.cell_indicator = Sprite(self)
indicator.add_frame(glyphs.get_tile(self.CELL_INDICATOR, self.TEXT_COLOR))
indicator = self.swap_indicator = Sprite(self)
indicator.add_frame(glyphs.get_tile(self.SWAP_INDICATOR, self.TEXT_COLOR))
shadow = self.tile_shadow = Surface([tile_size] * 2)
shadow.fill(self.SHADOW_COLOR)
advance_plate = self.advance_plate = Sprite(self)
advance_plate.add_frame(glyphs.get_surface_from_text(self.get_game().select_text(self.ADVANCE_TEXT),
background=(0, 0, 0)))
advance_plate.location.midbottom = open_plate.location.midbottom
swap_plate = self.swap_plate = Sprite(self)
text = self.SWAP_TEXT[1]
swap_plate.add_frame(glyphs.get_surface_from_text(self.get_game().select_text(self.SWAP_TEXT),
background=(0, 0, 0)))
swap_plate.set_alpha(self.CELL_ALPHA)
move_plate = self.move_plate = Sprite(self)
text_surface = glyphs.get_surface_from_text(self.MOVE_TEXT,
background=(0, 0, 0))
frame = Surface((tile_size * len(self.MOVE_ICONS) + text_surface.get_width(),
tile_size))
x = 0
for index in self.MOVE_ICONS:
frame.blit(glyphs.get_tile(index), (x, 0))
x += tile_size
frame.blit(text_surface, (x, 0))
move_plate.add_frame(frame)
move_plate.set_alpha(self.CELL_ALPHA)
move_plate.location.midtop = ds.get_width() / 2, 0
hide_plate = self.hide_plate = Sprite(self)
hide_plate.add_frame(glyphs.get_surface_from_text(self.get_game().select_text(self.HIDE_TEXT),
background=(0, 0, 0)))
hide_plate.set_alpha(self.CELL_ALPHA)
hide_plate.location.topright = ds.get_width(), 0
self.register(self.blink, interval=self.BLINK_INTERVAL)
self.register(self.play_song)
self.register(self.unsuppress_advance)
self.subscribe(self.respond)
def blink(self):
if self.closed and not self.solved:
self.open_plate.toggle_hidden()
if not self.closed and self.swapping_index is not None:
self.swap_indicator.toggle_hidden()
if self.solved and not self.suppressing_commands:
self.advance_plate.toggle_hidden()
def respond(self, event, suppress_sound=False):
if self.active and not self.suppressing_commands:
delegate = self.get_game().delegate
effects = self.get_game().sound_effects
is_pad_mode = self.get_game().is_gamepad_mode()
if self.closed and not self.solved and delegate.compare(event, "action"):
effects.play("memory")
self.unclose()
elif self.closed and self.solved and (delegate.compare(event, "advance") or \
(not is_pad_mode and delegate.compare(event, "action"))):
effects.play("go")
if self.get_game().levels.is_final_level():
self.get_game().ending.activate()
self.get_game().levels.deactivate()
else:
self.get_game().levels.load_next_level()
elif not self.closed:
if delegate.compare(event, "cancel"):
effects.play("cancel")
self.close()
elif delegate.compare(event, "action"):
if self.swapping_index is None:
effects.play("start")
self.swapping_index = self.cell_index
self.set_indicator_position(False)
self.respond(Event(delegate.command_event_id,
{"command": "down", "cancel": False}), True)
else:
if self.cell_index == self.swapping_index:
effects.play("cancel")
else:
level = self.get_game().levels.current_level
status = level.swap_status
temp = status[self.swapping_index]
status[self.swapping_index] = status[self.cell_index]
status[self.cell_index] = temp
self.swap_count += 1
if not level.is_solved():
effects.play("swap")
else:
effects.play("clear")
if not self.get_game().levels.is_final_level():
self.get_game().write_progress(self.get_game().levels.\
get_current_level_index() + 1,
self.swap_count, True)
else:
self.get_game().ending.\
set_swap_count(self.get_game().get_progress()[1] + \
self.swap_count)
self.get_game().write_progress(0, 0)
self.suppressing_commands = True
self.solved = True
self.play(self.play_song, delay=self.PLAY_SONG_DELAY, play_once=True)
self.swapping_index = None
elif delegate.compare(event, ["up", "down", "left", "right"]):
if not suppress_sound:
effects.play("menu-move")
cell_count = self.get_cell_count()
bp = (cell_count - 1) / 2
if delegate.compare(event, "up"):
self.cell_index -= 1
if self.cell_index == -1:
self.cell_index = bp
elif self.cell_index == bp:
self.cell_index = cell_count - 1
elif delegate.compare(event, "down"):
self.cell_index += 1
if self.cell_index == bp + 1:
self.cell_index = 0
elif self.cell_index == cell_count:
self.cell_index = bp + 1
elif delegate.compare(event, "left"):
if self.cell_index == 0:
self.cell_index = bp + 1
elif self.cell_index > bp:
self.cell_index -= bp + 1
else:
self.cell_index += bp
if self.cell_index == cell_count:
self.cell_index -= 1
elif delegate.compare(event, "right"):
if self.cell_index == cell_count - 1:
self.cell_index = bp
elif self.cell_index <= bp:
self.cell_index += bp + 1
if self.cell_index == cell_count:
self.cell_index -= 1
else:
self.cell_index -= bp
self.set_indicator_position()
def play_song(self):
self.close()
level = self.get_game().levels.current_level
level.clip_audio.stop()
level.full_audio.play(-1)
self.play(self.unsuppress_advance, delay=self.UNSUPPRESS_ADVANCE_DELAY,
play_once=True)
def unsuppress_advance(self):
self.suppressing_commands = False
self.advance_plate.unhide()
def set_indicator_position(self, cell=True):
if cell:
indicator = self.cell_indicator
else:
indicator = self.swap_indicator
indicator.location.midleft = self.cell_frames[self.cell_index].location.\
midleft
indicator.location.left += self.CELL_INDICATOR_OFFSET
def get_cell_count(self):
return len(self.get_game().levels.current_level.swap_status)
def reset(self):
self.deactivate()
self.solved = False
self.close()
self.halt()
self.suppressing_commands = False
def deactivate(self):
self.active = False
def setup(self):
self.activate()
self.close()
cell_count = self.get_cell_count()
left_count = cell_count / 2 + cell_count % 2
right_count = cell_count / 2
sw, sh = self.display_surface.get_size()
step = sh / (left_count + 1)
frames = self.cell_frames
index = 0
for y in xrange(step, step * (left_count + 1), step):
frames[index].location.midleft = 0, y
index += 1
step = sh / (right_count + 1)
for y in xrange(step, step * (right_count + 1), step):
frames[index].location.midright = sw, y
index += 1
self.cell_index = 0
self.set_indicator_position()
self.swapping_index = None
self.swap_count = 0
self.suppressing_commands = False
self.solved = False
self.advance_plate.hide()
self.play(self.blink)
def activate(self):
self.active = True
def close(self):
self.closed = True
if not self.solved:
self.open_plate.unhide()
def unclose(self):
self.closed = False
self.open_plate.hide()
def update(self):
Animation.update(self)
if self.active:
self.open_plate.update()
self.advance_plate.update()
if not self.closed:
for frame in self.cell_frames[:self.get_cell_count()]:
frame.update()
self.cell_indicator.update()
if self.swapping_index is not None:
self.swap_indicator.update()
level = self.get_game().levels.current_level
for index, position in level.swap_status.iteritems():
if position in level.colored_tiles.keys():
tile = level.colored_tiles[position]
else:
tile = level.tiles[position]
rect = tile.get_rect()
frame = self.cell_frames[index]
rect.topright = frame.location.right - self.CELL_INDENT, \
frame.location.top + self.CELL_VERTICAL_PADDING
self.display_surface.blit(self.tile_shadow, rect.move(self.SHADOW_OFFSET))
self.display_surface.blit(tile, rect)
self.swap_plate.update()
self.hide_plate.update()
self.move_plate.update()
class Title(Animation):
BLINK_INTERVAL = 400
MENU_OFFSET = 100
MENU_WIDTH = 440
BACKGROUND_SIZE = 40
ADVANCE_TEXT = "PRESS ENTER", "PRESS START"
MENU_OPTIONS = "NEW GAME", "CONTINUE"
MENU_MARGIN = 12
MENU_PADDING = 16
TRANSPARENT_COLOR = (128, 128, 128)
TURN_PROBABILITY = .0001
SCROLL_SPEED = 2
BACKGROUND_BACKGROUND = (0, 0, 0)
BACKGROUND_FRAME_COUNT = 1
BACKGROUND_FRAMERATE = 200
MENU_INDICATOR_LOCATION = 224
CHUNK_PROBABILITY = .5
CHUNK_VOLUME = .1
def __init__(self, parent):
Animation.__init__(self, parent)
self.display_surface = self.get_display_surface()
self.set_audio()
self.set_advance_plate()
self.register(self.blink, interval=self.BLINK_INTERVAL)
self.subscribe(self.respond)
self.play(self.blink)
def set_audio(self):
self.audio_loop = Sound(self.get_resource("aud/title.wav"))
chunks = self.audio_chunks = []
for path in glob(join(self.get_resource("aud/chunk"), "*.ogg")):
chunks.append(Sound(path))
chunks[-1].set_volume(self.CHUNK_VOLUME)
self.advance_effect = SoundEffect(self, "start")
self.move_effect = SoundEffect(self, "menu-move")
self.cancel_effect = SoundEffect(self, "cancel")
def set_advance_plate(self):
offset = 0
plate = self.advance_plate = Sprite(self, self.BLINK_INTERVAL)
plate.add_frame(self.get_game().glyphs.\
get_surface_from_text(self.get_game().select_text(self.ADVANCE_TEXT),
(255, 255, 255), background=(0, 0, 0)))
rect = self.display_surface.get_rect()
plate.location.center = rect.centerx, rect.bottom - self.MENU_OFFSET
def blink(self):
self.advance_plate.toggle_hidden()
def reset(self):
self.set_background()
self.activate()
self.advance_pressed = False
self.advance_plate.unhide()
self.set_scroll_step()
self.menu_index = 0
def set_background(self):
tiles = []
for level in self.get_game().levels.levels:
tiles.extend(level.tiles)
background = self.background = Sprite(self, self.BACKGROUND_FRAMERATE)
tw = tiles[0].get_width()
frames = []
for _ in xrange(self.BACKGROUND_FRAME_COUNT):
frames.append(Surface([self.BACKGROUND_SIZE * tw] * 2))
frames[-1].fill(self.BACKGROUND_BACKGROUND)
for x in xrange(0, frames[0].get_width(), tw):
for y in xrange(0, frames[0].get_width(), tw):
for frame in frames:
tile = choice(tiles)
if random() >= .5:
inverted = Surface((tw, tw))
inverted.fill((255, 255, 255))
inverted.blit(tile, (0, 0), None, BLEND_SUB)
tile = inverted
fx, fy = random() >= .5, random() >= .5
if fx or fy:
tile = flip(tile, fx, fy)
frame.blit(tile, (x, y))
for frame in frames:
background.add_frame(frame)
background.add_location(offset=(background.location.w, 0))
background.add_location(offset=(0, background.location.h))
background.add_location(offset=(background.location.w,
background.location.h))
def activate(self):
self.active = True
# self.audio_loop.play(-1)
self.set_menu()
def set_menu(self):
glyphs = self.get_game().glyphs
if self.get_game().get_progress()[0] > 0:
option_texts = self.MENU_OPTIONS
else:
option_texts = self.MENU_OPTIONS[:1]
height = glyphs.get_tile(0).get_height() * len(option_texts) + \
self.MENU_MARGIN * (len(option_texts) - 1) + \
self.MENU_PADDING * 2 + 3
background = self.menu_background = Surface((int(self.MENU_WIDTH),
height))
background.fill((0, 0, 0))
rect = self.menu_rect = background.get_rect()
rect.center = self.advance_plate.location.center
options = self.options = []
for option in option_texts:
options.append(Sprite(self))
options[-1].add_frame(glyphs.get_surface_from_text(option))
options[-1].location.centerx = rect.centerx
options[-1].location.top = rect.top + self.MENU_PADDING + \
(len(options) - 1) * options[0].location.h + \
(len(options) - 1) * self.MENU_MARGIN
indicator = self.indicator = Sprite(self)
indicator.add_frame(self.get_game().glyphs.get_tile(16))
def set_scroll_step(self):
self.scroll_step = get_delta(randrange(0, 360), self.SCROLL_SPEED)
def respond(self, event):
if self.active:
delegate = self.get_game().delegate
if not self.advance_pressed:
if delegate.compare(event, "advance") or not self.get_game().is_gamepad_mode() and \
delegate.compare(event, "action"):
self.advance_pressed = True
self.get_game().sound_effects.play("start")
elif delegate.compare(event, "cancel"):
self.get_game().sound_effects.play("cancel")
else:
if delegate.compare(event, "cancel"):
self.get_game().sound_effects.play("cancel")
self.advance_pressed = False
elif delegate.compare(event, "up"):
self.get_game().sound_effects.play("menu-move")
self.menu_index -= 1
elif delegate.compare(event, "down"):
self.get_game().sound_effects.play("menu-move")
self.menu_index += 1
elif delegate.compare(event, "advance") or not self.get_game().is_gamepad_mode() and \
delegate.compare(event, "action"):
self.get_game().sound_effects.play("start")
if self.menu_index == 0:
self.deactivate()
self.get_game().introduction.load()
self.get_game().write_progress(0, 0)
elif self.menu_index == 1:
self.deactivate()
self.get_game().levels.\
levels[self.get_game().get_progress()[0]].load()
else:
pass
event.dict["command"] = ""
if self.menu_index < 0:
self.menu_index = len(self.options) - 1
elif self.menu_index >= len(self.options):
self.menu_index = 0
def deactivate(self):
self.active = False
self.audio_loop.stop()
def update(self):
Animation.update(self)
if self.active:
if random() < self.TURN_PROBABILITY:
self.set_scroll_step()
self.background.move(*self.scroll_step)
if self.background.location.top > 0:
self.background.move(dy=-self.background.location.h)
if self.background.location.right < 0:
self.background.move(self.background.location.w)
if self.background.location.bottom < 0:
self.background.move(dy=self.background.location.h)
if self.background.location.left > 0:
self.background.move(-self.background.location.w)
self.background.update()
if not self.advance_pressed:
self.advance_plate.update()
else:
self.display_surface.blit(self.menu_background, self.menu_rect)
for option in self.options:
option.update()
self.indicator.location.centery = self.options[self.menu_index]\
.location.centery
self.indicator.location.right = self.MENU_INDICATOR_LOCATION
self.indicator.update()
if random() < self.CHUNK_PROBABILITY and \
get_busy_channel_count() < get_num_channels() - 5:
for _ in xrange(randint(1, 4)):
chunk = choice(self.audio_chunks)
channel = chunk.play()
if channel is not None:
channel.set_volume(random(), random())
class Introduction(Animation):
BACKGROUND = (0, 0, 0)
TEXT_COLOR = (255, 255, 255)
INDICATOR_INDEX = 31
TEXT = "MEDITATING.", "MEDITATING..", "MEDITATING...", \
"MANIPULATION OF THE/SYSTEM'S PPU GRANTED"
INDENT = 48
OFFSET = 128
MARGIN = 12
BLINK_INTERVAL = 400
def __init__(self, parent):
Animation.__init__(self, parent)
ds = self.display_surface = self.get_display_surface()
background = self.background = Surface(ds.get_size())
background.fill(self.BACKGROUND)
blocks = self.blocks = []
glyphs = self.get_game().glyphs
tile_height = glyphs.get_tile(0).get_height()
for block in self.TEXT:
blocks.append([])
for ii, line in enumerate(block.split("/")):
plate = Sprite(self)
plate.add_frame(glyphs.\
get_surface_from_text(line, self.TEXT_COLOR,
background=self.BACKGROUND))
plate.location.left = self.INDENT
plate.location.top = ds.get_height() - self.OFFSET + ii * \
(tile_height + self.MARGIN)
blocks[-1].append(plate)
indicator = self.indicator = Sprite(self)
indicator.add_frame(glyphs.get_tile(self.INDICATOR_INDEX, self.TEXT_COLOR))
indicator.location.top = ds.get_height() - self.OFFSET + 2 * \
(tile_height + self.MARGIN)
indicator.location.right = ds.get_width() - self.INDENT
self.register(self.blink, interval=self.BLINK_INTERVAL)
self.subscribe(self.respond)
self.play(self.blink)
def respond(self, event):
if self.active:
if self.get_game().delegate.compare(event, "action"):
self.block_index += 1
if self.block_index == len(self.blocks):
self.get_game().sound_effects.play("go")
self.deactivate()
self.get_game().levels.levels[0].load()
elif self.block_index == len(self.blocks) - 1:
self.get_game().sound_effects.play("granted")
else:
self.get_game().sound_effects.play("next")
def deactivate(self):
self.active = False
def load(self):
self.activate()
self.block_index = 0
self.indicator.unhide()
def activate(self):
self.active = True
def blink(self):
self.indicator.toggle_hidden()
def reset(self):
self.deactivate()
def update(self):
Animation.update(self)
if self.active:
ds = self.display_surface
ds.blit(self.background, (0, 0))
for block in self.blocks[self.block_index]:
block.update()
self.indicator.update()
class Ending(Animation):
GLYPH_RANGE = 1, 31
SCROLL_SPEED = 2
TURN_PROBABILITY = .0001
PLATE_SIZE = 312, 72
PLATE_BACKGROUND = 0, 0, 0
TEXT_COLOR = 255, 255, 255
END_TEXT = "THE END!"
SWAP_COUNT_TEXT = "SWAPS:"
UNSUPPRESS_DELAY = 1000
def __init__(self, parent):
Animation.__init__(self, parent)
ds = self.display_surface = self.get_display_surface()
end_plate = self.end_plate = Sprite(self)
frame = Surface(self.PLATE_SIZE)
frame.fill(self.PLATE_BACKGROUND)
text_surface = self.get_game().glyphs.get_surface_from_text(self.END_TEXT,
self.TEXT_COLOR)
rect = text_surface.get_rect()
rect.center = frame.get_rect().center
frame.blit(text_surface, rect)
end_plate.add_frame(frame)
end_plate.location.center = ds.get_rect().centerx, 3 * ds.get_height() / 8
self.audio = Sound(self.get_resource("aud/end.ogg"))
self.subscribe(self.respond)
self.register(self.unsuppress_advance)
def respond(self, event):
if self.active and not self.suppress_commands and \
((self.get_game().is_gamepad_mode() and self.get_game().delegate.compare(event, "advance")) or \
(not self.get_game().is_gamepad_mode() and self.get_game().delegate.compare(event, "action"))):
self.deactivate()
self.get_game().reset()
def unsuppress_advance(self):
self.suppress_commands = False
def set_swap_count(self, count):
self.swap_count = count
def reset(self):
self.deactivate()
self.halt()
def deactivate(self):
self.active = False
self.audio.stop()
def activate(self):
self.active = True
self.set_swap_plate()
self.set_background()
self.set_scroll_step()
self.suppress_commands = True
self.play(self.unsuppress_advance, delay=self.UNSUPPRESS_DELAY,
play_once=True)
self.audio.play(-1)
def set_swap_plate(self):
swap_count_plate = self.swap_count_plate = Sprite(self)
frame = Surface(self.PLATE_SIZE)
frame.fill(self.PLATE_BACKGROUND)
text_surface = self.get_game().glyphs.\
get_surface_from_text("%s %i" % (self.SWAP_COUNT_TEXT,
self.swap_count), self.TEXT_COLOR)
rect = text_surface.get_rect()
rect.center = frame.get_rect().center
frame.blit(text_surface, rect)
swap_count_plate.add_frame(frame)
swap_count_plate.location.center = self.display_surface.get_rect().centerx, \
5 * self.display_surface.get_height() / 8
def set_background(self):
background = self.background = Sprite(self)
glyphs = self.get_game().glyphs
tw = glyphs.get_tile(0).get_width()
ds = self.get_display_surface()
frame = Surface(ds.get_size())
for xi, x in enumerate(xrange(0, ds.get_width(), tw)):
for yi, y in enumerate(xrange(0, ds.get_height(), tw)):
background_color = Color(0, 0, 0)
background_color.hsla = randrange(0, 360), 100, 50, 100
foreground_color = Color(0, 0, 0)
foreground_color.hsla = (background_color.hsla[0] + 180) % 360, \
100, 50, 100
surface = Surface([tw] * 2)
surface.fill(background_color)
surface.blit(glyphs.get_tile(randint(*self.GLYPH_RANGE)), (0, 0))
frame.blit(surface, (x, y))
background.add_frame(frame)
background.add_location(offset=(background.location.w, 0))
background.add_location(offset=(0, background.location.h))
background.add_location(offset=(background.location.w,
background.location.h))
def set_scroll_step(self):
self.scroll_step = get_delta(randrange(0, 360), self.SCROLL_SPEED)
def update(self):
Animation.update(self)
if self.active:
if random() < self.TURN_PROBABILITY:
self.set_scroll_step()
self.background.move(*self.scroll_step)
if self.background.location.top > 0:
self.background.move(dy=-self.background.location.h)
if self.background.location.right < 0:
self.background.move(self.background.location.w)
if self.background.location.bottom < 0:
self.background.move(dy=self.background.location.h)
if self.background.location.left > 0:
self.background.move(-self.background.location.w)
self.background.update()
self.end_plate.update()
self.swap_count_plate.update()