score box
This commit is contained in:
parent
c5e62360a4
commit
539e61c054
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "lib/pgfw"]
|
||||||
|
path = lib/pgfw
|
||||||
|
url = makar:/var/www/git/pgfw
|
|
@ -0,0 +1,97 @@
|
||||||
|
Copyright (c) 2010 Dimitar Toshkov Zhekov,
|
||||||
|
with Reserved Font Name "Terminus Font".
|
||||||
|
|
||||||
|
Copyright (c) 2011 Tilman Blumenbach,
|
||||||
|
with Reserved Font Name "Terminus (TTF)".
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
http://scripts.sil.org/OFL
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
1
config
1
config
|
@ -15,6 +15,7 @@ caption = Electric Sieve
|
||||||
dimensions = 420, 700
|
dimensions = 420, 700
|
||||||
score-font-path = font/Titan-One.ttf
|
score-font-path = font/Titan-One.ttf
|
||||||
title-font-path = font/Oxygen.ttf
|
title-font-path = font/Oxygen.ttf
|
||||||
|
scoreboard-font-path = font/terminus/Terminus.ttf
|
||||||
|
|
||||||
[mouse]
|
[mouse]
|
||||||
visible = no
|
visible = no
|
||||||
|
|
|
@ -9,9 +9,10 @@ from pygame.font import Font
|
||||||
from pygame.mixer import Sound
|
from pygame.mixer import Sound
|
||||||
from pygame.locals import *
|
from pygame.locals import *
|
||||||
|
|
||||||
from electric_sieve.pgfw.Game import Game
|
from lib.pgfw.pgfw.Game import Game
|
||||||
from electric_sieve.pgfw.GameChild import GameChild
|
from lib.pgfw.pgfw.GameChild import GameChild
|
||||||
from electric_sieve.pgfw.Sprite import Sprite
|
from lib.pgfw.pgfw.Sprite import Sprite
|
||||||
|
from lib.pgfw.pgfw.extension import render_box
|
||||||
|
|
||||||
class ElectricSieve(Game):
|
class ElectricSieve(Game):
|
||||||
|
|
||||||
|
@ -53,27 +54,27 @@ class Title(GameChild):
|
||||||
for y in xrange(0, surface.get_height(), 2):
|
for y in xrange(0, surface.get_height(), 2):
|
||||||
for x in xrange(0, surface.get_width(), 2):
|
for x in xrange(0, surface.get_width(), 2):
|
||||||
surface.blit(tile, (x, y))
|
surface.blit(tile, (x, y))
|
||||||
font = Font(self.get_resource("display", "title-font-path"), 20)
|
# font = Font(self.get_resource("display", "title-font-path"), 20)
|
||||||
font.set_italic(True)
|
# font.set_italic(True)
|
||||||
font.set_bold(True)
|
# font.set_bold(True)
|
||||||
self.captions = captions = Sprite(self), Sprite(self)
|
# self.captions = captions = Sprite(self), Sprite(self)
|
||||||
colors = (0, 68, 170), (255, 255, 255), (128, 128, 128), \
|
# colors = (0, 68, 170), (255, 255, 255), (128, 128, 128), \
|
||||||
(220, 119, 41), (255, 80, 80), (0, 90, 110)
|
# (220, 119, 41), (255, 80, 80), (0, 90, 110)
|
||||||
texts = ["", ""]
|
# texts = ["", ""]
|
||||||
for ii, text in \
|
# for ii, text in \
|
||||||
enumerate(self.get_configuration("display",
|
# enumerate(self.get_configuration("display",
|
||||||
"caption").upper().split()):
|
# "caption").upper().split()):
|
||||||
texts[ii] += "•" * (5 if ii else 3)
|
# texts[ii] += "•" * (5 if ii else 3)
|
||||||
for ch in text:
|
# for ch in text:
|
||||||
texts[ii] += ch + " "
|
# texts[ii] += ch + " "
|
||||||
texts[ii] = texts[ii].strip() + "•" * (5 if ii else 3)
|
# texts[ii] = texts[ii].strip() + "•" * (5 if ii else 3)
|
||||||
for _ in xrange(25):
|
# for _ in xrange(25):
|
||||||
color = choice(colors)
|
# color = choice(colors)
|
||||||
captions[0].add_frame(font.render(texts[0], True, color, (220, 208, 255)))
|
# captions[0].add_frame(font.render(texts[0], True, color, (220, 208, 255)))
|
||||||
captions[1].add_frame(font.render(texts[1], True, color, (220, 208, 255)))
|
# captions[1].add_frame(font.render(texts[1], True, color, (220, 208, 255)))
|
||||||
cx = self.display_surface.get_rect().centerx
|
# cx = self.display_surface.get_rect().centerx
|
||||||
captions[0].location.center = cx, 301
|
# captions[0].location.center = cx, 301
|
||||||
captions[1].location.center = cx, 398
|
# captions[1].location.center = cx, 398
|
||||||
self.scoreboard = Scoreboard(self)
|
self.scoreboard = Scoreboard(self)
|
||||||
self.music = Sound(self.get_resource("audio", "title"))
|
self.music = Sound(self.get_resource("audio", "title"))
|
||||||
self.advance = Sound(self.get_resource("audio", "title-advance"))
|
self.advance = Sound(self.get_resource("audio", "title-advance"))
|
||||||
|
@ -99,8 +100,8 @@ class Title(GameChild):
|
||||||
def update(self):
|
def update(self):
|
||||||
if self.active:
|
if self.active:
|
||||||
self.display_surface.blit(self.background, (0, 0))
|
self.display_surface.blit(self.background, (0, 0))
|
||||||
for caption in self.captions:
|
# for caption in self.captions:
|
||||||
caption.update()
|
# caption.update()
|
||||||
self.scoreboard.update()
|
self.scoreboard.update()
|
||||||
|
|
||||||
|
|
||||||
|
@ -173,54 +174,70 @@ class Shift(GameChild):
|
||||||
return self.nodeset.get_y(self.time) * self.direction
|
return self.nodeset.get_y(self.time) * self.direction
|
||||||
|
|
||||||
|
|
||||||
class Scoreboard(GameChild, Surface):
|
class Scoreboard(GameChild):
|
||||||
|
|
||||||
|
|
||||||
|
BACKGROUND = 255, 255, 255
|
||||||
|
FOREGROUND = 27, 27, 27
|
||||||
|
NEW = 27, 27, 27
|
||||||
|
SPACING = 70
|
||||||
|
MARGIN = 30
|
||||||
|
BLINK_INTERVAL = 400
|
||||||
|
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
GameChild.__init__(self, parent)
|
GameChild.__init__(self, parent)
|
||||||
Surface.__init__(self, (380, 80))
|
ds = self.display_surface = self.get_display_surface()
|
||||||
self.scores_path = self.get_resource("score", "path")
|
self.scores_path = self.get_resource("score", "path")
|
||||||
self.display_surface = self.get_display_surface()
|
|
||||||
self.most_recent_score = None
|
self.most_recent_score = None
|
||||||
self.fill((255, 255, 255))
|
|
||||||
self.rect = self.get_rect()
|
|
||||||
self.rect.center = self.display_surface.get_rect().centerx, 350
|
|
||||||
self.load()
|
self.load()
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
scores = []
|
scores = []
|
||||||
for line in file(self.scores_path, "r"):
|
for line in file(self.scores_path, "r"):
|
||||||
fields = line.split()
|
fields = line.split()
|
||||||
scores.append((float(fields[0]), int(fields[1])))
|
scores.append((float(fields[0]), int(fields[1]), fields[2]))
|
||||||
self.sprites = sprites = []
|
self.sprites = sprites = []
|
||||||
font_path = self.get_resource("display", "score-font-path")
|
font_path = self.get_resource("display", "scoreboard-font-path")
|
||||||
y = 0
|
sizes = [14] * 5
|
||||||
for ii, score in enumerate(sorted(scores, key=lambda score: score[1],
|
for ii, score in enumerate(sorted(scores, key=lambda score: score[1],
|
||||||
reverse=True)[:3]):
|
reverse=True)[:len(sizes)]):
|
||||||
font = Font(font_path, [40, 24, 16][ii])
|
font = Font(font_path, sizes[ii])
|
||||||
sprites.append(Sprite(self, 250))
|
sprites.append((Sprite(self, self.BLINK_INTERVAL),
|
||||||
text = str(score[1])
|
Sprite(self, self.BLINK_INTERVAL)))
|
||||||
color = (0, 0, 0) if not (score[1] == self.most_recent_score) else \
|
score_text = str(score[1])
|
||||||
(255, 255, 255)
|
color = self.FOREGROUND if not (score[1] == self.most_recent_score) else \
|
||||||
sprites[ii].add_frame(font.render(text, True, color,
|
self.BACKGROUND
|
||||||
(255, 255, 255)))
|
score_plate = font.render(score_text, False, color, self.BACKGROUND)
|
||||||
|
rect = score_plate.get_rect()
|
||||||
|
surface = Surface(rect.inflate((2, 2)).size)
|
||||||
|
surface.fill(self.FOREGROUND)
|
||||||
|
rect.center = surface.get_rect().center
|
||||||
|
surface.blit(score_plate, rect)
|
||||||
|
sprites[ii][1].add_frame(render_box(font, score_text, False, color,
|
||||||
|
self.BACKGROUND, self.FOREGROUND, 1, 2))
|
||||||
|
sprites[ii][0].add_frame(render_box(font, score[2], False, color,
|
||||||
|
self.BACKGROUND, self.FOREGROUND, 1, 2))
|
||||||
if score[1] == self.most_recent_score:
|
if score[1] == self.most_recent_score:
|
||||||
sprites[ii].add_frame(font.render(text, True, (0, 255, 0),
|
sprites[ii][1].add_frame(render_box(font, score_text, False, self.NEW,
|
||||||
(255, 255, 255)))
|
self.BACKGROUND, self.FOREGROUND, 1, 2))
|
||||||
sprites[ii].location.midtop = self.rect.w / 2, y
|
sprites[ii][0].add_frame(render_box(font, score[2], False, self.NEW,
|
||||||
y += sprites[ii].location.h
|
self.BACKGROUND, self.FOREGROUND, 1, 2))
|
||||||
sprites[ii].display_surface = self
|
sprites[ii][0].location.left = self.MARGIN
|
||||||
|
sprites[ii][1].location.right = self.get_display_surface().get_rect().right - self.MARGIN
|
||||||
|
y = self.get_display_surface().get_rect().centery + self.SPACING * (ii - len(sizes) / 2)
|
||||||
|
for sprite in sprites[ii]:
|
||||||
|
sprite.location.centery = y
|
||||||
|
|
||||||
def write(self):
|
def write(self):
|
||||||
score = int(round(self.get_game().triangles.score))
|
score = int(round(self.get_game().triangles.score))
|
||||||
file(self.scores_path, "a").write(str(time()) + " " + str(score) + "\n")
|
file(self.scores_path, "a").write(str(time()) + " " + str(score) + " " + "SIV" + "\n")
|
||||||
self.most_recent_score = score
|
self.most_recent_score = score
|
||||||
self.load()
|
self.load()
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.fill((255, 255, 255))
|
for pair in self.sprites:
|
||||||
for sprite in self.sprites:
|
for sprite in pair:
|
||||||
sprite.update()
|
sprite.update()
|
||||||
self.display_surface.blit(self, self.rect)
|
|
||||||
|
|
||||||
|
|
||||||
class Sieve(Strip):
|
class Sieve(Strip):
|
||||||
|
|
|
@ -1,134 +0,0 @@
|
||||||
from GameChild import GameChild
|
|
||||||
|
|
||||||
class Animation(GameChild):
|
|
||||||
|
|
||||||
def __init__(self, parent, method=None, interval=None, unfiltered=False):
|
|
||||||
GameChild.__init__(self, parent)
|
|
||||||
self.unfiltered = unfiltered
|
|
||||||
self.default_method = method or self.build_frame
|
|
||||||
self.accounts = {}
|
|
||||||
self.register(self.default_method, interval=interval)
|
|
||||||
self.current_elapsed = 0
|
|
||||||
self.last_update = 0
|
|
||||||
|
|
||||||
def build_frame(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def register(self, *args, **kwargs):
|
|
||||||
interval = None
|
|
||||||
if kwargs.has_key("interval"):
|
|
||||||
interval = kwargs["interval"]
|
|
||||||
for method in args:
|
|
||||||
if method not in self.accounts:
|
|
||||||
self.accounts[method] = Account(interval, self)
|
|
||||||
else:
|
|
||||||
self.accounts[method].set_interval(interval)
|
|
||||||
|
|
||||||
def play(self, method=None, interval=None, delay=0, play_once=False,
|
|
||||||
**kwargs):
|
|
||||||
account = self.accounts[self.get_default(method)]
|
|
||||||
account.set_delay(delay)
|
|
||||||
account.set_args(kwargs)
|
|
||||||
account.set_play_once(play_once)
|
|
||||||
if interval:
|
|
||||||
account.set_interval(interval)
|
|
||||||
account.play()
|
|
||||||
|
|
||||||
def get_default(self, method):
|
|
||||||
if not method:
|
|
||||||
method = self.default_method
|
|
||||||
return method
|
|
||||||
|
|
||||||
def halt(self, method=None):
|
|
||||||
if not method:
|
|
||||||
for account in self.accounts.values():
|
|
||||||
account.halt()
|
|
||||||
else:
|
|
||||||
if self.accounts.has_key(method):
|
|
||||||
self.accounts[method].halt()
|
|
||||||
|
|
||||||
def is_playing(self, method=None, check_all=False, include_delay=False):
|
|
||||||
if check_all:
|
|
||||||
return any(self.is_account_playing(account, include_delay) for \
|
|
||||||
method, account in self.accounts.iteritems())
|
|
||||||
return self.is_account_playing(self.accounts[self.get_default(method)],
|
|
||||||
include_delay)
|
|
||||||
|
|
||||||
def is_account_playing(self, account, include_delay):
|
|
||||||
return account.playing and (not include_delay or not account.delay)
|
|
||||||
|
|
||||||
def update(self):
|
|
||||||
for method, account in self.accounts.iteritems():
|
|
||||||
if account.update():
|
|
||||||
method(**account.args)
|
|
||||||
|
|
||||||
|
|
||||||
class Account:
|
|
||||||
|
|
||||||
def __init__(self, interval, animation):
|
|
||||||
self.animation = animation
|
|
||||||
self.time_filter = animation.get_game().time_filter
|
|
||||||
self.set_interval(interval)
|
|
||||||
self.set_delay(0)
|
|
||||||
self.set_play_once(False)
|
|
||||||
self.interval_index = 0
|
|
||||||
self.last_frame = 0
|
|
||||||
self.halt()
|
|
||||||
|
|
||||||
def set_interval(self, interval):
|
|
||||||
if isinstance(interval, int) or isinstance(interval, str):
|
|
||||||
interval = [interval]
|
|
||||||
self.interval = interval
|
|
||||||
|
|
||||||
def set_delay(self, delay):
|
|
||||||
self.delay = delay
|
|
||||||
|
|
||||||
def set_play_once(self, play_once):
|
|
||||||
self.play_once = play_once
|
|
||||||
|
|
||||||
def set_args(self, args):
|
|
||||||
self.args = args
|
|
||||||
|
|
||||||
def play(self):
|
|
||||||
self.playing = True
|
|
||||||
|
|
||||||
def halt(self):
|
|
||||||
self.last_update = None
|
|
||||||
self.playing = False
|
|
||||||
|
|
||||||
def update(self):
|
|
||||||
if self.playing:
|
|
||||||
if self.animation.unfiltered:
|
|
||||||
ticks = self.time_filter.get_unfiltered_ticks()
|
|
||||||
else:
|
|
||||||
ticks = self.time_filter.get_ticks()
|
|
||||||
self.update_delay(ticks)
|
|
||||||
if not self.delay:
|
|
||||||
interval = self.interval
|
|
||||||
if interval:
|
|
||||||
if ticks - self.last_frame < self.get_current_interval():
|
|
||||||
return False
|
|
||||||
self.last_frame = ticks
|
|
||||||
self.increment_interval_index()
|
|
||||||
if self.play_once:
|
|
||||||
self.halt()
|
|
||||||
return True
|
|
||||||
|
|
||||||
def get_current_interval(self):
|
|
||||||
return self.interval[self.interval_index]
|
|
||||||
|
|
||||||
def increment_interval_index(self):
|
|
||||||
index = self.interval_index + 1
|
|
||||||
if index >= len(self.interval):
|
|
||||||
index = 0
|
|
||||||
self.interval_index = index
|
|
||||||
|
|
||||||
def update_delay(self, ticks):
|
|
||||||
delay = self.delay
|
|
||||||
if delay > 0:
|
|
||||||
last_update = self.last_update or ticks
|
|
||||||
delay -= ticks - last_update
|
|
||||||
if delay < 0:
|
|
||||||
delay = 0
|
|
||||||
self.last_update = ticks
|
|
||||||
self.delay = delay
|
|
|
@ -1,92 +0,0 @@
|
||||||
from os import listdir
|
|
||||||
from os.path import join
|
|
||||||
|
|
||||||
from pygame.mixer import Channel, Sound, music, find_channel
|
|
||||||
|
|
||||||
from GameChild import *
|
|
||||||
from Input import *
|
|
||||||
|
|
||||||
class Audio(GameChild):
|
|
||||||
|
|
||||||
current_channel = None
|
|
||||||
paused = False
|
|
||||||
muted = False
|
|
||||||
|
|
||||||
def __init__(self, game):
|
|
||||||
GameChild.__init__(self, game)
|
|
||||||
self.delegate = self.get_delegate()
|
|
||||||
self.load_fx()
|
|
||||||
self.subscribe(self.respond)
|
|
||||||
|
|
||||||
def load_fx(self):
|
|
||||||
fx = {}
|
|
||||||
if self.get_configuration().has_option("audio", "sfx-path"):
|
|
||||||
root = self.get_resource("audio", "sfx-path")
|
|
||||||
if root:
|
|
||||||
for name in listdir(root):
|
|
||||||
fx[name.split(".")[0]] = Sound(join(root, name))
|
|
||||||
self.fx = fx
|
|
||||||
|
|
||||||
def respond(self, event):
|
|
||||||
if self.delegate.compare(event, "mute"):
|
|
||||||
self.mute()
|
|
||||||
|
|
||||||
def mute(self):
|
|
||||||
self.muted = True
|
|
||||||
self.set_volume()
|
|
||||||
|
|
||||||
def unmute(self):
|
|
||||||
self.muted = False
|
|
||||||
self.set_volume()
|
|
||||||
|
|
||||||
def set_volume(self):
|
|
||||||
volume = int(not self.muted)
|
|
||||||
music.set_volume(volume)
|
|
||||||
if self.current_channel:
|
|
||||||
self.current_channel.set_volume(volume)
|
|
||||||
|
|
||||||
def play_bgm(self, path, stream=False):
|
|
||||||
self.stop_current_channel()
|
|
||||||
if stream:
|
|
||||||
music.load(path)
|
|
||||||
music.play(-1)
|
|
||||||
else:
|
|
||||||
self.current_channel = Sound(path).play(-1)
|
|
||||||
self.set_volume()
|
|
||||||
|
|
||||||
def stop_current_channel(self):
|
|
||||||
music.stop()
|
|
||||||
if self.current_channel:
|
|
||||||
self.current_channel.stop()
|
|
||||||
self.current_channel = None
|
|
||||||
self.paused = False
|
|
||||||
|
|
||||||
def play_fx(self, name, panning=.5):
|
|
||||||
if not self.muted:
|
|
||||||
channel = find_channel(True)
|
|
||||||
if panning != .5:
|
|
||||||
offset = 1 - abs(panning - .5) * 2
|
|
||||||
if panning < .5:
|
|
||||||
channel.set_volume(1, offset)
|
|
||||||
else:
|
|
||||||
channel.set_volume(offset, 1)
|
|
||||||
channel.play(self.fx[name])
|
|
||||||
|
|
||||||
def pause(self):
|
|
||||||
channel = self.current_channel
|
|
||||||
paused = self.paused
|
|
||||||
if paused:
|
|
||||||
music.unpause()
|
|
||||||
if channel:
|
|
||||||
channel.unpause()
|
|
||||||
else:
|
|
||||||
music.pause()
|
|
||||||
if channel:
|
|
||||||
channel.pause()
|
|
||||||
self.paused = not paused
|
|
||||||
|
|
||||||
def is_bgm_playing(self):
|
|
||||||
current = self.current_channel
|
|
||||||
if current and current.get_sound():
|
|
||||||
return True
|
|
||||||
return music.get_busy()
|
|
|
@ -1,442 +0,0 @@
|
||||||
from os import sep, getcwd
|
|
||||||
from os.path import join, exists, basename, dirname, expanduser
|
|
||||||
from sys import argv
|
|
||||||
from re import match
|
|
||||||
from pprint import pformat
|
|
||||||
|
|
||||||
from ConfigParser import RawConfigParser
|
|
||||||
|
|
||||||
class Configuration(RawConfigParser):
|
|
||||||
|
|
||||||
default_project_file_rel_path = "config"
|
|
||||||
default_resource_paths = [".", "resource"]
|
|
||||||
|
|
||||||
def __init__(self, project_file_rel_path=None, resource_path=None,
|
|
||||||
type_declarations=None):
|
|
||||||
RawConfigParser.__init__(self)
|
|
||||||
self.project_file_rel_path = project_file_rel_path
|
|
||||||
self.resource_path = resource_path
|
|
||||||
self.modifiable = {}
|
|
||||||
self.order = []
|
|
||||||
self.set_type_declarations(type_declarations)
|
|
||||||
self.set_defaults()
|
|
||||||
self.read_project_config_file()
|
|
||||||
self.modify_defaults()
|
|
||||||
self.print_debug(self)
|
|
||||||
|
|
||||||
def set_type_declarations(self, type_declarations):
|
|
||||||
if type_declarations is None:
|
|
||||||
type_declarations = TypeDeclarations()
|
|
||||||
self.type_declarations = type_declarations
|
|
||||||
|
|
||||||
def translate_path(self, path):
|
|
||||||
new = ""
|
|
||||||
if path and path[0] == sep:
|
|
||||||
new += sep
|
|
||||||
return expanduser("{0}{1}".format(new, join(*path.split(sep))))
|
|
||||||
|
|
||||||
def set_defaults(self):
|
|
||||||
add_section = self.add_section
|
|
||||||
set_option = self.set
|
|
||||||
section = "setup"
|
|
||||||
add_section(section)
|
|
||||||
set_option(section, "package-root", basename(getcwd()), False)
|
|
||||||
set_option(section, "additional-packages", "", False)
|
|
||||||
set_option(section, "title", "", False)
|
|
||||||
set_option(section, "classifiers", "", False)
|
|
||||||
set_option(section, "resource-search-path", "./, resource/", False)
|
|
||||||
set_option(section, "installation-dir", "/usr/local/share/games/",
|
|
||||||
False)
|
|
||||||
set_option(section, "changelog", "changelog", False)
|
|
||||||
set_option(section, "description-file", "", False)
|
|
||||||
set_option(section, "init-script", "", False)
|
|
||||||
set_option(section, "version", "", False)
|
|
||||||
set_option(section, "summary", "", False)
|
|
||||||
set_option(section, "license", "", False)
|
|
||||||
set_option(section, "platforms", "", False)
|
|
||||||
set_option(section, "contact-name", "", False)
|
|
||||||
set_option(section, "contact-email", "", False)
|
|
||||||
set_option(section, "url", "", False)
|
|
||||||
set_option(section, "requirements", "", False)
|
|
||||||
set_option(section, "main-object", "pgfw/Game.py", False)
|
|
||||||
set_option(section, "resource-path-identifier", "resource_path", False)
|
|
||||||
set_option(section, "special-char-placeholder", "_", False)
|
|
||||||
set_option(section, "whitespace-placeholder", "-", False)
|
|
||||||
set_option(section, "windows-dist-path", "dist/win/", False)
|
|
||||||
set_option(section, "windows-icon-path", "", False)
|
|
||||||
set_option(section, "lowercase-boolean-true", "yes", False)
|
|
||||||
section = "display"
|
|
||||||
add_section(section)
|
|
||||||
set_option(section, "dimensions", "480, 360", False)
|
|
||||||
set_option(section, "frame-duration", "40", False)
|
|
||||||
set_option(section, "wait-duration", "2", False)
|
|
||||||
set_option(section, "caption", "", False)
|
|
||||||
set_option(section, "centered", "yes", False)
|
|
||||||
set_option(section, "icon-path", "", False)
|
|
||||||
set_option(section, "skip-frames", "no", False)
|
|
||||||
set_option(section, "fullscreen", "no", False)
|
|
||||||
set_option(section, "windowed-flag", "wi", False)
|
|
||||||
set_option(section, "show-framerate", "no", False)
|
|
||||||
set_option(section, "framerate-display-flag", "fr", False)
|
|
||||||
set_option(section, "framerate-text-size", "16", False)
|
|
||||||
set_option(section, "framerate-text-color", "0, 0, 0", False)
|
|
||||||
set_option(section, "framerate-text-background", "255, 255, 255", False)
|
|
||||||
section = "input"
|
|
||||||
add_section(section)
|
|
||||||
set_option(section, "release-suffix", "-release", False)
|
|
||||||
section = "sprite"
|
|
||||||
add_section(section)
|
|
||||||
set_option(section, "transparent-color", "magenta", False)
|
|
||||||
section = "screen-captures"
|
|
||||||
add_section(section)
|
|
||||||
set_option(section, "rel-path", "caps", False)
|
|
||||||
set_option(section, "file-name-format", "%Y%m%d%H%M%S", False)
|
|
||||||
set_option(section, "file-extension", "png", False)
|
|
||||||
section = "video-recordings"
|
|
||||||
add_section(section)
|
|
||||||
set_option(section, "rel-path", "vids", False)
|
|
||||||
set_option(section, "directory-name-format", "%Y%m%d%H%M%S", False)
|
|
||||||
set_option(section, "file-extension", "png", False)
|
|
||||||
set_option(section, "frame-format", "RGB", False)
|
|
||||||
set_option(section, "framerate", "100", False)
|
|
||||||
section = "mouse"
|
|
||||||
add_section(section)
|
|
||||||
set_option(section, "visible", "yes", False)
|
|
||||||
set_option(section, "double-click-time-limit", ".5", False)
|
|
||||||
section = "keys"
|
|
||||||
add_section(section)
|
|
||||||
set_option(section, "up", "K_UP, K_w", False)
|
|
||||||
set_option(section, "right", "K_RIGHT, K_d", False)
|
|
||||||
set_option(section, "down", "K_DOWN, K_s", False)
|
|
||||||
set_option(section, "left", "K_LEFT, K_a", False)
|
|
||||||
set_option(section, "capture-screen", "K_F9", False)
|
|
||||||
set_option(section, "toggle-fullscreen", "K_F11", False)
|
|
||||||
set_option(section, "reset-game", "K_F8", False)
|
|
||||||
set_option(section, "record-video", "K_F10", False)
|
|
||||||
set_option(section, "mute", "K_F12", False)
|
|
||||||
set_option(section, "toggle-interpolator", "K_F7", False)
|
|
||||||
section = "joy"
|
|
||||||
add_section(section)
|
|
||||||
set_option(section, "advance", "7", False)
|
|
||||||
set_option(section, "pause", "7", False)
|
|
||||||
set_option(section, "select", "6", False)
|
|
||||||
section = "event"
|
|
||||||
add_section(section)
|
|
||||||
set_option(section, "user-event-id", "USEREVENT", False)
|
|
||||||
set_option(section, "command-id-offset", "1", False)
|
|
||||||
set_option(section, "command-key", "command", False)
|
|
||||||
set_option(section, "cancel-flag-key", "cancel", False)
|
|
||||||
section = "audio"
|
|
||||||
add_section(section)
|
|
||||||
set_option(section, "sfx-path", "aud/fx/", False)
|
|
||||||
section = "interpolator-gui"
|
|
||||||
add_section(section)
|
|
||||||
set_option(section, "margin", "80", False)
|
|
||||||
set_option(section, "marker-color", "255, 0, 0", False)
|
|
||||||
set_option(section, "marker-size", "11", False)
|
|
||||||
set_option(section, "curve-color", "0, 255, 0", False)
|
|
||||||
set_option(section, "label-size", "16", False)
|
|
||||||
set_option(section, "label-precision", "2", False)
|
|
||||||
set_option(section, "axis-label-count", "8", False)
|
|
||||||
set_option(section, "prompt-size", "380, 60", False)
|
|
||||||
set_option(section, "prompt-border-color", "255, 0, 0", False)
|
|
||||||
set_option(section, "prompt-border-width", "3", False)
|
|
||||||
set_option(section, "prompt-character-limit", "21", False)
|
|
||||||
set_option(section, "prompt-text-size", "42", False)
|
|
||||||
set_option(section, "template-nodeset", "L 0 0, 1000 1", False)
|
|
||||||
set_option(section, "template-nodeset-name", "template", False)
|
|
||||||
set_option(section, "flat-y-range", "1", False)
|
|
||||||
|
|
||||||
def add_section(self, name):
|
|
||||||
if name not in self.order:
|
|
||||||
self.order.append(name)
|
|
||||||
RawConfigParser.add_section(self, name)
|
|
||||||
|
|
||||||
def set(self, section, option, value, modifiable=True):
|
|
||||||
if modifiable:
|
|
||||||
if section not in self.order:
|
|
||||||
self.order.append(section)
|
|
||||||
if section not in self.modifiable:
|
|
||||||
self.modifiable[section] = []
|
|
||||||
if option not in self.modifiable[section]:
|
|
||||||
self.modifiable[section].append(option)
|
|
||||||
RawConfigParser.set(self, section, option, value)
|
|
||||||
|
|
||||||
def read_project_config_file(self):
|
|
||||||
path = self.locate_project_config_file()
|
|
||||||
if path:
|
|
||||||
fp = open(path)
|
|
||||||
self.set_modifiable(fp)
|
|
||||||
fp.seek(0)
|
|
||||||
self.readfp(fp)
|
|
||||||
fp.seek(0)
|
|
||||||
self.set_order(fp)
|
|
||||||
fp.close()
|
|
||||||
else:
|
|
||||||
self.print_debug("No configuration file found")
|
|
||||||
|
|
||||||
def locate_project_config_file(self):
|
|
||||||
rel_path = self.project_file_rel_path
|
|
||||||
if not rel_path:
|
|
||||||
rel_path = self.default_project_file_rel_path
|
|
||||||
if exists(rel_path) and not self.is_shared_mode():
|
|
||||||
return rel_path
|
|
||||||
if self.resource_path:
|
|
||||||
installed_path = join(self.resource_path, rel_path)
|
|
||||||
if exists(installed_path):
|
|
||||||
return installed_path
|
|
||||||
|
|
||||||
def set_order(self, fp):
|
|
||||||
self.order = order = []
|
|
||||||
for line in file(self.locate_project_config_file()):
|
|
||||||
result = match("^\s*\[(.*)\]\s*$", line)
|
|
||||||
if result:
|
|
||||||
order.append(result.group(1))
|
|
||||||
|
|
||||||
def set_modifiable(self, fp):
|
|
||||||
config = RawConfigParser()
|
|
||||||
config.readfp(fp)
|
|
||||||
modifiable = self.modifiable
|
|
||||||
for section in config._sections:
|
|
||||||
if section not in modifiable:
|
|
||||||
modifiable[section] = []
|
|
||||||
for option in config._sections[section]:
|
|
||||||
if option != "__name__" and option not in modifiable[section]:
|
|
||||||
modifiable[section].append(option)
|
|
||||||
|
|
||||||
def is_shared_mode(self):
|
|
||||||
return "-s" in argv
|
|
||||||
|
|
||||||
def print_debug(self, statement):
|
|
||||||
if self.is_debug_mode():
|
|
||||||
print statement
|
|
||||||
|
|
||||||
def is_debug_mode(self):
|
|
||||||
return "-d" in argv
|
|
||||||
|
|
||||||
def modify_defaults(self):
|
|
||||||
self.set_installation_path()
|
|
||||||
self.set_resource_search_path()
|
|
||||||
self.set_screen_captures_path()
|
|
||||||
self.set_video_recordings_path()
|
|
||||||
self.set_data_exclusion_list()
|
|
||||||
self.set_requirements()
|
|
||||||
|
|
||||||
def set_installation_path(self):
|
|
||||||
self.set("setup", "installation-path",
|
|
||||||
join(self.get("setup", "installation-dir"),
|
|
||||||
self.get("setup", "package-root")), False)
|
|
||||||
|
|
||||||
def set_resource_search_path(self):
|
|
||||||
section, option = "setup", "resource-search-path"
|
|
||||||
search_path = self.get(section, option)
|
|
||||||
if self.resource_path:
|
|
||||||
search_path.append(self.resource_path)
|
|
||||||
else:
|
|
||||||
search_path.append(self.get("setup", "installation-path"))
|
|
||||||
self.set(section, option, search_path, False)
|
|
||||||
|
|
||||||
def get(self, section, option):
|
|
||||||
value = RawConfigParser.get(self, section, option)
|
|
||||||
if value is None:
|
|
||||||
value = self.get_substitute(section, option)
|
|
||||||
return self.cast_value(section, option, value)
|
|
||||||
|
|
||||||
def get_substitute(self, section, option):
|
|
||||||
if section == "display":
|
|
||||||
if option == "caption":
|
|
||||||
return self.get("setup", "title")
|
|
||||||
|
|
||||||
def cast_value(self, section, option, value):
|
|
||||||
pair = section, option
|
|
||||||
types = self.type_declarations
|
|
||||||
if type(value) == str:
|
|
||||||
if pair in types["bool"]:
|
|
||||||
if value.lower() == self.get("setup", "lowercase-boolean-true"):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
elif pair in types["int"]:
|
|
||||||
return int(value)
|
|
||||||
elif pair in types["float"]:
|
|
||||||
return float(value)
|
|
||||||
elif pair in types["path"]:
|
|
||||||
return self.translate_path(value)
|
|
||||||
elif pair in types["list"]:
|
|
||||||
if value == "":
|
|
||||||
return []
|
|
||||||
else:
|
|
||||||
return map(str.strip, value.split(types.list_member_sep))
|
|
||||||
elif pair in types["int-list"]:
|
|
||||||
return map(int, value.split(types.list_member_sep))
|
|
||||||
elif pair in types["float-list"]:
|
|
||||||
return map(float, value.split(types.list_member_sep))
|
|
||||||
return value
|
|
||||||
|
|
||||||
def set_screen_captures_path(self):
|
|
||||||
section, option = "screen-captures", "path"
|
|
||||||
if not self.has_option(section, option):
|
|
||||||
self.set(section, option, join(self.build_home_path(),
|
|
||||||
self.get(section, "rel-path")),
|
|
||||||
False)
|
|
||||||
|
|
||||||
def build_home_path(self):
|
|
||||||
return join("~", "." + self.get("setup", "package-root"))
|
|
||||||
|
|
||||||
def set_video_recordings_path(self):
|
|
||||||
section, option = "video-recordings", "path"
|
|
||||||
if not self.has_option(section, option):
|
|
||||||
self.set(section, option, join(self.build_home_path(),
|
|
||||||
self.get(section, "rel-path")),
|
|
||||||
False)
|
|
||||||
|
|
||||||
def set_data_exclusion_list(self):
|
|
||||||
section, option = "setup", "data-exclude"
|
|
||||||
exclude = []
|
|
||||||
if self.has_option(section, option):
|
|
||||||
exclude = self.get(section, option)
|
|
||||||
exclude += [".git", ".gitignore", "README", "build/", "dist/",
|
|
||||||
"setup.py", "MANIFEST", "PKG-INFO",
|
|
||||||
self.get("setup", "changelog"),
|
|
||||||
self.get("setup", "package-root")]
|
|
||||||
for location in self.get("setup", "additional-packages"):
|
|
||||||
exclude.append(location)
|
|
||||||
self.set(section, option, exclude, False)
|
|
||||||
|
|
||||||
def set_requirements(self):
|
|
||||||
section, option = "setup", "requirements"
|
|
||||||
requirements = []
|
|
||||||
if self.has_option(section, option):
|
|
||||||
requirements = self.get(section, option)
|
|
||||||
if "pygame" not in requirements:
|
|
||||||
requirements.append("pygame")
|
|
||||||
self.set(section, option, requirements, False)
|
|
||||||
|
|
||||||
def get_section(self, section):
|
|
||||||
assignments = {}
|
|
||||||
for option in self.options(section):
|
|
||||||
assignments[option] = self.get(section, option)
|
|
||||||
return assignments
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
config = {}
|
|
||||||
for section in self.sections():
|
|
||||||
config[section] = self.get_section(section)
|
|
||||||
return pformat(config, 2, 1)
|
|
||||||
|
|
||||||
def items(self, section):
|
|
||||||
items = []
|
|
||||||
for option in self.options(section):
|
|
||||||
items.append((option, self.get(section, option)))
|
|
||||||
return items
|
|
||||||
|
|
||||||
def write(self, fp=None):
|
|
||||||
modifiable = self.modifiable
|
|
||||||
use_main = fp is None
|
|
||||||
if use_main:
|
|
||||||
path = self.locate_project_config_file()
|
|
||||||
if not path:
|
|
||||||
path = join(self.resource_path or "",
|
|
||||||
self.default_project_file_rel_path)
|
|
||||||
fp = open(path, "w")
|
|
||||||
break_line = False
|
|
||||||
for section in self.order:
|
|
||||||
if section in modifiable:
|
|
||||||
break_line and fp.write("\n")
|
|
||||||
fp.write("[%s]\n" % section)
|
|
||||||
for option in modifiable[section]:
|
|
||||||
if self.has_option(section, option):
|
|
||||||
value = self.get(section, option)
|
|
||||||
fp.write("%s = %s\n" % (option,
|
|
||||||
self.get_raw_value(value)))
|
|
||||||
break_line = True
|
|
||||||
if use_main:
|
|
||||||
fp.close()
|
|
||||||
|
|
||||||
def get_raw_value(self, value):
|
|
||||||
if isinstance(value, list):
|
|
||||||
raw = ""
|
|
||||||
for ii, value in enumerate(value):
|
|
||||||
if ii:
|
|
||||||
raw += ", "
|
|
||||||
raw += str(value)
|
|
||||||
else:
|
|
||||||
raw = str(value)
|
|
||||||
return raw
|
|
||||||
|
|
||||||
def clear_section(self, section):
|
|
||||||
if self.has_section(section):
|
|
||||||
for option in self.options(section):
|
|
||||||
self.remove_option(section, option)
|
|
||||||
|
|
||||||
|
|
||||||
class TypeDeclarations(dict):
|
|
||||||
|
|
||||||
list_member_sep = ','
|
|
||||||
|
|
||||||
defaults = {
|
|
||||||
|
|
||||||
"display": {"int": ["frame-duration", "wait-duration",
|
|
||||||
"framerate-text-size"],
|
|
||||||
|
|
||||||
"bool": ["centered", "skip-frames", "fullscreen",
|
|
||||||
"show-framerate"],
|
|
||||||
|
|
||||||
"int-list": ["dimensions", "framerate-text-color",
|
|
||||||
"framerate-text-background"]},
|
|
||||||
|
|
||||||
"screen-captures": {"path": ["rel-path", "path"]},
|
|
||||||
|
|
||||||
"video-recordings": {"path": ["rel-path", "path"],
|
|
||||||
|
|
||||||
"int": "framerate"},
|
|
||||||
|
|
||||||
"setup": {"list": ["classifiers", "resource-search-path",
|
|
||||||
"requirements", "data-exclude",
|
|
||||||
"additional-packages"],
|
|
||||||
|
|
||||||
"path": ["installation-dir", "changelog", "description-file",
|
|
||||||
"main-object", "icon-path", "windows-dist-path",
|
|
||||||
"package-root"]},
|
|
||||||
|
|
||||||
"mouse": {"float": "double-click-time-limit",
|
|
||||||
|
|
||||||
"bool": "visible"},
|
|
||||||
|
|
||||||
"keys": {"list": ["up", "right", "down", "left"]},
|
|
||||||
|
|
||||||
"joy": {"int": ["advance", "pause", "select"]},
|
|
||||||
|
|
||||||
"audio": {"path": "sfx-path"},
|
|
||||||
|
|
||||||
"event": {"int": "command-id-offset"},
|
|
||||||
|
|
||||||
"interpolator-gui": {"int": ["margin", "marker-size", "label-size",
|
|
||||||
"axis-label-count", "label-precision",
|
|
||||||
"prompt-border-width",
|
|
||||||
"prompt-character-limit",
|
|
||||||
"prompt-text-size", "flat-y-range"],
|
|
||||||
|
|
||||||
"int-list": ["marker-color", "curve-color",
|
|
||||||
"prompt-size",
|
|
||||||
"prompt-border-color"]},
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
additional_defaults = {}
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
dict.__init__(self, {"bool": [], "int": [], "float": [], "path": [],
|
|
||||||
"list": [], "int-list": [], "float-list": []})
|
|
||||||
self.add_chart(self.defaults)
|
|
||||||
self.add_chart(self.additional_defaults)
|
|
||||||
|
|
||||||
def add(self, cast, section, option):
|
|
||||||
self[cast].append((section, option))
|
|
||||||
|
|
||||||
def add_chart(self, chart):
|
|
||||||
for section, declarations in chart.iteritems():
|
|
||||||
for cast, options in declarations.iteritems():
|
|
||||||
if type(options) != list:
|
|
||||||
options = [options]
|
|
||||||
for option in options:
|
|
||||||
self.add(cast, section, option)
|
|
|
@ -1,87 +0,0 @@
|
||||||
from pygame.event import get, pump, Event, post
|
|
||||||
from pygame.locals import *
|
|
||||||
|
|
||||||
from GameChild import GameChild
|
|
||||||
from Input import Input
|
|
||||||
|
|
||||||
class Delegate(GameChild):
|
|
||||||
|
|
||||||
def __init__(self, game):
|
|
||||||
GameChild.__init__(self, game)
|
|
||||||
self.subscribers = dict()
|
|
||||||
self.load_configuration()
|
|
||||||
self.disable()
|
|
||||||
|
|
||||||
def load_configuration(self):
|
|
||||||
config = self.get_configuration("event")
|
|
||||||
self.cancel_flag_key = config["cancel-flag-key"]
|
|
||||||
self.command_key = config["command-key"]
|
|
||||||
self.command_event_id = config["command-id-offset"] + \
|
|
||||||
globals()[config["user-event-id"]]
|
|
||||||
|
|
||||||
def disable(self):
|
|
||||||
self.enabled = False
|
|
||||||
|
|
||||||
def enable(self):
|
|
||||||
self.enabled = True
|
|
||||||
self.interpolator = self.get_game().interpolator
|
|
||||||
|
|
||||||
def dispatch(self):
|
|
||||||
if self.enabled:
|
|
||||||
subscribers = self.subscribers
|
|
||||||
for evt in get():
|
|
||||||
kind = evt.type
|
|
||||||
if kind in subscribers:
|
|
||||||
for subscriber in subscribers[kind]:
|
|
||||||
if not self.interpolator.is_gui_active() or \
|
|
||||||
hasattr(subscriber, "im_class") and \
|
|
||||||
(subscriber.im_class == Input or \
|
|
||||||
subscriber.im_class == \
|
|
||||||
self.interpolator.gui.__class__):
|
|
||||||
self.print_debug("Passing %s to %s" % (evt,
|
|
||||||
subscriber))
|
|
||||||
subscriber(evt)
|
|
||||||
else:
|
|
||||||
pump()
|
|
||||||
|
|
||||||
def add_subscriber(self, callback, kind=None):
|
|
||||||
self.print_debug("Subscribing %s to %s" % (callback, kind))
|
|
||||||
if kind is None:
|
|
||||||
kind = self.command_event_id
|
|
||||||
subscribers = self.subscribers
|
|
||||||
if kind not in subscribers:
|
|
||||||
subscribers[kind] = list()
|
|
||||||
subscribers[kind].append(callback)
|
|
||||||
|
|
||||||
def is_command(self, event):
|
|
||||||
return event.type == self.command_event_id
|
|
||||||
|
|
||||||
def remove_subscriber(self, callback, kind=None):
|
|
||||||
if kind is None:
|
|
||||||
kind = self.command_event_id
|
|
||||||
self.subscribers[kind].remove(callback)
|
|
||||||
|
|
||||||
def compare(self, evt, commands=None, cancel=False, **attributes):
|
|
||||||
if evt.type == self.command_event_id:
|
|
||||||
self.add_cancel_flag_to_attributes(attributes, cancel)
|
|
||||||
if commands is not None and not isinstance(commands, list):
|
|
||||||
commands = [commands]
|
|
||||||
if commands is not None:
|
|
||||||
if not self.command_in_list(evt, commands):
|
|
||||||
return False
|
|
||||||
return all(key in evt.dict and evt.dict[key] == value for \
|
|
||||||
key, value in attributes.iteritems())
|
|
||||||
|
|
||||||
def add_cancel_flag_to_attributes(self, attributes, cancel):
|
|
||||||
attributes[self.cancel_flag_key] = cancel
|
|
||||||
|
|
||||||
def command_in_list(self, evt, commands):
|
|
||||||
return self.get_command_attribute(evt) in commands
|
|
||||||
|
|
||||||
def get_command_attribute(self, evt):
|
|
||||||
return evt.dict[self.command_key]
|
|
||||||
|
|
||||||
def post(self, command=None, cancel=False, **attributes):
|
|
||||||
attributes[self.command_key] = command
|
|
||||||
self.add_cancel_flag_to_attributes(attributes, cancel)
|
|
||||||
post(Event(self.command_event_id, attributes))
|
|
|
@ -1,81 +0,0 @@
|
||||||
from os import environ
|
|
||||||
|
|
||||||
from pygame import display, image, mouse
|
|
||||||
from pygame.locals import *
|
|
||||||
|
|
||||||
from GameChild import *
|
|
||||||
|
|
||||||
class Display(GameChild):
|
|
||||||
|
|
||||||
def __init__(self, game):
|
|
||||||
GameChild.__init__(self, game)
|
|
||||||
self.delegate = self.get_delegate()
|
|
||||||
self.load_configuration()
|
|
||||||
self.align_window()
|
|
||||||
self.init_screen()
|
|
||||||
self.set_caption()
|
|
||||||
self.set_icon()
|
|
||||||
self.set_mouse_visibility()
|
|
||||||
self.subscribe(self.toggle_fullscreen)
|
|
||||||
|
|
||||||
def load_configuration(self):
|
|
||||||
config = self.get_configuration("display")
|
|
||||||
self.centered = config["centered"]
|
|
||||||
self.fullscreen_enabled = config["fullscreen"]
|
|
||||||
self.caption = config["caption"]
|
|
||||||
self.windowed_flag = config["windowed-flag"]
|
|
||||||
self.icon_path = self.get_resource("display", "icon-path")
|
|
||||||
self.mouse_visibility = self.get_configuration("mouse", "visible")
|
|
||||||
|
|
||||||
def align_window(self):
|
|
||||||
if self.centered:
|
|
||||||
environ["SDL_VIDEO_CENTERED"] = "1"
|
|
||||||
|
|
||||||
def init_screen(self):
|
|
||||||
flags = 0
|
|
||||||
if self.fullscreen_requested():
|
|
||||||
flags = FULLSCREEN
|
|
||||||
self.set_screen(flags)
|
|
||||||
|
|
||||||
def fullscreen_requested(self):
|
|
||||||
return not self.check_command_line(self.windowed_flag) and \
|
|
||||||
self.fullscreen_enabled
|
|
||||||
|
|
||||||
def set_screen(self, flags=0, dimensions=None):
|
|
||||||
self.dimensions_changed = dimensions is not None
|
|
||||||
if dimensions is None:
|
|
||||||
if display.get_surface():
|
|
||||||
dimensions = display.get_surface().get_size()
|
|
||||||
else:
|
|
||||||
dimensions = self.get_configuration("display", "dimensions")
|
|
||||||
self.screen = display.set_mode(dimensions, flags)
|
|
||||||
if self.dimensions_changed:
|
|
||||||
interpolator = self.get_game().interpolator
|
|
||||||
if interpolator.gui_enabled:
|
|
||||||
interpolator.gui.rearrange()
|
|
||||||
|
|
||||||
def set_caption(self):
|
|
||||||
display.set_caption(self.caption)
|
|
||||||
|
|
||||||
def set_icon(self):
|
|
||||||
if self.icon_path:
|
|
||||||
print self.icon_path
|
|
||||||
display.set_icon(image.load(self.icon_path).convert_alpha())
|
|
||||||
|
|
||||||
def set_mouse_visibility(self, visibility=None):
|
|
||||||
if visibility is None:
|
|
||||||
visibility = self.mouse_visibility
|
|
||||||
return mouse.set_visible(visibility)
|
|
||||||
|
|
||||||
def get_screen(self):
|
|
||||||
return self.screen
|
|
||||||
|
|
||||||
def get_size(self):
|
|
||||||
return self.screen.get_size()
|
|
||||||
|
|
||||||
def toggle_fullscreen(self, event):
|
|
||||||
if self.delegate.compare(event, "toggle-fullscreen"):
|
|
||||||
screen = self.screen
|
|
||||||
cpy = screen.convert()
|
|
||||||
self.set_screen(self.screen.get_flags() ^ FULLSCREEN)
|
|
||||||
screen.blit(cpy, (0, 0))
|
|
|
@ -1,74 +0,0 @@
|
||||||
import pygame
|
|
||||||
from pygame.locals import *
|
|
||||||
|
|
||||||
from GameChild import GameChild
|
|
||||||
from Mainloop import Mainloop
|
|
||||||
from Audio import Audio
|
|
||||||
from Display import Display
|
|
||||||
from Configuration import Configuration
|
|
||||||
from Delegate import Delegate
|
|
||||||
from Input import Input
|
|
||||||
from ScreenGrabber import ScreenGrabber
|
|
||||||
from Profile import Profile
|
|
||||||
from VideoRecorder import VideoRecorder
|
|
||||||
from Interpolator import Interpolator
|
|
||||||
from TimeFilter import TimeFilter
|
|
||||||
|
|
||||||
class Game(GameChild):
|
|
||||||
|
|
||||||
resource_path = None
|
|
||||||
|
|
||||||
def __init__(self, config_rel_path=None, type_declarations=None):
|
|
||||||
self.profile = Profile(self)
|
|
||||||
GameChild.__init__(self)
|
|
||||||
self.print_debug(pygame.version.ver)
|
|
||||||
self.config_rel_path = config_rel_path
|
|
||||||
self.type_declarations = type_declarations
|
|
||||||
self.set_configuration()
|
|
||||||
pygame.init()
|
|
||||||
self.set_children()
|
|
||||||
self.subscribe(self.end, QUIT)
|
|
||||||
self.subscribe(self.end)
|
|
||||||
self.delegate.enable()
|
|
||||||
|
|
||||||
def set_configuration(self):
|
|
||||||
self.configuration = Configuration(self.config_rel_path,
|
|
||||||
self.resource_path,
|
|
||||||
self.type_declarations)
|
|
||||||
|
|
||||||
def set_children(self):
|
|
||||||
self.time_filter = TimeFilter(self)
|
|
||||||
self.delegate = Delegate(self)
|
|
||||||
self.display = Display(self)
|
|
||||||
self.mainloop = Mainloop(self)
|
|
||||||
self.input = Input(self)
|
|
||||||
self.audio = Audio(self)
|
|
||||||
self.screen_grabber = ScreenGrabber(self)
|
|
||||||
self.video_recorder = VideoRecorder(self)
|
|
||||||
self.interpolator = Interpolator(self)
|
|
||||||
|
|
||||||
def frame(self):
|
|
||||||
self.time_filter.update()
|
|
||||||
self.delegate.dispatch()
|
|
||||||
if not self.interpolator.is_gui_active():
|
|
||||||
self.update()
|
|
||||||
else:
|
|
||||||
self.interpolator.gui.update()
|
|
||||||
self.video_recorder.update()
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
self.mainloop.run()
|
|
||||||
|
|
||||||
def update(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def blit(self, source, destination, area=None, special_flags=0):
|
|
||||||
self.get_screen().blit(source, destination, area, special_flags)
|
|
||||||
|
|
||||||
def get_rect(self):
|
|
||||||
return self.get_screen().get_rect()
|
|
||||||
|
|
||||||
def end(self, evt):
|
|
||||||
if evt.type == QUIT or self.delegate.compare(evt, "quit"):
|
|
||||||
self.mainloop.stop()
|
|
||||||
self.profile.end()
|
|
|
@ -1,85 +0,0 @@
|
||||||
from os.path import exists, join, basename, normpath, abspath
|
|
||||||
from sys import argv
|
|
||||||
|
|
||||||
from pygame import mixer, event, time
|
|
||||||
from pygame.locals import *
|
|
||||||
|
|
||||||
import Game
|
|
||||||
|
|
||||||
class GameChild:
|
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
|
||||||
self.parent = parent
|
|
||||||
self.game = self.get_game()
|
|
||||||
|
|
||||||
def get_game(self):
|
|
||||||
current = self
|
|
||||||
while not isinstance(current, Game.Game):
|
|
||||||
current = current.parent
|
|
||||||
return current
|
|
||||||
|
|
||||||
def get_configuration(self, section=None, option=None):
|
|
||||||
config = self.game.configuration
|
|
||||||
if option and section:
|
|
||||||
return config.get(section, option)
|
|
||||||
if section:
|
|
||||||
return config.get_section(section)
|
|
||||||
return config
|
|
||||||
|
|
||||||
def get_input(self):
|
|
||||||
return self.game.input
|
|
||||||
|
|
||||||
def get_screen(self):
|
|
||||||
return self.game.display.get_screen()
|
|
||||||
|
|
||||||
def get_display_surface(self):
|
|
||||||
current = self
|
|
||||||
attribute = "display_surface"
|
|
||||||
while not isinstance(current, Game.Game):
|
|
||||||
if hasattr(current, attribute):
|
|
||||||
return getattr(current, attribute)
|
|
||||||
current = current.parent
|
|
||||||
return current.display.get_screen()
|
|
||||||
|
|
||||||
def get_audio(self):
|
|
||||||
return self.game.audio
|
|
||||||
|
|
||||||
def get_delegate(self):
|
|
||||||
return self.game.delegate
|
|
||||||
|
|
||||||
def get_resource(self, path_or_section, option=None):
|
|
||||||
config = self.get_configuration()
|
|
||||||
rel_path = path_or_section
|
|
||||||
if option is not None:
|
|
||||||
rel_path = config.get(path_or_section, option)
|
|
||||||
if rel_path:
|
|
||||||
for root in config.get("setup", "resource-search-path"):
|
|
||||||
if self.is_shared_mode() and not self.is_absolute_path(root):
|
|
||||||
continue
|
|
||||||
path = join(root, rel_path)
|
|
||||||
if exists(path):
|
|
||||||
return path
|
|
||||||
self.print_debug("Couldn't find resource: {0} {1}".\
|
|
||||||
format(path_or_section, option))
|
|
||||||
|
|
||||||
def is_shared_mode(self):
|
|
||||||
return self.check_command_line("s")
|
|
||||||
|
|
||||||
def check_command_line(self, flag):
|
|
||||||
return "-" + flag in argv
|
|
||||||
|
|
||||||
def print_debug(self, statement):
|
|
||||||
if self.is_debug_mode():
|
|
||||||
print statement
|
|
||||||
|
|
||||||
def is_debug_mode(self):
|
|
||||||
return self.check_command_line("d")
|
|
||||||
|
|
||||||
def is_absolute_path(self, path):
|
|
||||||
return normpath(path) == abspath(path)
|
|
||||||
|
|
||||||
def subscribe(self, callback, kind=None):
|
|
||||||
self.game.delegate.add_subscriber(callback, kind)
|
|
||||||
|
|
||||||
def unsubscribe(self, callback, kind=None):
|
|
||||||
self.game.delegate.remove_subscriber(callback, kind)
|
|
|
@ -1,204 +0,0 @@
|
||||||
from time import time as get_secs
|
|
||||||
|
|
||||||
from pygame import joystick as joy
|
|
||||||
from pygame.key import get_pressed
|
|
||||||
from pygame.locals import *
|
|
||||||
|
|
||||||
from GameChild import *
|
|
||||||
|
|
||||||
class Input(GameChild):
|
|
||||||
|
|
||||||
def __init__(self, game):
|
|
||||||
GameChild.__init__(self, game)
|
|
||||||
self.last_mouse_down_left = None
|
|
||||||
self.joystick = Joystick()
|
|
||||||
self.delegate = self.get_delegate()
|
|
||||||
self.load_configuration()
|
|
||||||
self.set_any_press_ignore_list()
|
|
||||||
self.unsuppress()
|
|
||||||
self.subscribe_to_events()
|
|
||||||
self.build_key_map()
|
|
||||||
self.build_joy_button_map()
|
|
||||||
|
|
||||||
def load_configuration(self):
|
|
||||||
self.release_suffix = self.get_configuration("input", "release-suffix")
|
|
||||||
self.key_commands = self.get_configuration().items("keys")
|
|
||||||
self.double_click_time_limit = self.get_configuration(
|
|
||||||
"mouse", "double-click-time-limit")
|
|
||||||
|
|
||||||
def set_any_press_ignore_list(self):
|
|
||||||
self.any_press_ignored = set(["capture-screen", "toggle-fullscreen",
|
|
||||||
"reset-game", "record-video", "quit",
|
|
||||||
"mute", "toggle-interpolator"])
|
|
||||||
self.any_press_ignored_keys = set()
|
|
||||||
|
|
||||||
def unsuppress(self):
|
|
||||||
self.suppressed = False
|
|
||||||
|
|
||||||
def subscribe_to_events(self):
|
|
||||||
self.subscribe(self.translate_key, KEYDOWN)
|
|
||||||
self.subscribe(self.translate_key, KEYUP)
|
|
||||||
self.subscribe(self.translate_joy_button, JOYBUTTONDOWN)
|
|
||||||
self.subscribe(self.translate_joy_button, JOYBUTTONUP)
|
|
||||||
self.subscribe(self.translate_axis_motion, JOYAXISMOTION)
|
|
||||||
self.subscribe(self.translate_mouse_input, MOUSEBUTTONDOWN)
|
|
||||||
self.subscribe(self.translate_mouse_input, MOUSEBUTTONUP)
|
|
||||||
|
|
||||||
def build_key_map(self):
|
|
||||||
key_map = {}
|
|
||||||
for command, keys in self.key_commands:
|
|
||||||
key_map[command] = []
|
|
||||||
if type(keys) == str:
|
|
||||||
keys = [keys]
|
|
||||||
for key in keys:
|
|
||||||
key_map[command].append(globals()[key])
|
|
||||||
self.key_map = key_map
|
|
||||||
|
|
||||||
def build_joy_button_map(self):
|
|
||||||
self.joy_button_map = self.get_configuration("joy")
|
|
||||||
|
|
||||||
def suppress(self):
|
|
||||||
self.suppressed = True
|
|
||||||
|
|
||||||
def translate_key(self, event):
|
|
||||||
if not self.suppressed:
|
|
||||||
cancel = event.type == KEYUP
|
|
||||||
posted = None
|
|
||||||
key = event.key
|
|
||||||
for cmd, keys in self.key_map.iteritems():
|
|
||||||
if key in keys:
|
|
||||||
self.post_command(cmd, cancel=cancel)
|
|
||||||
posted = cmd
|
|
||||||
if (not posted or posted not in self.any_press_ignored) and \
|
|
||||||
key not in self.any_press_ignored_keys:
|
|
||||||
self.post_any_command(key, cancel)
|
|
||||||
|
|
||||||
def post_command(self, cmd, **attributes):
|
|
||||||
self.delegate.post(cmd, **attributes)
|
|
||||||
|
|
||||||
def post_any_command(self, id, cancel=False):
|
|
||||||
self.post_command("any", id=id, cancel=cancel)
|
|
||||||
|
|
||||||
def translate_joy_button(self, event):
|
|
||||||
if not self.suppressed:
|
|
||||||
cancel = event.type == JOYBUTTONUP
|
|
||||||
posted = None
|
|
||||||
for command, button in self.joy_button_map.iteritems():
|
|
||||||
if button == event.button:
|
|
||||||
self.post_command(command, cancel=cancel)
|
|
||||||
posted = command
|
|
||||||
if not posted or posted not in self.any_press_ignored:
|
|
||||||
self.post_any_command(event.button, cancel)
|
|
||||||
|
|
||||||
def translate_axis_motion(self, event):
|
|
||||||
if not self.suppressed:
|
|
||||||
axis = event.axis
|
|
||||||
value = event.value
|
|
||||||
if not value:
|
|
||||||
for command in "up", "right", "down", "left":
|
|
||||||
self.post_command(command, cancel=True)
|
|
||||||
if command not in self.any_press_ignored:
|
|
||||||
self.post_any_command(command, True)
|
|
||||||
else:
|
|
||||||
if axis == 1:
|
|
||||||
if value < 0:
|
|
||||||
command = "up"
|
|
||||||
elif value > 0:
|
|
||||||
command = "down"
|
|
||||||
else:
|
|
||||||
if value > 0:
|
|
||||||
command = "right"
|
|
||||||
elif value < 0:
|
|
||||||
command = "left"
|
|
||||||
self.post_command(command)
|
|
||||||
if command not in self.any_press_ignored:
|
|
||||||
self.post_any_command(command)
|
|
||||||
|
|
||||||
def is_command_active(self, command):
|
|
||||||
if not self.suppressed:
|
|
||||||
if self.is_key_pressed(command):
|
|
||||||
return True
|
|
||||||
joystick = self.joystick
|
|
||||||
joy_map = self.joy_button_map
|
|
||||||
if command in joy_map and joystick.get_button(joy_map[command]):
|
|
||||||
return True
|
|
||||||
if command == "up":
|
|
||||||
return joystick.is_direction_pressed(Joystick.up)
|
|
||||||
elif command == "right":
|
|
||||||
return joystick.is_direction_pressed(Joystick.right)
|
|
||||||
elif command == "down":
|
|
||||||
return joystick.is_direction_pressed(Joystick.down)
|
|
||||||
elif command == "left":
|
|
||||||
return joystick.is_direction_pressed(Joystick.left)
|
|
||||||
|
|
||||||
def is_key_pressed(self, command):
|
|
||||||
poll = get_pressed()
|
|
||||||
for key in self.key_map[command]:
|
|
||||||
if poll[key]:
|
|
||||||
return True
|
|
||||||
|
|
||||||
def translate_mouse_input(self, event):
|
|
||||||
button = event.button
|
|
||||||
pos = event.pos
|
|
||||||
post = self.post_command
|
|
||||||
if event.type == MOUSEBUTTONDOWN:
|
|
||||||
if button == 1:
|
|
||||||
last = self.last_mouse_down_left
|
|
||||||
if last:
|
|
||||||
limit = self.double_click_time_limit
|
|
||||||
if get_secs() - last < limit:
|
|
||||||
post("mouse-double-click-left", pos=pos)
|
|
||||||
last = get_secs()
|
|
||||||
self.last_mouse_down_left = last
|
|
||||||
|
|
||||||
def get_axes(self):
|
|
||||||
axes = {}
|
|
||||||
for direction in "up", "right", "down", "left":
|
|
||||||
axes[direction] = self.is_command_active(direction)
|
|
||||||
return axes
|
|
||||||
|
|
||||||
def register_any_press_ignore(self, *args, **attributes):
|
|
||||||
self.any_press_ignored.update(args)
|
|
||||||
self.any_press_ignored_keys.update(self.extract_keys(attributes))
|
|
||||||
|
|
||||||
def extract_keys(self, attributes):
|
|
||||||
keys = []
|
|
||||||
if "keys" in attributes:
|
|
||||||
keys = attributes["keys"]
|
|
||||||
if type(keys) == int:
|
|
||||||
keys = [keys]
|
|
||||||
return keys
|
|
||||||
|
|
||||||
def unregister_any_press_ignore(self, *args, **attributes):
|
|
||||||
self.any_press_ignored.difference_update(args)
|
|
||||||
self.any_press_ignored_keys.difference_update(
|
|
||||||
self.extract_keys(attributes))
|
|
||||||
|
|
||||||
|
|
||||||
class Joystick:
|
|
||||||
|
|
||||||
(up, right, down, left) = range(4)
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
js = None
|
|
||||||
if joy.get_count() > 0:
|
|
||||||
js = joy.Joystick(0)
|
|
||||||
js.init()
|
|
||||||
self.js = js
|
|
||||||
|
|
||||||
def is_direction_pressed(self, direction):
|
|
||||||
js = self.js
|
|
||||||
if not js or direction > 4:
|
|
||||||
return False
|
|
||||||
if direction == 0:
|
|
||||||
return js.get_axis(1) < 0
|
|
||||||
elif direction == 1:
|
|
||||||
return js.get_axis(0) > 0
|
|
||||||
elif direction == 2:
|
|
||||||
return js.get_axis(1) > 0
|
|
||||||
elif direction == 3:
|
|
||||||
return js.get_axis(0) < 0
|
|
||||||
|
|
||||||
def get_button(self, id):
|
|
||||||
if self.js:
|
|
||||||
return self.js.get_button(id)
|
|
|
@ -1,733 +0,0 @@
|
||||||
from re import match
|
|
||||||
from os.path import join
|
|
||||||
from tempfile import gettempdir
|
|
||||||
|
|
||||||
from pygame import Surface
|
|
||||||
from pygame.font import Font
|
|
||||||
from pygame.draw import aaline
|
|
||||||
from pygame.locals import *
|
|
||||||
|
|
||||||
from GameChild import GameChild
|
|
||||||
from Sprite import Sprite
|
|
||||||
from Animation import Animation
|
|
||||||
|
|
||||||
class Interpolator(list, GameChild):
|
|
||||||
|
|
||||||
def __init__(self, parent):
|
|
||||||
GameChild.__init__(self, parent)
|
|
||||||
self.set_nodesets()
|
|
||||||
self.gui_enabled = self.check_command_line("-interpolator")
|
|
||||||
if self.gui_enabled:
|
|
||||||
self.gui = GUI(self)
|
|
||||||
|
|
||||||
def set_nodesets(self):
|
|
||||||
config = self.get_configuration()
|
|
||||||
if config.has_section("interpolate"):
|
|
||||||
for name, value in config.get_section("interpolate").iteritems():
|
|
||||||
self.add_nodeset(name, value)
|
|
||||||
|
|
||||||
def add_nodeset(self, name, value, method=None):
|
|
||||||
self.append(Nodeset(name, value, method))
|
|
||||||
return len(self) - 1
|
|
||||||
|
|
||||||
def is_gui_active(self):
|
|
||||||
return self.gui_enabled and self.gui.active
|
|
||||||
|
|
||||||
def get_nodeset(self, name):
|
|
||||||
for nodeset in self:
|
|
||||||
if nodeset.name == name:
|
|
||||||
return nodeset
|
|
||||||
|
|
||||||
def remove(self, outgoing):
|
|
||||||
for ii, nodeset in enumerate(self):
|
|
||||||
if nodeset.name == outgoing.name:
|
|
||||||
self.pop(ii)
|
|
||||||
break
|
|
||||||
|
|
||||||
|
|
||||||
class Nodeset(list):
|
|
||||||
|
|
||||||
LINEAR, CUBIC = range(2)
|
|
||||||
|
|
||||||
def __init__(self, name, nodes, method=None):
|
|
||||||
list.__init__(self, [])
|
|
||||||
self.name = name
|
|
||||||
if isinstance(nodes, str):
|
|
||||||
self.parse_raw(nodes)
|
|
||||||
else:
|
|
||||||
self.interpolation_method = method
|
|
||||||
self.parse_list(nodes)
|
|
||||||
self.set_splines()
|
|
||||||
|
|
||||||
def parse_raw(self, raw):
|
|
||||||
raw = raw.strip()
|
|
||||||
if raw[0].upper() == "L":
|
|
||||||
self.set_interpolation_method(self.LINEAR, False)
|
|
||||||
else:
|
|
||||||
self.set_interpolation_method(self.CUBIC, False)
|
|
||||||
for node in raw[1:].strip().split(","):
|
|
||||||
self.add_node(map(float, node.strip().split()), False)
|
|
||||||
|
|
||||||
def set_interpolation_method(self, method, refresh=True):
|
|
||||||
self.interpolation_method = method
|
|
||||||
if refresh:
|
|
||||||
self.set_splines()
|
|
||||||
|
|
||||||
def add_node(self, coordinates, refresh=True):
|
|
||||||
x = coordinates[0]
|
|
||||||
inserted = False
|
|
||||||
index = 0
|
|
||||||
for ii, node in enumerate(self):
|
|
||||||
if x < node.x:
|
|
||||||
self.insert(ii, Node(coordinates))
|
|
||||||
inserted = True
|
|
||||||
index = ii
|
|
||||||
break
|
|
||||||
elif x == node.x:
|
|
||||||
return None
|
|
||||||
if not inserted:
|
|
||||||
self.append(Node(coordinates))
|
|
||||||
index = len(self) - 1
|
|
||||||
if refresh:
|
|
||||||
self.set_splines()
|
|
||||||
return index
|
|
||||||
|
|
||||||
def parse_list(self, nodes):
|
|
||||||
for node in nodes:
|
|
||||||
self.add_node(node)
|
|
||||||
|
|
||||||
def set_splines(self):
|
|
||||||
if self.interpolation_method == self.LINEAR:
|
|
||||||
self.set_linear_splines()
|
|
||||||
else:
|
|
||||||
self.set_cubic_splines()
|
|
||||||
|
|
||||||
def set_linear_splines(self):
|
|
||||||
self.splines = splines = []
|
|
||||||
for ii in xrange(len(self) - 1):
|
|
||||||
x1, y1, x2, y2 = self[ii] + self[ii + 1]
|
|
||||||
m = float(y2 - y1) / (x2 - x1)
|
|
||||||
splines.append(LinearSpline(x1, y1, m))
|
|
||||||
|
|
||||||
def set_cubic_splines(self):
|
|
||||||
n = len(self) - 1
|
|
||||||
a = [node.y for node in self]
|
|
||||||
b = [None] * n
|
|
||||||
d = [None] * n
|
|
||||||
h = [self[ii + 1].x - self[ii].x for ii in xrange(n)]
|
|
||||||
alpha = [None] + [(3.0 / h[ii]) * (a[ii + 1] - a[ii]) - \
|
|
||||||
(3.0 / h[ii - 1]) * (a[ii] - a[ii - 1]) \
|
|
||||||
for ii in xrange(1, n)]
|
|
||||||
c = [None] * (n + 1)
|
|
||||||
l = [None] * (n + 1)
|
|
||||||
u = [None] * (n + 1)
|
|
||||||
z = [None] * (n + 1)
|
|
||||||
l[0] = 1
|
|
||||||
u[0] = z[0] = 0
|
|
||||||
for ii in xrange(1, n):
|
|
||||||
l[ii] = 2 * (self[ii + 1].x - self[ii - 1].x) - \
|
|
||||||
h[ii - 1] * u[ii - 1]
|
|
||||||
u[ii] = h[ii] / l[ii]
|
|
||||||
z[ii] = (alpha[ii] - h[ii - 1] * z[ii - 1]) / l[ii]
|
|
||||||
l[n] = 1
|
|
||||||
z[n] = c[n] = 0
|
|
||||||
for jj in xrange(n - 1, -1, -1):
|
|
||||||
c[jj] = z[jj] - u[jj] * c[jj + 1]
|
|
||||||
b[jj] = (a[jj + 1] - a[jj]) / h[jj] - \
|
|
||||||
(h[jj] * (c[jj + 1] + 2 * c[jj])) / 3
|
|
||||||
d[jj] = (c[jj + 1] - c[jj]) / (3 * h[jj])
|
|
||||||
self.splines = [CubicSpline(self[ii].x, a[ii], b[ii], c[ii],
|
|
||||||
d[ii]) for ii in xrange(n)]
|
|
||||||
|
|
||||||
def get_y(self, t, loop=False, reverse=False, natural=False):
|
|
||||||
if loop or reverse:
|
|
||||||
if reverse and int(t) / int(self[-1].x) % 2:
|
|
||||||
t = self[-1].x - t
|
|
||||||
t %= self[-1].x
|
|
||||||
elif not natural:
|
|
||||||
if t < self[0].x:
|
|
||||||
t = self[0].x
|
|
||||||
elif t > self[-1].x:
|
|
||||||
t = self[-1].x
|
|
||||||
splines = self.splines
|
|
||||||
for ii in xrange(len(splines) - 1):
|
|
||||||
if t < splines[ii + 1].x:
|
|
||||||
return splines[ii].get_y(t)
|
|
||||||
return splines[-1].get_y(t)
|
|
||||||
|
|
||||||
def remove(self, node, refresh=True):
|
|
||||||
list.remove(self, node)
|
|
||||||
if refresh:
|
|
||||||
self.set_splines()
|
|
||||||
|
|
||||||
def resize(self, left, length, refresh=True):
|
|
||||||
old_left = self[0].x
|
|
||||||
old_length = self.get_length()
|
|
||||||
for node in self:
|
|
||||||
node.x = left + length * (node.x - old_left) / old_length
|
|
||||||
if refresh:
|
|
||||||
self.set_splines()
|
|
||||||
|
|
||||||
def get_length(self):
|
|
||||||
return self[-1].x - self[0].x
|
|
||||||
|
|
||||||
|
|
||||||
class Node(list):
|
|
||||||
|
|
||||||
def __init__(self, coordinates):
|
|
||||||
list.__init__(self, coordinates)
|
|
||||||
|
|
||||||
def __getattr__(self, name):
|
|
||||||
if name == "x":
|
|
||||||
return self[0]
|
|
||||||
elif name == "y":
|
|
||||||
return self[1]
|
|
||||||
return list.__get__(self, name)
|
|
||||||
|
|
||||||
def __setattr__(self, name, value):
|
|
||||||
if name == "x":
|
|
||||||
list.__setitem__(self, 0, value)
|
|
||||||
elif name == "y":
|
|
||||||
list.__setitem__(self, 1, value)
|
|
||||||
else:
|
|
||||||
list.__setattr__(self, name, value)
|
|
||||||
|
|
||||||
|
|
||||||
class Spline:
|
|
||||||
|
|
||||||
def __init__(self, x):
|
|
||||||
self.x = x
|
|
||||||
|
|
||||||
|
|
||||||
class CubicSpline(Spline):
|
|
||||||
|
|
||||||
def __init__(self, x, a, b, c, d):
|
|
||||||
Spline.__init__(self, x)
|
|
||||||
self.a = a
|
|
||||||
self.b = b
|
|
||||||
self.c = c
|
|
||||||
self.d = d
|
|
||||||
|
|
||||||
def get_y(self, t):
|
|
||||||
x = self.x
|
|
||||||
return self.a + self.b * (t - x) + self.c * (t - x) ** 2 + self.d * \
|
|
||||||
(t - x) ** 3
|
|
||||||
|
|
||||||
|
|
||||||
class LinearSpline(Spline):
|
|
||||||
|
|
||||||
def __init__(self, x, y, m):
|
|
||||||
Spline.__init__(self, x)
|
|
||||||
self.y = y
|
|
||||||
self.m = m
|
|
||||||
|
|
||||||
def get_y(self, t):
|
|
||||||
return self.m * (t - self.x) + self.y
|
|
||||||
|
|
||||||
|
|
||||||
class GUI(Animation):
|
|
||||||
|
|
||||||
B_DUPLICATE, B_WRITE, B_DELETE, B_LINEAR, B_CUBIC, B_SPLIT = range(6)
|
|
||||||
S_NONE, S_LEFT, S_RIGHT = range(3)
|
|
||||||
|
|
||||||
def __init__(self, parent):
|
|
||||||
Animation.__init__(self, parent, unfiltered=True)
|
|
||||||
self.audio = self.get_audio()
|
|
||||||
self.display = self.get_game().display
|
|
||||||
self.display_surface = self.get_display_surface()
|
|
||||||
self.time_filter = self.get_game().time_filter
|
|
||||||
self.delegate = self.get_delegate()
|
|
||||||
self.split = self.S_NONE
|
|
||||||
self.success_indicator_active = True
|
|
||||||
self.success_indicator_blink_count = 0
|
|
||||||
self.load_configuration()
|
|
||||||
self.font = Font(None, self.label_size)
|
|
||||||
self.prompt = Prompt(self)
|
|
||||||
self.set_temporary_file()
|
|
||||||
self.set_background()
|
|
||||||
self.set_success_indicator()
|
|
||||||
self.set_plot_rect()
|
|
||||||
self.set_marker_frame()
|
|
||||||
self.set_buttons()
|
|
||||||
self.active = False
|
|
||||||
self.set_nodeset_index()
|
|
||||||
self.set_y_range()
|
|
||||||
self.set_markers()
|
|
||||||
self.subscribe(self.respond_to_command)
|
|
||||||
self.subscribe(self.respond_to_mouse_down, MOUSEBUTTONDOWN)
|
|
||||||
self.subscribe(self.respond_to_key, KEYDOWN)
|
|
||||||
self.register(self.show_success_indicator, interval=100)
|
|
||||||
self.register(self.save_temporary_file, interval=10000)
|
|
||||||
self.play(self.save_temporary_file)
|
|
||||||
|
|
||||||
def load_configuration(self):
|
|
||||||
config = self.get_configuration("interpolator-gui")
|
|
||||||
self.label_size = config["label-size"]
|
|
||||||
self.axis_label_count = config["axis-label-count"]
|
|
||||||
self.margin = config["margin"]
|
|
||||||
self.curve_color = config["curve-color"]
|
|
||||||
self.marker_size = config["marker-size"]
|
|
||||||
self.marker_color = config["marker-color"]
|
|
||||||
self.label_precision = config["label-precision"]
|
|
||||||
self.template_nodeset = config["template-nodeset"]
|
|
||||||
self.template_nodeset_name = config["template-nodeset-name"]
|
|
||||||
self.flat_y_range = config["flat-y-range"]
|
|
||||||
|
|
||||||
def set_temporary_file(self):
|
|
||||||
self.temporary_file = open(join(gettempdir(), "pgfw-config"), "w")
|
|
||||||
|
|
||||||
def set_background(self):
|
|
||||||
surface = Surface(self.display_surface.get_size())
|
|
||||||
surface.fill((0, 0, 0))
|
|
||||||
self.background = surface
|
|
||||||
|
|
||||||
def set_success_indicator(self):
|
|
||||||
surface = Surface((10, 10))
|
|
||||||
surface.fill((0, 255, 0))
|
|
||||||
rect = surface.get_rect()
|
|
||||||
rect.topleft = self.display_surface.get_rect().topleft
|
|
||||||
self.success_indicator, self.success_indicator_rect = surface, rect
|
|
||||||
|
|
||||||
def set_plot_rect(self):
|
|
||||||
margin = self.margin
|
|
||||||
self.plot_rect = self.display_surface.get_rect().inflate(-margin,
|
|
||||||
-margin)
|
|
||||||
|
|
||||||
def set_marker_frame(self):
|
|
||||||
size = self.marker_size
|
|
||||||
surface = Surface((size, size))
|
|
||||||
transparent_color = (255, 0, 255)
|
|
||||||
surface.fill(transparent_color)
|
|
||||||
surface.set_colorkey(transparent_color)
|
|
||||||
line_color = self.marker_color
|
|
||||||
aaline(surface, line_color, (0, 0), (size - 1, size - 1))
|
|
||||||
aaline(surface, line_color, (0, size - 1), (size - 1, 0))
|
|
||||||
self.marker_frame = surface
|
|
||||||
|
|
||||||
def set_buttons(self):
|
|
||||||
self.buttons = buttons = []
|
|
||||||
text = "Duplicate", "Write", "Delete", "Linear", "Cubic", "Split: No"
|
|
||||||
x = 0
|
|
||||||
for instruction in text:
|
|
||||||
buttons.append(Button(self, instruction, x))
|
|
||||||
x += buttons[-1].location.w + 10
|
|
||||||
|
|
||||||
def set_nodeset_index(self, increment=None, index=None):
|
|
||||||
parent = self.parent
|
|
||||||
if index is None:
|
|
||||||
if not increment:
|
|
||||||
index = 0
|
|
||||||
else:
|
|
||||||
index = self.nodeset_index + increment
|
|
||||||
limit = len(parent) - 1
|
|
||||||
if index > limit:
|
|
||||||
index = 0
|
|
||||||
elif index < 0:
|
|
||||||
index = limit
|
|
||||||
self.nodeset_index = index
|
|
||||||
self.set_nodeset_label()
|
|
||||||
|
|
||||||
def set_nodeset_label(self):
|
|
||||||
surface = self.font.render(self.get_nodeset().name, True, (0, 0, 0),
|
|
||||||
(255, 255, 255))
|
|
||||||
rect = surface.get_rect()
|
|
||||||
rect.bottomright = self.display_surface.get_rect().bottomright
|
|
||||||
self.nodeset_label, self.nodeset_label_rect = surface, rect
|
|
||||||
|
|
||||||
def get_nodeset(self):
|
|
||||||
if not len(self.parent):
|
|
||||||
self.parent.add_nodeset(self.template_nodeset_name,
|
|
||||||
self.template_nodeset)
|
|
||||||
self.set_nodeset_index(0)
|
|
||||||
return self.parent[self.nodeset_index]
|
|
||||||
|
|
||||||
def set_y_range(self):
|
|
||||||
width = self.plot_rect.w
|
|
||||||
nodeset = self.get_nodeset()
|
|
||||||
self.y_range = y_range = [nodeset[0].y, nodeset[-1].y]
|
|
||||||
x = 0
|
|
||||||
while x < width:
|
|
||||||
y = nodeset.get_y(self.get_function_coordinates(x)[0])
|
|
||||||
if y < y_range[0]:
|
|
||||||
y_range[0] = y
|
|
||||||
elif y > y_range[1]:
|
|
||||||
y_range[1] = y
|
|
||||||
x += width * .01
|
|
||||||
if y_range[1] - y_range[0] == 0:
|
|
||||||
y_range[1] += self.flat_y_range
|
|
||||||
if self.split:
|
|
||||||
self.adjust_for_split(y_range, nodeset)
|
|
||||||
self.set_axis_labels()
|
|
||||||
|
|
||||||
def get_function_coordinates(self, xp=0, yp=0):
|
|
||||||
nodeset = self.get_nodeset()
|
|
||||||
x_min, x_max, (y_min, y_max) = nodeset[0].x, nodeset[-1].x, self.y_range
|
|
||||||
rect = self.plot_rect
|
|
||||||
x = float(xp) / (rect.right - rect.left) * (x_max - x_min) + x_min
|
|
||||||
y = float(yp) / (rect.bottom - rect.top) * (y_min - y_max) + y_max
|
|
||||||
return x, y
|
|
||||||
|
|
||||||
def adjust_for_split(self, y_range, nodeset):
|
|
||||||
middle = nodeset[0].y if self.split == self.S_LEFT else nodeset[-1].y
|
|
||||||
below, above = middle - y_range[0], y_range[1] - middle
|
|
||||||
if below > above:
|
|
||||||
y_range[1] += below - above
|
|
||||||
else:
|
|
||||||
y_range[0] -= above - below
|
|
||||||
|
|
||||||
def set_axis_labels(self):
|
|
||||||
self.axis_labels = labels = []
|
|
||||||
nodeset, formatted, render, rect, yr = (self.get_nodeset(),
|
|
||||||
self.get_formatted_measure,
|
|
||||||
self.font.render,
|
|
||||||
self.plot_rect, self.y_range)
|
|
||||||
for ii, node in enumerate(nodeset[0::len(nodeset) - 1]):
|
|
||||||
xs = render(formatted(node.x), True, (0, 0, 0), (255, 255, 255))
|
|
||||||
xsr = xs.get_rect()
|
|
||||||
xsr.top = rect.bottom
|
|
||||||
if not ii:
|
|
||||||
xsr.left = rect.left
|
|
||||||
else:
|
|
||||||
xsr.right = rect.right
|
|
||||||
ys = render(formatted(yr[ii]), True, (0, 0, 0), (255, 255, 255))
|
|
||||||
ysr = ys.get_rect()
|
|
||||||
ysr.right = rect.left
|
|
||||||
if not ii:
|
|
||||||
ysr.bottom = rect.bottom
|
|
||||||
else:
|
|
||||||
ysr.top = rect.top
|
|
||||||
labels.append(((xs, xsr), (ys, ysr)))
|
|
||||||
|
|
||||||
def get_formatted_measure(self, measure):
|
|
||||||
return "%s" % float(("%." + str(self.label_precision) + "g") % measure)
|
|
||||||
|
|
||||||
def deactivate(self):
|
|
||||||
self.active = False
|
|
||||||
self.time_filter.open()
|
|
||||||
self.audio.muted = self.saved_mute_state
|
|
||||||
self.display.set_mouse_visibility(self.saved_mouse_state)
|
|
||||||
|
|
||||||
def respond_to_command(self, event):
|
|
||||||
compare = self.delegate.compare
|
|
||||||
if compare(event, "toggle-interpolator"):
|
|
||||||
self.toggle()
|
|
||||||
elif self.active:
|
|
||||||
if compare(event, "reset-game"):
|
|
||||||
self.deactivate()
|
|
||||||
elif compare(event, "quit"):
|
|
||||||
self.get_game().end(event)
|
|
||||||
|
|
||||||
def toggle(self):
|
|
||||||
if self.active:
|
|
||||||
self.deactivate()
|
|
||||||
else:
|
|
||||||
self.activate()
|
|
||||||
|
|
||||||
def activate(self):
|
|
||||||
self.active = True
|
|
||||||
self.time_filter.close()
|
|
||||||
self.saved_mute_state = self.audio.muted
|
|
||||||
self.audio.mute()
|
|
||||||
self.draw()
|
|
||||||
self.saved_mouse_state = self.display.set_mouse_visibility(True)
|
|
||||||
|
|
||||||
def respond_to_mouse_down(self, event):
|
|
||||||
redraw = False
|
|
||||||
if self.active and not self.prompt.active:
|
|
||||||
nodeset_rect = self.nodeset_label_rect
|
|
||||||
plot_rect = self.plot_rect
|
|
||||||
if event.button == 1:
|
|
||||||
pos = event.pos
|
|
||||||
if nodeset_rect.collidepoint(pos):
|
|
||||||
self.set_nodeset_index(1)
|
|
||||||
redraw = True
|
|
||||||
elif self.axis_labels[0][0][1].collidepoint(pos):
|
|
||||||
text = "{0} {1}".format(*map(self.get_formatted_measure,
|
|
||||||
self.get_nodeset()[0]))
|
|
||||||
self.prompt.activate(text, self.resize_nodeset, 0)
|
|
||||||
elif self.axis_labels[1][0][1].collidepoint(pos):
|
|
||||||
text = "{0} {1}".format(*map(self.get_formatted_measure,
|
|
||||||
self.get_nodeset()[-1]))
|
|
||||||
self.prompt.activate(text, self.resize_nodeset, -1)
|
|
||||||
else:
|
|
||||||
bi = self.collide_buttons(pos)
|
|
||||||
if bi is not None:
|
|
||||||
if bi == self.B_WRITE:
|
|
||||||
self.get_configuration().write()
|
|
||||||
self.play(self.show_success_indicator)
|
|
||||||
elif bi in (self.B_LINEAR, self.B_CUBIC):
|
|
||||||
nodeset = self.get_nodeset()
|
|
||||||
if bi == self.B_LINEAR:
|
|
||||||
nodeset.set_interpolation_method(Nodeset.LINEAR)
|
|
||||||
else:
|
|
||||||
nodeset.set_interpolation_method(Nodeset.CUBIC)
|
|
||||||
self.store_in_configuration()
|
|
||||||
redraw = True
|
|
||||||
elif bi == self.B_DUPLICATE:
|
|
||||||
self.prompt.activate("", self.add_nodeset)
|
|
||||||
elif bi == self.B_DELETE and len(self.parent) > 1:
|
|
||||||
self.parent.remove(self.get_nodeset())
|
|
||||||
self.set_nodeset_index(1)
|
|
||||||
self.store_in_configuration()
|
|
||||||
redraw = True
|
|
||||||
elif bi == self.B_SPLIT:
|
|
||||||
self.toggle_split()
|
|
||||||
redraw = True
|
|
||||||
elif plot_rect.collidepoint(pos) and \
|
|
||||||
not self.collide_markers(pos):
|
|
||||||
xp, yp = pos[0] - plot_rect.left, pos[1] - plot_rect.top
|
|
||||||
self.get_nodeset().add_node(
|
|
||||||
self.get_function_coordinates(xp, yp))
|
|
||||||
self.store_in_configuration()
|
|
||||||
redraw = True
|
|
||||||
elif event.button == 3:
|
|
||||||
pos = event.pos
|
|
||||||
if nodeset_rect.collidepoint(pos):
|
|
||||||
self.set_nodeset_index(-1)
|
|
||||||
redraw = True
|
|
||||||
elif plot_rect.collidepoint(pos):
|
|
||||||
marker = self.collide_markers(pos)
|
|
||||||
if marker:
|
|
||||||
self.get_nodeset().remove(marker.node)
|
|
||||||
self.store_in_configuration()
|
|
||||||
redraw = True
|
|
||||||
elif self.active and self.prompt.active and \
|
|
||||||
not self.prompt.rect.collidepoint(event.pos):
|
|
||||||
self.prompt.deactivate()
|
|
||||||
redraw = True
|
|
||||||
if redraw:
|
|
||||||
self.set_y_range()
|
|
||||||
self.set_markers()
|
|
||||||
self.draw()
|
|
||||||
|
|
||||||
def resize_nodeset(self, text, index):
|
|
||||||
result = match("^\s*(-{,1}\d*\.{,1}\d*)\s+(-{,1}\d*\.{,1}\d*)\s*$",
|
|
||||||
text)
|
|
||||||
if result:
|
|
||||||
try:
|
|
||||||
nodeset = self.get_nodeset()
|
|
||||||
x, y = map(float, result.group(1, 2))
|
|
||||||
if (index == -1 and x > nodeset[0].x) or \
|
|
||||||
(index == 0 and x < nodeset[-1].x):
|
|
||||||
nodeset[index].y = y
|
|
||||||
if index == -1:
|
|
||||||
nodeset.resize(nodeset[0].x, x - nodeset[0].x)
|
|
||||||
else:
|
|
||||||
nodeset.resize(x, nodeset[-1].x - x)
|
|
||||||
self.store_in_configuration()
|
|
||||||
self.set_y_range()
|
|
||||||
self.set_axis_labels()
|
|
||||||
self.set_markers()
|
|
||||||
self.draw()
|
|
||||||
return True
|
|
||||||
except ValueError:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def collide_buttons(self, pos):
|
|
||||||
for ii, button in enumerate(self.buttons):
|
|
||||||
if button.location.collidepoint(pos):
|
|
||||||
return ii
|
|
||||||
|
|
||||||
def store_in_configuration(self):
|
|
||||||
config = self.get_configuration()
|
|
||||||
section = "interpolate"
|
|
||||||
config.clear_section(section)
|
|
||||||
for nodeset in self.parent:
|
|
||||||
code = "L" if nodeset.interpolation_method == Nodeset.LINEAR else \
|
|
||||||
"C"
|
|
||||||
for ii, node in enumerate(nodeset):
|
|
||||||
if ii > 0:
|
|
||||||
code += ","
|
|
||||||
code += " {0} {1}".format(*map(self.get_formatted_measure,
|
|
||||||
node))
|
|
||||||
if not config.has_section(section):
|
|
||||||
config.add_section(section)
|
|
||||||
config.set(section, nodeset.name, code)
|
|
||||||
|
|
||||||
def toggle_split(self):
|
|
||||||
self.split += 1
|
|
||||||
if self.split > self.S_RIGHT:
|
|
||||||
self.split = self.S_NONE
|
|
||||||
self.buttons[self.B_SPLIT].set_frame(["Split: No", "Split: L",
|
|
||||||
"Split: R"][self.split])
|
|
||||||
|
|
||||||
def add_nodeset(self, name):
|
|
||||||
nodeset = self.get_nodeset()
|
|
||||||
self.set_nodeset_index(index=self.parent.add_nodeset(\
|
|
||||||
name, nodeset, nodeset.interpolation_method))
|
|
||||||
self.store_in_configuration()
|
|
||||||
self.draw()
|
|
||||||
return True
|
|
||||||
|
|
||||||
def collide_markers(self, pos):
|
|
||||||
for marker in self.markers:
|
|
||||||
if marker.location.collidepoint(pos):
|
|
||||||
return marker
|
|
||||||
|
|
||||||
def set_markers(self):
|
|
||||||
self.markers = markers = []
|
|
||||||
for node in self.get_nodeset()[1:-1]:
|
|
||||||
markers.append(Marker(self, node))
|
|
||||||
markers[-1].location.center = self.get_plot_coordinates(*node)
|
|
||||||
|
|
||||||
def get_plot_coordinates(self, x=0, y=0):
|
|
||||||
nodeset = self.get_nodeset()
|
|
||||||
x_min, x_max, (y_min, y_max) = nodeset[0].x, nodeset[-1].x, self.y_range
|
|
||||||
x_ratio = float(x - x_min) / (x_max - x_min)
|
|
||||||
rect = self.plot_rect
|
|
||||||
xp = x_ratio * (rect.right - rect.left) + rect.left
|
|
||||||
y_ratio = float(y - y_min) / (y_max - y_min)
|
|
||||||
yp = rect.bottom - y_ratio * (rect.bottom - rect.top)
|
|
||||||
return xp, yp
|
|
||||||
|
|
||||||
def draw(self):
|
|
||||||
display_surface = self.display_surface
|
|
||||||
display_surface.blit(self.background, (0, 0))
|
|
||||||
display_surface.blit(self.nodeset_label, self.nodeset_label_rect)
|
|
||||||
self.draw_axes()
|
|
||||||
self.draw_function()
|
|
||||||
self.draw_markers()
|
|
||||||
self.draw_buttons()
|
|
||||||
|
|
||||||
def draw_axes(self):
|
|
||||||
display_surface = self.display_surface
|
|
||||||
for xl, yl in self.axis_labels:
|
|
||||||
display_surface.blit(*xl)
|
|
||||||
display_surface.blit(*yl)
|
|
||||||
|
|
||||||
def draw_function(self):
|
|
||||||
rect = self.plot_rect
|
|
||||||
surface = self.display_surface
|
|
||||||
nodeset = self.get_nodeset()
|
|
||||||
step = 1
|
|
||||||
for x in xrange(rect.left, rect.right + step, step):
|
|
||||||
ii = x - rect.left
|
|
||||||
fx = nodeset.get_y(self.get_function_coordinates(ii)[0])
|
|
||||||
y = self.get_plot_coordinates(y=fx)[1]
|
|
||||||
if ii > 0:
|
|
||||||
aaline(surface, self.curve_color, (x - step, last_y), (x, y))
|
|
||||||
last_y = y
|
|
||||||
|
|
||||||
def draw_markers(self):
|
|
||||||
for marker in self.markers:
|
|
||||||
marker.update()
|
|
||||||
|
|
||||||
def draw_buttons(self):
|
|
||||||
for button in self.buttons:
|
|
||||||
button.update()
|
|
||||||
|
|
||||||
def respond_to_key(self, event):
|
|
||||||
if self.prompt.active:
|
|
||||||
prompt = self.prompt
|
|
||||||
if event.key == K_RETURN:
|
|
||||||
if prompt.callback[0](prompt.text, *prompt.callback[1]):
|
|
||||||
prompt.deactivate()
|
|
||||||
elif event.key == K_BACKSPACE:
|
|
||||||
prompt.text = prompt.text[:-1]
|
|
||||||
prompt.update()
|
|
||||||
prompt.draw_text()
|
|
||||||
elif (event.unicode.isalnum() or event.unicode.isspace() or \
|
|
||||||
event.unicode in (".", "-", "_")) and len(prompt.text) < \
|
|
||||||
prompt.character_limit:
|
|
||||||
prompt.text += event.unicode
|
|
||||||
prompt.update()
|
|
||||||
prompt.draw_text()
|
|
||||||
|
|
||||||
def show_success_indicator(self):
|
|
||||||
self.draw()
|
|
||||||
if self.success_indicator_blink_count > 1:
|
|
||||||
self.success_indicator_blink_count = 0
|
|
||||||
self.halt(self.show_success_indicator)
|
|
||||||
else:
|
|
||||||
if self.success_indicator_active:
|
|
||||||
self.display_surface.blit(self.success_indicator,
|
|
||||||
self.success_indicator_rect)
|
|
||||||
if self.success_indicator_active:
|
|
||||||
self.success_indicator_blink_count += 1
|
|
||||||
self.success_indicator_active = not self.success_indicator_active
|
|
||||||
|
|
||||||
def save_temporary_file(self):
|
|
||||||
fp = self.temporary_file
|
|
||||||
fp.seek(0)
|
|
||||||
fp.truncate()
|
|
||||||
self.get_configuration().write(fp)
|
|
||||||
|
|
||||||
def rearrange(self):
|
|
||||||
self.set_background()
|
|
||||||
self.set_success_indicator()
|
|
||||||
self.set_plot_rect()
|
|
||||||
self.set_markers()
|
|
||||||
self.set_nodeset_label()
|
|
||||||
self.set_axis_labels()
|
|
||||||
self.set_buttons()
|
|
||||||
self.prompt.reset()
|
|
||||||
|
|
||||||
class Marker(Sprite):
|
|
||||||
|
|
||||||
def __init__(self, parent, node):
|
|
||||||
Sprite.__init__(self, parent)
|
|
||||||
self.add_frame(parent.marker_frame)
|
|
||||||
self.node = node
|
|
||||||
|
|
||||||
|
|
||||||
class Button(Sprite):
|
|
||||||
|
|
||||||
def __init__(self, parent, text, left):
|
|
||||||
Sprite.__init__(self, parent)
|
|
||||||
self.set_frame(text)
|
|
||||||
self.location.bottomleft = left, \
|
|
||||||
self.get_display_surface().get_rect().bottom
|
|
||||||
|
|
||||||
def set_frame(self, text):
|
|
||||||
self.clear_frames()
|
|
||||||
self.add_frame(self.parent.font.render(text, True, (0, 0, 0),
|
|
||||||
(255, 255, 255)))
|
|
||||||
|
|
||||||
|
|
||||||
class Prompt(Sprite):
|
|
||||||
|
|
||||||
def __init__(self, parent):
|
|
||||||
Sprite.__init__(self, parent)
|
|
||||||
self.load_configuration()
|
|
||||||
self.font = Font(None, self.text_size)
|
|
||||||
self.reset()
|
|
||||||
self.deactivate()
|
|
||||||
|
|
||||||
def deactivate(self):
|
|
||||||
self.active = False
|
|
||||||
|
|
||||||
def load_configuration(self):
|
|
||||||
config = self.get_configuration("interpolator-gui")
|
|
||||||
self.size = config["prompt-size"]
|
|
||||||
self.border_color = config["prompt-border-color"]
|
|
||||||
self.border_width = config["prompt-border-width"]
|
|
||||||
self.character_limit = config["prompt-character-limit"]
|
|
||||||
self.text_size = config["prompt-text-size"]
|
|
||||||
|
|
||||||
def reset(self):
|
|
||||||
self.set_frame()
|
|
||||||
self.place()
|
|
||||||
|
|
||||||
def set_frame(self):
|
|
||||||
self.clear_frames()
|
|
||||||
surface = Surface(self.size)
|
|
||||||
self.add_frame(surface)
|
|
||||||
surface.fill(self.border_color)
|
|
||||||
width = self.border_width * 2
|
|
||||||
surface.fill((0, 0, 0), surface.get_rect().inflate(-width, -width))
|
|
||||||
|
|
||||||
def place(self):
|
|
||||||
self.location.center = self.display_surface.get_rect().center
|
|
||||||
|
|
||||||
def activate(self, text, callback, *args):
|
|
||||||
self.active = True
|
|
||||||
self.text = str(text)
|
|
||||||
self.callback = callback, args
|
|
||||||
self.update()
|
|
||||||
self.draw_text()
|
|
||||||
|
|
||||||
def draw_text(self):
|
|
||||||
surface = self.font.render(self.text, True, (255, 255, 255), (0, 0, 0))
|
|
||||||
rect = surface.get_rect()
|
|
||||||
rect.center = self.location.center
|
|
||||||
self.display_surface.blit(surface, rect)
|
|
|
@ -1,108 +0,0 @@
|
||||||
from pygame import display
|
|
||||||
from pygame.font import Font
|
|
||||||
from pygame.time import get_ticks, wait
|
|
||||||
|
|
||||||
from GameChild import GameChild
|
|
||||||
|
|
||||||
class Mainloop(GameChild):
|
|
||||||
|
|
||||||
def __init__(self, parent):
|
|
||||||
GameChild.__init__(self, parent)
|
|
||||||
self.overflow = 0
|
|
||||||
self.frame_count = 1
|
|
||||||
self.actual_frame_duration = 0
|
|
||||||
self.frames_this_second = 0
|
|
||||||
self.last_framerate_display = 0
|
|
||||||
self.load_configuration()
|
|
||||||
self.init_framerate_display()
|
|
||||||
self.last_ticks = get_ticks()
|
|
||||||
self.stopping = False
|
|
||||||
|
|
||||||
def load_configuration(self):
|
|
||||||
config = self.get_configuration("display")
|
|
||||||
self.target_frame_duration = config["frame-duration"]
|
|
||||||
self.wait_duration = config["wait-duration"]
|
|
||||||
self.skip_frames = config["skip-frames"]
|
|
||||||
self.show_framerate = config["show-framerate"]
|
|
||||||
self.framerate_text_size = config["framerate-text-size"]
|
|
||||||
self.framerate_text_color = config["framerate-text-color"]
|
|
||||||
self.framerate_text_background = config["framerate-text-background"]
|
|
||||||
self.framerate_display_flag = config["framerate-display-flag"]
|
|
||||||
|
|
||||||
def init_framerate_display(self):
|
|
||||||
if self.framerate_display_active():
|
|
||||||
screen = self.get_screen()
|
|
||||||
self.last_framerate_count = 0
|
|
||||||
self.framerate_topright = screen.get_rect().topright
|
|
||||||
self.display_surface = screen
|
|
||||||
self.font = Font(None, self.framerate_text_size)
|
|
||||||
self.font.set_bold(True)
|
|
||||||
self.render_framerate()
|
|
||||||
|
|
||||||
def framerate_display_active(self):
|
|
||||||
return self.check_command_line(self.framerate_display_flag) or \
|
|
||||||
self.show_framerate
|
|
||||||
|
|
||||||
def render_framerate(self):
|
|
||||||
text = self.font.render(str(self.last_framerate_count), False,
|
|
||||||
self.framerate_text_color,
|
|
||||||
self.framerate_text_background)
|
|
||||||
rect = text.get_rect()
|
|
||||||
rect.topright = self.framerate_topright
|
|
||||||
self.framerate_text = text
|
|
||||||
self.framerate_text_rect = rect
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
while not self.stopping:
|
|
||||||
self.advance_frame()
|
|
||||||
self.update_frame_duration()
|
|
||||||
self.update_overflow()
|
|
||||||
self.stopping = False
|
|
||||||
|
|
||||||
def advance_frame(self):
|
|
||||||
refresh = False
|
|
||||||
while self.frame_count > 0:
|
|
||||||
refresh = True
|
|
||||||
self.parent.frame()
|
|
||||||
if self.framerate_display_active():
|
|
||||||
self.update_framerate()
|
|
||||||
self.frame_count -= 1
|
|
||||||
if not self.skip_frames:
|
|
||||||
break
|
|
||||||
if refresh:
|
|
||||||
display.update()
|
|
||||||
|
|
||||||
def update_frame_duration(self):
|
|
||||||
last_ticks = self.last_ticks
|
|
||||||
actual_frame_duration = get_ticks() - last_ticks
|
|
||||||
last_ticks = get_ticks()
|
|
||||||
while actual_frame_duration < self.target_frame_duration:
|
|
||||||
wait(self.wait_duration)
|
|
||||||
actual_frame_duration += get_ticks() - last_ticks
|
|
||||||
last_ticks = get_ticks()
|
|
||||||
self.actual_frame_duration = actual_frame_duration
|
|
||||||
self.last_ticks = last_ticks
|
|
||||||
|
|
||||||
def update_overflow(self):
|
|
||||||
self.frame_count = 1
|
|
||||||
target_frame_duration = self.target_frame_duration
|
|
||||||
overflow = self.overflow
|
|
||||||
overflow += self.actual_frame_duration - target_frame_duration
|
|
||||||
while overflow > target_frame_duration:
|
|
||||||
self.frame_count += 1
|
|
||||||
overflow -= target_frame_duration
|
|
||||||
overflow = self.overflow
|
|
||||||
|
|
||||||
def update_framerate(self):
|
|
||||||
count = self.frames_this_second + 1
|
|
||||||
if get_ticks() - self.last_framerate_display > 1000:
|
|
||||||
if count != self.last_framerate_count:
|
|
||||||
self.last_framerate_count = count
|
|
||||||
self.render_framerate()
|
|
||||||
self.last_framerate_display = get_ticks()
|
|
||||||
count = 0
|
|
||||||
self.display_surface.blit(self.framerate_text, self.framerate_text_rect)
|
|
||||||
self.frames_this_second = count
|
|
||||||
|
|
||||||
def stop(self):
|
|
||||||
self.stopping = True
|
|
|
@ -1,26 +0,0 @@
|
||||||
import cProfile
|
|
||||||
from time import strftime
|
|
||||||
from os import mkdir
|
|
||||||
from os.path import join, exists
|
|
||||||
|
|
||||||
from GameChild import GameChild
|
|
||||||
|
|
||||||
class Profile(cProfile.Profile, GameChild):
|
|
||||||
|
|
||||||
def __init__(self, parent):
|
|
||||||
GameChild.__init__(self, parent)
|
|
||||||
cProfile.Profile.__init__(self)
|
|
||||||
if self.requested():
|
|
||||||
self.enable()
|
|
||||||
|
|
||||||
def requested(self):
|
|
||||||
return self.check_command_line("p")
|
|
||||||
|
|
||||||
def end(self):
|
|
||||||
if self.requested():
|
|
||||||
root = "stat/"
|
|
||||||
if not exists(root):
|
|
||||||
mkdir(root)
|
|
||||||
self.disable()
|
|
||||||
self.create_stats()
|
|
||||||
self.dump_stats(join(root, strftime("%Y%m%d-%H%M_%S.stat")))
|
|
|
@ -1,41 +0,0 @@
|
||||||
from os import makedirs
|
|
||||||
from os.path import exists, join
|
|
||||||
from sys import exc_info
|
|
||||||
from time import strftime
|
|
||||||
|
|
||||||
from pygame import image
|
|
||||||
|
|
||||||
from GameChild import *
|
|
||||||
from Input import *
|
|
||||||
|
|
||||||
class ScreenGrabber(GameChild):
|
|
||||||
|
|
||||||
def __init__(self, game):
|
|
||||||
GameChild.__init__(self, game)
|
|
||||||
self.delegate = self.get_delegate()
|
|
||||||
self.load_configuration()
|
|
||||||
self.subscribe(self.save_display)
|
|
||||||
|
|
||||||
def load_configuration(self):
|
|
||||||
config = self.get_configuration("screen-captures")
|
|
||||||
self.save_path = config["path"]
|
|
||||||
self.file_name_format = config["file-name-format"]
|
|
||||||
self.file_extension = config["file-extension"]
|
|
||||||
|
|
||||||
def save_display(self, event):
|
|
||||||
if self.delegate.compare(event, "capture-screen"):
|
|
||||||
directory = self.save_path
|
|
||||||
try:
|
|
||||||
if not exists(directory):
|
|
||||||
makedirs(directory)
|
|
||||||
name = self.build_name()
|
|
||||||
path = join(directory, name)
|
|
||||||
capture = image.save(self.get_screen(), path)
|
|
||||||
self.print_debug("Saved screen capture to %s" % (path))
|
|
||||||
except:
|
|
||||||
self.print_debug("Couldn't save screen capture to %s, %s" %\
|
|
||||||
(directory, exc_info()[1]))
|
|
||||||
|
|
||||||
def build_name(self):
|
|
||||||
return "{0}.{1}".format(strftime(self.file_name_format),
|
|
||||||
self.file_extension)
|
|
|
@ -1,131 +0,0 @@
|
||||||
from os import walk, remove
|
|
||||||
from os.path import sep, join, exists, normpath
|
|
||||||
from re import findall, sub
|
|
||||||
from distutils.core import setup
|
|
||||||
from distutils.command.install import install
|
|
||||||
from pprint import pprint
|
|
||||||
from fileinput import FileInput
|
|
||||||
from re import sub, match
|
|
||||||
|
|
||||||
from Configuration import *
|
|
||||||
|
|
||||||
class Setup:
|
|
||||||
|
|
||||||
config = Configuration()
|
|
||||||
manifest_path = "MANIFEST"
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def remove_old_mainfest(self):
|
|
||||||
path = self.manifest_path
|
|
||||||
if exists(path):
|
|
||||||
remove(path)
|
|
||||||
|
|
||||||
def build_package_list(self):
|
|
||||||
packages = []
|
|
||||||
config = self.config.get_section("setup")
|
|
||||||
locations = [config["package-root"]] + config["additional-packages"]
|
|
||||||
for location in locations:
|
|
||||||
if exists(location):
|
|
||||||
for root, dirs, files in walk(location, followlinks=True):
|
|
||||||
packages.append(root.replace(sep, "."))
|
|
||||||
return packages
|
|
||||||
|
|
||||||
def build_data_map(self):
|
|
||||||
include = []
|
|
||||||
config = self.config.get_section("setup")
|
|
||||||
exclude = map(normpath, config["data-exclude"])
|
|
||||||
for root, dirs, files in walk("."):
|
|
||||||
dirs = self.remove_excluded(dirs, root, exclude)
|
|
||||||
files = [join(root, f) for f in self.remove_excluded(files, root,
|
|
||||||
exclude)]
|
|
||||||
if files:
|
|
||||||
include.append((normpath(join(config["installation-path"],
|
|
||||||
root)), files))
|
|
||||||
return include
|
|
||||||
|
|
||||||
def remove_excluded(self, paths, root, exclude):
|
|
||||||
removal = []
|
|
||||||
for path in paths:
|
|
||||||
if normpath(join(root, path)) in exclude:
|
|
||||||
removal.append(path)
|
|
||||||
for path in removal:
|
|
||||||
paths.remove(path)
|
|
||||||
return paths
|
|
||||||
|
|
||||||
def translate_title(self):
|
|
||||||
config = self.config.get_section("setup")
|
|
||||||
title = config["title"].replace(" ", config["whitespace-placeholder"])
|
|
||||||
return sub("[^\w-]", config["special-char-placeholder"], title)
|
|
||||||
|
|
||||||
def build_description(self):
|
|
||||||
description = ""
|
|
||||||
path = self.config.get("setup", "description-file")
|
|
||||||
if exists(path):
|
|
||||||
description = "\n%s\n%s\n%s" % (file(path).read(),
|
|
||||||
"Changelog\n=========",
|
|
||||||
self.translate_changelog())
|
|
||||||
return description
|
|
||||||
|
|
||||||
def translate_changelog(self):
|
|
||||||
translation = ""
|
|
||||||
path = self.config.get("setup", "changelog")
|
|
||||||
if exists(path):
|
|
||||||
lines = file(path).readlines()
|
|
||||||
package_name = lines[0].split()[0]
|
|
||||||
for line in lines:
|
|
||||||
line = line.strip()
|
|
||||||
if line.startswith(package_name):
|
|
||||||
version = findall("\((.*)\)", line)[0]
|
|
||||||
translation += "\n%s\n%s\n" % (version, "-" * len(version))
|
|
||||||
elif line and not line.startswith("--"):
|
|
||||||
if line.startswith("*"):
|
|
||||||
translation += line + "\n"
|
|
||||||
else:
|
|
||||||
translation += " " + line + "\n"
|
|
||||||
return translation
|
|
||||||
|
|
||||||
def setup(self, windows=[], options={}):
|
|
||||||
print "running setup..."
|
|
||||||
self.remove_old_mainfest()
|
|
||||||
config = self.config.get_section("setup")
|
|
||||||
scripts = []
|
|
||||||
if config["init-script"]:
|
|
||||||
scripts.append(config["init-script"])
|
|
||||||
setup(cmdclass={"install": insert_resource_path},
|
|
||||||
name=self.translate_title(),
|
|
||||||
packages=self.build_package_list(),
|
|
||||||
scripts=scripts,
|
|
||||||
data_files=self.build_data_map(),
|
|
||||||
requires=config["requirements"],
|
|
||||||
version=config["version"],
|
|
||||||
description=config["summary"],
|
|
||||||
classifiers=config["classifiers"],
|
|
||||||
long_description=self.build_description(),
|
|
||||||
license=config["license"],
|
|
||||||
platforms=config["platforms"],
|
|
||||||
author=config["contact-name"],
|
|
||||||
author_email=config["contact-email"],
|
|
||||||
url=config["url"],
|
|
||||||
windows=windows,
|
|
||||||
options=options)
|
|
||||||
|
|
||||||
|
|
||||||
class insert_resource_path(install):
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
install.run(self)
|
|
||||||
self.edit_game_object_file()
|
|
||||||
|
|
||||||
def edit_game_object_file(self):
|
|
||||||
config = Configuration().get_section("setup")
|
|
||||||
for path in self.get_outputs():
|
|
||||||
if path.endswith(config["main-object"]):
|
|
||||||
for line in FileInput(path, inplace=True):
|
|
||||||
pattern = "^ *{0} *=.*".\
|
|
||||||
format(config["resource-path-identifier"])
|
|
||||||
if match(pattern, line):
|
|
||||||
line = sub("=.*$", "= \"{0}\"".\
|
|
||||||
format(config["installation-path"]), line)
|
|
||||||
print line.strip("\n")
|
|
|
@ -1,69 +0,0 @@
|
||||||
from os import makedirs, walk, sep, remove
|
|
||||||
from os.path import join, dirname, basename, exists
|
|
||||||
from shutil import rmtree, copy, rmtree
|
|
||||||
from itertools import chain
|
|
||||||
from zipfile import ZipFile
|
|
||||||
|
|
||||||
import py2exe
|
|
||||||
|
|
||||||
from Setup import Setup
|
|
||||||
|
|
||||||
class SetupWin(Setup):
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
Setup.__init__(self)
|
|
||||||
self.replace_isSystemDLL()
|
|
||||||
|
|
||||||
def replace_isSystemDLL(self):
|
|
||||||
origIsSystemDLL = py2exe.build_exe.isSystemDLL
|
|
||||||
def isSystemDLL(pathname):
|
|
||||||
if basename(pathname).lower() in ("libogg-0.dll", "sdl_ttf.dll"):
|
|
||||||
return 0
|
|
||||||
return origIsSystemDLL(pathname)
|
|
||||||
py2exe.build_exe.isSystemDLL = isSystemDLL
|
|
||||||
|
|
||||||
def setup(self):
|
|
||||||
config = self.config.get_section("setup")
|
|
||||||
windows = [{}]
|
|
||||||
if config["init-script"]:
|
|
||||||
windows[0]["script"] = config["init-script"]
|
|
||||||
if config["windows-icon-path"]:
|
|
||||||
windows[0]["icon-resources"] = [(1, config["windows-icon-path"])]
|
|
||||||
Setup.setup(self, windows,
|
|
||||||
{"py2exe": {"packages": self.build_package_list(),
|
|
||||||
"dist_dir": config["windows-dist-path"]}})
|
|
||||||
rmtree("build")
|
|
||||||
self.copy_data_files()
|
|
||||||
self.create_archive()
|
|
||||||
|
|
||||||
def copy_data_files(self):
|
|
||||||
root = self.config.get("setup", "windows-dist-path")
|
|
||||||
for path in chain(*zip(*self.build_data_map())[1]):
|
|
||||||
dest = join(root, dirname(path))
|
|
||||||
if not exists(dest):
|
|
||||||
makedirs(dest)
|
|
||||||
copy(path, dest)
|
|
||||||
self.include_readme(root)
|
|
||||||
|
|
||||||
def include_readme(self, root):
|
|
||||||
name = "README"
|
|
||||||
if exists(name):
|
|
||||||
readme = open(name, "r")
|
|
||||||
reformatted = open(join(root, name + ".txt"), "w")
|
|
||||||
for line in open(name, "r"):
|
|
||||||
reformatted.write(line.rstrip() + "\r\n")
|
|
||||||
|
|
||||||
def create_archive(self):
|
|
||||||
config = self.config.get_section("setup")
|
|
||||||
title = self.translate_title() + "-" + config["version"] + "-win"
|
|
||||||
archive_name = title + ".zip"
|
|
||||||
archive = ZipFile(archive_name, "w")
|
|
||||||
destination = config["windows-dist-path"]
|
|
||||||
for root, dirs, names in walk(destination):
|
|
||||||
for name in names:
|
|
||||||
path = join(root, name)
|
|
||||||
archive.write(path, path.replace(destination, title + sep))
|
|
||||||
archive.close()
|
|
||||||
copy(archive_name, "dist")
|
|
||||||
remove(archive_name)
|
|
||||||
rmtree(destination)
|
|
|
@ -1,359 +0,0 @@
|
||||||
from os import listdir
|
|
||||||
from os.path import isfile, join
|
|
||||||
from sys import exc_info, stdout
|
|
||||||
from glob import glob
|
|
||||||
from traceback import print_exc, print_stack
|
|
||||||
|
|
||||||
from pygame import Color, Rect, Surface
|
|
||||||
from pygame.image import load
|
|
||||||
from pygame.transform import flip
|
|
||||||
from pygame.locals import *
|
|
||||||
|
|
||||||
from Animation import Animation
|
|
||||||
from Vector import Vector
|
|
||||||
|
|
||||||
class Sprite(Animation):
|
|
||||||
|
|
||||||
def __init__(self, parent, framerate=None):
|
|
||||||
Animation.__init__(self, parent, self.shift_frame, framerate)
|
|
||||||
self.frames = []
|
|
||||||
self.mirrored = False
|
|
||||||
self.hidden = False
|
|
||||||
self.alpha = 255
|
|
||||||
self.locations = [Location(self)]
|
|
||||||
self.framesets = [Frameset(self, framerate=framerate)]
|
|
||||||
self.set_frameset(0)
|
|
||||||
self.motion_overflow = Vector()
|
|
||||||
self.display_surface = self.get_display_surface()
|
|
||||||
|
|
||||||
def __getattr__(self, name):
|
|
||||||
if name in ("location", "rect"):
|
|
||||||
return self.locations[0]
|
|
||||||
if hasattr(Animation, "__getattr__"):
|
|
||||||
return Animation.__getattr__(self, name)
|
|
||||||
raise AttributeError, name
|
|
||||||
|
|
||||||
def set_frameset(self, identifier):
|
|
||||||
if isinstance(identifier, str):
|
|
||||||
for ii, frameset in enumerate(self.framesets):
|
|
||||||
if frameset.name == identifier:
|
|
||||||
identifier = ii
|
|
||||||
break
|
|
||||||
self.frameset_index = identifier
|
|
||||||
self.register_interval()
|
|
||||||
self.update_location_size()
|
|
||||||
if self.get_current_frameset().length() > 1:
|
|
||||||
self.play()
|
|
||||||
|
|
||||||
def register_interval(self):
|
|
||||||
self.register(self.shift_frame,
|
|
||||||
interval=self.get_current_frameset().framerate)
|
|
||||||
|
|
||||||
def get_current_frameset(self):
|
|
||||||
return self.framesets[self.frameset_index]
|
|
||||||
|
|
||||||
def update_location_size(self):
|
|
||||||
size = self.get_current_frameset().rect.size
|
|
||||||
for location in self.locations:
|
|
||||||
location.size = size
|
|
||||||
location.fader.init_surface()
|
|
||||||
|
|
||||||
def set_framerate(self, framerate):
|
|
||||||
self.get_current_frameset().set_framerate(framerate)
|
|
||||||
self.register_interval()
|
|
||||||
|
|
||||||
def load_from_path(self, path, transparency=False, ppa=True, key=None,
|
|
||||||
extension=None, omit=False):
|
|
||||||
if isfile(path):
|
|
||||||
paths = [path]
|
|
||||||
else:
|
|
||||||
if extension:
|
|
||||||
paths = sorted(glob(join(path, "*." + extension)))
|
|
||||||
else:
|
|
||||||
paths = [join(path, name) for name in sorted(listdir(path))]
|
|
||||||
for path in paths:
|
|
||||||
img = load(path)
|
|
||||||
if transparency:
|
|
||||||
if ppa:
|
|
||||||
frame = img.convert_alpha()
|
|
||||||
else:
|
|
||||||
frame = self.fill_colorkey(img, key)
|
|
||||||
else:
|
|
||||||
frame = img.convert()
|
|
||||||
self.add_frame(frame, omit)
|
|
||||||
|
|
||||||
def fill_colorkey(self, img, key=None):
|
|
||||||
if not key:
|
|
||||||
key = (255, 0, 255)
|
|
||||||
img = img.convert_alpha()
|
|
||||||
frame = Surface(img.get_size())
|
|
||||||
frame.fill(key)
|
|
||||||
frame.set_colorkey(key)
|
|
||||||
frame.blit(img, (0, 0))
|
|
||||||
return frame
|
|
||||||
|
|
||||||
def add_frame(self, frame, omit=False):
|
|
||||||
self.frames.append(frame)
|
|
||||||
frame.set_alpha(self.alpha)
|
|
||||||
if not omit:
|
|
||||||
frameset = self.get_current_frameset()
|
|
||||||
frameset.add_index(self.frames.index(frame))
|
|
||||||
self.update_location_size()
|
|
||||||
if frameset.length() > 1:
|
|
||||||
self.play()
|
|
||||||
|
|
||||||
def shift_frame(self):
|
|
||||||
self.get_current_frameset().shift()
|
|
||||||
|
|
||||||
def get_current_frame(self):
|
|
||||||
return self.frames[self.get_current_frameset().get_current_id()]
|
|
||||||
|
|
||||||
def move(self, dx=0, dy=0):
|
|
||||||
for location in self.locations:
|
|
||||||
location.move_ip(dx, dy)
|
|
||||||
|
|
||||||
def reset_motion_overflow(self):
|
|
||||||
for location in self.locations:
|
|
||||||
location.reset_motion_overflow()
|
|
||||||
|
|
||||||
def collide(self, other):
|
|
||||||
if not isinstance(other, Rect):
|
|
||||||
other = other.rect
|
|
||||||
for location in self.locations:
|
|
||||||
if location.colliderect(other):
|
|
||||||
return location
|
|
||||||
|
|
||||||
def mirror(self):
|
|
||||||
frames = self.frames
|
|
||||||
for ii, frame in enumerate(frames):
|
|
||||||
frames[ii] = flip(frame, True, False)
|
|
||||||
self.mirrored = not self.mirrored
|
|
||||||
|
|
||||||
def clear_frames(self):
|
|
||||||
self.frames = []
|
|
||||||
for frameset in self.framesets:
|
|
||||||
frameset.order = []
|
|
||||||
frameset.reset()
|
|
||||||
frameset.measure_rect()
|
|
||||||
|
|
||||||
def add_location(self, topleft=None, offset=(0, 0), count=1, base=0):
|
|
||||||
if topleft is not None:
|
|
||||||
for ii in xrange(count):
|
|
||||||
self.locations.append(Location(
|
|
||||||
self, Rect(topleft, self.locations[0].size)))
|
|
||||||
else:
|
|
||||||
base = self.locations[base]
|
|
||||||
current_offset = list(offset)
|
|
||||||
for ii in xrange(count):
|
|
||||||
self.locations.append(Location(self,
|
|
||||||
base.move(*current_offset)))
|
|
||||||
current_offset[0] += offset[0]
|
|
||||||
current_offset[1] += offset[1]
|
|
||||||
return self.locations[-1]
|
|
||||||
|
|
||||||
def fade(self, length=0, out=None, index=None):
|
|
||||||
if index is None:
|
|
||||||
for location in self.locations:
|
|
||||||
location.fader.start(length, out)
|
|
||||||
else:
|
|
||||||
self.locations[index].fader.start(length, out)
|
|
||||||
|
|
||||||
def set_alpha(self, alpha):
|
|
||||||
self.alpha = alpha
|
|
||||||
for frame in self.frames:
|
|
||||||
frame.set_alpha(alpha)
|
|
||||||
for location in self.locations:
|
|
||||||
location.fader.set_alpha()
|
|
||||||
|
|
||||||
def add_frameset(self, order, framerate=None, name=None):
|
|
||||||
frameset = Frameset(self, order, framerate, name)
|
|
||||||
self.framesets.append(frameset)
|
|
||||||
return frameset
|
|
||||||
|
|
||||||
def hide(self):
|
|
||||||
self.hidden = True
|
|
||||||
|
|
||||||
def unhide(self):
|
|
||||||
self.hidden = False
|
|
||||||
|
|
||||||
def remove_locations(self, location=None):
|
|
||||||
if location:
|
|
||||||
self.locations.remove(location)
|
|
||||||
else:
|
|
||||||
self.locations = self.locations[:1]
|
|
||||||
|
|
||||||
def reverse(self, frameset=None):
|
|
||||||
if frameset:
|
|
||||||
frameset.reverse()
|
|
||||||
else:
|
|
||||||
for frameset in self.framesets:
|
|
||||||
frameset.reverse()
|
|
||||||
|
|
||||||
def update(self, flags=0):
|
|
||||||
Animation.update(self)
|
|
||||||
self.draw(flags)
|
|
||||||
|
|
||||||
def draw(self, flags=0):
|
|
||||||
for location in self.locations:
|
|
||||||
location.fader.draw(flags)
|
|
||||||
|
|
||||||
|
|
||||||
class Location(Rect):
|
|
||||||
|
|
||||||
def __init__(self, sprite, rect=(0, 0, 0, 0)):
|
|
||||||
self.sprite = sprite
|
|
||||||
Rect.__init__(self, rect)
|
|
||||||
self.motion_overflow = Vector()
|
|
||||||
self.fader = Fader(self)
|
|
||||||
|
|
||||||
def move_ip(self, dx, dy):
|
|
||||||
if isinstance(dx, float) or isinstance(dy, float):
|
|
||||||
excess = self.update_motion_overflow(dx, dy)
|
|
||||||
Rect.move_ip(self, int(dx) + excess[0], int(dy) + excess[1])
|
|
||||||
else:
|
|
||||||
Rect.move_ip(self, dx, dy)
|
|
||||||
|
|
||||||
def update_motion_overflow(self, dx, dy):
|
|
||||||
overflow = self.motion_overflow
|
|
||||||
overflow.move(dx - int(dx), dy - int(dy))
|
|
||||||
excess = map(int, overflow)
|
|
||||||
overflow[0] -= int(overflow[0])
|
|
||||||
overflow[1] -= int(overflow[1])
|
|
||||||
return excess
|
|
||||||
|
|
||||||
def reset_motion_overflow(self):
|
|
||||||
self.motion_overflow.place_at_origin()
|
|
||||||
|
|
||||||
|
|
||||||
class Fader(Surface):
|
|
||||||
|
|
||||||
def __init__(self, location):
|
|
||||||
self.location = location
|
|
||||||
self.time_filter = location.sprite.get_game().time_filter
|
|
||||||
self.reset()
|
|
||||||
|
|
||||||
def reset(self):
|
|
||||||
self.init_surface()
|
|
||||||
self.fade_remaining = None
|
|
||||||
|
|
||||||
def init_surface(self):
|
|
||||||
Surface.__init__(self, self.location.size)
|
|
||||||
if self.location.sprite.frames:
|
|
||||||
background = Surface(self.get_size())
|
|
||||||
sprite = self.location.sprite
|
|
||||||
key = sprite.get_current_frame().get_colorkey() or (255, 0, 255)
|
|
||||||
self.set_colorkey(key)
|
|
||||||
background.fill(key)
|
|
||||||
self.background = background
|
|
||||||
self.set_alpha()
|
|
||||||
|
|
||||||
def set_alpha(self, alpha=None):
|
|
||||||
if alpha is None:
|
|
||||||
alpha = self.location.sprite.alpha
|
|
||||||
Surface.set_alpha(self, alpha)
|
|
||||||
|
|
||||||
def start(self, length, out=None):
|
|
||||||
if self.fade_remaining <= 0:
|
|
||||||
alpha = self.get_alpha()
|
|
||||||
maximum = self.location.sprite.alpha
|
|
||||||
if out is None:
|
|
||||||
out = alpha == maximum
|
|
||||||
if out and alpha > 0 or not out and alpha < maximum:
|
|
||||||
self.fade_length = self.fade_remaining = length
|
|
||||||
self.start_time = self.time_filter.get_ticks()
|
|
||||||
self.fading_out = out
|
|
||||||
|
|
||||||
def draw(self, flags):
|
|
||||||
sprite = self.location.sprite
|
|
||||||
if self.fade_remaining >= 0:
|
|
||||||
self.update_alpha()
|
|
||||||
self.clear()
|
|
||||||
frame = sprite.get_current_frame()
|
|
||||||
frame.set_alpha(255)
|
|
||||||
self.blit(frame, (0, 0))
|
|
||||||
frame.set_alpha(sprite.alpha)
|
|
||||||
if not sprite.hidden:
|
|
||||||
self.blit_to_display(self, flags)
|
|
||||||
elif self.fade_remaining is None or self.get_alpha() >= sprite.alpha:
|
|
||||||
if self.fade_remaining >= 0:
|
|
||||||
self.update_alpha()
|
|
||||||
if not sprite.hidden:
|
|
||||||
self.blit_to_display(sprite.get_current_frame(), flags)
|
|
||||||
|
|
||||||
def blit_to_display(self, frame, flags):
|
|
||||||
self.location.sprite.display_surface.blit(frame, self.location, None,
|
|
||||||
flags)
|
|
||||||
|
|
||||||
def update_alpha(self):
|
|
||||||
remaining = self.fade_remaining = self.fade_length - \
|
|
||||||
(self.time_filter.get_ticks() - self.start_time)
|
|
||||||
ratio = self.fade_length and float(remaining) / self.fade_length
|
|
||||||
if not self.fading_out:
|
|
||||||
ratio = 1 - ratio
|
|
||||||
maximum = self.location.sprite.alpha
|
|
||||||
alpha = int(ratio * maximum)
|
|
||||||
if alpha > maximum:
|
|
||||||
alpha = maximum
|
|
||||||
elif alpha < 0:
|
|
||||||
alpha = 0
|
|
||||||
self.set_alpha(alpha)
|
|
||||||
|
|
||||||
def clear(self):
|
|
||||||
self.blit(self.background, (0, 0))
|
|
||||||
|
|
||||||
|
|
||||||
class Frameset():
|
|
||||||
|
|
||||||
def __init__(self, sprite, order=[], framerate=None, name=None):
|
|
||||||
self.sprite = sprite
|
|
||||||
self.name = name
|
|
||||||
self.reversed = False
|
|
||||||
self.order = []
|
|
||||||
self.rect = Rect(0, 0, 0, 0)
|
|
||||||
self.add_index(order)
|
|
||||||
self.set_framerate(framerate)
|
|
||||||
self.reset()
|
|
||||||
|
|
||||||
def add_index(self, order):
|
|
||||||
if isinstance(order, int):
|
|
||||||
order = [order]
|
|
||||||
self.order += order
|
|
||||||
self.measure_rect()
|
|
||||||
|
|
||||||
def set_framerate(self, framerate):
|
|
||||||
self.framerate = framerate
|
|
||||||
|
|
||||||
def reset(self):
|
|
||||||
self.current_index = 0
|
|
||||||
|
|
||||||
def get_current_id(self):
|
|
||||||
return self.order[self.current_index]
|
|
||||||
|
|
||||||
def measure_rect(self):
|
|
||||||
max_width, max_height = 0, 0
|
|
||||||
frames = self.sprite.frames
|
|
||||||
for index in self.order:
|
|
||||||
frame = frames[index]
|
|
||||||
width, height = frame.get_size()
|
|
||||||
max_width = max(width, max_width)
|
|
||||||
max_height = max(height, max_height)
|
|
||||||
self.rect.size = max_width, max_height
|
|
||||||
|
|
||||||
def shift(self):
|
|
||||||
if len(self.order) > 1:
|
|
||||||
self.increment_index()
|
|
||||||
|
|
||||||
def increment_index(self):
|
|
||||||
increment = 1 if not self.reversed else -1
|
|
||||||
index = self.current_index + increment
|
|
||||||
if index < 0:
|
|
||||||
index = self.length() - 1
|
|
||||||
elif index >= self.length():
|
|
||||||
index = 0
|
|
||||||
self.current_index = index
|
|
||||||
|
|
||||||
def length(self):
|
|
||||||
return len(self.order)
|
|
||||||
|
|
||||||
def reverse(self):
|
|
||||||
self.reversed = not self.reversed
|
|
|
@ -1,36 +0,0 @@
|
||||||
from pygame.time import get_ticks
|
|
||||||
|
|
||||||
from GameChild import GameChild
|
|
||||||
|
|
||||||
class TimeFilter(GameChild):
|
|
||||||
|
|
||||||
def __init__(self, parent):
|
|
||||||
GameChild.__init__(self, parent)
|
|
||||||
self.ticks = self.unfiltered_ticks = self.last_ticks = get_ticks()
|
|
||||||
self.open()
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
self.closed = True
|
|
||||||
|
|
||||||
def open(self):
|
|
||||||
self.closed = False
|
|
||||||
|
|
||||||
def get_ticks(self):
|
|
||||||
return self.ticks
|
|
||||||
|
|
||||||
def get_unfiltered_ticks(self):
|
|
||||||
return self.unfiltered_ticks
|
|
||||||
|
|
||||||
def get_last_ticks(self):
|
|
||||||
return self.last_ticks
|
|
||||||
|
|
||||||
def get_last_frame_duration(self):
|
|
||||||
return self.last_frame_duration
|
|
||||||
|
|
||||||
def update(self):
|
|
||||||
ticks = get_ticks()
|
|
||||||
self.last_frame_duration = duration = ticks - self.last_ticks
|
|
||||||
if not self.closed:
|
|
||||||
self.ticks += duration
|
|
||||||
self.unfiltered_ticks += duration
|
|
||||||
self.last_ticks = ticks
|
|
|
@ -1,69 +0,0 @@
|
||||||
class Vector(list):
|
|
||||||
|
|
||||||
def __init__(self, x=0, y=0):
|
|
||||||
list.__init__(self, (x, y))
|
|
||||||
|
|
||||||
def __getattr__(self, name):
|
|
||||||
if name == "x":
|
|
||||||
return self[0]
|
|
||||||
elif name == "y":
|
|
||||||
return self[1]
|
|
||||||
|
|
||||||
def __setattr__(self, name, value):
|
|
||||||
if name == "x":
|
|
||||||
self[0] = value
|
|
||||||
elif name == "y":
|
|
||||||
self[1] = value
|
|
||||||
else:
|
|
||||||
list.__setattr__(self, name, value)
|
|
||||||
|
|
||||||
def __add__(self, other):
|
|
||||||
return Vector(self.x + other[0], self.y + other[1])
|
|
||||||
|
|
||||||
__radd__ = __add__
|
|
||||||
|
|
||||||
def __iadd__(self, other):
|
|
||||||
self.x += other[0]
|
|
||||||
self.y += other[1]
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __sub__(self, other):
|
|
||||||
return Vector(self.x - other[0], self.y - other[1])
|
|
||||||
|
|
||||||
def __rsub__(self, other):
|
|
||||||
return Vector(other[0] - self.x, other[1] - self.y)
|
|
||||||
|
|
||||||
def __isub__(self, other):
|
|
||||||
self.x -= other[0]
|
|
||||||
self.y -= other[1]
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __mul__(self, other):
|
|
||||||
return Vector(self.x * other, self.y * other)
|
|
||||||
|
|
||||||
__rmul__ = __mul__
|
|
||||||
|
|
||||||
def __imul__(self, other):
|
|
||||||
self.x *= other
|
|
||||||
self.y *= other
|
|
||||||
return self
|
|
||||||
|
|
||||||
def apply_to_components(self, function):
|
|
||||||
self.x = function(self.x)
|
|
||||||
self.y = function(self.y)
|
|
||||||
|
|
||||||
def place(self, x=None, y=None):
|
|
||||||
if x is not None:
|
|
||||||
self.x = x
|
|
||||||
if y is not None:
|
|
||||||
self.y = y
|
|
||||||
|
|
||||||
def move(self, dx=0, dy=0):
|
|
||||||
if dx:
|
|
||||||
self.x += dx
|
|
||||||
if dy:
|
|
||||||
self.y += dy
|
|
||||||
|
|
||||||
def place_at_origin(self):
|
|
||||||
self.x = 0
|
|
||||||
self.y = 0
|
|
|
@ -1,71 +0,0 @@
|
||||||
from os import makedirs
|
|
||||||
from os.path import exists, join
|
|
||||||
from tempfile import TemporaryFile
|
|
||||||
from time import strftime
|
|
||||||
|
|
||||||
from pygame.image import tostring, frombuffer, save
|
|
||||||
from pygame.time import get_ticks
|
|
||||||
|
|
||||||
from GameChild import GameChild
|
|
||||||
|
|
||||||
class VideoRecorder(GameChild):
|
|
||||||
|
|
||||||
def __init__(self, parent):
|
|
||||||
GameChild.__init__(self, parent)
|
|
||||||
self.display_surface = self.get_display_surface()
|
|
||||||
self.delegate = self.get_delegate()
|
|
||||||
self.load_configuration()
|
|
||||||
self.reset()
|
|
||||||
self.subscribe(self.respond)
|
|
||||||
|
|
||||||
def load_configuration(self):
|
|
||||||
config = self.get_configuration("video-recordings")
|
|
||||||
self.root = config["path"]
|
|
||||||
self.directory_name_format = config["directory-name-format"]
|
|
||||||
self.file_extension = config["file-extension"]
|
|
||||||
self.frame_format = config["frame-format"]
|
|
||||||
self.framerate = config["framerate"]
|
|
||||||
|
|
||||||
def reset(self):
|
|
||||||
self.recording = False
|
|
||||||
self.frame_length = None
|
|
||||||
self.frames = None
|
|
||||||
self.last_frame = 0
|
|
||||||
|
|
||||||
def respond(self, event):
|
|
||||||
compare = self.delegate.compare
|
|
||||||
if compare(event, "record-video"):
|
|
||||||
self.toggle_record()
|
|
||||||
elif compare(event, "reset-game"):
|
|
||||||
self.reset()
|
|
||||||
|
|
||||||
def toggle_record(self):
|
|
||||||
recording = not self.recording
|
|
||||||
if recording:
|
|
||||||
self.frame_length = len(self.get_string())
|
|
||||||
self.frames = TemporaryFile()
|
|
||||||
else:
|
|
||||||
self.write_frames()
|
|
||||||
self.recording = recording
|
|
||||||
|
|
||||||
def get_string(self):
|
|
||||||
return tostring(self.display_surface, self.frame_format)
|
|
||||||
|
|
||||||
def write_frames(self):
|
|
||||||
root = join(self.root, strftime(self.directory_name_format))
|
|
||||||
if not exists(root):
|
|
||||||
makedirs(root)
|
|
||||||
size = self.display_surface.get_size()
|
|
||||||
frames = self.frames
|
|
||||||
frames.seek(0)
|
|
||||||
for ii, frame in enumerate(iter(lambda: frames.read(self.frame_length),
|
|
||||||
"")):
|
|
||||||
path = join(root, "%04i.png" % ii)
|
|
||||||
save(frombuffer(frame, size, self.frame_format), path)
|
|
||||||
print "wrote video frames to " + root
|
|
||||||
|
|
||||||
def update(self):
|
|
||||||
ticks = get_ticks()
|
|
||||||
if self.recording and ticks - self.last_frame >= self.framerate:
|
|
||||||
self.frames.write(self.get_string())
|
|
||||||
self.last_frame = ticks
|
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit a0aba9a0bb527ec7f3d7269cdd522448560a99c3
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,20 +1,8 @@
|
||||||
1398631170.296798 200
|
1398631170.296798 100 SIV
|
||||||
1398631170.296798 100
|
1398631170.296798 70 SIV
|
||||||
1398631170.296798 40
|
1398631170.296798 45 SIV
|
||||||
1398635621.7 158
|
1398635621.7 25 SIV
|
||||||
1398635792.99 154
|
1398635792.99 10 SIV
|
||||||
1398636058.07 180
|
1437514837.26 206 SIV
|
||||||
1398636195.37 232
|
1437514932.23 22 SIV
|
||||||
1398636310.09 131
|
1437514988.25 88 SIV
|
||||||
1398636404.1 120
|
|
||||||
1398636488.41 165
|
|
||||||
1398636581.89 173
|
|
||||||
1398636667.8 186
|
|
||||||
1398647055.97 78
|
|
||||||
1398647195.17 187
|
|
||||||
1398647939.59 155
|
|
||||||
1398648230.57 88
|
|
||||||
1436645313.22 196
|
|
||||||
1436645428.32 246
|
|
||||||
1436645528.27 193
|
|
||||||
1437504178.89 165
|
|
||||||
|
|
Loading…
Reference in New Issue