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