Compare commits

...

8 commits

Author SHA1 Message Date
2a73e487a5 impromptu cli bugfix 2024-09-04 02:17:32 +02:00
1523860c9a Merge from 2024.02.10+chozo1 into master
Reviewed-on: #1
2024-09-03 20:30:48 +00:00
a36c9a95f0 update readme 2024-09-03 12:20:14 +02:00
fe6fa75972 fix boss item placement + update flips submodule 2024-09-03 11:49:03 +02:00
672cf3ca23 upload last edits 2024-09-03 01:47:49 +02:00
01dee434bd wip: fix boss/dataroom placement act2 2024-09-03 00:23:28 +02:00
367fdd75ec wip: fix boss/dataroom placement? 2024-09-02 23:33:35 +02:00
0c17440bde fix icon 2024-09-02 22:51:09 +02:00
5 changed files with 72 additions and 36 deletions

2
GUI.py
View file

@ -227,7 +227,7 @@ def main_window(debug):
sg.Push(),
sg.Checkbox(text='Create patch', key='-PATCH-', tooltip=tt_patch),
sg.Button(button_text='Generate', bind_return_key=True)]]
window = sg.Window('Open Metroid Fusion Open Randomizer', layout, icon=str(Path(__file__).parent / 'data' / 'MFOR.ico'))
window = sg.Window('Open Metroid Fusion Open Randomizer', layout, icon=str(Path.cwd() / 'data' / 'MFOR.ico'))
file_name = str()
finish_generating = False
old_num = str()

13
MFOR.py
View file

@ -146,12 +146,13 @@ def main():
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)
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

View file

