SM: failing generation fixes (#1726)
- fixed wrong condition in Collect to assign lastAP - fixed possible infinite loop in generating output when many SM worlds are present - fixed new VARIA code that changed a list used for every SM worlds and would throw if many SM worlds uses Aea rando and not AreaLayout
This commit is contained in:
parent
f6758524d5
commit
cb634fa8d4
|
@ -22,8 +22,9 @@ import Utils
|
||||||
from .variaRandomizer.logic.smboolmanager import SMBoolManager
|
from .variaRandomizer.logic.smboolmanager import SMBoolManager
|
||||||
from .variaRandomizer.graph.vanilla.graph_locations import locationsDict
|
from .variaRandomizer.graph.vanilla.graph_locations import locationsDict
|
||||||
from .variaRandomizer.graph.graph_utils import getAccessPoint
|
from .variaRandomizer.graph.graph_utils import getAccessPoint
|
||||||
from .variaRandomizer.rando.ItemLocContainer import ItemLocation
|
from .variaRandomizer.rando.ItemLocContainer import ItemLocation, ItemLocContainer
|
||||||
from .variaRandomizer.rando.Items import ItemManager
|
from .variaRandomizer.rando.Items import ItemManager
|
||||||
|
from .variaRandomizer.rando.RandoServices import ComebackCheckType
|
||||||
from .variaRandomizer.utils.parameters import *
|
from .variaRandomizer.utils.parameters import *
|
||||||
from .variaRandomizer.utils.utils import openFile
|
from .variaRandomizer.utils.utils import openFile
|
||||||
from .variaRandomizer.logic.logic import Logic
|
from .variaRandomizer.logic.logic import Logic
|
||||||
|
@ -169,9 +170,13 @@ class SMWorld(World):
|
||||||
elif item.Category == 'Nothing':
|
elif item.Category == 'Nothing':
|
||||||
isAdvancement = False
|
isAdvancement = False
|
||||||
|
|
||||||
|
classification = ItemClassification.progression if isAdvancement else ItemClassification.filler
|
||||||
itemClass = ItemManager.Items[item.Type].Class
|
itemClass = ItemManager.Items[item.Type].Class
|
||||||
smitem = SMItem(item.Name, ItemClassification.progression if isAdvancement else ItemClassification.filler,
|
smitem = SMItem(item.Name,
|
||||||
item.Type, None if itemClass == 'Boss' else self.item_name_to_id[item.Name], player=self.player)
|
classification,
|
||||||
|
item.Type,
|
||||||
|
None if itemClass == 'Boss' else self.item_name_to_id[item.Name],
|
||||||
|
player=self.player)
|
||||||
if itemClass == 'Boss':
|
if itemClass == 'Boss':
|
||||||
self.locked_items[item.Name] = smitem
|
self.locked_items[item.Name] = smitem
|
||||||
elif item.Category == 'Nothing':
|
elif item.Category == 'Nothing':
|
||||||
|
@ -645,10 +650,10 @@ class SMWorld(World):
|
||||||
|
|
||||||
def collect(self, state: CollectionState, item: Item) -> bool:
|
def collect(self, state: CollectionState, item: Item) -> bool:
|
||||||
state.smbm[self.player].addItem(item.type)
|
state.smbm[self.player].addItem(item.type)
|
||||||
if (item.location != None and item.location.player == self.player):
|
if item.location != None:
|
||||||
for entrance in self.multiworld.get_region(item.location.parent_region.name, self.player).entrances:
|
for entrance in self.multiworld.get_region(item.location.parent_region.name, item.location.player).entrances:
|
||||||
if (entrance.parent_region.can_reach(state)):
|
if (entrance.parent_region.can_reach(state)):
|
||||||
state.smbm[self.player].lastAP = entrance.parent_region.name
|
state.smbm[item.location.player].lastAP = entrance.parent_region.name
|
||||||
break
|
break
|
||||||
return super(SMWorld, self).collect(state, item)
|
return super(SMWorld, self).collect(state, item)
|
||||||
|
|
||||||
|
@ -797,29 +802,25 @@ class SMLocation(Location):
|
||||||
def can_reach(self, state: CollectionState) -> bool:
|
def can_reach(self, state: CollectionState) -> bool:
|
||||||
# self.access_rule computes faster on average, so placing it first for faster abort
|
# self.access_rule computes faster on average, so placing it first for faster abort
|
||||||
assert self.parent_region, "Can't reach location without region"
|
assert self.parent_region, "Can't reach location without region"
|
||||||
return self.access_rule(state) and self.parent_region.can_reach(state) and self.can_comeback(state)
|
return self.access_rule(state) and \
|
||||||
|
self.parent_region.can_reach(state) and \
|
||||||
|
self.can_comeback(state, self.item)
|
||||||
|
|
||||||
def can_comeback(self, state: CollectionState):
|
def can_comeback(self, state: CollectionState, item):
|
||||||
# some specific early/late game checks
|
|
||||||
if self.name == 'Bomb' or self.name == 'Mother Brain':
|
|
||||||
return True
|
|
||||||
|
|
||||||
randoExec = state.multiworld.worlds[self.player].variaRando.randoExec
|
randoExec = state.multiworld.worlds[self.player].variaRando.randoExec
|
||||||
|
randoService = randoExec.setup.services
|
||||||
|
|
||||||
|
comebackCheck = ComebackCheckType.JustComeback
|
||||||
n = 2 if GraphUtils.isStandardStart(randoExec.graphSettings.startAP) else 3
|
n = 2 if GraphUtils.isStandardStart(randoExec.graphSettings.startAP) else 3
|
||||||
# is early game
|
# is early game
|
||||||
if (len([loc for loc in state.locations_checked if loc.player == self.player]) <= n):
|
if (len([loc for loc in state.locations_checked if loc.player == self.player]) <= n):
|
||||||
return True
|
comebackCheck = ComebackCheckType.NoCheck
|
||||||
|
container = ItemLocContainer(state.smbm[self.player], [], [])
|
||||||
for key in locationsDict[self.name].AccessFrom.keys():
|
return randoService.fullComebackCheck( container,
|
||||||
smbm = state.smbm[self.player]
|
state.smbm[self.player].lastAP,
|
||||||
if (randoExec.areaGraph.canAccess( smbm,
|
ItemManager.Items[item.type] if item is not None and item.player == self.player else None,
|
||||||
smbm.lastAP,
|
locationsDict[self.name],
|
||||||
key,
|
comebackCheck)
|
||||||
smbm.maxDiff,
|
|
||||||
None)):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
class SMItem(Item):
|
class SMItem(Item):
|
||||||
game = "Super Metroid"
|
game = "Super Metroid"
|
||||||
|
|
|
@ -362,7 +362,8 @@ class AccessGraph(object):
|
||||||
|
|
||||||
# test access from an access point to another, given an optional item
|
# test access from an access point to another, given an optional item
|
||||||
def canAccess(self, smbm, srcAccessPointName, destAccessPointName, maxDiff, item=None):
|
def canAccess(self, smbm, srcAccessPointName, destAccessPointName, maxDiff, item=None):
|
||||||
if item is not None:
|
addAndRemoveItem = item is not None and (smbm.isCountItem(item) or not smbm.haveItem(item))
|
||||||
|
if addAndRemoveItem:
|
||||||
smbm.addItem(item)
|
smbm.addItem(item)
|
||||||
#print("canAccess: item: {}, src: {}, dest: {}".format(item, srcAccessPointName, destAccessPointName))
|
#print("canAccess: item: {}, src: {}, dest: {}".format(item, srcAccessPointName, destAccessPointName))
|
||||||
destAccessPoint = self.accessPoints[destAccessPointName]
|
destAccessPoint = self.accessPoints[destAccessPointName]
|
||||||
|
@ -371,7 +372,7 @@ class AccessGraph(object):
|
||||||
can = destAccessPoint in availAccessPoints
|
can = destAccessPoint in availAccessPoints
|
||||||
# if not can:
|
# if not can:
|
||||||
# self.log.debug("canAccess KO: avail = {}".format([ap.Name for ap in availAccessPoints.keys()]))
|
# self.log.debug("canAccess KO: avail = {}".format([ap.Name for ap in availAccessPoints.keys()]))
|
||||||
if item is not None:
|
if addAndRemoveItem:
|
||||||
smbm.removeItem(item)
|
smbm.removeItem(item)
|
||||||
#print("canAccess: {}".format(can))
|
#print("canAccess: {}".format(can))
|
||||||
return can
|
return can
|
||||||
|
|
|
@ -59,9 +59,12 @@ class Location:
|
||||||
|
|
||||||
def evalPostAvailable(self, smbm):
|
def evalPostAvailable(self, smbm):
|
||||||
if self.difficulty.bool == True and self.PostAvailable is not None:
|
if self.difficulty.bool == True and self.PostAvailable is not None:
|
||||||
smbm.addItem(self.itemName)
|
addAndRemoveItem = smbm.isCountItem(self.itemName) or not smbm.haveItem(self.itemName)
|
||||||
|
if addAndRemoveItem:
|
||||||
|
smbm.addItem(self.itemName)
|
||||||
postAvailable = self.PostAvailable(smbm)
|
postAvailable = self.PostAvailable(smbm)
|
||||||
smbm.removeItem(self.itemName)
|
if addAndRemoveItem:
|
||||||
|
smbm.removeItem(self.itemName)
|
||||||
|
|
||||||
self.difficulty = self.difficulty & postAvailable
|
self.difficulty = self.difficulty & postAvailable
|
||||||
if self.locDifficulty is not None:
|
if self.locDifficulty is not None:
|
||||||
|
|
|
@ -91,9 +91,12 @@ class SMBoolManager(object):
|
||||||
return itemsDict
|
return itemsDict
|
||||||
|
|
||||||
def withItem(self, item, func):
|
def withItem(self, item, func):
|
||||||
self.addItem(item)
|
addAndRemoveItem = self.isCountItem(item) or not self.haveItem(item)
|
||||||
|
if addAndRemoveItem:
|
||||||
|
self.addItem(item)
|
||||||
ret = func(self)
|
ret = func(self)
|
||||||
self.removeItem(item)
|
if addAndRemoveItem:
|
||||||
|
self.removeItem(item)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def resetItems(self):
|
def resetItems(self):
|
||||||
|
|
|
@ -279,11 +279,12 @@ class RomPatcher:
|
||||||
|
|
||||||
# apply area patches
|
# apply area patches
|
||||||
if self.settings["area"] == True:
|
if self.settings["area"] == True:
|
||||||
|
areaPatches = list(RomPatcher.IPSPatches['Area'])
|
||||||
if not self.settings["areaLayout"]:
|
if not self.settings["areaLayout"]:
|
||||||
for p in ['area_rando_layout.ips', 'Sponge_Bath_Blinking_Door', 'east_ocean.ips', 'aqueduct_bomb_blocks.ips']:
|
for p in ['area_rando_layout.ips', 'Sponge_Bath_Blinking_Door', 'east_ocean.ips', 'aqueduct_bomb_blocks.ips']:
|
||||||
RomPatcher.IPSPatches['Area'].remove(p)
|
areaPatches.remove(p)
|
||||||
RomPatcher.IPSPatches['Area'].append('area_rando_layout_base.ips')
|
areaPatches.append('area_rando_layout_base.ips')
|
||||||
for patchName in RomPatcher.IPSPatches['Area']:
|
for patchName in areaPatches:
|
||||||
self.applyIPSPatch(patchName)
|
self.applyIPSPatch(patchName)
|
||||||
else:
|
else:
|
||||||
self.applyIPSPatch('area_ids_alt.ips')
|
self.applyIPSPatch('area_ids_alt.ips')
|
||||||
|
|
|
@ -740,7 +740,7 @@ class Objectives(object):
|
||||||
if c not in char2tile:
|
if c not in char2tile:
|
||||||
continue
|
continue
|
||||||
romFile.writeWord(0x3800 + char2tile[c])
|
romFile.writeWord(0x3800 + char2tile[c])
|
||||||
|
Synonyms.alreadyUsed = []
|
||||||
# write goal completed positions y in sprites OAM
|
# write goal completed positions y in sprites OAM
|
||||||
baseY = 0x40
|
baseY = 0x40
|
||||||
addr = Addresses.getOne('objectivesSpritesOAM')
|
addr = Addresses.getOne('objectivesSpritesOAM')
|
||||||
|
|
Loading…
Reference in New Issue