untangle patch_game

master
magical 2024-02-03 01:25:28 -08:00
parent afde644b38
commit 707a7b70a1
1 changed files with 219 additions and 237 deletions

View File

@ -2646,166 +2646,169 @@ def patch_game():
for line in symFile: for line in symFile:
x = line.split() x = line.split()
if len(x) > 1 and re.search('^[a-zA-Z]', x[1]): if len(x) > 1 and re.search('^[a-zA-Z]', x[1]):
sym.update({ sym.update({ x[1]: x[0][2:] })
x[1]: x[0][2:] }) os.remove(os.path.join('.', 'data', 'asm', 'temp.sym'))
os.remove(os.path.join('.', 'data', 'asm', 'temp.sym')) roomEventOffset = int(sym.get('t_bossanddownloadevents'), 16)
roomEventOffset = int(sym.get('t_bossanddownloadevents'), 16) itemEventOffset = int(sym.get('t_obtainitemevents'), 16)
itemEventOffset = int(sym.get('t_obtainitemevents'), 16) securityOffset = int(sym.get('b_unlocklowerlevels'), 16)
securityOffset = int(sym.get('b_unlocklowerlevels'), 16) print('roomEventOffset: 0x{:06X}'.format(roomEventOffset))
print('roomEventOffset: 0x{:06X}'.format(roomEventOffset)) print('itemEventOffset: 0x{:06X}'.format(itemEventOffset))
print('itemEventOffset: 0x{:06X}'.format(itemEventOffset)) print('securityOffset: 0x{:06X}'.format(securityOffset))
print('securityOffset: 0x{:06X}'.format(securityOffset)) else:
roomEventOffset = 8326320 roomEventOffset = 8326320
itemEventOffset = 5726112 itemEventOffset = 5726112
securityOffset = 479192 securityOffset = 479192
for area in RoomNodes: for area in RoomNodes:
areaIndex = list(RoomNodes.keys()).index(area) areaIndex = list(RoomNodes.keys()).index(area)
for node in RoomNodes[area]: for node in RoomNodes[area]:
name = node.get('Name') name = node.get('Name')
nodeType = node.get('Type') nodeType = node.get('Type')
if nodeType != None: if nodeType != None:
itemName = '' itemName = ''
if 'Tank' in nodeType: if 'Tank' in nodeType:
itemName = PlacedItems[UsedLocations.index(name)] itemName = PlacedItems[UsedLocations.index(name)]
bg1 = int(node.get('BG1'), 16) bg1 = int(node.get('BG1'), 16)
clipdata = int(node.get('Clipdata'), 16) clipdata = int(node.get('Clipdata'), 16)
tileset = int(node.get('Tileset'), 16) tileset = int(node.get('Tileset'), 16)
if SeedSettings['HideItems']: if SeedSettings['HideItems']:
if tileset == 33: if tileset == 33:
blockValue = 7 blockValue = 7
elif tileset == 34: elif tileset == 34:
blockValue = 7 blockValue = 7
elif tileset == 40: elif tileset == 40:
blockValue = 7 blockValue = 7
elif tileset == 42: elif tileset == 42:
blockValue = 7 blockValue = 7
else: else:
blockValue = 3 blockValue = 3
else: else:
blockValue = ItemList.index(itemName) blockValue = ItemList.index(itemName)
if blockValue < 2: if blockValue < 2:
blockValue = blockValue ^ 1 blockValue = blockValue ^ 1
elif blockValue > 2: elif blockValue > 2:
if tileset == 33: if tileset == 33:
blockValue = 7 blockValue = 7
elif tileset == 34: elif tileset == 34:
blockValue = 7 blockValue = 7
elif tileset == 40: elif tileset == 40:
blockValue = 7 blockValue = 7
elif tileset == 42: elif tileset == 42:
blockValue = 7 blockValue = 7
else: else:
blockValue = 3 blockValue = 3
blockValue += 70 blockValue += 70
if tileset == 9: if tileset == 9:
blockValue += 1 blockValue += 1
elif tileset == 11: elif tileset == 11:
blockValue += 1 blockValue += 1
elif tileset == 25: elif tileset == 25:
blockValue += 1 blockValue += 1
elif tileset >= 30 and tileset <= 34: elif tileset >= 30 and tileset <= 34:
blockValue += 1 blockValue += 1
elif tileset == 40: elif tileset == 40:
blockValue += 1 blockValue += 1
elif tileset == 42: elif tileset == 42:
blockValue += 1 blockValue += 1
elif tileset == 48: elif tileset == 48:
blockValue += 1 blockValue += 1
elif tileset == 49: elif tileset == 49:
blockValue += 1 blockValue += 1
elif tileset == 52: elif tileset == 52:
blockValue += 1 blockValue += 1
elif tileset == 56: elif tileset == 56:
blockValue += 1 blockValue += 1
elif tileset == 61: elif tileset == 61:
blockValue += 1 blockValue += 1
elif tileset == 62: elif tileset == 62:
blockValue += 1 blockValue += 1
elif tileset == 64: elif tileset == 64:
blockValue += 1 blockValue += 1
elif tileset == 67: elif tileset == 67:
blockValue += 1 blockValue += 1
elif tileset == 72: elif tileset == 72:
blockValue += 1 blockValue += 1
clipValue = ItemList.index(itemName) clipValue = ItemList.index(itemName)
if clipValue < 2: if clipValue < 2:
clipValue = clipValue ^ 99 # Energy Tank or Missile Tank
if 'Hidden' in nodeType: clipValue = clipValue ^ 99
clipValue += 2 if 'Hidden' in nodeType:
elif 'Underwater' in nodeType: clipValue += 2
clipValue += 4 elif 'Underwater' in nodeType:
elif clipValue == 2: clipValue += 4
clipValue = 104 elif clipValue == 2:
if 'Hidden' in nodeType: clipValue = 104
clipValue += 1 if 'Hidden' in nodeType:
elif 'Underwater' in nodeType: clipValue += 1
clipValue += 2 elif 'Underwater' in nodeType:
elif clipValue >= 3: clipValue += 2
clipValue = (clipValue - 3) * 3 + 120 elif clipValue >= 3:
if 'Hidden' in nodeType: clipValue = (clipValue - 3)*3 + 120
clipValue += 1 if 'Hidden' in nodeType:
elif 'Underwater' in nodeType: clipValue += 1
clipValue += 2 elif 'Underwater' in nodeType:
if 'Hidden' not in nodeType: clipValue += 2
patchedGame.seek(bg1) if 'Hidden' not in nodeType:
patchedGame.write(blockValue.to_bytes(1, 'little')) patchedGame.seek(bg1)
patchedGame.seek(clipdata) patchedGame.write(blockValue.to_bytes(1, 'little'))
patchedGame.write(clipValue.to_bytes(1, 'little')) patchedGame.seek(clipdata)
elif 'Boss' in nodeType or 'Data' in nodeType: patchedGame.write(clipValue.to_bytes(1, 'little'))
itemName = PlacedItems[UsedLocations.index(name)] elif 'Boss' in nodeType or 'Data' in nodeType:
itemValue = ItemList.index(itemName) itemName = PlacedItems[UsedLocations.index(name)]
slot = BossDataList.index(name) itemValue = ItemList.index(itemName)
roomEvent = roomEventOffset slot = BossDataList.index(name)
if roomEvent != None: roomEvent = roomEventOffset
roomEvent = roomEvent + 3 + slot * 4 if roomEvent != None:
if itemValue < 3: roomEvent = roomEvent + 3 + slot*4
itemValue += 1 if itemValue < 3:
else: itemValue += 1
itemValue -= 3 else:
itemEvent = itemEventOffset itemValue -= 3
if itemEvent != None: itemEvent = itemEventOffset
itemEvent = itemEvent + 1 + itemValue if itemEvent != None:
patchedGame.seek(itemEvent) itemEvent = itemEvent + 1 + itemValue
itemValue = int.from_bytes(patchedGame.read(1), 'little') patchedGame.seek(itemEvent)
patchedGame.seek(roomEvent) itemValue = int.from_bytes(patchedGame.read(1), 'little')
patchedGame.write(itemValue.to_bytes(1, 'little')) patchedGame.seek(roomEvent)
if name == 'Data S5': patchedGame.write(itemValue.to_bytes(1, 'little'))
roomEvent = roomEventOffset if name == 'Data S5':
roomEvent = roomEvent + 3 + (slot + 1) * 4 roomEvent = roomEventOffset
patchedGame.seek(roomEvent) roomEvent = roomEvent + 3 + (slot + 1)*4
patchedGame.write(itemValue.to_bytes(1, 'little')) patchedGame.seek(roomEvent)
if itemName in MajorItems: patchedGame.write(itemValue.to_bytes(1, 'little'))
offset = CreditsOffsets.get(itemName)
if 'Boss' in nodeType: if itemName in MajorItems:
location = name offset = CreditsOffsets.get(itemName)
elif 'S0' in name: if 'Boss' in nodeType:
location = name
else:
if 'S0' in name:
location = 'Main Deck : ' location = 'Main Deck : '
else: else:
location = 'Sector {} : '.format(name[6:7]) location = 'Sector {} : '.format(name[6:7])
if 'Tank' in nodeType: if 'Tank' in nodeType:
location = location + name[8:] location = location + name[8:]
else: else:
location = location + nodeType + ' Room' location = location + nodeType + ' Room'
spaces = ceiling(30 - len(location), 2) spaces = ceiling(30 - len(location), 2)
location = ' ' * spaces + location location = ' '*spaces + location
patchedGame.seek(offset) patchedGame.seek(offset)
patchedGame.write(location.encode('ascii')) patchedGame.write(location.encode('ascii'))
for x in range(len(location), 35): for x in range(len(location), 35):
patchedGame.write((0).to_bytes(1, 'little')) patchedGame.write((0).to_bytes(1, 'little'))
if SeedSettings['HideItems']: if SeedSettings['HideItems']:
patchedGame.seek(3926048) patchedGame.seek(3926048)
patchedGame.write((76).to_bytes(2, 'little')) patchedGame.write((76).to_bytes(2, 'little'))
patchedGame.write((77).to_bytes(2, 'little')) patchedGame.write((77).to_bytes(2, 'little'))
patchedGame.write((78).to_bytes(2, 'little')) patchedGame.write((78).to_bytes(2, 'little'))
patchedGame.write((79).to_bytes(2, 'little')) patchedGame.write((79).to_bytes(2, 'little'))
patchedGame.write((76).to_bytes(2, 'little')) patchedGame.write((76).to_bytes(2, 'little'))
patchedGame.write((77).to_bytes(2, 'little')) patchedGame.write((77).to_bytes(2, 'little'))
patchedGame.write((78).to_bytes(2, 'little')) patchedGame.write((78).to_bytes(2, 'little'))
patchedGame.write((79).to_bytes(2, 'little')) patchedGame.write((79).to_bytes(2, 'little'))
patchedGame.write((76).to_bytes(2, 'little')) patchedGame.write((76).to_bytes(2, 'little'))
patchedGame.write((77).to_bytes(2, 'little')) patchedGame.write((77).to_bytes(2, 'little'))
patchedGame.write((78).to_bytes(2, 'little')) patchedGame.write((78).to_bytes(2, 'little'))
patchedGame.write((79).to_bytes(2, 'little')) patchedGame.write((79).to_bytes(2, 'little'))
if SeedSettings['SplitSecurity'] == True: if SeedSettings['SplitSecurity'] == True:
security = securityOffset security = securityOffset
patchedGame.seek(security) patchedGame.seek(security)
@ -2830,24 +2833,25 @@ def patch_game():
doorData = unpacked[0] - 134217728 doorData = unpacked[0] - 134217728
patchedGame.seek(doorData, 0) patchedGame.seek(doorData, 0)
doorNumber = 0 doorNumber = 0
connectionType = int.from_bytes(patchedGame.read(1), 'little') while True:
patchedGame.seek(5, 1) connectionType = int.from_bytes(patchedGame.read(1), 'little')
offset = patchedGame.tell() patchedGame.seek(5, 1)
connectedDoor = int.from_bytes(patchedGame.read(1), 'little') offset = patchedGame.tell()
patchedGame.seek(5, 1) connectedDoor = int.from_bytes(patchedGame.read(1), 'little')
resume = patchedGame.tell() patchedGame.seek(5, 1)
if connectionType == 0 and connectedDoor == 0: resume = patchedGame.tell()
continue if connectionType == 0 and connectedDoor == 0:
sourceDoor = 'S{}-{:02X}'.format(currentArea, doorNumber) break
targetDoorStr = World.doorConnections.get(sourceDoor) sourceDoor = 'S{}-{:02X}'.format(currentArea, doorNumber)
connectedArea = World.areaConnections.get(sourceDoor, currentArea) targetDoorStr = World.doorConnections.get(sourceDoor)
connectedDoorStr = 'S{}-{:02X}'.format(connectedArea, connectedDoor) connectedArea = World.areaConnections.get(sourceDoor, currentArea)
if connectedDoorStr != targetDoorStr: connectedDoorStr = 'S{}-{:02X}'.format(connectedArea, connectedDoor)
targetDoor = int(targetDoorStr[-2:], 16) if connectedDoorStr != targetDoorStr:
patchedGame.seek(offset) targetDoor = int(targetDoorStr[-2:], 16)
patchedGame.write(targetDoor.to_bytes(1, 'little')) patchedGame.seek(offset)
patchedGame.seek(resume) patchedGame.write(targetDoor.to_bytes(1, 'little'))
doorNumber += 1 patchedGame.seek(resume)
doorNumber += 1
for door, targetArea in World.areaConnections.items(): for door, targetArea in World.areaConnections.items():
offset = World.areaConnectionOffsets.get(door) offset = World.areaConnectionOffsets.get(door)
patchedGame.seek(offset) patchedGame.seek(offset)
@ -2855,26 +2859,26 @@ def patch_game():
if areaByte != targetArea: if areaByte != targetArea:
patchedGame.seek(offset) patchedGame.seek(offset)
patchedGame.write(targetArea.to_bytes(1, 'little')) patchedGame.write(targetArea.to_bytes(1, 'little'))
continue for target in World.patcher:
for target in World.patcher: value = World.patcher.get(target)
value = World.patcher.get(target) patchedGame.seek(target)
patchedGame.seek(target) patchedGame.write(value.to_bytes(1, 'little'))
patchedGame.write(value.to_bytes(1, 'little'))
if Patch: if Patch:
with open(BaseGame, 'rb') as source: with open(BaseGame, 'rb') as source:
sourcedata = source.read() sourcedata = source.read()
with open(os.path.join('.', 'seeds', '{}.gba'.format(FileName)), 'rb') as target: with open(os.path.join('.', 'seeds', '{}.gba'.format(FileName)), 'rb') as target:
targetdata = target.read() targetdata = target.read()
patch = open(os.path.join('.', 'seeds', '{}.bps'.format(FileName)), 'wb') patch = open(os.path.join('.', 'seeds', '{}.bps'.format(FileName)), 'wb')
blocksize = (len(sourcedata) + len(targetdata)) // 1000000 + 1 blocksize = (len(sourcedata) + len(targetdata)) // 1000000 + 1
print("Using blocks of {0} bytes".format(blocksize)) print("Using blocks of {0} bytes".format(blocksize))
iterable = diff_bytearrays(blocksize, sourcedata, targetdata) iterable = diff_bytearrays(blocksize, sourcedata, targetdata)
write_bps(bps_progress(iterable), patch) write_bps(bps_progress(iterable), patch)
print('') print('')
ItemNames = [ ItemNames = [
'Missile Data', 'Missile Data',
'Morph Ball', 'Morph Ball',
@ -2896,67 +2900,45 @@ def patch_game():
'Ice Beam'] 'Ice Beam']
if SeedSettings['RaceSeed'] == False: if SeedSettings['RaceSeed'] == False:
spoilerLog = dict() spoilerLog = dict()
spoilerLog.update({ spoilerLog.update({ 'MFOR Version': version })
'MFOR Version': version }) spoilerLog.update({ 'Seed': SeedValue })
spoilerLog.update({
'Seed': SeedValue })
settingsDict = dict() settingsDict = dict()
settingsDict.update({ settingsDict.update({ 'Difficulty': SeedSettings['Difficulty'] })
'Difficulty': SeedSettings['Difficulty'] })
if SeedSettings['MajorMinor'] == False: if SeedSettings['MajorMinor'] == False:
settingsDict.update({ settingsDict.update({ 'Item pool': 'Major items anywhere' })
'Item pool': 'Major items anywhere' })
else: else:
settingsDict.update({ settingsDict.update({ 'Item pool': 'Limited major item locations' })
'Item pool': 'Limited major item locations' }) settingsDict.update({ 'Missile upgrades enable Missiles': SeedSettings['MissilesWithoutMainData'] })
settingsDict.update({ settingsDict.update({ 'Power Bombs without normal Bombs': SeedSettings['PowerBombsWithoutBombs'] })
'Missile upgrades enable Missiles': SeedSettings['MissilesWithoutMainData'] }) settingsDict.update({ 'Allow logical damage runs': SeedSettings['DamageRuns'] })
settingsDict.update({ settingsDict.update({ 'Separated security levels': SeedSettings['SplitSecurity'] })
'Power Bombs without normal Bombs': SeedSettings['PowerBombsWithoutBombs'] }) settingsDict.update({ 'Sector shuffle': SeedSettings['SectorShuffle'] })
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: if SeedSettings['SectorShuffle'] == True:
sectorLayout = str() sectorLayout = str()
for x in areaLayout: for x in areaLayout:
sectorLayout = sectorLayout.strip() + ' {}'.format(x) sectorLayout = sectorLayout.strip() + ' {}'.format(x)
settingsDict.update({ settingsDict.update({ 'Sector layout:': sectorLayout })
'Sector layout:': sectorLayout }) settingsDict.update({ 'Hide item graphics': SeedSettings['HideItems'] })
settingsDict.update({ settingsDict.update({ 'E-Tanks': PlacedETanks })
'Hide item graphics': SeedSettings['HideItems'] }) settingsDict.update({ 'Missile Tanks': PlacedMissiles })
settingsDict.update({ settingsDict.update({ 'Power Bomb Tanks': PlacedPowerBombs })
'E-Tanks': PlacedETanks }) spoilerLog.update({ 'Settings': settingsDict })
settingsDict.update({
'Missile Tanks': PlacedMissiles })
settingsDict.update({
'Power Bomb Tanks': PlacedPowerBombs })
spoilerLog.update({
'Settings': settingsDict })
itemProgression = dict() itemProgression = dict()
for x in range(len(PlacedItems)): for x in range(len(PlacedItems)):
if PlacedItems[x] in MajorItems: if PlacedItems[x] in MajorItems:
namedItem = ItemNames[MajorItems.index(PlacedItems[x])] namedItem = ItemNames[MajorItems.index(PlacedItems[x])]
PlacedItems[x] = namedItem PlacedItems[x] = namedItem
itemProgression.update({ itemProgression.update({ UsedLocations[x]: PlacedItems[x] })
UsedLocations[x]: PlacedItems[x] }) spoilerLog.update({ 'Item order': itemProgression })
continue itemDict = dict()
spoilerLog.update({ World.itemLocations.sort()
'Item order': itemProgression }) for x in range(0, len(World.itemLocations)):
itemDict = dict() itemDict.update({ World.itemLocations[x]: 0 })
World.itemLocations.sort() for x in range(0, len(PlacedItems)):
for x in range(0, len(World.itemLocations)): itemDict.update({ UsedLocations[x]: PlacedItems[x] })
itemDict.update({ spoilerLog.update({ 'Items': itemDict })
World.itemLocations[x]: 0 }) with open(os.path.join('.', 'spoilers', '{}.json'.format(FileName)), 'w') as spoiler:
for x in range(0, len(PlacedItems)): json.dump(spoilerLog, spoiler, indent=4)
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(): def initialize():