diff --git a/UndertaleClient.py b/UndertaleClient.py index e0ec642b..64197072 100644 --- a/UndertaleClient.py +++ b/UndertaleClient.py @@ -99,6 +99,7 @@ class UndertaleContext(CommonContext): def __init__(self, server_address, password): super().__init__(server_address, password) self.pieces_needed = 0 + self.finished_game = False self.game = "Undertale" self.got_deathlink = False self.syncing = False @@ -239,8 +240,6 @@ async def process_undertale_cmd(ctx: UndertaleContext, cmd: str, args: dict): for ss in set(args["checked_locations"]): f.write(str(ss-12000)+"\n") f.close() - message = [{"cmd": "LocationChecks", "locations": [79067]}] - await ctx.send_msgs(message) elif cmd == "LocationInfo": for l in args["locations"]: locationid = l.location @@ -436,9 +435,9 @@ async def game_watcher(ctx: UndertaleContext): for l in lines: if ctx.server_locations.__contains__(int(l)+12000): sending = sending + [int(l.rstrip('\n'))+12000] + finally: await ctx.send_msgs([{"cmd": "LocationScouts", "locations": sending, "create_as_hint": int(2)}]) - finally: os.remove(root+"/"+file) if "check.spot" in file: sending = [] @@ -447,10 +446,8 @@ async def game_watcher(ctx: UndertaleContext): lines = f.readlines() for l in lines: sending = sending+[(int(l.rstrip('\n')))+12000] - message = [{"cmd": "LocationChecks", "locations": sending}] - await ctx.send_msgs(message) finally: - pass + await ctx.send_msgs([{"cmd": "LocationChecks", "locations": sending}]) if "victory" in file and str(ctx.route) in file: victory = True if ".playerspot" in file and "Online" not in ctx.tags: diff --git a/worlds/undertale/Items.py b/worlds/undertale/Items.py index 50811bd1..03310266 100644 --- a/worlds/undertale/Items.py +++ b/worlds/undertale/Items.py @@ -88,10 +88,10 @@ item_table = { "ATK Up": ItemData(77065, ItemClassification.useful), "DEF Up": ItemData(77066, ItemClassification.useful), "HP Up": ItemData(77067, ItemClassification.useful), - "FIGHT": ItemData(77077, ItemClassification.progression), - "ACT": ItemData(77078, ItemClassification.progression), - "ITEM": ItemData(77079, ItemClassification.progression), - "MERCY": ItemData(77080, ItemClassification.progression), + "FIGHT": ItemData(77077, ItemClassification.useful), + "ACT": ItemData(77078, ItemClassification.useful), + "ITEM": ItemData(77079, ItemClassification.useful), + "MERCY": ItemData(77080, ItemClassification.useful), "Ruins Key": ItemData(77081, ItemClassification.progression), "Snowdin Key": ItemData(77082, ItemClassification.progression), "Waterfall Key": ItemData(77083, ItemClassification.progression), diff --git a/worlds/undertale/Locations.py b/worlds/undertale/Locations.py index c000a46d..2f7de445 100644 --- a/worlds/undertale/Locations.py +++ b/worlds/undertale/Locations.py @@ -77,7 +77,6 @@ advancement_table = { "True Lab Plot": AdvData(79063, "Hotland"), "Left New Home Key": AdvData(79064, "New Home"), "Right New Home Key": AdvData(79065, "New Home"), - "Starting Key": AdvData(79067, "Hub"), "LOVE 2": AdvData(79902, "???"), "LOVE 3": AdvData(79903, "???"), "LOVE 4": AdvData(79904, "???"), diff --git a/worlds/undertale/Options.py b/worlds/undertale/Options.py index d4fd1488..146a7838 100644 --- a/worlds/undertale/Options.py +++ b/worlds/undertale/Options.py @@ -12,6 +12,17 @@ class RouteRequired(Choice): default = 0 +class StartingArea(Choice): + """Which area to start with access to.""" + display_name = "Starting Area" + option_ruins = 0 + option_snowdin = 1 + option_waterfall = 2 + option_hotland = 3 + option_core = 4 + default = 0 + + class IncludeTemy(Toggle): """Adds Temmy Armor to the item pool.""" display_name = "Include Temy Armor" @@ -77,6 +88,7 @@ class RandoBattleOptions(Toggle): undertale_options: typing.Dict[str, type(Option)] = { "route_required": RouteRequired, + "starting_area": StartingArea, "key_hunt": KeyHunt, "key_pieces": KeyPieces, "rando_love": RandomizeLove, diff --git a/worlds/undertale/Rules.py b/worlds/undertale/Rules.py index eb99e8ca..02c21f53 100644 --- a/worlds/undertale/Rules.py +++ b/worlds/undertale/Rules.py @@ -76,21 +76,6 @@ def set_rules(multiworld: MultiWorld, player: int): set_rule(multiworld.get_entrance("Waterfall Hub", player), lambda state: state.has("Waterfall Key", player)) set_rule(multiworld.get_entrance("Hotland Hub", player), lambda state: state.has("Hotland Key", player)) set_rule(multiworld.get_entrance("Core Hub", player), lambda state: state.has("Core Key", player)) - if _undertale_is_route(multiworld.state, player, 1): - add_rule(multiworld.get_entrance("Snowdin Hub", player), lambda state: state.has("ACT", player) and state.has("MERCY", player)) - add_rule(multiworld.get_entrance("Waterfall Hub", player), lambda state: state.has("ACT", player) and state.has("MERCY", player)) - add_rule(multiworld.get_entrance("Hotland Hub", player), lambda state: state.has("ACT", player) and state.has("MERCY", player)) - add_rule(multiworld.get_entrance("Core Hub", player), lambda state: state.has("ACT", player) and state.has("MERCY", player)) - if _undertale_is_route(multiworld.state, player, 2) or _undertale_is_route(multiworld.state, player, 3): - add_rule(multiworld.get_entrance("Snowdin Hub", player), lambda state: state.has("FIGHT", player)) - add_rule(multiworld.get_entrance("Waterfall Hub", player), lambda state: state.has("FIGHT", player)) - add_rule(multiworld.get_entrance("Hotland Hub", player), lambda state: state.has("FIGHT", player)) - add_rule(multiworld.get_entrance("Core Hub", player), lambda state: state.has("FIGHT", player)) - if _undertale_is_route(multiworld.state, player, 0): - add_rule(multiworld.get_entrance("Snowdin Hub", player), lambda state: ((state.has("ACT", player) and state.has("MERCY", player)) or state.has("FIGHT", player))) - add_rule(multiworld.get_entrance("Waterfall Hub", player), lambda state: ((state.has("ACT", player) and state.has("MERCY", player)) or state.has("FIGHT", player))) - add_rule(multiworld.get_entrance("Hotland Hub", player), lambda state: ((state.has("ACT", player) and state.has("MERCY", player)) or state.has("FIGHT", player))) - add_rule(multiworld.get_entrance("Core Hub", player), lambda state: ((state.has("ACT", player) and state.has("MERCY", player)) or state.has("FIGHT", player))) set_rule(multiworld.get_entrance("Core Exit", player), lambda state: _undertale_has_plot(state, player, "Mettaton Plush")) set_rule(multiworld.get_entrance("New Home Exit", player), @@ -153,7 +138,7 @@ def set_rules(multiworld: MultiWorld, player: int): if multiworld.rando_stats[player]: set_rule(multiworld.get_location(("ATK "+str(maxlv)), player), lambda state: False) set_rule(multiworld.get_location(("HP "+str(maxlv)), player), lambda state: False) - if maxlv == 9 or maxlv == 13 or maxlv == 17: + if maxlv in {5, 9, 13, 17}: set_rule(multiworld.get_location(("DEF "+str(maxlv)), player), lambda state: False) maxlv = 1 while maxlv < 20: @@ -165,7 +150,7 @@ def set_rules(multiworld: MultiWorld, player: int): lambda state: (state.can_reach("Old Home", "Region", player)), combine="or") add_rule(multiworld.get_location(("HP "+str(maxlv)), player), lambda state: (state.can_reach("Old Home", "Region", player)), combine="or") - if maxlv == 9 or maxlv == 13 or maxlv == 17: + if maxlv == 5 or maxlv == 9 or maxlv == 13 or maxlv == 17: add_rule(multiworld.get_location(("DEF "+str(maxlv)), player), lambda state: (state.can_reach("Old Home", "Region", player)), combine="or") elif curarea == "Snowdin Town": @@ -173,7 +158,7 @@ def set_rules(multiworld: MultiWorld, player: int): lambda state: (state.can_reach("Snowdin Town", "Region", player)), combine="or") add_rule(multiworld.get_location(("HP "+str(maxlv)), player), lambda state: (state.can_reach("Snowdin Town", "Region", player)), combine="or") - if maxlv == 9 or maxlv == 13 or maxlv == 17: + if maxlv == 5 or maxlv == 9 or maxlv == 13 or maxlv == 17: add_rule(multiworld.get_location(("DEF "+str(maxlv)), player), lambda state: (state.can_reach("Snowdin Town", "Region", player)), combine="or") elif curarea == "Waterfall": @@ -181,7 +166,7 @@ def set_rules(multiworld: MultiWorld, player: int): lambda state: (state.can_reach("Waterfall", "Region", player)), combine="or") add_rule(multiworld.get_location(("HP "+str(maxlv)), player), lambda state: (state.can_reach("Waterfall", "Region", player)), combine="or") - if maxlv == 9 or maxlv == 13 or maxlv == 17: + if maxlv == 5 or maxlv == 9 or maxlv == 13 or maxlv == 17: add_rule(multiworld.get_location(("DEF "+str(maxlv)), player), lambda state: (state.can_reach("Waterfall", "Region", player)), combine="or") elif curarea == "News Show": @@ -189,7 +174,7 @@ def set_rules(multiworld: MultiWorld, player: int): lambda state: (state.can_reach("News Show", "Region", player)), combine="or") add_rule(multiworld.get_location(("HP "+str(maxlv)), player), lambda state: (state.can_reach("News Show", "Region", player)), combine="or") - if maxlv == 9 or maxlv == 13 or maxlv == 17: + if maxlv == 5 or maxlv == 9 or maxlv == 13 or maxlv == 17: add_rule(multiworld.get_location(("DEF "+str(maxlv)), player), lambda state: (state.can_reach("News Show", "Region", player)), combine="or") elif curarea == "Core": @@ -197,7 +182,7 @@ def set_rules(multiworld: MultiWorld, player: int): lambda state: (state.can_reach("Core Exit", "Entrance", player)), combine="or") add_rule(multiworld.get_location(("HP "+str(maxlv)), player), lambda state: (state.can_reach("Core Exit", "Entrance", player)), combine="or") - if maxlv == 9 or maxlv == 13 or maxlv == 17: + if maxlv == 5 or maxlv == 9 or maxlv == 13 or maxlv == 17: add_rule(multiworld.get_location(("DEF "+str(maxlv)), player), lambda state: (state.can_reach("Core Exit", "Entrance", player)), combine="or") elif curarea == "Sans": @@ -205,13 +190,13 @@ def set_rules(multiworld: MultiWorld, player: int): lambda state: (state.can_reach("New Home Exit", "Entrance", player)), combine="or") add_rule(multiworld.get_location(("HP "+str(maxlv)), player), lambda state: (state.can_reach("New Home Exit", "Entrance", player)), combine="or") - if maxlv == 9 or maxlv == 13 or maxlv == 17: + if maxlv == 5 or maxlv == 9 or maxlv == 13 or maxlv == 17: add_rule(multiworld.get_location(("DEF "+str(maxlv)), player), lambda state: (state.can_reach("New Home Exit", "Entrance", player)), combine="or") if multiworld.rando_love[player]: if curarea == "Old Home": add_rule(multiworld.get_location(("LOVE "+str(maxlv)), player), - lambda state: ( state.can_reach("Old Home", "Region", player)), combine="or") + lambda state: (state.can_reach("Old Home", "Region", player)), combine="or") elif curarea == "Snowdin Town": add_rule(multiworld.get_location(("LOVE "+str(maxlv)), player), lambda state: (state.can_reach("Snowdin Town", "Region", player)), combine="or") @@ -247,46 +232,8 @@ def set_rules(multiworld: MultiWorld, player: int): curarea = "Sans" maxlv = 1 exp = 99999 - set_rule(multiworld.get_entrance("??? Exit", player), lambda state: state.has("FIGHT", player)) set_rule(multiworld.get_location("Snowman", player), lambda state: state.can_reach("Snowdin Town", "Region", player)) - add_item_rule(multiworld.get_location("Starting Key", player), lambda item: item.name == "Ruins Key" or - item.name == "Snowdin Key" or - item.name == "Waterfall Key" or - item.name == "Hotland Key") - if _undertale_is_route(multiworld.state, player, 1): - set_rule(multiworld.get_location("Donut Sale", player), - lambda state: state.has("ACT", player) and state.has("MERCY", player)) - set_rule(multiworld.get_location("Cider Sale", player), - lambda state: state.has("ACT", player) and state.has("MERCY", player)) - set_rule(multiworld.get_location("Ribbon Cracks", player), - lambda state: state.has("ACT", player) and state.has("MERCY", player)) - set_rule(multiworld.get_location("Toy Knife Edge", player), - lambda state: state.has("ACT", player) and state.has("MERCY", player)) - set_rule(multiworld.get_location("B.Scotch Pie Given", player), - lambda state: state.has("ACT", player) and state.has("MERCY", player)) - if _undertale_is_route(multiworld.state, player, 2) or _undertale_is_route(multiworld.state, player, 3): - set_rule(multiworld.get_location("Donut Sale", player), - lambda state: state.has("FIGHT", player)) - set_rule(multiworld.get_location("Cider Sale", player), - lambda state: state.has("FIGHT", player)) - set_rule(multiworld.get_location("Ribbon Cracks", player), - lambda state: state.has("FIGHT", player)) - set_rule(multiworld.get_location("Toy Knife Edge", player), - lambda state: state.has("FIGHT", player)) - set_rule(multiworld.get_location("B.Scotch Pie Given", player), - lambda state: state.has("FIGHT", player)) - if _undertale_is_route(multiworld.state, player, 0): - set_rule(multiworld.get_location("Donut Sale", player), - lambda state: ((state.has("ACT", player) and state.has("MERCY", player)) or state.has("FIGHT", player))) - set_rule(multiworld.get_location("Cider Sale", player), - lambda state: ((state.has("ACT", player) and state.has("MERCY", player)) or state.has("FIGHT", player))) - set_rule(multiworld.get_location("Ribbon Cracks", player), - lambda state: ((state.has("ACT", player) and state.has("MERCY", player)) or state.has("FIGHT", player))) - set_rule(multiworld.get_location("Toy Knife Edge", player), - lambda state: ((state.has("ACT", player) and state.has("MERCY", player)) or state.has("FIGHT", player))) - set_rule(multiworld.get_location("B.Scotch Pie Given", player), - lambda state: ((state.has("ACT", player) and state.has("MERCY", player)) or state.has("FIGHT", player))) set_rule(multiworld.get_location("Mettaton Plot", player), lambda state: state.can_reach("Core Exit", "Entrance", player)) set_rule(multiworld.get_location("Bunny 1", player), @@ -357,7 +304,7 @@ def set_rules(multiworld: MultiWorld, player: int): # Sets rules on completion condition def set_completion_rules(multiworld: MultiWorld, player: int): - completion_requirements = lambda state: state.can_reach("New Home Exit", "Entrance", player) and state.has("FIGHT", player) + completion_requirements = lambda state: state.can_reach("New Home Exit", "Entrance", player) if _undertale_is_route(multiworld.state, player, 1): completion_requirements = lambda state: state.can_reach("True Lab", "Region", player) diff --git a/worlds/undertale/__init__.py b/worlds/undertale/__init__.py index 717b5c0f..3a34a162 100644 --- a/worlds/undertale/__init__.py +++ b/worlds/undertale/__init__.py @@ -52,7 +52,7 @@ class UndertaleWorld(World): item_name_to_id = {name: data.code for name, data in item_table.items()} location_name_to_id = {name: data.id for name, data in advancement_table.items()} - data_version = 6 + data_version = 7 def _get_undertale_data(self): return { @@ -63,6 +63,7 @@ class UndertaleWorld(World): "client_version": self.required_client_version, "race": self.multiworld.is_race, "route": self.multiworld.route_required[self.player].current_key, + "starting_area": self.multiworld.starting_area[self.player].current_key, "temy_armor_include": bool(self.multiworld.temy_include[self.player].value), "only_flakes": bool(self.multiworld.only_flakes[self.player].value), "no_equips": bool(self.multiworld.no_equips[self.player].value), @@ -153,6 +154,10 @@ class UndertaleWorld(World): if item == "Heart Locket" else item for item in itempool] if self.multiworld.only_flakes[self.player]: itempool = [item for item in itempool if item not in non_key_items] + + starting_key = self.multiworld.starting_area[self.player].current_key.title() + " Key" + itempool.remove(starting_key) + self.multiworld.push_precollected(self.create_item(starting_key)) # Choose locations to automatically exclude based on settings exclusion_pool = set() exclusion_pool.update(exclusion_table[self.multiworld.route_required[self.player].current_key])