comparison eosd @ 373:6deab6ad8be8

Add the ability to save a replay.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Sun, 05 Aug 2012 16:37:26 +0200
parents 704bea2e4360
children 8f2f3053906a
comparison
equal deleted inserted replaced
372:704bea2e4360 373:6deab6ad8be8
25 from pytouhou.game.background import Background 25 from pytouhou.game.background import Background
26 from pytouhou.ui.gamerunner import GameRunner 26 from pytouhou.ui.gamerunner import GameRunner
27 from pytouhou.games.eosd import EoSDGame 27 from pytouhou.games.eosd import EoSDGame
28 from pytouhou.game.game import GameOver 28 from pytouhou.game.game import GameOver
29 from pytouhou.game.player import PlayerState 29 from pytouhou.game.player import PlayerState
30 from pytouhou.formats.t6rp import T6RP 30 from pytouhou.formats.t6rp import T6RP, Level
31 from pytouhou.utils.random import Random 31 from pytouhou.utils.random import Random
32 from pytouhou.vm.msgrunner import NextStage 32 from pytouhou.vm.msgrunner import NextStage
33 33
34 34
35 class EoSDGameBossRush(EoSDGame): 35 class EoSDGameBossRush(EoSDGame):
60 self.bullets = [bullet for bullet in self.bullets if bullet.frame > 1] 60 self.bullets = [bullet for bullet in self.bullets if bullet.frame > 1]
61 EoSDGame.cleanup(self) 61 EoSDGame.cleanup(self)
62 62
63 63
64 64
65 def main(path, data, stage_num, rank, character, replay, boss_rush, fps_limit, single_buffer, debug, fixed_pipeline): 65 def main(path, data, stage_num, rank, character, replay, save_filename,
66 boss_rush, fps_limit, single_buffer, debug, fixed_pipeline):
67
66 resource_loader = Loader(path) 68 resource_loader = Loader(path)
67 69
68 try: 70 try:
69 resource_loader.scan_archives(data) 71 resource_loader.scan_archives(data)
70 except IOError: 72 except IOError:
87 with open(replay, 'rb') as file: 89 with open(replay, 'rb') as file:
88 replay = T6RP.read(file) 90 replay = T6RP.read(file)
89 rank = replay.rank 91 rank = replay.rank
90 character = replay.character 92 character = replay.character
91 93
94 save_keystates = None
95 if save_filename:
96 save_replay = T6RP()
97 save_replay.rank = rank
98 save_replay.character = character
99
92 difficulty = 16 100 difficulty = 16
93 default_power = [0, 64, 128, 128, 128, 128, 0][stage_num - 1] 101 default_power = [0, 64, 128, 128, 128, 128, 0][stage_num - 1]
94 states = [PlayerState(character=character, power=default_power)] 102 states = [PlayerState(character=character, power=default_power)]
95 103
96 game_class = EoSDGameBossRush if boss_rush else EoSDGame 104 game_class = EoSDGameBossRush if boss_rush else EoSDGame
108 #TODO: see if the stored score is used or if it’s the one from the previous stage. 116 #TODO: see if the stored score is used or if it’s the one from the previous stage.
109 if stage_num != 1 and stage_num - 2 in replay.levels: 117 if stage_num != 1 and stage_num - 2 in replay.levels:
110 previous_level = replay.levels[stage_num - 1] 118 previous_level = replay.levels[stage_num - 1]
111 states[0].score = previous_level.score 119 states[0].score = previous_level.score
112 states[0].effective_score = previous_level.score 120 states[0].effective_score = previous_level.score
121 states[0].point_items = level.point_items
113 states[0].power = level.power 122 states[0].power = level.power
114 states[0].lives = level.lives 123 states[0].lives = level.lives
115 states[0].bombs = level.bombs 124 states[0].bombs = level.bombs
116 difficulty = level.difficulty 125 difficulty = level.difficulty
117 else: 126 else:
118 prng = None 127 prng = Random()
128
129 if save_filename:
130 if not replay:
131 save_replay.levels[stage_num - 1] = level = Level()
132 level.score = states[0].score
133 level.random_seed = prng.seed
134 level.point_items = states[0].points
135 level.power = states[0].power
136 level.lives = states[0].lives
137 level.bombs = states[0].bombs
138 level.difficulty = difficulty
139 save_keystates = []
119 140
120 # Load stage data 141 # Load stage data
121 stage = resource_loader.get_stage('stage%d.std' % stage_num) 142 stage = resource_loader.get_stage('stage%d.std' % stage_num)
122 143
123 game = game_class(resource_loader, states, stage_num, rank, difficulty, prng=prng, continues=continues) 144 game = game_class(resource_loader, states, stage_num, rank, difficulty, prng=prng, continues=continues)
124 145
125 background_anm_wrapper = resource_loader.get_anm_wrapper(('stg%dbg.anm' % stage_num,)) 146 background_anm_wrapper = resource_loader.get_anm_wrapper(('stg%dbg.anm' % stage_num,))
126 background = Background(stage, background_anm_wrapper) 147 background = Background(stage, background_anm_wrapper)
127 148
128 # Main loop 149 # Main loop
129 runner.load_game(game, background, stage.bgms, replay) 150 runner.load_game(game, background, stage.bgms, replay, save_keystates)
130 try: 151 try:
131 runner.start() 152 runner.start()
132 break 153 break
133 except NextStage: 154 except NextStage:
134 game.music.pause() 155 game.music.pause()
137 stage_num += 1 158 stage_num += 1
138 states = [player.state.copy() for player in game.players] # if player.state.lives >= 0] 159 states = [player.state.copy() for player in game.players] # if player.state.lives >= 0]
139 except GameOver: 160 except GameOver:
140 print('Game over') 161 print('Game over')
141 break 162 break
163 finally:
164 if save_filename:
165 last_key = -1
166 for time, key in enumerate(save_keystates):
167 if key != last_key:
168 level.keys.append((time, key, 0))
169 last_key = key
170
171 if save_filename:
172 with open(save_filename, 'wb+') as file:
173 save_replay.write(file)
142 174
143 175
144 pathsep = os.path.pathsep 176 pathsep = os.path.pathsep
145 default_data = (pathsep.join(('CM.DAT', 'th06*_CM.DAT', '*CM.DAT', '*cm.dat')), 177 default_data = (pathsep.join(('CM.DAT', 'th06*_CM.DAT', '*CM.DAT', '*cm.dat')),
146 pathsep.join(('ST.DAT', 'th6*ST.DAT', '*ST.DAT', '*st.dat')), 178 pathsep.join(('ST.DAT', 'th6*ST.DAT', '*ST.DAT', '*st.dat')),
155 parser.add_argument('-p', '--path', metavar='DIRECTORY', default='.', help='Game directory path.') 187 parser.add_argument('-p', '--path', metavar='DIRECTORY', default='.', help='Game directory path.')
156 parser.add_argument('-s', '--stage', metavar='STAGE', type=int, default=None, help='Stage, 1 to 7 (Extra).') 188 parser.add_argument('-s', '--stage', metavar='STAGE', type=int, default=None, help='Stage, 1 to 7 (Extra).')
157 parser.add_argument('-r', '--rank', metavar='RANK', type=int, default=0, help='Rank, from 0 (Easy, default) to 3 (Lunatic).') 189 parser.add_argument('-r', '--rank', metavar='RANK', type=int, default=0, help='Rank, from 0 (Easy, default) to 3 (Lunatic).')
158 parser.add_argument('-c', '--character', metavar='CHARACTER', type=int, default=0, help='Select the character to use, from 0 (ReimuA, default) to 3 (MarisaB).') 190 parser.add_argument('-c', '--character', metavar='CHARACTER', type=int, default=0, help='Select the character to use, from 0 (ReimuA, default) to 3 (MarisaB).')
159 parser.add_argument('--replay', metavar='REPLAY', help='Select a replay') 191 parser.add_argument('--replay', metavar='REPLAY', help='Select a replay')
192 parser.add_argument('--save-replay', metavar='REPLAY', help='Save the upcoming game into a replay file')
160 parser.add_argument('-b', '--boss-rush', action='store_true', help='Fight only bosses') 193 parser.add_argument('-b', '--boss-rush', action='store_true', help='Fight only bosses')
161 parser.add_argument('--single-buffer', action='store_true', help='Disable double buffering') 194 parser.add_argument('--single-buffer', action='store_true', help='Disable double buffering')
162 parser.add_argument('--fps-limit', metavar='FPS', default=60, type=int, help='Set fps limit') 195 parser.add_argument('--fps-limit', metavar='FPS', default=60, type=int, help='Set fps limit')
163 parser.add_argument('--debug', action='store_true', help='Set unlimited continues, and perhaps other debug features.') 196 parser.add_argument('--debug', action='store_true', help='Set unlimited continues, and perhaps other debug features.')
164 parser.add_argument('--fixed-pipeline', action='store_true', help='Use the fixed pipeline instead of the new programmable one.') 197 parser.add_argument('--fixed-pipeline', action='store_true', help='Use the fixed pipeline instead of the new programmable one.')
165 198
166 args = parser.parse_args() 199 args = parser.parse_args()
167 200
168 main(args.path, tuple(args.data), args.stage, args.rank, args.character, 201 main(args.path, tuple(args.data), args.stage, args.rank, args.character,
169 args.replay, args.boss_rush, args.fps_limit, args.single_buffer, 202 args.replay, args.save_replay, args.boss_rush, args.fps_limit,
170 args.debug, args.fixed_pipeline) 203 args.single_buffer, args.debug, args.fixed_pipeline)