From 8c861390668fa02282dd5a67e24a149a65318f79 Mon Sep 17 00:00:00 2001 From: Alchav <59858495+Alchav@users.noreply.github.com> Date: Wed, 10 Jul 2024 11:15:29 -0400 Subject: [PATCH 1/8] ALTTP: Bombable Wall to Crystaroller Room Logic (#3627) --- worlds/alttp/Rules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/alttp/Rules.py b/worlds/alttp/Rules.py index 171c82f9b226..67684a6f3ced 100644 --- a/worlds/alttp/Rules.py +++ b/worlds/alttp/Rules.py @@ -488,7 +488,7 @@ def global_rules(multiworld: MultiWorld, player: int): set_rule(multiworld.get_location('Turtle Rock - Roller Room - Right', player), lambda state: state.has('Cane of Somaria', player) and state.has('Fire Rod', player)) set_rule(multiworld.get_location('Turtle Rock - Big Chest', player), lambda state: state.has('Big Key (Turtle Rock)', player) and (state.has('Cane of Somaria', player) or state.has('Hookshot', player))) set_rule(multiworld.get_entrance('Turtle Rock (Big Chest) (North)', player), lambda state: state.has('Cane of Somaria', player) or state.has('Hookshot', player)) - set_rule(multiworld.get_entrance('Turtle Rock Big Key Door', player), lambda state: state.has('Big Key (Turtle Rock)', player) and can_kill_most_things(state, player, 10)) + set_rule(multiworld.get_entrance('Turtle Rock Big Key Door', player), lambda state: state.has('Big Key (Turtle Rock)', player) and can_kill_most_things(state, player, 10) and can_bomb_or_bonk(state, player)) set_rule(multiworld.get_location('Turtle Rock - Chain Chomps', player), lambda state: can_use_bombs(state, player) or can_shoot_arrows(state, player) or has_beam_sword(state, player) or state.has_any(["Blue Boomerang", "Red Boomerang", "Hookshot", "Cane of Somaria", "Fire Rod", "Ice Rod"], player)) set_rule(multiworld.get_entrance('Turtle Rock (Dark Room) (North)', player), lambda state: state.has('Cane of Somaria', player)) From 1e3a4b6db5acff8e82bdecdc79773f2923de919a Mon Sep 17 00:00:00 2001 From: Doug Hoskisson Date: Wed, 10 Jul 2024 23:11:47 -0700 Subject: [PATCH 2/8] Zillion: more rooms added to map_gen option (#3634) --- worlds/zillion/client.py | 5 +++++ worlds/zillion/gen_data.py | 7 +++++++ worlds/zillion/requirements.txt | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/worlds/zillion/client.py b/worlds/zillion/client.py index be32028463c7..09d0565e1c5e 100644 --- a/worlds/zillion/client.py +++ b/worlds/zillion/client.py @@ -347,6 +347,11 @@ def process_from_game_queue(self) -> None: "operations": [{"operation": "replace", "value": doors_b64}] } async_start(self.send_msgs([payload])) + elif isinstance(event_from_game, events.MapEventFromGame): + row = event_from_game.map_index // 8 + col = event_from_game.map_index % 8 + room_name = f"({chr(row + 64)}-{col + 1})" + logger.info(f"You are at {room_name}") else: logger.warning(f"WARNING: unhandled event from game {event_from_game}") diff --git a/worlds/zillion/gen_data.py b/worlds/zillion/gen_data.py index aa24ff8961b3..13cbee9ced20 100644 --- a/worlds/zillion/gen_data.py +++ b/worlds/zillion/gen_data.py @@ -28,6 +28,13 @@ def to_json(self) -> str: def from_json(gen_data_str: str) -> "GenData": """ the reverse of `to_json` """ from_json = json.loads(gen_data_str) + + # backwards compatibility for seeds generated before new map_gen options + room_gen = from_json["zz_game"]["options"].get("room_gen", None) + if room_gen is not None: + from_json["zz_game"]["options"]["map_gen"] = {False: "none", True: "rooms"}.get(room_gen, "none") + del from_json["zz_game"]["options"]["room_gen"] + return GenData( from_json["multi_items"], ZzGame.from_jsonable(from_json["zz_game"]), diff --git a/worlds/zillion/requirements.txt b/worlds/zillion/requirements.txt index b4f554902f48..d6b01ac107ae 100644 --- a/worlds/zillion/requirements.txt +++ b/worlds/zillion/requirements.txt @@ -1,2 +1,2 @@ -zilliandomizer @ git+https://github.com/beauxq/zilliandomizer@4a2fec0aa1c529df866e510cdfcf6dca4d53679b#0.8.0 +zilliandomizer @ git+https://github.com/beauxq/zilliandomizer@33045067f626266850f91c8045b9d3a9f52d02b0#0.9.0 typing-extensions>=4.7, <5 From eaec41d8854ef53bf626a1dce4f81a87cd867500 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Thu, 11 Jul 2024 16:44:29 -0400 Subject: [PATCH 3/8] TUNIC: Fix event region for Quarry fuse (#3635) --- worlds/tunic/er_scripts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/tunic/er_scripts.py b/worlds/tunic/er_scripts.py index 8689a51b7601..0bd8c5e80681 100644 --- a/worlds/tunic/er_scripts.py +++ b/worlds/tunic/er_scripts.py @@ -67,7 +67,7 @@ def create_er_regions(world: "TunicWorld") -> Dict[Portal, Portal]: "Eastern Vault West Fuses": "Eastern Vault Fortress", "Eastern Vault East Fuse": "Eastern Vault Fortress", "Quarry Connector Fuse": "Quarry Connector", - "Quarry Fuse": "Quarry", + "Quarry Fuse": "Quarry Entry", "Ziggurat Fuse": "Rooted Ziggurat Lower Back", "West Garden Fuse": "West Garden", "Library Fuse": "Library Lab", From 187f9dac9425b916f2f60cd673f1acf31390fc69 Mon Sep 17 00:00:00 2001 From: black-sliver <59490463+black-sliver@users.noreply.github.com> Date: Sun, 14 Jul 2024 13:56:27 +0200 Subject: [PATCH 4/8] customserver: preemtively run GC before starting room (#3637) GC seems to be lazy. --- WebHostLib/customserver.py | 1 + 1 file changed, 1 insertion(+) diff --git a/WebHostLib/customserver.py b/WebHostLib/customserver.py index 9f70165b61e5..50c316f3b750 100644 --- a/WebHostLib/customserver.py +++ b/WebHostLib/customserver.py @@ -325,6 +325,7 @@ def _done(self, task: asyncio.Future): def run(self): while 1: next_room = rooms_to_run.get(block=True, timeout=None) + gc.collect(0) task = asyncio.run_coroutine_threadsafe(start_room(next_room), loop) self._tasks.append(task) task.add_done_callback(self._done) From 948f50f35db1b13336f08b0e5740d900904404b0 Mon Sep 17 00:00:00 2001 From: black-sliver <59490463+black-sliver@users.noreply.github.com> Date: Sun, 14 Jul 2024 13:56:56 +0200 Subject: [PATCH 5/8] customserver: fix minor memory leak (#3636) Old code keeps ref to last started room's task and thus never fully cleans it up. --- WebHostLib/customserver.py | 1 + 1 file changed, 1 insertion(+) diff --git a/WebHostLib/customserver.py b/WebHostLib/customserver.py index 50c316f3b750..ccffc40b384d 100644 --- a/WebHostLib/customserver.py +++ b/WebHostLib/customserver.py @@ -330,6 +330,7 @@ def run(self): self._tasks.append(task) task.add_done_callback(self._done) logging.info(f"Starting room {next_room} on {name}.") + del task # delete reference to task object starter = Starter() starter.daemon = True From 48dc14421e125d20d651f8b0368b20b484250631 Mon Sep 17 00:00:00 2001 From: Bryce Wilson Date: Sun, 14 Jul 2024 05:05:50 -0700 Subject: [PATCH 6/8] Pokemon Emerald: Fix logic for coin case location (#3631) --- worlds/pokemon_emerald/rules.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/worlds/pokemon_emerald/rules.py b/worlds/pokemon_emerald/rules.py index f93441baeac1..5b2aaa1ffcd0 100644 --- a/worlds/pokemon_emerald/rules.py +++ b/worlds/pokemon_emerald/rules.py @@ -558,6 +558,10 @@ def get_location(location: str): get_location("NPC_GIFT_GOT_BASEMENT_KEY_FROM_WATTSON"), lambda state: state.has("EVENT_DEFEAT_NORMAN", world.player) ) + set_rule( + get_location("NPC_GIFT_RECEIVED_COIN_CASE"), + lambda state: state.has("EVENT_BUY_HARBOR_MAIL", world.player) + ) # Route 117 set_rule( @@ -1638,10 +1642,6 @@ def get_location(location: str): get_location("NPC_GIFT_GOT_TM_THUNDERBOLT_FROM_WATTSON"), lambda state: state.has("EVENT_DEFEAT_NORMAN", world.player) and state.has("EVENT_TURN_OFF_GENERATOR", world.player) ) - set_rule( - get_location("NPC_GIFT_RECEIVED_COIN_CASE"), - lambda state: state.has("EVENT_BUY_HARBOR_MAIL", world.player) - ) # Fallarbor Town set_rule( From 08a36ec223b1c7bc27cca3b766744fcbdd844326 Mon Sep 17 00:00:00 2001 From: dennisw100 <100dennisw@gmail.com> Date: Sun, 14 Jul 2024 14:11:52 +0200 Subject: [PATCH 7/8] Undertale: Fixed output location of the patched game in UndertaleClient.py (#3418) * Update UndertaleClient.py Fixed output location of the patched game Fixed the error that when the client is opened outside of the archipelago folder, the patched folder would be created in there which on windows ends up trying to create it in the system32 folder Bug Report: https://discord.com/channels/731205301247803413/1148330675452264499/1237412436382973962 * Undertale: removed unnecessary wrapping in UndertaleClient.py I did not know os.path.join was unnecessary in this case the more you know. --- UndertaleClient.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/UndertaleClient.py b/UndertaleClient.py index 415d7e7f21a3..dfacee148abc 100644 --- a/UndertaleClient.py +++ b/UndertaleClient.py @@ -29,7 +29,7 @@ def _cmd_resync(self): def _cmd_patch(self): """Patch the game. Only use this command if /auto_patch fails.""" if isinstance(self.ctx, UndertaleContext): - os.makedirs(name=os.path.join(os.getcwd(), "Undertale"), exist_ok=True) + os.makedirs(name=Utils.user_path("Undertale"), exist_ok=True) self.ctx.patch_game() self.output("Patched.") @@ -43,7 +43,7 @@ def _cmd_savepath(self, directory: str): def _cmd_auto_patch(self, steaminstall: typing.Optional[str] = None): """Patch the game automatically.""" if isinstance(self.ctx, UndertaleContext): - os.makedirs(name=os.path.join(os.getcwd(), "Undertale"), exist_ok=True) + os.makedirs(name=Utils.user_path("Undertale"), exist_ok=True) tempInstall = steaminstall if not os.path.isfile(os.path.join(tempInstall, "data.win")): tempInstall = None @@ -62,7 +62,7 @@ def _cmd_auto_patch(self, steaminstall: typing.Optional[str] = None): for file_name in os.listdir(tempInstall): if file_name != "steam_api.dll": shutil.copy(os.path.join(tempInstall, file_name), - os.path.join(os.getcwd(), "Undertale", file_name)) + Utils.user_path("Undertale", file_name)) self.ctx.patch_game() self.output("Patching successful!") @@ -111,12 +111,12 @@ def __init__(self, server_address, password): self.save_game_folder = os.path.expandvars(r"%localappdata%/UNDERTALE") def patch_game(self): - with open(os.path.join(os.getcwd(), "Undertale", "data.win"), "rb") as f: + with open(Utils.user_path("Undertale", "data.win"), "rb") as f: patchedFile = bsdiff4.patch(f.read(), undertale.data_path("patch.bsdiff")) - with open(os.path.join(os.getcwd(), "Undertale", "data.win"), "wb") as f: + with open(Utils.user_path("Undertale", "data.win"), "wb") as f: f.write(patchedFile) - os.makedirs(name=os.path.join(os.getcwd(), "Undertale", "Custom Sprites"), exist_ok=True) - with open(os.path.expandvars(os.path.join(os.getcwd(), "Undertale", "Custom Sprites", + os.makedirs(name=Utils.user_path("Undertale", "Custom Sprites"), exist_ok=True) + with open(os.path.expandvars(Utils.user_path("Undertale", "Custom Sprites", "Which Character.txt")), "w") as f: f.writelines(["// Put the folder name of the sprites you want to play as, make sure it is the only " "line other than this one.\n", "frisk"]) From e76d32e9089efa0554034a0c2c9049f03026267e Mon Sep 17 00:00:00 2001 From: CookieCat <81494827+CookieCat45@users.noreply.github.com> Date: Sun, 14 Jul 2024 08:17:05 -0400 Subject: [PATCH 8/8] AHIT: Fix act shuffle test fail (#3522) --- worlds/ahit/Regions.py | 3 +++ worlds/ahit/Rules.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/worlds/ahit/Regions.py b/worlds/ahit/Regions.py index 0ba0f5b9a5a4..c6aeaa357799 100644 --- a/worlds/ahit/Regions.py +++ b/worlds/ahit/Regions.py @@ -292,6 +292,9 @@ # See above comment "Time Rift - Deep Sea": ["Alpine Free Roam", "Nyakuza Free Roam", "Contractual Obligations", "Murder on the Owl Express"], + + # was causing test failures + "Time Rift - Balcony": ["Alpine Free Roam"], } diff --git a/worlds/ahit/Rules.py b/worlds/ahit/Rules.py index 71f74b17d7ed..b0513c433289 100644 --- a/worlds/ahit/Rules.py +++ b/worlds/ahit/Rules.py @@ -863,6 +863,8 @@ def set_rift_rules(world: "HatInTimeWorld", regions: Dict[str, Region]): if world.is_dlc1(): for entrance in regions["Time Rift - Balcony"].entrances: add_rule(entrance, lambda state: can_clear_required_act(state, world, "The Arctic Cruise - Finale")) + reg_act_connection(world, world.multiworld.get_entrance("The Arctic Cruise - Finale", + world.player).connected_region, entrance) for entrance in regions["Time Rift - Deep Sea"].entrances: add_rule(entrance, lambda state: has_relic_combo(state, world, "Cake")) @@ -939,6 +941,7 @@ def set_default_rift_rules(world: "HatInTimeWorld"): if world.is_dlc1(): for entrance in world.multiworld.get_region("Time Rift - Balcony", world.player).entrances: add_rule(entrance, lambda state: can_clear_required_act(state, world, "The Arctic Cruise - Finale")) + reg_act_connection(world, "Rock the Boat", entrance.name) for entrance in world.multiworld.get_region("Time Rift - Deep Sea", world.player).entrances: add_rule(entrance, lambda state: has_relic_combo(state, world, "Cake"))