changeset 548:1e9ea6519f3c

Make EoSDInterface separate from EoSD game.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Wed, 21 May 2014 20:56:53 +0200
parents e35bef07290d
children 56bca8ce4b68
files pytouhou/games/eosd.py pytouhou/interfaces/__init__.py pytouhou/interfaces/eosd.py scripts/pytouhou
diffstat 4 files changed, 170 insertions(+), 146 deletions(-) [+]
line wrap: on
line diff
--- a/pytouhou/games/eosd.py
+++ b/pytouhou/games/eosd.py
@@ -20,8 +20,6 @@ from pytouhou.game.lasertype import Lase
 from pytouhou.game.itemtype import ItemType
 from pytouhou.game.player import Player
 from pytouhou.game.orb import Orb
-from pytouhou.game.effect import Effect
-from pytouhou.game.text import Text, Counter, Gauge, NativeText
 from pytouhou.game.background import Background
 
 from pytouhou.vm import ECLMainRunner
@@ -96,8 +94,6 @@ class EoSDCommon(object):
                                          eosd_characters[player_character],
                                          character, default_power, continues)
 
-        self.interface = EoSDInterface(resource_loader, self.players[0]) #XXX
-
 
 
 class EoSDGame(Game):
@@ -143,149 +139,15 @@ class EoSDGame(Game):
                       common.height, prng, common.interface, hints,
                       friendly_fire)
 
-        self.texts['stage_name'] = common.interface.stage_name
-        self.texts['song_name'] = common.interface.song_name
-
-
-
-class EoSDInterface(object):
-    def __init__(self, resource_loader, player_state):
-        self.game = None
-        self.player_state = player_state
-        front = resource_loader.get_single_anm('front.anm')
-        self.ascii_anm = resource_loader.get_single_anm('ascii.anm')
-
-        self.width = 640
-        self.height = 480
-        self.game_pos = (32, 16)
-
-        self.highscore = 1000000 #TODO: read score.dat
-        self.items = ([Effect((0, 32 * i), 6, front) for i in range(15)] +
-                      [Effect((416 + 32 * i, 32 * j), 6, front) for i in range(7) for j in range(15)] +
-                      [Effect((32 + 32 * i, 0), 7, front) for i in range(12)] +
-                      [Effect((32 + 32 * i, 464), 8, front) for i in range(12)] +
-                      [Effect((0, 0), i, front) for i in reversed(range(6))] +
-                      [Effect((0, 0), i, front) for i in range(9, 16)])
-        for item in self.items:
-            item.sprite.allow_dest_offset = True #XXX
-
-        self.level_start = []
-
-        self.labels = {
-            'highscore': Text((500, 58), self.ascii_anm, front, text='0'),
-            'score': Text((500, 82), self.ascii_anm, front, text='0'),
-            'player': Counter((500, 122), front, front, script=16, value=0),
-            'bombs': Counter((500, 146), front, front, script=17, value=0),
-            'power': Text((500, 186), self.ascii_anm, front, text='0'),
-            'graze': Text((500, 206), self.ascii_anm, front, text='0'),
-            'points': Text((500, 226), self.ascii_anm, front, text='0'),
-            'framerate': Text((512, 464), self.ascii_anm, front),
-            'debug?': Text((0, 464), self.ascii_anm, front),
-
-            # Only when there is a boss.
-            'boss_lives': Text((80, 16), self.ascii_anm),
-            'timeout': Text((384, 16), self.ascii_anm),
-        }
-        self.labels['boss_lives'].set_color('yellow')
-
-        self.boss_items = [
-            Effect((0, 0), 19, front), # Enemy
-            Gauge((100, 24), front), # Gauge
-            Gauge((100, 24), front), # Spellcard gauge
-        ]
-        for item in self.boss_items:
-            item.sprite.allow_dest_offset = True #XXX
-
-
-    def start_stage(self, game, stage):
-        self.game = game
-        if stage < 6:
-            text = 'STAGE %d' % stage
-        elif stage == 6:
-            text = 'FINAL STAGE'
-        elif stage == 7:
-            text = 'EXTRA STAGE'
-
-        self.stage_name = NativeText((192, 200), unicode(game.std.name), shadow=True, align='center')
-        self.stage_name.set_timeout(240, effect='fadeout', duration=60, start=120)
-
-        self.set_song_name(game.std.bgms[0][0])
-
-        self.level_start = [Text((16+384/2, 200), self.ascii_anm, text=text, align='center')] #TODO: find the exact location.
-        self.level_start[0].set_timeout(240, effect='fadeout', duration=60, start=120)
-        self.level_start[0].set_color('yellow')
+        try:
+            self.texts['stage_name'] = common.interface.stage_name
+        except AttributeError:
+            pass
 
