bass, how low can you go
parent
28f2adc3d1
commit
8674605497
|
@ -31,7 +31,58 @@ class Game:
|
||||||
self.minorItemLocations.clear()
|
self.minorItemLocations.clear()
|
||||||
self.itemLocations.clear()
|
self.itemLocations.clear()
|
||||||
self.patcher.clear()
|
self.patcher.clear()
|
||||||
# WARNING: Decompyle incomplete
|
|
||||||
|
try:
|
||||||
|
with open(vanillaGame, 'rb') as sourceRom:
|
||||||
|
sourceRom.seek(3967888, 0)
|
||||||
|
sourceArea = int.from_bytes(sourceRom.read(1), 'little')
|
||||||
|
sourceDoor = int.from_bytes(sourceRom.read(1), 'little')
|
||||||
|
targetOffset = sourceRom.tell()
|
||||||
|
targetArea = int.from_bytes(sourceRom.read(1), 'little')
|
||||||
|
if sourceArea != 255:
|
||||||
|
self.areaConnections.update({
|
||||||
|
'S{}-{:02X}'.format(sourceArea, sourceDoor): targetArea })
|
||||||
|
self.areaConnectionOffsets.update({
|
||||||
|
'S{}-{:02X}'.format(sourceArea, sourceDoor): targetOffset })
|
||||||
|
sourceArea = int.from_bytes(sourceRom.read(1), 'little')
|
||||||
|
sourceDoor = int.from_bytes(sourceRom.read(1), 'little')
|
||||||
|
targetOffset = sourceRom.tell()
|
||||||
|
targetArea = int.from_bytes(sourceRom.read(1), 'little')
|
||||||
|
continue
|
||||||
|
for currentArea in range(7):
|
||||||
|
sourceRom.seek(7977108 + currentArea * 4, 0)
|
||||||
|
data = sourceRom.read(4)
|
||||||
|
unpacked = struct.unpack('<L', data)
|
||||||
|
doorData = unpacked[0] - 134217728
|
||||||
|
sourceRom.seek(doorData, 0)
|
||||||
|
doorNumber = 0
|
||||||
|
connectionType = int.from_bytes(sourceRom.read(1), 'little')
|
||||||
|
roomNumber = int.from_bytes(sourceRom.read(1), 'little')
|
||||||
|
sourceRom.seek(4, 1)
|
||||||
|
connectedDoor = int.from_bytes(sourceRom.read(1), 'little')
|
||||||
|
sourceRom.seek(5, 1)
|
||||||
|
if connectionType == 0 and connectedDoor == 0:
|
||||||
|
continue
|
||||||
|
sourceNode = 'S{}-{:02X}'.format(currentArea, doorNumber)
|
||||||
|
connectedArea = self.areaConnections.get(sourceNode, currentArea)
|
||||||
|
targetNode = 'S{}-{:02X}'.format(connectedArea, connectedDoor)
|
||||||
|
self.doorConnections.update({
|
||||||
|
sourceNode: targetNode })
|
||||||
|
roomNumber = format(roomNumber, '02X')
|
||||||
|
roomString = 'Room-S{}-{}'.format(currentArea, roomNumber)
|
||||||
|
doorString = 'S{}-{:02X}'.format(currentArea, doorNumber)
|
||||||
|
if roomString in self.rooms:
|
||||||
|
self.rooms[roomString].append(doorString)
|
||||||
|
else:
|
||||||
|
self.rooms[roomString] = [
|
||||||
|
doorString]
|
||||||
|
doorNumber += 1
|
||||||
|
finally:
|
||||||
|
pass
|
||||||
|
except FileNotFoundError:
|
||||||
|
sys.exit('Error:', vanillaGame, 'could not be opened.')
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def set_setting(self, setting, value):
|
def set_setting(self, setting, value):
|
||||||
|
|
477
Randomizer.py
477
Randomizer.py
|
@ -4685,40 +4685,414 @@ def patch_game():
|
||||||
os.unlink(os.path.join('.', 'seeds', '{}.gba'.format(FileName)))
|
os.unlink(os.path.join('.', 'seeds', '{}.gba'.format(FileName)))
|
||||||
print('Error: Base patch file has been modified. Please go to https://metroidconstruction.com/ and re-download MFOR.')
|
print('Error: Base patch file has been modified. Please go to https://metroidconstruction.com/ and re-download MFOR.')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
# WARNING: Decompyle incomplete
|
|
||||||
|
with open(os.path.join('.', 'seeds', '{}.gba'.format(FileName)), 'rb+') as patchedGame:
|
||||||
|
if Debug:
|
||||||
|
sym = dict()
|
||||||
|
sym.clear()
|
||||||
|
with open(os.path.join('.', 'data', 'asm', 'temp.sym'), 'r') as symFile:
|
||||||
|
for line in symFile:
|
||||||
|
x = line.split()
|
||||||
|
if len(x) > 1 and re.search('^[a-zA-Z]', x[1]):
|
||||||
|
sym.update({
|
||||||
|
x[1]: x[0][2:] })
|
||||||
|
finally:
|
||||||
|
pass
|
||||||
|
os.remove(os.path.join('.', 'data', 'asm', 'temp.sym'))
|
||||||
|
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))
|
||||||
|
roomEventOffset = 8326320
|
||||||
|
itemEventOffset = 5726112
|
||||||
|
securityOffset = 479192
|
||||||
|
for area in RoomNodes:
|
||||||
|
areaIndex = list(RoomNodes.keys()).index(area)
|
||||||
|
for node in RoomNodes[area]:
|
||||||
|
name = node.get('Name')
|
||||||
|
nodeType = node.get('Type')
|
||||||
|
if nodeType != None:
|
||||||
|
itemName = ''
|
||||||
|
if 'Tank' in nodeType:
|
||||||
|
itemName = PlacedItems[UsedLocations.index(name)]
|
||||||
|
bg1 = int(node.get('BG1'), 16)
|
||||||
|
clipdata = int(node.get('Clipdata'), 16)
|
||||||
|
tileset = int(node.get('Tileset'), 16)
|
||||||
|
if SeedSettings['HideItems']:
|
||||||
|
if tileset == 33:
|
||||||
|
blockValue = 7
|
||||||
|
elif tileset == 34:
|
||||||
|
blockValue = 7
|
||||||
|
elif tileset == 40:
|
||||||
|
blockValue = 7
|
||||||
|
elif tileset == 42:
|
||||||
|
blockValue = 7
|
||||||
|
else:
|
||||||
|
blockValue = 3
|
||||||
|
else:
|
||||||
|
blockValue = ItemList.index(itemName)
|
||||||
|
if blockValue < 2:
|
||||||
|
blockValue = blockValue ^ 1
|
||||||
|
elif blockValue > 2:
|
||||||
|
if tileset == 33:
|
||||||
|
blockValue = 7
|
||||||
|
elif tileset == 34:
|
||||||
|
blockValue = 7
|
||||||
|
elif tileset == 40:
|
||||||
|
blockValue = 7
|
||||||
|
elif tileset == 42:
|
||||||
|
blockValue = 7
|
||||||
|
else:
|
||||||
|
blockValue = 3
|
||||||
|
blockValue += 70
|
||||||
|
if tileset == 9:
|
||||||
|
blockValue += 1
|
||||||
|
elif tileset == 11:
|
||||||
|
blockValue += 1
|
||||||
|
elif tileset == 25:
|
||||||
|
blockValue += 1
|
||||||
|
elif tileset >= 30 and tileset <= 34:
|
||||||
|
blockValue += 1
|
||||||
|
elif tileset == 40:
|
||||||
|
blockValue += 1
|
||||||
|
elif tileset == 42:
|
||||||
|
blockValue += 1
|
||||||
|
elif tileset == 48:
|
||||||
|
blockValue += 1
|
||||||
|
elif tileset == 49:
|
||||||
|
blockValue += 1
|
||||||
|
elif tileset == 52:
|
||||||
|
blockValue += 1
|
||||||
|
elif tileset == 56:
|
||||||
|
blockValue += 1
|
||||||
|
elif tileset == 61:
|
||||||
|
blockValue += 1
|
||||||
|
elif tileset == 62:
|
||||||
|
blockValue += 1
|
||||||
|
elif tileset == 64:
|
||||||
|
blockValue += 1
|
||||||
|
elif tileset == 67:
|
||||||
|
blockValue += 1
|
||||||
|
elif tileset == 72:
|
||||||
|
blockValue += 1
|
||||||
|
clipValue = ItemList.index(itemName)
|
||||||
|
if clipValue < 2:
|
||||||
|
clipValue = clipValue ^ 99
|
||||||
|
if 'Hidden' in nodeType:
|
||||||
|
clipValue += 2
|
||||||
|
elif 'Underwater' in nodeType:
|
||||||
|
clipValue += 4
|
||||||
|
elif clipValue == 2:
|
||||||
|
clipValue = 104
|
||||||
|
if 'Hidden' in nodeType:
|
||||||
|
clipValue += 1
|
||||||
|
elif 'Underwater' in nodeType:
|
||||||
|
clipValue += 2
|
||||||
|
elif clipValue >= 3:
|
||||||
|
clipValue = (clipValue - 3) * 3 + 120
|
||||||
|
if 'Hidden' in nodeType:
|
||||||
|
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:
|
||||||
|
itemName = PlacedItems[UsedLocations.index(name)]
|
||||||
|
itemValue = ItemList.index(itemName)
|
||||||
|
slot = BossDataList.index(name)
|
||||||
|
roomEvent = roomEventOffset
|
||||||
|
if roomEvent != None:
|
||||||
|
roomEvent = roomEvent + 3 + slot * 4
|
||||||
|
if itemValue < 3:
|
||||||
|
itemValue += 1
|
||||||
|
else:
|
||||||
|
itemValue -= 3
|
||||||
|
itemEvent = itemEventOffset
|
||||||
|
if itemEvent != None:
|
||||||
|
itemEvent = itemEvent + 1 + itemValue
|
||||||
|
patchedGame.seek(itemEvent)
|
||||||
|
itemValue = int.from_bytes(patchedGame.read(1), 'little')
|
||||||
|
patchedGame.seek(roomEvent)
|
||||||
|
patchedGame.write(itemValue.to_bytes(1, 'little'))
|
||||||
|
if name == 'Data S5':
|
||||||
|
roomEvent = roomEventOffset
|
||||||
|
roomEvent = roomEvent + 3 + (slot + 1) * 4
|
||||||
|
patchedGame.seek(roomEvent)
|
||||||
|
patchedGame.write(itemValue.to_bytes(1, 'little'))
|
||||||
|
if itemName in MajorItems:
|
||||||
|
offset = CreditsOffsets.get(itemName)
|
||||||
|
if 'Boss' in nodeType:
|
||||||
|
location = name
|
||||||
|
elif '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'
|
||||||
|
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'))
|
||||||
|
if SeedSettings['HideItems']:
|
||||||
|
patchedGame.seek(3926048)
|
||||||
|
patchedGame.write(76.to_bytes(2, 'little'))
|
||||||
|
patchedGame.write(77.to_bytes(2, 'little'))
|
||||||
|
patchedGame.write(78.to_bytes(2, 'little'))
|
||||||
|
patchedGame.write(79.to_bytes(2, 'little'))
|
||||||
|
patchedGame.write(76.to_bytes(2, 'little'))
|
||||||
|
patchedGame.write(77.to_bytes(2, 'little'))
|
||||||
|
patchedGame.write(78.to_bytes(2, 'little'))
|
||||||
|
patchedGame.write(79.to_bytes(2, 'little'))
|
||||||
|
patchedGame.write(76.to_bytes(2, 'little'))
|
||||||
|
patchedGame.write(77.to_bytes(2, 'little'))
|
||||||
|
patchedGame.write(78.to_bytes(2, 'little'))
|
||||||
|
patchedGame.write(79.to_bytes(2, 'little'))
|
||||||
|
if SeedSettings['SplitSecurity'] == True:
|
||||||
|
security = securityOffset
|
||||||
|
patchedGame.seek(security)
|
||||||
|
patchedGame.write(0.to_bytes(2, 'little'))
|
||||||
|
if SeedSettings['MissilesWithoutMainData']:
|
||||||
|
patchedGame.seek(24828)
|
||||||
|
patchedGame.write(15.to_bytes(1, 'little'))
|
||||||
|
patchedGame.seek(395742)
|
||||||
|
patchedGame.write(15.to_bytes(1, 'little'))
|
||||||
|
patchedGame.seek(465582)
|
||||||
|
patchedGame.write(15.to_bytes(1, 'little'))
|
||||||
|
if SeedSettings['PowerBombsWithoutBombs']:
|
||||||
|
patchedGame.seek(24756)
|
||||||
|
patchedGame.write(32.to_bytes(1, 'little'))
|
||||||
|
patchedGame.seek(465672)
|
||||||
|
patchedGame.write(32.to_bytes(1, 'little'))
|
||||||
|
if SeedSettings['SectorShuffle'] == True:
|
||||||
|
for currentArea in range(7):
|
||||||
|
patchedGame.seek(7977108 + currentArea * 4, 0)
|
||||||
|
data = patchedGame.read(4)
|
||||||
|
unpacked = struct.unpack('<L', data)
|
||||||
|
doorData = unpacked[0] - 134217728
|
||||||
|
patchedGame.seek(doorData, 0)
|
||||||
|
doorNumber = 0
|
||||||
|
connectionType = int.from_bytes(patchedGame.read(1), 'little')
|
||||||
|
patchedGame.seek(5, 1)
|
||||||
|
offset = patchedGame.tell()
|
||||||
|
connectedDoor = int.from_bytes(patchedGame.read(1), 'little')
|
||||||
|
patchedGame.seek(5, 1)
|
||||||
|
resume = patchedGame.tell()
|
||||||
|
if connectionType == 0 and connectedDoor == 0:
|
||||||
|
continue
|
||||||
|
sourceDoor = 'S{}-{:02X}'.format(currentArea, doorNumber)
|
||||||
|
targetDoorStr = World.doorConnections.get(sourceDoor)
|
||||||
|
connectedArea = World.areaConnections.get(sourceDoor, currentArea)
|
||||||
|
connectedDoorStr = 'S{}-{:02X}'.format(connectedArea, connectedDoor)
|
||||||
|
if connectedDoorStr != targetDoorStr:
|
||||||
|
targetDoor = int(targetDoorStr[-2:], 16)
|
||||||
|
patchedGame.seek(offset)
|
||||||
|
patchedGame.write(targetDoor.to_bytes(1, 'little'))
|
||||||
|
patchedGame.seek(resume)
|
||||||
|
doorNumber += 1
|
||||||
|
for door, targetArea in World.areaConnections.items():
|
||||||
|
offset = World.areaConnectionOffsets.get(door)
|
||||||
|
patchedGame.seek(offset)
|
||||||
|
areaByte = int.from_bytes(patchedGame.read(1), 'little')
|
||||||
|
if areaByte != targetArea:
|
||||||
|
patchedGame.seek(offset)
|
||||||
|
patchedGame.write(targetArea.to_bytes(1, 'little'))
|
||||||
|
continue
|
||||||
|
for target in World.patcher:
|
||||||
|
value = World.patcher.get(target)
|
||||||
|
patchedGame.seek(target)
|
||||||
|
patchedGame.write(value.to_bytes(1, 'little'))
|
||||||
|
finally:
|
||||||
|
pass
|
||||||
|
if Patch:
|
||||||
|
# FIXME: replace with internal patch creator
|
||||||
|
os.system('.\\flips\\flips.exe --create --bps "{}" ".\\seeds\\{}.gba"'.format(BaseGame, FileName))
|
||||||
|
print('')
|
||||||
|
ItemNames = [
|
||||||
|
'Missile Data',
|
||||||
|
'Morph Ball',
|
||||||
|
'Charge Beam',
|
||||||
|
'Bombs',
|
||||||
|
'Hi-Jump Boots',
|
||||||
|
'Speed Booster',
|
||||||
|
'Super Missile Data',
|
||||||
|
'Varia Suit',
|
||||||
|
'Ice Missile Data',
|
||||||
|
'Wide Beam',
|
||||||
|
'Power Bomb Data',
|
||||||
|
'Space Jump',
|
||||||
|
'Plasma Beam',
|
||||||
|
'Gravity Suit',
|
||||||
|
'Diffusion Data',
|
||||||
|
'Wave Beam',
|
||||||
|
'Screw Attack',
|
||||||
|
'Ice Beam']
|
||||||
|
if SeedSettings['RaceSeed'] == False:
|
||||||
|
spoilerLog = dict()
|
||||||
|
spoilerLog.update({
|
||||||
|
'MFOR Version': version })
|
||||||
|
spoilerLog.update({
|
||||||
|
'Seed': SeedValue })
|
||||||
|
settingsDict = dict()
|
||||||
|
settingsDict.update({
|
||||||
|
'Difficulty': SeedSettings['Difficulty'] })
|
||||||
|
if SeedSettings['MajorMinor'] == False:
|
||||||
|
settingsDict.update({
|
||||||
|
'Item pool': 'Major items anywhere' })
|
||||||
|
else:
|
||||||
|
settingsDict.update({
|
||||||
|
'Item pool': 'Limited major item locations' })
|
||||||
|
settingsDict.update({
|
||||||
|
'Missile upgrades enable Missiles': SeedSettings['MissilesWithoutMainData'] })
|
||||||
|
settingsDict.update({
|
||||||
|
'Power Bombs without normal Bombs': SeedSettings['PowerBombsWithoutBombs'] })
|
||||||
|
settingsDict.update({
|
||||||
|
'Allow logical damage runs': SeedSettings['DamageRuns'] })
|
||||||
|
settingsDict.update({
|
||||||
|
'Separated security levels': SeedSettings['SplitSecurity'] })
|
||||||
|
settingsDict.update({
|
||||||
|
'Sector shuffle': SeedSettings['SectorShuffle'] })
|
||||||
|
if SeedSettings['SectorShuffle'] == True:
|
||||||
|
sectorLayout = str()
|
||||||
|
for x in areaLayout:
|
||||||
|
sectorLayout = sectorLayout.strip() + ' {}'.format(x)
|
||||||
|
settingsDict.update({
|
||||||
|
'Sector layout:': sectorLayout })
|
||||||
|
settingsDict.update({
|
||||||
|
'Hide item graphics': SeedSettings['HideItems'] })
|
||||||
|
settingsDict.update({
|
||||||
|
'E-Tanks': PlacedETanks })
|
||||||
|
settingsDict.update({
|
||||||
|
'Missile Tanks': PlacedMissiles })
|
||||||
|
settingsDict.update({
|
||||||
|
'Power Bomb Tanks': PlacedPowerBombs })
|
||||||
|
spoilerLog.update({
|
||||||
|
'Settings': settingsDict })
|
||||||
|
itemProgression = dict()
|
||||||
|
for x in range(len(PlacedItems)):
|
||||||
|
if PlacedItems[x] in MajorItems:
|
||||||
|
namedItem = ItemNames[MajorItems.index(PlacedItems[x])]
|
||||||
|
PlacedItems[x] = namedItem
|
||||||
|
itemProgression.update({
|
||||||
|
UsedLocations[x]: PlacedItems[x] })
|
||||||
|
continue
|
||||||
|
spoilerLog.update({
|
||||||
|
'Item order': itemProgression })
|
||||||
|
itemDict = dict()
|
||||||
|
World.itemLocations.sort()
|
||||||
|
for x in range(0, len(World.itemLocations)):
|
||||||
|
itemDict.update({
|
||||||
|
World.itemLocations[x]: 0 })
|
||||||
|
for x in range(0, len(PlacedItems)):
|
||||||
|
itemDict.update({
|
||||||
|
UsedLocations[x]: PlacedItems[x] })
|
||||||
|
spoilerLog.update({
|
||||||
|
'Items': itemDict })
|
||||||
|
with open(os.path.join('.', 'spoilers', '{}.json'.format(FileName)), 'w') as spoiler:
|
||||||
|
json.dump(spoilerLog, spoiler, indent=4)
|
||||||
|
finally:
|
||||||
|
pass
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def initialize():
|
def initialize():
|
||||||
global HashList, HashList
|
global HashList, HashList, AreaOpen, Energy, WallJumpSetting, InfiniteBombJump, BackwardsLabs, MaxETanks, MaxMissiles, MaxPowerBombs, PlacedETanks, PlacedMissiles, PlacedPowerBombs, MissileDamage, MissileCount, MajorItems, MinorItems, BossDataList, ItemList, PlacedItems, BossLocations, AccessibleLocations, UsedLocations
|
||||||
HashList = list()
|
HashList = list()
|
||||||
# WARNING: Decompyle incomplete
|
with open(os.path.join('.', 'data', 'SeedHash.json')) as jsonFile:
|
||||||
|
HashList = json.load(jsonFile)
|
||||||
|
finally:
|
||||||
|
pass
|
||||||
|
HashList.sort()
|
||||||
|
AreaOpen = list()
|
||||||
|
for area in range(0, 7):
|
||||||
|
AreaOpen.append(None)
|
||||||
|
Energy = 0
|
||||||
|
WallJumpSetting = False
|
||||||
|
InfiniteBombJump = False
|
||||||
|
BackwardsLabs = False
|
||||||
|
MaxETanks = 20
|
||||||
|
MaxMissiles = 48
|
||||||
|
MaxPowerBombs = 32
|
||||||
|
PlacedETanks = PlacedMissiles = PlacedPowerBombs = 0
|
||||||
|
MissileDamage = 0
|
||||||
|
MissileCount = 10
|
||||||
|
MajorItems = [
|
||||||
|
'MainMissiles',
|
||||||
|
'MorphBall',
|
||||||
|
'ChargeBeam',
|
||||||
|
'Bombs',
|
||||||
|
'HiJumpBoots',
|
||||||
|
'SpeedBooster',
|
||||||
|
'SuperMissileItem',
|
||||||
|
'VariaSuit',
|
||||||
|
'IceMissileItem',
|
||||||
|
'WideBeam',
|
||||||
|
'MainPowerBombs',
|
||||||
|
'SpaceJump',
|
||||||
|
'PlasmaBeam',
|
||||||
|
'GravitySuit',
|
||||||
|
'DiffusionItem',
|
||||||
|
'WaveBeam',
|
||||||
|
'ScrewAttack',
|
||||||
|
'IceBeam']
|
||||||
|
MinorItems = [
|
||||||
|
'Energy Tank',
|
||||||
|
'Missile Tank',
|
||||||
|
'Power Bomb Tank']
|
||||||
|
BossDataList = [
|
||||||
|
'Data S0',
|
||||||
|
'Arachnus',
|
||||||
|
'Charge Core-X',
|
||||||
|
'Data S2',
|
||||||
|
'Zazabi',
|
||||||
|
'Serris',
|
||||||
|
'Data S3',
|
||||||
|
'Mega Core-X',
|
||||||
|
'Data S5',
|
||||||
|
'Data S5',
|
||||||
|
'Wide Core-X',
|
||||||
|
'Data S6',
|
||||||
|
'Yakuza',
|
||||||
|
'Nettori',
|
||||||
|
'Nightmare',
|
||||||
|
'Data S4',
|
||||||
|
'Box-2',
|
||||||
|
'Ridley',
|
||||||
|
'Omega Metroid']
|
||||||
|
ItemList = MinorItems + MajorItems
|
||||||
|
PlacedItems = list()
|
||||||
|
BossLocations = list()
|
||||||
|
AccessibleLocations = list()
|
||||||
|
UsedLocations = list()
|
||||||
|
return None
|
||||||
|
|
||||||
def start_randomizer(rom, settings):
|
def start_randomizer(rom, settings):
|
||||||
global BaseGame, Debug, SeedValue, SeedValue, Patch, Patch, SeedSettings, SeedValue, Difficulty, DamageRuns, World, AreaItemLocations, RoomNodes
|
global BaseGame, Debug, SeedValue, SeedValue, Patch, Patch, SeedSettings, SeedValue, Difficulty, DamageRuns, World, AreaItemLocations, RoomNodes, StartLocation
|
||||||
print('DEBUG: entered start_randomizer')
|
|
||||||
BaseGame = rom
|
BaseGame = rom
|
||||||
print(BaseGame)
|
|
||||||
if BaseGame == None or BaseGame == '':
|
if BaseGame == None or BaseGame == '':
|
||||||
print('Error: no base game provided.')
|
sys.exit('Error: no base game provided.')
|
||||||
sys.exit(1)
|
|
||||||
checksum = fileHash(BaseGame)
|
checksum = fileHash(BaseGame)
|
||||||
if checksum != 1819625372:
|
if checksum != 1819625372:
|
||||||
print('Only Metroid Fusion (U) is supported. Check the CRC32 value: it should be 6C75479C')
|
sys.exit('Only Metroid Fusion (U) is supported. Check the CRC32 value: it should be 6C75479C')
|
||||||
sys.exit(1)
|
|
||||||
Debug = settings['Debug']
|
Debug = settings['Debug']
|
||||||
settings.pop('Debug')
|
settings.pop('Debug')
|
||||||
if Debug == False:
|
if Debug == False:
|
||||||
checksum = fileHash(os.path.join('.', 'data', 'MFOR.bps'))
|
checksum = fileHash(os.path.join('.', 'data', 'MFOR.bps'))
|
||||||
if checksum != 558161692:
|
if checksum != 558161692:
|
||||||
print('Error: Base patch file has been modified. Please go to https://metroidconstruction.com/ and re-download MFOR.')
|
sys.exit('Error: Base patch file has been modified. Please go to https://metroidconstruction.com/ and re-download MFOR.')
|
||||||
sys.exit(1)
|
|
||||||
totalRandoTime = time.time()
|
totalRandoTime = time.time()
|
||||||
if settings['Seed']:
|
if settings['Seed']:
|
||||||
SeedValue = str(settings['Seed']).strip(' \n')
|
SeedValue = str(settings['Seed']).strip(' \n')
|
||||||
else:
|
else:
|
||||||
SeedValue = str(random.randrange(sys.maxsize))
|
SeedValue = str(random.randrange(sys.maxsize))
|
||||||
print(SeedValue)
|
|
||||||
settings.pop('Seed')
|
settings.pop('Seed')
|
||||||
repeat = 1
|
repeat = 1
|
||||||
if settings['Num'] and settings['Num'] > repeat:
|
if settings['Num'] and settings['Num'] > repeat:
|
||||||
|
@ -4729,7 +5103,76 @@ def start_randomizer(rom, settings):
|
||||||
else:
|
else:
|
||||||
Patch = False
|
Patch = False
|
||||||
settings.pop('Patch')
|
settings.pop('Patch')
|
||||||
patch_game()
|
for loop in range(repeat):
|
||||||
|
initialize()
|
||||||
# WARNING: Decompyle incomplete
|
SeedSettings = settings.copy()
|
||||||
|
if Debug:
|
||||||
|
print('Debug generation enabled')
|
||||||
|
if loop > 0:
|
||||||
|
SeedValue = str(random.randrange(sys.maxsize))
|
||||||
|
Difficulty = SeedSettings['Difficulty']
|
||||||
|
DamageRuns = SeedSettings['DamageRuns']
|
||||||
|
random.seed(SeedValue + str(SeedSettings))
|
||||||
|
World = Graph.Game(BaseGame)
|
||||||
|
World.RemoveNodeFromRoom('Room-S2-07', 'S2-10')
|
||||||
|
World.RemoveNodeFromRoom('Room-S2-0D', 'S2-1E')
|
||||||
|
World.RemoveNodeFromRoom('Room-S3-07', 'S3-10')
|
||||||
|
World.RemoveNodeFromRoom('Room-S3-12', 'S3-2B')
|
||||||
|
World.RemoveNodeFromRoom('Room-S5-15', 'S5-2A')
|
||||||
|
World.AddNodeToRoom('Room-S2-1F', 'S2-10')
|
||||||
|
World.AddNodeToRoom('Room-S2-2E', 'S2-1E')
|
||||||
|
World.AddNodeToRoom('Room-S3-16', 'S3-10')
|
||||||
|
World.AddNodeToRoom('Room-S3-17', 'S3-2B')
|
||||||
|
World.AddNodeToRoom('Room-S5-16', 'S5-2A')
|
||||||
|
World.UpdateDoorConnection('S0-4A', 'S0-61')
|
||||||
|
World.UpdateDoorConnection('S0-96', 'S0-22')
|
||||||
|
World.UpdateDoorConnection('S0-98', 'S0-20')
|
||||||
|
World.UpdateDoorConnection('S2-13', 'S2-45')
|
||||||
|
World.UpdateDoorConnection('S2-19', 'S2-2F')
|
||||||
|
World.UpdateDoorConnection('S2-1B', 'S2-68')
|
||||||
|
World.UpdateDoorConnection('S2-23', 'S2-69')
|
||||||
|
World.UpdateDoorConnection('S2-5F', 'S2-6A')
|
||||||
|
World.UpdateDoorConnection('S2-6E', 'S2-70')
|
||||||
|
World.UpdateDoorConnection('S3-2D', 'S3-2E')
|
||||||
|
World.UpdateDoorConnection('S5-28', 'S5-6C')
|
||||||
|
AreaItemLocations = list()
|
||||||
|
for area in range(7):
|
||||||
|
AreaItemLocations.append(list())
|
||||||
|
with open(os.path.join('.', 'data', 'NodeData.json')) as jsonFile:
|
||||||
|
RoomNodes = json.load(jsonFile)
|
||||||
|
finally:
|
||||||
|
pass
|
||||||
|
for area in RoomNodes:
|
||||||
|
areaIndex = list(RoomNodes.keys()).index(area)
|
||||||
|
for node in RoomNodes[area]:
|
||||||
|
name = node.get('Name')
|
||||||
|
room = node.get('Room')
|
||||||
|
item = node.get('Item')
|
||||||
|
nodeType = node.get('Type')
|
||||||
|
World.AddNodeToRoom('Room-S{}-{:02X}'.format(areaIndex, int(room, 16)), name)
|
||||||
|
if item == 'Missile' or item == 'Power Bomb':
|
||||||
|
World.add_to_minors(name)
|
||||||
|
elif nodeType == 'Boss':
|
||||||
|
World.add_to_majors(name)
|
||||||
|
BossLocations.append(name)
|
||||||
|
elif nodeType == 'Data' or item == 'E-Tank':
|
||||||
|
World.add_to_majors(name)
|
||||||
|
if name == 'Data S3':
|
||||||
|
BossLocations.append(name)
|
||||||
|
if not 'Item' in name and nodeType == 'Boss':
|
||||||
|
if nodeType == 'Data':
|
||||||
|
AreaItemLocations[areaIndex].append(name)
|
||||||
|
continue
|
||||||
|
continue
|
||||||
|
World.ConnectAllNodes()
|
||||||
|
StartLocation = 'S0-00'
|
||||||
|
startTime = time.time()
|
||||||
|
randomize_game(World)
|
||||||
|
seedTime = time.time() - startTime
|
||||||
|
print(str(FileName))
|
||||||
|
print('Randomized in:', seedTime)
|
||||||
|
continue
|
||||||
|
totalRandoTime = time.time() - totalRandoTime
|
||||||
|
print('All seeds took:', totalRandoTime)
|
||||||
|
return FileName
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue