from math import ceil
from collections import deque

from pygame import Surface
from pygame.draw import polygon
from pygame.locals import *

from lib.pgfw.pgfw.Sprite import Sprite

class ExitArrow(Sprite):

    def __init__(self, parent):
        Sprite.__init__(self, parent)
        self.load_configuration()
        self.set_mask()
        self.set_hues()
        self.set_frames()
        self.reset()
        self.set_framerate(self.interval)
        self.set_alpha(self.alpha)

    def load_configuration(self):
        config = self.get_configuration("exit-arrow")
        self.width = config["width"]
        self.height = config["height"]
        self.overlap = config["overlap"]
        self.arrow_count = config["arrow-count"]
        self.hue = config["hue"]
        self.frame_count = config["frame-count"]
        self.interval = config["interval"]
        self.saturation = config["saturation"]
        self.offset = config["offset"]
        self.fade_in_length = config["fade-in"]
        self.fade_out_length = config["fade-out"]
        self.alpha = config["alpha"]

    def set_mask(self):
        surface = Surface(self.get_size())
        surface.set_colorkey((0, 0, 0))
        rect = surface.get_rect()
        width = self.width
        x = 0
        for ii in xrange(self.arrow_count):
            points = (x, rect.centery), (x + width, 0), (x + width, rect.bottom)
            polygon(surface, (255, 255, 255), points)
            x += width - self.overlap
        self.mask = surface

    def get_size(self):
        count = self.arrow_count
        return self.width * count - self.overlap * (count - 1), self.height

    def set_hues(self):
        start, end = self.hue
        step = float(end - start) / (self.frame_count - 1)
        hues = deque([start])
        while start < end:
            start += step
            hues.append(start)
        hues.append(end)
        self.hues = hues

    def set_frames(self):
        for _ in xrange(self.frame_count):
            self.append_frame()

    def append_frame(self):
        width, height = self.get_size()
        gradient = Surface((width, height))
        gradient.set_colorkey((0, 0, 0))
        hues = self.hues
        step = float(width) / self.arrow_count / len(hues)
        x = 0
        color = Color(0, 0, 0)
        while x < width:
            for hue in hues:
                color.hsla = hue, self.saturation, 50, 100
                gradient.fill(color, (int(x), 0, ceil(step), height))
                x += step
        hues.rotate(-1)
        mask = self.mask.convert()
        gradient.blit(mask, (0, 0), None, BLEND_RGBA_MIN)
        self.add_frame(gradient)

    def reset(self):
        location = self.location
        base = self.parent.door.background.location
        location.left = base.centerx + self.offset
        location.centery = base.centery
        self.fade(0, out=True)

    def fade(self, length=None, out=None):
        if length is None:
            length = self.fade_out_length if out else self.fade_in_length
        Sprite.fade(self, length, out)

    def update(self):
        self.move(-self.parent.velocity[0])
        Sprite.update(self)
from os.path import join
from math import tan, radians

from pygame import Rect, Surface, Color
from pygame.image import load
from pygame.draw import polygon, ellipse, circle
from pygame.mask import from_surface, Mask
from pygame.locals import *

from lib.pgfw.pgfw.GameChild import GameChild
from lib.pgfw.pgfw.Sprite import Sprite

class Food(Sprite):

    def __init__(self, parent):
        Sprite.__init__(self, parent)
        self.compare = self.get_delegate().compare
        self.time_filter = self.get_game().time_filter
        self.mouth = Mouth(self)
        self.scope = Scope(self)
        self.load_configuration()
        self.load_nodesets()
        self.set_frames()
        self.set_frameset("cursed")
        self.subscribe(self.respond)
        self.register(self.unfreeze)
        self.set_mask()
        self.reset()
        self.set_base()

    def load_configuration(self):
        config = self.get_configuration("food")
        self.root = config["path"]
        self.offset = config["offset"]
        self.dx = config["dx"]
        self.angle_range = config["angle-range"]
        self.crouch_offset = config["crouch"]
        self.drop_velocity = config["drop-velocity"]
        self.dx_boost = config["dx-boost"]
        self.blink_rate = config["blink-rate"]
        self.freeze_length = config["freeze-length"]

    def load_nodesets(self):
        interpolator = self.get_game().interpolator
        self.charge_nodeset = interpolator.get_nodeset("charge")
        self.jump_width_nodeset = interpolator.get_nodeset("jump-width");
        self.jump_height_nodeset = interpolator.get_nodeset("jump-height");

    def set_frames(self):
        root = self.get_resource(join(self.root, str(self.parent.index)))
        self.load_from_path(root, True, omit=True)
        self.add_frameset(0, name="cursed")
        self.add_frameset(1, name="uncursed")
        self.add_frameset([0, 1], name="transforming")
        self.set_crouched()
        self.set_frozen()

    def set_crouched(self):
        cursed = self.frames[0]
        cursed_rect = cursed.get_rect()
        offset = self.crouch_offset
        surface = Surface((cursed_rect.w, cursed_rect.h - offset), SRCALPHA)
        destination = Rect(0, 0, cursed_rect.w, cursed_rect.h / 2 + 1)
        area = destination.move(0, 0)
        destination.bottom = surface.get_rect().bottom
        area.bottom = cursed_rect.bottom
        surface.blit(cursed, destination, area)
        destination.top = 0
        surface.blit(cursed, destination, destination)
        self.add_frame(surface, omit=True)
        self.add_frameset(2, name="crouched")

    def set_frozen(self):
        surface = Surface(self.location.size)
        surface.set_colorkey((0, 0, 0))
        self.add_frame(surface, omit=True)
        self.add_frameset([0, 3], self.blink_rate, "frozen")

    def respond(self, event):
        parent = self.parent
        if parent.active:
            if self.compare(event, "any") and not self.charging() and \
                   not self.frozen:
                self.activate_charge(event.id)
            elif self.compare(event, "any", cancel=True):
                if event.id == self.charge_key:
                    if not self.jumping and parent.is_going():
                        parent.exit_available = False
                        parent.exit_arrow.fade(out=True)
                        self.jump()
                    self.cancel_charge()

    def activate_charge(self, key):
        self.charge_key = key
        self.set_frameset("crouched")
        self.move(0, self.crouch_offset)
        self.parent.siphon.contract()

    def jump(self):
        self.jumping = True
        self.submitted_charge = self.charge
        rect = self.jump_rect = Rect((0, 0), self.get_jump_size())
        rect.bottomleft = self.location.center

    def get_jump_size(self):
        charge = self.submitted_charge
        return int(round(self.jump_width_nodeset.get_y(charge))), \
               int(round(self.jump_height_nodeset.get_y(charge)))

    def cancel_charge(self):
        self.set_frameset("cursed")
        self.move(0, -self.crouch_offset)
        self.charge_key = None
        self.charge_length = 0
        self.charge = 0
        self.parent.siphon.release()

    def set_mask(self):
        self.mask = from_surface(self.get_current_frame())

    def reset(self):
        self.ground = self.parent.platforms[0].rect.top
        self.falling = False
        self.dropping = False
        self.submitted_charge = 0
        self.cancel_jump()
        self.cancel_charge()
        self.place_at_start()
        self.unfreeze()
        self.scope.reset()

    def place_at_start(self):
        self.rect.bottomleft = self.offset, self.ground

    def cancel_jump(self, offset=None):
        self.location.bottom = self.ground
        if offset:
            self.location.right -= offset
        self.jumping = False
        self.gravity_effect = 0
        self.previous_location = None
        self.last_jump_x = 0

    def set_base(self):
        rect = self.rect
        yy = rect.h - 2
        start = None
        for xx in xrange(rect.w):
            visible = self.mask.get_at((xx, yy))
            if start is None:
                if visible:
                    start = xx
            else:
                if not visible:
                    break
        width = xx - start
        self.base = Rect(start, yy, width, 3)

    def freeze(self):
        if not self.frozen:
            self.frozen = True
            if self.charging():
                self.cancel_charge()
            self.set_frameset("frozen")
            self.play(self.unfreeze, delay=self.freeze_length, play_once=True)

    def unfreeze(self):
        self.frozen = False
        self.set_frameset("cursed")

    def update(self):
        if self.parent.active:
            if self.jumping:
                self.propell()
                if not self.falling and self.rect.bottom >= self.ground and \
                       self.last_jump_x > 0:
                    collide = self.collide_with_platform()
                    if collide:
                        self.cancel_jump(collide)
                    else:
                        self.falling = True
                elif self.rect.top > self.display_surface.get_height():
                    self.parent.queue_reset()
            elif self.parent.is_going():
                self.move(-self.parent.velocity[0])
            if self.falling:
                index = self.location.collidelist(self.parent.platforms)
                if index > -1:
                    platform = self.parent.platforms[index].location
                    intersection = self.location.clip(platform)
                    if platform.left > self.location.left:
                        self.location.right = platform.left
                    else:
                        self.location.left = platform.right
                    self.dropping = True
            self.update_charge()
        self.scope.place()
        Sprite.update(self)
        if self.charging():
            self.mouth.update()
        self.scope.update()

    def propell(self):
        self.previous_location = Rect(self.location)
        if not self.dropping:
            rect = self.jump_rect
            w, h = rect.size = self.get_jump_size()
            x = self.dx + (self.parent.velocity[0] - 1) * self.dx_boost + \
                self.last_jump_x
            if w == 0:
                w = .00000000001
            y = (-2 * h / (.5 * w ** 2)) * x ** 2 + (4 * h / w) * x
            self.location.center = rect.move(int(round(x)),
                                             int(round(-y))).bottomleft
            self.last_jump_x = x
        else:
            self.move(*self.drop_velocity)

    def collide_with_platform(self):
        base = self.base
        previous = base.move(*self.previous_location.topleft)
        current = base.move(*self.location.topleft)
        box = Rect(previous.topleft, (current.right - previous.left,
                                      current.bottom - previous.top))
        platform_index = box.collidelist(self.parent.platforms)
        if platform_index > -1:
            stripe = Surface(box.size)
            stripe.set_colorkey((0, 0, 0))
            polygon(stripe, (255, 255, 255),
                    ((0, 0), (base.w, 0), box.size, (box.w - base.w, box.h)))
            stripe_mask = from_surface(stripe)
            platform = self.parent.platforms[platform_index]
            platform_mask = from_surface(Surface((platform.location.w, 3)))
            offset = platform.location.left - box.left, \
                     platform.location.top - 1 - box.top
            overlap = stripe_mask.overlap(platform_mask, offset)
            if overlap:
                for x in xrange(stripe_mask.get_size()[0]):
                    if stripe_mask.get_at((x, overlap[1] + 1)):
                        break
                return box.w - base.w - x

    def update_charge(self):
        if self.charging():
            self.charge_length += self.time_filter.get_last_frame_duration()
            self.charge = self.charge_nodeset.get_y(self.charge_length)

    def charging(self):
        return self.charge_key is not None


