LttP: Rename Shop Slot 1, 2, 3 to Shop Slot Left, Center, Right
General: Move generic IDs from LttP to new Generic World Generate: ensure thread errors are collected before data from their completion may be referenced in playthrough/spoiler
This commit is contained in:
		
							parent
							
								
									e8da9924c6
								
							
						
					
					
						commit
						21255b3b46
					
				|  | @ -911,7 +911,8 @@ class Boss(): | |||
|         return f"Boss({self.name})" | ||||
| 
 | ||||
| class Location(): | ||||
|     shop_slot: bool = False | ||||
|     # If given as integer, then this is the shop's inventory index | ||||
|     shop_slot: Optional[int] = None | ||||
|     shop_slot_disabled: bool = False | ||||
|     event: bool = False | ||||
|     locked: bool = False | ||||
|  |  | |||
							
								
								
									
										18
									
								
								Main.py
								
								
								
								
							
							
						
						
									
										18
									
								
								Main.py
								
								
								
								
							|  | @ -147,7 +147,9 @@ def main(args, seed=None): | |||
|     longest_name = max(len(text) for text in AutoWorld.AutoWorldRegister.world_types) | ||||
|     numlength = 8 | ||||
|     for name, cls in AutoWorld.AutoWorldRegister.world_types.items(): | ||||
|         logger.info(f"  {name:{longest_name}}: {len(cls.item_names):3} Items | {len(cls.location_names):3} Locations") | ||||
|         if not getattr(cls, "hidden", False): | ||||
|             logger.info(f"  {name:{longest_name}}: {len(cls.item_names):3} Items | " | ||||
|                         f"{len(cls.location_names):3} Locations") | ||||
|             logger.info(f"  Item IDs: {min(cls.item_id_to_name):{numlength}} - " | ||||
|                         f"{max(cls.item_id_to_name):{numlength}} | " | ||||
|                         f"Location IDs: {min(cls.location_id_to_name):{numlength}} - " | ||||
|  | @ -383,22 +385,28 @@ def main(args, seed=None): | |||
|                 raise Exception("Game appears as unbeatable. Aborting.") | ||||
|             else: | ||||
|                 logger.warning("Location Accessibility requirements not fulfilled.") | ||||
| 
 | ||||
|         # retrieve exceptions via .result() if they occured. | ||||
|         if multidata_task: | ||||
|             multidata_task.result()  # retrieve exception if one exists | ||||
|             multidata_task.result() | ||||
|         for future in output_file_futures: | ||||
|             future.result() | ||||
| 
 | ||||
|         pool.shutdown()  # wait for all queued tasks to complete | ||||
| 
 | ||||
|         if not args.skip_playthrough: | ||||
|             logger.info('Calculating playthrough.') | ||||
|             create_playthrough(world) | ||||
| 
 | ||||
|         if args.create_spoiler: | ||||
|             world.spoiler.to_file(os.path.join(temp_dir, '%s_Spoiler.txt' % outfilebase)) | ||||
|         for future in output_file_futures: | ||||
|             future.result() | ||||
| 
 | ||||
|         zipfilename = output_path(f"AP_{world.seed_name}.zip") | ||||
|         logger.info(f'Creating final archive at {zipfilename}.') | ||||
|         with zipfile.ZipFile(zipfilename, mode="w", compression=zipfile.ZIP_DEFLATED, | ||||
|                              compresslevel=9) as zf: | ||||
|             for file in os.scandir(temp_dir): | ||||
|                 zf.write(os.path.join(temp_dir, file), arcname=file.name) | ||||
|                 zf.write(file.path, arcname=file.name) | ||||
| 
 | ||||
|     logger.info('Done. Enjoy. Total Time: %s', time.perf_counter() - start) | ||||
|     return world | ||||
|  |  | |||
|  | @ -500,14 +500,14 @@ def create_dynamic_shop_locations(world, player): | |||
|                 if item is None: | ||||
|                     continue | ||||
|                 if item['create_location']: | ||||
|                     loc = ALttPLocation(player, "{} Slot {}".format(shop.region.name, i + 1), parent=shop.region) | ||||
|                     loc = ALttPLocation(player, f"{shop.region.name} {shop.slot_names[i]}", parent=shop.region) | ||||
|                     shop.region.locations.append(loc) | ||||
|                     world.dynamic_locations.append(loc) | ||||
| 
 | ||||
|                     world.clear_location_cache() | ||||
| 
 | ||||
|                     world.push_item(loc, ItemFactory(item['item'], player), False) | ||||
|                     loc.shop_slot = True | ||||
|                     loc.shop_slot = i | ||||
|                     loc.event = True | ||||
|                     loc.locked = True | ||||
| 
 | ||||
|  |  | |||
|  | @ -676,12 +676,10 @@ location_table: typing.Dict[str, | |||
| 
 | ||||
| from worlds.alttp.Shops import shop_table_by_location_id, shop_table_by_location | ||||
| lookup_id_to_name = {data[0]: name for name, data in location_table.items() if type(data[0]) == int} | ||||
| lookup_id_to_name = {**lookup_id_to_name, **{data[1]: name for name, data in key_drop_data.items()}, | ||||
|                      -1: "Cheat Console", -2: "Server"} | ||||
| lookup_id_to_name = {**lookup_id_to_name, **{data[1]: name for name, data in key_drop_data.items()}} | ||||
| lookup_id_to_name.update(shop_table_by_location_id) | ||||
| lookup_name_to_id = {name: data[0] for name, data in location_table.items() if type(data[0]) == int} | ||||
| lookup_name_to_id = {**lookup_name_to_id, **{name: data[1] for name, data in key_drop_data.items()}, | ||||
|                      "Cheat Console": -1, "Server": -2} | ||||
| lookup_name_to_id = {**lookup_name_to_id, **{name: data[1] for name, data in key_drop_data.items()}} | ||||
| lookup_name_to_id.update(shop_table_by_location) | ||||
| 
 | ||||
| lookup_vanilla_location_to_entrance = {1572883: 'Kings Grave Inner Rocks', 191256: 'Kings Grave Inner Rocks', | ||||
|  |  | |||
|  | @ -763,7 +763,7 @@ def patch_rom(world, rom, player, enemized): | |||
|     # patch items | ||||
| 
 | ||||
|     for location in world.get_locations(): | ||||
|         if location.player != player or location.address is None or location.shop_slot: | ||||
|         if location.player != player or location.address is None or location.shop_slot is not None: | ||||
|             continue | ||||
| 
 | ||||
|         itemid = location.item.code if location.item is not None else 0x5A | ||||
|  |  | |||
|  | @ -22,6 +22,11 @@ class Shop(): | |||
|     slots: int = 3  # slot count is not dynamic in asm, however inventory can have None as empty slots | ||||
|     blacklist: Set[str] = set()  # items that don't work, todo: actually check against this | ||||
|     type = ShopType.Shop | ||||
|     slot_names: Dict[int, str] = { | ||||
|         0: "Left", | ||||
|         1: "Center", | ||||
|         2: "Right" | ||||
|     } | ||||
| 
 | ||||
|     def __init__(self, region, room_id: int, shopkeeper_config: int, custom: bool, locked: bool, sram_offset: int): | ||||
|         self.region = region | ||||
|  | @ -131,23 +136,22 @@ shop_class_mapping = {ShopType.UpgradeShop: UpgradeShop, | |||
| 
 | ||||
| def FillDisabledShopSlots(world): | ||||
|     shop_slots: Set[ALttPLocation] = {location for shop_locations in (shop.region.locations for shop in world.shops) | ||||
|                                       for location in shop_locations if location.shop_slot and location.shop_slot_disabled} | ||||
|                                       for location in shop_locations | ||||
|                                       if location.shop_slot is not None and location.shop_slot_disabled} | ||||
|     for location in shop_slots: | ||||
|         location.shop_slot_disabled = True | ||||
|         slot_num = int(location.name[-1]) - 1 | ||||
|         shop: Shop = location.parent_region.shop | ||||
|         location.item = ItemFactory(shop.inventory[slot_num]['item'], location.player) | ||||
|         location.item = ItemFactory(shop.inventory[location.shop_slot]['item'], location.player) | ||||
|         location.item_rule = lambda item: item.name == location.item.name and item.player == location.player | ||||
| 
 | ||||
| 
 | ||||
| def ShopSlotFill(world): | ||||
|     shop_slots: Set[ALttPLocation] = {location for shop_locations in (shop.region.locations for shop in world.shops) | ||||
|                                       for location in shop_locations if location.shop_slot} | ||||
|                                       for location in shop_locations if location.shop_slot is not None} | ||||
|     removed = set() | ||||
|     for location in shop_slots: | ||||
|         slot_num = int(location.name[-1]) - 1 | ||||
|         shop: Shop = location.parent_region.shop | ||||
|         if not shop.can_push_inventory(slot_num) or location.shop_slot_disabled: | ||||
|         if not shop.can_push_inventory(location.shop_slot) or location.shop_slot_disabled: | ||||
|             location.shop_slot_disabled = True | ||||
|             removed.add(location) | ||||
| 
 | ||||
|  | @ -179,7 +183,7 @@ def ShopSlotFill(world): | |||
|             shops_per_sphere.append(current_shops_slots) | ||||
|             candidates_per_sphere.append(current_candidates) | ||||
|             for location in sphere: | ||||
|                 if location.shop_slot: | ||||
|                 if location.shop_slot is not None: | ||||
|                     if not location.shop_slot_disabled: | ||||
|                         current_shops_slots.append(location) | ||||
|                 elif not location.locked and not location.item.name in blacklist_words: | ||||
|  | @ -229,7 +233,7 @@ def ShopSlotFill(world): | |||
|                     else: | ||||
|                         price = world.random.randrange(8, 56) | ||||
| 
 | ||||
|                     shop.push_inventory(int(location.name[-1]) - 1, item_name, price * 5, 1, | ||||
|                     shop.push_inventory(location.shop_slot, item_name, price * 5, 1, | ||||
|                                         location.item.player if location.item.player != location.player else 0) | ||||
| 
 | ||||
| 
 | ||||
|  | @ -278,10 +282,10 @@ def create_shops(world, player: int): | |||
|         for index, item in enumerate(inventory): | ||||
|             shop.add_inventory(index, *item) | ||||
|             if not locked and num_slots: | ||||
|                 slot_name = "{} Slot {}".format(region.name, index + 1) | ||||
|                 slot_name = f"{region.name} {shop.slot_names[index]}" | ||||
|                 loc = ALttPLocation(player, slot_name, address=shop_table_by_location[slot_name], | ||||
|                                     parent=region, hint_text="for sale") | ||||
|                 loc.shop_slot = True | ||||
|                 loc.shop_slot = index | ||||
|                 loc.locked = True | ||||
|                 if single_purchase_slots.pop(): | ||||
|                     if world.goal[player] != 'icerodhunt': | ||||
|  | @ -337,9 +341,10 @@ total_shop_slots = len(shop_table) * 3 | |||
| total_dynamic_shop_slots = sum(3 for shopname, data in shop_table.items() if not data[4])  # data[4] -> locked | ||||
| 
 | ||||
| SHOP_ID_START = 0x400000 | ||||
| shop_table_by_location_id = {cnt: s for cnt, s in enumerate( | ||||
|     (f"{name} Slot {num}" for name in [key for key, value in sorted(shop_table.items(), key=lambda item: item[1].sram_offset)] | ||||
|      for num in range(1, 4)), start=SHOP_ID_START)} | ||||
| shop_table_by_location_id = dict(enumerate( | ||||
|     (f"{name} {Shop.slot_names[num]}" for name, shop_data in sorted(shop_table.items(), key=lambda item: item[1].sram_offset) | ||||
|      for num in range(3)), start=SHOP_ID_START)) | ||||
| 
 | ||||
| shop_table_by_location_id[(SHOP_ID_START + total_shop_slots)] = "Old Man Sword Cave" | ||||
| shop_table_by_location_id[(SHOP_ID_START + total_shop_slots + 1)] = "Take-Any #1" | ||||
| shop_table_by_location_id[(SHOP_ID_START + total_shop_slots + 2)] = "Take-Any #2" | ||||
|  |  | |||
|  | @ -26,14 +26,12 @@ class ALTTPWorld(World): | |||
|     options = alttp_options | ||||
|     topology_present = True | ||||
|     item_name_groups = item_name_groups | ||||
|     item_names = frozenset(item_table) | ||||
|     location_names = frozenset(lookup_name_to_id) | ||||
|     hint_blacklist = {"Triforce"} | ||||
| 
 | ||||
|     item_name_to_id = {name: data.item_code for name, data in item_table.items() if type(data.item_code) == int} | ||||
|     location_name_to_id = lookup_name_to_id | ||||
| 
 | ||||
|     data_version = 7 | ||||
|     data_version = 8 | ||||
|     remote_items: bool = False | ||||
| 
 | ||||
|     set_rules = set_rules | ||||
|  |  | |||
|  | @ -1,6 +1,20 @@ | |||
| from typing import NamedTuple, Union | ||||
| import logging | ||||
| 
 | ||||
| from ..AutoWorld import World | ||||
| 
 | ||||
| 
 | ||||
| class GenericWorld(World): | ||||
|     game = "Archipelago" | ||||
|     topology_present = False | ||||
|     item_name_to_id = { | ||||
|         "Nothing": -1 | ||||
|     } | ||||
|     location_name_to_id = { | ||||
|         "Cheat Console" : -1, | ||||
|         "Server": -2 | ||||
|     } | ||||
|     hidden = True | ||||
| 
 | ||||
| class PlandoItem(NamedTuple): | ||||
|     item: str | ||||
|  |  | |||
|  | @ -19,6 +19,8 @@ class HKWorld(World): | |||
|     item_name_to_id = {name: data.id for name, data in item_table.items() if data.type != "Event"} | ||||
|     location_name_to_id = lookup_name_to_id | ||||
| 
 | ||||
|     hidden = True | ||||
| 
 | ||||
|     def generate_basic(self): | ||||
|         # Link regions | ||||
|         self.world.get_entrance('Hollow Nest S&Q', self.player).connect(self.world.get_region('Hollow Nest', self.player)) | ||||
|  |  | |||
|  | @ -19,6 +19,8 @@ class OriBlindForest(World): | |||
| 
 | ||||
|     options = options | ||||
| 
 | ||||
|     hidden = True | ||||
| 
 | ||||
|     def generate_early(self): | ||||
|         logic_sets = {"casual-core"} | ||||
|         for logic_set in location_rules: | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue