diff --git a/Randomizer.py b/Randomizer.py index d117cea..df55d7e 100644 --- a/Randomizer.py +++ b/Randomizer.py @@ -2646,166 +2646,169 @@ def patch_game(): 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:] }) - 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: + sym.update({ x[1]: x[0][2:] }) + 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)) + else: + 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: + # Energy Tank or Missile Tank + 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 + 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' + if 'Tank' in nodeType: + location = location + name[8:] + else: + location = location + nodeType + ' Room' spaces = ceiling(30 - len(location), 2) - location = ' ' * spaces + location + 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['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) @@ -2830,24 +2833,25 @@ def patch_game(): 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 + while True: + 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: + break + 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) @@ -2855,26 +2859,26 @@ def patch_game(): 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')) - - if Patch: - with open(BaseGame, 'rb') as source: - sourcedata = source.read() - with open(os.path.join('.', 'seeds', '{}.gba'.format(FileName)), 'rb') as target: - targetdata = target.read() - - patch = open(os.path.join('.', 'seeds', '{}.bps'.format(FileName)), 'wb') - - blocksize = (len(sourcedata) + len(targetdata)) // 1000000 + 1 - print("Using blocks of {0} bytes".format(blocksize)) + for target in World.patcher: + value = World.patcher.get(target) + patchedGame.seek(target) + patchedGame.write(value.to_bytes(1, 'little')) - iterable = diff_bytearrays(blocksize, sourcedata, targetdata) - write_bps(bps_progress(iterable), patch) + if Patch: + with open(BaseGame, 'rb') as source: + sourcedata = source.read() + with open(os.path.join('.', 'seeds', '{}.gba'.format(FileName)), 'rb') as target: + targetdata = target.read() + + patch = open(os.path.join('.', 'seeds', '{}.bps'.format(FileName)), 'wb') + + blocksize = (len(sourcedata) + len(targetdata)) // 1000000 + 1 + print("Using blocks of {0} bytes".format(blocksize)) + + iterable = diff_bytearrays(blocksize, sourcedata, targetdata) + write_bps(bps_progress(iterable), patch) print('') + ItemNames = [ 'Missile Data', 'Morph Ball', @@ -2896,67 +2900,45 @@ def patch_game(): 'Ice Beam'] if SeedSettings['RaceSeed'] == False: spoilerLog = dict() - spoilerLog.update({ - 'MFOR Version': version }) - spoilerLog.update({ - 'Seed': SeedValue }) + spoilerLog.update({ 'MFOR Version': version }) + spoilerLog.update({ 'Seed': SeedValue }) settingsDict = dict() - settingsDict.update({ - 'Difficulty': SeedSettings['Difficulty'] }) + settingsDict.update({ 'Difficulty': SeedSettings['Difficulty'] }) if SeedSettings['MajorMinor'] == False: - settingsDict.update({ - 'Item pool': 'Major items anywhere' }) + 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'] }) + 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 }) + 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) + itemProgression.update({ UsedLocations[x]: PlacedItems[x] }) + 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) def initialize():