class Mouth(Surface, GameChild):

    transparent_color = (255, 0, 255)

    def __init__(self, parent):
        GameChild.__init__(self, parent)
        self.set_images()
        self.init_surface()
        self.set_background()
        self.load_configuration()

    def set_images(self):
        get = self.get_resource
        self.lower_jaw = load(get("food", "lower-jaw-path")).convert_alpha()
        self.lower_jaw_rect = self.lower_jaw.get_rect()
        self.upper_jaw = load(get("food", "upper-jaw-path")).convert_alpha()
        self.upper_jaw_rect = self.upper_jaw.get_rect()

    def init_surface(self):
        Surface.__init__(self, self.get_configuration("food", "mouth-size"),
                         SRCALPHA)

    def set_background(self):
        surface = Surface(self.get_size())
        key = self.transparent_color
        surface.fill(key)
        surface.set_colorkey(key)
        surface.set_alpha(self.get_configuration("food", "mouth-bg-alpha"))
        self.background = surface

    def load_configuration(self):
        config = self.get_configuration("food")
        self.offset = config["mouth-offset"]
        self.background_shrink = config["mouth-bg-shrink"]
        self.gap = config["mouth-gap"]

    def update(self):
        self.display_surface = self.parent.display_surface
        self.init_surface()
        self.clear_background()
        self.rect = self.get_position(self.parent.location)
        self.draw_jaws()
        mask = self.draw_mask()
        self.draw_background(mask, self.rect)
        self.display_surface.blit(self, self.rect)
        if self.parent.scope.active:
            scope_rect = self.get_position(self.parent.scope.extra_location)
            self.draw_background(mask, scope_rect)
            self.display_surface.blit(self, scope_rect)

    def clear_background(self):
        self.background.fill(self.transparent_color)

    def get_position(self, base):
        offset = self.offset
        rect = self.get_rect()
        rect.center = base.left + offset[0], base.bottom - offset[1]
        return rect

    def draw_jaws(self):
        rect = self.rect
        center = rect.h / 2
        offset = max(self.gap, int(round(self.parent.charge * center)))
        lower_rect = self.lower_jaw_rect
        lower_rect.bottom = center + offset
        self.blit(self.lower_jaw, lower_rect)
        upper_rect = self.upper_jaw_rect
        upper_rect.top = center - offset
        self.blit(self.upper_jaw, upper_rect)

    def draw_mask(self):
        surface = Surface(self.get_size(), SRCALPHA)
        width = self.rect.w
        height = int(round(self.rect.h * self.parent.charge))
        rect = Rect(0, 0, width, height)
        rect.centery = self.rect.h / 2
        ellipse(surface, (255, 255, 255), rect)
        self.blit(surface, (0, 0), None, BLEND_RGBA_MIN)
        return rect

    def draw_background(self, ellipse_rect, rect):
        shrink = self.background_shrink
        if ellipse_rect.h >= -shrink[0]:
            ellipse(self.background, (0, 0, 0), ellipse_rect.inflate(*shrink))
            self.display_surface.blit(self.background, rect)


