OpenMFOR/MFOR.py
2024-09-04 02:17:32 +02:00

185 lines
7.8 KiB
Python

# OpenMFOR
# credits manually reinstated due to the comments being lost from the object code decompilation
# Original release is Copyright (C) 2022 Kazuto88
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# Source Generated with Decompyle++
# File: MFOR.pyc (Python 3.8)
import argparse
import random
import sys
import zlib
from datetime import datetime
from pathlib import Path
version = '2024.02.10+chozo1'
def main():
parser = argparse.ArgumentParser(description=f'''Metroid Fusion Open Randomizer v{version}''')
parser.add_argument('-file', help='Path to unmodified game (Metroid Fusion (U).gba)')
parser.add_argument('-seed', default=None, help='Optional seed value')
parser.add_argument('-difficulty', choices=['0','1','2','3','4','5','r'], default='0', help='Trick difficulty level 0-5 (default 0)')
parser.add_argument('-race', choices=['t','f','r'], default='f', help='Generate race seed (no spoiler log)')
parser.add_argument('-hidden', choices=['t','f','r'], default='f', help='All items use ? tank graphics')
parser.add_argument('-limit', choices=['t','f','r'], default='f', help='Major/minor item pool')
parser.add_argument('-missiles', choices=['t','f','r'], default='f', help='Missile upgrades enable the Missile launcher (default f)')
parser.add_argument('-bombs', choices=['t','f','r'], default='f', help='Enable Power Bombs without normal Bombs (default f)')
parser.add_argument('-hazards', choices=['t','f','r'], default='f', help='Logic allows hazard runs (default f)')
parser.add_argument('-security', choices=['t','f','r'], default='f', help='Split security: if split, security stations only unlock their specific security level. By default, higher level security stations will unlock all lesser security levels.')
parser.add_argument('-sectors', choices=['t','f','r'], default='f', help='Choose whether to shuffle the arrangement of the Sectors')
parser.add_argument('-tubes', choices=['t','f','r'], default='f', help='Choose whether to shuffle the tube connections between the Sectors')
parser.add_argument('-palettes', help='Enable palette shuffle: [t]ilesets, [b]eams, [s]uits, s[p]rites')
parser.add_argument('-num', default=1, help='Number of seeds to generate')
parser.add_argument('-patch', default=False, action='store_true', help='Generate BPS patch for easy sharing')
args = parser.parse_args()
if not hasattr(args, "debug"):
args.debug = False
if args.file:
from Randomizer import start_randomizer
settings = dict()
logic = list()
settings.update({"-SEED-": (args.seed)})
if args.difficulty == "r":
args.difficulty = random.randrange(6)
logic.append(f"Difficulty: {args.difficulty}")
else:
args.difficulty = int(args.difficulty)
if args.race == "r":
args.race = random.choice([True, False])
logic.append(f"Race: {args.race}")
elif args.race == "t":
args.race = True
else:
args.race = False
if args.hidden == "r":
args.hidden = random.choice([True, False])
logic.append(f"Hide items: {args.hidden}")
elif args.hidden == "t":
args.hidden = True
else:
args.hidden = False
if args.limit == "r":
args.limit = random.choice([True, False])
logic.append(f"Major/minor: {args.limit}")
elif args.limit == "t":
args.limit = True
else:
args.limit = False
if args.missiles == "r":
args.missiles = random.choice([True, False])
logic.append(f'Missile launcher: {"any" if args.missiles else "main"}')
elif args.missiles == "t":
args.missiles = True
else:
args.missiles = False
if args.bombs == "r":
args.bombs = random.choice([True, False])
logic.append(f'Power Bombs require: {"data" if args.bombs else "bombs"}')
elif args.bombs == "t":
args.bombs = True
else:
args.bombs = False
if args.hazards == "r":
args.hazards = random.choice([True, False])
logic.append(f"Hazard runs: {args.hazards}")
elif args.hazards == "t":
args.hazards = True
else:
args.hazards = False
if args.security == "r":
args.security = random.choice([True, False])
logic.append(f"Split security: {args.security}")
elif args.security == "t":
args.security = True
else:
args.security = False
if args.sectors == "r":
args.sectors = random.choice([True, False])
logic.append(f"Shuffle Sectors: {args.sectors}")
elif args.sectors == "t":
args.sectors = True
else:
args.sectors = False
if args.tubes == "r":
args.tubes = random.choice([True, False])
logic.append(f"Shuffle tubes: {args.tubes}")
elif args.tubes == "t":
args.tubes = True
else:
args.tubes = False
settings.update({"-DIFFICULTY-": (args.difficulty)})
settings.update({"-RACE-": (args.race)})
settings.update({"-HIDEITEMS-": (args.hidden)})
settings.update({"-MAJORMINOR-": (args.limit)})
settings.update({"-MISSILEDATA-": (args.missiles)})
settings.update({"-PBDATA-": (args.bombs)})
settings.update({"-HAZARDRUNS-": (args.hazards)})
settings.update({"-SPLITSECURITY-": (args.security)})
settings.update({"-SHUFFLESECTORS-": (args.sectors)})
settings.update({"-SHUFFLETUBES-": (args.tubes)})
if args.num:
args.num = int(args.num)
if args.num < 1:
args.num = 1
settings.update({"-NUM-": (args.num)})
else:
settings.update({"-NUM-": 1})
settings.update({"-PATCH-": (args.patch)})
settings.update({"Debug": (args.debug)})
settings.update({"-PALTILESETS-": False})
settings.update({"-PALSPRITES-": False})
settings.update({"-PALSUITS-": False})
settings.update({"-PALBEAMS-": False})
if args.palettes:
if "t" in args.palettes:
settings.update({"-PALTILESETS-": True})
if "b" in args.palettes:
settings.update({"-PALBEAMS-": True})
if "s" in args.palettes:
settings.update({"-PALSUITS-": True})
if "p" in args.palettes:
settings.update({"-PALSPRITES-": True})
settings = {key: settings[key] for key in sorted(settings.keys())}
start_randomizer(args.file, settings)
if len(logic) > 0:
print("\nRandom settings:")
for item in logic:
print(item)
else:
import GUI
GUI.main_window(args.debug)
def _init():
checksum = file_hash(Path.cwd() / 'data' / 'MFOR.bps')
if checksum != 558161692:
sys.exit('Error: Core files could not be read. Please go to https://metroidconstruction.com/ and re-download MFOR.')
Path(Path.cwd() / 'seeds').mkdir(exist_ok=True)
Path(Path.cwd() / 'spoilers').mkdir(exist_ok=True)
def file_hash(file):
checksum = 0
try:
with open(file, 'rb') as source:
while True:
s = source.read(65536)
if not s:
break
checksum = zlib.crc32(s, checksum)
except FileNotFoundError:
sys.exit('Error:', file, 'could not be opened.')
return checksum & 0xFFFFFFFF
if __name__ == '__main__':
_init()
main()