diff --git a/BaseClasses.py b/BaseClasses.py index 5921632e..2f6d9d23 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -2755,7 +2755,7 @@ mixed_travel_mode = {"prevent": 0, "allow": 1, "force": 2} # new byte 4: ?DDD PPPP (unused, drop, pottery) # dropshuffle reserves 2 bits, pottery needs 2 but reserves 2 for future modes) -pottery_mode = {"none": 0, "shuffle": 1, "keys": 2, "lottery": 3} +pottery_mode = {"none": 0, "shuffle": 1, "keys": 2, "lottery": 3, 'dungeon': 4, 'cave': 5} # byte 5: CCCC CTTX (crystals gt, ctr2, experimental) counter_mode = {"default": 0, "off": 1, "on": 2, "pickup": 3} diff --git a/DoorShuffle.py b/DoorShuffle.py index 6fbeb805..49af732c 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -1002,7 +1002,7 @@ def cross_dungeon(world, player): target_items += 29 # small keys in chests if world.dropshuffle[player]: target_items += 14 # 13 dropped smalls + 1 big - if world.pottery[player] != 'none': + if world.pottery[player] not in ['none', 'cave']: target_items += 19 # 19 pot keys d_items = target_items - all_dungeon_items_cnt world.pool_adjustment[player] = d_items @@ -1064,7 +1064,7 @@ def assign_cross_keys(dungeon_builders, world, player): remaining = 29 if world.dropshuffle[player]: remaining += 13 - if world.pottery[player] in ['keys', 'lottery']: + if world.pottery[player] not in ['none', 'cave']: remaining += 19 else: remaining = len(list(x for dgn in world.dungeons if dgn.player == player for x in dgn.small_keys)) diff --git a/ItemList.py b/ItemList.py index 05844ff7..d995e516 100644 --- a/ItemList.py +++ b/ItemList.py @@ -5,7 +5,7 @@ import RaceRandom as random from BaseClasses import Region, RegionType, Shop, ShopType, Location, CollectionState, PotItem from EntranceShuffle import connect_entrance -from Regions import shop_to_location_table, retro_shops, shop_table_by_location +from Regions import shop_to_location_table, retro_shops, shop_table_by_location, valid_pot_location from Fill import FillError, fill_restrictive, fast_fill, get_dungeon_item_pool from PotShuffle import vanilla_pots from Items import ItemFactory @@ -391,13 +391,13 @@ def generate_itempool(world, player): set_up_take_anys(world, player) if world.dropshuffle[player]: world.itempool += [ItemFactory('Small Key (Universal)', player)] * 13 - if world.pottery[player] != 'none': + if world.pottery[player] not in ['none', 'cave']: world.itempool += [ItemFactory('Small Key (Universal)', player)] * 19 create_dynamic_shop_locations(world, player) - if world.pottery[player] == 'lottery': + if world.pottery[player] not in ['none', 'keys']: add_pot_contents(world, player) @@ -759,7 +759,8 @@ def add_pot_contents(world, player): for super_tile, pot_list in vanilla_pots.items(): for pot in pot_list: if pot.item not in [PotItem.Hole, PotItem.Key, PotItem.Switch]: - world.itempool.append(ItemFactory(pot_items[pot.item], player)) + if valid_pot_location(pot, world, player): + world.itempool.append(ItemFactory(pot_items[pot.item], player)) def get_pool_core(progressive, shuffle, difficulty, treasure_hunt_total, timer, goal, mode, swords, retro, bombbag, door_shuffle, logic): diff --git a/Main.py b/Main.py index c48c8a37..467a73c3 100644 --- a/Main.py +++ b/Main.py @@ -158,7 +158,7 @@ def main(args, seed=None, fish=None): logger.info(world.fish.translate("cli", "cli", "shuffling.pots")) for player in range(1, world.players + 1): if world.potshuffle[player]: - if world.pottery[player] != 'lottery': + if world.pottery[player] not in ['lottery', 'dungeon']: shuffle_pots(world, player) else: shuffle_pot_switches(world, player) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 914b2aff..0cf2a521 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -4,10 +4,12 @@ ### Pottery -New pottery option that control which pots are in the locations pool: +New pottery option that control which pots (and large blocks) are in the locations pool: * None: No pots are in the pool, like normal randomizer * Key Pots: The pots that have keys are in the pool. This is about half of the old keydropshuffle option +* Cave Pots: The pots that are not found in dungeon are in the pool. (Includes the large block in Spike Cave) +* Dungeon Pots: The pots that are in dungeons are in the pool. (Includes serveral large blocks) * Lottery: All pots and large blocks are in the pool By default, switches remain in their vanilla location (unless you turn on the legacy option below) @@ -145,8 +147,12 @@ Same as above but both small keys and bigs keys of the dungeon are not allowed o #### Volatile * 1.0.1.5 + * A couple new options for lighter pottery modes + * New option for Boss Shuffle: Unique (Prize bosses will be one of each, but GT bosses can be anything) * Fix for Hera Basement Cage item inheriting last pot checked * Update indicators on keysanity menu for overworld map option + * Fix for Standard ER where locations in rain state could be in logic + * Fix for Ice Refill room pots, require being able to hit a switch for bombbag mode * 1.0.1.4 * Reverted SRAM change (the underlying refactor isn't done yet) * 1.0.1.3 diff --git a/Regions.py b/Regions.py index fa1107e8..bb83a090 100644 --- a/Regions.py +++ b/Regions.py @@ -1007,7 +1007,7 @@ def adjust_locations(world, player): loc.address = pot_address(pot_index, datum[1]) loc.pot = pot if (not world.dropshuffle[player] and drop_location)\ - or (not drop_location and world.pottery[player] == 'none'): + or (not drop_location and world.pottery[player] in ['none', 'cave']): loc.skip = True else: key_item = loc.item @@ -1030,7 +1030,8 @@ def adjust_locations(world, player): else: pot = pot_orig.copy() world.pot_contents[player].room_map[super_tile].append(pot) - if world.pottery[player] == 'lottery': + + if valid_pot_location(pot, world, player): create_pot_location(pot, pot_index, super_tile, world, player) if world.shopsanity[player]: index = 0 @@ -1053,9 +1054,20 @@ def adjust_locations(world, player): location.skip = True +def valid_pot_location(pot, world, player): + if world.pottery[player] == 'lottery': + return True + if world.pottery[player] == 'dungeon' and world.get_region(pot.room, player).type == RegionType.Dungeon: + return True + if world.pottery[player] == 'cave' and world.get_region(pot.room, player).type == RegionType.Cave: + return True + return False + + def create_pot_location(pot, pot_index, super_tile, world, player): if (pot.item not in [PotItem.Key, PotItem.Hole] - and (pot.item != PotItem.Switch or world.potshuffle[player])): + and (pot.item != PotItem.Switch or (world.potshuffle[player] + and world.pottery[player] in ['lottery', 'dungeon']))): address = pot_address(pot_index, super_tile) region = pot.room if world.mode[player] == 'inverted': diff --git a/Rom.py b/Rom.py index 0a032719..53cf30f7 100644 --- a/Rom.py +++ b/Rom.py @@ -746,7 +746,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): valid_loc_by_dungeon = valid_dungeon_locations(valid_locations) # fix hc big key problems (map and compass too) - if world.doorShuffle[player] == 'crossed' or world.dropshuffle[player] or world.pottery[player] != 'none': + if world.doorShuffle[player] == 'crossed' or world.dropshuffle[player] or world.pottery[player] not in ['none', 'cave']: rom.write_byte(0x151f1, 2) rom.write_byte(0x15270, 2) sanctuary = world.get_region('Sanctuary', player) @@ -879,10 +879,11 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): multiClientFlags = ((0x1 if world.dropshuffle[player] else 0) | (0x2 if world.shopsanity[player] else 0) | (0x4 if world.retro[player] else 0) - | (0x8 if world.pottery[player] in ['keys', 'lottery'] else 0) + | (0x8 if world.pottery[player] != 'none' else 0) | (0x10 if is_mystery else 0)) rom.write_byte(0x142A51, multiClientFlags) - rom.write_byte(0x142A55, ((0x1 if world.pottery[player] != 'none' else 0) # StandingItemCounterMask + # StandingItemCounterMask + rom.write_byte(0x142A55, ((0x1 if world.pottery[player] not in ['none', 'cave'] else 0) | (0x2 if world.dropshuffle[player] else 0))) if world.pottery[player] not in ['none', 'keys']: # Cuccos should not prevent kill rooms from opening @@ -1466,7 +1467,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): elif world.dungeon_counters[player] == 'on': compass_mode = 0x02 # always on elif (world.compassshuffle[player] or world.doorShuffle[player] != 'vanilla' or world.dropshuffle[player] - or world.dungeon_counters[player] == 'pickup' or world.pottery[player] != 'none'): + or world.dungeon_counters[player] == 'pickup' or world.pottery[player] not in ['none', 'cave']): compass_mode = 0x01 # show on pickup if world.shuffle[player] != 'vanilla' and world.overworld_map[player] != 'default': compass_mode |= 0x80 # turn on locating dungeons diff --git a/Rules.py b/Rules.py index bd2d32ad..afd1a8c3 100644 --- a/Rules.py +++ b/Rules.py @@ -716,7 +716,7 @@ def bomb_rules(world, player): def pot_rules(world, player): - if world.pottery[player] == 'lottery': + if world.pottery[player] in ['lottery', 'cave']: blocks = [l for l in world.get_locations() if l.type == LocationType.Pot and l.pot.flags & PotFlags.Block] for block_pot in blocks: add_rule(block_pot, lambda state: state.can_lift_rocks(player)) @@ -740,7 +740,7 @@ def pot_rules(world, player): if l.type == LocationType.Pot: add_rule(l, lambda state: state.world.can_take_damage or state.has('Hookshot', player)) - # dungeons + if world.pottery[player] in ['lottery', 'dungeon']: for l in world.get_region('Ice Hammer Block', player).locations: if l.type == LocationType.Pot: add_rule(l, lambda state: state.has('Hammer', player) and state.can_lift_rocks(player)) diff --git a/resources/app/cli/args.json b/resources/app/cli/args.json index d948230e..8d9dd329 100644 --- a/resources/app/cli/args.json +++ b/resources/app/cli/args.json @@ -76,6 +76,8 @@ "choices" : [ "none", "keys", + "dungeon", + "cave", "lottery" ] }, diff --git a/resources/app/cli/lang/en.json b/resources/app/cli/lang/en.json index ca8eddd3..aa974003 100644 --- a/resources/app/cli/lang/en.json +++ b/resources/app/cli/lang/en.json @@ -256,6 +256,8 @@ "pottery": [ "Controls how items under pots are shuffled and if other items can take their place:", "None: No pots are changed", "Keys: Key pots are included in the location pool and other items can take their place", + "Cave: Only pots in houses and caves are included in the location pool", + "Dungeon: Only pots in dungeons are included in the location pool", "Lottery: All pots are part of the location pool" ], "shufflepots": [ "Pots and switches are shuffled on the supertile (legacy potshuffle) (default: %(default)s)"], diff --git a/resources/app/gui/lang/en.json b/resources/app/gui/lang/en.json index 37a3e549..371e76a3 100644 --- a/resources/app/gui/lang/en.json +++ b/resources/app/gui/lang/en.json @@ -59,6 +59,8 @@ "randomizer.dungeon.pottery": "Pottery", "randomizer.dungeon.pottery.none": "None", "randomizer.dungeon.pottery.keys": "Key Pots", + "randomizer.dungeon.pottery.cave": "Cave Pots", + "randomizer.dungeon.pottery.dungeon": "Dungeon Pots", "randomizer.dungeon.pottery.lottery": "Lottery (All Pots and Large Blocks)", "randomizer.dungeon.dungeondoorshuffle": "Dungeon Door Shuffle", diff --git a/resources/app/gui/randomize/dungeon/widgets.json b/resources/app/gui/randomize/dungeon/widgets.json index 0a32b530..7a4d0d13 100644 --- a/resources/app/gui/randomize/dungeon/widgets.json +++ b/resources/app/gui/randomize/dungeon/widgets.json @@ -29,6 +29,8 @@ "options": [ "none", "keys", + "cave", + "dungeon", "lottery" ], "config": { diff --git a/source/item/FillUtil.py b/source/item/FillUtil.py index 33f0a688..8b6a75a4 100644 --- a/source/item/FillUtil.py +++ b/source/item/FillUtil.py @@ -73,7 +73,7 @@ def create_item_pool_config(world): if world.pottery[player] != 'none': for item, locs in potkeys_vanilla_mapping.items(): config.static_placement[player][item].extend(locs) - if world.pottery[player] == 'lottery': + if world.pottery[player] in ['lottery', 'cave', 'dungeon']: for super_tile, pot_list in vanilla_pots.items(): for pot_index, pot in enumerate(pot_list): if pot.item not in [PotItem.Key, PotItem.Hole, PotItem.Switch]: @@ -96,7 +96,7 @@ def create_item_pool_config(world): for item, locs in keydrop_vanilla_mapping.items(): if 'Small Key' in item: universal_key_locations.extend(locs) - if world.pottery[player] != 'none': + if world.pottery[player] not in ['none', 'cave']: for item, locs in potkeys_vanilla_mapping.items(): universal_key_locations.extend(locs) if world.shopsanity[player]: