|
|
|
@ -7,7 +7,6 @@ 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
|
|
|
|
@ -27,7 +26,8 @@ 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
|
|
|
|
|
render_box, get_hsla_color, get_hue_shifted_surface,
|
|
|
|
|
get_color_swapped_surface
|
|
|
|
|
)
|
|
|
|
|
from lib.pgfw.pgfw.gfx_extension import aa_filled_polygon
|
|
|
|
|
|
|
|
|
@ -44,6 +44,17 @@ class NS(Game, Animation):
|
|
|
|
|
|
|
|
|
|
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"]
|
|
|
|
|
},
|
|
|
|
|
"input":
|
|
|
|
|
{
|
|
|
|
|
"bool": "serial"
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
Animation.__init__(self, self)
|
|
|
|
|
self.load_sfx()
|
|
|
|
|
self.subscribe(self.respond, KEYDOWN)
|
|
|
|
@ -60,17 +71,6 @@ class NS(Game, Animation):
|
|
|
|
|
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
|
|
|
|
@ -222,6 +222,50 @@ class Button(Sprite):
|
|
|
|
|
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):
|
|
|
|
|
self.background = background
|
|
|
|
|
self.rect = rect
|
|
|
|
|
self.icons = []
|
|
|
|
|
x = rect.left + indent
|
|
|
|
|
base = get_color_swapped_surface(
|
|
|
|
|
load(self.get_resource("HUD_circle.png")).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 Title(GameChild):
|
|
|
|
|
|
|
|
|
|
def __init__(self, parent):
|
|
|
|
@ -1010,11 +1054,13 @@ class Chemtrails(Sprite):
|
|
|
|
|
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):
|
|
|
|
@ -1036,13 +1082,15 @@ class Chemtrails(Sprite):
|
|
|
|
|
if boss.queue:
|
|
|
|
|
self.timer.tick()
|
|
|
|
|
self.attack()
|
|
|
|
|
if self.timer.time_remaining < 0:
|
|
|
|
|
if self.timer.amount < 0:
|
|
|
|
|
self.life.decrease()
|
|
|
|
|
if not boss.is_playing(boss.show_end_dialogue):
|
|
|
|
|
self.timer.reset()
|
|
|
|
|
boss.combo()
|
|
|
|
|
# self.timer.update()
|
|
|
|
|
self.life.update()
|
|
|
|
|
if not boss.is_playing(boss.show_introduction_dialogue):
|
|
|
|
|
self.timer.update()
|
|
|
|
|
self.life.update()
|
|
|
|
|
self.boys.update()
|
|
|
|
|
|
|
|
|
|
def attack(self):
|
|
|
|
|
boss = self.get_game().boss
|
|
|
|
@ -1103,94 +1151,52 @@ class Chemtrails(Sprite):
|
|
|
|
|
self.orientation = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Timer(GameChild):
|
|
|
|
|
|
|
|
|
|
TEXT = u"\u25F7"
|
|
|
|
|
BAR_POSITION = 448, 11
|
|
|
|
|
SIZE = 160
|
|
|
|
|
TOP = 120
|
|
|
|
|
RING_OFFSET = 8
|
|
|
|
|
class Timer(Meter):
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
Meter.__init__(self, parent)
|
|
|
|
|
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")
|
|
|
|
|
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"))
|
|
|
|
|
|
|
|
|
|
def add_time(self, amount):
|
|
|
|
|
self.time_remaining += amount
|
|
|
|
|
self.change(amount)
|
|
|
|
|
|
|
|
|
|
def tick(self):
|
|
|
|
|
self.time_remaining -= self.get_game().time_filter.get_last_frame_duration()
|
|
|
|
|
self.change(-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()
|
|
|
|
|
class Life(Meter):
|
|
|
|
|
|
|
|
|
|
def reset(self):
|
|
|
|
|
self.count = 3
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
|
def decrease(self):
|
|
|
|
|
self.get_game().sfx["hurt"].play()
|
|
|
|
|
if self.count > 0:
|
|
|
|
|
self.count -= 1
|
|
|
|
|
if self.count <= 0:
|
|
|
|
|
self.count = 0
|
|
|
|
|
self.change(-1)
|
|
|
|
|
if self.amount <= 0:
|
|
|
|
|
self.amount = 0
|
|
|
|
|
self.parent.boys.change(-1)
|
|
|
|
|
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 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)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Boss(Animation):
|
|
|
|
@ -1227,7 +1233,7 @@ class Boss(Animation):
|
|
|
|
|
self.spoopy.set_frameset("normal")
|
|
|
|
|
|
|
|
|
|
def start_level(self, index):
|
|
|
|
|
self.level_index = 2
|
|
|
|
|
self.level_index = index
|
|
|
|
|
self.battle_finished = False
|
|
|
|
|
self.player_defeated = False
|
|
|
|
|
self.health.reset()
|
|
|
|
@ -1669,34 +1675,20 @@ class Sword(Animation):
|
|
|
|
|
sprite.update(substitute=substitute)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Health(GameChild):
|
|
|
|
|
class Health(Meter):
|
|
|
|
|
|
|
|
|
|
TEXT = "BOSS"
|
|
|
|
|
BAR_POSITION = 23, 11
|
|
|
|
|
BACKGROUND_ALPHA = 125
|
|
|
|
|
OFFSET = 11
|
|
|
|
|
OFFSET = 4
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
Meter.__init__(self, parent)
|
|
|
|
|
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
|
|
|
|
|
background = load(self.get_resource("HUD_boss.png")).convert()
|
|
|
|
|
rect = background.get_rect()
|
|
|
|
|
rect.midtop = dsr.centerx, self.OFFSET
|
|
|
|
|
self.setup(background, rect, 52, (255, 0, 255), 100)
|
|
|
|
|
|
|
|
|
|
def decrease(self, damage):
|
|
|
|
|
self.amount -= damage
|
|
|
|
|
self.change(-damage)
|
|
|
|
|
self.parent.damage()
|
|
|
|
|
if self.amount <= 0:
|
|
|
|
|
self.amount = 0
|
|
|
|
@ -1706,22 +1698,6 @@ class Health(GameChild):
|
|
|
|
|
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):
|
|
|
|
|
|
|
|
|
|