LttP: Move more functionality into ALttPItem from Item
LttP: More efficiently build !hint entrance info LttP: More efficiently check for and build Big Bomb Shop playthrough path
This commit is contained in:
		
							parent
							
								
									de4775b0c8
								
							
						
					
					
						commit
						de567cc701
					
				| 
						 | 
				
			
			@ -808,10 +808,6 @@ class Region(object):
 | 
			
		|||
        return False
 | 
			
		||||
 | 
			
		||||
    def can_fill(self, item: Item):
 | 
			
		||||
        inside_dungeon_item = item.locked_dungeon_item
 | 
			
		||||
        if inside_dungeon_item:
 | 
			
		||||
            return self.dungeon.is_dungeon_item(item) and item.player == self.player
 | 
			
		||||
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
| 
						 | 
				
			
			@ -973,15 +969,24 @@ class Location():
 | 
			
		|||
class Item():
 | 
			
		||||
    location: Optional[Location] = None
 | 
			
		||||
    world: Optional[MultiWorld] = None
 | 
			
		||||
    code: Optional[str] = None  # an item with ID None is called an Event, and does not get written to multidata
 | 
			
		||||
    game: str = "Generic"
 | 
			
		||||
    type: str = None
 | 
			
		||||
    never_exclude = False  # change manually to ensure that a specific nonprogression item never goes on an excluded location
 | 
			
		||||
    # change manually to ensure that a specific non-progression item never goes on an excluded location
 | 
			
		||||
    never_exclude = False
 | 
			
		||||
 | 
			
		||||
    # need to find a decent place for these to live and to allow other games to register texts if they want.
 | 
			
		||||
    pedestal_credit_text: str = "and the Unknown Item"
 | 
			
		||||
    sickkid_credit_text: Optional[str] = None
 | 
			
		||||
    magicshop_credit_text: Optional[str] = None
 | 
			
		||||
    zora_credit_text: Optional[str] = None
 | 
			
		||||
    fluteboy_credit_text: Optional[str] = None
 | 
			
		||||
    code: Optional[str] = None  # an item with ID None is called an Event, and does not get written to multidata
 | 
			
		||||
 | 
			
		||||
    # hopefully temporary attributes to satisfy legacy LttP code, proper implementation in subclass ALttPItem
 | 
			
		||||
    smallkey: bool = False
 | 
			
		||||
    bigkey: bool = False
 | 
			
		||||
    map: bool = False
 | 
			
		||||
    compass: bool = False
 | 
			
		||||
 | 
			
		||||
    def __init__(self, name: str, advancement: bool, code: Optional[int], player: int):
 | 
			
		||||
        self.name = name
 | 
			
		||||