-
-    def set_song_name(self, name):
-        #TODO: use the correct animation.
-        self.song_name = NativeText((384, 432), u'♪ ' + name, shadow=True, align='right')
-        self.song_name.set_timeout(240, effect='fadeout', duration=60, start=120)
-
-
-    def set_boss_life(self):
-        if not self.game.boss:
-            return
-        self.boss_items[1].maximum = self.game.boss.life or 1
-        self.boss_items[2].maximum = self.game.boss.life or 1
-
-
-    def set_spell_life(self):
-        self.boss_items[2].set_value(self.game.boss.low_life_trigger if self.game.boss else 0)
-
-
-    def update(self):
-        for elem in self.items:
-            elem.update()
-
-        for elem in self.level_start:
-            elem.update()
-            if elem.removed: #XXX
-                self.level_start = []
-
-        player_state = self.player_state
-
-        self.highscore = max(self.highscore, player_state.effective_score)
-        self.labels['highscore'].set_text('%09d' % self.highscore)
-        self.labels['score'].set_text('%09d' % player_state.effective_score)
-        self.labels['power'].set_text('%d' % player_state.power)
-        self.labels['graze'].set_text('%d' % player_state.graze)
-        self.labels['points'].set_text('%d' % player_state.points)
-        self.labels['player'].set_value(player_state.lives)
-        self.labels['bombs'].set_value(player_state.bombs)
-
-        if self.game.boss:
-            boss = self.game.boss
-
-            life_gauge = self.boss_items[1]
-            life_gauge.set_value(boss.life)
-
-            spell_gauge = self.boss_items[2]
-            spell_gauge.sprite.color = (255, 192, 192)
-            if boss.life < spell_gauge.value:
-                spell_gauge.set_value(boss.life)
-
-            for item in self.boss_items:
-                item.update()
-
-            self.labels['boss_lives'].set_text('%d' % boss.remaining_lives)
-            self.labels['boss_lives'].changed = True
-
-            timeout = min((boss.timeout - boss.frame) // 60, 99)
-            timeout_label = self.labels['timeout']
-            if timeout >= 20:
-                timeout_label.set_color('blue')
-            elif timeout >= 10:
-                timeout_label.set_color('darkblue')
-            else:
-                if timeout >= 5:
-                    timeout_label.set_color('purple')
-                else:
-                    timeout_label.set_color('red')
-                if (boss.timeout - boss.frame) % 60 == 0 and boss.timeout != 0:
-                    self.game.sfx_player.set_volume('timeout.wav', 1.)
-                    self.game.sfx_player.play('timeout.wav')
-            timeout_label.set_text('%02d' % (timeout if timeout >= 0 else 0))
-            timeout_label.changed = True
+        try:
+            self.texts['song_name'] = common.interface.song_name
+        except AttributeError:
+            pass
 
 
 
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/pytouhou/interfaces/eosd.py
@@ -0,0 +1,156 @@
+# -*- encoding: utf-8 -*-
+##
+## Copyright (C) 2014 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published
+## by the Free Software Foundation; version 3 only.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+
+from pytouhou.game.effect import Effect
+from pytouhou.game.text import Text, Counter, Gauge, NativeText
+
+
+class EoSDInterface(object):
+    def __init__(self, resource_loader, player_state):
+        self.game = None
+        self.player_state = player_state
+        front = resource_loader.get_single_anm('front.anm')
+        self.ascii_anm = resource_loader.get_single_anm('ascii.anm')
+
+        self.width = 640
+        self.height = 480
+        self.game_pos = (32, 16)
+
+        self.highscore = 1000000 #TODO: read score.dat
+        self.items = ([Effect((0, 32 * i), 6, front) for i in range(15)] +
+                      [Effect((416 + 32 * i, 32 * j), 6, front) for i in range(7) for j in range(15)] +
+                      [Effect((32 + 32 * i, 0), 7, front) for i in range(12)] +
+                      [Effect((32 + 32 * i, 464), 8, front) for i in range(12)] +
+                      [Effect((0, 0), i, front) for i in reversed(range(6))] +
+                      [Effect((0, 0), i, front) for i in range(9, 16)])
+        for item in self.items:
+            item.sprite.allow_dest_offset = True #XXX
+
+        self.level_start = []
+
+        self.labels = {
+            'highscore': Text((500, 58), self.ascii_anm, front, text='0'),
+            'score': Text((500, 82), self.ascii_anm, front, text='0'),
+            'player': Counter((500, 122), front, front, script=16, value=0),
+            'bombs': Counter((500, 146), front, front, script=17, value=0),
+            'power': Text((500, 186), self.ascii_anm, front, text='0'),
+            'graze': Text((500, 206), self.ascii_anm, front, text='0'),
+            'points': Text((500, 226), self.ascii_anm, front, text='0'),
+            'framerate': Text((512, 464), self.ascii_anm, front),
+            'debug?': Text((0, 464), self.ascii_anm, front),
+
+            # Only when there is a boss.
+            'boss_lives': Text((80, 16), self.ascii_anm),
+            'timeout': Text((384, 16), self.ascii_anm),
+        }
+        self.labels['boss_lives'].set_color('yellow')
+
+        self.boss_items = [
+            Effect((0, 0), 19, front), # Enemy
+            Gauge((100, 24), front), # Gauge
+            Gauge((100, 24), front), # Spellcard gauge
+        ]
+        for item in self.boss_items:
+            item.sprite.allow_dest_offset = True #XXX
+
+
+    def start_stage(self, game, stage):
+        self.game = game
+        if stage < 6:
+            text = 'STAGE %d' % stage
+        elif stage == 6:
+            text = 'FINAL STAGE'
+        elif stage == 7:
+            text = 'EXTRA STAGE'
+
+        self.stage_name = NativeText((192, 200), unicode(game.std.name), shadow=True, align='center')
+        self.stage_name.set_timeout(240, effect='fadeout', duration=60, start=120)
+
+        self.set_song_name(game.std.bgms[0][0])
+
+        self.level_start = [Text((16+384/2, 200), self.ascii_anm, text=text, align='center')] #TODO: find the exact location.
+        self.level_start[0].set_timeout(240, effect='fadeout', duration=60, start=120)
+        self.level_start[0].set_color('yellow')
+
+
+    def set_song_name(self, name):
+        #TODO: use the correct animation.
+        self.song_name = NativeText((384, 432), u'♪ ' + name, shadow=True, align='right')
+        self.song_name.set_timeout(240, effect='fadeout', duration=60, start=120)
+
+
+    def set_boss_life(self):
+        if not self.game.boss:
+            return
+        self.boss_items[1].maximum = self.game.boss.life or 1
+        self.boss_items[2].maximum = self.game.boss.life or 1
+
+
+    def set_spell_life(self):
+        self.boss_items[2].set_value(self.game.boss.low_life_trigger if self.game.boss else 0)
+
+
+    def update(self):
+        for elem in self.items:
+            elem.update()
+
+        for elem in self.level_start:
+            elem.update()
+            if elem.removed: #XXX
+                self.level_start = []
+
+        player_state = self.player_state
+
+        self.highscore = max(self.highscore, player_state.effective_score)
+        self.labels['highscore'].set_text('%09d' % self.highscore)
+        self.labels['score'].set_text('%09d' % player_state.effective_score)
+        self.labels['power'].set_text('%d' % player_state.power)
+        self.labels['graze'].set_text('%d' % player_state.graze)
+        self.labels['points'].set_text('%d' % player_state.points)
+        self.labels['player'].set_value(player_state.lives)
+        self.labels['bombs'].set_value(player_state.bombs)
+
+        if self.game.boss:
+            boss = self.game.boss
+
+            life_gauge = self.boss_items[1]
+            life_gauge.set_value(boss.life)
+
+            spell_gauge = self.boss_items[2]
+            spell_gauge.sprite.color = (255, 192, 192)
+            if boss.life < spell_gauge.value:
+                spell_gauge.set_value(boss.life)
+
+            for item in self.boss_items:
+                item.update()
+
+            self.labels['boss_lives'].set_text('%d' % boss.remaining_lives)
+            self.labels['boss_lives'].changed = True
+
+            timeout = min((boss.timeout - boss.frame) // 60, 99)
+            timeout_label = self.labels['timeout']
+            if timeout >= 20:
+                timeout_label.set_color('blue')
+            elif timeout >= 10:
+                timeout_label.set_color('darkblue')
+            else:
+                if timeout >= 5:
+                    timeout_label.set_color('purple')
+                else:
+                    timeout_label.set_color('red')
+                if (boss.timeout - boss.frame) % 60 == 0 and boss.timeout != 0:
+                    self.game.sfx_player.set_volume('timeout.wav', 1.)
+                    self.game.sfx_player.play('timeout.wav')
+            timeout_label.set_text('%02d' % (timeout if timeout >= 0 else 0))
+            timeout_label.changed = True
--- a/scripts/pytouhou
+++ b/scripts/pytouhou
@@ -38,6 +38,7 @@ game_group.add_argument('-r', '--rank', 
 game_group.add_argument('-c', '--character', metavar='CHARACTER', type=int, default=0, help='Select the character to use, from 0 (ReimuA, default) to 3 (MarisaB).')
 game_group.add_argument('-b', '--boss-rush', action='store_true', help='Fight only bosses.')
 game_group.add_argument('--game', metavar='GAME', choices=['EoSD'], default='EoSD', help='Select the game engine to use.')
+game_group.add_argument('--interface', metavar='INTERFACE', choices=['EoSD'], default='EoSD', help='Select the interface to use.')
 game_group.add_argument('--hints', metavar='HINTS', default=None, help='Hints file, to display text while playing.')
 
 replay_group = parser.add_argument_group('Replay options')
@@ -69,6 +70,9 @@ import logging
 if args.game == 'EoSD':
     from pytouhou.games.eosd import EoSDCommon as Common, EoSDGame as Game
 
+if args.interface == 'EoSD':
+    from pytouhou.interfaces.eosd import EoSDInterface as Interface
+
 
 from pytouhou.lib.sdl import SDL, show_simple_message_box
 from pytouhou.ui.window import Window
@@ -188,6 +192,8 @@ def main(window, path, data, stage_num, 
     game_class = GameBossRush if boss_rush else Game
 
     common = Common(resource_loader, characters, continues, stage_num - 1)
+    interface = Interface(resource_loader, common.players[0]) #XXX
+    common.interface = interface #XXX
     renderer = GameRenderer(resource_loader, window)
     runner = GameRunner(window, renderer, common, resource_loader, skip_replay, con)
     window.set_runner(runner)