from os import listdir
from glob import glob
from random import choice
from collections import deque
from pygame import cursors, PixelArray, Surface, Color
from pygame.mouse import set_cursor, get_pos
from pygame.font import Font
from pygame.image import load
from pygame.draw import polygon, aalines
from pygame.locals import *
from shaken_and_spit_out.pgfw.Game import Game
from shaken_and_spit_out.pgfw.GameChild import GameChild
from shaken_and_spit_out.pgfw.Sprite import Sprite
from shaken_and_spit_out.pgfw.Animation import Animation
class SSO(Game):
def __init__(self):
Game.__init__(self)
set_cursor(*cursors.tri_left)
# string = u"\u2250\u2254\u2258"
# font = Font(self.get_resource("display", "font"), 24)
# self.message = font.render(string, True, (0, 255, 0))
self.backgrounds = [load(path).convert() for path in \
glob(self.get_resource("image", "background") + \
"*.png")]
self.used_backgrounds = []
self.set_random_background()
self.subscribe(self.respond)
self.title.activate()
def set_children(self):
Game.set_children(self)
self.floor = Floor(self)
self.title = Title(self)
self.cloud = Cloud(self)
def set_random_background(self):
index = choice(list(set(range(len(self.backgrounds))).\
difference(self.used_backgrounds)))
self.used_backgrounds.append(index)
if len(self.used_backgrounds) > 3:
self.used_backgrounds.pop(0)
self.background = self.backgrounds[index]
def respond(self, event):
if self.delegate.compare(event, "reset-game"):
self.set_random_background()
def update(self):
self.get_screen().blit(self.background, (0, 0))
self.cloud.update()
self.title.update()
self.floor.update()
# self.get_screen().fill((0, 0, 0))
# self.get_screen().blit(self.message, (100, 100))
class Title(GameChild):
def __init__(self, parent):
GameChild.__init__(self, parent)
self.delegate = self.get_delegate()
self.preface = Preface(self)
self.preamble = Preamble(self)
self.initializer = Initializer(self)
self.subscribe(self.respond)
self.subscribe(self.respond, MOUSEBUTTONDOWN)
self.deactivate()
def respond(self, event):
if self.delegate.is_command(event) and \
self.delegate.compare(event, "reset-game"):
self.activate()
def deactivate(self):
self.active = True
def activate(self):
self.active = True
self.preface.reset()
self.preamble.reset()
def update(self):
if self.active:
self.preface.update()
self.preamble.update()
self.initializer.update()
class Initializer(Sprite):
def __init__(self, parent):
Sprite.__init__(self, parent)
self.load_from_path(self.get_resource("image", "initializer"),
query="[0-9]*.png", omit=True)
self.add_frameset(0, name="idle")
self.add_frameset(1, name="pressed")
self.add_frameset((0, 2), (340, 40), "blinking")
self.set_frameset("idle")
self.location.center = 380, 500
self.subscribe(self.respond, MOUSEBUTTONDOWN)
self.subscribe(self.respond, MOUSEBUTTONUP)
def respond(self, event):
if self.parent.active:
if event.type == MOUSEBUTTONDOWN and self.collides_mouse():
self.set_frameset("pressed")
elif event.type == MOUSEBUTTONUP:
self.set_frameset("idle")
def collides_mouse(self):
return self.location.collidepoint(get_pos())
def update(self):
if self.parent.active:
name = self.get_current_frameset().name
if name == "idle" and self.collides_mouse():
self.set_frameset("blinking")
elif name == "blinking" and not self.collides_mouse():
self.set_frameset("idle")
Sprite.update(self)
class Preface(GameChild, Surface):
def __init__(self, parent):
GameChild.__init__(self, parent)
ds = self.ds = self.get_display_surface()
w, h = ds.get_width(), int(round(ds.get_width() / 3))
Surface.__init__(self, (w, h), SRCALPHA)
self.background = Surface((w, h))
self.background.fill((0, 0, 0))
mask = self.mask = Surface((w, h), SRCALPHA)
pixels = PixelArray(mask)
for y in xrange(h):
alpha = int(round(255 - (float(y) / h) * 255))
for x in xrange(w):
pixels[x][y] = Color(255, 255, 255, alpha)
del pixels
self.set_text()
self.reset()
def set_text(self):
lines = self.get_configuration("text", "preface",
False).decode("unicode-escape").upper().\
split("/")
cc = 0
for line in lines:
if len(line) > cc:
cc = len(line)
cw = int(round((self.get_width() - 80) / float(cc)))
font = Font(self.get_resource("display", "font"), 12)
font.set_bold(True)
ch = font.metrics(lines[0][0])[0][3]
margin = 24
surface = Surface((cw * cc,
ch * len(lines) + margin * (len(lines) - 1)),
SRCALPHA)
text = self.text = Sprite(self, 200)
text.display_surface = self
magic_word = u"PS\u27A2;' P\u2591T"
magic_colors = deque(((255, 128, 128), (255, 255, 128), (128, 255, 128),
(128, 255, 255), (128, 128, 255),
(255, 128, 255)))
box_rect = Rect(0, 0, cw, ch)
for _ in xrange(len(magic_word)):
frame = surface.copy()
box_rect.top = 0
for line in lines:
box_rect.left = 0
extra = cc - len(line)
space_count = 0
for char in line:
if char == " ":
space_count += 1
if space_count:
space_widths = [1 + extra / space_count] * space_count
for ii in xrange(len(space_widths)):
if ii >= (extra % space_count):
break
space_widths[ii] += 1
magic_word_ii = 0
for ii in xrange(len(line)):
if line != lines[-1] and line[ii] == " ":
box_rect.left += cw * space_widths.pop(-1)
else:
if (magic_word_ii and \
magic_word_ii < len(magic_word)) \
or line[ii:ii + len(magic_word)] == magic_word:
color = magic_colors[0]
magic_colors.rotate(-1)
magic_word_ii += 1
else:
color = (255, 255, 255)
left = font.render(line[ii], True, (255, 0, 0))
frame.blit(left, self.get_glyph_rect(left, box_rect, 0))
right = font.render(line[ii], True, (0, 0, 255))
frame.blit(right, self.get_glyph_rect(right, box_rect,
4))
glyph = font.render(line[ii], True, color)
frame.blit(glyph, self.get_glyph_rect(glyph, box_rect,
2))
box_rect.left += cw
box_rect.top += ch + margin
text.add_frame(frame)
magic_colors.rotate(-1)
text.location.centerx = self.get_width() / 2
def get_glyph_rect(self, glyph, box_rect, offset):
gr = glyph.get_rect()
gr.center = box_rect.center
gr.left += offset
return gr
def reset(self):
self.text.location.top = self.get_height()
def update(self):
self.text.move(dy=-.5)
if self.text.location.bottom < 0:
self.reset()
self.blit(self.background, (0, 0))
self.text.update()
self.blit(self.mask, (0, 0), None, BLEND_RGBA_MIN)
self.ds.blit(self, (0, 0))
class Preamble(Animation):
def __init__(self, parent):
Animation.__init__(self, parent, self.increment_plate_index, 4000)
plates = self.plates = []
font = Font(self.get_resource("display", "font"), 12)
font.set_bold(True)
for line in self.get_configuration("text", "preamble",
False).upper().split("/"):
plates.append([])
spaced = str(line[0])
for character in line[1:]:
spaced += " " + character
for ii, color in enumerate(((0, 255, 255), (0, 255, 255),
(255, 12, 64))):
text = Sprite(self)
text.add_frame(font.render(spaced, True, color))
fr = self.get_game().floor.location
text.location.midtop = fr.centerx + (-1, 1, 0)[ii], \
fr.bottom + 10
plates[-1].append(text)
self.reset()
self.play()
def increment_plate_index(self):
index = self.plate_index + 1
if index >= len(self.plates):
index = 0
self.plate_index = index
def reset(self):
self.plate_index = 0
def update(self):
Animation.update(self)
for text in self.plates[self.plate_index]:
text.update()
class Arrow(Sprite):
def __init__(self, parent):
Sprite.__init__(self, parent, 360)
w, h = 56, 39
surface = Surface((w, h), SRCALPHA)
for color in ((255, 255, 0, 200), (0, 255, 255, 200), (255, 0, 255, 200)):
frame = surface.copy()
for offset in (0, 5):
points = [[int(round(val)) for val in coordinate] for
coordinate in self.get_coordinates(w - 10, h, offset)]
if offset == 5:
color = Color(*color)
hue, s, l, a = color.hsla
color.hsla = (hue + 180) % 360, 50, 100, 100
polygon(frame, color, points)
self.add_frame(frame)
floor = self.get_game().floor.location
self.location.midbottom = int(floor.w * .75), floor.top - 8
def get_coordinates(self, w, h, offset):
return (w * .25 + offset, 0), (w * .75 + offset, 0), \
(w * .75 + offset, h * .62), (w - 1 + offset, h * .62), \
(w * .5 + offset, h - 1), (0 + offset, h * .62), \
(w * .25 + offset, h * .62)
class Floor(Sprite):
transparent_color = 255, 0, 255
def __init__(self, parent):
Sprite.__init__(self, parent, (520, 80))
base = load(self.get_resource("image", "brick")).convert()
ds = self.ds = self.get_display_surface()
surface = Surface((ds.get_width(), 17))
surface.set_colorkey(self.transparent_color)
for swap in False, True:
frame = surface.copy()
tile = base.copy()
if swap:
pixels = PixelArray(tile)
foreground, background = pixels[1][1], pixels[0][0]
for x in xrange(len(pixels)):
for y in xrange(len(pixels[0])):
if pixels[x][y] == foreground:
pixels[x][y] = background
else:
pixels[x][y] = foreground
del pixels
for x in xrange(0, frame.get_width(), tile.get_width()):
for y in xrange(0, frame.get_height(), tile.get_height()):
frame.blit(tile, (x, y))
self.add_frame(frame)
self.location.bottom = self.ds.get_height() - 34
hole = self.hole = Sprite(self)
def explode(self, x):
pass
class Cloud(GameChild):
def __init__(self, parent):
GameChild.__init__(self, parent)
self.ds = self.get_display_surface()
layers = self.layers = []
base = load(self.get_resource("image", "cloud")).convert_alpha()
for ii in xrange(3):
layer = Sprite(self)
frame = base.copy()
pixels = PixelArray(frame)
for x in xrange(len(pixels)):
for y in xrange(len(pixels[0])):
color = Color(*base.unmap_rgb(pixels[x][y]))
h, s, l, a = color.hsla
color.hsla = int((h + (0, 90, 180)[ii]) % 360), int(s), \
int(l), int(a * (.95 * (1 - ii * .15)))
pixels[x][y] = color
del pixels
layer.add_frame(frame)
layer.move((0, -5, 5)[ii])
layer.location.bottom = self.ds.get_height()
layer.add_location(offset=(0, -layer.location.h))
layers.append(layer)
def update(self):
fr = self.get_game().floor.location
ds = self.ds
ds.set_clip(fr.topleft, (ds.get_width(), ds.get_height() - fr.top))
for ii, layer in enumerate(self.layers):
layer.move(dy=1 + (ii * .5))
if layer.location.top > ds.get_height():
layer.move(dy=-layer.location.h)
layer.update()
ds.set_clip(None)