class LowerJaw(Sprite):

    def __init__(self, parent):
        Sprite.__init__(self, parent)
        self.load_from_path(self.get_resource("food", "lower-jaw-path"), True)


class UpperJaw(Sprite):

    def __init__(self, parent):
        Sprite.__init__(self, parent)
        self.load_from_path(self.get_resource("food", "upper-jaw-path"), True)


class Scope(Sprite):

    def __init__(self, parent):
        Sprite.__init__(self, parent)
        self.active = False
        self.limit = 400
        self.reset()

    def offset_points(self, points):
        offset = []
        for point in points:
            offset.append((point[0], point[1] + 2))
        return offset

    def reset(self):
        if self.active:
            self.parent.remove_locations(self.extra_location)
            self.active = False

    def place(self):
        if self.parent.parent.is_going():
            if not self.active and self.parent.location.right <= 0:
                self.active = True
                self.extra_location = self.parent.add_location()
            if self.active:
                if self.parent.location.right > 0:
                    self.reset()
                else:
                    if self.parent.location.right <= -self.limit:
                        self.parent.parent.queue_reset()
                    self.set_frame()
                    location = self.location
                    location.centery = self.parent.location.centery
                    self.extra_location.reset_motion_overflow()
                    self.extra_location.midright = location.right - 15, \
                                                   location.centery

    def set_frame(self):
        surface = Surface((76, 60))
        rect = surface.get_rect()
        key = (255, 0, 255)
        surface.fill(key)
        surface.set_colorkey(key)
        background = (128, 128, 128)
        distance = self.parent.location.right
        if distance < -self.limit:
            distance = -self.limit
        foreground = Color(0, 0, 0)
        limit = self.limit
        foreground.hsla = int(120 * (limit + distance) / limit), 95, 55, 100
        points = (0, rect.h / 2 - 1), (8, rect.h / 2 - 11), (8, rect.h / 2 + 9)
        polygon(surface, background, self.offset_points(points))
        polygon(surface, foreground, points)
        square = Rect(8, rect.h / 2 - 6, 10, 10)
        surface.fill(background, square.move(0, 2))
        surface.fill(foreground, square)
        center = 46, rect.h / 2 - 1
        radius = 29
        circle(surface, background, (center[0], center[1] + 2), radius, 10)
        area = circle(surface, foreground, center, radius, 10)
        ellipse(surface, foreground, area.inflate(-1, 0), 9)
        ellipse(surface, foreground, area.inflate(0, -1), 9)
        ellipse(surface, foreground, area.inflate(-2, -1), 8)
        ellipse(surface, foreground, area.inflate(-1, -2), 8)
        self.clear_frames()
        self.add_frame(surface)

    def update(self):
        if self.parent.parent.is_going() and self.active:
            Sprite.update(self)
18.97.14.83
18.97.14.83
18.97.14.83
 
January 28, 2014


E F F L U E N C E