| 
						 | 
				
			
			@ -1008,51 +1013,6 @@ class Item():
 | 
			
		|||
    def __hash__(self):
 | 
			
		||||
        return hash((self.name, self.player))
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def crystal(self) -> bool:
 | 
			
		||||
        return self.type == 'Crystal'
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def smallkey(self) -> bool:
 | 
			
		||||
        return self.type == 'SmallKey'
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def bigkey(self) -> bool:
 | 
			
		||||
        return self.type == 'BigKey'
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def map(self) -> bool:
 | 
			
		||||
        return self.type == 'Map'
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def compass(self) -> bool:
 | 
			
		||||
        return self.type == 'Compass'
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def dungeon_item(self) -> Optional[str]:
 | 
			
		||||
        if self.game == "A Link to the Past" and self.type in {"SmallKey", "BigKey", "Map", "Compass"}:
 | 
			
		||||
            return self.type
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def shuffled_dungeon_item(self) -> bool:
 | 
			
		||||
        dungeon_item_type = self.dungeon_item
 | 
			
		||||
        if dungeon_item_type:
 | 
			
		||||
            return {"SmallKey" : self.world.keyshuffle,
 | 
			
		||||
                    "BigKey": self.world.bigkeyshuffle,
 | 
			
		||||
                    "Map": self.world.mapshuffle,
 | 
			
		||||
                    "Compass": self.world.compassshuffle}[dungeon_item_type][self.player]
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def locked_dungeon_item(self) -> bool:
 | 
			
		||||
        dungeon_item_type = self.dungeon_item
 | 
			
		||||
        if dungeon_item_type:
 | 
			
		||||
            return not {"SmallKey" : self.world.keyshuffle,
 | 
			
		||||
                        "BigKey": self.world.bigkeyshuffle,
 | 
			
		||||
                        "Map": self.world.mapshuffle,
 | 
			
		||||
                        "Compass": self.world.compassshuffle}[dungeon_item_type][self.player]
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
        return self.__str__()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										46
									
								
								Main.py
								
								
								
								
							
							
						
						
									
										46
									
								
								Main.py
								
								
								
								
							| 
						 | 
				
			
			@ -249,20 +249,21 @@ def main(args, seed=None):
 | 
			
		|||
        for player in range(1, world.players + 1):
 | 
			
		||||
            checks_in_area[player]["Total"] = 0
 | 
			
		||||
 | 
			
		||||
        for location in [loc for loc in world.get_filled_locations() if type(loc.address) is int]:
 | 
			
		||||
            main_entrance = get_entrance_to_region(location.parent_region)
 | 
			
		||||
            if location.game != "A Link to the Past":
 | 
			
		||||
                checks_in_area[location.player]["Light World"].append(location.address)
 | 
			
		||||
            elif location.parent_region.dungeon:
 | 
			
		||||
                dungeonname = {'Inverted Agahnims Tower': 'Agahnims Tower',
 | 
			
		||||
                               'Inverted Ganons Tower': 'Ganons Tower'} \
 | 
			
		||||
                    .get(location.parent_region.dungeon.name, location.parent_region.dungeon.name)
 | 
			
		||||
                checks_in_area[location.player][dungeonname].append(location.address)
 | 
			
		||||
            elif main_entrance.parent_region.type == RegionType.LightWorld:
 | 
			
		||||
                checks_in_area[location.player]["Light World"].append(location.address)
 | 
			
		||||
            elif main_entrance.parent_region.type == RegionType.DarkWorld:
 | 
			
		||||
                checks_in_area[location.player]["Dark World"].append(location.address)
 | 
			
		||||
            checks_in_area[location.player]["Total"] += 1
 | 
			
		||||
        for location in world.get_filled_locations():
 | 
			
		||||
            if type(location.address) is int:
 | 
			
		||||
                main_entrance = get_entrance_to_region(location.parent_region)
 | 
			
		||||
                if location.game != "A Link to the Past":
 | 
			
		||||
                    checks_in_area[location.player]["Light World"].append(location.address)
 | 
			
		||||
                elif location.parent_region.dungeon:
 | 
			
		||||
                    dungeonname = {'Inverted Agahnims Tower': 'Agahnims Tower',
 | 
			
		||||
                                   'Inverted Ganons Tower': 'Ganons Tower'} \
 | 
			
		||||
                        .get(location.parent_region.dungeon.name, location.parent_region.dungeon.name)
 | 
			
		||||
                    checks_in_area[location.player][dungeonname].append(location.address)
 | 
			
		||||
                elif main_entrance.parent_region.type == RegionType.LightWorld:
 | 
			
		||||
                    checks_in_area[location.player]["Light World"].append(location.address)
 | 
			
		||||
                elif main_entrance.parent_region.type == RegionType.DarkWorld:
 | 
			
		||||
                    checks_in_area[location.player]["Dark World"].append(location.address)
 | 
			
		||||
                checks_in_area[location.player]["Total"] += 1
 | 
			
		||||
 | 
			
		||||
        oldmancaves = []
 | 
			
		||||
        takeanyregions = ["Old Man Sword Cave", "Take-Any #1", "Take-Any #2", "Take-Any #3", "Take-Any #4"]
 | 
			
		||||
