| 
									
										
										
										
											2022-10-20 10:41:11 -07:00
										 |  |  | import os | 
					
						
							| 
									
										
										
										
											2024-11-29 12:25:01 -08:00
										 |  |  | from typing import BinaryIO | 
					
						
							| 
									
										
										
										
											2024-03-03 13:10:14 -08:00
										 |  |  | import zipfile | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from typing_extensions import override | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import Utils | 
					
						
							| 
									
										
										
										
											2024-03-14 14:29:29 -07:00
										 |  |  | from worlds.Files import APAutoPatchInterface | 
					
						
							| 
									
										
										
										
											2024-03-03 13:10:14 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | from zilliandomizer.patch import Patcher | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from .gen_data import GenData | 
					
						
							| 
									
										
										
										
											2022-10-20 10:41:11 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-29 12:25:01 -08:00
										 |  |  | US_HASH = "d4bf9e7bcf9a48da53785d2ae7bc4270" | 
					
						
							| 
									
										
										
										
											2022-10-20 10:41:11 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-14 14:29:29 -07:00
										 |  |  | class ZillionPatch(APAutoPatchInterface): | 
					
						
							| 
									
										
										
										
											2024-11-29 12:25:01 -08:00
										 |  |  |     hash = US_HASH | 
					
						
							| 
									
										
										
										
											2022-10-20 10:41:11 -07:00
										 |  |  |     game = "Zillion" | 
					
						
							|  |  |  |     patch_file_ending = ".apzl" | 
					
						
							|  |  |  |     result_file_ending = ".sms" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-03 13:10:14 -08:00
										 |  |  |     gen_data_str: str | 
					
						
							|  |  |  |     """ JSON encoded """ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-29 12:25:01 -08:00
										 |  |  |     def __init__(self, | 
					
						
							|  |  |  |                  path: str | None = None, | 
					
						
							|  |  |  |                  player: int | None = None, | 
					
						
							|  |  |  |                  player_name: str = "", | 
					
						
							|  |  |  |                  server: str = "", | 
					
						
							|  |  |  |                  *, | 
					
						
							|  |  |  |                  gen_data_str: str = "") -> None: | 
					
						
							|  |  |  |         super().__init__(path=path, player=player, player_name=player_name, server=server) | 
					
						
							| 
									
										
										
										
											2024-03-03 13:10:14 -08:00
										 |  |  |         self.gen_data_str = gen_data_str | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-20 10:41:11 -07:00
										 |  |  |     @classmethod | 
					
						
							|  |  |  |     def get_source_data(cls) -> bytes: | 
					
						
							|  |  |  |         with open(get_base_rom_path(), "rb") as stream: | 
					
						
							|  |  |  |             return read_rom(stream) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-03 13:10:14 -08:00
										 |  |  |     @override | 
					
						
							|  |  |  |     def write_contents(self, opened_zipfile: zipfile.ZipFile) -> None: | 
					
						
							|  |  |  |         super().write_contents(opened_zipfile) | 
					
						
							|  |  |  |         opened_zipfile.writestr("gen_data.json", | 
					
						
							|  |  |  |                                 self.gen_data_str, | 
					
						
							|  |  |  |                                 compress_type=zipfile.ZIP_DEFLATED) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @override | 
					
						
							|  |  |  |     def read_contents(self, opened_zipfile: zipfile.ZipFile) -> None: | 
					
						
							|  |  |  |         super().read_contents(opened_zipfile) | 
					
						
							|  |  |  |         self.gen_data_str = opened_zipfile.read("gen_data.json").decode() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-29 12:25:01 -08:00
										 |  |  |     @override | 
					
						
							| 
									
										
										
										
											2024-03-03 13:10:14 -08:00
										 |  |  |     def patch(self, target: str) -> None: | 
					
						
							|  |  |  |         self.read() | 
					
						
							|  |  |  |         write_rom_from_gen_data(self.gen_data_str, target) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-20 10:41:11 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-29 12:25:01 -08:00
										 |  |  | def get_base_rom_path(file_name: str | None = None) -> str: | 
					
						
							|  |  |  |     from . import ZillionSettings, ZillionWorld | 
					
						
							|  |  |  |     settings: ZillionSettings = ZillionWorld.settings | 
					
						
							| 
									
										
										
										
											2022-10-20 10:41:11 -07:00
										 |  |  |     if not file_name: | 
					
						
							| 
									
										
										
										
											2024-11-29 12:25:01 -08:00
										 |  |  |         file_name = settings.rom_file | 
					
						
							| 
									
										
										
										
											2022-10-20 10:41:11 -07:00
										 |  |  |     if not os.path.exists(file_name): | 
					
						
							|  |  |  |         file_name = Utils.user_path(file_name) | 
					
						
							|  |  |  |     return file_name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def read_rom(stream: BinaryIO) -> bytes: | 
					
						
							|  |  |  |     """ reads rom into bytearray """ | 
					
						
							|  |  |  |     data = stream.read() | 
					
						
							|  |  |  |     # I'm not aware of any sms header. | 
					
						
							|  |  |  |     return data | 
					
						
							| 
									
										
										
										
											2024-03-03 13:10:14 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def write_rom_from_gen_data(gen_data_str: str, output_rom_file_name: str) -> None: | 
					
						
							|  |  |  |     """ take the output of `GenData.to_json`, and create rom from it """ | 
					
						
							|  |  |  |     gen_data = GenData.from_json(gen_data_str) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     base_rom_path = get_base_rom_path() | 
					
						
							|  |  |  |     zz_patcher = Patcher(base_rom_path) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     zz_patcher.write_locations(gen_data.zz_game.regions, gen_data.zz_game.char_order[0]) | 
					
						
							|  |  |  |     zz_patcher.all_fixes_and_options(gen_data.zz_game) | 
					
						
							|  |  |  |     zz_patcher.set_external_item_interface(gen_data.zz_game.char_order[0], gen_data.zz_game.options.max_level) | 
					
						
							|  |  |  |     zz_patcher.set_multiworld_items(gen_data.multi_items) | 
					
						
							|  |  |  |     zz_patcher.set_rom_to_ram_data(gen_data.game_id) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     patched_rom_bytes = zz_patcher.get_patched_bytes() | 
					
						
							|  |  |  |     with open(output_rom_file_name, "wb") as binary_file: | 
					
						
							|  |  |  |         binary_file.write(patched_rom_bytes) |