From 8d933b82debbe0f4b4f2f29575f179e1ebf9ece9 Mon Sep 17 00:00:00 2001 From: Fouton Date: Fri, 12 Mar 2021 16:41:35 -0500 Subject: [PATCH] TFH Futures --- BaseClasses.py | 6 +-- CLI.py | 106 ++++++++++++++++++++++++------------------------- ItemList.py | 31 +++++---------- Main.py | 9 ++--- Mystery.py | 9 +++-- Rom.py | 7 +--- 6 files changed, 76 insertions(+), 92 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index aafe03a8..45017752 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -128,6 +128,7 @@ class World(object): set_player_attr('open_pyramid', False) set_player_attr('treasure_hunt_icon', 'Triforce Piece') set_player_attr('treasure_hunt_count', 0) + set_player_attr('treasure_hunt_total', 0) set_player_attr('potshuffle', False) set_player_attr('pot_contents', None) @@ -1377,11 +1378,6 @@ class Door(object): else: self.passage = False - def kind(self, world): - if self.roomIndex != -1 and self.doorListPos != -1: - return world.get_room(self.roomIndex, self.player).kind(self) - return None - def __eq__(self, other): return isinstance(other, self.__class__) and self.name == other.name diff --git a/CLI.py b/CLI.py index a48031b5..0ceec234 100644 --- a/CLI.py +++ b/CLI.py @@ -6,6 +6,7 @@ import textwrap import shlex import sys +import source.classes.constants as CONST from source.classes.BabelFish import BabelFish from Utils import update_deprecated_args @@ -16,7 +17,6 @@ class ArgumentDefaultsHelpFormatter(argparse.RawTextHelpFormatter): def _get_help_string(self, action): return textwrap.dedent(action.help) - def parse_cli(argv, no_defaults=False): def defval(value): return value if not no_defaults else None @@ -28,49 +28,44 @@ def parse_cli(argv, no_defaults=False): fish = BabelFish(lang=lang) # we need to know how many players we have first - # also if we're loading our own settings file, we should do that now parser = argparse.ArgumentParser(add_help=False) - parser.add_argument('--settingsfile', help="input json file of settings", type=str) parser.add_argument('--multi', default=defval(settings["multi"]), type=lambda value: min(max(int(value), 1), 255)) multiargs, _ = parser.parse_known_args(argv) - if multiargs.settingsfile: - settings = apply_settings_file(settings, multiargs.settingsfile) - parser = argparse.ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter) # get args args = [] - with open(os.path.join("resources", "app", "cli", "args.json")) as argsFile: - args = json.load(argsFile) - for arg in args: - argdata = args[arg] - argname = "--" + arg - argatts = {} - argatts["help"] = "(default: %(default)s)" - if "action" in argdata: - argatts["action"] = argdata["action"] - if "choices" in argdata: - argatts["choices"] = argdata["choices"] - argatts["const"] = argdata["choices"][0] - argatts["default"] = argdata["choices"][0] - argatts["nargs"] = "?" - if arg in settings: - default = settings[arg] - if "type" in argdata and argdata["type"] == "bool": - default = settings[arg] != 0 - argatts["default"] = defval(default) - arghelp = fish.translate("cli", "help", arg) - if "help" in argdata and argdata["help"] == "suppress": - argatts["help"] = argparse.SUPPRESS - elif not isinstance(arghelp, str): - argatts["help"] = '\n'.join(arghelp).replace("\\'", "'") - else: - argatts["help"] = arghelp + " " + argatts["help"] - parser.add_argument(argname, **argatts) + with open(os.path.join("resources","app","cli","args.json")) as argsFile: + args = json.load(argsFile) + for arg in args: + argdata = args[arg] + argname = "--" + arg + argatts = {} + argatts["help"] = "(default: %(default)s)" + if "action" in argdata: + argatts["action"] = argdata["action"] + if "choices" in argdata: + argatts["choices"] = argdata["choices"] + argatts["const"] = argdata["choices"][0] + argatts["default"] = argdata["choices"][0] + argatts["nargs"] = "?" + if arg in settings: + default = settings[arg] + if "type" in argdata and argdata["type"] == "bool": + default = settings[arg] != 0 + argatts["default"] = defval(default) + arghelp = fish.translate("cli","help",arg) + if "help" in argdata and argdata["help"] == "suppress": + argatts["help"] = argparse.SUPPRESS + elif not isinstance(arghelp,str): + argatts["help"] = '\n'.join(arghelp).replace("\\'","'") + else: + argatts["help"] = arghelp + " " + argatts["help"] + parser.add_argument(argname,**argatts) - parser.add_argument('--seed', default=defval(int(settings["seed"]) if settings["seed"] != "" and settings["seed"] is not None else None), help="\n".join(fish.translate("cli", "help", "seed")), type=int) - parser.add_argument('--count', default=defval(int(settings["count"]) if settings["count"] != "" and settings["count"] is not None else 1), help="\n".join(fish.translate("cli", "help", "count")), type=int) + parser.add_argument('--seed', default=defval(int(settings["seed"]) if settings["seed"] != "" and settings["seed"] is not None else None), help="\n".join(fish.translate("cli","help","seed")), type=int) + parser.add_argument('--count', default=defval(int(settings["count"]) if settings["count"] != "" and settings["count"] is not None else 1), help="\n".join(fish.translate("cli","help","count")), type=int) parser.add_argument('--customitemarray', default={}, help=argparse.SUPPRESS) # included for backwards compatibility @@ -78,7 +73,6 @@ def parse_cli(argv, no_defaults=False): parser.add_argument('--multi', default=defval(settings["multi"]), type=lambda value: min(max(int(value), 1), 255)) parser.add_argument('--securerandom', default=defval(settings["securerandom"]), action='store_true') parser.add_argument('--teams', default=defval(1), type=lambda value: max(int(value), 1)) - parser.add_argument('--settingsfile', dest="filename", help="input json file of settings", type=str) if multiargs.multi: for player in range(1, multiargs.multi + 1): @@ -92,11 +86,13 @@ def parse_cli(argv, no_defaults=False): if multiargs.multi: defaults = copy.deepcopy(ret) for player in range(1, multiargs.multi + 1): - playerargs = parse_cli(shlex.split(getattr(ret, f"p{player}")), True) + playerargs = parse_cli(shlex.split(getattr(ret,f"p{player}")), True) for name in ['logic', 'mode', 'swords', 'goal', 'difficulty', 'item_functionality', 'shuffle', 'door_shuffle', 'intensity', 'crystals_ganon', 'crystals_gt', 'openpyramid', 'mapshuffle', 'compassshuffle', 'keyshuffle', 'bigkeyshuffle', 'startinventory', + 'triforce_pool_min', 'triforce_pool_max', 'triforce_goal_min', 'triforce_goal_max', + 'triforce_min_difference', 'triforce_goal', 'triforce_pool', 'retro', 'accessibility', 'hints', 'beemizer', 'experimental', 'dungeon_counters', 'shufflebosses', 'shuffleenemies', 'enemy_health', 'enemy_damage', 'shufflepots', 'ow_palettes', 'uw_palettes', 'sprite', 'disablemusic', 'quickswap', 'fastmenu', 'heartcolor', 'heartbeep', @@ -110,15 +106,6 @@ def parse_cli(argv, no_defaults=False): return ret -def apply_settings_file(settings, settings_path): - if os.path.exists(settings_path): - with open(settings_path) as json_file: - data = json.load(json_file) - for k, v in data.items(): - settings[k] = v - return settings - - def parse_settings(): # set default settings settings = { @@ -162,6 +149,15 @@ def parse_settings(): "dungeon_counters": "default", "mixed_travel": "prevent", "standardize_palettes": "standardize", + + "triforce_pool": 0, + "triforce_goal": 0, + "triforce_pool_min": 0, + "triforce_pool_max": 0, + "triforce_goal_min": 0, + "triforce_goal_max": 0, + "triforce_min_difference": 0, + "code": "", "multi": 1, @@ -175,7 +171,7 @@ def parse_settings(): "quickswap": False, "heartcolor": "red", "heartbeep": "normal", - "sprite": os.path.join(".", "data", "sprites", "official", "001.link.1.zspr"), + "sprite": os.path.join(".","data","sprites","official","001.link.1.zspr"), "fastmenu": "normal", "ow_palettes": "default", "uw_palettes": "default", @@ -281,15 +277,17 @@ def parse_settings(): # read saved settings file if it exists and set these settings_path = os.path.join(".", "resources", "user", "settings.json") - settings = apply_settings_file(settings, settings_path) + if os.path.exists(settings_path): + with(open(settings_path)) as json_file: + data = json.load(json_file) + for k, v in data.items(): + settings[k] = v return settings # Priority fallback is: # 1: CLI -# 2: Settings file(s) +# 2: Settings file # 3: Canned defaults - - def get_args_priority(settings_args, gui_args, cli_args): args = {} args["settings"] = parse_settings() if settings_args is None else settings_args @@ -316,7 +314,7 @@ def get_args_priority(settings_args, gui_args, cli_args): for k in vars(args["cli"]): load_doesnt_have_key = k not in args["load"] cli_val = cli[k] - if isinstance(cli_val, dict) and 1 in cli_val: + if isinstance(cli_val,dict) and 1 in cli_val: cli_val = cli_val[1] different_val = (k in args["load"] and k in cli) and (str(args["load"][k]) != str(cli_val)) cli_has_empty_dict = k in cli and isinstance(cli_val, dict) and len(cli_val) == 0 @@ -325,9 +323,9 @@ def get_args_priority(settings_args, gui_args, cli_args): args["load"][k] = cli_val newArgs = {} - for key in ["settings", "gui", "cli", "load"]: + for key in [ "settings", "gui", "cli", "load" ]: if args[key]: - if isinstance(args[key], dict): + if isinstance(args[key],dict): newArgs[key] = argparse.Namespace(**args[key]) else: newArgs[key] = args[key] diff --git a/ItemList.py b/ItemList.py index d1e44918..495f3897 100644 --- a/ItemList.py +++ b/ItemList.py @@ -37,7 +37,7 @@ Difficulty = namedtuple('Difficulty', ['baseitems', 'bottles', 'bottle_count', 'same_bottle', 'progressiveshield', 'basicshield', 'progressivearmor', 'basicarmor', 'swordless', 'progressivesword', 'basicsword', 'basicbow', 'timedohko', 'timedother', - 'triforcehunt', 'triforce_pieces_required', 'retro', + 'retro', 'extras', 'progressive_sword_limit', 'progressive_shield_limit', 'progressive_armor_limit', 'progressive_bottle_limit', 'progressive_bow_limit', 'heart_piece_limit', 'boss_heart_container_limit']) @@ -60,8 +60,6 @@ difficulties = { basicbow = ['Bow', 'Silver Arrows'], timedohko = ['Green Clock'] * 25, timedother = ['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10, - triforcehunt = ['Triforce Piece'] * 30, - triforce_pieces_required = 20, retro = ['Small Key (Universal)'] * 18 + ['Rupees (20)'] * 10, extras = [normalfirst15extra, normalsecond15extra, normalthird10extra, normalfourth5extra, normalfinal25extra], progressive_sword_limit = 4, @@ -87,8 +85,6 @@ difficulties = { basicbow = ['Bow'] * 2, timedohko = ['Green Clock'] * 25, timedother = ['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10, - triforcehunt = ['Triforce Piece'] * 30, - triforce_pieces_required = 20, retro = ['Small Key (Universal)'] * 13 + ['Rupees (5)'] * 15, extras = [normalfirst15extra, normalsecond15extra, normalthird10extra, normalfourth5extra, normalfinal25extra], progressive_sword_limit = 3, @@ -114,8 +110,6 @@ difficulties = { basicbow = ['Bow'] * 2, timedohko = ['Green Clock'] * 20 + ['Red Clock'] * 5, timedother = ['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10, - triforcehunt = ['Triforce Piece'] * 30, - triforce_pieces_required = 20, retro = ['Small Key (Universal)'] * 13 + ['Rupees (5)'] * 15, extras = [normalfirst15extra, normalsecond15extra, normalthird10extra, normalfourth5extra, normalfinal25extra], progressive_sword_limit = 2, @@ -262,7 +256,7 @@ def generate_itempool(world, player): (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms) = make_custom_item_pool(world.progressive, world.shuffle[player], world.difficulty[player], world.timer, world.goal[player], world.mode[player], world.swords[player], world.retro[player], world.customitemarray) world.rupoor_cost = min(world.customitemarray[player]["rupoorcost"], 9999) else: - (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms) = get_pool_core(world.progressive, world.shuffle[player], world.difficulty[player], world.timer, world.goal[player], world.mode[player], world.swords[player], world.retro[player], world.doorShuffle[player]) + (pool, placed_items, precollected_items, clock_mode, lamps_needed_for_dark_rooms) = get_pool_core(world.progressive, world.shuffle[player], world.difficulty[player], world.treasure_hunt_total[player], world.timer, world.goal[player], world.mode[player], world.swords[player], world.retro[player], world.doorShuffle[player]) if player in world.pool_adjustment.keys(): amt = world.pool_adjustment[player] @@ -320,10 +314,10 @@ def generate_itempool(world, player): if clock_mode is not None: world.clock_mode = clock_mode - if treasure_hunt_count is not None: - world.treasure_hunt_count[player] = treasure_hunt_count - if treasure_hunt_icon is not None: - world.treasure_hunt_icon[player] = treasure_hunt_icon + if world.goal[player] == 'triforcehunt': + world.treasure_hunt_icon[player] = 'Triforce Piece' + if world.custom: + world.treasure_hunt_count[player] = treasure_hunt_count world.itempool.extend([item for item in get_dungeon_item_pool(world) if item.player == player and ((item.smallkey and world.keyshuffle[player]) @@ -640,13 +634,12 @@ shop_transfer = {'Red Potion': 'Rupees (100)', 'Bee': 'Rupees (5)', 'Blue Potion } -def get_pool_core(progressive, shuffle, difficulty, timer, goal, mode, swords, retro, door_shuffle): +def get_pool_core(progressive, shuffle, difficulty, treasure_hunt_total, timer, goal, mode, swords, retro, door_shuffle): pool = [] placed_items = {} precollected_items = [] clock_mode = None - treasure_hunt_count = None - treasure_hunt_icon = None + triforcepool = ['Triforce Piece'] * treasure_hunt_total pool.extend(alwaysitems) @@ -740,10 +733,8 @@ def get_pool_core(progressive, shuffle, difficulty, timer, goal, mode, swords, r extraitems -= len(diff.timedohko) clock_mode = 'countdown-ohko' if goal == 'triforcehunt': - pool.extend(diff.triforcehunt) - extraitems -= len(diff.triforcehunt) - treasure_hunt_count = diff.triforce_pieces_required - treasure_hunt_icon = 'Triforce Piece' + pool.extend(triforcepool) + extraitems -= len(triforcepool) for extra in diff.extras: if extraitems > 0: @@ -771,7 +762,7 @@ def get_pool_core(progressive, shuffle, difficulty, timer, goal, mode, swords, r pool.extend(['Small Key (Universal)']) else: pool.extend(['Small Key (Universal)']) - return (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms) + return (pool, placed_items, precollected_items, clock_mode, lamps_needed_for_dark_rooms) def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, swords, retro, customitemarray): if isinstance(customitemarray,dict) and 1 in customitemarray: diff --git a/Main.py b/Main.py index 0ed2b7eb..c6795d15 100644 --- a/Main.py +++ b/Main.py @@ -22,11 +22,11 @@ from RoomData import create_rooms from Rules import set_rules from Dungeons import create_dungeons, fill_dungeons, fill_dungeons_restrictive from Fill import distribute_items_cutoff, distribute_items_staleness, distribute_items_restrictive, flood_items -from Fill import sell_potions, sell_keys, balance_multiworld_progression, balance_money_progression, lock_shop_locations +from Fill import sell_potions, sell_keys, balance_multiworld_progression, balance_money_progression from ItemList import generate_itempool, difficulties, fill_prizes, customize_shops from Utils import output_path, parse_player_names -__version__ = '0.3.1.5-u' +__version__ = '0.3.1.4-u' class EnemizerError(RuntimeError): @@ -86,6 +86,8 @@ def main(args, seed=None, fish=None): world.keydropshuffle = args.keydropshuffle.copy() world.mixed_travel = args.mixed_travel.copy() world.standardize_palettes = args.standardize_palettes.copy() + world.treasure_hunt_count = args.triforce_goal.copy() + world.treasure_hunt_total = args.triforce_pool.copy() world.rom_seeds = {player: random.randint(0, 999999999) for player in range(1, world.players + 1)} @@ -165,9 +167,6 @@ def main(args, seed=None, fish=None): sell_potions(world, player) if world.retro[player]: sell_keys(world, player) - else: - lock_shop_locations(world, player) - logger.info(world.fish.translate("cli","cli","placing.dungeon.prizes")) diff --git a/Mystery.py b/Mystery.py index 77ab630a..4be8870a 100644 --- a/Mystery.py +++ b/Mystery.py @@ -171,9 +171,11 @@ def roll_settings(weights): ret.openpyramid = goal == 'fast_ganon' if ret.shuffle in ['vanilla', 'dungeonsfull', 'dungeonssimple'] else False ret.crystals_gt = get_choice('tower_open') - ret.crystals_ganon = get_choice('ganon_open') - + + if ret.goal == 'triforcehunt': + ret.triforce_goal = random.randint(int(get_choice('triforce_goal_min')),int(get_choice('triforce_goal_max'))) + ret.triforce_pool = random.randint(max(int(get_choice('triforce_pool_min')),ret.triforce_goal + int(get_choice('triforce_min_difference'))),int(get_choice('triforce_pool_max'))) ret.mode = get_choice('world_state') if ret.mode == 'retro': ret.mode = 'open' @@ -213,7 +215,8 @@ def roll_settings(weights): ret.shufflepots = get_choice('pot_shuffle') == 'on' ret.beemizer = int(get_choice('beemizer')) if 'beemizer' in weights else 0 - + + inventoryweights = weights.get('startinventory', {}) startitems = [] for item in inventoryweights.keys(): diff --git a/Rom.py b/Rom.py index 7458ee5b..ac031a9b 100644 --- a/Rom.py +++ b/Rom.py @@ -16,7 +16,7 @@ from BaseClasses import CollectionState, ShopType, Region, Location, Door, DoorT from DoorShuffle import compass_data, DROptions, boss_indicator from Dungeons import dungeon_music_addresses from KeyDoorShuffle import count_locations_exclude_logic -from Regions import location_table, shop_to_location_table +from Regions import location_table from RoomData import DoorKind from Text import MultiByteTextMapper, CompressedTextMapper, text_addresses, Credits, TextTable from Text import Uncle_texts, Ganon1_texts, TavernMan_texts, Sahasrahla2_texts, Triforce_texts, Blind_texts, BombShop2_texts, junk_texts @@ -1568,10 +1568,7 @@ def write_custom_shops(rom, world, player): break if world.shopsanity[player] or shop.type == ShopType.TakeAny: rom.write_byte(0x186560 + shop.sram_address + index, 1) - loc_item = world.get_location(shop_to_location_table[shop.region.name][index], player).item - if not loc_item: - loc_item = ItemFactory(item['item'], player) - item_id = loc_item.code + item_id = ItemFactory(item['item'], player).code price = int16_as_bytes(item['price']) replace = ItemFactory(item['replacement'], player).code if item['replacement'] else 0xFF replace_price = int16_as_bytes(item['replacement_price'])