| 
						 | 
				
			
			@ -497,14 +498,15 @@ def create_playthrough(world):
 | 
			
		|||
            {str(location): get_path(state, location.parent_region) for sphere in collection_spheres for location in
 | 
			
		||||
             sphere if location.player == player})
 | 
			
		||||
        if player in world.get_game_players("A Link to the Past"):
 | 
			
		||||
            for path in dict(world.spoiler.paths).values():
 | 
			
		||||
                if any(exit_path == 'Pyramid Fairy' for (_, exit_path) in path):
 | 
			
		||||
                    if world.mode[player] != 'inverted':
 | 
			
		||||
                        world.spoiler.paths[str(world.get_region('Big Bomb Shop', player))] = \
 | 
			
		||||
                            get_path(state,world.get_region('Big Bomb Shop', player))
 | 
			
		||||
                    else:
 | 
			
		||||
                        world.spoiler.paths[str(world.get_region('Inverted Big Bomb Shop', player))] = \
 | 
			
		||||
                            get_path(state,world.get_region('Inverted Big Bomb Shop', player))
 | 
			
		||||
            # If Pyramid Fairy Entrance needs to be reached, also path to Big Bomb Shop
 | 
			
		||||
            # Maybe move the big bomb over to the Event system instead?
 | 
			
		||||
            if any(exit_path == 'Pyramid Fairy' for path in world.spoiler.paths.values() for (_, exit_path) in path):
 | 
			
		||||
                if world.mode[player] != 'inverted':
 | 
			
		||||
                    world.spoiler.paths[str(world.get_region('Big Bomb Shop', player))] = \
 | 
			
		||||
                        get_path(state, world.get_region('Big Bomb Shop', player))
 | 
			
		||||
                else:
 | 
			
		||||
                    world.spoiler.paths[str(world.get_region('Inverted Big Bomb Shop', player))] = \
 | 
			
		||||
                        get_path(state, world.get_region('Inverted Big Bomb Shop', player))
 | 
			
		||||
 | 
			
		||||
    # we can finally output our playthrough
 | 
			
		||||
    world.spoiler.playthrough = {"0": sorted([str(item) for item in world.precollected_items if item.advancement])}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								Utils.py
								
								
								
								
							
							
						
						
									
										2
									
								
								Utils.py
								
								
								
								
							| 
						 | 
				
			
			@ -13,7 +13,7 @@ class Version(typing.NamedTuple):
 | 
			
		|||
    build: int
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
__version__ = "0.1.6"
 | 
			
		||||
__version__ = "0.1.7"
 | 
			
		||||
version_tuple = tuplize_version(__version__)
 | 
			
		||||
 | 
			
		||||
import builtins
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,4 +29,49 @@ class ALttPItem(Item):
 | 
			
		|||
        self.zora_credit_text = zora_credit
 | 
			
		||||
        self.magicshop_credit_text = witch_credit
 | 
			
		||||
        self.fluteboy_credit_text = flute_boy_credit
 | 
			
		||||
        self._hint_text = hint_text
 | 
			
		||||
        self._hint_text = hint_text
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def crystal(self) -> bool:
 | 
			
		||||
        return self.type == 'Crystal'
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def smallkey(self) -> bool:
 | 
			
		||||
        return self.type == 'SmallKey'
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def bigkey(self) -> bool:
 | 
			
		||||
        return self.type == 'BigKey'
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def map(self) -> bool:
 | 
			
		||||
        return self.type == 'Map'
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def compass(self) -> bool:
 | 
			
		||||
        return self.type == 'Compass'
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def dungeon_item(self) -> Optional[str]:
 | 
			
		||||
        if self.game == "A Link to the Past" and self.type in {"SmallKey", "BigKey", "Map", "Compass"}:
 | 
			
		||||
            return self.type
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def shuffled_dungeon_item(self) -> bool:
 | 
			
		||||
        dungeon_item_type = self.dungeon_item
 | 
			
		||||
        if dungeon_item_type:
 | 
			
		||||
            return {"SmallKey" : self.world.keyshuffle,
 | 
			
		||||
                    "BigKey": self.world.bigkeyshuffle,
 | 
			
		||||
                    "Map": self.world.mapshuffle,
 | 
			
		||||
                    "Compass": self.world.compassshuffle}[dungeon_item_type][self.player]
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def locked_dungeon_item(self) -> bool:
 | 
			
		||||
        dungeon_item_type = self.dungeon_item
 | 
			
		||||
        if dungeon_item_type:
 | 
			
		||||
            return not {"SmallKey" : self.world.keyshuffle,
 | 
			
		||||
                        "BigKey": self.world.bigkeyshuffle,
 | 
			
		||||
                        "Map": self.world.mapshuffle,
 | 
			
		||||
                        "Compass": self.world.compassshuffle}[dungeon_item_type][self.player]
 | 
			
		||||
        return False
 | 
			
		||||
| 
						 | 
				
			
			@ -62,6 +62,7 @@ class ALTTPWorld(World):
 | 
			
		|||
        world.difficulty_requirements[player] = difficulties[world.difficulty[player]]
 | 
			
		||||
 | 
			
		||||
    def create_regions(self):
 | 
			
		||||
        # noinspection PyAttributeOutsideInit
 | 
			
		||||
        self.rom_name_available_event = threading.Event()
 | 
			
		||||
 | 
			
		||||
        player = self.player
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue