scrapeboard/NS.py

2140 lines
84 KiB
Python

# -*- coding: utf-8 -*-
from random import randint, choice, random
from math import pi
from copy import copy
from glob import iglob
from os.path import basename, join
from threading import Thread
from serial import Serial, SerialException
from serial.tools import list_ports
from time import sleep
from PIL import Image
from pygame import Surface, Color, mixer
from pygame.event import clear
from pygame.mixer import Sound
from pygame.image import load, fromstring
from pygame.transform import rotate, flip, scale, smoothscale
from pygame.time import get_ticks
from pygame.font import Font
from pygame.draw import aalines, lines
from pygame.gfxdraw import aapolygon, arc, polygon, aaellipse, ellipse, filled_ellipse, filled_circle
from pygame.locals import *
from lib.pgfw.pgfw.Game import Game
from lib.pgfw.pgfw.GameChild import GameChild
from lib.pgfw.pgfw.Sprite import Sprite, RainbowSprite
from lib.pgfw.pgfw.Animation import Animation
from lib.pgfw.pgfw.extension import (
get_step, get_step_relative, get_delta, reflect_angle,
render_box, get_hsla_color, get_hue_shifted_surface,
get_color_swapped_surface
)
from lib.pgfw.pgfw.gfx_extension import aa_filled_polygon
class NS(Game, Animation):
LNW, LNE, LSE, LSW = range(4)
N, NE, E, NW, S, W = range(6)
FRONT_WIDTH = 230
BACK_WIDTH = 500
LENGTH = 150
FRONT = 300
STEP = .4
IDLE_TIMEOUT = 60000 * 5
CHANNEL_COUNT = 8
NO_RESET_TIMEOUT = 3000
def __init__(self):
Game.__init__(self)
self.get_configuration().type_declarations.add_chart(
{
"time":
{
"int": ["timer-max-time", "timer-start-time", "timer-addition", "sword-delay",
"attract-gif-length", "attract-board-length"]
},
"input":
{
"bool": "serial"
},
"display":
{
"float": "attract-gif-alpha"
}
})
Animation.__init__(self, self)
mixer.init(44100, -16, self.CHANNEL_COUNT, 4096)
self.subscribe(self.respond, KEYDOWN)
self.subscribe(self.respond, KEYUP)
self.subscribe(self.respond)
ds = self.get_display_surface()
self.background = Surface(ds.get_size())
self.background.fill((0, 0, 0))
self.platform = Platform(self)
self.tony = Tony(self)
self.logo = Logo(self)
self.title = Title(self)
self.introduction = Introduction(self)
self.ending = Ending(self)
self.wipe = Wipe(self)
self.dialogue = Dialogue(self)
self.chemtrails = Chemtrails(self)
self.boss = Boss(self)
if self.serial_enabled():
self.serial_kill = False
self.serial_data = 0
self.serial_reader = Serial(self.get_configuration("input", "arduino-port"),
timeout=.3)
self.reset_arduino()
# for port in list_ports.comports():
# print port.device
# print "---"
# ports = list_ports.grep(self.get_configuration("input", "arduino-port"))
# for port in ports:
# print port.device
self.serial_thread = Thread(target=self.read_serial)
self.serial_thread.start()
self.last_press = get_ticks()
self.register(self.blink_score, interval=500)
self.play(self.blink_score)
self.reset()
self.most_recent_time = None
clear()
def serial_enabled(self):
return self.get_configuration("input", "serial") and not self.check_command_line("-no-serial")
def read_serial(self):
while not self.serial_kill:
name = self.get_configuration("input", "arduino-port")
try:
transmission = self.serial_reader.readline().strip()
print(transmission)
except SerialException:
print("Serial not ready... passing...")
transmission = ""
if len(transmission) == 4:
try:
self.serial_data = int(transmission, 2)
except ValueError:
print("Value error checking four digit serial transmission")
self.handle_garbage(transmission)
self.reset_arduino()
self.idle_elapsed = 0
elif len(transmission) > 0:
try:
int(transmission, 2)
except ValueError:
print("Received a non-four digit serial transmission")
self.handle_garbage(transmission)
else:
self.serial_data = 0
def handle_garbage(self, transmission):
self.serial_data = 0
print("Garbage detected: %s" % transmission)
self.serial_reader.reset_input_buffer()
def reset_arduino(self):
if self.serial_enabled():
self.serial_reader.dtr = False
self.serial_reader.reset_input_buffer()
self.serial_reader.dtr = True
def end(self, evt):
if evt.type == QUIT or self.delegate.compare(evt, "quit"):
self.serial_kill = True
Game.end(self, evt)
def apply_serial(self):
for ii, light in enumerate(self.platform.lights):
light.pressed = bool(self.serial_data & (2 ** ii))
def reset(self, leave_wipe_running=False):
self.score_hidden = False
self.idle_elapsed = 0
self.suppressing_input = False
self.title.reset()
if not leave_wipe_running:
self.wipe.reset()
self.introduction.reset()
self.ending.reset()
self.boss.reset()
self.chemtrails.reset()
self.platform.reset()
self.dialogue.reset()
self.no_reset_elapsed = 0
self.title.activate()
def set_most_recent_time(self, score):
self.most_recent_time = score
def blink_score(self):
self.score_hidden = not self.score_hidden
def suppress_input(self):
self.suppressing_input = True
# self.platform.unpress()
def unsuppress_input(self):
self.suppressing_input = False
def respond(self, event):
if not self.suppressing_input and event.type in (KEYDOWN, KEYUP):
if self.last_press <= get_ticks() - int(self.get_configuration("input", "buffer")):
pressed = True if event.type == KEYDOWN else False
lights = self.platform.lights
self.idle_elapsed = 0
if event.key in (K_UP, K_o):
lights[NS.LNW].pressed = pressed
elif event.key in (K_RIGHT, K_p):
lights[NS.LNE].pressed = pressed
elif event.key in (K_DOWN, K_SEMICOLON):
lights[NS.LSE].pressed = pressed
elif event.key in (K_LEFT, K_l):
lights[NS.LSW].pressed = pressed
elif event.key == K_z:
self.reset()
elif event.key == K_a:
self.reset_arduino()
self.last_press = get_ticks()
else:
if self.get_delegate().compare(event, "reset-game"):
self.reset()
def update(self):
Animation.update(self)
last_frame_duration = self.time_filter.get_last_frame_duration()
if self.serial_enabled():
self.apply_serial()
if self.title.active or self.introduction.active or self.ending.active or \
self.dialogue.active:
self.no_reset_elapsed += last_frame_duration
# if we received good input, reset the auto reset timer
if 0b11 <= self.serial_data <= 0b1100:
self.no_reset_elapsed = 0
if self.no_reset_elapsed >= self.NO_RESET_TIMEOUT:
print("auto arduino reset triggered")
self.reset_arduino()
self.no_reset_elapsed = 0
self.title.update()
self.introduction.update()
self.ending.update()
self.boss.update()
if not self.title.active:
self.platform.update()
self.chemtrails.update()
self.boss.update_dialogue()
self.wipe.update()
self.idle_elapsed += self.time_filter.get_last_frame_duration()
if self.idle_elapsed >= self.IDLE_TIMEOUT:
self.reset()
class Button(Sprite):
MARGIN = 2
BLANK = (200, 200, 200)
def __init__(self, parent, edge, size, border):
Sprite.__init__(self, parent)
colors = self.get_game().platform.get_color_pair_from_edge(edge)
width = size * 2 + self.MARGIN + border * 4
step = width / 2 + self.MARGIN / 2
rect_width = width / 2 - self.MARGIN / 2
rects = Rect(0, 0, rect_width, rect_width), \
Rect(step, 0, rect_width, rect_width), \
Rect(step, step, rect_width, rect_width), \
Rect(0, step, rect_width, rect_width)
if edge == NS.N:
colored = rects[0], rects[1]
elif edge == NS.NE:
colored = rects[1], rects[3]
elif edge == NS.E:
colored = rects[1], rects[2]
elif edge == NS.NW:
colored = rects[0], rects[2]
elif edge == NS.S:
colored = rects[3], rects[2]
elif edge == NS.W:
colored = rects[0], rects[3]
for lightness in range(30, 90, 5):
frame = Surface((width, width), SRCALPHA)
for topleft in (0, 0), (step, 0), (step, step), (0, step):
rect = Rect(topleft, (rect_width, rect_width))
border_color = Color(*self.BLANK)
border_color.a = 179
frame.fill(border_color, rect)
frame.fill((0, 0, 0, 0), rect.inflate(-border * 2, -border * 2))
for ii in range(2):
original_color = Color(*colors[ii])
original_color.a = 255
edited_color = Color(0, 0, 0)
edited_color.hsla = int(original_color.hsla[0]), int(original_color.hsla[1]), \
lightness, 70
frame.fill(edited_color, colored[ii])
frame.fill(original_color, colored[ii].inflate(-border * 2, -border * 2))
self.add_frame(frame)
class Meter(GameChild):
SPACING = 12
def __init__(self, parent):
GameChild.__init__(self, parent)
def setup(self, background, rect, indent, color, units, path):
self.background = background
self.rect = rect
self.icons = []
x = rect.left + indent
base = get_color_swapped_surface(
load(self.get_resource(path)).convert_alpha(),
(0, 0, 0), color)
while x <= self.rect.right - base.get_width() - self.SPACING:
icon = Sprite(self)
icon.add_frame(base)
icon.location.midleft = x, self.rect.centery
self.icons.append(icon)
x += icon.location.w + self.SPACING
self.units = units
def reset(self):
self.amount = self.units
for icon in self.icons:
icon.unhide()
def change(self, delta):
self.amount += delta
cutoff = float(self.amount) / self.units * len(self.icons)
for ii, icon in enumerate(self.icons):
if ii < cutoff:
icon.unhide()
else:
icon.hide()
def update(self):
ds = self.get_display_surface()
ds.blit(self.background, self.rect)
for icon in self.icons:
icon.update()
class Tony(Sprite):
def __init__(self, parent):
Sprite.__init__(self, parent, 100, False)
self.board = Sprite(self, 100)
self.board.load_from_path(self.get_resource("newTony/TonyArms"), True)
self.effect = Sprite(self)
dsr = self.get_display_surface().get_rect()
for offset in range(12):
w, h = dsr.w + 40, int(dsr.h * .65)
glow = Surface((w, h), SRCALPHA)
for ii, y in enumerate(range(h, 0, -8)):
hue = range(200, 140, -5)[(ii - offset) % 12]
alpha = min(100, int(round(y / float(h - 10) * 100)))
color = get_hsla_color(hue, 100, 50, alpha)
if ii == 0:
aaellipse(glow, w // 2, y, w // 2 - 4, h // 20, color)
ellipse(glow, w // 2, y, w // 2 - 4, h // 20, color)
filled_ellipse(glow, w // 2, y, w // 2 - 4, h // 20, color)
self.effect.add_frame(glow)
self.effect.location.topleft = -20, int(dsr.h * .35)
self.add_frame(load(self.get_resource("Big_Tony.png")).convert_alpha())
self.load_from_path(self.get_resource("newTony/TonyShirtHead"), True)
self.add_frameset([0], name="static")
self.add_frameset(range(1, len(self.frames)), name="board")
def set_frameset(self, name):
Sprite.set_frameset(self, name)
self.get_current_frameset().reset()
self.set_framerate(100)
if name == "board":
self.board.get_current_frameset().reset()
self.board.unhide()
self.board.set_framerate(100)
self.board.halt()
elif name == "static":
self.board.hide()
def shift_frame(self):
Sprite.shift_frame(self)
frameset = self.get_current_frameset()
if frameset.name == "board" and frameset.current_index == 1:
self.get_audio().play_sfx("comeOn")
def update(self):
save = self.get_display_surface()
intermediate_surface = Surface(self.location.size, SRCALPHA)
self.display_surface = intermediate_surface
Sprite.update(self)
self.display_surface = save
self.effect.display_surface = intermediate_surface
self.effect.update(flags=BLEND_RGBA_SUB)
self.get_display_surface().blit(intermediate_surface, self.location.topleft)
if self.get_game().title.active:
self.get_game().platform.update()
self.get_game().chemtrails.update()
frameset = self.get_current_frameset()
if frameset.name == "board":
self.board.get_current_frameset().current_index = frameset.current_index
if frameset.current_index == len(frameset.order) - 1:
self.set_framerate(3000)
else:
self.set_framerate(100)
self.board.update()
class Video(Sprite):
def __init__(self, parent, diameter, next_video_chance=.01):
Sprite.__init__(self, parent, 100)
self.next_video_chance = next_video_chance
pattern = join(self.get_resource("gif"), "Boarding_*.gif")
self.gifs = []
for path in iglob(pattern):
self.gifs.append(Image.open(path))
print(self.gifs[-1].info)
self.gif = self.gifs[1]
self.mask = Surface([diameter] * 2, SRCALPHA)
rect = self.mask.get_rect()
alpha = int(self.get_configuration("display", "attract-gif-alpha") * 255)
filled_circle(self.mask, rect.centerx, rect.centery, rect.centerx, (0, 0, 0, alpha))
filled_circle(self.mask, rect.centerx, rect.centery, rect.centerx - 2, (255, 255, 255, alpha))
self.add_frame(self.mask)
self.play()
def shift_frame(self):
Sprite.shift_frame(self)
if random() < self.next_video_chance:
while True:
selection = choice(self.gifs)
if selection != self.gif:
self.gif = selection
break
self.gif.seek((self.gif.tell() + 1) % self.gif.n_frames)
frame = smoothscale(
fromstring(self.gif.convert("RGBA").tobytes(), self.gif.size, "RGBA"),
(self.mask.get_width(), int(self.gif.width * self.gif.height / self.mask.get_width())))
copy = self.mask.copy()
rect = frame.get_rect()
rect.bottom = copy.get_rect().bottom
copy.blit(frame, rect, None, BLEND_RGBA_MIN)
self.clear_frames()
self.add_frame(copy)
class Logo(Sprite):
def __init__(self, parent):
Sprite.__init__(self, parent)
dsr = self.get_display_surface().get_rect()
self.load_from_path(self.get_resource("Title_tile.png"), True)
for y in range(0, dsr.h + self.location.h, self.location.h):
for x in range(0, dsr.w + self.location.w, self.location.w):
if x != 0 or y != 0:
self.add_location((x, y))
self.effect = Sprite(self, 100)
palette = (255, 255, 255), (255, 255, 128), (255, 255, 0)
thickness = 8
for offset in range(len(palette)):
frame = Surface(dsr.size)
for x in range(0, dsr.w, thickness):
frame.fill(palette[(offset + x) % len(palette)], (x, 0, thickness, dsr.h))
self.effect.add_frame(frame)
def update(self):
self.effect.update()
# tiled background
self.move(-2, 2)
if self.location.right < 0:
self.move(self.location.w)
if self.location.top > 0:
self.move(dy=-self.location.h)
Sprite.update(self, flags=BLEND_RGBA_MIN)
class Title(Animation):
UNLOCK_MOVES = NS.NW, NS.N, NS.NE, NS.NW
def __init__(self, parent):
Animation.__init__(self, parent)
self.plank = Sprite(self)
self.plank.load_from_path(self.get_resource("Title_plank.png"), True)
ds = self.get_display_surface()
dsr = ds.get_rect()
self.plank.location.center = dsr.center
self.angle = pi / 8
self.video = Video(self, 320)
self.video.location.center = 329, 182
self.register(self.show_video, self.hide_video)
self.show_video()
def reset(self):
self.unlock_index = 0
self.get_game().platform.set_glowing(self.get_game().platform.get_buttons_from_edges([self.UNLOCK_MOVES[0]]))
self.halt()
self.show_video()
def activate(self):
self.active = True
platform = self.get_game().platform
platform.activate()
platform.set_glowing(platform.get_buttons_from_edges([self.UNLOCK_MOVES[self.unlock_index]]))
self.get_game().chemtrails.activate()
self.get_game().tony.set_frameset("static")
def deactivate(self):
self.active = False
self.halt()
def start_game(self):
self.deactivate()
self.get_game().set_most_recent_time(None)
self.get_game().boss.start_level(0)
def draw_scores(self):
step = 75
ds = self.get_display_surface()
lines = map(int, open(self.get_resource("scores")).readlines())
entries = ["BEST"] + sorted(lines)[:9]
for ii, entry in enumerate(entries):
if ii == 0 or ii == 5:
y = 30
font = Font(self.get_resource(Dialogue.FONT_PATH), 18)
if ii > 0:
text = self.get_formatted_time(entry)
else:
text = entry
message = render_box(font, text, True, Color(255, 255, 255),
Color(128, 128, 128), Color(0, 0, 0), padding=2)
message.set_alpha(230)
rect = message.get_rect()
rect.top = y
if ii < 5:
rect.left = -1
else:
rect.right = ds.get_width() + 1
if not entry == self.get_game().most_recent_time or not self.get_game().score_hidden:
ds.blit(message, rect)
y += step
def get_formatted_time(self, entry):
if int(entry) == 5999999:
return "--:--.-"
else:
minutes, milliseconds = divmod(int(entry), 60000)
seconds, fraction = divmod(milliseconds, 1000)
return "%i:%02i.%i" % (minutes, seconds, fraction / 100)
def show_video(self):
self.video.unhide()
self.play(self.hide_video, delay=self.get_configuration("time", "attract-gif-length"), play_once=True)
self.get_game().tony.set_frameset("static")
self.unlock_index = 0
self.get_game().platform.set_glowing(self.get_game().platform.get_buttons_from_edges([self.UNLOCK_MOVES[0]]))
def hide_video(self):
self.video.hide()
self.play(self.show_video, delay=self.get_configuration("time", "attract-board-length"), play_once=True)
self.get_game().tony.set_frameset("board")
def update(self):
'''
Move title, check button presses, and draw screen
'''
Animation.update(self)
if self.active:
ds = self.get_display_surface()
dsr = ds.get_rect()
self.get_game().logo.update()
# advance unlock pattern
platform = self.get_game().platform
if not self.get_game().wipe.is_playing() and platform.get_edge_pressed() == self.UNLOCK_MOVES[self.unlock_index]:
# self.first_pressed = True
# self.first_pressed_elapsed = 0
if self.unlock_index == len(self.UNLOCK_MOVES) - 1:
platform.set_glowing([])
self.get_game().wipe.start(self.start_game)
self.get_audio().play_sfx("confirm")
else:
self.unlock_index += 1
platform.set_glowing(platform.get_buttons_from_edges([self.UNLOCK_MOVES[self.unlock_index]]))
self.get_audio().play_sfx("land_0")
# reset unlock pattern if idle
# if self.first_pressed:
# self.first_pressed_elapsed += self.get_game().time_filter.get_last_frame_duration()
# if self.first_pressed_elapsed > 1000 * 10:
# self.reset()
self.get_game().tony.update()
# bounce the gif around the screen
if self.video.location.right > dsr.right or self.video.location.left < dsr.left:
self.angle = reflect_angle(self.angle, 0)
if self.video.location.right > dsr.right:
self.video.move(dsr.right - self.video.location.right)
else:
self.video.move(dsr.left - self.video.location.left)
if self.video.location.bottom > dsr.bottom or self.video.location.top < dsr.top:
self.angle = reflect_angle(self.angle, pi)
if self.video.location.bottom > dsr.bottom:
self.video.move(dy=dsr.bottom - self.video.location.bottom)
else:
self.video.move(dy=dsr.top - self.video.location.top)
dx, dy = get_delta(self.angle, 5, False)
self.video.move(dx, dy)
if platform.get_pressed():
self.video.hide()
self.get_game().tony.set_frameset("static")
self.halt()
self.play(self.show_video, delay=10000, play_once=True)
self.video.update()
self.draw_scores()
class Dialogue(Animation):
BACKGROUND = 255, 255, 255
BORDER = 0, 0, 0
TEXT_COLOR = 0, 0, 0
FONT_PATH = "rounded-mplus-1m-bold.ttf"
FONT_SIZE = 18
def __init__(self, parent):
Animation.__init__(self, parent)
ds = self.get_display_surface()
dsr = ds.get_rect()
frame = Surface((640, 72))
frame.fill(self.BORDER)
frame.fill(self.BACKGROUND, (1, 1, frame.get_width() - 2, frame.get_height() - 2))
self.text_box = Sprite(self)
self.text_box.add_frame(frame)
self.text_box.location.bottomleft = dsr.bottomleft
frame = Surface((66, 66))
frame.fill(self.BORDER)
frame.fill(self.BACKGROUND, (1, 1, frame.get_width() - 2, frame.get_height() - 2))
self.avatar_box = Sprite(self)
self.avatar_box.add_frame(frame)
self.avatar_box.location.bottomleft = self.text_box.location.topleft
frame = Surface((128, 24))
frame.fill(self.BORDER)
frame.fill(self.BACKGROUND, (1, 1, frame.get_width() - 2, frame.get_height() - 2))
self.name_box = Sprite(self)
self.name_box.add_frame(frame)
self.name_box.location.bottomleft = self.avatar_box.location.bottomright
self.speech_channel = None
def reset(self):
self.stop_speech()
self.halt()
self.deactivate()
self.first_pressed = False
self.first_press_elapsed = 0
def stop_speech(self):
if self.speech_channel is not None:
self.speech_channel.stop()
self.speech_channel = None
def deactivate(self):
self.stop_speech()
self.active = False
def activate(self):
self.active = True
def set_avatar(self, image):
self.avatar = Sprite(self)
self.avatar.add_frame(image)
self.avatar.location.center = self.avatar_box.location.center
def set_name(self, text):
font = Font(self.get_resource(self.FONT_PATH), self.FONT_SIZE)
self.name = Sprite(self)
self.name.add_frame(font.render(text, True, self.TEXT_COLOR).convert_alpha())
self.name.location.midleft = self.name_box.location.left + 5, self.name_box.location.centery
def show_text(self, text):
self.full_text = text
self.text_index = 0
self.speech_channel = self.get_audio().play_sfx("talk", -1)
self.play()
def build_frame(self):
self.text_index += 2
if self.text_index >= len(self.full_text):
self.show_all()
def show_all(self):
self.stop_speech()
self.text_index = len(self.full_text)
self.halt()
def update(self):
if self.active:
Animation.update(self)
self.avatar_box.update()
self.avatar.update()
self.name_box.update()
self.name.update()
self.text_box.update()
font = Font(self.get_resource(self.FONT_PATH), self.FONT_SIZE)
message = Sprite(self)
lines = self.full_text[:self.text_index].split("\n")
frame = Surface((self.text_box.location.w - 10, 30 * len(lines)), SRCALPHA)
for ii, line in enumerate(lines):
surface = font.render(line, True, self.TEXT_COLOR).convert_alpha()
frame.blit(surface, (0, 30 * ii))
message.add_frame(frame)
message.location.topleft = self.text_box.location.left + 9, self.text_box.location.top + 8
message.update()
class Introduction(Animation):
TEXT = (
"Hey, you lizard slime bag. It's me Giant Tony. " + \
"Do you think you\ncan skate like me? Prove it!",
"I'll even give you my board for this adventure. And ink my name\n" + \
"on it. Now the power of Giant Tony pulses through you.",
# "Before you go, show me you can scrape! Use your board to touch\n" + \
"Before you play, show me you can scrape! Use your board to touch\n" + \
"the glowing pads on the platform!", \
# "Good job, lizard scum! Maybe now you're ready to take on Kool\n" + \
"Good job, slime bag! Maybe now you're ready to take on Kool\n" + \
"Man and his friends. Don't let me down!")
SKATEBOARD_START = -30, -20
TUTORIAL_MOVES = NS.S, NS.NE, NS.N, NS.E
def __init__(self, parent):
Animation.__init__(self, parent)
self.words = []
for word in "hey you lizard slime bag show me you can scrape".split(" "):
font = Font(self.get_resource(Dialogue.FONT_PATH), 96)
sprite = RainbowSprite(self, font.render(word, True, (255, 0, 0)).convert_alpha(), 30)
self.words.append(sprite)
self.skateboard = Sprite(self)
self.skateboard.load_from_path(self.get_resource("Introduction_skateboard.png"), True)
self.slime_bag = Sprite(self)
self.slime_bag.load_from_path(self.get_resource("Introduction_slime_bag.png"), True)
self.slime_bag.load_from_path(self.get_resource("Introduction_slime_bag_board.png"), True)
self.slime_bag.add_frameset([0], name="standing", switch=True)
self.slime_bag.add_frameset([1], name="board")
self.slime_bag.location.center = self.get_display_surface().get_rect().center
self.tony_avatar = load(self.get_resource("Introduction_tony_avatar.png")).convert()
self.advance_prompt = AdvancePrompt(self)
self.skip_prompt = SkipPrompt(self, self.start_wipe)
self.register(self.start, self.move_board, self.take_board, self.speak)
def reset(self):
self.deactivate()
self.slime_bag.set_frameset("standing")
self.slime_bag.unhide()
self.halt()
self.skateboard.hide()
self.text_index = 0
self.tutorial_index = 0
self.words_index = 0
self.advance_prompt.reset()
self.skip_prompt.reset()
for word in self.words:
word.location.center = self.get_display_surface().get_rect().centerx, 100
word.hide()
def deactivate(self):
self.active = False
def activate(self):
self.active = True
self.play(self.start, delay=3000, play_once=True)
self.words[0].unhide()
self.play(self.speak)
# self.get_game().platform.unpress()
def speak(self):
for ii in range(self.words_index + 1):
self.words[ii].move(0, 12)
if ii == self.words_index and self.words[ii].location.bottom > self.get_display_surface().get_rect().bottom - 40:
if self.words_index < len(self.words) - 1:
self.words_index += 1
self.words[self.words_index].unhide()
self.get_audio().play_sfx("talk")
def start(self):
self.advance_prompt.cancel_first_press()
dialogue = self.get_game().dialogue
dialogue.activate()
dialogue.set_avatar(self.tony_avatar)
dialogue.set_name("???")
# dialogue.show_text(self.TEXT[0])
dialogue.show_text(self.TEXT[2])
self.text_index = 0
# temporary dialogue skip
dialogue.set_name("Tony")
self.slime_bag.hide()
self.halt(self.move_board)
self.take_board()
platform = self.get_game().platform
platform.activate()
platform.set_glowing(platform.get_buttons_from_edges(
[self.TUTORIAL_MOVES[self.tutorial_index]]))
self.get_game().chemtrails.activate()
self.text_index = 2
def give_board(self):
self.skateboard.location.center = self.SKATEBOARD_START
self.skateboard_step = get_step(self.skateboard.location.center, self.slime_bag.location.center, 2)
self.skateboard.unhide()
self.play(self.move_board)
def move_board(self):
self.skateboard.move(*self.skateboard_step)
if self.skateboard.location.colliderect(self.slime_bag.location.inflate(-30, -30)):
self.halt(self.move_board)
self.play(self.take_board, delay=2000, play_once=True)
self.get_audio().play_sfx("go")
def take_board(self):
self.skateboard.hide()
self.slime_bag.set_frameset("board")
def activate_boss(self):
self.deactivate()
self.get_game().boss.start_level(0)
def start_wipe(self):
self.get_game().wipe.start(self.activate_boss)
def update(self):
if self.active:
Animation.update(self)
# dialogue = self.get_game().dialogue
wipe = self.get_game().wipe
if not wipe.is_playing() and not self.is_playing(self.start) and not self.text_index == 2:
if self.advance_prompt.check_first_press():
self.advance_prompt.press_first()
elif self.advance_prompt.check_second_press():
if dialogue.is_playing():
dialogue.show_all()
else:
if self.text_index < len(self.TEXT) - 1:
self.text_index += 1
if self.text_index == 1:
dialogue.set_name("Tony")
self.give_board()
elif self.text_index == 2:
self.slime_bag.hide()
self.halt(self.move_board)
self.take_board()
platform = self.get_game().platform
platform.activate()
platform.set_glowing(platform.get_buttons_from_edges(
[self.TUTORIAL_MOVES[self.tutorial_index]]))
self.get_game().chemtrails.activate()
dialogue.show_text(self.TEXT[self.text_index])
else:
self.start_wipe()
# self.get_game().platform.unpress()
self.advance_prompt.cancel_first_press()
elif not wipe.is_playing() and self.text_index == 2:
platform = self.get_game().platform
if platform.get_edge_pressed() == self.TUTORIAL_MOVES[self.tutorial_index]:
self.tutorial_index += 1
self.get_audio().play_sfx("land_0")
if self.tutorial_index == len(self.TUTORIAL_MOVES):
# self.text_index += 1
# self.advance_prompt.cancel_first_press()
platform.set_glowing([])
self.start_wipe()
# dialogue.show_text(self.TEXT[self.text_index])
else:
platform.set_glowing(platform.get_buttons_from_edges(
[self.TUTORIAL_MOVES[self.tutorial_index]]))
self.get_game().tony.update()
self.slime_bag.update()
self.skateboard.update()
for word in self.words:
word.update()
self.get_game().platform.update()
# self.get_game().dialogue.update()
# if not wipe.is_playing() and not self.is_playing(self.start) and \
# not self.text_index == 2:
# self.advance_prompt.update()
if not wipe.is_playing() and not self.text_index == 2:
self.skip_prompt.update()
class SkipPrompt(GameChild):
def __init__(self, parent, callback):
GameChild.__init__(self, parent)
self.callback = callback
self.buttons = []
self.pluses = []
top = 3
left = 3
for ii, edge in enumerate((NS.S, NS.NE, NS.W)):
self.buttons.append(Button(self, edge, AdvancePrompt.BUTTON_SIZE,
AdvancePrompt.BUTTON_BORDER))
self.buttons[-1].location.topleft = left, top
if ii < 2:
self.pluses.append(Sprite(self))
self.pluses[-1].load_from_path(self.get_resource("Plus.png"), True)
self.pluses[-1].location.center = (
self.buttons[-1].location.right + AdvancePrompt.BUTTON_SPACING / 2,
self.buttons[-1].location.centery)
left += self.buttons[-1].location.width + AdvancePrompt.BUTTON_SPACING
self.text = Sprite(self)
font = Font(self.get_resource(Dialogue.FONT_PATH), 18)
self.text.add_frame(font.render("TO SKIP", True, (0, 0, 0)).convert_alpha())
self.text.location.midleft = (
self.buttons[2].location.right + 5,
self.buttons[2].location.centery)
self.button_sound = self.get_audio().sfx["button"]
def reset(self):
self.press_index = 0
self.press_elapsed = 0
for button in self.buttons:
button.unhide()
for plus in self.pluses:
plus.unhide()
def update(self):
platform = self.get_game().platform
if self.press_index == 0 and platform.get_edge_pressed() == NS.S:
self.press_index += 1
self.button_sound.play()
self.buttons[0].hide()
self.pluses[0].hide()
elif self.press_index == 1 and platform.get_edge_pressed() == NS.NE:
self.press_index += 1
self.button_sound.play()
self.buttons[1].hide()
self.pluses[1].hide()
elif self.press_index == 2 and platform.get_edge_pressed() == NS.W:
self.callback()
self.get_audio().play_sfx("confirm")
elif self.press_index > 0:
self.press_elapsed += self.get_game().time_filter.get_last_frame_duration()
if self.press_elapsed > 4000:
self.reset()
for button in self.buttons:
button.update()
for plus in self.pluses:
plus.update()
self.text.update()
class AdvancePrompt(GameChild):
BUTTON_SIZE = 30
BUTTON_BORDER = 3
BUTTON_SPACING = 64
def __init__(self, parent):
GameChild.__init__(self, parent)
dsr = self.get_display_surface().get_rect()
self.buttons = Button(self, NS.N, self.BUTTON_SIZE, self.BUTTON_BORDER), \
Button(self, NS.NW, self.BUTTON_SIZE, self.BUTTON_BORDER)
self.plus = Sprite(self)
self.plus.load_from_path(self.get_resource("Plus.png"), True)
dsr = self.get_display_surface().get_rect()
self.plus.location.center = dsr.centerx, dsr.centery + 70
self.buttons[1].location.center = self.plus.location.move(self.BUTTON_SPACING, 0).center
self.buttons[0].location.center = self.plus.location.move(-self.BUTTON_SPACING, 0).center
self.background_rect = Rect(
self.buttons[0].location.topleft,
(self.buttons[1].location.right - self.buttons[0].location.left, self.buttons[0].location.height))
self.background_rect.inflate_ip((10, 10))
def reset(self):
self.cancel_first_press()
for button in self.buttons:
button.unhide()
self.plus.unhide()
def cancel_first_press(self):
self.first_pressed = False
self.first_pressed_elapsed = 0
self.buttons[0].unhide()
self.plus.unhide()
def check_first_press(self):
return not self.first_pressed and self.get_game().platform.get_edge_pressed() == NS.N
def press_first(self):
self.first_pressed = True
self.buttons[0].hide()
self.plus.hide()
self.get_audio().play_sfx("button")
def check_second_press(self):
pressed = self.first_pressed and self.get_game().platform.get_edge_pressed() == NS.NW
if pressed:
self.get_audio().play_sfx("confirm")
return pressed
def update(self):
if self.first_pressed:
self.first_pressed_elapsed += self.get_game().time_filter.get_last_frame_duration()
self.get_display_surface().fill((255, 255, 255), self.background_rect)
for button in self.buttons:
button.update()
self.plus.update()
class Wipe(Animation):
BLIND_COUNT = 4
SPEED = 6
TRANSPARENT_COLOR = 255, 0, 0
def __init__(self, parent):
Animation.__init__(self, parent)
self.image = load(self.get_resource("Ink.png")).convert()
self.image.set_colorkey(self.TRANSPARENT_COLOR)
self.sound = self.get_audio().sfx["wipe"]
def reset(self):
self.deactivate()
self.halt()
def deactivate(self):
self.active = False
def activate(self):
self.active = True
def start(self, callback):
self.activate()
self.up = True
# self.get_game().suppress_input()
self.blind_height = self.get_display_surface().get_height() / self.BLIND_COUNT
self.callback = callback
self.play()
self.sound.play()
def build_frame(self):
if self.up:
self.blind_height -= self.SPEED
if self.blind_height <= 0:
self.up = False
self.callback()
else:
self.blind_height += self.SPEED
if self.blind_height >= self.get_display_surface().get_height() / self.BLIND_COUNT:
self.halt()
self.deactivate()
self.get_game().unsuppress_input()
def update(self):
if self.active:
Animation.update(self)
ds = self.get_display_surface()
dsr = ds.get_rect()
frame = self.image.copy()
for y in range(0, dsr.h, dsr.h // self.BLIND_COUNT):
if self.up:
frame.fill(self.TRANSPARENT_COLOR, (0, y, dsr.w, self.blind_height))
else:
frame.fill(self.TRANSPARENT_COLOR,
(0, y + dsr.h / self.BLIND_COUNT - self.blind_height, dsr.w, self.blind_height))
ds.blit(frame, (0, 0))
class Platform(GameChild):
def __init__(self, parent):
GameChild.__init__(self, parent)
dsr = self.get_display_surface().get_rect()
self.border = Sprite(self)
self.border.load_from_path(self.get_resource("DancePadClear.png"), True)
self.border.location.midbottom = dsr.centerx, dsr.bottom
self.lights = [
Light(self, "cyan", NS.LNW),
Light(self, "magenta", NS.LNE),
Light(self, "yellow", NS.LSE),
Light(self, "white", NS.LSW)
]
def reset(self):
self.deactivate()
self.reset_lights()
def reset_lights(self):
for light in self.lights:
light.reset()
def deactivate(self):
self.active = False
def activate(self):
self.active = True
def unpress(self):
for light in self.lights:
light.pressed = False
def get_pressed(self):
return [light.position for light in self.lights if light.pressed]
def get_edge_pressed(self):
pressed = self.get_pressed()
if NS.LNW in pressed and NS.LNE in pressed:
return NS.N
elif NS.LNE in pressed and NS.LSW in pressed:
return NS.NE
elif NS.LNE in pressed and NS.LSE in pressed:
return NS.E
elif NS.LNW in pressed and NS.LSE in pressed:
return NS.NW
elif NS.LSE in pressed and NS.LSW in pressed:
return NS.S
elif NS.LSW in pressed and NS.LNW in pressed:
return NS.W
def get_buttons_from_edges(self, edges):
buttons = set()
for edge in edges:
if edge == NS.N:
buttons = buttons.union((NS.LNW, NS.LNE))
elif edge == NS.NE:
buttons = buttons.union((NS.LNE, NS.LSW))
elif edge == NS.E:
buttons = buttons.union((NS.LNE, NS.LSE))
elif edge == NS.NW:
buttons = buttons.union((NS.LNW, NS.LSE))
elif edge == NS.S:
buttons = buttons.union((NS.LSE, NS.LSW))
elif edge == NS.W:
buttons = buttons.union((NS.LSW, NS.LNW))
return list(buttons)
def get_steps_from_edge(self, edge):
if edge == NS.N:
return NS.NE, NS.NW
elif edge == NS.NE:
return NS.N, NS.E, NS.S, NS.W
elif edge == NS.E:
return NS.NE, NS.NW
elif edge == NS.NW:
return NS.N, NS.E, NS.S, NS.W
elif edge == NS.S:
return NS.NE, NS.NW
elif edge == NS.W:
return NS.NE, NS.NW
def get_right_angles_from_edge(self, edge):
if edge == NS.N:
return NS.E, NS.W
elif edge == NS.NE:
return None
elif edge == NS.E:
return NS.N, NS.S
elif edge == NS.NW:
return None
elif edge == NS.S:
return NS.E, NS.W
elif edge == NS.W:
return NS.N, NS.S
def get_opposite_of_edge(self, edge):
if edge == NS.N:
return NS.S
elif edge == NS.NE:
return NS.NW
elif edge == NS.E:
return NS.W
elif edge == NS.NW:
return NS.NE
elif edge == NS.S:
return NS.N
elif edge == NS.W:
return NS.E
def get_color_pair_from_edge(self, edge):
if edge == NS.N:
return self.lights[NS.LNW].color, self.lights[NS.LNE].color
elif edge == NS.NE:
return self.lights[NS.LNE].color, self.lights[NS.LSW].color
elif edge == NS.E:
return self.lights[NS.LNE].color, self.lights[NS.LSE].color
elif edge == NS.NW:
return self.lights[NS.LNW].color, self.lights[NS.LSE].color
elif edge == NS.S:
return self.lights[NS.LSW].color, self.lights[NS.LSE].color
elif edge == NS.W:
return self.lights[NS.LNW].color, self.lights[NS.LSW].color
def set_glowing(self, selected):
for ii, light in enumerate(self.lights):
light.glow_index = 0
light.halt(light.glow)
if ii in selected:
light.play(light.glow)
def update(self):
if self.active:
for light in self.lights:
light.update()
# self.border.update()
for light in self.lights:
light.draw_glow()
class Light(Animation):
MAX_GLOW_INDEX = 25
TITLE_OFFSET = 0
def __init__(self, parent, color, position):
Animation.__init__(self, parent)
self.color = Color(color)
self.color.a = 225
self.position = position
self.pressed = False
ds = self.get_display_surface()
frontleft = ds.get_width() / 2 - NS.FRONT_WIDTH / 2, NS.FRONT
backleft = ds.get_width() / 2 - NS.BACK_WIDTH / 2, NS.FRONT + NS.LENGTH
left_step = get_step_relative(frontleft, backleft, NS.STEP)
midleft = frontleft[0] + left_step[0], frontleft[1] + left_step[1]
frontmid = ds.get_width() / 2, NS.FRONT
mid = ds.get_width() / 2, NS.FRONT + NS.LENGTH * NS.STEP
backmid = ds.get_width() / 2, NS.FRONT + NS.LENGTH
frontright = ds.get_width() / 2 + NS.FRONT_WIDTH / 2, NS.FRONT
backright = ds.get_width() / 2 + NS.BACK_WIDTH / 2, NS.FRONT + NS.LENGTH
right_step = get_step_relative(frontright, backright, NS.STEP)
midright = frontright[0] + right_step[0], frontright[1] + right_step[1]
if self.position == NS.LNW:
self.points = frontleft, frontmid, mid, midleft
elif self.position == NS.LNE:
self.points = frontmid, frontright, midright, mid
elif self.position == NS.LSE:
self.points = mid, midright, backright, backmid
elif self.position == NS.LSW:
self.points = midleft, mid, backmid, backleft
self.register(self.blink, interval=300)
self.register(self.glow)
def reset(self):
self.hidden = False
self.halt(self.blink)
self.halt(self.glow)
self.reset_timer()
self.glow_index = 0
def blink(self):
self.hidden = not self.hidden
def glow(self):
self.glow_index += 1
if self.glow_index > self.MAX_GLOW_INDEX:
self.glow_index = 0
def update(self):
Animation.update(self)
if not self.get_game().title.active:
boss = self.get_game().boss
chemtrails = self.get_game().chemtrails
if boss.queue and boss.brandish_complete and not self.is_playing(self.glow) \
and self.in_orientation(boss.queue[chemtrails.queue_index]):
self.play(self.glow)
elif self.is_playing(self.glow) and (not boss.queue or
not self.in_orientation(boss.queue[chemtrails.queue_index])):
self.reset()
if not self.hidden:
ds = self.get_display_surface()
aa_filled_polygon(ds, self.get_points(), self.color)
def get_points(self):
if self.get_game().title.active:
points = []
for point in self.points:
points.append((point[0], point[1] - self.TITLE_OFFSET))
return points
else:
return self.points
def draw_glow(self):
for ii, y in enumerate(range(0, self.glow_index, 3)):
shifted = []
for point in self.get_points():
shifted.append((point[0], point[1] - y))
# ratio = 1 - float(y + 1) / (self.MAX_GLOW_INDEX + 1)
# alpha = int(ratio * 255)
# color = Color(self.color.r, self.color.g, self.color.b, alpha)
# ds = self.get_display_surface()
# intermediate = Surface(ds.get_size(), SRCALPHA)
if self.position == NS.LSW:
saturation = 0
else:
saturation = int((self.color.hsla[1] + 80) % 100)
if not ii % 2:
lightness = 0
else:
lightness = 40
lines(
self.get_display_surface(),
get_hsla_color(
int(self.color.hsla[0]), saturation, lightness
),
True, shifted, 3
)
# ds.blit(intermediate, (0, 0))
def in_orientation(self, orientation):
if self.position == NS.LNW:
return orientation in (NS.N, NS.NW, NS.W)
elif self.position == NS.LNE:
return orientation in (NS.N, NS.NE, NS.E)
elif self.position == NS.LSE:
return orientation in (NS.NW, NS.E, NS.S)
elif self.position == NS.LSW:
return orientation in (NS.S, NS.NE, NS.W)
class Chemtrails(Sprite):
def __init__(self, parent):
Sprite.__init__(self, parent)
self.load_from_path(self.get_resource("littleSlimeGoop"), True)
for direction in (NS.N, NS.NE, NS.E, NS.NW, NS.S, NS.W):
self.add_frameset([direction], switch=(direction == NS.N))
self.life = Life(self)
self.boys = Boys(self)
self.timer = Timer(self)
def reset(self):
self.deactivate()
self.life.reset()
self.boys.reset()
self.timer.reset()
def deactivate(self):
self.active = False
def activate(self):
self.active = True
def challenge(self):
self.timer.reset()
self.queue_index = 0
def update(self):
if self.active:
self.orient()
Sprite.update(self)
if not self.get_game().title.active:
boss = self.get_game().boss
if boss.queue:
self.timer.tick()
self.attack()
if self.timer.amount < 0:
self.life.decrease()
if not boss.is_playing(boss.show_end_dialogue, include_delay=True):
self.timer.reset()
boss.combo()
if not boss.is_playing(boss.show_introduction_dialogue, include_delay=True):
self.timer.update()
self.life.update()
# self.boys.update()
def attack(self):
boss = self.get_game().boss
queue = boss.queue
if self.orientation == queue[self.queue_index]:
self.timer.add_time(self.get_configuration("time", "timer-addition"))
if boss.level_index == 0:
boss.health.decrease(4)
elif boss.level_index == 1:
boss.health.decrease(4)
elif boss.level_index == 2:
boss.health.decrease(4)
self.queue_index += 1
boss.last_attack = self.orientation
boss.sword.block()
if self.queue_index == len(queue):
self.timer.reset()
if not boss.is_playing(boss.show_end_dialogue, include_delay=True):
boss.combo()
self.get_audio().play_sfx("complete_pattern_3")
else:
self.get_audio().play_sfx("land_0")
self.get_game().platform.reset_lights()
def orient(self):
ds = self.get_display_surface()
edge = self.get_game().platform.get_edge_pressed()
dy = -Light.TITLE_OFFSET if self.get_game().title.active else 0
if edge is not None:
self.set_frameset(edge + 1)
self.unhide()
else:
self.hide()
if edge == NS.N:
self.location.center = ds.get_width() / 2, NS.FRONT + 15 + dy
self.orientation = NS.N
elif edge == NS.E:
self.location.center = ds.get_width() / 2 + NS.FRONT_WIDTH / 2 - 115, \
NS.FRONT + NS.LENGTH * NS.STEP - 75 + dy
self.orientation = NS.E
elif edge == NS.S:
self.location.center = ds.get_width() / 2, \
NS.FRONT + NS.LENGTH - NS.LENGTH * NS.STEP - 110 + dy
self.orientation = NS.S
elif edge == NS.W:
self.location.center = ds.get_width() / 2 - NS.FRONT_WIDTH / 2 + 100, \
NS.FRONT + NS.LENGTH * NS.STEP - 85 + dy
self.orientation = NS.W
elif edge == NS.NW:
self.location.center = ds.get_width() / 2 + 5, \
NS.FRONT + NS.LENGTH * NS.STEP - 75 + dy
self.orientation = NS.NW
elif edge == NS.NE:
self.location.center = ds.get_width() / 2 + 10, \
NS.FRONT + NS.LENGTH * NS.STEP - 80 + dy
self.orientation = NS.NE
else:
self.orientation = None
class Timer(Meter):
def __init__(self, parent):
Meter.__init__(self, parent)
dsr = self.get_display_surface().get_rect()
background = load(self.get_resource("HUD_timer.png")).convert()
rect = background.get_rect()
rect.bottomright = dsr.right - 6, dsr.bottom - 4
self.setup(background, rect, 53, (0, 0, 255),
self.get_configuration("time", "timer-start-time"), "scrapeIcons/scrapeIcons_07.png")
def add_time(self, amount):
self.change(amount)
def tick(self):
self.change(-self.get_game().time_filter.get_last_frame_duration())
class Life(Meter):
def __init__(self, parent):
Meter.__init__(self, parent)
dsr = self.get_display_surface().get_rect()
background = load(self.get_resource("HUD_health.png")).convert()
rect = background.get_rect()
rect.bottomleft = 172, dsr.bottom - 4
self.setup(background, rect, 70, (255, 0, 0), 3, "scrapeIcons/scrapeIcons_03.png")
def decrease(self):
self.get_audio().play_sfx("hurt")
self.change(-1)
if self.amount <= 0:
self.amount = 0
self.parent.boys.change(-1)
self.get_game().boss.finish_battle(False)
class Boys(Meter):
def __init__(self, parent):
Meter.__init__(self, parent)
dsr = self.get_display_surface().get_rect()
background = load(self.get_resource("HUD_lives.png")).convert()
rect = background.get_rect()
rect.bottomleft = 6, dsr.bottom - 4
self.setup(background, rect, 60, (0, 255, 0), 3, "scrapeIcons/scrapeIcons_01.png")
class Boss(Animation):
def __init__(self, parent):
Animation.__init__(self, parent)
self.kool_man = RainbowSprite(self, load(self.get_resource("Kool_man_waah.png")).convert_alpha(), 30)
self.visitor = RainbowSprite(self, load(self.get_resource("Visitor.png")).convert_alpha(), 30)
self.spoopy = RainbowSprite(self, load(self.get_resource("Spoopy.png")).convert_alpha(), 30)
for sprite in self.kool_man, self.visitor, self.spoopy:
sprite.location.topleft = 100, 0
self.health = Health(self)
self.sword = Sword(self)
self.register(self.brandish, self.cancel_flash, self.show_introduction_dialogue,
self.show_end_dialogue, self.end_dialogue)
self.kool_man.add_frameset([0], name="normal", switch=True)
self.visitor.add_frameset([0], name="normal", switch=True)
self.spoopy.add_frameset([0], name="normal", switch=True)
self.kool_man_avatar = load(self.get_resource("Kool_man_avatar.png")).convert()
self.visitor_avatar = load(self.get_resource("Visitor_avatar.png")).convert()
self.spoopy_avatar = load(self.get_resource("Spoopy_avatar.png")).convert()
self.advance_prompt = AdvancePrompt(self)
self.backgrounds = [Sprite(self), Sprite(self), Sprite(self)]
self.backgrounds[0].load_from_path(self.get_resource("bg/bg001.png"))
self.backgrounds[1].load_from_path(self.get_resource("bg/bg002.png"))
self.backgrounds[2].load_from_path(self.get_resource("bg/bg003.png"))
self.countdown = Countdown(self)
def cancel_flash(self):
if self.level_index == 0:
self.kool_man.set_frameset("normal")
elif self.level_index == 1:
self.visitor.set_frameset("normal")
elif self.level_index == 2:
self.spoopy.set_frameset("normal")
def start_level(self, index):
self.level_index = index
self.battle_finished = False
self.player_defeated = False
self.health.reset()
self.get_game().chemtrails.timer.reset()
self.get_game().chemtrails.life.reset()
self.activate()
dialogue = self.get_game().dialogue
dialogue.deactivate()
if index == 0:
dialogue.set_avatar(self.kool_man_avatar)
dialogue.set_name("Kool Man")
self.kool_man.unhide()
self.kool_man.set_frameset("normal")
elif index == 1:
dialogue.set_avatar(self.visitor_avatar)
dialogue.set_name("Visitor")
self.visitor.unhide()
self.visitor.set_frameset("normal")
elif index == 2:
dialogue.set_avatar(self.spoopy_avatar)
dialogue.set_name("Spoopy")
self.spoopy.unhide()
self.spoopy.set_frameset("normal")
self.play(self.show_introduction_dialogue, delay=3000, play_once=True)
self.get_game().platform.activate()
self.get_game().chemtrails.activate()
self.last_attack = NS.NW
def show_introduction_dialogue(self):
dialogue = self.get_game().dialogue
dialogue.activate()
if self.level_index == 0:
dialogue.show_text("You'll never be able to block my sword, you lizard slime!" +
" See\nif you can keep up with these moves!")
elif self.level_index == 1:
dialogue.show_text("We're just warming up, slime breath! Prepare to get spun" +
" by\nthese combos!")
elif self.level_index == 2:
dialogue.show_text("Lizard! My moves are so unpredictable you might as well" +
" give\nup now!")
self.play(self.end_dialogue, delay=5000, play_once=True)
def reset(self):
self.level_index = 0
self.kills = 0
self.time_elapsed = 0
self.deactivate()
self.cancel_flash()
self.halt(self.cancel_flash)
self.health.reset()
self.halt(self.brandish)
self.sword.reset()
self.advance_prompt.reset()
self.queue = None
self.brandish_complete = True
self.countdown.reset()
self.halt(self.end_dialogue)
def deactivate(self):
self.active = False
def activate(self):
self.active = True
def combo(self, delay=2500):
self.queue = None
if self.get_game().serial_enabled():
self.get_game().reset_arduino()
self.play(self.brandish, delay=delay, play_once=True)
def brandish(self):
self.queue = []
platform = self.get_game().platform
if self.level_index == 0:
if self.health.amount > 90:
first = choice(platform.get_steps_from_edge(self.last_attack))
self.queue = [first]
elif self.health.amount > 70:
first = choice(platform.get_steps_from_edge(self.last_attack))
self.queue = [first, choice(platform.get_steps_from_edge(first))]
elif self.health.amount > 30:
choices = [0]
if self.last_attack in (NS.NE, NS.NW):
choices.append(1)
else:
choices.extend((2, 3))
result = choice(choices)
if result == 0:
first = choice(platform.get_steps_from_edge(self.last_attack))
second = choice(platform.get_steps_from_edge(first))
self.queue = [first, second, first, second]
elif result == 1:
first = choice(platform.get_steps_from_edge(self.last_attack))
self.queue = [first, choice(platform.get_steps_from_edge(first)),
choice(platform.get_right_angles_from_edge(first))]
elif result == 2:
first = choice(platform.get_steps_from_edge(self.last_attack))
self.queue = [first, choice(platform.get_steps_from_edge(first)),
platform.get_opposite_of_edge(first)]
elif result == 3:
first = choice(platform.get_steps_from_edge(self.last_attack))
second = choice(platform.get_steps_from_edge(first))
self.queue = [first, second,
choice(platform.get_right_angles_from_edge(second))]
else:
choices = [0, 1]
if self.last_attack in (NS.NE, NS.NW):
choices.extend((2, 3, 4))
else:
choices.append(5)
result = choice(choices)
if result == 0 or result == 1:
first = choice(platform.get_steps_from_edge(self.last_attack))
second = choice(platform.get_steps_from_edge(first))
last = second if result else platform.get_opposite_of_edge(second)
self.queue = [first, second, platform.get_opposite_of_edge(first),
last]
elif result == 2:
first = choice(platform.get_steps_from_edge(self.last_attack))
self.queue = [first, choice(platform.get_right_angles_from_edge(first)),
platform.get_opposite_of_edge(first)]
elif result == 3:
first = choice(platform.get_steps_from_edge(self.last_attack))
self.queue = [first, choice(platform.get_steps_from_edge(first)),
choice(platform.get_right_angles_from_edge(first)),
platform.get_opposite_of_edge(first)]
elif result == 4:
first = choice(platform.get_steps_from_edge(self.last_attack))
second = choice(platform.get_steps_from_edge(first))
self.queue = [first, second,
choice(platform.get_right_angles_from_edge(first)),
platform.get_opposite_of_edge(second)]
elif result == 5:
first = choice(platform.get_steps_from_edge(self.last_attack))
second = choice(platform.get_steps_from_edge(first))
self.queue = [first, second, platform.get_opposite_of_edge(first),
choice(platform.get_right_angles_from_edge(second))]
elif self.level_index == 1:
if self.health.amount > 85:
if self.last_attack in (NS.NE, NS.NW):
choices = 1, 2
else:
choices = 0,
result = choice(choices)
if result == 0:
first = choice(platform.get_steps_from_edge(self.last_attack))
self.queue = [first, platform.get_opposite_of_edge(first)]
elif result == 1:
first = choice(platform.get_steps_from_edge(self.last_attack))
self.queue = [first, choice(platform.get_right_angles_from_edge(first)),
platform.get_opposite_of_edge(first)]
elif result == 2:
first = choice(platform.get_steps_from_edge(self.last_attack))
self.queue = [first, platform.get_opposite_of_edge(first)]
elif self.health.amount > 60:
if self.last_attack in (NS.NE, NS.NW):
choices = 2, 3
else:
choices = 0, 1
result = choice(choices)
first = choice(platform.get_steps_from_edge(self.last_attack))
if result == 0:
second = choice(platform.get_steps_from_edge(first))
self.queue = [first, second, platform.get_opposite_of_edge(second)]
elif result == 1:
second = choice(platform.get_steps_from_edge(first))
self.queue = [first, second,
choice(platform.get_right_angles_from_edge(second)),
platform.get_opposite_of_edge(first)]
elif result == 2:
second = platform.get_opposite_of_edge(first)
self.queue = [first, second,
choice(platform.get_right_angles_from_edge(second))]
elif result == 3:
second = choice(platform.get_right_angles_from_edge(first))
self.queue = [first, second, platform.get_opposite_of_edge(first),
platform.get_opposite_of_edge(second)]
elif self.health.amount > 30:
result = choice(range(3))
if result == 0:
first = self.choose_new_edge((NS.N, NS.E, NS.S, NS.W))
self.queue = [first, choice(platform.get_steps_from_edge(first)),
platform.get_opposite_of_edge(first), first]
elif result == 1:
first = self.choose_new_edge((NS.NE, NS.NW))
second = choice(platform.get_steps_from_edge(first))
self.queue = [first, second, platform.get_opposite_of_edge(second),
choice(platform.get_right_angles_from_edge(second))]
elif result == 2:
first = self.choose_new_edge((NS.NE, NS.NW))
second = choice(platform.get_steps_from_edge(first))
self.queue = [first, second,
choice(platform.get_right_angles_from_edge(second)),
platform.get_opposite_of_edge(second)]
else:
result = choice(range(4))
if result == 0:
first = self.choose_new_edge((NS.NE, NS.NW))
second = platform.get_opposite_of_edge(first)
self.queue = [first, second, first, second]
elif result == 1:
first = self.choose_new_edge((NS.N, NS.E, NS.S, NS.W))
self.queue = [first, platform.get_opposite_of_edge(first), first]
elif result == 2:
first = self.choose_new_edge((NS.N, NS.E, NS.S, NS.W))
self.queue = [first, choice(platform.get_steps_from_edge(first)),
choice(platform.get_right_angles_from_edge(first)),
platform.get_opposite_of_edge(first), first]
elif result == 3:
first = self.choose_new_edge((NS.N, NS.E, NS.S, NS.W))
second = platform.get_opposite_of_edge(first)
third = choice(platform.get_right_angles_from_edge(first))
self.queue = [first, second, third, platform.get_opposite_of_edge(second),
platform.get_opposite_of_edge(third)]
elif self.level_index == 2:
if self.health.amount > 90:
length = 3
elif self.health.amount > 70:
length = 4
elif self.health.amount > 40:
length = 5
else:
length = 6
while len(self.queue) < length:
while True:
orientation = randint(0, 5)
if (not self.queue and orientation != self.last_attack) or \
(len(self.queue) > 0 and orientation != self.queue[-1]):
self.queue.append(orientation)
break
self.unbrandished = copy(self.queue)
self.brandish_complete = False
self.sword.reset()
self.sword.play(self.sword.brandish, play_once=True)
self.get_game().chemtrails.challenge()
def choose_new_edge(self, edges):
while True:
edge = choice(edges)
if edge != self.last_attack:
return edge
def finish_battle(self, win):
self.battle_finished = True
self.halt(self.brandish)
self.halt(self.cancel_flash)
self.sword.reset()
self.queue = []
self.brandish_complete = True
if win:
if self.level_index == 0:
self.kool_man.set_frameset(0)
elif self.level_index == 1:
self.visitor.set_frameset(0)
elif self.level_index == 2:
self.spoopy.set_frameset(0)
self.add_score()
self.player_defeated = not win
self.kills += not win
self.play(self.show_end_dialogue, delay=3000, play_once=True)
def add_score(self):
self.get_game().set_most_recent_time(self.time_elapsed)
open(self.get_resource("scores"), "a").write(str(self.time_elapsed) + "\n")
def show_end_dialogue(self):
dialogue = self.get_game().dialogue
dialogue.activate()
if self.level_index == 0:
if self.player_defeated:
dialogue.show_text("Maybe next time!")
else:
dialogue.show_text("Hey! Wow! Lizard!")
elif self.level_index == 1:
if self.player_defeated:
dialogue.show_text("Wiped out!")
else:
dialogue.show_text("Well done! But it's not over yet!")
elif self.level_index == 2:
if self.player_defeated:
dialogue.show_text("Just like I thought!")
else:
dialogue.show_text("H-how? But you're only a lizard! How could you" +
" manage to defeat\nall of us?")
if self.player_defeated:
self.countdown.activate()
else:
self.play(self.end_dialogue, delay=5000, play_once=True)
def transition_to_battle(self):
index = self.level_index + (not self.player_defeated)
if self.kills >= 3:
self.get_game().reset(True)
elif index < 3:
self.start_level(index)
else:
game = self.get_game()
game.boss.reset()
game.chemtrails.reset()
game.platform.reset()
game.ending.activate()
def transition_to_title(self):
self.get_game().reset(True)
def damage(self):
if self.level_index == 0:
self.kool_man.set_frameset(0)
elif self.level_index == 1:
self.visitor.set_frameset(0)
elif self.level_index == 2:
self.spoopy.set_frameset(0)
def end_dialogue(self):
self.get_game().dialogue.deactivate()
if not self.battle_finished:
self.combo(delay=1300)
else:
self.get_game().wipe.start(self.transition_to_battle)
def update(self):
if self.active:
self.backgrounds[self.level_index].update()
dialogue = self.get_game().dialogue
if self.countdown.active and dialogue.active and self.get_game().chemtrails.boys.amount > 0:
if self.advance_prompt.check_first_press():
self.advance_prompt.press_first()
elif self.advance_prompt.check_second_press():
self.countdown.deactivate()
if dialogue.is_playing():
dialogue.show_all()
else:
self.get_game().dialogue.deactivate()
if not self.battle_finished:
self.combo()
else:
self.get_game().wipe.start(self.transition_to_battle)
self.advance_prompt.cancel_first_press()
else:
self.time_elapsed += self.get_game().time_filter.get_last_frame_duration()
Animation.update(self)
if self.level_index == 0:
self.kool_man.update()
elif self.level_index == 1:
self.visitor.update()
elif self.level_index == 2:
self.spoopy.update()
self.sword.update()
self.health.update()
self.countdown.update()
def update_dialogue(self):
if self.active:
dialogue = self.get_game().dialogue
if dialogue.active:
self.get_game().dialogue.update()
if self.countdown.active:
self.advance_prompt.update()
class Countdown(GameChild):
def __init__(self, parent):
GameChild.__init__(self, parent)
dsr = self.get_display_surface().get_rect()
font = Font(self.get_resource(Dialogue.FONT_PATH), 76)
self.heading = Sprite(self)
self.heading.add_frame(font.render("CONTINUE?", True, (0, 0, 0), (255, 255, 255)).convert_alpha())
self.heading.location.midtop = dsr.centerx, 50
self.game_over = Sprite(self)
self.game_over.add_frame(font.render("GAME OVER", True, (0, 0, 0), (255, 255, 255)).convert_alpha())
self.game_over.location.center = dsr.centerx, dsr.centery - 40
self.glyphs = []
for ii in range(10):
glyph = Sprite(self)
frame = Surface((140, 140))
frame.fill((255, 255, 255))
digits = font.render("%i" % ii, True, (0, 0, 0), (255, 255, 255)).convert_alpha()
rect = digits.get_rect()
rect.center = frame.get_rect().center
frame.blit(digits, rect)
glyph.add_frame(frame)
glyph.location.center = dsr.centerx, dsr.centery - 30
self.glyphs.append(glyph)
def reset(self):
self.deactivate()
def deactivate(self):
self.active = False
def activate(self):
self.remaining = 9999
self.active = True
def end_game(self):
self.get_game().reset(True)
def update(self):
if self.active:
if self.get_game().chemtrails.boys.amount > 0:
self.heading.update()
self.glyphs[int(self.remaining / 1000)].update()
else:
self.game_over.update()
if not self.get_game().wipe.is_playing():
if self.remaining <= 0:
self.get_game().wipe.start(self.end_game)
self.remaining = 0
else:
self.remaining -= self.get_game().time_filter.get_last_frame_duration()
class Sword(Animation):
SHIFT = 15
SPRITE_COUNT = 6
def __init__(self, parent):
Animation.__init__(self, parent)
swords = self.swords = []
for root in "Sword_kool_man/", "Sword_visitor/", "Sword_spoopy/":
swords.append([[], [], [], [], [], []])
for path in sorted(iglob(join(self.get_resource(root), "*.png"))):
base = load(self.get_resource(path)).convert_alpha()
for position in range(6):
if position == NS.N or position == NS.S:
rotated = rotate(base, 270)
elif position == NS.NW:
rotated = rotate(base, 45)
elif position == NS.NE:
rotated = rotate(base, 310)
else:
rotated = base
surface = rotated.copy()
colors = self.get_game().platform.get_color_pair_from_edge(position)
color_a = Color(colors[0].r, colors[0].g, colors[0].b, 255)
color_b = Color(colors[1].r, colors[1].g, colors[1].b, 255)
rect = surface.get_rect()
if position == NS.N or position == NS.S:
surface.fill(color_a, (0, 0, rect.w / 2, rect.h), BLEND_RGBA_MIN)
surface.fill(color_b, (rect.centerx, 0, rect.w / 2, rect.h), BLEND_RGBA_MIN)
else:
surface.fill(color_a, (0, 0, rect.w, rect.h / 2), BLEND_RGBA_MIN)
surface.fill(color_b, (0, rect.centery, rect.w, rect.h / 2), BLEND_RGBA_MIN)
swords[-1][position].append(surface)
masks = self.masks = []
for alpha in range(16, 255, 16):
surface = Surface((300, 300), SRCALPHA)
surface.fill((255, 255, 255, alpha))
masks.append(surface)
self.register(self.brandish, self.lower)
def reset(self):
self.halt(self.brandish)
self.halt(self.lower)
self.next_index = 0
self.sprites = []
def brandish(self):
position = self.parent.unbrandished.pop(0)
offset = -self.SHIFT
for ii, queued in enumerate(self.parent.queue):
offset += self.SHIFT * (queued == position)
if len(self.parent.unbrandished) == len(self.parent.queue) - ii - 1:
break
dsr = self.get_display_surface().get_rect()
sprite = Sprite(self)
for frame in self.swords[self.parent.level_index][position]:
sprite.add_frame(frame)
if position in (NS.W, NS.E):
sprite.location.centery = dsr.centery - 100 + offset
if position == NS.W:
sprite.location.centerx = dsr.centerx - 100 - offset
else:
sprite.location.centerx = dsr.centerx + 100 - offset
elif position in (NS.N, NS.S):
sprite.location.centerx = dsr.centerx - offset
if position == NS.N:
sprite.location.centery = dsr.centery - 170 + offset
else:
sprite.location.centery = dsr.centery + offset
else:
sprite.location.center = dsr.centerx - offset, dsr.centery - 100
self.sprites.append(sprite)
self.get_audio().play_sfx("brandish")
self.play(self.lower, delay=400, play_once=True)
if len(self.parent.unbrandished) > 0:
self.play(self.brandish, delay=self.get_configuration("time", "sword-delay"),
play_once=True)
def lower(self):
if len(self.parent.unbrandished) == 0:
self.parent.brandish_complete = True
def block(self):
if len(self.sprites):
self.sprites.pop(0)
def update(self):
Animation.update(self)
for ii, sprite in enumerate(reversed(self.sprites)):
if ii == len(self.sprites) - 1:
substitute = None
else:
mask = self.masks[int(float(ii + 1) / len(self.sprites) * len(self.masks))]
frame = sprite.get_current_frame()
copy = frame.copy()
copy.blit(mask, (0, 0), None, BLEND_RGBA_MIN)
substitute = copy
sprite.update(substitute=substitute)
class Health(Meter):
OFFSET = 4
def __init__(self, parent):
Meter.__init__(self, parent)
dsr = self.get_display_surface().get_rect()
self.background = load(self.get_resource("HUD_boss.png")).convert()
self.rect = self.background.get_rect()
self.rect.midtop = dsr.centerx, self.OFFSET
def setup(self):
level_index = self.get_game().boss.level_index
if level_index == 0:
icon_index = 22
elif level_index == 1:
icon_index = 17
elif level_index == 2:
icon_index = 19
Meter.setup(self, self.background, self.rect, 52, (255, 0, 255), 100,
"scrapeIcons/scrapeIcons_%i.png" % icon_index)
def reset(self):
self.setup()
Meter.reset(self)
def decrease(self, damage):
self.change(-damage)
self.parent.damage()
if self.amount <= 0:
self.amount = 0
self.get_audio().play_sfx("complete_pattern_1")
self.get_audio().play_sfx("defeat")
self.get_game().boss.finish_battle(True)
else:
self.parent.play(self.parent.cancel_flash, delay=1000, play_once=True)
class Ending(Animation):
TEXT = "Wow! You vanquished all the goons and skated like a pro, slime bag.\n" + \
"You made your father proud today. I love you, child.",
def __init__(self, parent):
Animation.__init__(self, parent)
self.slime_bag = Sprite(self)
self.slime_bag.load_from_path(self.get_resource("Introduction_slime_bag.png"), True)
self.slime_bag.location.center = self.get_display_surface().get_rect().centerx, 300
self.tony_avatar = load(self.get_resource("Introduction_tony_avatar.png")).convert()
self.advance_prompt = AdvancePrompt(self)
self.register(self.start, self.start_wipe)
def reset(self):
self.deactivate()
self.slime_bag.unhide()
self.halt()
self.text_index = 0
self.advance_prompt.reset()
self.angle = choice((pi / 4, 3 * pi / 4, 5 * pi / 4, 7 * pi / 4))
def deactivate(self):
self.active = False
def activate(self):
self.active = True
self.play(self.start, delay=3000, play_once=True)
font = Font(self.get_resource("rounded-mplus-1m-bold.ttf"), 64)
time = self.get_game().title.get_formatted_time(self.get_game().most_recent_time)
foreground = font.render(time, False, (180, 150, 20), (255, 255, 255)).convert_alpha()
dsr = self.get_display_surface().get_rect()
self.text = RainbowSprite(self, foreground, 180, 200)
self.text.location.midtop = dsr.centerx, 80
self.get_game().tony.set_frameset("static")
dialogue = self.get_game().dialogue
dialogue.activate()
dialogue.set_avatar(self.tony_avatar)
dialogue.set_name("???")
dialogue.show_text("")
self.play(self.start_wipe, delay=20000, play_once=True)
def start(self):
self.advance_prompt.cancel_first_press()
dialogue = self.get_game().dialogue
# dialogue.activate()
# dialogue.set_avatar(self.tony_avatar)
dialogue.set_name("Tony")
dialogue.show_text(self.TEXT[0])
self.text_index = 0
def end_game(self):
self.deactivate()
self.get_game().reset(True)
def start_wipe(self):
self.get_game().wipe.start(self.end_game)
def update(self):
if self.active:
Animation.update(self)
dialogue = self.get_game().dialogue
wipe = self.get_game().wipe
# if not wipe.is_playing() and not self.is_playing(self.start) and not self.text_index == 2:
# if self.advance_prompt.check_first_press():
# self.advance_prompt.press_first()
# elif self.advance_prompt.check_second_press():
# if dialogue.is_playing():
# dialogue.show_all()
# else:
# if self.text_index < len(self.TEXT) - 1:
# pass
# else:
# self.start_wipe()
# self.advance_prompt.cancel_first_press()
self.get_game().logo.update()
self.get_game().tony.update()
self.slime_bag.update()
dsr = self.get_display_surface().get_rect()
if self.text.location.right > dsr.right or self.text.location.left < dsr.left:
self.angle = reflect_angle(self.angle, 0)
if self.text.location.right > dsr.right:
self.text.move(dsr.right - self.text.location.right)
else:
self.text.move(dsr.left - self.text.location.left)
if self.text.location.bottom > self.get_game().dialogue.avatar_box.location.top \
or self.text.location.top < dsr.top:
self.angle = reflect_angle(self.angle, pi)
if self.text.location.top < dsr.top:
self.text.move(dy=dsr.top - self.text.location.top)
else:
self.text.move(
dy=self.get_game().dialogue.avatar_box.location.top - \
self.text.location.bottom)
dx, dy = get_delta(self.angle, 5, False)
self.text.move(dx, dy)
self.text.update()
self.get_game().dialogue.update()
# if not wipe.is_playing() and not self.is_playing(self.start):
# self.advance_prompt.update()