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.graph.vanilla.graph_locations import locationsDict
 | 
			
		||||
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.RandoServices import ComebackCheckType
 | 
			
		||||
from .variaRandomizer.utils.parameters import *
 | 
			
		||||
from .variaRandomizer.utils.utils import openFile
 | 
			
		||||
from .variaRandomizer.logic.logic import Logic
 | 
			
		||||
| 
						 | 
				
			
			@ -169,9 +170,13 @@ class SMWorld(World):
 | 
			
		|||
            elif item.Category == 'Nothing':
 | 
			
		||||
                isAdvancement = False
 | 
			
		||||
 | 
			
		||||
            classification = ItemClassification.progression if isAdvancement else ItemClassification.filler
 | 
			
		||||
            itemClass = ItemManager.Items[item.Type].Class
 | 
			
		||||
            smitem = SMItem(item.Name, ItemClassification.progression if isAdvancement else ItemClassification.filler,
 | 
			
		||||
                            item.Type, None if itemClass == 'Boss' else self.item_name_to_id[item.Name], player=self.player)
 | 
			
		||||
            smitem = SMItem(item.Name, 
 | 
			
		||||
                            classification, 
 | 
			
		||||
                            item.Type,
 | 
			
		||||
                            None if itemClass == 'Boss' else self.item_name_to_id[item.Name], 
 | 
			
		||||
                            player=self.player)
 | 
			
		||||
            if itemClass == 'Boss':
 | 
			
		||||
                self.locked_items[item.Name] = smitem
 | 
			
		||||
            elif item.Category == 'Nothing':
 | 
			
		||||
| 
						 | 
				
			
			@ -645,10 +650,10 @@ class SMWorld(World):
 | 
			
		|||
 | 
			
		||||
    def collect(self, state: CollectionState, item: Item) -> bool:
 | 
			
		||||
        state.smbm[self.player].addItem(item.type)
 | 
			
		||||
        if (item.location != None and item.location.player == self.player):
 | 
			
		||||
            for entrance in self.multiworld.get_region(item.location.parent_region.name, self.player).entrances:
 | 
			
		||||
        if item.location != None:
 | 
			
		||||
            for entrance in self.multiworld.get_region(item.location.parent_region.name, item.location.player).entrances:
 | 
			
		||||
                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
 | 
			
		||||
        return super(SMWorld, self).collect(state, item)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -797,29 +802,25 @@ class SMLocation(Location):
 | 
			
		|||
    def can_reach(self, state: CollectionState) -> bool:
 | 
			
		||||
        # self.access_rule computes faster on average, so placing it first for faster abort
 | 
			
		||||
        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)
 | 
			
		||||
    
 | 
			
		||||
    def can_comeback(self, state: CollectionState):
 | 
			
		||||
        # some specific early/late game checks
 | 
			
		||||
        if self.name == 'Bomb' or self.name == 'Mother Brain':
 | 
			
		||||
            return True
 | 
			
		||||
        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, item):
 | 
			
		||||
        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
 | 
			
		||||
        # is early game
 | 
			
		||||
        if (len([loc for loc in state.locations_checked if loc.player == self.player]) <= n):
 | 
			
		||||
            return True
 | 
			
		||||
 | 
			
		||||
        for key in locationsDict[self.name].AccessFrom.keys():
 | 
			
		||||
            smbm = state.smbm[self.player]
 | 
			
		||||
            if (randoExec.areaGraph.canAccess(  smbm, 
 | 
			
		||||
                                                smbm.lastAP,
 | 
			
		||||
                                                key,
 | 
			
		||||
                                                smbm.maxDiff,
 | 
			
		||||
                                                None)):
 | 
			
		||||
                return True
 | 
			
		||||
        return False
 | 
			
		||||
 
 | 
			
		||||
            comebackCheck = ComebackCheckType.NoCheck
 | 
			
		||||
        container = ItemLocContainer(state.smbm[self.player], [], [])
 | 
			
		||||
        return randoService.fullComebackCheck(  container, 
 | 
			
		||||
                                                state.smbm[self.player].lastAP, 
 | 
			
		||||
                                                ItemManager.Items[item.type] if item is not None and item.player == self.player else None,
 | 
			
		||||
                                                locationsDict[self.name], 
 | 
			
		||||
                                                comebackCheck) 
 | 
			
		||||
 | 
			
		||||
class SMItem(Item):
 | 
			
		||||
    game = "Super Metroid"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -362,7 +362,8 @@ class AccessGraph(object):
 | 
			
		|||
 | 
			
		||||
    # test access from an access point to another, given an optional item
 | 
			
		||||
    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)
 | 
			
		||||
        #print("canAccess: item: {}, src: {}, dest: {}".format(item, srcAccessPointName, destAccessPointName))
 | 
			
		||||
        destAccessPoint = self.accessPoints[destAccessPointName]
 | 
			
		||||
| 
						 | 
				
			
			@ -371,7 +372,7 @@ class AccessGraph(object):
 | 
			
		|||
        can = destAccessPoint in availAccessPoints
 | 
			
		||||
        # if not can:
 | 
			
		||||
        #     self.log.debug("canAccess KO: avail = {}".format([ap.Name for ap in availAccessPoints.keys()]))
 | 
			
		||||
        if item is not None:
 | 
			
		||||
        if addAndRemoveItem:
 | 
			
		||||
            smbm.removeItem(item)
 | 
			
		||||
        #print("canAccess: {}".format(can))
 | 
			
		||||
        return can
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -59,8 +59,11 @@ class Location:
 | 
			
		|||
 | 
			
		||||
    def evalPostAvailable(self, smbm):
 | 
			
		||||
        if self.difficulty.bool == True and self.PostAvailable is not None:
 | 
			
		||||
            addAndRemoveItem = smbm.isCountItem(self.itemName) or not smbm.haveItem(self.itemName)
 | 
			
		||||
            if addAndRemoveItem:
 | 
			
		||||
                smbm.addItem(self.itemName)
 | 
			
		||||
            postAvailable = self.PostAvailable(smbm)
 | 
			
		||||
            if addAndRemoveItem:
 | 
			
		||||
                smbm.removeItem(self.itemName)
 | 
			
		||||
 | 
			
		||||
            self.difficulty = self.difficulty & postAvailable
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -91,8 +91,11 @@ class SMBoolManager(object):
 | 
			
		|||
        return itemsDict
 | 
			
		||||
 | 
			
		||||
    def withItem(self, item, func):
 | 
			
		||||
        addAndRemoveItem = self.isCountItem(item) or not self.haveItem(item)
 | 
			
		||||
        if addAndRemoveItem:
 | 
			
		||||
            self.addItem(item)
 | 
			
		||||
        ret = func(self)
 | 
			
		||||
        if addAndRemoveItem:
 | 
			
		||||
            self.removeItem(item)
 | 
			
		||||
        return ret
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -279,11 +279,12 @@ class RomPatcher:
 | 
			
		|||
 | 
			
		||||
            # apply area patches
 | 
			
		||||
            if self.settings["area"] == True:
 | 
			
		||||
                areaPatches = list(RomPatcher.IPSPatches['Area'])
 | 
			
		||||
                if not self.settings["areaLayout"]:
 | 
			
		||||
                    for p in ['area_rando_layout.ips', 'Sponge_Bath_Blinking_Door', 'east_ocean.ips', 'aqueduct_bomb_blocks.ips']:
 | 
			
		||||
                       RomPatcher.IPSPatches['Area'].remove(p)
 | 
			
		||||
                    RomPatcher.IPSPatches['Area'].append('area_rando_layout_base.ips')
 | 
			
		||||
                for patchName in RomPatcher.IPSPatches['Area']:
 | 
			
		||||
                       areaPatches.remove(p)
 | 
			
		||||
                    areaPatches.append('area_rando_layout_base.ips')
 | 
			
		||||
                for patchName in areaPatches:
 | 
			
		||||
                    self.applyIPSPatch(patchName)
 | 
			
		||||
            else:
 | 
			
		||||
                self.applyIPSPatch('area_ids_alt.ips')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -740,7 +740,7 @@ class Objectives(object):
 | 
			
		|||
                if c not in char2tile:
 | 
			
		||||
                    continue
 | 
			
		||||
                romFile.writeWord(0x3800 + char2tile[c])
 | 
			
		||||
 | 
			
		||||
        Synonyms.alreadyUsed = []
 | 
			
		||||
        # write goal completed positions y in sprites OAM
 | 
			
		||||
        baseY = 0x40
 | 
			
		||||
        addr = Addresses.getOne('objectivesSpritesOAM')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue