Mercurial > touhou
comparison pytouhou/game/player.pyx @ 494:6be9c99a3a24
Merge PlayerState into Player, fix player respawn position.
author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
---|---|
date | Mon, 14 Oct 2013 12:11:01 +0200 |
parents | 887de1309491 |
children | c9c2fb873dbd |
comparison
equal
deleted
inserted
replaced
493:26c082870dcf | 494:6be9c99a3a24 |
---|---|
24 | 24 |
25 class GameOver(Exception): | 25 class GameOver(Exception): |
26 pass | 26 pass |
27 | 27 |
28 | 28 |
29 cdef class PlayerState: | 29 cdef class Player(Element): |
30 def __init__(self, long number, long character=0, long score=0, | 30 def __init__(self, long number, anm, long character=0, long power=0, |
31 long power=0, long lives=2, long bombs=3, long continues=0): | 31 long continues=0, long lives=2, long bombs=3, long score=0): |
32 Element.__init__(self) | |
33 | |
32 self.number = number | 34 self.number = number |
33 self.character = character # ReimuA/ReimuB/MarisaA/MarisaB/... | 35 self.character = character # ReimuA/ReimuB/MarisaA/MarisaB/... |
34 | 36 |
35 self.score = score | 37 self.score = score |
36 self.effective_score = score | 38 self.effective_score = score |
37 self.lives = lives | 39 self.lives = lives |
38 self.bombs = bombs | 40 self.bombs = bombs |
41 self.continues = continues | |
39 self.power = power | 42 self.power = power |
40 self.continues = continues | |
41 | 43 |
42 self.continues_used = 0 | 44 self.continues_used = 0 |
43 self.miss = 0 | 45 self.miss = 0 |
44 self.bombs_used = 0 | 46 self.bombs_used = 0 |
45 | 47 |
53 self.touchable = True | 55 self.touchable = True |
54 self.focused = False | 56 self.focused = False |
55 | 57 |
56 self.power_bonus = 0 # Never goes over 30. | 58 self.power_bonus = 0 # Never goes over 30. |
57 | 59 |
58 | 60 self._game = None |
59 cdef class Player(Element): | |
60 def __init__(self, PlayerState state, Game game, anm): | |
61 Element.__init__(self) | |
62 | |
63 self._game = game | |
64 self.anm = anm | 61 self.anm = anm |
65 | 62 |
66 self.speeds = (self.sht.horizontal_vertical_speed, | 63 self.speeds = (self.sht.horizontal_vertical_speed, |
67 self.sht.diagonal_speed, | 64 self.sht.diagonal_speed, |
68 self.sht.horizontal_vertical_focused_speed, | 65 self.sht.horizontal_vertical_focused_speed, |
69 self.sht.diagonal_focused_speed) | 66 self.sht.diagonal_focused_speed) |
70 | 67 |
71 self.fire_time = 0 | 68 self.fire_time = 0 |
72 | 69 |
73 self.state = state | |
74 self.direction = 0 | 70 self.direction = 0 |
75 | 71 |
76 self.set_anim(0) | 72 self.set_anim(0) |
77 | 73 |
78 self.death_time = 0 | 74 self.death_time = 0 |
86 cdef void play_sound(self, str name): | 82 cdef void play_sound(self, str name): |
87 self._game.sfx_player.play('%s.wav' % name) | 83 self._game.sfx_player.play('%s.wav' % name) |
88 | 84 |
89 | 85 |
90 cdef void collide(self): | 86 cdef void collide(self): |
91 if not self.state.invulnerable_time and not self.death_time and self.state.touchable: # Border Between Life and Death | 87 if not self.invulnerable_time and not self.death_time and self.touchable: # Border Between Life and Death |
92 self.death_time = self._game.frame | 88 self.death_time = self._game.frame |
93 self._game.new_effect((self.state.x, self.state.y), 17) | 89 self._game.new_effect((self.x, self.y), 17) |
94 self._game.modify_difficulty(-1600) | 90 self._game.modify_difficulty(-1600) |
95 self.play_sound('pldead00') | 91 self.play_sound('pldead00') |
96 for i in xrange(16): | 92 for i in xrange(16): |
97 self._game.new_particle((self.state.x, self.state.y), 11, 256) #TODO: find the real size and range. | 93 self._game.new_particle((self.x, self.y), 11, 256) #TODO: find the real size and range. |
98 | 94 |
99 | 95 |
100 def start_focusing(self): | 96 def start_focusing(self): |
101 self.state.focused = True | 97 self.focused = True |
102 | 98 |
103 | 99 |
104 def stop_focusing(self): | 100 def stop_focusing(self): |
105 self.state.focused = False | 101 self.focused = False |
106 | 102 |
107 | 103 |
108 cdef void fire(self): | 104 cdef void fire(self): |
109 cdef double x, y | |
110 cdef long shot_power | 105 cdef long shot_power |
111 | 106 |
112 sht = self.focused_sht if self.state.focused else self.sht | 107 sht = self.focused_sht if self.focused else self.sht |
113 | 108 |
114 # Don’t use min() since sht.shots could be an empty dict. | 109 # Don’t use min() since sht.shots could be an empty dict. |
115 power = 999 | 110 power = 999 |
116 for shot_power in sht.shots: | 111 for shot_power in sht.shots: |
117 if self.state.power < shot_power: | 112 if self.power < shot_power: |
118 power = power if power < shot_power else shot_power | 113 power = power if power < shot_power else shot_power |
119 | 114 |
120 bullets = self._game.players_bullets | 115 bullets = self._game.players_bullets |
121 lasers = self._game.players_lasers | 116 lasers = self._game.players_lasers |
122 nb_bullets_max = self._game.nb_bullets_max | 117 nb_bullets_max = self._game.nb_bullets_max |
123 | 118 |
124 if self.fire_time % 5 == 0: | 119 if self.fire_time % 5 == 0: |
125 self.play_sound('plst00') | 120 self.play_sound('plst00') |
126 | 121 |
127 for shot in sht.shots[power]: | 122 for shot in sht.shots[power]: |
128 origin = self.orbs[shot.orb - 1] if shot.orb else self.state | 123 origin = <Element>(self.orbs[shot.orb - 1] if shot.orb else self) |
129 shot_type = <unsigned char>shot.type | 124 shot_type = <unsigned char>shot.type |
130 | 125 |
131 if shot_type == 3: | 126 if shot_type == 3: |
132 if self.fire_time != 30: | 127 if self.fire_time != 30: |
133 continue | 128 continue |
147 continue | 142 continue |
148 | 143 |
149 if nb_bullets_max != 0 and len(bullets) == nb_bullets_max: | 144 if nb_bullets_max != 0 and len(bullets) == nb_bullets_max: |
150 break | 145 break |
151 | 146 |
152 x = origin.x + shot.pos[0] | 147 x = origin.x + <double>shot.pos[0] |
153 y = origin.y + shot.pos[1] | 148 y = origin.y + <double>shot.pos[1] |
154 | 149 |
155 #TODO: find a better way to do that. | 150 #TODO: find a better way to do that. |
156 bullet_type = BulletType(self.anm, shot.sprite % 256, | 151 bullet_type = BulletType(self.anm, shot.sprite % 256, |
157 shot.sprite % 256 + 32, #TODO: find the real cancel anim | 152 shot.sprite % 256 + 32, #TODO: find the real cancel anim |
158 0, 0, 0, 0.) | 153 0, 0, 0, 0.) |
160 if shot_type == 2: | 155 if shot_type == 2: |
161 #TODO: triple-check acceleration! | 156 #TODO: triple-check acceleration! |
162 bullets.append(Bullet((x, y), bullet_type, 0, | 157 bullets.append(Bullet((x, y), bullet_type, 0, |
163 shot.angle, shot.speed, | 158 shot.angle, shot.speed, |
164 (-1, 0, 0, 0, 0.15, -pi/2., 0., 0.), | 159 (-1, 0, 0, 0, 0.15, -pi/2., 0., 0.), |
165 16, self, self._game, player=self.state.number, | 160 16, self, self._game, player=self.number, |
166 damage=shot.damage, hitbox=shot.hitbox)) | 161 damage=shot.damage, hitbox=shot.hitbox)) |
167 else: | 162 else: |
168 bullets.append(Bullet((x, y), bullet_type, 0, | 163 bullets.append(Bullet((x, y), bullet_type, 0, |
169 shot.angle, shot.speed, | 164 shot.angle, shot.speed, |
170 (0, 0, 0, 0, 0., 0., 0., 0.), | 165 (0, 0, 0, 0, 0., 0., 0., 0.), |
171 0, self, self._game, player=self.state.number, | 166 0, self, self._game, player=self.number, |
172 damage=shot.damage, hitbox=shot.hitbox)) | 167 damage=shot.damage, hitbox=shot.hitbox)) |
173 | 168 |
174 | 169 |
175 cpdef update(self, long keystate): | 170 cpdef update(self, long keystate): |
176 cdef double dx, dy | 171 cdef double dx, dy |
177 | 172 |
178 if self.death_time == 0 or self._game.frame - self.death_time > 60: | 173 if self.death_time == 0 or self._game.frame - self.death_time > 60: |
179 speed, diag_speed = self.speeds[2:] if self.state.focused else self.speeds[:2] | 174 speed, diag_speed = self.speeds[2:] if self.focused else self.speeds[:2] |
180 try: | 175 try: |
181 dx, dy = {16: (0., -speed), 32: (0., speed), 64: (-speed, 0.), 128: (speed, 0.), | 176 dx, dy = {16: (0., -speed), 32: (0., speed), 64: (-speed, 0.), 128: (speed, 0.), |
182 16|64: (-diag_speed, -diag_speed), 16|128: (diag_speed, -diag_speed), | 177 16|64: (-diag_speed, -diag_speed), 16|128: (diag_speed, -diag_speed), |
183 32|64: (-diag_speed, diag_speed), 32|128: (diag_speed, diag_speed)}[keystate & (16|32|64|128)] | 178 32|64: (-diag_speed, diag_speed), 32|128: (diag_speed, diag_speed)}[keystate & (16|32|64|128)] |
184 except KeyError: | 179 except KeyError: |
192 self.direction = +1 | 187 self.direction = +1 |
193 elif dx == 0 and self.direction != 0: | 188 elif dx == 0 and self.direction != 0: |
194 self.set_anim({-1: 2, +1: 4}[self.direction]) | 189 self.set_anim({-1: 2, +1: 4}[self.direction]) |
195 self.direction = 0 | 190 self.direction = 0 |
196 | 191 |
197 self.state.x += dx | 192 self.x += dx |
198 self.state.y += dy | 193 self.y += dy |
199 | 194 |
200 #XXX | 195 if self.x < 8.: |
201 self.x = self.state.x | 196 self.x = 8. |
202 self.y = self.state.y | 197 if self.x > self._game.width - 8: |
203 | 198 self.x = self._game.width - 8. |
204 if self.state.x < 8.: | 199 if self.y < 16.: |
205 self.state.x = 8. | 200 self.y = 16. |
206 if self.state.x > self._game.width - 8: | 201 if self.y > self._game.height - 16: |
207 self.state.x = self._game.width - 8. | 202 self.y = self._game.height -16. |
208 if self.state.y < 16.: | 203 |
209 self.state.y = 16. | 204 if not self.focused and keystate & 4: |
210 if self.state.y > self._game.height - 16: | |
211 self.state.y = self._game.height -16. | |
212 | |
213 if not self.state.focused and keystate & 4: | |
214 self.start_focusing() | 205 self.start_focusing() |
215 elif self.state.focused and not keystate & 4: | 206 elif self.focused and not keystate & 4: |
216 self.stop_focusing() | 207 self.stop_focusing() |
217 | 208 |
218 if self.state.invulnerable_time > 0: | 209 if self.invulnerable_time > 0: |
219 self.state.invulnerable_time -= 1 | 210 self.invulnerable_time -= 1 |
220 | 211 |
221 m = self.state.invulnerable_time % 8 | 212 m = self.invulnerable_time % 8 |
222 if m == 7 or self.state.invulnerable_time == 0: | 213 if m == 7 or self.invulnerable_time == 0: |
223 self.sprite.color = (255, 255, 255) | 214 self.sprite.color = (255, 255, 255) |
224 self.sprite.changed = True | 215 self.sprite.changed = True |
225 elif m == 1: | 216 elif m == 1: |
226 self.sprite.color = (64, 64, 64) | 217 self.sprite.color = (64, 64, 64) |
227 self.sprite.changed = True | 218 self.sprite.changed = True |
241 self._game.unset_player_bomb() | 232 self._game.unset_player_bomb() |
242 | 233 |
243 if self.death_time: | 234 if self.death_time: |
244 time = self._game.frame - self.death_time | 235 time = self._game.frame - self.death_time |
245 if time == 6: # too late, you are dead :( | 236 if time == 6: # too late, you are dead :( |
246 self.state.touchable = False | 237 self.touchable = False |
247 if self.state.power > 16: | 238 if self.power > 16: |
248 self.state.power -= 16 | 239 self.power -= 16 |
249 else: | 240 else: |
250 self.state.power = 0 | 241 self.power = 0 |
251 self._game.cancel_player_lasers() | 242 self._game.cancel_player_lasers() |
252 | 243 |
253 self.state.miss += 1 | 244 self.miss += 1 |
254 self.state.lives -= 1 | 245 self.lives -= 1 |
255 if self.state.lives < 0: | 246 if self.lives < 0: |
256 #TODO: display a menu to ask the players if they want to continue. | 247 #TODO: display a menu to ask the players if they want to continue. |
257 if self.state.continues == 0: | 248 if self.continues == 0: |
258 raise GameOver | 249 raise GameOver |
259 | 250 |
260 # Don’t decrement if it’s infinite. | 251 # Don’t decrement if it’s infinite. |
261 if self.state.continues >= 0: | 252 if self.continues >= 0: |
262 self.state.continues -= 1 | 253 self.continues -= 1 |
263 self.state.continues_used += 1 | 254 self.continues_used += 1 |
264 | 255 |
265 for i in xrange(5): | 256 for i in xrange(5): |
266 self._game.drop_bonus(self.state.x, self.state.y, 4, | 257 self._game.drop_bonus(self.x, self.y, 4, |
267 end_pos=(self._game.prng.rand_double() * 288 + 48, | 258 end_pos=(self._game.prng.rand_double() * 288 + 48, |
268 self._game.prng.rand_double() * 192 - 64)) | 259 self._game.prng.rand_double() * 192 - 64)) |
269 self.state.score = 0 | 260 self.score = 0 |
270 self.state.effective_score = 0 | 261 self.effective_score = 0 |
271 self.state.lives = 2 #TODO: use the right default. | 262 self.lives = 2 #TODO: use the right default. |
272 self.state.bombs = 3 #TODO: use the right default. | 263 self.bombs = 3 #TODO: use the right default. |
273 self.state.power = 0 | 264 self.power = 0 |
274 | 265 |
275 self.state.graze = 0 | 266 self.graze = 0 |
276 self.state.points = 0 | 267 self.points = 0 |
277 else: | 268 else: |
278 self._game.drop_bonus(self.state.x, self.state.y, 2, | 269 self._game.drop_bonus(self.x, self.y, 2, |
279 end_pos=(self._game.prng.rand_double() * 288 + 48, # 102h.exe@0x41f3dc | 270 end_pos=(self._game.prng.rand_double() * 288 + 48, # 102h.exe@0x41f3dc |
280 self._game.prng.rand_double() * 192 - 64)) # @0x41f3 | 271 self._game.prng.rand_double() * 192 - 64)) # @0x41f3 |
281 for i in xrange(5): | 272 for i in xrange(5): |
282 self._game.drop_bonus(self.state.x, self.state.y, 0, | 273 self._game.drop_bonus(self.x, self.y, 0, |
283 end_pos=(self._game.prng.rand_double() * 288 + 48, | 274 end_pos=(self._game.prng.rand_double() * 288 + 48, |
284 self._game.prng.rand_double() * 192 - 64)) | 275 self._game.prng.rand_double() * 192 - 64)) |
285 | 276 |
286 elif time == 7: | 277 elif time == 7: |
287 self.sprite.mirrored = False | 278 self.sprite.mirrored = False |
293 #TODO: the next two branches could be happening at the same frame. | 284 #TODO: the next two branches could be happening at the same frame. |
294 elif time == 31: | 285 elif time == 31: |
295 self._game.cancel_bullets() | 286 self._game.cancel_bullets() |
296 | 287 |
297 elif time == 32: | 288 elif time == 32: |
298 self.state.x = float(self._game.width) / 2. #TODO | 289 self.x = float(self._game.width) / 2. #TODO |
299 self.state.y = float(self._game.width) #TODO | 290 self.y = float(self._game.width) #TODO |
300 self.direction = 0 | 291 self.direction = 0 |
301 | 292 |
302 self.sprite = Sprite() | 293 self.sprite = Sprite() |
303 self.anmrunner = ANMRunner(self.anm, 0, self.sprite) | 294 self.anmrunner = ANMRunner(self.anm, 0, self.sprite) |
304 self.sprite.alpha = 128 | 295 self.sprite.alpha = 128 |
306 self.sprite.fade(30, 255) | 297 self.sprite.fade(30, 255) |
307 self.sprite.blendfunc = 1 | 298 self.sprite.blendfunc = 1 |
308 self.sprite.scale_in(30, 1., 1.) | 299 self.sprite.scale_in(30, 1., 1.) |
309 | 300 |
310 elif time == 61: # respawned | 301 elif time == 61: # respawned |
311 self.state.touchable = True | 302 self.touchable = True |
312 self.state.invulnerable_time = 240 | 303 self.invulnerable_time = 240 |
313 self.sprite.blendfunc = 0 | 304 self.sprite.blendfunc = 0 |
314 self.sprite.changed = True | 305 self.sprite.changed = True |
315 | 306 |
316 elif time == 91: # start the bullet hell again | 307 elif time == 91: # start the bullet hell again |
317 self.death_time = 0 | 308 self.death_time = 0 |