OpenMFOR/GUI.py

309 lines
14 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: GUI.pyc (Python 3.8)
import PySimpleGUI as ui
import zlib
import time
import threading
import os
ui.theme('SystemDefault')
tt_race = ' Generating a race seed will not generate a spoiler log. '
tt_createpatch = ' Automatically creates a .bps patch after generating a randomized game, so you can easily share with others. '
tt_difficulty = ' Higher difficulty means harder tricks. Difficulty 0 means no tricks are expected outside of vanilla strategies. '
tt_itempool = ' Limit where important items can be placed. If checked, major upgrades will only be in Data rooms, \n at bosses, or at vanilla E-tank locations. If unchecked, any item can be anywhere within logic. '
tt_missileswithupgrades = ' If checked, collecting any major Missile item will enable Missiles. Logic will account for this setting. '
tt_pbswithoutbombs = ' If checked, Power Bombs can be used without having regular Bombs. Logic will account for this setting. '
tt_damageruns = ' Allow logic to require Samus to run through damaging environments to acquire important items. \n Examples include heated rooms, electrified water, and lava. '
tt_splitsecurity = ' If checked, each door color must be unlocked independently. \n If unchecked, unlocking higher security levels will unlock all security levels below it. \n E.G.: unlocking Level 2 (Green) doors will also unlock Level 1 (Blue) doors. '
tt_SectorShuffle = ' Randomly shuffle the arrangement of the Sectors. '
tt_HideItems = ' Make all items appear as ? tanks. '
generating = False
def fileHash(fileName):
with open(fileName, 'rb') as fh:
hash = 0
while True:
s = fh.read(65536)
if not s:
break
hash = zlib.crc32(s, hash)
return hash & 0xFFFFFFFF
def rando_thread(window = None, values = None):
global fileName, basegame, failedgen, randoerror, generating, finishGenerating
values.update({
'Difficulty': int(values.get('Difficulty')) })
if values['Num']:
values.update({
'Num': int(values.get('Num')) })
else:
values.update({
'Num': 1 })
if values['Num'] < 1:
values.update({
'Num': 1 })
values.pop(0)
failedgen = False
randoerror = False
generating = True
from Randomizer import start_randomizer
if values['Debug']:
fileName = start_randomizer(basegame, values)
else:
# FIXME: let it explode
#try:
fileName = start_randomizer(basegame, values)
# finally:
# pass
#except SystemExit:
# failedgen = True
#except:
# print('An error occurred, no game was generated.')
# randoerror = True
generating = False
finishGenerating = True
def main_window(debug):
global fileName, basegame, generating, finishGenerating
itemPool = [
[
ui.Text('Charge Beam'),
ui.Radio('Shuffled', 'radioChargeBeam', default=True),
ui.Radio('Starting', 'radioChargeBeam'),
ui.Radio('Disabled', 'radioChargeBeam')],
[
ui.Text('Wide Beam'),
ui.Radio('Shuffled', 'radioWideBeam', default=True),
ui.Radio('Starting', 'radioWideBeam'),
ui.Radio('Disabled', 'radioWideBeam')],
[
ui.Text('Plasma Beam'),
ui.Radio('Shuffled', 'radioPlasmaBeam', default=True),
ui.Radio('Starting', 'radioPlasmaBeam'),
ui.Radio('Disabled', 'radioPlasmaBeam')],
[
ui.Text('Wave Beam'),
ui.Radio('Shuffled', 'radioWaveBeam', default=True),
ui.Radio('Starting', 'radioWaveBeam'),
ui.Radio('Disabled', 'radioWaveBeam')],
[
ui.Text('Ice Beam'),
ui.Radio('Shuffled', 'radioIceBeam', default=True),
ui.Radio('Starting', 'radioIceBeam'),
ui.Radio('Disabled', 'radioIceBeam')],
[
ui.Text('Missile Data'),
ui.Radio('Shuffled', 'radioMissileData', default=True),
ui.Radio('Starting', 'radioMissileData'),
ui.Radio('Disabled', 'radioMissileData')],
[
ui.Text('Super Missile Data'),
ui.Radio('Shuffled', 'radioSuperMissile', default=True),
ui.Radio('Starting', 'radioSuperMissile'),
ui.Radio('Disabled', 'radioSuperMissile')],
[
ui.Text('Ice Missile Data'),
ui.Radio('Shuffled', 'radioIceMissile', default=True),
ui.Radio('Starting', 'radioIceMissile'),
ui.Radio('Disabled', 'radioIceMissile')],
[
ui.Text('Diffusion Data'),
ui.Radio('Shuffled', 'radioDiffusion', default=True),
ui.Radio('Starting', 'radioDiffusion'),
ui.Radio('Disabled', 'radioDiffusion')],
[
ui.Text('Bombs'),
ui.Radio('Shuffled', 'radioBombs', default=True),
ui.Radio('Starting', 'radioBombs'),
ui.Radio('Disabled', 'radioBombs')],
[
ui.Text('Power Bomb Data'),
ui.Radio('Shuffled', 'radioPowerBombData', default=True),
ui.Radio('Starting', 'radioPowerBombData'),
ui.Radio('Disabled', 'radioPowerBombData')],
[
ui.Text('Hi-Jump Boots'),
ui.Radio('Shuffled', 'radioHiJump', default=True),
ui.Radio('Starting', 'radioHiJump'),
ui.Radio('Disabled', 'radioHiJump')],
[
ui.Text('Speed Booster'),
ui.Radio('Shuffled', 'radioSpeedBooster', default=True),
ui.Radio('Starting', 'radioSpeedBooster'),
ui.Radio('Disabled', 'radioSpeedBooster')],
[
ui.Text('Space Jump'),
ui.Radio('Shuffled', 'radioSpaceJump', default=True),
ui.Radio('Starting', 'radioSpaceJump'),
ui.Radio('Disabled', 'radioSpaceJump')],
[
ui.Text('Screw Attack'),
ui.Radio('Shuffled', 'radioScrewAttack', default=True),
ui.Radio('Starting', 'radioScrewAttack'),
ui.Radio('Disabled', 'radioScrewAttack')],
[
ui.Text('Varia Suit'),
ui.Radio('Shuffled', 'radioVariaSuit', default=True),
ui.Radio('Starting', 'radioVariaSuit'),
ui.Radio('Disabled', 'radioVariaSuit')],
[
ui.Text('Gravity Suit'),
ui.Radio('Shuffled', 'radioGravitySuit', default=True),
ui.Radio('Starting', 'radioGravitySuit'),
ui.Radio('Disabled', 'radioGravitySuit')],
[
ui.Text('Morph Ball'),
ui.Radio('Shuffled', 'radioMorphBall', default=True),
ui.Radio('Starting', 'radioMorphBall'),
ui.Radio('Disabled', 'radioMorphBall')],
[
ui.Text('Blue Doors (Level 1)'),
ui.Radio('Standard', 'radioBlueDoors', default=True),
ui.Radio('Starting', 'radioBlueDoors'),
ui.Radio('Shuffled', 'radioBlueDoors')],
[
ui.Text('Green Doors (Level 2)'),
ui.Radio('Standard', 'radioGreenDoors', default=True),
ui.Radio('Starting', 'radioGreenDoors'),
ui.Radio('Shuffled', 'radioGreenDoors')],
[
ui.Text('Yellow Doors (Level 3)'),
ui.Radio('Standard', 'radioYellowDoors', default=True),
ui.Radio('Starting', 'radioYellowDoors'),
ui.Radio('Shuffled', 'radioYellowDoors')],
[
ui.Text('Red Doors (Level 4)'),
ui.Radio('Standard', 'radioRedDoors', default=True),
ui.Radio('Starting', 'radioRedDoors'),
ui.Radio('Shuffled', 'radioRedDoors')]]
settings = [
[
ui.Text('Difficulty'),
ui.Slider(range=(0, 5), orientation='h', tooltip=tt_difficulty, key='Difficulty')],
[
ui.Checkbox(text='Major/minor item split', key='MajorMinor', tooltip=tt_itempool)],
[
ui.Checkbox(text='Missile upgrades enable Missiles', key='MissilesWithoutMainData', tooltip=tt_missileswithupgrades)],
[
ui.Checkbox(text='Enable Power Bombs without Bombs', key='PowerBombsWithoutBombs', tooltip=tt_pbswithoutbombs)],
[
ui.Checkbox(text='Damage runs', key='DamageRuns', tooltip=tt_damageruns)],
[
ui.Checkbox(text='Split security levels', key='SplitSecurity', tooltip=tt_splitsecurity)],
[
ui.Checkbox(text='Sector Shuffle', key='SectorShuffle', tooltip=tt_SectorShuffle)],
[
ui.Checkbox(text='Hide item graphics', key='HideItems', tooltip=tt_HideItems)],
[
ui.Checkbox(text='Race seed', key='RaceSeed', tooltip=tt_race)]]
tabLayout = [
[
ui.TabGroup([
[
ui.Tab('Logic', settings)]], tab_location='topleft')]]
layout = [
[
ui.Text('Seed value'),
ui.Input(key='Seed')],
[
tabLayout],
[
ui.Text('Number of Seeds to generate:'),
ui.Input(key='Num', size=5, justification='center', enable_events=True),
ui.Push(),
ui.Checkbox(text='Create patch', key='Patch', tooltip=tt_createpatch),
ui.Button(button_text='Generate', bind_return_key=True)]]
window = ui.Window('Open Metroid Fusion Open Randomizer', layout)
fileName = str()
finishGenerating = False
oldNum = str()
while True:
(event, values) = window.read()
if event == ui.WINDOW_CLOSED:
break
if event == 'Num':
if len(values['Num']) > 3:
window['Num'].update(oldNum)
for x in range(4):
if x < len(values['Num']):
if values['Num'][x] not in '0123456789':
window['Num'].update(oldNum)
break
else:
oldNum = values['Num']
if event == 'Generate':
basegame = ui.popup_get_file('Choose base game', no_titlebar=True, file_types=[('GBA File', '*.gba')], history=True, history_setting_filename=os.path.join('.', 'settings.json'))
if basegame == '':
ui.popup('Please select a Metroid Fusion (U) rom.', title='No source rom selected')
if basegame != None and basegame != '':
checksum = fileHash(basegame)
if checksum != 1819625372:
ui.popup('Only Metroid Fusion (U) is supported.\nCheck the CRC32 value: it should be 6C75479C', title='Bad Checksum')
else:
values.update({
'Debug': debug })
threading.Thread(target=rando_thread, args=[window, values], daemon=True).start()
window['Difficulty'].update(disabled=True)
window['MajorMinor'].update(disabled=True)
window['MissilesWithoutMainData'].update(disabled=True)
window['PowerBombsWithoutBombs'].update(disabled=True)
window['DamageRuns'].update(disabled=True)
window['SplitSecurity'].update(disabled=True)
window['SectorShuffle'].update(disabled=True)
window['HideItems'].update(disabled=True)
window['Seed'].update(disabled=True)
window['RaceSeed'].update(disabled=True)
window['Num'].update(disabled=True)
window['Patch'].update(disabled=True)
window['Generate'].update(disabled=True)
while generating:
ui.popup_animated(ui.DEFAULT_BASE64_LOADING_GIF, 'Generating game, please wait...', time_between_frames=20)
window.Refresh()
if finishGenerating:
ui.popup_animated(None)
if failedgen:
ui.popup('Could not generate a game with the current settings. Try changing your settings.', title='Metroid Fusion Open Randomizer')
elif randoerror:
ui.popup('An error occurred, no game was generated.', title='Error')
elif ui.Input.get(window['Num']) != '':
if int(ui.Input.get(window['Num'])) > 1:
ui.popup('Multiple games have been added to the seeds folder.', title='Success!')
else:
ui.popup('{}\nhas been added to the seeds folder.'.format(fileName), title='Success!')
else:
ui.popup('{}\nhas been added to the seeds folder.'.format(fileName), title='Success!')
window['Difficulty'].update(disabled=False)
window['MajorMinor'].update(disabled=False)
window['MissilesWithoutMainData'].update(disabled=False)
window['PowerBombsWithoutBombs'].update(disabled=False)
window['DamageRuns'].update(disabled=False)
window['SplitSecurity'].update(disabled=False)
window['SectorShuffle'].update(disabled=False)
window['HideItems'].update(disabled=False)
window['Seed'].update(disabled=False)
window['RaceSeed'].update(disabled=False)
window['Num'].update(disabled=False)
window['Patch'].update(disabled=False)
window['Generate'].update(disabled=False)
finishGenerating = False
window.close()