Undertale: Key placement fix (#2030)

Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
Co-authored-by: el-u <109771707+el-u@users.noreply.github.com>
This commit is contained in:
Mewlif 2023-08-16 10:02:01 -04:00 committed by GitHub
parent 26b4ff1df2
commit 5cd837256f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 34 additions and 74 deletions

View File

@ -99,6 +99,7 @@ class UndertaleContext(CommonContext):
def __init__(self, server_address, password): def __init__(self, server_address, password):
super().__init__(server_address, password) super().__init__(server_address, password)
self.pieces_needed = 0 self.pieces_needed = 0
self.finished_game = False
self.game = "Undertale" self.game = "Undertale"
self.got_deathlink = False self.got_deathlink = False
self.syncing = 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"]): for ss in set(args["checked_locations"]):
f.write(str(ss-12000)+"\n") f.write(str(ss-12000)+"\n")
f.close() f.close()
message = [{"cmd": "LocationChecks", "locations": [79067]}]
await ctx.send_msgs(message)
elif cmd == "LocationInfo": elif cmd == "LocationInfo":
for l in args["locations"]: for l in args["locations"]:
locationid = l.location locationid = l.location
@ -436,9 +435,9 @@ async def game_watcher(ctx: UndertaleContext):
for l in lines: for l in lines:
if ctx.server_locations.__contains__(int(l)+12000): if ctx.server_locations.__contains__(int(l)+12000):
sending = sending + [int(l.rstrip('\n'))+12000] sending = sending + [int(l.rstrip('\n'))+12000]
finally:
await ctx.send_msgs([{"cmd": "LocationScouts", "locations": sending, await ctx.send_msgs([{"cmd": "LocationScouts", "locations": sending,
"create_as_hint": int(2)}]) "create_as_hint": int(2)}])
finally:
os.remove(root+"/"+file) os.remove(root+"/"+file)
if "check.spot" in file: if "check.spot" in file:
sending = [] sending = []
@ -447,10 +446,8 @@ async def game_watcher(ctx: UndertaleContext):
lines = f.readlines() lines = f.readlines()
for l in lines: for l in lines:
sending = sending+[(int(l.rstrip('\n')))+12000] sending = sending+[(int(l.rstrip('\n')))+12000]
message = [{"cmd": "LocationChecks", "locations": sending}]
await ctx.send_msgs(message)
finally: finally:
pass await ctx.send_msgs([{"cmd": "LocationChecks", "locations": sending}])
if "victory" in file and str(ctx.route) in file: if "victory" in file and str(ctx.route) in file:
victory = True victory = True
if ".playerspot" in file and "Online" not in ctx.tags: if ".playerspot" in file and "Online" not in ctx.tags:

View File

@ -88,10 +88,10 @@ item_table = {
"ATK Up": ItemData(77065, ItemClassification.useful), "ATK Up": ItemData(77065, ItemClassification.useful),
"DEF Up": ItemData(77066, ItemClassification.useful), "DEF Up": ItemData(77066, ItemClassification.useful),
"HP Up": ItemData(77067, ItemClassification.useful), "HP Up": ItemData(77067, ItemClassification.useful),
"FIGHT": ItemData(77077, ItemClassification.progression), "FIGHT": ItemData(77077, ItemClassification.useful),
"ACT": ItemData(77078, ItemClassification.progression), "ACT": ItemData(77078, ItemClassification.useful),
"ITEM": ItemData(77079, ItemClassification.progression), "ITEM": ItemData(77079, ItemClassification.useful),
"MERCY": ItemData(77080, ItemClassification.progression), "MERCY": ItemData(77080, ItemClassification.useful),
"Ruins Key": ItemData(77081, ItemClassification.progression), "Ruins Key": ItemData(77081, ItemClassification.progression),
"Snowdin Key": ItemData(77082, ItemClassification.progression), "Snowdin Key": ItemData(77082, ItemClassification.progression),
"Waterfall Key": ItemData(77083, ItemClassification.progression), "Waterfall Key": ItemData(77083, ItemClassification.progression),

View File

@ -77,7 +77,6 @@ advancement_table = {
"True Lab Plot": AdvData(79063, "Hotland"), "True Lab Plot": AdvData(79063, "Hotland"),
"Left New Home Key": AdvData(79064, "New Home"), "Left New Home Key": AdvData(79064, "New Home"),
"Right New Home Key": AdvData(79065, "New Home"), "Right New Home Key": AdvData(79065, "New Home"),
"Starting Key": AdvData(79067, "Hub"),
"LOVE 2": AdvData(79902, "???"), "LOVE 2": AdvData(79902, "???"),
"LOVE 3": AdvData(79903, "???"), "LOVE 3": AdvData(79903, "???"),
"LOVE 4": AdvData(79904, "???"), "LOVE 4": AdvData(79904, "???"),

View File

@ -12,6 +12,17 @@ class RouteRequired(Choice):
default = 0 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): class IncludeTemy(Toggle):
"""Adds Temmy Armor to the item pool.""" """Adds Temmy Armor to the item pool."""
display_name = "Include Temy Armor" display_name = "Include Temy Armor"
@ -77,6 +88,7 @@ class RandoBattleOptions(Toggle):
undertale_options: typing.Dict[str, type(Option)] = { undertale_options: typing.Dict[str, type(Option)] = {
"route_required": RouteRequired, "route_required": RouteRequired,
"starting_area": StartingArea,
"key_hunt": KeyHunt, "key_hunt": KeyHunt,
"key_pieces": KeyPieces, "key_pieces": KeyPieces,
"rando_love": RandomizeLove, "rando_love": RandomizeLove,

View File

@ -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("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("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)) 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), set_rule(multiworld.get_entrance("Core Exit", player),
lambda state: _undertale_has_plot(state, player, "Mettaton Plush")) lambda state: _undertale_has_plot(state, player, "Mettaton Plush"))
set_rule(multiworld.get_entrance("New Home Exit", player), 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]: if multiworld.rando_stats[player]:
set_rule(multiworld.get_location(("ATK "+str(maxlv)), player), lambda state: False) set_rule(multiworld.get_location(("ATK "+str(maxlv)), player), lambda state: False)
set_rule(multiworld.get_location(("HP "+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) set_rule(multiworld.get_location(("DEF "+str(maxlv)), player), lambda state: False)
maxlv = 1 maxlv = 1
while maxlv < 20: 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") lambda state: (state.can_reach("Old Home", "Region", player)), combine="or")
add_rule(multiworld.get_location(("HP "+str(maxlv)), player), add_rule(multiworld.get_location(("HP "+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")
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), add_rule(multiworld.get_location(("DEF "+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": 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") lambda state: (state.can_reach("Snowdin Town", "Region", player)), combine="or")
add_rule(multiworld.get_location(("HP "+str(maxlv)), player), add_rule(multiworld.get_location(("HP "+str(maxlv)), player),
lambda state: (state.can_reach("Snowdin Town", "Region", player)), combine="or") 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), add_rule(multiworld.get_location(("DEF "+str(maxlv)), player),
lambda state: (state.can_reach("Snowdin Town", "Region", player)), combine="or") lambda state: (state.can_reach("Snowdin Town", "Region", player)), combine="or")
elif curarea == "Waterfall": elif curarea == "Waterfall":
@ -181,7 +166,7 @@ def set_rules(multiworld: MultiWorld, player: int):
lambda state: (state.can_reach("Waterfall", "Region", player)), combine="or") lambda state: (state.can_reach("Waterfall", "Region", player)), combine="or")
add_rule(multiworld.get_location(("HP "+str(maxlv)), player), add_rule(multiworld.get_location(("HP "+str(maxlv)), player),
lambda state: (state.can_reach("Waterfall", "Region", player)), combine="or") 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), add_rule(multiworld.get_location(("DEF "+str(maxlv)), player),
lambda state: (state.can_reach("Waterfall", "Region", player)), combine="or") lambda state: (state.can_reach("Waterfall", "Region", player)), combine="or")
elif curarea == "News Show": 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") lambda state: (state.can_reach("News Show", "Region", player)), combine="or")
add_rule(multiworld.get_location(("HP "+str(maxlv)), player), add_rule(multiworld.get_location(("HP "+str(maxlv)), player),
lambda state: (state.can_reach("News Show", "Region", player)), combine="or") 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), add_rule(multiworld.get_location(("DEF "+str(maxlv)), player),
lambda state: (state.can_reach("News Show", "Region", player)), combine="or") lambda state: (state.can_reach("News Show", "Region", player)), combine="or")
elif curarea == "Core": 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") lambda state: (state.can_reach("Core Exit", "Entrance", player)), combine="or")
add_rule(multiworld.get_location(("HP "+str(maxlv)), player), add_rule(multiworld.get_location(("HP "+str(maxlv)), player),
lambda state: (state.can_reach("Core Exit", "Entrance", player)), combine="or") 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), add_rule(multiworld.get_location(("DEF "+str(maxlv)), player),
lambda state: (state.can_reach("Core Exit", "Entrance", player)), combine="or") lambda state: (state.can_reach("Core Exit", "Entrance", player)), combine="or")
elif curarea == "Sans": elif curarea == "Sans":
@ -205,7 +190,7 @@ def set_rules(multiworld: MultiWorld, player: int):
lambda state: (state.can_reach("New Home Exit", "Entrance", player)), combine="or") lambda state: (state.can_reach("New Home Exit", "Entrance", player)), combine="or")
add_rule(multiworld.get_location(("HP "+str(maxlv)), player), add_rule(multiworld.get_location(("HP "+str(maxlv)), player),
lambda state: (state.can_reach("New Home Exit", "Entrance", player)), combine="or") 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), add_rule(multiworld.get_location(("DEF "+str(maxlv)), player),
lambda state: (state.can_reach("New Home Exit", "Entrance", player)), combine="or") lambda state: (state.can_reach("New Home Exit", "Entrance", player)), combine="or")
if multiworld.rando_love[player]: if multiworld.rando_love[player]:
@ -247,46 +232,8 @@ def set_rules(multiworld: MultiWorld, player: int):
curarea = "Sans" curarea = "Sans"
maxlv = 1 maxlv = 1
exp = 99999 exp = 99999
set_rule(multiworld.get_entrance("??? Exit", player), lambda state: state.has("FIGHT", player))
set_rule(multiworld.get_location("Snowman", player), set_rule(multiworld.get_location("Snowman", player),
lambda state: state.can_reach("Snowdin Town", "Region", 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), set_rule(multiworld.get_location("Mettaton Plot", player),
lambda state: state.can_reach("Core Exit", "Entrance", player)) lambda state: state.can_reach("Core Exit", "Entrance", player))
set_rule(multiworld.get_location("Bunny 1", 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 # Sets rules on completion condition
def set_completion_rules(multiworld: MultiWorld, player: int): 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): if _undertale_is_route(multiworld.state, player, 1):
completion_requirements = lambda state: state.can_reach("True Lab", "Region", player) completion_requirements = lambda state: state.can_reach("True Lab", "Region", player)

View File

@ -52,7 +52,7 @@ class UndertaleWorld(World):
item_name_to_id = {name: data.code for name, data in item_table.items()} 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()} 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): def _get_undertale_data(self):
return { return {
@ -63,6 +63,7 @@ class UndertaleWorld(World):
"client_version": self.required_client_version, "client_version": self.required_client_version,
"race": self.multiworld.is_race, "race": self.multiworld.is_race,
"route": self.multiworld.route_required[self.player].current_key, "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), "temy_armor_include": bool(self.multiworld.temy_include[self.player].value),
"only_flakes": bool(self.multiworld.only_flakes[self.player].value), "only_flakes": bool(self.multiworld.only_flakes[self.player].value),
"no_equips": bool(self.multiworld.no_equips[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 item == "Heart Locket" else item for item in itempool]
if self.multiworld.only_flakes[self.player]: if self.multiworld.only_flakes[self.player]:
itempool = [item for item in itempool if item not in non_key_items] 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 # Choose locations to automatically exclude based on settings
exclusion_pool = set() exclusion_pool = set()
exclusion_pool.update(exclusion_table[self.multiworld.route_required[self.player].current_key]) exclusion_pool.update(exclusion_table[self.multiworld.route_required[self.player].current_key])