comparison pytouhou/games/eosd/game.py @ 597:244c99c568c8

Don’t hardcode the available games and interfaces, and relocation them.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Sat, 25 Oct 2014 18:52:16 +0200
parents pytouhou/games/eosd.py@1e9ea6519f3c
children 2cf518129725
comparison
equal deleted inserted replaced
596:ab131d04987d 597:244c99c568c8
1 # -*- encoding: utf-8 -*-
2 ##
3 ## Copyright (C) 2011 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
4 ##
5 ## This program is free software; you can redistribute it and/or modify
6 ## it under the terms of the GNU General Public License as published
7 ## by the Free Software Foundation; version 3 only.
8 ##
9 ## This program is distributed in the hope that it will be useful,
10 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 ## GNU General Public License for more details.
13 ##
14
15 from pytouhou.utils.interpolator import Interpolator
16
17 from pytouhou.game.game import Game as GameBase
18 from pytouhou.game.bullettype import BulletType
19 from pytouhou.game.lasertype import LaserType
20 from pytouhou.game.itemtype import ItemType
21 from pytouhou.game.player import Player as PlayerBase
22 from pytouhou.game.orb import Orb
23 from pytouhou.game.background import Background
24
25 from pytouhou.vm import ECLMainRunner
26
27
28 class Common(object):
29 def __init__(self, resource_loader, player_characters, continues, stage,
30 width=384, height=448):
31 self.width, self.height = width, height
32
33 self.etama = resource_loader.get_multi_anm(('etama3.anm', 'etama4.anm'))
34 self.bullet_types = [BulletType(self.etama[0], 0, 11, 14, 15, 16, hitbox_size=2,
35 type_id=0),
36 BulletType(self.etama[0], 1, 12, 17, 18, 19, hitbox_size=3,
37 type_id=1),
38 BulletType(self.etama[0], 2, 12, 17, 18, 19, hitbox_size=2,
39 type_id=2),
40 BulletType(self.etama[0], 3, 12, 17, 18, 19, hitbox_size=3,
41 type_id=3),
42 BulletType(self.etama[0], 4, 12, 17, 18, 19, hitbox_size=2.5,
43 type_id=4),
44 BulletType(self.etama[0], 5, 12, 17, 18, 19, hitbox_size=2,
45 type_id=5),
46 BulletType(self.etama[0], 6, 13, 20, 20, 20, hitbox_size=8,
47 launch_anim_offsets=(0, 1, 1, 2, 2, 3, 4, 0),
48 type_id=6),
49 BulletType(self.etama[0], 7, 13, 20, 20, 20, hitbox_size=5.5,
50 launch_anim_offsets=(1, 1, 1, 1),
51 type_id=7),
52 BulletType(self.etama[0], 8, 13, 20, 20, 20, hitbox_size=4.5,
53 launch_anim_offsets=(0, 1, 1, 2, 2, 3, 4, 0),
54 type_id=8),
55 BulletType(self.etama[1], 0, 1, 2, 2, 2, hitbox_size=16,
56 launch_anim_offsets=(0, 1, 2, 3),
57 type_id=9)]
58
59 self.laser_types = [LaserType(self.etama[0], 9),
60 LaserType(self.etama[0], 10)]
61
62 self.item_types = [ItemType(self.etama[0], 0, 7), #Power
63 ItemType(self.etama[0], 1, 8), #Point
64 ItemType(self.etama[0], 2, 9), #Big power
65 ItemType(self.etama[0], 3, 10), #Bomb
66 ItemType(self.etama[0], 4, 11), #Full power
67 ItemType(self.etama[0], 5, 12), #1up
68 ItemType(self.etama[0], 6, 13)] #Star
69
70 self.enemy_face = [('face03a.anm', 'face03b.anm'),
71 ('face05a.anm',),
72 ('face06a.anm', 'face06b.anm'),
73 ('face08a.anm', 'face08b.anm'),
74 ('face09a.anm', 'face09b.anm'),
75 ('face09b.anm', 'face10a.anm', 'face10b.anm'),
76 ('face08a.anm', 'face12a.anm', 'face12b.anm', 'face12c.anm')]
77
78 default_power = [0, 64, 128, 128, 128, 128, 0][stage]
79
80 eosd_characters = resource_loader.get_eosd_characters()
81 self.first_character = player_characters[0] // 2
82 self.player_anms = {}
83 self.players = [None] * len(player_characters)
84 for i, player_character in enumerate(player_characters):
85 character = player_character // 2
86 if character not in self.player_anms:
87 face = resource_loader.get_multi_anm(('face0%da.anm' % character,
88 'face0%db.anm' % character,
89 'face0%dc.anm' % character))
90 anm = resource_loader.get_single_anm('player0%d.anm' % character)
91 self.player_anms[character] = (anm, face)
92
93 self.players[i] = Player(i, self.player_anms[character][0],
94 eosd_characters[player_character],
95 character, default_power, continues)
96
97
98
99 class Game(GameBase):
100 def __init__(self, resource_loader, stage, rank, difficulty,
101 common, prng, hints=None, friendly_fire=True,
102 nb_bullets_max=640):
103
104 self.etama = common.etama #XXX
105 try:
106 self.enm_anm = resource_loader.get_multi_anm(('stg%denm.anm' % stage,
107 'stg%denm2.anm' % stage))
108 except KeyError:
109 self.enm_anm = resource_loader.get_anm('stg%denm.anm' % stage)
110 ecl = resource_loader.get_ecl('ecldata%d.ecl' % stage)
111 self.ecl_runners = [ECLMainRunner(main, ecl.subs, self) for main in ecl.mains]
112
113 self.spellcard_effect_anm = resource_loader.get_single_anm('eff0%d.anm' % stage)
114
115 self.msg = resource_loader.get_msg('msg%d.dat' % stage)
116 msg_anm = [common.player_anms[common.first_character][1], #TODO: does it break bomb face of non-first player?
117 resource_loader.get_multi_anm(common.enemy_face[stage - 1])]
118
119 self.msg_anm = [[], []]
120 for i, anms in enumerate(msg_anm):
121 for anm in anms:
122 for sprite in anm.sprites.values():
123 self.msg_anm[i].append((anm, sprite))
124
125 for player in common.players:
126 player._game = self
127
128 # Load stage data
129 self.std = resource_loader.get_stage('stage%d.std' % stage)
130
131 background_anm = resource_loader.get_single_anm('stg%dbg.anm' % stage)
132 self.background = Background(self.std, background_anm)
133
134 common.interface.start_stage(self, stage)
135
136 GameBase.__init__(self, common.players, stage, rank, difficulty,
137 common.bullet_types, common.laser_types,
138 common.item_types, nb_bullets_max, common.width,
139 common.height, prng, common.interface, hints,
140 friendly_fire)
141
142 try:
143 self.texts['stage_name'] = common.interface.stage_name
144 except AttributeError:
145 pass
146
147 try:
148 self.texts['song_name'] = common.interface.song_name
149 except AttributeError:
150 pass
151
152
153
154 class Player(PlayerBase):
155 def __init__(self, number, anm, shts, character, power, continues):
156 self.sht = shts[0]
157 self.focused_sht = shts[1]
158
159 PlayerBase.__init__(self, number, anm, character, power, continues)
160
161 self.orbs = [Orb(anm, 128, self),
162 Orb(anm, 129, self)]
163
164 self.orbs[0].offset_x = -24
165 self.orbs[1].offset_x = 24
166
167 self.orb_dx_interpolator = None
168 self.orb_dy_interpolator = None
169
170
171 def start_focusing(self):
172 self.orb_dx_interpolator = Interpolator((24,), self._game.frame,
173 (8,), self._game.frame + 8,
174 lambda x: x ** 2)
175 self.orb_dy_interpolator = Interpolator((0,), self._game.frame,
176 (-32,), self._game.frame + 8)
177 self.focused = True
178
179
180 def stop_focusing(self):
181 self.orb_dx_interpolator = Interpolator((8,), self._game.frame,
182 (24,), self._game.frame + 8,
183 lambda x: x ** 2)
184 self.orb_dy_interpolator = Interpolator((-32,), self._game.frame,
185 (0,), self._game.frame + 8)
186 self.focused = False
187
188
189 @property
190 def objects(self):
191 return [self] + (self.orbs if self.power >= 8 else [])
192
193
194 def update(self, keystate):
195 PlayerBase.update(self, keystate)
196
197 if self.death_time == 0 or self._game.frame - self.death_time > 60:
198 if self.orb_dx_interpolator:
199 self.orb_dx_interpolator.update(self._game.frame)
200 dx, = self.orb_dx_interpolator.values
201 self.orbs[0].offset_x = -dx
202 self.orbs[1].offset_x = dx
203 if self.orb_dy_interpolator:
204 self.orb_dy_interpolator.update(self._game.frame)
205 dy, = self.orb_dy_interpolator.values
206 self.orbs[0].offset_y = dy
207 self.orbs[1].offset_y = dy
208
209 for orb in self.orbs:
210 orb.update()