first working commit
Marco Andronaco andronacomarco@gmail.com
Wed, 06 Jul 2022 00:36:40 +0200
4 files changed,
142 insertions(+),
94 deletions(-)
M
Constants.py
→
Constants.py
@@ -1,10 +1,18 @@
#!/usr/bin/python3 +import os +from sys import platform + PATCH_VERSION = '1.1.1' FINAL_ROM_NAME = f'Mother 1+2 [T+Ita{PATCH_VERSION}].gba' STATUS_START = "Benvenutə al patcher per Mother 1+2." STATUS_PRESET = "Preset applicato." STATUS_MD5 = "MD5 verificato." +STATUS_COPIED = "File copiati." +STATUS_ASSEMBLY = "Codice compilato." +STATUS_INJECTED = "Testo inserito." +STATUS_PATCHED = "Patch applicate." +STATUS_CLEANED = "Pulizia effettuata." VAR_WINDOW_TITLE = "Mother 1+2 Patcher by Earthbound Café" VAR_FILEPICKER = "ROM giapponese di Mother 1+2"@@ -13,6 +21,8 @@ WARNING_TITLE = "Attenzione"
WARNING_EXTRACT = "È necessario estrarre l'archivio." WARNING_MD5_MISMATCH = "La ROM selezionata non è compatibile con la nostra patch." +PATH_TOOLS = os.path.join('.', 'tools') +PATH_ALT = os.path.join(PATH_TOOLS, 'alt') PRESETS = { "Scelte consigliate": {@@ -60,82 +70,49 @@ ]
} ALT_FILENAMES = { - 100: {'option': '\nFONT'}, - 1: { - 'option': 'Originale (serif)', - 'files': ['m1_gfx_font_og.bin'] - }, - 2: { - 'option': 'Tomato (sans)', - 'files': ['m1_gfx_font_new.bin'] - }, - 101: {'option': '\nSPRITE E TILE'}, - 3: { - 'option': 'Mix', - 'files': [ - 'm1_restoration_gfx_sprites_mix.bin', - 'm1_restoration_gfx_ending_us.bin', - 'm1_restoration_gfx_enemies_jp.bin', - 'm1_restoration_gfx_maptiles_jp.bin' - ] - }, - 4: { - 'option': 'US', - 'files': [ - 'm1_restoration_gfx_sprites_us.bin', - 'm1_restoration_gfx_ending_us.bin', - 'm1_restoration_gfx_enemies_us.bin', - 'm1_restoration_gfx_maptiles_us.bin' - ] - }, - 5: { - 'option': 'JP', - 'files': [ - 'm1_restoration_gfx_sprites_jp.bin', - 'm1_restoration_gfx_ending_jp.bin', - 'm1_restoration_gfx_enemies_jp.bin', - 'm1_restoration_gfx_maptiles_jp.bin' - ] - }, - 102: {'option': '\nLUOGHI'}, - 6: { - 'option': 'US', - 'files': [ - 'm1_main_text_us.txt', - 'm1_gfx_map_us.bin' - ] - }, - 7: { - 'option': 'JP', - 'files': [ - 'm1_main_text_jp.txt', - 'm1_gfx_map_jp.bin' - ] - }, - 103: {'option': '\nPALETTE'}, - 8: { - 'option': 'NES', - 'files': 'nes.ips' - }, - 9: { - 'option': 'GBA', - 'files': None - }, - 10: { - 'option': 'Nintendo Classic Mini - NES', - 'files': 'ncm.ips' - }, - 11: { - 'option': 'Virtual Console Wii e Wii U', - 'files': 'vc.ips' - }, - 104: {'option': '\nSKIP A MOTHER 1?'}, - 12: { - 'option': 'Sì', - 'files': 'skipm1.ips' - }, - 13: { - 'option': 'No', - 'files': None - } -}+ 1: ['m1_gfx_font_og.bin'], + + 2: ['m1_gfx_font_new.bin'], + + 3: ['m1_restoration_gfx_sprites_mix.bin', + 'm1_restoration_gfx_ending_us.bin', + 'm1_restoration_gfx_enemies_jp.bin', + 'm1_restoration_gfx_maptiles_jp.bin'], + + 4: ['m1_restoration_gfx_sprites_us.bin', + 'm1_restoration_gfx_ending_us.bin', + 'm1_restoration_gfx_enemies_us.bin', + 'm1_restoration_gfx_maptiles_us.bin'], + + 5: ['m1_restoration_gfx_sprites_jp.bin', + 'm1_restoration_gfx_ending_jp.bin', + 'm1_restoration_gfx_enemies_jp.bin', + 'm1_restoration_gfx_maptiles_jp.bin'], + + 6: ['m1_main_text_us.txt', + 'm1_gfx_map_us.bin'], + + 7: ['m1_main_text_jp.txt', + 'm1_gfx_map_jp.bin'], + + 8: 'nes.ips', + 9: None, + 10: 'ncm.ips', + 11: 'vc.ips', + 12: 'skipm1.ips', + 13: None +} + +OS_SUFFIX = ( + '.exe' if platform.startswith('win32') else + '_mac' if platform.startswith('darwin') + else '' +) + +OS_FILENAMES = { + 'xkas': os.path.join('.', 'xkas' + OS_SUFFIX), + 'insert': os.path.join('.', 'insert' + OS_SUFFIX), + 'introconv': os.path.join('.', 'introconv' + OS_SUFFIX) +} + +OS_SHELL = True if os.name == 'nt' else False
M
Functions.py
→
Functions.py
@@ -1,7 +1,11 @@
#!/usr/bin/python3 from hashlib import md5 from tkinter.messagebox import showwarning +from ips_util import Patch +from shutil import copyfile +import os, subprocess import Constants + def check_rom(filename): if filename == '':@@ -13,5 +17,75 @@ file_hash.update(chunk)
return file_hash.hexdigest() == 'f41e36204356974c94fabf7d144dd32a' +def apply_patch(base, ips): + patch = Patch.load(ips) + target = base + '_temp' + + with open(base, 'rb') as f_in: + with open(target, 'w+b') as f_out: + f_out.write(patch.apply(f_in.read())) + + os.replace(target, base) + def show_warning(message): - showwarning(title=Constants.WARNING_TITLE, message=message)+ showwarning(title=Constants.WARNING_TITLE, message=message) + +def set_progress(app, percent, message): + app.progress.set(percent) + app.progress_text.set(message) + +def start_patching(app): + set_progress(app, 20, Constants.STATUS_MD5) + delete_list = [] + + sel_filenames = { + 'font': Constants.ALT_FILENAMES[app.font.get()], + 'sprites': Constants.ALT_FILENAMES[app.sprites.get()], + 'places': Constants.ALT_FILENAMES[app.places.get()] + } + + sel_patches = { + 'palette': Constants.ALT_FILENAMES[app.palette.get()], + 'skip_m1': Constants.ALT_FILENAMES[app.skip_m1.get()] + } + + for key in sel_filenames.keys(): + sel_list = sel_filenames[key] + def_list = Constants.DEF_FILENAMES[key] + + for idx, i in enumerate(sel_list): + original = os.path.join(Constants.PATH_ALT, sel_list[idx]) + target = os.path.join(Constants.PATH_TOOLS, def_list[idx]) + + copyfile(original, target) + delete_list.append(target) + + target = os.path.join(Constants.PATH_TOOLS, 'test.gba') + copyfile(app.baserom, target) + + set_progress(app, 40, Constants.STATUS_COPIED) + p = subprocess.Popen([Constants.OS_FILENAMES['xkas'], '-o', 'test.gba', 'm12.asm'], + cwd=Constants.PATH_TOOLS, shell=Constants.OS_SHELL) + p.wait() + + set_progress(app, 50, Constants.STATUS_ASSEMBLY) + p = subprocess.Popen([Constants.OS_FILENAMES['insert']], + cwd=Constants.PATH_TOOLS, shell=Constants.OS_SHELL) + p.wait() + + set_progress(app, 70, Constants.STATUS_INJECTED) + for key in sel_patches.keys(): + val = sel_patches[key] + + if val is not None: + path = os.path.join(Constants.PATH_ALT, val) + apply_patch(target, path) + + os.replace(target, Constants.FINAL_ROM_NAME) + + set_progress(app, 90, Constants.STATUS_PATCHED) + for item in delete_list: + os.remove(item) + + set_progress(app, 100, Constants.STATUS_CLEANED) +
M
Gui.py
→
Gui.py
@@ -4,7 +4,7 @@ from tkinter.filedialog import askopenfilename
import pathlib import pygubu import Constants -from Functions import check_rom, show_warning +from Functions import check_rom, show_warning, start_patching PROJECT_PATH = pathlib.Path(__file__).parent PROJECT_UI = PROJECT_PATH / "patcher.ui"@@ -44,7 +44,7 @@ self.font.set(1)
self.sprites.set(3) self.places.set(6) self.palette.set(8) - self.skip_m1.set(1) + self.skip_m1.set(12) self.progress_text.set(Constants.STATUS_START) self.apply_button = builder.get_object("apply_button")@@ -53,12 +53,6 @@ if baserom is not None:
self.browse_path.set(baserom) builder.connect_callbacks(self) - - def set_progress(self, percent, message): - self.progress.set(percent) - self.progress_text.set(message) - - def run(self): self.mainwindow.mainloop()@@ -77,8 +71,11 @@
def on_apply_button(self): self.apply_button['state'] = 'disabled' - if check_rom(self.browse_path.get()): - self.set_progress(20, Constants.STATUS_MD5) - else: + baserom_temp = self.browse_path.get() + + if not check_rom(baserom_temp): show_warning(Constants.WARNING_MD5_MISMATCH) - self.apply_button['state'] = 'normal'+ self.apply_button['state'] = 'normal' + return + self.baserom = baserom_temp + start_patching(self)
M
patcher.ui
→
patcher.ui
@@ -266,8 +266,8 @@ <property name="sticky">ew</property>
</layout> <child> <object class="ttk.Checkbutton" id="skip_m1_check"> - <property name="offvalue">0</property> - <property name="onvalue">1</property> + <property name="offvalue">13</property> + <property name="onvalue">12</property> <property name="text" translatable="yes">Avvia automaticamente Mother 1</property> <property name="variable">int:skip_m1</property> <layout manager="pack">