diff --git a/BaseClasses.py b/BaseClasses.py index 099d4d53..263bd223 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -347,7 +347,7 @@ class World(object): else: if self.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull']: return False - elif self.goal[player] in ['crystals', 'trinity']: + elif self.goal[player] in ['crystals', 'trinity', 'ganonhunt']: return True else: return False diff --git a/CLI.py b/CLI.py index d9ff24f3..b554d20f 100644 --- a/CLI.py +++ b/CLI.py @@ -134,7 +134,7 @@ def parse_cli(argv, no_defaults=False): 'shuffle', 'door_shuffle', 'intensity', 'crystals_ganon', 'crystals_gt', 'openpyramid', 'mapshuffle', 'compassshuffle', 'keyshuffle', 'bigkeyshuffle', 'startinventory', 'usestartinventory', 'bombbag', 'shuffleganon', 'overworld_map', 'restrict_boss_items', - 'triforce_pool_min', 'triforce_pool_max', 'triforce_goal_min', 'triforce_goal_max', + 'triforce_pool_min', 'triforce_pool_max', 'triforce_goal_min', 'triforce_goal_max', 'triforce_max_difference', 'triforce_min_difference', 'triforce_goal', 'triforce_pool', 'shufflelinks', 'shuffletavern', 'pseudoboots', 'retro', 'accessibility', 'hints', 'beemizer', 'experimental', 'dungeon_counters', 'shufflebosses', 'shuffleenemies', 'enemy_health', 'enemy_damage', 'shufflepots', @@ -239,6 +239,7 @@ def parse_settings(): "triforce_goal_min": 0, "triforce_goal_max": 0, "triforce_min_difference": 0, + "triforce_max_difference": 10000, "code": "", "multi": 1, diff --git a/DoorShuffle.py b/DoorShuffle.py index bbc798c9..9d59a34f 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -2548,13 +2548,12 @@ def reassign_big_key_doors(bk_map, used_doors, world, player): queue = deque(find_current_bk_doors(builder)) while len(queue) > 0: d = queue.pop() - if (d.type is DoorType.Interior and d not in flat_proposal and d.dest not in flat_proposal - and d not in used_doors and d.dest not in used_doors): - if not d.entranceFlag: + if d.type is DoorType.Interior and d not in flat_proposal and d.dest not in flat_proposal: + if not d.entranceFlag and d not in used_doors and d.dest not in used_doors: world.get_room(d.roomIndex, player).change(d.doorListPos, DoorKind.Normal) d.bigKey = False - elif d.type is DoorType.Normal and d not in flat_proposal and d not in used_doors: - if not d.entranceFlag: + elif d.type is DoorType.Normal and d not in flat_proposal : + if not d.entranceFlag and d not in used_doors: world.get_room(d.roomIndex, player).change(d.doorListPos, DoorKind.Normal) d.bigKey = False for obj in big_doors: @@ -3015,7 +3014,7 @@ def reassign_key_doors(small_map, used_doors, world, player): queue = deque(find_current_key_doors(builder)) while len(queue) > 0: d = queue.pop() - if d.type is DoorType.SpiralStairs and d not in proposal and d not in used_doors: + if d.type is DoorType.SpiralStairs and d not in proposal: room = world.get_room(d.roomIndex, player) if room.doorList[d.doorListPos][1] == DoorKind.StairKeyLow: room.delete(d.doorListPos) @@ -3025,15 +3024,14 @@ def reassign_key_doors(small_map, used_doors, world, player): else: room.delete(d.doorListPos) d.smallKey = False - elif (d.type is DoorType.Interior and d not in flat_proposal and d.dest not in flat_proposal - and d not in used_doors and d.dest not in used_doors): - if not d.entranceFlag: + elif d.type is DoorType.Interior and d not in flat_proposal and d.dest not in flat_proposal: + if not d.entranceFlag and d not in used_doors and d.dest not in used_doors: world.get_room(d.roomIndex, player).change(d.doorListPos, DoorKind.Normal) d.smallKey = False d.dest.smallKey = False queue.remove(d.dest) - elif d.type is DoorType.Normal and d not in flat_proposal and d not in used_doors: - if not d.entranceFlag: + elif d.type is DoorType.Normal and d not in flat_proposal: + if not d.entranceFlag and d not in used_doors: world.get_room(d.roomIndex, player).change(d.doorListPos, DoorKind.Normal) d.smallKey = False for dp in world.paired_doors[player]: diff --git a/ItemList.py b/ItemList.py index a30369eb..c6462f62 100644 --- a/ItemList.py +++ b/ItemList.py @@ -1362,19 +1362,6 @@ def make_custom_item_pool(world, player, progressive, shuffle, difficulty, timer return (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_total, treasure_hunt_icon, lamps_needed_for_dark_rooms) -def set_default_triforce(goal, custom_goal, custom_total): - triforce_goal, triforce_total = 0, 0 - if goal == 'triforcehunt': - triforce_goal, triforce_total = 20, 30 - elif goal == 'trinity': - triforce_goal, triforce_total = 8, 10 - if custom_goal > 0: - triforce_goal = max(min(custom_goal, 128), 1) - if custom_total > 0 or custom_goal > 0: - triforce_total = max(min(custom_total, 128), triforce_goal) #128 max to ensure other progression can fit. - return (triforce_goal, triforce_total) - - def make_customizer_pool(world, player): pool = [] placed_items = {} diff --git a/Main.py b/Main.py index bf2bf008..3d8d46e3 100644 --- a/Main.py +++ b/Main.py @@ -36,7 +36,7 @@ from source.overworld.EntranceShuffle2 import link_entrances_new from source.tools.BPS import create_bps_from_data from source.classes.CustomSettings import CustomSettings -version_number = '1.2.0.18' +version_number = '1.2.0.19' version_branch = '-u' __version__ = f'{version_number}{version_branch}' @@ -131,8 +131,6 @@ def main(args, seed=None, fish=None): world.potshuffle = args.shufflepots.copy() world.mixed_travel = args.mixed_travel.copy() world.standardize_palettes = args.standardize_palettes.copy() - world.treasure_hunt_count = {k: int(v) for k, v in args.triforce_goal.items()} - world.treasure_hunt_total = {k: int(v) for k, v in args.triforce_pool.items()} world.shufflelinks = args.shufflelinks.copy() world.shuffletavern = args.shuffletavern.copy() world.pseudoboots = args.pseudoboots.copy() @@ -142,6 +140,26 @@ def main(args, seed=None, fish=None): world.collection_rate = args.collection_rate.copy() world.colorizepots = args.colorizepots.copy() + world.treasure_hunt_count = {} + world.treasure_hunt_total = {} + for p in args.triforce_goal: + if int(args.triforce_goal[p]) != 0 or int(args.triforce_pool[p]) != 0 or int(args.triforce_goal_min[p]) != 0 or int(args.triforce_goal_max[p]) != 0 or int(args.triforce_pool_min[p]) != 0 or int(args.triforce_pool_max[p]) != 0: + if int(args.triforce_goal[p]) != 0: + world.treasure_hunt_count[p] = int(args.triforce_goal[p]) + elif int(args.triforce_goal_min[p]) != 0 and int(args.triforce_goal_max[p]) != 0: + world.treasure_hunt_count[p] = random.randint(int(args.triforce_goal_min[p]), int(args.triforce_goal_max[p])) + else: + world.treasure_hunt_count[p] = 8 if world.goal[p] == 'trinity' else 20 + if int(args.triforce_pool[p]) != 0: + world.treasure_hunt_total[p] = int(args.triforce_pool[p]) + elif int(args.triforce_pool_min[p]) != 0 and int(args.triforce_pool_max[p]) != 0: + world.treasure_hunt_total[p] = random.randint(max(int(args.triforce_pool_min[p]), world.treasure_hunt_count[p] + int(args.triforce_min_difference[p])), min(int(args.triforce_pool_max[p]), world.treasure_hunt_count[p] + int(args.triforce_max_difference[p]))) + else: + world.treasure_hunt_total[p] = 10 if world.goal[p] == 'trinity' else 30 + else: + # this will be handled in ItemList.py and custom item pool is used to determine the numbers + world.treasure_hunt_count[p], world.treasure_hunt_total[p] = 0, 0 + world.rom_seeds = {player: random.randint(0, 999999999) for player in range(1, world.players + 1)} world.finish_init() diff --git a/MultiClient.py b/MultiClient.py index 5b8ebd30..78fd0f5f 100644 --- a/MultiClient.py +++ b/MultiClient.py @@ -66,6 +66,8 @@ class Context: self.lookup_name_to_id = {} self.lookup_id_to_name = {} + self.pottery_locations_enabled = None + def color_code(*args): codes = {'reset': 0, 'bold': 1, 'underline': 4, 'black': 30, 'red': 31, 'green': 32, 'yellow': 33, 'blue': 34, 'magenta': 35, 'cyan': 36, 'white': 37 , 'black_bg': 40, 'red_bg': 41, 'green_bg': 42, 'yellow_bg': 43, @@ -96,6 +98,8 @@ SHOP_SRAM_START = WRAM_START + 0x0164B8 # 2 bytes? ITEM_SRAM_SIZE = 0x250 SHOP_SRAM_LEN = 0x29 # 41 tracked items +POT_LOCATION_TABLE = 0x142A60 + RECV_PROGRESS_ADDR = SAVEDATA_START + 0x4D0 # 2 bytes RECV_ITEM_ADDR = SAVEDATA_START + 0x4D2 # 1 byte RECV_ITEM_PLAYER_ADDR = SAVEDATA_START + 0x4D3 # 1 byte @@ -827,12 +831,14 @@ def get_location_name_from_address(ctx, address): def filter_location(ctx, location): + if location in location_table_pot_items: + tile_idx, mask = location_table_pot_items[location] + tracking_data = ctx.pottery_locations_enabled + tile_pots = tracking_data[tile_idx] | (tracking_data[tile_idx+1] << 8) + return (mask & tile_pots) == 0 if (not ctx.key_drop_mode and location in PotShuffle.key_drop_data and PotShuffle.key_drop_data[location][0] == 'Drop'): return True - if (not ctx.pottery_mode and location in PotShuffle.key_drop_data - and PotShuffle.key_drop_data[location][0] == 'Pot'): - return True if not ctx.shop_mode and location in Regions.flat_normal_shops: return True if not ctx.retro_mode and location in Regions.flat_retro_shops: @@ -1006,6 +1012,9 @@ async def game_watcher(ctx : Context): logging.warning("ROM change detected, please reconnect to the multiworld server") await disconnect(ctx) + if ctx.pottery_locations_enabled is None: + ctx.pottery_locations_enabled = await snes_read(ctx, POT_LOCATION_TABLE, 0x250) + gamemode = await snes_read(ctx, WRAM_START + 0x10, 1) if gamemode is None or gamemode[0] not in INGAME_MODES: continue diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 7010ecb6..3231157f 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -109,12 +109,18 @@ These are now independent of retro mode and have three options: None, Random, an # Bug Fixes and Notes +* 1.2.0.19u + * Added min/max for triforce pool, goal, and difference for CLI and Customizer. (Thanks Catobat) + * Fixed a bug with dungeon generation + * Multiworld: Fixed /missing command to not list all the pots + * Changed the "Ganonhunt" goal to use open pyramid on the Auto setting + * Customizer: Fixed the example yaml for shopsanity * 1.2.0.18u * Fixed an issue with pyramid hole being in logic when it is not opened. * Crystal cutscene at GT use new symmetrical layouts (thanks Codemann) * Fix for Hera Boss music (thanks Codemann) * Fixed an issue where certain vanilla door types would not allow other types to be placed. - * Customizer: fixed an issue where last ditch placements would move customized items. Those are now locked and the generation will fail instead is no alternative are found. + * Customizer: fixed an issue where last ditch placements would move customized items. Those are now locked and the generation will fail instead if no alternatives are found. * Customizer: fixed an issue with assured sword and start_inventory * Customizer: warns when trying to specifically place an item that's not in the item pool * Fixed "accessibility: none" displaying a spoiling message diff --git a/docs/customizer_example.yaml b/docs/customizer_example.yaml index cd70004c..82505821 100644 --- a/docs/customizer_example.yaml +++ b/docs/customizer_example.yaml @@ -1,7 +1,7 @@ meta: algorithm: balanced players: 1 - seed: 42 + seed: 41 # note to self: seed 42 had an interesting Swamp Palace problem names: Lonk settings: 1: diff --git a/mystery_example.yml b/mystery_example.yml index 50ced9ab..f515e772 100644 --- a/mystery_example.yml +++ b/mystery_example.yml @@ -134,6 +134,7 @@ triforce_pool_min: 20 triforce_pool_max: 40 triforce_min_difference: 10 + triforce_max_difference: 15 algorithm: balanced: 12 vanilla_fill: 1 diff --git a/mystery_testsuite.yml b/mystery_testsuite.yml index 7210fca6..4465619a 100644 --- a/mystery_testsuite.yml +++ b/mystery_testsuite.yml @@ -86,6 +86,7 @@ triforce_goal_max: 30 triforce_pool_min: 30 triforce_pool_max: 40 triforce_min_difference: 10 +triforce_max_difference: 12 map_shuffle: on: 1 off: 1 diff --git a/resources/app/cli/args.json b/resources/app/cli/args.json index 8dca326f..08ccec98 100644 --- a/resources/app/cli/args.json +++ b/resources/app/cli/args.json @@ -402,6 +402,7 @@ "triforce_goal_min": {}, "triforce_goal_max": {}, "triforce_min_difference": {}, + "triforce_max_difference": {}, "custom": { "type": "bool", "help": "suppress" diff --git a/source/classes/CustomSettings.py b/source/classes/CustomSettings.py index 3e90e5b3..5d02ca14 100644 --- a/source/classes/CustomSettings.py +++ b/source/classes/CustomSettings.py @@ -152,6 +152,12 @@ class CustomSettings(object): args.pseudoboots[p] = get_setting(settings['pseudoboots'], args.pseudoboots[p]) args.triforce_goal[p] = get_setting(settings['triforce_goal'], args.triforce_goal[p]) args.triforce_pool[p] = get_setting(settings['triforce_pool'], args.triforce_pool[p]) + args.triforce_goal_min[p] = get_setting(settings['triforce_goal_min'], args.triforce_goal_min[p]) + args.triforce_goal_max[p] = get_setting(settings['triforce_goal_max'], args.triforce_goal_max[p]) + args.triforce_pool_min[p] = get_setting(settings['triforce_pool_min'], args.triforce_pool_min[p]) + args.triforce_pool_max[p] = get_setting(settings['triforce_pool_max'], args.triforce_pool_max[p]) + args.triforce_min_difference[p] = get_setting(settings['triforce_min_difference'], args.triforce_min_difference[p]) + args.triforce_max_difference[p] = get_setting(settings['triforce_max_difference'], args.triforce_max_difference[p]) args.beemizer[p] = get_setting(settings['beemizer'], args.beemizer[p]) # mystery usage diff --git a/source/tools/MysteryUtils.py b/source/tools/MysteryUtils.py index a5681a11..07f06856 100644 --- a/source/tools/MysteryUtils.py +++ b/source/tools/MysteryUtils.py @@ -138,15 +138,14 @@ def roll_settings(weights): ret.crystals_gt = get_choice('tower_open') ret.crystals_ganon = get_choice('ganon_open') - from ItemList import set_default_triforce - default_tf_goal, default_tf_pool = set_default_triforce(ret.goal, 0, 0) - goal_min = get_choice_default('triforce_goal_min', default=default_tf_goal) - goal_max = get_choice_default('triforce_goal_max', default=default_tf_goal) - pool_min = get_choice_default('triforce_pool_min', default=default_tf_pool) - pool_max = get_choice_default('triforce_pool_max', default=default_tf_pool) - ret.triforce_goal = random.randint(int(goal_min), int(goal_max)) - min_diff = get_choice_default('triforce_min_difference', default=(default_tf_pool-default_tf_goal)) - ret.triforce_pool = random.randint(max(int(pool_min), ret.triforce_goal + int(min_diff)), int(pool_max)) + ret.triforce_pool = get_choice_default('triforce_pool', default=0) + ret.triforce_goal = get_choice_default('triforce_goal', default=0) + ret.triforce_pool_min = get_choice_default('triforce_pool_min', default=0) + ret.triforce_pool_max = get_choice_default('triforce_pool_max', default=0) + ret.triforce_goal_min = get_choice_default('triforce_goal_min', default=0) + ret.triforce_goal_max = get_choice_default('triforce_goal_max', default=0) + ret.triforce_min_difference = get_choice_default('triforce_min_difference', default=0) + ret.triforce_max_difference = get_choice_default('triforce_max_difference', default=10000) ret.mode = get_choice('world_state') if ret.mode == 'retro':