score box

main
Frank DeMarco 8 years ago
parent c5e62360a4
commit 539e61c054

3
.gitmodules vendored

@ -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.

@ -15,6 +15,7 @@ caption = Electric Sieve
dimensions = 420, 700
score-font-path = font/Titan-One.ttf
title-font-path = font/Oxygen.ttf
scoreboard-font-path = font/terminus/Terminus.ttf
[mouse]
visible = no

@ -9,9 +9,10 @@ from pygame.font import Font
from pygame.mixer import Sound
from pygame.locals import *
from electric_sieve.pgfw.Game import Game
from electric_sieve.pgfw.GameChild import GameChild
from electric_sieve.pgfw.Sprite import Sprite
from lib.pgfw.pgfw.Game import Game
from lib.pgfw.pgfw.GameChild import GameChild
from lib.pgfw.pgfw.Sprite import Sprite
from lib.pgfw.pgfw.extension import render_box
class ElectricSieve(Game):
@ -53,27 +54,27 @@ class Title(GameChild):
for y in xrange(0, surface.get_height(), 2):
for x in xrange(0, surface.get_width(), 2):
surface.blit(tile, (x, y))
font = Font(self.get_resource("display", "title-font-path"), 20)
font.set_italic(True)
font.set_bold(True)
self.captions = captions = Sprite(self), Sprite(self)
colors = (0, 68, 170), (255, 255, 255), (128, 128, 128), \
(220, 119, 41), (255, 80, 80), (0, 90, 110)
texts = ["", ""]
for ii, text in \
enumerate(self.get_configuration("display",
"caption").upper().split()):
texts[ii] += "" * (5 if ii else 3)
for ch in text:
texts[ii] += ch + " "
texts[ii] = texts[ii].strip() + "" * (5 if ii else 3)
for _ in xrange(25):
color = choice(colors)
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)))
cx = self.display_surface.get_rect().centerx
captions[0].location.center = cx, 301
captions[1].location.center = cx, 398
# font = Font(self.get_resource("display", "title-font-path"), 20)
# font.set_italic(True)
# font.set_bold(True)
# self.captions = captions = Sprite(self), Sprite(self)
# colors = (0, 68, 170), (255, 255, 255), (128, 128, 128), \
# (220, 119, 41), (255, 80, 80), (0, 90, 110)
# texts = ["", ""]
# for ii, text in \
# enumerate(self.get_configuration("display",
# "caption").upper().split()):
# texts[ii] += "•" * (5 if ii else 3)
# for ch in text:
# texts[ii] += ch + " "
# texts[ii] = texts[ii].strip() + "•" * (5 if ii else 3)
# for _ in xrange(25):
# color = choice(colors)
# 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)))
# cx = self.display_surface.get_rect().centerx
# captions[0].location.center = cx, 301
# captions[1].location.center = cx, 398
self.scoreboard = Scoreboard(self)
self.music = Sound(self.get_resource("audio", "title"))
self.advance = Sound(self.get_resource("audio", "title-advance"))
@ -99,8 +100,8 @@ class Title(GameChild):
def update(self):
if self.active:
self.display_surface.blit(self.background, (0, 0))
for caption in self.captions:
caption.update()
# for caption in self.captions:
# caption.update()
self.scoreboard.update()
@ -173,54 +174,70 @@ class Shift(GameChild):
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):
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.display_surface = self.get_display_surface()
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()
def load(self):
scores = []
for line in file(self.scores_path, "r"):
fields = line.split()
scores.append((float(fields[0]), int(fields[1])))
scores.append((float(fields[0]), int(fields[1]), fields[2]))
self.sprites = sprites = []
font_path = self.get_resource("display", "score-font-path")
y = 0
font_path = self.get_resource("display", "scoreboard-font-path")
sizes = [14] * 5
for ii, score in enumerate(sorted(scores, key=lambda score: score[1],
reverse=True)[:3]):
font = Font(font_path, [40, 24, 16][ii])
sprites.append(Sprite(self, 250))
text = str(score[1])
color = (0, 0, 0) if not (score[1] == self.most_recent_score) else \
(255, 255, 255)
sprites[ii].add_frame(font.render(text, True, color,
(255, 255, 255)))
reverse=True)[:len(sizes)]):
font = Font(font_path, sizes[ii])
sprites.append((Sprite(self, self.BLINK_INTERVAL),
Sprite(self, self.BLINK_INTERVAL)))
score_text = str(score[1])
color = self.FOREGROUND if not (score[1] == self.most_recent_score) else \
self.BACKGROUND
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:
sprites[ii].add_frame(font.render(text, True, (0, 255, 0),
(255, 255, 255)))
sprites[ii].location.midtop = self.rect.w / 2, y
y += sprites[ii].location.h
sprites[ii].display_surface = self
sprites[ii][1].add_frame(render_box(font, score_text, False, self.NEW,
self.BACKGROUND, self.FOREGROUND, 1, 2))
sprites[ii][0].add_frame(render_box(font, score[2], False, self.NEW,
self.BACKGROUND, self.FOREGROUND, 1, 2))
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):
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.load()
def update(self):
self.fill((255, 255, 255))
for sprite in self.sprites:
sprite.update()
self.display_surface.blit(self, self.rect)
for pair in self.sprites:
for sprite in pair:
sprite.update()
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