1819 lines
72 KiB
Python
1819 lines
72 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
from random import randint, choice
|
|
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
|
|
from PIL import Image, ImageDraw
|
|
|
|
from pygame import Surface, Color
|
|
from pygame.event import clear
|
|
from pygame.mixer import Sound
|
|
from pygame.image import load, fromstring
|
|
from pygame.transform import rotate, flip
|
|
from pygame.time import get_ticks
|
|
from pygame.font import Font
|
|
from pygame.draw import aalines, lines
|
|
from pygame.gfxdraw import aapolygon, arc, polygon
|
|
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.Audio import SoundEffect
|
|
from lib.pgfw.pgfw.extension import (
|
|
get_step, get_step_relative, get_delta, reflect_angle,
|
|
render_box, get_hsla_color, get_hue_shifted_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
|
|
|
|
def __init__(self):
|
|
Game.__init__(self)
|
|
Animation.__init__(self, self)
|
|
self.load_sfx()
|
|
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.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)
|
|
self.get_configuration().type_declarations.add_chart(
|
|
{
|
|
"time":
|
|
{
|
|
"int": ["timer-max-time", "timer-start-time", "timer-addition", "sword-delay"]
|
|
},
|
|
"input":
|
|
{
|
|
"bool": "serial"
|
|
}
|
|
})
|
|
if self.serial_enabled():
|
|
self.serial_kill = False
|
|
self.serial_data = 0
|
|
self.serial_reader = Serial(self.get_configuration("input", "arduino-port"), timeout=.1)
|
|
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 load_sfx(self):
|
|
sfx = self.sfx = {}
|
|
for path in iglob(self.get_resource("sfx/") + "*.wav"):
|
|
sfx[basename(path.split(".")[0])] = SoundEffect(self, path)
|
|
|
|
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:
|
|
output = self.serial_reader.readline().strip()
|
|
if output:
|
|
self.serial_data = int(output, 2)
|
|
self.idle_elapsed = 0
|
|
else:
|
|
self.serial_data = 0
|
|
|
|
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()
|
|
|
|
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()
|
|
self.last_press = get_ticks()
|
|
else:
|
|
if self.get_delegate().compare(event, "reset-game"):
|
|
self.reset()
|
|
|
|
def update(self):
|
|
Animation.update(self)
|
|
if self.serial_enabled():
|
|
self.apply_serial()
|
|
self.title.update()
|
|
self.introduction.update()
|
|
self.ending.update()
|
|
self.boss.update()
|
|
if not self.introduction.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 xrange(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 xrange(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 Title(GameChild):
|
|
|
|
def __init__(self, parent):
|
|
GameChild.__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.slime_bag = Sprite(self)
|
|
self.slime_bag.load_from_path(self.get_resource("Title_slime_bag.png"), True)
|
|
self.slime_bag.location.bottomleft = dsr.bottomleft
|
|
image = load(self.get_resource("Title_border.png")).convert()
|
|
image.set_colorkey((0, 0, 0))
|
|
self.border = RainbowSprite(self, image, 30)
|
|
self.border.location.center = dsr.centerx, dsr.bottom - 100
|
|
self.text = Sprite(self)
|
|
self.text.load_from_path(self.get_resource("Title_text.png"), True, False, (255, 0, 0))
|
|
self.text.location.center = dsr.centerx, dsr.bottom - 100
|
|
self.angle = choice((pi / 4, 3 * pi / 4, 5 * pi / 4, 7 * pi / 4))
|
|
self.button_sound = self.get_game().sfx["button"]
|
|
self.buttons = Button(self, NS.N, 10, 4), Button(self, NS.NW, 10, 4)
|
|
self.buttons[0].location.center = 277, 381
|
|
self.buttons[1].location.center = 453, 381
|
|
|
|
def reset(self):
|
|
self.activate()
|
|
self.first_pressed = False
|
|
self.first_pressed_elapsed = 0
|
|
for button in self.buttons:
|
|
button.unhide()
|
|
|
|
def activate(self):
|
|
self.active = True
|
|
|
|
def deactivate(self):
|
|
self.active = False
|
|
|
|
def activate_introduction(self):
|
|
self.deactivate()
|
|
self.get_game().introduction.activate()
|
|
self.get_game().set_most_recent_time(None)
|
|
|
|
def draw_scores(self):
|
|
step = 75
|
|
ds = self.get_display_surface()
|
|
lines = map(int, file(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(200)
|
|
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 update(self):
|
|
if self.active:
|
|
ds = self.get_display_surface()
|
|
ds.fill((255, 255, 255))
|
|
dsr = ds.get_rect()
|
|
if self.plank.location.right > dsr.right or self.plank.location.left < dsr.left:
|
|
self.angle = reflect_angle(self.angle, 0)
|
|
if self.plank.location.right > dsr.right:
|
|
self.plank.move(dsr.right - self.plank.location.right)
|
|
else:
|
|
self.plank.move(dsr.left - self.plank.location.left)
|
|
if self.plank.location.bottom > dsr.bottom or self.plank.location.top < dsr.top:
|
|
self.angle = reflect_angle(self.angle, pi)
|
|
if self.plank.location.bottom > dsr.bottom:
|
|
self.plank.move(dy=dsr.bottom - self.plank.location.bottom)
|
|
else:
|
|
self.plank.move(dy=dsr.top - self.plank.location.top)
|
|
dx, dy = get_delta(self.angle, 2, False)
|
|
self.plank.move(dx, dy)
|
|
self.plank.update()
|
|
self.slime_bag.update()
|
|
wipe = self.get_game().wipe
|
|
if not self.first_pressed and self.get_game().platform.get_edge_pressed() == NS.N:
|
|
self.first_pressed = True
|
|
self.first_pressed_elapsed = 0
|
|
self.buttons[0].hide()
|
|
self.button_sound.play()
|
|
elif not wipe.is_playing() and self.first_pressed and \
|
|
self.get_game().platform.get_edge_pressed() == NS.NW:
|
|
wipe.start(self.activate_introduction)
|
|
self.get_game().sfx["confirm"].play()
|
|
elif self.first_pressed:
|
|
self.first_pressed_elapsed += self.get_game().time_filter.get_last_frame_duration()
|
|
if self.first_pressed_elapsed > 4000:
|
|
self.first_pressed = False
|
|
self.first_pressed_elapsed = 0
|
|
self.buttons[0].unhide()
|
|
self.border.update()
|
|
self.text.update()
|
|
self.draw_scores()
|
|
for button in self.buttons:
|
|
button.update()
|
|
|
|
|
|
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))
|
|
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_game().sfx["talk"].play(-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)
|
|
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" + \
|
|
"the glowing pads on the platform!", \
|
|
"Good job, lizard scum! 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.tony = load(self.get_resource("Big_Tony.png")).convert()
|
|
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)
|
|
|
|
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.advance_prompt.reset()
|
|
self.skip_prompt.reset()
|
|
|
|
def deactivate(self):
|
|
self.active = False
|
|
|
|
def activate(self):
|
|
self.active = True
|
|
self.play(self.start, delay=3000, play_once=True)
|
|
# self.get_game().platform.unpress()
|
|
|
|
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])
|
|
self.text_index = 0
|
|
|
|
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_game().sfx["go"].play()
|
|
|
|
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 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_game().sfx["land_0"].play()
|
|
if self.tutorial_index == len(self.TUTORIAL_MOVES):
|
|
self.text_index += 1
|
|
self.advance_prompt.cancel_first_press()
|
|
platform.set_glowing([])
|
|
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_display_surface().blit(self.tony, (0, 0))
|
|
self.slime_bag.update()
|
|
self.skateboard.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)))
|
|
self.text.location.midleft = (
|
|
self.buttons[2].location.right + 5,
|
|
self.buttons[2].location.centery)
|
|
self.button_sound = self.get_game().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_game().sfx["confirm"].play()
|
|
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 = 8
|
|
BUTTON_BORDER = 1
|
|
BUTTON_SPACING = 27
|
|
|
|
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.buttons[1].location.bottomright = dsr.right - 3, dsr.bottom - 3
|
|
self.buttons[0].location.bottomright = (
|
|
self.buttons[1].location.right - self.buttons[0].location.w - self.BUTTON_SPACING,
|
|
self.buttons[1].location.bottom)
|
|
self.plus = Sprite(self)
|
|
self.plus.load_from_path(self.get_resource("Plus.png"), True)
|
|
self.plus.location.center = self.buttons[1].location.left - self.BUTTON_SPACING / 2, \
|
|
self.buttons[1].location.centery
|
|
|
|
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_game().sfx["button"].play()
|
|
|
|
def check_second_press(self):
|
|
pressed = self.first_pressed and self.get_game().platform.get_edge_pressed() == NS.NW
|
|
if pressed:
|
|
self.get_game().sfx["confirm"].play()
|
|
return pressed
|
|
|
|
def update(self):
|
|
if self.first_pressed:
|
|
self.first_pressed_elapsed += self.get_game().time_filter.get_last_frame_duration()
|
|
if self.first_pressed_elapsed > 4000:
|
|
self.cancel_first_press()
|
|
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_game().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 xrange(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)
|
|
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()
|
|
for light in self.lights:
|
|
light.draw_glow()
|
|
|
|
|
|
class Light(Animation):
|
|
|
|
MAX_GLOW_INDEX = 25
|
|
INTRODUCTION_OFFSET = 80
|
|
|
|
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().introduction.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().introduction.active:
|
|
points = []
|
|
for point in self.points:
|
|
points.append((point[0], point[1] - self.INTRODUCTION_OFFSET))
|
|
return points
|
|
else:
|
|
return self.points
|
|
|
|
def draw_glow(self):
|
|
for ii, y in enumerate(xrange(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.timer = Timer(self)
|
|
|
|
def reset(self):
|
|
self.deactivate()
|
|
self.life.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().introduction.active:
|
|
boss = self.get_game().boss
|
|
if boss.queue:
|
|
self.timer.tick()
|
|
self.attack()
|
|
if self.timer.time_remaining < 0:
|
|
self.life.decrease()
|
|
if not boss.is_playing(boss.show_end_dialogue):
|
|
self.timer.reset()
|
|
boss.combo()
|
|
# self.timer.update()
|
|
self.life.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):
|
|
boss.combo()
|
|
self.get_game().sfx["complete_pattern_3"].play()
|
|
else:
|
|
self.get_game().sfx["land_0"].play()
|
|
self.get_game().platform.reset_lights()
|
|
|
|
def orient(self):
|
|
ds = self.get_display_surface()
|
|
edge = self.get_game().platform.get_edge_pressed()
|
|
dy = -Light.INTRODUCTION_OFFSET if self.get_game().introduction.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(GameChild):
|
|
|
|
TEXT = u"\u25F7"
|
|
BAR_POSITION = 448, 11
|
|
SIZE = 160
|
|
TOP = 120
|
|
RING_OFFSET = 8
|
|
|
|
def __init__(self, parent):
|
|
GameChild.__init__(self, parent)
|
|
self.background = Sprite(self)
|
|
image = load(self.get_resource("HUD_background.png")).convert_alpha()
|
|
image = flip(image, True, False)
|
|
self.background.add_frame(image)
|
|
self.background.location.topright = self.get_display_surface().get_rect().topright
|
|
self.bar = load(self.get_resource("HUD_bar.png")).convert_alpha()
|
|
self.bar = flip(self.bar, True, False)
|
|
self.hourglass = Sprite(self)
|
|
self.hourglass.load_from_path(self.get_resource("Hourglass.png"), True)
|
|
dsr = self.get_display_surface().get_rect()
|
|
self.hourglass.location.midright = dsr.right, self.TOP + self.SIZE / 2
|
|
|
|
def reset(self):
|
|
self.time_remaining = self.get_configuration("time", "timer-start-time")
|
|
|
|
def add_time(self, amount):
|
|
self.time_remaining += amount
|
|
|
|
def tick(self):
|
|
self.time_remaining -= self.get_game().time_filter.get_last_frame_duration()
|
|
|
|
def update(self):
|
|
self.hourglass.update()
|
|
if self.time_remaining > 5500:
|
|
hue = 120
|
|
elif self.time_remaining > 3000:
|
|
hue = 30
|
|
else:
|
|
hue = 0
|
|
ds = self.get_display_surface()
|
|
max_time = self.get_configuration("time", "timer-max-time")
|
|
remaining_ratio = float(self.time_remaining) / max_time
|
|
left = ds.get_width() - self.SIZE / 2
|
|
ds.blit(self.get_ring(get_hsla_color(hue, lightness=20, alpha=67), remaining_ratio),
|
|
(left, self.TOP + self.RING_OFFSET))
|
|
ds.blit(self.get_ring(get_hsla_color(hue, lightness=80, alpha=67), remaining_ratio),
|
|
(left, self.TOP - self.RING_OFFSET))
|
|
ds.blit(self.get_ring(get_hsla_color(hue, alpha=67), remaining_ratio), (left, self.TOP))
|
|
|
|
def get_ring(self, color, remaining):
|
|
image = Image.new("RGBA", (self.SIZE, self.SIZE))
|
|
draw = ImageDraw.Draw(image)
|
|
draw.pieslice((0, 0, self.SIZE - 1, self.SIZE - 1), 90, remaining * 180 + 90,
|
|
fill=(color.r, color.g, color.b, color.a))
|
|
draw.ellipse((self.SIZE / 4, self.SIZE / 4, self.SIZE / 4 * 3, self.SIZE / 4 * 3), (0, 0, 0, 0))
|
|
string = fromstring(image.tobytes(), image.size, image.mode)
|
|
image.close()
|
|
return string
|
|
|
|
|
|
class Life(GameChild):
|
|
|
|
SPACING = 30
|
|
MARGIN = 0
|
|
|
|
def __init__(self, parent):
|
|
GameChild.__init__(self, parent)
|
|
self.heart = load(self.get_resource("Heart.png")).convert_alpha()
|
|
|
|
def reset(self):
|
|
self.count = 3
|
|
|
|
def decrease(self):
|
|
self.get_game().sfx["hurt"].play()
|
|
if self.count > 0:
|
|
self.count -= 1
|
|
if self.count <= 0:
|
|
self.count = 0
|
|
self.get_game().boss.finish_battle(False)
|
|
|
|
def update(self):
|
|
ds = self.get_display_surface()
|
|
dsr = ds.get_rect()
|
|
hr = self.heart.get_rect()
|
|
rect = Rect(0, 0, hr.w * self.count + self.SPACING * (self.count - 1), hr.h)
|
|
rect.midbottom = dsr.centerx, dsr.h - self.MARGIN
|
|
for x in xrange(rect.left, rect.right, hr.w + self.SPACING):
|
|
ds.blit(self.heart, (x, rect.top))
|
|
|
|
|
|
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.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"))
|
|
|
|
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 = 2
|
|
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!")
|
|
|
|
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
|
|
|
|
def deactivate(self):
|
|
self.active = False
|
|
|
|
def activate(self):
|
|
self.active = True
|
|
|
|
def combo(self):
|
|
self.queue = None
|
|
self.play(self.brandish, delay=2500, 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)
|
|
file(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?")
|
|
|
|
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 update(self):
|
|
if self.active:
|
|
self.backgrounds[self.level_index].update()
|
|
dialogue = self.get_game().dialogue
|
|
if dialogue.active:
|
|
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:
|
|
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()
|
|
|
|
def update_dialogue(self):
|
|
if self.active:
|
|
dialogue = self.get_game().dialogue
|
|
if dialogue.active:
|
|
self.get_game().dialogue.update()
|
|
self.advance_prompt.update()
|
|
|
|
|
|
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 xrange(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 xrange(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_game().sfx["brandish"].play()
|
|
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(GameChild):
|
|
|
|
TEXT = "BOSS"
|
|
BAR_POSITION = 23, 11
|
|
BACKGROUND_ALPHA = 125
|
|
OFFSET = 11
|
|
|
|
def __init__(self, parent):
|
|
GameChild.__init__(self, parent)
|
|
self.background = Sprite(self)
|
|
self.background.load_from_path(self.get_resource("HUD_boss_health_background.png"), True)
|
|
dsr = self.get_display_surface().get_rect()
|
|
self.background.location.center = dsr.centerx, self.OFFSET
|
|
self.foreground = Sprite(self)
|
|
self.foreground.load_from_path(self.get_resource("HUD_boss_health_foreground.png"), True)
|
|
self.foreground.location.center = dsr.centerx, self.OFFSET
|
|
self.label = Sprite(self)
|
|
font = Font(self.get_resource("rounded-mplus-1m-bold.ttf"), 24)
|
|
text = font.render(self.TEXT, True, Color("white"))
|
|
self.label.add_frame(text)
|
|
self.label.location.topleft = 2, -2
|
|
self.bar = load(self.get_resource("HUD_bar.png")).convert_alpha()
|
|
|
|
def reset(self):
|
|
self.amount = 100
|
|
|
|
def decrease(self, damage):
|
|
self.amount -= damage
|
|
self.parent.damage()
|
|
if self.amount <= 0:
|
|
self.amount = 0
|
|
self.get_game().sfx["complete_pattern_1"].play()
|
|
self.get_game().sfx["defeat"].play()
|
|
self.get_game().boss.finish_battle(True)
|
|
else:
|
|
self.parent.play(self.parent.cancel_flash, delay=1000, play_once=True)
|
|
|
|
def update(self):
|
|
self.background.update()
|
|
if self.amount > 50:
|
|
shift = 0
|
|
elif self.amount > 25:
|
|
shift = -70
|
|
else:
|
|
shift = -120
|
|
ratio = self.amount / 100.0
|
|
ds = self.get_display_surface()
|
|
ds.set_clip((self.foreground.location.left, self.foreground.location.top,
|
|
int(self.foreground.location.w * ratio), self.foreground.location.h))
|
|
surface = get_hue_shifted_surface(self.foreground.get_current_frame(), shift)
|
|
ds.blit(surface, self.foreground.location.topleft)
|
|
ds.set_clip(None)
|
|
|
|
|
|
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.tony = load(self.get_resource("Big_Tony.png")).convert()
|
|
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)
|
|
|
|
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))
|
|
dsr = self.get_display_surface().get_rect()
|
|
self.text = RainbowSprite(self, foreground, 180, 200)
|
|
self.text.location.midtop = dsr.centerx, 80
|
|
|
|
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_display_surface().blit(self.tony, (0, 0))
|
|
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()
|