Compare commits
10 Commits
bd7e1bc15d
...
0a1e3e0cad
Author | SHA1 | Date |
---|---|---|
magical | 0a1e3e0cad | |
magical | 2f2c281265 | |
magical | 20e24a40e3 | |
magical | e7a5af202a | |
magical | 12a22c8724 | |
magical | 707a7b70a1 | |
magical | afde644b38 | |
magical | 9f22730870 | |
Lucent | c4f720c505 | |
Lucent | 409efe14ac |
121
Fusion_Graph.py
121
Fusion_Graph.py
|
@ -1,3 +1,12 @@
|
||||||
|
# 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++
|
# Source Generated with Decompyle++
|
||||||
# File: Fusion_Graph.pyc (Python 3.8)
|
# File: Fusion_Graph.pyc (Python 3.8)
|
||||||
|
|
||||||
|
@ -5,8 +14,8 @@ import struct
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
class Game:
|
class Game:
|
||||||
|
|
||||||
def __init__(self, vanillaGame, randoSettings = (None,)):
|
def __init__(self, vanillaGame, randoSettings=None):
|
||||||
self.graph = dict()
|
self.graph = dict()
|
||||||
self.areaConnections = dict()
|
self.areaConnections = dict()
|
||||||
self.areaConnectionOffsets = dict()
|
self.areaConnectionOffsets = dict()
|
||||||
|
@ -31,9 +40,9 @@ class Game:
|
||||||
self.minorItemLocations.clear()
|
self.minorItemLocations.clear()
|
||||||
self.itemLocations.clear()
|
self.itemLocations.clear()
|
||||||
self.patcher.clear()
|
self.patcher.clear()
|
||||||
|
|
||||||
# print('DEBUG: Opening ROM to pick stuff')
|
# print('DEBUG: Opening ROM to pick stuff')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(vanillaGame, 'rb') as sourceRom:
|
with open(vanillaGame, 'rb') as sourceRom:
|
||||||
sourceRom.seek(3967888, 0)
|
sourceRom.seek(3967888, 0)
|
||||||
|
@ -41,7 +50,7 @@ class Game:
|
||||||
sourceDoor = int.from_bytes(sourceRom.read(1), 'little')
|
sourceDoor = int.from_bytes(sourceRom.read(1), 'little')
|
||||||
targetOffset = sourceRom.tell()
|
targetOffset = sourceRom.tell()
|
||||||
targetArea = int.from_bytes(sourceRom.read(1), 'little')
|
targetArea = int.from_bytes(sourceRom.read(1), 'little')
|
||||||
if sourceArea != 255:
|
while sourceArea != 255:
|
||||||
self.areaConnections.update({
|
self.areaConnections.update({
|
||||||
'S{}-{:02X}'.format(sourceArea, sourceDoor): targetArea })
|
'S{}-{:02X}'.format(sourceArea, sourceDoor): targetArea })
|
||||||
self.areaConnectionOffsets.update({
|
self.areaConnectionOffsets.update({
|
||||||
|
@ -58,7 +67,7 @@ class Game:
|
||||||
doorData = unpacked[0] - 134217728
|
doorData = unpacked[0] - 134217728
|
||||||
sourceRom.seek(doorData, 0)
|
sourceRom.seek(doorData, 0)
|
||||||
doorNumber = 0
|
doorNumber = 0
|
||||||
while True:
|
while True:
|
||||||
connectionType = int.from_bytes(sourceRom.read(1), 'little')
|
connectionType = int.from_bytes(sourceRom.read(1), 'little')
|
||||||
roomNumber = int.from_bytes(sourceRom.read(1), 'little')
|
roomNumber = int.from_bytes(sourceRom.read(1), 'little')
|
||||||
sourceRom.seek(4, 1)
|
sourceRom.seek(4, 1)
|
||||||
|
@ -82,20 +91,20 @@ class Game:
|
||||||
doorString]
|
doorString]
|
||||||
doorNumber += 1
|
doorNumber += 1
|
||||||
# print('DEBUG: Parsing seemingly done?')
|
# print('DEBUG: Parsing seemingly done?')
|
||||||
except:
|
except FileNotFoundError:
|
||||||
print('Error:', vanillaGame, 'could not be opened.')
|
print('Error:', vanillaGame, 'could not be opened.')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def set_setting(self, setting, value):
|
def set_setting(self, setting, value):
|
||||||
self.settings[setting] = value
|
self.settings[setting] = value
|
||||||
|
|
||||||
|
|
||||||
def get_setting(self, setting):
|
def get_setting(self, setting):
|
||||||
return self.settings[setting]
|
return self.settings[setting]
|
||||||
|
|
||||||
|
|
||||||
def AddNodeToRoom(self, room, node):
|
def AddNodeToRoom(self, room, node):
|
||||||
nodeList = self.rooms.get(room)
|
nodeList = self.rooms.get(room)
|
||||||
nodeList.append(node)
|
nodeList.append(node)
|
||||||
|
@ -103,7 +112,7 @@ class Game:
|
||||||
self.rooms.update({
|
self.rooms.update({
|
||||||
room: nodeList })
|
room: nodeList })
|
||||||
|
|
||||||
|
|
||||||
def RemoveNodeFromRoom(self, room, node):
|
def RemoveNodeFromRoom(self, room, node):
|
||||||
nodeList = self.rooms.get(room)
|
nodeList = self.rooms.get(room)
|
||||||
if node in nodeList:
|
if node in nodeList:
|
||||||
|
@ -112,17 +121,17 @@ class Game:
|
||||||
self.rooms.update({
|
self.rooms.update({
|
||||||
room: nodeList })
|
room: nodeList })
|
||||||
|
|
||||||
|
|
||||||
def ClearGraph(self):
|
def ClearGraph(self):
|
||||||
self.graph.clear()
|
self.graph.clear()
|
||||||
|
|
||||||
|
|
||||||
def ConnectAllNodes(self):
|
def ConnectAllNodes(self):
|
||||||
self.ClearGraph()
|
self.ClearGraph()
|
||||||
self.ConnectNodesInRooms()
|
self.ConnectNodesInRooms()
|
||||||
self.ConnectNodesBetweenRooms()
|
self.ConnectNodesBetweenRooms()
|
||||||
|
|
||||||
|
|
||||||
def ConnectNodesInRooms(self):
|
def ConnectNodesInRooms(self):
|
||||||
for room in self.rooms:
|
for room in self.rooms:
|
||||||
for start in self.rooms[room]:
|
for start in self.rooms[room]:
|
||||||
|
@ -130,12 +139,12 @@ class Game:
|
||||||
if start != end:
|
if start != end:
|
||||||
self.add_edges(start, end)
|
self.add_edges(start, end)
|
||||||
|
|
||||||
|
|
||||||
def ConnectNodesBetweenRooms(self):
|
def ConnectNodesBetweenRooms(self):
|
||||||
for connection in self.doorConnections.items():
|
for connection in self.doorConnections.items():
|
||||||
if len(connection) == 2:
|
if len(connection) == 2:
|
||||||
self.add_directed_edge(connection[0], connection[1])
|
self.add_directed_edge(connection[0], connection[1])
|
||||||
|
|
||||||
def UpdateDoorConnection(self, source, destination):
|
def UpdateDoorConnection(self, source, destination):
|
||||||
self.doorConnections.update({
|
self.doorConnections.update({
|
||||||
source: destination })
|
source: destination })
|
||||||
|
@ -145,7 +154,7 @@ class Game:
|
||||||
source: int(destination[1:2]) })
|
source: int(destination[1:2]) })
|
||||||
return self.areaConnectionOffsets.get(source)
|
return self.areaConnectionOffsets.get(source)
|
||||||
|
|
||||||
|
|
||||||
def AddConnectedNodesToRoom(self, targetRoom, *nodes):
|
def AddConnectedNodesToRoom(self, targetRoom, *nodes):
|
||||||
for currentNode in nodes:
|
for currentNode in nodes:
|
||||||
if targetRoom in self.rooms:
|
if targetRoom in self.rooms:
|
||||||
|
@ -165,86 +174,82 @@ class Game:
|
||||||
else:
|
else:
|
||||||
self.graph[start] = [
|
self.graph[start] = [
|
||||||
end]
|
end]
|
||||||
|
|
||||||
def add_edges(self, start, *nodes):
|
def add_edges(self, start, *nodes):
|
||||||
for end in nodes:
|
for end in nodes:
|
||||||
self.add_directed_edge(start, end)
|
self.add_directed_edge(start, end)
|
||||||
self.add_directed_edge(end, start)
|
self.add_directed_edge(end, start)
|
||||||
|
|
||||||
|
|
||||||
def add_to_majors(self, item):
|
def add_to_majors(self, item):
|
||||||
if item not in self.itemLocations:
|
if item not in self.itemLocations:
|
||||||
self.itemLocations.append(item)
|
self.itemLocations.append(item)
|
||||||
if item not in self.majorItemLocations:
|
if item not in self.majorItemLocations:
|
||||||
self.majorItemLocations.append(item)
|
self.majorItemLocations.append(item)
|
||||||
|
|
||||||
|
|
||||||
def add_list_to_majors(self, locations):
|
def add_list_to_majors(self, locations):
|
||||||
for item in locations:
|
for item in locations:
|
||||||
if item not in self.itemLocations:
|
if item not in self.itemLocations:
|
||||||
self.itemLocations.append(item)
|
self.itemLocations.append(item)
|
||||||
if item not in self.majorItemLocations:
|
if item not in self.majorItemLocations:
|
||||||
self.majorItemLocations.append(item)
|
self.majorItemLocations.append(item)
|
||||||
|
|
||||||
def add_to_minors(self, item):
|
def add_to_minors(self, item):
|
||||||
if item not in self.itemLocations:
|
if item not in self.itemLocations:
|
||||||
self.itemLocations.append(item)
|
self.itemLocations.append(item)
|
||||||
if item not in self.minorItemLocations:
|
if item not in self.minorItemLocations:
|
||||||
self.minorItemLocations.append(item)
|
self.minorItemLocations.append(item)
|
||||||
|
|
||||||
def add_list_to_minors(self, locations):
|
def add_list_to_minors(self, locations):
|
||||||
for item in locations:
|
for item in locations:
|
||||||
if item not in self.itemLocations:
|
if item not in self.itemLocations:
|
||||||
self.itemLocations.append(item)
|
self.itemLocations.append(item)
|
||||||
if item not in self.minorItemLocations:
|
if item not in self.minorItemLocations:
|
||||||
self.minorItemLocations.append(item)
|
self.minorItemLocations.append(item)
|
||||||
|
|
||||||
def get_requirements(self, start, end):
|
def get_requirements(self, start, end):
|
||||||
checkRequirement = (start, end)
|
checkRequirement = (start, end)
|
||||||
return self.requirements.get(checkRequirement)
|
return self.requirements.get(checkRequirement)
|
||||||
|
|
||||||
def get_path(self, start, end, LimitArea, path, depth = (False, None, 100)):
|
def get_path(self, start, end, LimitArea=False, path=None, depth=100):
|
||||||
if path == None:
|
if path == None:
|
||||||
self.visited.clear()
|
self.visited.clear()
|
||||||
self.queue.clear()
|
self.queue.clear()
|
||||||
path = list()
|
path = list()
|
||||||
path = path + [
|
path = path + [start]
|
||||||
start]
|
|
||||||
if start not in self.graph:
|
if start not in self.graph:
|
||||||
return None
|
return None
|
||||||
if None == end:
|
if start == end:
|
||||||
return path
|
return path
|
||||||
# if None(path) >= depth:
|
if len(path) >= depth:
|
||||||
if path >= depth:
|
|
||||||
return None
|
return None
|
||||||
for point in None.graph[start]:
|
for point in self.graph[start]:
|
||||||
if point in self.itemLocations and point not in end:
|
if point in self.itemLocations:
|
||||||
continue
|
if point not in end:
|
||||||
|
continue
|
||||||
if point in path:
|
if point in path:
|
||||||
continue
|
continue
|
||||||
if LimitArea:
|
if LimitArea:
|
||||||
for area in range(0, 7):
|
for area in range(0, 7):
|
||||||
if 'S{}'.format(area) in start and 'S{}'.format(area) not in point:
|
if 'S{}'.format(area) in start:
|
||||||
return None
|
if 'S{}'.format(area) not in point:
|
||||||
edge = (start, point)
|
return None
|
||||||
self.queue.append(edge)
|
edge = (start, point)
|
||||||
if self.queue:
|
self.queue.append(edge)
|
||||||
edge = self.queue.pop()
|
while self.queue:
|
||||||
if edge not in self.visited:
|
edge = self.queue.pop()
|
||||||
self.visited.append(edge)
|
if edge not in self.visited:
|
||||||
node = edge[1]
|
self.visited.append(edge)
|
||||||
pathReqs = self.get_requirements(start, node)
|
node = edge[1]
|
||||||
if pathReqs == None:
|
pathReqs = self.get_requirements(start, node)
|
||||||
newpath = self.get_path(node, end, LimitArea, path, depth)
|
if pathReqs == None:
|
||||||
if newpath:
|
newpath = self.get_path(node, end, LimitArea, path, depth)
|
||||||
path = path + [
|
if newpath:
|
||||||
node]
|
path = path + [node]
|
||||||
return newpath
|
return newpath
|
||||||
if pathReqs == True:
|
elif pathReqs == True:
|
||||||
newpath = self.get_path(node, end, LimitArea, path, depth)
|
newpath = self.get_path(node, end, LimitArea, path, depth)
|
||||||
if newpath:
|
if newpath:
|
||||||
path = path + [
|
path = path + [node]
|
||||||
node]
|
return newpath
|
||||||
return newpath
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,12 @@
|
||||||
|
# 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++
|
# Source Generated with Decompyle++
|
||||||
# File: Fusion_Items.pyc (Python 3.8)
|
# File: Fusion_Items.pyc (Python 3.8)
|
||||||
|
|
||||||
|
|
9
GUI.py
9
GUI.py
|
@ -1,3 +1,12 @@
|
||||||
|
# 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++
|
# Source Generated with Decompyle++
|
||||||
# File: GUI.pyc (Python 3.8)
|
# File: GUI.pyc (Python 3.8)
|
||||||
|
|
||||||
|
|
9
MFOR.py
9
MFOR.py
|
@ -1,3 +1,12 @@
|
||||||
|
# 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++
|
# Source Generated with Decompyle++
|
||||||
# File: MFOR.pyc (Python 3.8)
|
# File: MFOR.pyc (Python 3.8)
|
||||||
|
|
||||||
|
|
14
README.md
14
README.md
|
@ -4,13 +4,23 @@ This is the official unofficial Git repository for the Metroid Fusion Open Rando
|
||||||
|
|
||||||
Considering the original repository states that the software is GPL-3.0 licensed, but no source was ever released, we're endeavouring on this (potentially failing) task of making MFOR Open Again️™️
|
Considering the original repository states that the software is GPL-3.0 licensed, but no source was ever released, we're endeavouring on this (potentially failing) task of making MFOR Open Again️™️
|
||||||
|
|
||||||
|
## Links
|
||||||
|
|
||||||
|
* [OpenMFOR repository][] (This project, in case you are looking at a fork)
|
||||||
|
* The [original MFOR repository][] on Github
|
||||||
|
* The [original MFOR thread][] on Metroid Construction
|
||||||
|
|
||||||
|
[OpenMFOR]: https://git.inabaudonge.reisen/OpenMFOR/OpenMFOR
|
||||||
|
[original MFOR repository]: https://github.com/Kazuto88/MFOR
|
||||||
|
[original MFOR thread]: https://forum.metroidconstruction.com/index.php/topic,5376.0.html
|
||||||
|
|
||||||
## Project Status
|
## Project Status
|
||||||
|
|
||||||
- [x] Decent disassembly
|
- [x] Decent disassembly
|
||||||
- [x] GUI
|
- [x] GUI
|
||||||
- [x] CRC verification
|
- [x] CRC verification
|
||||||
- [ ] Logic
|
- [x] Logic
|
||||||
- [ ] Reconstructing missing parts of code
|
- [x] Reconstructing missing parts of code
|
||||||
- [x] Patching
|
- [x] Patching
|
||||||
- [ ] Generating BPS patches
|
- [ ] Generating BPS patches
|
||||||
|
|
||||||
|
|
7203
Randomizer.py
7203
Randomizer.py
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue