Mercurial > touhou
comparison pytouhou/vm/eclrunner.py @ 151:5cf927cbd9c5
Merge GameState into Game. TODO: Merge PlayerState into Player
author | Thibaut Girka <thib@sitedethib.com> |
---|---|
date | Tue, 04 Oct 2011 23:32:02 +0200 |
parents | 4f46717390aa |
children | 86807b8a63bd |
comparison
equal
deleted
inserted
replaced
150:4f46717390aa | 151:5cf927cbd9c5 |
---|---|
23 | 23 |
24 | 24 |
25 | 25 |
26 class ECLMainRunner(object): | 26 class ECLMainRunner(object): |
27 __metaclass__ = MetaRegistry | 27 __metaclass__ = MetaRegistry |
28 __slots__ = ('_ecl', '_new_enemy_func', '_game_state', 'processes', | 28 __slots__ = ('_ecl', '_new_enemy_func', '_game', 'processes', |
29 'instruction_pointer') | 29 'instruction_pointer') |
30 | 30 |
31 def __init__(self, ecl, new_enemy_func, game_state): | 31 def __init__(self, ecl, new_enemy_func, game): |
32 self._ecl = ecl | 32 self._ecl = ecl |
33 self._new_enemy_func = new_enemy_func | 33 self._new_enemy_func = new_enemy_func |
34 self._game_state = game_state | 34 self._game = game |
35 | 35 |
36 self.processes = [] | 36 self.processes = [] |
37 | 37 |
38 self.instruction_pointer = 0 | 38 self.instruction_pointer = 0 |
39 | 39 |
43 try: | 43 try: |
44 frame, sub, instr_type, args = self._ecl.main[self.instruction_pointer] | 44 frame, sub, instr_type, args = self._ecl.main[self.instruction_pointer] |
45 except IndexError: | 45 except IndexError: |
46 break | 46 break |
47 | 47 |
48 if frame > self._game_state.frame: | 48 if frame > self._game.frame: |
49 break | 49 break |
50 else: | 50 else: |
51 self.instruction_pointer += 1 | 51 self.instruction_pointer += 1 |
52 | 52 |
53 if frame == self._game_state.frame: | 53 if frame == self._game.frame: |
54 try: | 54 try: |
55 callback = self._handlers[instr_type] | 55 callback = self._handlers[instr_type] |
56 except KeyError: | 56 except KeyError: |
57 logger.warn('unhandled main opcode %d (args: %r)', instr_type, args) | 57 logger.warn('unhandled main opcode %d (args: %r)', instr_type, args) |
58 else: | 58 else: |
63 | 63 |
64 | 64 |
65 def _pop_enemy(self, sub, instr_type, x, y, z, life, bonus_dropped, unknown2, unknown3): | 65 def _pop_enemy(self, sub, instr_type, x, y, z, life, bonus_dropped, unknown2, unknown3): |
66 if instr_type & 4: | 66 if instr_type & 4: |
67 if x < -990: #102h.exe@0x411820 | 67 if x < -990: #102h.exe@0x411820 |
68 x = self._game_state.prng.rand_double() * 368 | 68 x = self._game.prng.rand_double() * 368 |
69 if y < -990: #102h.exe@0x41184b | 69 if y < -990: #102h.exe@0x41184b |
70 y = self._game_state.prng.rand_double() * 416 | 70 y = self._game.prng.rand_double() * 416 |
71 if z < -990: #102h.exe@0x411881 | 71 if z < -990: #102h.exe@0x411881 |
72 y = self._game_state.prng.rand_double() * 800 | 72 y = self._game.prng.rand_double() * 800 |
73 enemy = self._new_enemy_func((x, y), life, instr_type, self._pop_enemy) | 73 enemy = self._new_enemy_func((x, y), life, instr_type, self._pop_enemy) |
74 process = ECLRunner(self._ecl, sub, enemy, self._game_state) | 74 process = ECLRunner(self._ecl, sub, enemy, self._game) |
75 self.processes.append(process) | 75 self.processes.append(process) |
76 process.run_iteration() | 76 process.run_iteration() |
77 | 77 |
78 | 78 |
79 @instruction(0) | 79 @instruction(0) |
80 @instruction(2) | 80 @instruction(2) |
81 @instruction(4) | 81 @instruction(4) |
82 @instruction(6) | 82 @instruction(6) |
83 def pop_enemy(self, sub, instr_type, x, y, z, life, bonus_dropped, unknown2, unknown3): | 83 def pop_enemy(self, sub, instr_type, x, y, z, life, bonus_dropped, unknown2, unknown3): |
84 if self._game_state.boss: | 84 if self._game.boss: |
85 return | 85 return |
86 self._pop_enemy(sub, instr_type, x, y, z, life, bonus_dropped, unknown2, unknown3) | 86 self._pop_enemy(sub, instr_type, x, y, z, life, bonus_dropped, unknown2, unknown3) |
87 | 87 |
88 | 88 |
89 | 89 |
90 | 90 |
91 class ECLRunner(object): | 91 class ECLRunner(object): |
92 __metaclass__ = MetaRegistry | 92 __metaclass__ = MetaRegistry |
93 __slots__ = ('_ecl', '_enemy', '_game_state', 'variables', 'sub', 'frame', | 93 __slots__ = ('_ecl', '_enemy', '_game', 'variables', 'sub', 'frame', |
94 'instruction_pointer', 'comparison_reg', 'stack') | 94 'instruction_pointer', 'comparison_reg', 'stack') |
95 | 95 |
96 def __init__(self, ecl, sub, enemy, game_state): | 96 def __init__(self, ecl, sub, enemy, game): |
97 # Things not supposed to change | 97 # Things not supposed to change |
98 self._ecl = ecl | 98 self._ecl = ecl |
99 self._enemy = enemy | 99 self._enemy = enemy |
100 self._game_state = game_state | 100 self._game = game |
101 | 101 |
102 # Things supposed to change (and be put in the stack) | 102 # Things supposed to change (and be put in the stack) |
103 self.variables = [0, 0, 0, 0, | 103 self.variables = [0, 0, 0, 0, |
104 0., 0., 0., 0., | 104 0., 0., 0., 0., |
105 0, 0, 0, 0] | 105 0, 0, 0, 0] |
157 else: | 157 else: |
158 self.instruction_pointer += 1 | 158 self.instruction_pointer += 1 |
159 | 159 |
160 | 160 |
161 #TODO: skip bad ranks | 161 #TODO: skip bad ranks |
162 if not rank_mask & (0x100 << self._game_state.rank): | 162 if not rank_mask & (0x100 << self._game.rank): |
163 continue | 163 continue |
164 | 164 |
165 | 165 |
166 if frame == self.frame: | 166 if frame == self.frame: |
167 try: | 167 try: |
179 def _getval(self, value): | 179 def _getval(self, value): |
180 if -10012 <= value <= -10001: | 180 if -10012 <= value <= -10001: |
181 return self.variables[int(-10001-value)] | 181 return self.variables[int(-10001-value)] |
182 elif -10025 <= value <= -10013: | 182 elif -10025 <= value <= -10013: |
183 if value == -10013: | 183 if value == -10013: |
184 return self._game_state.rank | 184 return self._game.rank |
185 elif value == -10014: | 185 elif value == -10014: |
186 return self._game_state.difficulty | 186 return self._game.difficulty |
187 elif value == -10015: | 187 elif value == -10015: |
188 return self._enemy.x | 188 return self._enemy.x |
189 elif value == -10016: | 189 elif value == -10016: |
190 return self._enemy.y | 190 return self._enemy.y |
191 elif value == -10017: | 191 elif value == -10017: |
201 elif value == -10022: | 201 elif value == -10022: |
202 return self._enemy.frame | 202 return self._enemy.frame |
203 elif value == -10024: | 203 elif value == -10024: |
204 return self._enemy.life | 204 return self._enemy.life |
205 elif value == -10025: | 205 elif value == -10025: |
206 return self._enemy.select_player().character | 206 return self._enemy.select_player().state.character #TODO |
207 raise NotImplementedError(value) #TODO | 207 raise NotImplementedError(value) #TODO |
208 else: | 208 else: |
209 return value | 209 return value |
210 | 210 |
211 | 211 |
272 | 272 |
273 @instruction(6) | 273 @instruction(6) |
274 def set_random_int(self, variable_id, maxval): | 274 def set_random_int(self, variable_id, maxval): |
275 """Set the specified variable to a random int in the [0, maxval) range. | 275 """Set the specified variable to a random int in the [0, maxval) range. |
276 """ | 276 """ |
277 self._setval(variable_id, int(self._getval(maxval) * self._game_state.prng.rand_double())) | 277 self._setval(variable_id, int(self._getval(maxval) * self._game.prng.rand_double())) |
278 | 278 |
279 | 279 |
280 @instruction(8) | 280 @instruction(8) |
281 def set_random_float(self, variable_id, maxval): | 281 def set_random_float(self, variable_id, maxval): |
282 """Set the specified variable to a random float in [0, maxval) range. | 282 """Set the specified variable to a random float in [0, maxval) range. |
283 """ | 283 """ |
284 self._setval(variable_id, self._getval(maxval) * self._game_state.prng.rand_double()) | 284 self._setval(variable_id, self._getval(maxval) * self._game.prng.rand_double()) |
285 | 285 |
286 | 286 |
287 @instruction(9) | 287 @instruction(9) |
288 def set_random_float2(self, variable_id, amp, minval): | 288 def set_random_float2(self, variable_id, amp, minval): |
289 self._setval(variable_id, self._getval(minval) + self._getval(amp) * self._game_state.prng.rand_double()) | 289 self._setval(variable_id, self._getval(minval) + self._getval(amp) * self._game.prng.rand_double()) |
290 | 290 |
291 | 291 |
292 @instruction(10) | 292 @instruction(10) |
293 def store_x(self, variable_id): | 293 def store_x(self, variable_id): |
294 self._setval(variable_id, self._enemy.x) | 294 self._setval(variable_id, self._enemy.x) |
441 self._enemy.acceleration = acceleration | 441 self._enemy.acceleration = acceleration |
442 | 442 |
443 | 443 |
444 @instruction(49) | 444 @instruction(49) |
445 def set_random_angle(self, min_angle, max_angle): | 445 def set_random_angle(self, min_angle, max_angle): |
446 angle = self._game_state.prng.rand_double() * (max_angle - min_angle) + min_angle | 446 angle = self._game.prng.rand_double() * (max_angle - min_angle) + min_angle |
447 self._enemy.angle = angle | 447 self._enemy.angle = angle |
448 | 448 |
449 | 449 |
450 @instruction(50) | 450 @instruction(50) |
451 def set_random_angle_ex(self, min_angle, max_angle): | 451 def set_random_angle_ex(self, min_angle, max_angle): |
452 if self._enemy.screen_box: | 452 if self._enemy.screen_box: |
453 minx, miny, maxx, maxy = self._enemy.screen_box | 453 minx, miny, maxx, maxy = self._enemy.screen_box |
454 else: | 454 else: |
455 minx, miny, maxx, maxy = (0., 0., 0., 0.) | 455 minx, miny, maxx, maxy = (0., 0., 0., 0.) |
456 | 456 |
457 angle = self._game_state.prng.rand_double() * (max_angle - min_angle) + min_angle | 457 angle = self._game.prng.rand_double() * (max_angle - min_angle) + min_angle |
458 sa, ca = sin(angle), cos(angle) | 458 sa, ca = sin(angle), cos(angle) |
459 | 459 |
460 distx = min(96.0, (maxx - minx) / 2.) | 460 distx = min(96.0, (maxx - minx) / 2.) |
461 disty = min(96.0, (maxy - miny) / 2.) | 461 disty = min(96.0, (maxy - miny) / 2.) |
462 | 462 |
633 | 633 |
634 | 634 |
635 @instruction(77) | 635 @instruction(77) |
636 def set_bullet_interval_ex(self, value): | 636 def set_bullet_interval_ex(self, value): |
637 self._enemy.bullet_launch_interval = value | 637 self._enemy.bullet_launch_interval = value |
638 self._enemy.bullet_launch_timer = int(self._game_state.prng.rand_double() * value) #TODO: check | 638 self._enemy.bullet_launch_timer = int(self._game.prng.rand_double() * value) #TODO: check |
639 | 639 |
640 | 640 |
641 @instruction(78) | 641 @instruction(78) |
642 def set_delay_attack(self): | 642 def set_delay_attack(self): |
643 self._enemy.delay_attack = True | 643 self._enemy.delay_attack = True |
658 self._enemy.extended_bullet_attributes = tuple(self._getval(attr) for attr in attributes) | 658 self._enemy.extended_bullet_attributes = tuple(self._getval(attr) for attr in attributes) |
659 | 659 |
660 | 660 |
661 @instruction(83) | 661 @instruction(83) |
662 def change_bullets_into_star_items(self): | 662 def change_bullets_into_star_items(self): |
663 self._game_state.change_bullets_into_star_items() | 663 self._game.change_bullets_into_star_items() |
664 | 664 |
665 | 665 |
666 @instruction(93) | 666 @instruction(93) |
667 def set_spellcard(self, unknown, number, name): | 667 def set_spellcard(self, unknown, number, name): |
668 #TODO: display it on the game. | 668 #TODO: display it on the game. |
691 | 691 |
692 | 692 |
693 @instruction(101) | 693 @instruction(101) |
694 def set_boss_mode(self, unknown): | 694 def set_boss_mode(self, unknown): |
695 #TODO: unknown | 695 #TODO: unknown |
696 self._game_state.boss = self._enemy | 696 self._game.boss = self._enemy |
697 | 697 |
698 | 698 |
699 @instruction(103) | 699 @instruction(103) |
700 def set_hitbox(self, width, height, depth): | 700 def set_hitbox(self, width, height, depth): |
701 self._enemy.hitbox = (width, height) | 701 self._enemy.hitbox = (width, height) |
785 | 785 |
786 @instruction(121) | 786 @instruction(121) |
787 def call_special_function(self, function, arg): | 787 def call_special_function(self, function, arg): |
788 if function == 0: # Cirno | 788 if function == 0: # Cirno |
789 if arg == 0: | 789 if arg == 0: |
790 for bullet in self._game_state.bullets: | 790 for bullet in self._game.bullets: |
791 bullet.speed = bullet.angle = 0. | 791 bullet.speed = bullet.angle = 0. |
792 bullet.delta = (0., 0.) | 792 bullet.delta = (0., 0.) |
793 bullet.set_anim(sprite_idx_offset=15) #TODO: check | 793 bullet.set_anim(sprite_idx_offset=15) #TODO: check |
794 else: | 794 else: |
795 for bullet in self._game_state.bullets: | 795 for bullet in self._game.bullets: |
796 bullet.speed = 2.0 #TODO | 796 bullet.speed = 2.0 #TODO |
797 bullet.angle = self._game_state.prng.rand_double() * pi #TODO | 797 bullet.angle = self._game.prng.rand_double() * pi #TODO |
798 bullet.delta = (cos(bullet.angle) * bullet.speed, sin(bullet.angle) * bullet.speed) | 798 bullet.delta = (cos(bullet.angle) * bullet.speed, sin(bullet.angle) * bullet.speed) |
799 else: | 799 else: |
800 logger.warn("Unimplemented special function %d!", function) | 800 logger.warn("Unimplemented special function %d!", function) |
801 | 801 |
802 | 802 |