@ -25,7 +25,8 @@ Caveat emptor: the project is already diverging from the original decompilation
- [x] Reconstructing missing parts of code
- [x] Patching
- [x] Generating BPS patches (python-bps-continued used to apply base patch as it's platform independent, but FLIPS to generate BPS files)
- [ ] Potentially merging/reimplementing the new features from v2024.02.10
- [x] Potentially merging/reimplementing the new features from v2024.02.10
- [ ] Merging the logic edits from v2024.02.10
- [ ] Solver refactoring
- [x] CI/CD for Windows frozen builds
@ -39,6 +40,10 @@ Caveat emptor: the project is already diverging from the original decompilation
- ????
- PROFIT
Prebuilt release builds might be available on the [releases](https://git.inabaudonge.reisen/OpenMFOR/OpenMFOR/releases) tab.
If you feel more inclined testing the tip of the development branches or playing with the logic, part of the following guide can be used on Windows too to run the randomizer from sources rather than PyInstaller packed executables.
## Install (any OS)
On *NIX OSes, the only strict prerequisites are Python 3.x and pip. For the GUI, sourcing `python3-tk` from your package manager is highly recommended.
@ -71,7 +76,6 @@ The randomizer currently works **only** with the USA (and, by proxy, the Austral
## Help
* [OpenMFOR Discord guild](https://discord.gg/QV3p8MWKab) since we've been told to refrain to bring this up on the wider community server over ongoing diplomacy issues.
* soon™ we might have an IRC channel or a Matrix group bridged to the Discord guild.
## Special Thanks
@ -81,6 +85,7 @@ The randomizer currently works **only** with the USA (and, by proxy, the Austral
- [tcprescott's python-bps-continued](https://github.com/tcprescott/python-bps-continued) since this makes at least rolling the seeds completely platform independent.
- [Alcaro's Floating IPS](https://github.com/Alcaro/Flips)
- Fedor Batogonov's [docker-pyinstaller](https://gitlab.com/batonogov/docker-pyinstaller) used by the CI/CD to make Windows builds on AppVeyor
- The testers in the various Discord guilds that are spotting the massive scams before I do! (SkullAdult, Mr. Fox, baria, Fpiz_, jakoliath)
[Kazuto88](https://github.com/Kazuto88) being the original randomizer developer. The following lines are his special thanks to the people that contributed to making this a reality:

View file

@ -2188,15 +2188,15 @@ def randomize_game(graph):
MajorList = list(WeightedMajors.keys())
if SeedSettings['-MISSILEDATA-']:
WeightedMajors.update({'MainMissiles': 8})
WeightedMajors.update({'SuperMissileItem': 8})
WeightedMajors.update({'IceMissileItem': 8})
WeightedMajors.update({'DiffusionItem': 8})
WeightedMajors.update({'MainMissiles': 4})
WeightedMajors.update({'SuperMissileItem': 4})
WeightedMajors.update({'IceMissileItem': 4})
WeightedMajors.update({'DiffusionItem': 4})
if SeedSettings['-PBDATA-']:
WeightedMajors.update({'Bombs': 10})
WeightedMajors.update({'MainPowerBombs': 10})
WeightedMajors.update({'Bombs': 3})
WeightedMajors.update({'MainPowerBombs': 3})
if SeedSettings['-HAZARDRUNS-']:
WeightedMajors.update({'VariaSuit': 4})
WeightedMajors.update({'VariaSuit': 3})
MajorWeights = list(WeightedMajors.values())
MajorWeights.pop(MajorList.index('Bombs'))
MajorList.remove('Bombs')
@ -2746,15 +2746,24 @@ def patch_game():
roomEventOffset = int(sym.get('t_bossanddownloadevents'), 16)
itemEventOffset = int(sym.get('t_obtainitemevents'), 16)
securityOffset = int(sym.get('b_unlocklowerlevels'), 16)
print('roomEventOffset: 0x{:06X}'.format(roomEventOffset))
print('itemEventOffset: 0x{:06X}'.format(itemEventOffset))
print('securityOffset: 0x{:06X}'.format(securityOffset))
saxAnyOffset = int(sym.get('@t_saxany'), 16)
spawnBox = int(sym.get('@spawnbox'), 16)
spawnMegaCoreX = int(sym.get('@spawnmegacorex'), 16)
print('Debug values')
print(f'''roomEventOffset={roomEventOffset:06X}''')
print(f'''itemEventOffset={itemEventOffset:06X}''')
print(f'''securityOffset={securityOffset:06X}''')
print(f'''saxAnyOffset={saxAnyOffset:06X}''')
print(f'''spawnBox={spawnBox:06X}''')
print(f'''spawnMegaCoreX={spawnMegaCoreX:06X}''')
else:
roomEventOffset = 8326320
roomEventOffset = 8326304
itemEventOffset = 5726112
securityOffset = 479192
saxAnyOffset = 395796
spawnBox = 8326096
spawnMegaCoreX = 8326260
for area in RoomNodes:
areaIndex = list(RoomNodes.keys()).index(area)
for node in RoomNodes[area]:
name = node.get('Name')
nodeType = node.get('Type')
@ -2778,6 +2787,7 @@ def patch_game():
blockValue = 3
else:
blockValue = ItemList.index(itemName)
if blockValue < 2:
blockValue = blockValue ^ 1
elif blockValue > 2:
@ -2791,6 +2801,7 @@ def patch_game():
blockValue = 7
else:
blockValue = 3
blockValue += 70
if tileset == 9:
blockValue += 1
@ -2822,6 +2833,7 @@ def patch_game():
blockValue += 1
elif tileset == 72:
blockValue += 1
clipValue = ItemList.index(itemName)
if clipValue < 2:
# Energy Tank or Missile Tank
@ -2842,18 +2854,21 @@ def patch_game():
clipValue += 1
elif 'Underwater' in nodeType:
clipValue += 2
if 'Hidden' not in nodeType:
patchedGame.seek(bg1)
patchedGame.write(blockValue.to_bytes(1, 'little'))
patchedGame.seek(clipdata)
patchedGame.write(clipValue.to_bytes(1, 'little'))
elif 'Boss' in nodeType or 'Data' in nodeType:
if 'Boss' in nodeType or 'Data' in nodeType:
itemName = PlacedItems[UsedLocations.index(name)]
itemValue = ItemList.index(itemName)
slot = BossDataList.index(name)
roomEvent = roomEventOffset
if roomEvent != None:
roomEvent = roomEvent + 3 + slot*4
roomEvent = roomEvent + 3 + slot * 4
if itemValue < 3:
itemValue += 1
else:
@ -2877,21 +2892,25 @@ def patch_game():
location = name
elif name in CreditsNames:
location = CreditsNames.get(name)
elif 'S0' in name:
location = 'Main Deck : '
else:
if 'S0' in name:
location = 'Main Deck : '
else:
location = 'Sector {} : '.format(name[6:7])
if 'Tank' in nodeType:
location = location + name[8:]
else:
location = location + nodeType + ' Room'
location = 'Sector {} : '.format(name[6:7])
spaces = ceiling(30 - len(location), 2)
location = ' ' * spaces + location
patchedGame.seek(offset)
patchedGame.write(location.encode('ascii'))
for x in range(len(location), 35):
patchedGame.write((0).to_bytes(1, 'little'))
patchedGame.seek(5726109)
patchedGame.write(PlacedETanks.to_bytes(1, 'little'))
patchedGame.seek(5726110)
patchedGame.write(PlacedMissiles.to_bytes(1, 'little'))
patchedGame.seek(5726111)
patchedGame.write(PlacedPowerBombs.to_bytes(1, 'little'))
if SeedSettings['-HIDEITEMS-']:
patchedGame.seek(3926048)
patchedGame.write((76).to_bytes(2, 'little'))
@ -2907,22 +2926,33 @@ def patch_game():
patchedGame.write((78).to_bytes(2, 'little'))
patchedGame.write((79).to_bytes(2, 'little'))
if SeedSettings['-SPLITSECURITY-'] == True:
security = securityOffset
patchedGame.seek(security)
patchedGame.seek(securityOffset)
patchedGame.write((0).to_bytes(2, 'little'))
if SeedSettings['-MISSILEDATA-']:
patchedGame.seek(24828)
patchedGame.write((15).to_bytes(1, 'little'))
patchedGame.seek(395742)
patchedGame.seek(saxAnyOffset + 1)
patchedGame.write((15).to_bytes(1, 'little'))
patchedGame.seek(465582)
patchedGame.write((15).to_bytes(1, 'little'))
patchedGame.seek(spawnBox + 13)
patchedGame.write((2).to_bytes(1, 'little'))
patchedGame.seek(spawnBox + 21)
patchedGame.write((4).to_bytes(1, 'little'))
patchedGame.seek(spawnBox + 29)
patchedGame.write((8).to_bytes(1, 'little'))
patchedGame.seek(spawnMegaCoreX + 13)
patchedGame.write((2).to_bytes(1, 'little'))
patchedGame.seek(spawnMegaCoreX + 21)
patchedGame.write((4).to_bytes(1, 'little'))
patchedGame.seek(spawnMegaCoreX + 29)
patchedGame.write((8).to_bytes(1, 'little'))
if SeedSettings['-PBDATA-']:
patchedGame.seek(24756)
patchedGame.write((32).to_bytes(1, 'little'))
patchedGame.seek(465672)
patchedGame.write((32).to_bytes(1, 'little'))
if SeedSettings['-SHUFFLESECTORS-'] == True:
if SeedSettings['-SHUFFLESECTORS-'] == True or SeedSettings['-SHUFFLETUBES-'] == True:
for currentArea in range(7):
patchedGame.seek(7977108 + currentArea * 4, 0)
data = patchedGame.read(4)

2
flips

@ -1 +1 @@
Subproject commit fdd5c6e34285beef5b9be759c9b91390df486c66
Subproject commit e12ef189900b2c720c6dcd55036a8bb43925ea53