# HG changeset patch # User Emmanuel Gil Peyrot # Date 1364117377 -3600 # Node ID 6c0cb3eee33e4e2fd7e528d5bd2d16e94561a11d # Parent 9589a01e6edfe40a46caec1ddac6a1605d875d8f Add MoF’s hints support, and fix the Text timeout interface. diff --git a/eosd b/eosd --- a/eosd +++ b/eosd @@ -30,6 +30,7 @@ from pytouhou.game.player import PlayerS from pytouhou.formats.t6rp import T6RP, Level from pytouhou.utils.random import Random from pytouhou.vm.msgrunner import NextStage +from pytouhou.formats.hint import Hint class EoSDGameBossRush(EoSDGame): @@ -64,7 +65,7 @@ class EoSDGameBossRush(EoSDGame): def main(path, data, stage_num, rank, character, replay, save_filename, skip_replay, boss_rush, fps_limit, single_buffer, debug, - fixed_pipeline, display_background): + fixed_pipeline, display_background, hints): resource_loader = Loader(path) @@ -98,6 +99,10 @@ def main(path, data, stage_num, rank, ch save_replay.rank = rank save_replay.character = character + if hints: + with open(hints, 'rb') as file: + hints = Hint.read(file) + difficulty = 16 default_power = [0, 64, 128, 128, 128, 128, 0][stage_num - 1] states = [PlayerState(character=character, power=default_power)] @@ -139,10 +144,12 @@ def main(path, data, stage_num, rank, ch level.difficulty = difficulty save_keystates = [] + hints_stage = hints.stages[stage_num - 1] if hints else None + # Load stage data stage = resource_loader.get_stage('stage%d.std' % stage_num) - game = game_class(resource_loader, states, stage_num, rank, difficulty, prng=prng, continues=continues) + game = game_class(resource_loader, states, stage_num, rank, difficulty, prng=prng, continues=continues, hints=hints_stage) if display_background: background_anm_wrapper = resource_loader.get_anm_wrapper(('stg%dbg.anm' % stage_num,)) @@ -201,10 +208,11 @@ parser.add_argument('--fps-limit', metav parser.add_argument('--debug', action='store_true', help='Set unlimited continues, and perhaps other debug features.') parser.add_argument('--fixed-pipeline', action='store_true', help='Use the fixed pipeline instead of the new programmable one.') parser.add_argument('--no-background', action='store_false', help='Disable background display (huge performance boost on slow systems).') +parser.add_argument('--hints', metavar='HINTS', default=None, help='Hints file, to display text while playing.') args = parser.parse_args() main(args.path, tuple(args.data), args.stage, args.rank, args.character, args.replay, args.save_replay, args.skip_replay, args.boss_rush, args.fps_limit, args.single_buffer, args.debug, args.fixed_pipeline, - args.no_background) + args.no_background, args.hints) diff --git a/pytouhou/formats/hint.py b/pytouhou/formats/hint.py --- a/pytouhou/formats/hint.py +++ b/pytouhou/formats/hint.py @@ -76,6 +76,7 @@ class Hint(object): stage_mode = False tip_mode = False stage = None + tip = None hints = cls() stages = hints.stages diff --git a/pytouhou/game/game.py b/pytouhou/game/game.py --- a/pytouhou/game/game.py +++ b/pytouhou/game/game.py @@ -34,7 +34,7 @@ class Game(object): def __init__(self, resource_loader, players, stage, rank, difficulty, bullet_types, laser_types, item_types, nb_bullets_max=None, width=384, height=448, prng=None, - interface=None, continues=0): + interface=None, continues=0, hints=None): self.resource_loader = resource_loader self.width, self.height = width, height @@ -56,6 +56,7 @@ class Game(object): self.labels = [] self.faces = [None, None] self.interface = interface + self.hints = hints self.continues = continues self.stage = stage @@ -166,7 +167,7 @@ class Game(object): score = 0 bonus = 2000 for bullet in self.bullets: - label = self.new_label((bullet.x, bullet.y), str(bonus)) + self.new_label((bullet.x, bullet.y), str(bonus)) score += bonus bonus += 10 self.bullets = [] @@ -211,7 +212,20 @@ class Game(object): def new_label(self, pos, text): label = Text(pos, self.ascii_wrapper, text=text, xspacing=8, shift=48) - label.set_timeout(60) + label.set_timeout(60, effect='move') + self.labels.append(label) + return label + + + def new_hint(self, hint): + pos = hint['Pos'] + #TODO: Scale + + pos = pos[0] + 192, pos[1] + label = Text(pos, self.ascii_wrapper, text=hint['Text'], align=hint['Align']) + label.set_timeout(hint['Time']) + label.set_alpha(hint['Alpha']) + label.set_color(hint['Color'], text=False) self.labels.append(label) return label @@ -255,6 +269,8 @@ class Game(object): for laser in self.lasers: #TODO: what priority is it? laser.update() self.interface.update() # Pri 12 + if self.hints: + self.update_hints() # Not from this game, so unknown. for label in self.labels: #TODO: what priority is it? label.update() self.update_faces() # Pri XXX @@ -307,6 +323,12 @@ class Game(object): effect.update() + def update_hints(self): + for hint in self.hints: + if hint['Count'] == self.frame and hint['Base'] == 'start': + self.new_hint(hint) + + def update_faces(self): for face in self.faces: if face: diff --git a/pytouhou/game/text.py b/pytouhou/game/text.py --- a/pytouhou/game/text.py +++ b/pytouhou/game/text.py @@ -86,15 +86,39 @@ class GlyphCollection(Widget): glyph.sprite.changed = True + def set_color(self, color, text=True): + if text: + colors = {'white': (255, 255, 255), 'yellow': (255, 255, 0), + 'blue': (192, 192, 255), 'darkblue': (160, 128, 255), + 'purple': (224, 128, 255), 'red': (255, 64, 0)} + color = colors[color] + self.ref_sprite.color = color + for glyph in self.glyphes: + glyph.sprite.color = color + + + def set_alpha(self, alpha): + self.ref_sprite.alpha = alpha + for glyph in self.glyphes: + glyph.sprite.alpha = alpha + + class Text(GlyphCollection): def __init__(self, pos, ascii_wrapper, back_wrapper=None, text='', - xspacing=14, shift=21, back_script=22): + xspacing=14, shift=21, back_script=22, align='left'): GlyphCollection.__init__(self, pos, ascii_wrapper, back_wrapper, xspacing=xspacing, back_script=back_script) self.text = '' self.shift = shift + if align == 'center': + self.x -= xspacing * len(text) // 2 + elif align == 'right': + self.x -= xspacing * len(text) + else: + assert align == 'left' + self.set_text(text) @@ -112,13 +136,10 @@ class Text(GlyphCollection): self.changed = True - def set_color(self, color): - colors = {'white': (255, 255, 255), 'yellow': (255, 255, 0), - 'blue': (192, 192, 255), 'darkblue': (160, 128, 255), - 'purple': (224, 128, 255), 'red': (255, 64, 0)} - self.ref_sprite.color = colors[color] - for glyph in self.glyphes: - glyph.sprite.color = colors[color] + def timeout_update(self): + GlyphCollection.update(self) + if self.frame == self.timeout: + self.removed = True def move_timeout_update(self): @@ -134,9 +155,9 @@ class Text(GlyphCollection): GlyphCollection.update(self) if self.frame >= self.start: if self.frame == self.start: - self.fade(self.effect, 255, lambda x: x) - elif self.frame == self.timeout - self.effect: - self.fade(self.effect, 0, lambda x: x) + self.fade(self.duration, 255, lambda x: x) + elif self.frame == self.timeout - self.duration: + self.fade(self.duration, 0, lambda x: x) if self.fade_interpolator: self.fade_interpolator.update(self.frame) self.alpha = int(self.fade_interpolator.values[0]) @@ -153,18 +174,21 @@ class Text(GlyphCollection): formula) - def set_timeout(self, timeout, effect=None, start=0): - if effect == None: #XXX + def set_timeout(self, timeout, effect=None, duration=0, start=0): + if effect == 'move': self.update = self.move_timeout_update self.timeout = timeout + start - else: + elif effect == 'fadeout': self.alpha = 0 for glyph in self.glyphes: glyph.sprite.alpha = 0 self.update = self.fadeout_timeout_update - self.effect = effect + self.duration = duration self.start = start self.timeout = timeout + start + else: + self.update = self.timeout_update + self.timeout = timeout + start diff --git a/pytouhou/games/eosd.py b/pytouhou/games/eosd.py --- a/pytouhou/games/eosd.py +++ b/pytouhou/games/eosd.py @@ -30,7 +30,8 @@ SQ2 = 2. ** 0.5 / 2. class EoSDGame(Game): def __init__(self, resource_loader, player_states, stage, rank, difficulty, bullet_types=None, laser_types=None, item_types=None, - nb_bullets_max=640, width=384, height=448, prng=None, continues=0): + nb_bullets_max=640, width=384, height=448, prng=None, + continues=0, hints=None): if not bullet_types: etama3 = resource_loader.get_anm_wrapper(('etama3.anm',)) @@ -96,7 +97,7 @@ class EoSDGame(Game): Game.__init__(self, resource_loader, players, stage, rank, difficulty, bullet_types, laser_types, item_types, nb_bullets_max, - width, height, prng, interface, continues) + width, height, prng, interface, continues, hints) @@ -121,7 +122,7 @@ class EoSDInterface(object): item.sprite.allow_dest_offset = True #XXX self.level_start = [Text((176, 200), ascii_wrapper, text='STAGE %d' % game.stage)] #TODO: find the exact location. - self.level_start[0].set_timeout(240, effect=60, start=120) + self.level_start[0].set_timeout(240, effect='fadeout', duration=60, start=120) self.level_start[0].set_color('yellow') #TODO: use the system text for the stage name, and the song name.