185 lines
7.8 KiB
Python
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()
|