Bug Squashing
This commit is contained in:
parent
70e3c47120
commit
199b778d2b
|
@ -0,0 +1 @@
|
|||
/Resources
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,377 @@
|
|||
"""
|
||||
Logic Extractor designed for "Randomizer 4".
|
||||
Place a Randomizer 4 compatible "Resources" folder next to this script, then run the script, to create AP data.
|
||||
"""
|
||||
import os
|
||||
import json
|
||||
import typing
|
||||
import ast
|
||||
|
||||
import jinja2
|
||||
|
||||
try:
|
||||
from ast import unparse
|
||||
except ImportError:
|
||||
# Py 3.8 and earlier compatibility module
|
||||
from astunparse import unparse
|
||||
|
||||
from Utils import get_text_between
|
||||
|
||||
|
||||
def put_digits_at_end(text: str) -> str:
|
||||
for x in range(len(text)):
|
||||
if text[0].isdigit():
|
||||
text = text[1:] + text[0]
|
||||
else:
|
||||
break
|
||||
return text
|
||||
|
||||
|
||||
def hk_loads(file: str) -> typing.Any:
|
||||
with open(file) as f:
|
||||
data = f.read()
|
||||
new_data = []
|
||||
for row in data.split("\n"):
|
||||
if not row.strip().startswith(r"//"):
|
||||
new_data.append(row)
|
||||
return json.loads("\n".join(new_data))
|
||||
|
||||
|
||||
def hk_convert(text: str) -> str:
|
||||
parts = text.replace("(", "( ").replace(")", " )").replace(">", " > ").replace("=", "==").split()
|
||||
new_parts = []
|
||||
for part in parts:
|
||||
part = put_digits_at_end(part)
|
||||
|
||||
if part in items or part in effect_names or part in event_names or part in connectors:
|
||||
new_parts.append(f"\"{part}\"")
|
||||
else:
|
||||
new_parts.append(part)
|
||||
text = " ".join(new_parts)
|
||||
result = ""
|
||||
parts = text.split("$StartLocation[")
|
||||
for i, part in enumerate(parts[:-1]):
|
||||
result += part + "StartLocation[\""
|
||||
parts[i+1] = parts[i+1].replace("]", "\"]", 1)
|
||||
|
||||
text = result + parts[-1]
|
||||
|
||||
result = ""
|
||||
parts = text.split("COMBAT[")
|
||||
for i, part in enumerate(parts[:-1]):
|
||||
result += part + "COMBAT[\""
|
||||
parts[i+1] = parts[i+1].replace("]", "\"]", 1)
|
||||
|
||||
text = result + parts[-1]
|
||||
return text.replace("+", "and").replace("|", "or").replace("$", "").strip()
|
||||
|
||||
|
||||
class Absorber(ast.NodeTransformer):
|
||||
additional_truths = set()
|
||||
additional_falses = set()
|
||||
|
||||
def __init__(self, truth_values, false_values):
|
||||
self.truth_values = truth_values
|
||||
self.truth_values |= {"True", "None", "ANY", "ITEMRANDO"}
|
||||
self.false_values = false_values
|
||||
self.false_values |= {"False", "NONE", "RANDOMELEVATORS"}
|
||||
|
||||
super(Absorber, self).__init__()
|
||||
|
||||
def generic_visit(self, node: ast.AST) -> ast.AST:
|
||||
# Need to call super() in any case to visit child nodes of the current one.
|
||||
node = super().generic_visit(node)
|
||||
return node
|
||||
|
||||
def visit_BoolOp(self, node: ast.BoolOp) -> ast.AST:
|
||||
if type(node.op) == ast.And:
|
||||
if self.is_always_true(node.values[0]):
|
||||
return self.visit(node.values[1])
|
||||
if self.is_always_true(node.values[1]):
|
||||
return self.visit(node.values[0])
|
||||
if self.is_always_false(node.values[0]) or self.is_always_false(node.values[1]):
|
||||
return ast.Constant(False, ctx=ast.Load())
|
||||
elif type(node.op) == ast.Or:
|
||||
if self.is_always_true(node.values[0]) or self.is_always_true(node.values[1]):
|
||||
return ast.Constant(True, ctx=ast.Load())
|
||||
if self.is_always_false(node.values[0]):
|
||||
return self.visit(node.values[1])
|
||||
if self.is_always_false(node.values[1]):
|
||||
return self.visit(node.values[0])
|
||||
return self.generic_visit(node)
|
||||
|
||||
def visit_Name(self, node: ast.Name) -> ast.AST:
|
||||
if node.id in self.truth_values:
|
||||
return ast.Constant(True, ctx=node.ctx)
|
||||
if node.id in self.false_values:
|
||||
return ast.Constant(False, ctx=node.ctx)
|
||||
if node.id in logic_options:
|
||||
return ast.Call(
|
||||
func=ast.Attribute(value=ast.Name(id='state', ctx=ast.Load()), attr='_kh_option', ctx=ast.Load()),
|
||||
args=[ast.Name(id="player", ctx=ast.Load()), ast.Constant(value=logic_options[node.id])], keywords=[])
|
||||
if node.id in macros:
|
||||
return macros[node.id].body
|
||||
if node.id in region_names:
|
||||
raise Exception(f"Should be event {node.id}")
|
||||
# You'd think this means reach Scene/Region of that name, but is actually waypoint/event
|
||||
# if node.id in region_names:
|
||||
# return ast.Call(
|
||||
# func=ast.Attribute(value=ast.Name(id='state', ctx=ast.Load()), attr='can_reach', ctx=ast.Load()),
|
||||
# args=[ast.Constant(value=node.id),
|
||||
# ast.Constant(value="Region"),
|
||||
# ast.Name(id="player", ctx=ast.Load())],
|
||||
# keywords=[])
|
||||
return self.generic_visit(node)
|
||||
|
||||
def visit_Constant(self, node: ast.Constant) -> ast.AST:
|
||||
if type(node.value) == str:
|
||||
logic_items.add(node.value)
|
||||
return ast.Call(
|
||||
func=ast.Attribute(value=ast.Name(id='state', ctx=ast.Load()), attr='count', ctx=ast.Load()),
|
||||
args=[ast.Constant(value=node.value), ast.Name(id="player", ctx=ast.Load())], keywords=[])
|
||||
|
||||
return node
|
||||
|
||||
def visit_Subscript(self, node: ast.Subscript) -> ast.AST:
|
||||
if node.value.id == "NotchCost":
|
||||
notches = [ast.Constant(value=notch.value - 1) for notch in node.slice.elts] # apparently 1-indexed
|
||||
return ast.Call(
|
||||
func=ast.Attribute(value=ast.Name(id='state', ctx=ast.Load()), attr='_hk_notches', ctx=ast.Load()),
|
||||
args=[ast.Name(id="player", ctx=ast.Load())] + notches, keywords=[])
|
||||
elif node.value.id == "StartLocation":
|
||||
node.slice.value = node.slice.value.replace(" ", "_").lower()
|
||||
if node.slice.value in removed_starts:
|
||||
return ast.Constant(False, ctx=node.ctx)
|
||||
return ast.Call(
|
||||
func=ast.Attribute(value=ast.Name(id='state', ctx=ast.Load()), attr='_kh_start', ctx=ast.Load()),
|
||||
args=[ast.Name(id="player", ctx=ast.Load()), node.slice], keywords=[])
|
||||
elif node.value.id == "COMBAT":
|
||||
return macros[unparse(node)].body
|
||||
else:
|
||||
name = unparse(node)
|
||||
if name in self.additional_truths:
|
||||
return ast.Constant(True, ctx=ast.Load())
|
||||
elif name in self.additional_falses:
|
||||
return ast.Constant(False, ctx=ast.Load())
|
||||
elif name in macros:
|
||||
# macro such as "COMBAT[White_Palace_Arenas]"
|
||||
return macros[name].body
|
||||
else:
|
||||
# assume Entrance
|
||||
entrance = unparse(node)
|
||||
assert entrance in connectors, entrance
|
||||
return ast.Call(
|
||||
func=ast.Attribute(value=ast.Name(id='state', ctx=ast.Load()), attr='can_reach', ctx=ast.Load()),
|
||||
args=[ast.Constant(value=entrance),
|
||||
ast.Constant(value="Entrance"),
|
||||
ast.Name(id="player", ctx=ast.Load())],
|
||||
keywords=[])
|
||||
return node
|
||||
|
||||
def is_always_true(self, node):
|
||||
if isinstance(node, ast.Name) and (node.id in self.truth_values or node.id in self.additional_truths):
|
||||
return True
|
||||
if isinstance(node, ast.Subscript) and unparse(node) in self.additional_truths:
|
||||
return True
|
||||
|
||||
def is_always_false(self, node):
|
||||
if isinstance(node, ast.Name) and (node.id in self.false_values or node.id in self.additional_falses):
|
||||
return True
|
||||
if isinstance(node, ast.Subscript) and unparse(node) in self.additional_falses:
|
||||
return True
|
||||
|
||||
|
||||
def get_parser(truths: typing.Set[str] = frozenset(), falses: typing.Set[str] = frozenset()):
|
||||
return Absorber(truths, falses)
|
||||
|
||||
|
||||
def ast_parse(parser, rule_text, truths: typing.Set[str] = frozenset(), falses: typing.Set[str] = frozenset()):
|
||||
tree = ast.parse(hk_convert(rule_text), mode='eval')
|
||||
parser.additional_truths = truths
|
||||
parser.additional_falses = falses
|
||||
new_tree = parser.visit(tree)
|
||||
parser.additional_truths = set()
|
||||
parser.additional_truths = set()
|
||||
return new_tree
|
||||
|
||||
|
||||
world_folder = os.path.dirname(__file__)
|
||||
|
||||
resources_source = os.path.join(world_folder, "Resources")
|
||||
data_folder = os.path.join(resources_source, "Data")
|
||||
logic_folder = os.path.join(resources_source, "Logic")
|
||||
logic_options: typing.Dict[str, str] = hk_loads(os.path.join(data_folder, "logic_settings.json"))
|
||||
for logic_key, logic_value in logic_options.items():
|
||||
logic_options[logic_key] = logic_value.split(".", 1)[-1]
|
||||
del (logic_options["RANDOMELEVATORS"])
|
||||
extra_pool_options: typing.List[typing.Dict[str, typing.Any]] = hk_loads(os.path.join(data_folder, "pools.json"))
|
||||
pool_options: typing.Dict[str, typing.Tuple[typing.List[str], typing.List[str]]] = {}
|
||||
for option in extra_pool_options:
|
||||
if option["Path"] != "False":
|
||||
items: typing.List[str] = []
|
||||
locations: typing.List[str] = []
|
||||
for pairing in option["Vanilla"]:
|
||||
items.append(pairing["item"])
|
||||
location_name = pairing["location"]
|
||||
if any(cost_entry["term"] == "CHARMS" for cost_entry in pairing.get("costs", [])):
|
||||
location_name += "_(Requires_Charms)"
|
||||
locations.append(location_name)
|
||||
if option["Path"]:
|
||||
# basename carries over from prior entry if no Path given
|
||||
basename = option["Path"].split(".", 1)[-1]
|
||||
if not basename.startswith("Randomize"):
|
||||
basename = "Randomize" + basename
|
||||
assert len(items) == len(locations)
|
||||
if items: # skip empty pools
|
||||
if basename in pool_options:
|
||||
pool_options[basename] = pool_options[basename][0]+items, pool_options[basename][1]+locations
|
||||
else:
|
||||
pool_options[basename] = items, locations
|
||||
del extra_pool_options
|
||||
|
||||
# items
|
||||
items: typing.Dict[str, typing.Dict] = hk_loads(os.path.join(data_folder, "items.json"))
|
||||
logic_items: typing.Set[str] = set()
|
||||
for item_name in sorted(items):
|
||||
item = items[item_name]
|
||||
items[item_name] = item["Pool"]
|
||||
items: typing.Dict[str, str]
|
||||
|
||||
extra_item_data: typing.List[typing.Dict[str, typing.Any]] = hk_loads(os.path.join(logic_folder, "items.json"))
|
||||
item_effects: typing.Dict[str, typing.Dict[str, int]] = {}
|
||||
effect_names: typing.Set[str] = set()
|
||||
for item_data in extra_item_data:
|
||||
if "FalseItem" in item_data:
|
||||
item_data = item_data["FalseItem"]
|
||||
effects = []
|
||||
if "Effect" in item_data:
|
||||
effects = [item_data["Effect"]]
|
||||
elif "Effects" in item_data:
|
||||
effects = item_data["Effects"]
|
||||
for effect in effects:
|
||||
effect_names.add(effect["Term"])
|
||||
effects = {effect["Term"]: effect["Value"] for effect in effects if
|
||||
effect["Term"] != item_data["Name"] and effect["Term"] != "GEO"}
|
||||
if effects:
|
||||
item_effects[item_data["Name"]] = effects
|
||||
|
||||
del extra_item_data
|
||||
|
||||
# locations
|
||||
original_locations: typing.Dict[str, typing.Dict[str, typing.Any]] = hk_loads(os.path.join(data_folder, "locations.json"))
|
||||
del(original_locations["Start"]) # Starting Inventory works different in AP
|
||||
|
||||
locations: typing.List[str] = []
|
||||
locations_in_regions: typing.Dict[str, typing.List[str]] = {}
|
||||
location_to_region_lookup: typing.Dict[str, str] = {}
|
||||
multi_locations: typing.Dict[str, typing.List[str]] = {}
|
||||
for location_name, location_data in original_locations.items():
|
||||
region_name = location_data["SceneName"]
|
||||
if location_data["FlexibleCount"]:
|
||||
location_names = [f"{location_name}_{count}" for count in range(1, 17)]
|
||||
multi_locations[location_name] = location_names
|
||||
else:
|
||||
location_names = [location_name]
|
||||
|
||||
location_to_region_lookup.update({name: region_name for name in location_names})
|
||||
locations_in_regions.setdefault(region_name, []).extend(location_names)
|
||||
locations.extend(location_names)
|
||||
del original_locations
|
||||
|
||||
# regions
|
||||
region_names: typing.Set[str] = set(hk_loads(os.path.join(data_folder, "rooms.json")))
|
||||
connectors_data: typing.Dict[str, typing.Dict[str, typing.Any]] = hk_loads(os.path.join(data_folder, "transitions.json"))
|
||||
connectors_logic: typing.List[typing.Dict[str, typing.Any]] = hk_loads(os.path.join(logic_folder, "transitions.json"))
|
||||
exits: typing.Dict[str, typing.List[str]] = {}
|
||||
connectors: typing.Dict[str, str] = {}
|
||||
one_ways: typing.Set[str] = set()
|
||||
for connector_name, connector_data in connectors_data.items():
|
||||
exits.setdefault(connector_data["SceneName"], []).append(connector_name)
|
||||
connectors[connector_name] = connector_data["VanillaTarget"]
|
||||
if connector_data["Sides"] != "Both":
|
||||
one_ways.add(connector_name)
|
||||
del connectors_data
|
||||
|
||||
# starts
|
||||
starts: typing.Dict[str, typing.Dict[str, typing.Any]] = hk_loads(os.path.join(data_folder, "starts.json"))
|
||||
|
||||
# only allow always valid starts for now
|
||||
removed_starts: typing.Set[str] = {name.replace(" ", "_").lower() for name, data in starts.items() if
|
||||
name != "King's Pass"}
|
||||
|
||||
starts: typing.Dict[str, str] = {
|
||||
name.replace(" ", "_").lower(): data["sceneName"] for name, data in starts.items() if name == "King's Pass"}
|
||||
|
||||
# logic
|
||||
falses = {"MAPAREARANDO", "FULLAREARANDO"}
|
||||
macros: typing.Dict[str, ast.AST] = {
|
||||
}
|
||||
parser = get_parser(set(), falses)
|
||||
extra_macros: typing.Dict[str, str] = hk_loads(os.path.join(logic_folder, "macros.json"))
|
||||
raw_location_rules: typing.List[typing.Dict[str, str]] = hk_loads(os.path.join(logic_folder, "locations.json"))
|
||||
events: typing.List[typing.Dict[str, typing.Any]] = hk_loads(os.path.join(logic_folder, "waypoints.json"))
|
||||
|
||||
event_names: typing.Set[str] = {event["name"] for event in events}
|
||||
|
||||
for macro_name, rule in extra_macros.items():
|
||||
if macro_name not in macros:
|
||||
macro_name = put_digits_at_end(macro_name)
|
||||
if macro_name in items or macro_name in effect_names:
|
||||
continue
|
||||
assert macro_name not in events
|
||||
rule = ast_parse(parser, rule)
|
||||
macros[macro_name] = rule
|
||||
if macro_name.startswith("COMBAT["):
|
||||
name = get_text_between(macro_name, "COMBAT[", "]")
|
||||
if not "'" in name:
|
||||
macros[f"COMBAT['{name}']"] = rule
|
||||
macros[f'COMBAT["{name}"]'] = rule
|
||||
|
||||
location_rules: typing.Dict[str, str] = {}
|
||||
for loc_obj in raw_location_rules:
|
||||
loc_name = loc_obj["name"]
|
||||
rule = loc_obj["logic"]
|
||||
if rule != "ANY":
|
||||
rule = ast_parse(parser, rule)
|
||||
location_rules[loc_name] = unparse(rule)
|
||||
location_rules["Salubra_(Requires_Charms)"] = location_rules["Salubra"]
|
||||
|
||||
connectors_rules: typing.Dict[str, str] = {}
|
||||
for connector_obj in connectors_logic:
|
||||
name = connector_obj["Name"]
|
||||
rule = connector_obj["logic"]
|
||||
rule = ast_parse(parser, rule)
|
||||
rule = unparse(rule)
|
||||
if rule != "True":
|
||||
connectors_rules[name] = rule
|
||||
|
||||
event_rules: typing.Dict[str, str] = {}
|
||||
for event in events:
|
||||
rule = ast_parse(parser, event["logic"])
|
||||
rule = unparse(rule)
|
||||
if rule != "True":
|
||||
event_rules[event["name"]] = rule
|
||||
|
||||
|
||||
event_rules.update(connectors_rules)
|
||||
connectors_rules = {}
|
||||
|
||||
names = sorted({"logic_options", "starts", "pool_options", "locations", "multi_locations", "location_to_region_lookup",
|
||||
"event_names", "item_effects", "items", "logic_items", "region_names",
|
||||
"exits", "connectors", "one_ways"})
|
||||
warning = "# This module is written by Extractor.py, do not edit manually!.\n\n"
|
||||
with open(os.path.join(os.path.dirname(__file__), "ExtractedData.py"), "wt") as py:
|
||||
py.write(warning)
|
||||
for name in names:
|
||||
py.write(f"{name} = {globals()[name]}\n")
|
||||
|
||||
|
||||
template_env: jinja2.Environment = \
|
||||
jinja2.Environment(loader=jinja2.FileSystemLoader([os.path.join(os.path.dirname(__file__), "templates")]))
|
||||
rules_template = template_env.get_template("RulesTemplate.pyt")
|
||||
rules = rules_template.render(location_rules=location_rules, one_ways=one_ways, connectors_rules=connectors_rules,
|
||||
event_rules=event_rules)
|
||||
|
||||
with open("Rules.py", "wt") as py:
|
||||
py.write(warning)
|
||||
py.write(rules)
|
|
@ -1,397 +1,20 @@
|
|||
# generated by https://github.com/Berserker66/HollowKnight.RandomizerMod/blob/master/extract_data.py
|
||||
# do not edit manually
|
||||
from typing import Dict, Set, NamedTuple
|
||||
from .ExtractedData import items, logic_items, item_effects
|
||||
|
||||
from .Types import HKItemData
|
||||
from typing import Dict, Set
|
||||
item_table = {}
|
||||
|
||||
item_table = \
|
||||
{ '150_Geo-Resting_Grounds_Chest': HKItemData(advancement=False, id=16777336, type='Geo'),
|
||||
'160_Geo-Weavers_Den_Chest': HKItemData(advancement=False, id=16777338, type='Geo'),
|
||||
'1_Geo': HKItemData(advancement=False, id=16777339, type='Fake'),
|
||||
'200_Geo-False_Knight_Chest': HKItemData(advancement=False, id=16777331, type='Geo'),
|
||||
'380_Geo-Soul_Master_Chest': HKItemData(advancement=False, id=16777332, type='Geo'),
|
||||
'620_Geo-Mantis_Lords_Chest': HKItemData(advancement=False, id=16777335, type='Geo'),
|
||||
'655_Geo-Watcher_Knights_Chest': HKItemData(advancement=False, id=16777333, type='Geo'),
|
||||
'80_Geo-Crystal_Peak_Chest': HKItemData(advancement=False, id=16777337, type='Geo'),
|
||||
'85_Geo-Greenpath_Chest': HKItemData(advancement=False, id=16777334, type='Geo'),
|
||||
'Abyss': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Abyss_Shriek': HKItemData(advancement=True, id=16777236, type='Skill'),
|
||||
'Ancestral_Mound': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Ancient_Basin_Map': HKItemData(advancement=False, id=16777482, type='Map'),
|
||||
'Arcane_Egg-Birthplace': HKItemData(advancement=False, id=16777402, type='Relic'),
|
||||
'Arcane_Egg-Lifeblood_Core': HKItemData(advancement=False, id=16777400, type='Relic'),
|
||||
'Arcane_Egg-Seer': HKItemData(advancement=False, id=16777399, type='Relic'),
|
||||
'Arcane_Egg-Shade_Cloak': HKItemData(advancement=False, id=16777401, type='Relic'),
|
||||
'Awoken_Dream_Nail': HKItemData(advancement=True, id=16777230, type='Skill'),
|
||||
'Baldur_Shell': HKItemData(advancement=False, id=16777245, type='Charm'),
|
||||
"Beast's_Den": HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Blue_Lake': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Boss_Essence-Elder_Hu': HKItemData(advancement=True, id=16777418, type='Essence_Boss'),
|
||||
'Boss_Essence-Failed_Champion': HKItemData(advancement=True, id=16777425, type='Essence_Boss'),
|
||||
'Boss_Essence-Galien': HKItemData(advancement=True, id=16777423, type='Essence_Boss'),
|
||||
'Boss_Essence-Gorb': HKItemData(advancement=True, id=16777420, type='Essence_Boss'),
|
||||
'Boss_Essence-Grey_Prince_Zote': HKItemData(advancement=True, id=16777429, type='Essence_Boss'),
|
||||
'Boss_Essence-Lost_Kin': HKItemData(advancement=True, id=16777427, type='Essence_Boss'),
|
||||
'Boss_Essence-Markoth': HKItemData(advancement=True, id=16777424, type='Essence_Boss'),
|
||||
'Boss_Essence-Marmu': HKItemData(advancement=True, id=16777421, type='Essence_Boss'),
|
||||
'Boss_Essence-No_Eyes': HKItemData(advancement=True, id=16777422, type='Essence_Boss'),
|
||||
'Boss_Essence-Soul_Tyrant': HKItemData(advancement=True, id=16777426, type='Essence_Boss'),
|
||||
'Boss_Essence-White_Defender': HKItemData(advancement=True, id=16777428, type='Essence_Boss'),
|
||||
'Boss_Essence-Xero': HKItemData(advancement=True, id=16777419, type='Essence_Boss'),
|
||||
'Bottom_Left_Fungal_Wastes': HKItemData(advancement=True, id=0, type='Event'),
|
||||
"Bottom_Left_Queen's_Gardens": HKItemData(advancement=True, id=0, type='Event'),
|
||||
"Bottom_Right_Queen's_Gardens": HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Can_Stag': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Cast_Off_Shell': HKItemData(advancement=True, id=0, type='Event'),
|
||||
"Center_Right_Kingdom's_Edge": HKItemData(advancement=True, id=0, type='Event'),
|
||||
"Central_Kingdom's_Edge": HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Central_Left_Waterways': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Charm_Notch-Colosseum': HKItemData(advancement=False, id=16777323, type='Notch'),
|
||||
'Charm_Notch-Fog_Canyon': HKItemData(advancement=False, id=16777322, type='Notch'),
|
||||
'Charm_Notch-Grimm': HKItemData(advancement=False, id=16777324, type='Notch'),
|
||||
'Charm_Notch-Shrumal_Ogres': HKItemData(advancement=False, id=16777321, type='Notch'),
|
||||
'City_Crest': HKItemData(advancement=True, id=16777283, type='Key'),
|
||||
'City_Storerooms_Stag': HKItemData(advancement=True, id=16777495, type='Stag'),
|
||||
'City_of_Tears_Map': HKItemData(advancement=False, id=16777484, type='Map'),
|
||||
"Collector's_Map": HKItemData(advancement=False, id=16777295, type='Key'),
|
||||
'Colosseum': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Crossroads': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Crossroads_Map': HKItemData(advancement=False, id=16777476, type='Map'),
|
||||
'Crossroads_Stag': HKItemData(advancement=True, id=16777491, type='Stag'),
|
||||
'Crystal_Heart': HKItemData(advancement=True, id=16777224, type='Skill'),
|
||||
'Crystal_Peak': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Crystal_Peak_Map': HKItemData(advancement=False, id=16777487, type='Map'),
|
||||
'Crystallized_Mound': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Cyclone_Slash': HKItemData(advancement=True, id=16777237, type='Skill'),
|
||||
'Dark_Deepnest': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Dash_Slash': HKItemData(advancement=True, id=16777238, type='Skill'),
|
||||
'Dashmaster': HKItemData(advancement=True, id=16777271, type='Charm'),
|
||||
'Deep_Focus': HKItemData(advancement=False, id=16777274, type='Charm'),
|
||||
'Deepnest': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Deepnest_Map-Right_[Gives_Quill]': HKItemData(advancement=False, id=16777481, type='Map'),
|
||||
'Deepnest_Map-Upper': HKItemData(advancement=False, id=16777480, type='Map'),
|
||||
"Defender's_Crest": HKItemData(advancement=False, id=16777250, type='Charm'),
|
||||
'Descending_Dark': HKItemData(advancement=True, id=16777234, type='Skill'),
|
||||
'Desolate_Dive': HKItemData(advancement=True, id=16777233, type='Skill'),
|
||||
'Dirtmouth': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Dirtmouth_Stag': HKItemData(advancement=True, id=16777490, type='Stag'),
|
||||
'Distant_Village': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Distant_Village_Stag': HKItemData(advancement=True, id=16777498, type='Stag'),
|
||||
'Dream_Gate': HKItemData(advancement=True, id=16777229, type='Skill'),
|
||||
'Dream_Nail': HKItemData(advancement=True, id=16777228, type='Skill'),
|
||||
'Dream_Wielder': HKItemData(advancement=False, id=16777270, type='Charm'),
|
||||
'Dreamer': HKItemData(advancement=True, id=16777221, type='Fake'),
|
||||
'Dreamshield': HKItemData(advancement=False, id=16777280, type='Charm'),
|
||||
'Elegant_Key': HKItemData(advancement=True, id=16777291, type='Key'),
|
||||
'Emilitia': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Equipped': HKItemData(advancement=False, id=16777521, type='Fake'),
|
||||
'Failed_Tramway': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Far_Left_Basin': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Far_Left_Waterways': HKItemData(advancement=True, id=0, type='Event'),
|
||||
"Far_Queen's_Gardens": HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Far_Right_Deepnest': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Flukenest': HKItemData(advancement=False, id=16777251, type='Charm'),
|
||||
'Focus': HKItemData(advancement=True, id=16777240, type='Cursed'),
|
||||
'Fog_Canyon_Map': HKItemData(advancement=False, id=16777478, type='Map'),
|
||||
'Fragile_Greed': HKItemData(advancement=False, id=16777264, type='Charm'),
|
||||
'Fragile_Heart': HKItemData(advancement=False, id=16777263, type='Charm'),
|
||||
'Fragile_Strength': HKItemData(advancement=False, id=16777265, type='Charm'),
|
||||
'Fungal_Core': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Fungal_Wastes': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Fungal_Wastes_Map': HKItemData(advancement=False, id=16777479, type='Map'),
|
||||
'Fury_of_the_Fallen': HKItemData(advancement=False, id=16777246, type='Charm'),
|
||||
'Gathering_Swarm': HKItemData(advancement=False, id=16777241, type='Charm'),
|
||||
'Glowing_Womb': HKItemData(advancement=True, id=16777262, type='Charm'),
|
||||
'Godtuner': HKItemData(advancement=False, id=16777294, type='Key'),
|
||||
'Great_Slash': HKItemData(advancement=True, id=16777239, type='Skill'),
|
||||
'Greenpath': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Greenpath-QG': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Greenpath_Map': HKItemData(advancement=False, id=16777477, type='Map'),
|
||||
'Greenpath_Stag': HKItemData(advancement=True, id=16777492, type='Stag'),
|
||||
'Grimmchild': HKItemData(advancement=True, id=16777282, type='Charm'),
|
||||
'Grimmkin_Flame-Ancient_Basin': HKItemData(advancement=True, id=16777516, type='Flame'),
|
||||
'Grimmkin_Flame-Brumm': HKItemData(advancement=True, id=16777518, type='Flame'),
|
||||
'Grimmkin_Flame-City_Storerooms': HKItemData(advancement=True, id=16777509, type='Flame'),
|
||||
'Grimmkin_Flame-Crystal_Peak': HKItemData(advancement=True, id=16777511, type='Flame'),
|
||||
'Grimmkin_Flame-Fungal_Core': HKItemData(advancement=True, id=16777515, type='Flame'),
|
||||
'Grimmkin_Flame-Greenpath': HKItemData(advancement=True, id=16777510, type='Flame'),
|
||||
'Grimmkin_Flame-Hive': HKItemData(advancement=True, id=16777517, type='Flame'),
|
||||
"Grimmkin_Flame-King's_Pass": HKItemData(advancement=True, id=16777512, type='Flame'),
|
||||
"Grimmkin_Flame-Kingdom's_Edge": HKItemData(advancement=True, id=16777514, type='Flame'),
|
||||
'Grimmkin_Flame-Resting_Grounds': HKItemData(advancement=True, id=16777513, type='Flame'),
|
||||
'Grub-Basin_Requires_Dive': HKItemData(advancement=True, id=16777452, type='Grub'),
|
||||
'Grub-Basin_Requires_Wings': HKItemData(advancement=True, id=16777451, type='Grub'),
|
||||
"Grub-Beast's_Den": HKItemData(advancement=True, id=16777446, type='Grub'),
|
||||
'Grub-City_of_Tears_Guarded': HKItemData(advancement=True, id=16777459, type='Grub'),
|
||||
'Grub-City_of_Tears_Left': HKItemData(advancement=True, id=16777456, type='Grub'),
|
||||
'Grub-Collector_1': HKItemData(advancement=True, id=16777473, type='Grub'),
|
||||
'Grub-Collector_2': HKItemData(advancement=True, id=16777474, type='Grub'),
|
||||
'Grub-Collector_3': HKItemData(advancement=True, id=16777475, type='Grub'),
|
||||
'Grub-Crossroads_Acid': HKItemData(advancement=True, id=16777430, type='Grub'),
|
||||
'Grub-Crossroads_Center': HKItemData(advancement=True, id=16777431, type='Grub'),
|
||||
'Grub-Crossroads_Guarded': HKItemData(advancement=True, id=16777434, type='Grub'),
|
||||
'Grub-Crossroads_Spike': HKItemData(advancement=True, id=16777433, type='Grub'),
|
||||
'Grub-Crossroads_Stag': HKItemData(advancement=True, id=16777432, type='Grub'),
|
||||
'Grub-Crystal_Heart': HKItemData(advancement=True, id=16777467, type='Grub'),
|
||||
'Grub-Crystal_Peak_Below_Chest': HKItemData(advancement=True, id=16777462, type='Grub'),
|
||||
'Grub-Crystal_Peak_Crushers': HKItemData(advancement=True, id=16777466, type='Grub'),
|
||||
'Grub-Crystal_Peak_Mimic': HKItemData(advancement=True, id=16777465, type='Grub'),
|
||||
'Grub-Crystal_Peak_Spike': HKItemData(advancement=True, id=16777464, type='Grub'),
|
||||
'Grub-Crystallized_Mound': HKItemData(advancement=True, id=16777463, type='Grub'),
|
||||
'Grub-Dark_Deepnest': HKItemData(advancement=True, id=16777445, type='Grub'),
|
||||
'Grub-Deepnest_Mimic': HKItemData(advancement=True, id=16777442, type='Grub'),
|
||||
'Grub-Deepnest_Nosk': HKItemData(advancement=True, id=16777443, type='Grub'),
|
||||
'Grub-Deepnest_Spike': HKItemData(advancement=True, id=16777444, type='Grub'),
|
||||
'Grub-Fog_Canyon': HKItemData(advancement=True, id=16777439, type='Grub'),
|
||||
'Grub-Fungal_Bouncy': HKItemData(advancement=True, id=16777440, type='Grub'),
|
||||
'Grub-Fungal_Spore_Shroom': HKItemData(advancement=True, id=16777441, type='Grub'),
|
||||
'Grub-Greenpath_Cornifer': HKItemData(advancement=True, id=16777435, type='Grub'),
|
||||
'Grub-Greenpath_Journal': HKItemData(advancement=True, id=16777436, type='Grub'),
|
||||
'Grub-Greenpath_MMC': HKItemData(advancement=True, id=16777437, type='Grub'),
|
||||
'Grub-Greenpath_Stag': HKItemData(advancement=True, id=16777438, type='Grub'),
|
||||
'Grub-Hallownest_Crown': HKItemData(advancement=True, id=16777468, type='Grub'),
|
||||
'Grub-Hive_External': HKItemData(advancement=True, id=16777449, type='Grub'),
|
||||
'Grub-Hive_Internal': HKItemData(advancement=True, id=16777450, type='Grub'),
|
||||
'Grub-Howling_Cliffs': HKItemData(advancement=True, id=16777469, type='Grub'),
|
||||
"Grub-King's_Station": HKItemData(advancement=True, id=16777460, type='Grub'),
|
||||
"Grub-Kingdom's_Edge_Camp": HKItemData(advancement=True, id=16777448, type='Grub'),
|
||||
"Grub-Kingdom's_Edge_Oro": HKItemData(advancement=True, id=16777447, type='Grub'),
|
||||
"Grub-Queen's_Gardens_Marmu": HKItemData(advancement=True, id=16777471, type='Grub'),
|
||||
"Grub-Queen's_Gardens_Stag": HKItemData(advancement=True, id=16777470, type='Grub'),
|
||||
"Grub-Queen's_Gardens_Top": HKItemData(advancement=True, id=16777472, type='Grub'),
|
||||
'Grub-Resting_Grounds': HKItemData(advancement=True, id=16777461, type='Grub'),
|
||||
'Grub-Soul_Sanctum': HKItemData(advancement=True, id=16777457, type='Grub'),
|
||||
"Grub-Watcher's_Spire": HKItemData(advancement=True, id=16777458, type='Grub'),
|
||||
'Grub-Waterways_East': HKItemData(advancement=True, id=16777454, type='Grub'),
|
||||
'Grub-Waterways_Main': HKItemData(advancement=True, id=16777453, type='Grub'),
|
||||
'Grub-Waterways_Requires_Tram': HKItemData(advancement=True, id=16777455, type='Grub'),
|
||||
"Grubberfly's_Elegy": HKItemData(advancement=True, id=16777275, type='Charm'),
|
||||
'Grubfather': HKItemData(advancement=False, id=16777519, type='Fake'),
|
||||
'Grubsong': HKItemData(advancement=False, id=16777243, type='Charm'),
|
||||
"Hallownest's_Crown": HKItemData(advancement=True, id=0, type='Event'),
|
||||
"Hallownest_Seal-Beast's_Den": HKItemData(advancement=False, id=16777389, type='Relic'),
|
||||
'Hallownest_Seal-City_Rafters': HKItemData(advancement=False, id=16777385, type='Relic'),
|
||||
'Hallownest_Seal-Crossroads_Well': HKItemData(advancement=False, id=16777374, type='Relic'),
|
||||
'Hallownest_Seal-Deepnest_By_Mantis_Lords': HKItemData(advancement=False, id=16777388, type='Relic'),
|
||||
'Hallownest_Seal-Fog_Canyon_East': HKItemData(advancement=False, id=16777378, type='Relic'),
|
||||
'Hallownest_Seal-Fog_Canyon_West': HKItemData(advancement=False, id=16777377, type='Relic'),
|
||||
'Hallownest_Seal-Fungal_Wastes_Sporgs': HKItemData(advancement=False, id=16777380, type='Relic'),
|
||||
'Hallownest_Seal-Greenpath': HKItemData(advancement=False, id=16777376, type='Relic'),
|
||||
'Hallownest_Seal-Grubs': HKItemData(advancement=False, id=16777375, type='Relic'),
|
||||
"Hallownest_Seal-King's_Station": HKItemData(advancement=False, id=16777384, type='Relic'),
|
||||
'Hallownest_Seal-Mantis_Lords': HKItemData(advancement=False, id=16777381, type='Relic'),
|
||||
"Hallownest_Seal-Queen's_Gardens": HKItemData(advancement=False, id=16777390, type='Relic'),
|
||||
"Hallownest_Seal-Queen's_Station": HKItemData(advancement=False, id=16777379, type='Relic'),
|
||||
'Hallownest_Seal-Resting_Grounds_Catacombs': HKItemData(advancement=False, id=16777383, type='Relic'),
|
||||
'Hallownest_Seal-Seer': HKItemData(advancement=False, id=16777382, type='Relic'),
|
||||
'Hallownest_Seal-Soul_Sanctum': HKItemData(advancement=False, id=16777386, type='Relic'),
|
||||
'Hallownest_Seal-Watcher_Knight': HKItemData(advancement=False, id=16777387, type='Relic'),
|
||||
'Heavy_Blow': HKItemData(advancement=False, id=16777255, type='Charm'),
|
||||
'Herrah': HKItemData(advancement=True, id=16777219, type='Dreamer'),
|
||||
'Hidden_Station_Stag': HKItemData(advancement=True, id=16777499, type='Stag'),
|
||||
'Hive': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Hiveblood': HKItemData(advancement=False, id=16777269, type='Charm'),
|
||||
'Hollow Knight': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Howling_Cliffs': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Howling_Cliffs_Map': HKItemData(advancement=False, id=16777486, type='Map'),
|
||||
'Howling_Wraiths': HKItemData(advancement=True, id=16777235, type='Skill'),
|
||||
"Isma's_Grove": HKItemData(advancement=True, id=0, type='Event'),
|
||||
"Isma's_Tear": HKItemData(advancement=True, id=16777227, type='Skill'),
|
||||
"Joni's_Blessing": HKItemData(advancement=True, id=16777267, type='Charm'),
|
||||
'Junk_Pit': HKItemData(advancement=True, id=0, type='Event'),
|
||||
"King's_Brand": HKItemData(advancement=True, id=16777293, type='Key'),
|
||||
"King's_Idol-Cliffs": HKItemData(advancement=False, id=16777392, type='Relic'),
|
||||
"King's_Idol-Crystal_Peak": HKItemData(advancement=False, id=16777393, type='Relic'),
|
||||
"King's_Idol-Deepnest": HKItemData(advancement=False, id=16777398, type='Relic'),
|
||||
"King's_Idol-Dung_Defender": HKItemData(advancement=False, id=16777395, type='Relic'),
|
||||
"King's_Idol-Glade_of_Hope": HKItemData(advancement=False, id=16777394, type='Relic'),
|
||||
"King's_Idol-Great_Hopper": HKItemData(advancement=False, id=16777396, type='Relic'),
|
||||
"King's_Idol-Grubs": HKItemData(advancement=False, id=16777391, type='Relic'),
|
||||
"King's_Idol-Pale_Lurker": HKItemData(advancement=False, id=16777397, type='Relic'),
|
||||
"King's_Pass": HKItemData(advancement=True, id=0, type='Event'),
|
||||
"King's_Station_Stag": HKItemData(advancement=True, id=16777496, type='Stag'),
|
||||
'King_Fragment': HKItemData(advancement=True, id=16777277, type='Charm'),
|
||||
"Kingdom's_Edge_Map": HKItemData(advancement=False, id=16777483, type='Map'),
|
||||
'Lake_of_Unn': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Left_City': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Left_Elevator': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Left_Fog_Canyon': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Lifeblood_Cocoon-Ancestral_Mound': HKItemData(advancement=False, id=16777502, type='Cocoon'),
|
||||
'Lifeblood_Cocoon-Failed_Tramway': HKItemData(advancement=False, id=16777506, type='Cocoon'),
|
||||
'Lifeblood_Cocoon-Fog_Canyon_West': HKItemData(advancement=False, id=16777504, type='Cocoon'),
|
||||
'Lifeblood_Cocoon-Galien': HKItemData(advancement=False, id=16777507, type='Cocoon'),
|
||||
'Lifeblood_Cocoon-Greenpath': HKItemData(advancement=False, id=16777503, type='Cocoon'),
|
||||
"Lifeblood_Cocoon-King's_Pass": HKItemData(advancement=False, id=16777501, type='Cocoon'),
|
||||
"Lifeblood_Cocoon-Kingdom's_Edge": HKItemData(advancement=False, id=16777508, type='Cocoon'),
|
||||
'Lifeblood_Cocoon-Mantis_Village': HKItemData(advancement=False, id=16777505, type='Cocoon'),
|
||||
'Lifeblood_Core': HKItemData(advancement=True, id=16777249, type='Charm'),
|
||||
'Lifeblood_Heart': HKItemData(advancement=True, id=16777248, type='Charm'),
|
||||
'Longnail': HKItemData(advancement=False, id=16777258, type='Charm'),
|
||||
'Love_Key': HKItemData(advancement=True, id=16777292, type='Key'),
|
||||
'Lower_Basin': HKItemData(advancement=True, id=0, type='Event'),
|
||||
"Lower_King's_Station": HKItemData(advancement=True, id=0, type='Event'),
|
||||
"Lower_Kingdom's_Edge": HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Lower_Left_Waterways': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Lower_Resting_Grounds': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Lower_Tram': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Lumafly_Lantern': HKItemData(advancement=True, id=16777284, type='Key'),
|
||||
'Lurien': HKItemData(advancement=True, id=16777217, type='Dreamer'),
|
||||
'Mantis_Claw': HKItemData(advancement=True, id=16777223, type='Skill'),
|
||||
'Mantis_Outskirts': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Mantis_Village': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Mark_of_Pride': HKItemData(advancement=True, id=16777253, type='Charm'),
|
||||
'Mask_Shard-5_Grubs': HKItemData(advancement=False, id=16777301, type='Mask'),
|
||||
'Mask_Shard-Bretta': HKItemData(advancement=False, id=16777311, type='Mask'),
|
||||
'Mask_Shard-Brooding_Mawlek': HKItemData(advancement=False, id=16777302, type='Mask'),
|
||||
'Mask_Shard-Crossroads_Goam': HKItemData(advancement=False, id=16777303, type='Mask'),
|
||||
'Mask_Shard-Deepnest': HKItemData(advancement=False, id=16777306, type='Mask'),
|
||||
'Mask_Shard-Enraged_Guardian': HKItemData(advancement=False, id=16777308, type='Mask'),
|
||||
'Mask_Shard-Grey_Mourner': HKItemData(advancement=False, id=16777310, type='Mask'),
|
||||
'Mask_Shard-Hive': HKItemData(advancement=False, id=16777309, type='Mask'),
|
||||
"Mask_Shard-Queen's_Station": HKItemData(advancement=False, id=16777305, type='Mask'),
|
||||
'Mask_Shard-Seer': HKItemData(advancement=False, id=16777300, type='Mask'),
|
||||
'Mask_Shard-Sly1': HKItemData(advancement=False, id=16777296, type='Mask'),
|
||||
'Mask_Shard-Sly2': HKItemData(advancement=False, id=16777297, type='Mask'),
|
||||
'Mask_Shard-Sly3': HKItemData(advancement=False, id=16777298, type='Mask'),
|
||||
'Mask_Shard-Sly4': HKItemData(advancement=False, id=16777299, type='Mask'),
|
||||
'Mask_Shard-Stone_Sanctuary': HKItemData(advancement=False, id=16777304, type='Mask'),
|
||||
'Mask_Shard-Waterways': HKItemData(advancement=False, id=16777307, type='Mask'),
|
||||
'Mid_Basin': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Monarch_Wings': HKItemData(advancement=True, id=16777225, type='Skill'),
|
||||
'Monomon': HKItemData(advancement=True, id=16777218, type='Dreamer'),
|
||||
'Mothwing_Cloak': HKItemData(advancement=True, id=16777222, type='Skill'),
|
||||
"Nailmaster's_Glory": HKItemData(advancement=False, id=16777266, type='Charm'),
|
||||
'Oro_Bench': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Overgrown_Mound': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Palace_Grounds': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Pale_Lurker_Area': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Pale_Ore-Basin': HKItemData(advancement=False, id=16777325, type='Ore'),
|
||||
'Pale_Ore-Colosseum': HKItemData(advancement=False, id=16777330, type='Ore'),
|
||||
'Pale_Ore-Crystal_Peak': HKItemData(advancement=False, id=16777326, type='Ore'),
|
||||
'Pale_Ore-Grubs': HKItemData(advancement=False, id=16777329, type='Ore'),
|
||||
'Pale_Ore-Nosk': HKItemData(advancement=False, id=16777327, type='Ore'),
|
||||
'Pale_Ore-Seer': HKItemData(advancement=False, id=16777328, type='Ore'),
|
||||
'Placeholder': HKItemData(advancement=False, id=16777522, type='Fake'),
|
||||
'Pleasure_House': HKItemData(advancement=True, id=0, type='Event'),
|
||||
"Queen's_Gardens_Map": HKItemData(advancement=False, id=16777488, type='Map'),
|
||||
"Queen's_Gardens_Stag": HKItemData(advancement=True, id=16777494, type='Stag'),
|
||||
"Queen's_Station": HKItemData(advancement=True, id=0, type='Event'),
|
||||
"Queen's_Station_Stag": HKItemData(advancement=True, id=16777493, type='Stag'),
|
||||
'Queen_Fragment': HKItemData(advancement=True, id=16777276, type='Charm'),
|
||||
'Quick_Focus': HKItemData(advancement=False, id=16777247, type='Charm'),
|
||||
'Quick_Slash': HKItemData(advancement=False, id=16777272, type='Charm'),
|
||||
"Rancid_Egg-Beast's_Den": HKItemData(advancement=False, id=16777351, type='Egg'),
|
||||
'Rancid_Egg-Blue_Lake': HKItemData(advancement=False, id=16777345, type='Egg'),
|
||||
'Rancid_Egg-City_of_Tears_Left': HKItemData(advancement=False, id=16777349, type='Egg'),
|
||||
'Rancid_Egg-City_of_Tears_Pleasure_House': HKItemData(advancement=False, id=16777350, type='Egg'),
|
||||
'Rancid_Egg-Crystal_Peak_Dark_Room': HKItemData(advancement=False, id=16777347, type='Egg'),
|
||||
'Rancid_Egg-Crystal_Peak_Dive_Entrance': HKItemData(advancement=False, id=16777346, type='Egg'),
|
||||
'Rancid_Egg-Crystal_Peak_Tall_Room': HKItemData(advancement=False, id=16777348, type='Egg'),
|
||||
'Rancid_Egg-Dark_Deepnest': HKItemData(advancement=False, id=16777352, type='Egg'),
|
||||
'Rancid_Egg-Fungal_Core': HKItemData(advancement=False, id=16777343, type='Egg'),
|
||||
'Rancid_Egg-Grubs': HKItemData(advancement=False, id=16777341, type='Egg'),
|
||||
'Rancid_Egg-Near_Quick_Slash': HKItemData(advancement=False, id=16777354, type='Egg'),
|
||||
"Rancid_Egg-Queen's_Gardens": HKItemData(advancement=False, id=16777344, type='Egg'),
|
||||
'Rancid_Egg-Sheo': HKItemData(advancement=False, id=16777342, type='Egg'),
|
||||
'Rancid_Egg-Sly': HKItemData(advancement=False, id=16777340, type='Egg'),
|
||||
"Rancid_Egg-Upper_Kingdom's_Edge": HKItemData(advancement=False, id=16777355, type='Egg'),
|
||||
'Rancid_Egg-Waterways_East': HKItemData(advancement=False, id=16777356, type='Egg'),
|
||||
'Rancid_Egg-Waterways_Main': HKItemData(advancement=False, id=16777357, type='Egg'),
|
||||
'Rancid_Egg-Waterways_West_Bluggsac': HKItemData(advancement=False, id=16777358, type='Egg'),
|
||||
'Rancid_Egg-Waterways_West_Pickup': HKItemData(advancement=False, id=16777359, type='Egg'),
|
||||
"Rancid_Egg-Weaver's_Den": HKItemData(advancement=False, id=16777353, type='Egg'),
|
||||
'Resting_Grounds_Map': HKItemData(advancement=False, id=16777489, type='Map'),
|
||||
'Resting_Grounds_Stag': HKItemData(advancement=True, id=16777497, type='Stag'),
|
||||
'Right_City': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Right_Elevator': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Right_Fog_Canyon': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Right_Waterways': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Royal_Waterways_Map': HKItemData(advancement=False, id=16777485, type='Map'),
|
||||
'Seer': HKItemData(advancement=False, id=16777520, type='Fake'),
|
||||
'Shade_Cloak': HKItemData(advancement=True, id=16777226, type='Skill'),
|
||||
'Shade_Soul': HKItemData(advancement=True, id=16777232, type='Skill'),
|
||||
'Shaman_Stone': HKItemData(advancement=False, id=16777259, type='Charm'),
|
||||
'Shape_of_Unn': HKItemData(advancement=False, id=16777268, type='Charm'),
|
||||
'Sharp_Shadow': HKItemData(advancement=True, id=16777256, type='Charm'),
|
||||
"Shopkeeper's_Key": HKItemData(advancement=True, id=16777290, type='Key'),
|
||||
'Simple_Key-Basin': HKItemData(advancement=True, id=16777287, type='Key'),
|
||||
'Simple_Key-City': HKItemData(advancement=True, id=16777288, type='Key'),
|
||||
'Simple_Key-Lurker': HKItemData(advancement=True, id=16777289, type='Key'),
|
||||
'Simple_Key-Sly': HKItemData(advancement=True, id=16777286, type='Key'),
|
||||
'Soul_Catcher': HKItemData(advancement=False, id=16777260, type='Charm'),
|
||||
'Soul_Eater': HKItemData(advancement=False, id=16777261, type='Charm'),
|
||||
'Soul_Sanctum': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Spell_Twister': HKItemData(advancement=False, id=16777273, type='Charm'),
|
||||
'Spirits_Glade': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Spore_Shroom': HKItemData(advancement=True, id=16777257, type='Charm'),
|
||||
'Sprintmaster': HKItemData(advancement=True, id=16777279, type='Charm'),
|
||||
'Stag_Nest': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Stag_Nest_Stag': HKItemData(advancement=True, id=16777500, type='Stag'),
|
||||
'Stalwart_Shell': HKItemData(advancement=False, id=16777244, type='Charm'),
|
||||
'Steady_Body': HKItemData(advancement=False, id=16777254, type='Charm'),
|
||||
'Stone_Sanctuary': HKItemData(advancement=True, id=0, type='Event'),
|
||||
"Teacher's_Archives": HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Thorns_of_Agony': HKItemData(advancement=False, id=16777252, type='Charm'),
|
||||
"Top_Kingdom's_Edge": HKItemData(advancement=True, id=0, type='Event'),
|
||||
"Top_Left_Queen's_Gardens": HKItemData(advancement=True, id=0, type='Event'),
|
||||
"Top_Right_Queen's_Gardens": HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Tower_of_Love': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Tram_Pass': HKItemData(advancement=True, id=16777285, type='Key'),
|
||||
'Upper_Basin': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Upper_Crystal_Peak': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Upper_Deepnest': HKItemData(advancement=True, id=0, type='Event'),
|
||||
"Upper_King's_Station": HKItemData(advancement=True, id=0, type='Event'),
|
||||
"Upper_Kingdom's_Edge": HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Upper_Left_Waterways': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Upper_Resting_Grounds': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Upper_Tram': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Vengeful_Spirit': HKItemData(advancement=True, id=16777231, type='Skill'),
|
||||
'Vessel_Fragment-Basin': HKItemData(advancement=False, id=16777318, type='Vessel'),
|
||||
'Vessel_Fragment-City': HKItemData(advancement=False, id=16777316, type='Vessel'),
|
||||
'Vessel_Fragment-Crossroads': HKItemData(advancement=False, id=16777317, type='Vessel'),
|
||||
'Vessel_Fragment-Deepnest': HKItemData(advancement=False, id=16777319, type='Vessel'),
|
||||
'Vessel_Fragment-Greenpath': HKItemData(advancement=False, id=16777315, type='Vessel'),
|
||||
'Vessel_Fragment-Seer': HKItemData(advancement=False, id=16777314, type='Vessel'),
|
||||
'Vessel_Fragment-Sly1': HKItemData(advancement=False, id=16777312, type='Vessel'),
|
||||
'Vessel_Fragment-Sly2': HKItemData(advancement=False, id=16777313, type='Vessel'),
|
||||
'Vessel_Fragment-Stag_Nest': HKItemData(advancement=False, id=16777320, type='Vessel'),
|
||||
'Void_Heart': HKItemData(advancement=True, id=16777278, type='Charm'),
|
||||
"Wanderer's_Journal-Above_Mantis_Village": HKItemData(advancement=False, id=16777364, type='Relic'),
|
||||
"Wanderer's_Journal-Ancient_Basin": HKItemData(advancement=False, id=16777370, type='Relic'),
|
||||
"Wanderer's_Journal-City_Storerooms": HKItemData(advancement=False, id=16777369, type='Relic'),
|
||||
"Wanderer's_Journal-Cliffs": HKItemData(advancement=False, id=16777360, type='Relic'),
|
||||
"Wanderer's_Journal-Crystal_Peak_Crawlers": HKItemData(advancement=False, id=16777365, type='Relic'),
|
||||
"Wanderer's_Journal-Fungal_Wastes_Thorns_Gauntlet": HKItemData(advancement=False, id=16777363, type='Relic'),
|
||||
"Wanderer's_Journal-Greenpath_Lower": HKItemData(advancement=False, id=16777362, type='Relic'),
|
||||
"Wanderer's_Journal-Greenpath_Stag": HKItemData(advancement=False, id=16777361, type='Relic'),
|
||||
"Wanderer's_Journal-King's_Station": HKItemData(advancement=False, id=16777367, type='Relic'),
|
||||
"Wanderer's_Journal-Kingdom's_Edge_Camp": HKItemData(advancement=False, id=16777372, type='Relic'),
|
||||
"Wanderer's_Journal-Kingdom's_Edge_Entrance": HKItemData(advancement=False, id=16777371, type='Relic'),
|
||||
"Wanderer's_Journal-Kingdom's_Edge_Requires_Dive": HKItemData(advancement=False, id=16777373, type='Relic'),
|
||||
"Wanderer's_Journal-Pleasure_House": HKItemData(advancement=False, id=16777368, type='Relic'),
|
||||
"Wanderer's_Journal-Resting_Grounds_Catacombs": HKItemData(advancement=False, id=16777366, type='Relic'),
|
||||
'Waterways_Shaft': HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Wayward_Compass': HKItemData(advancement=False, id=16777242, type='Charm'),
|
||||
"Weaver's_Den": HKItemData(advancement=True, id=0, type='Event'),
|
||||
'Weaversong': HKItemData(advancement=True, id=16777281, type='Charm'),
|
||||
'Whispering_Root-Ancestral_Mound': HKItemData(advancement=True, id=16777416, type='Root'),
|
||||
'Whispering_Root-City': HKItemData(advancement=True, id=16777411, type='Root'),
|
||||
'Whispering_Root-Crossroads': HKItemData(advancement=True, id=16777403, type='Root'),
|
||||
'Whispering_Root-Crystal_Peak': HKItemData(advancement=True, id=16777414, type='Root'),
|
||||
'Whispering_Root-Deepnest': HKItemData(advancement=True, id=16777407, type='Root'),
|
||||
'Whispering_Root-Greenpath': HKItemData(advancement=True, id=16777404, type='Root'),
|
||||
'Whispering_Root-Hive': HKItemData(advancement=True, id=16777417, type='Root'),
|
||||
'Whispering_Root-Howling_Cliffs': HKItemData(advancement=True, id=16777415, type='Root'),
|
||||
'Whispering_Root-Kingdoms_Edge': HKItemData(advancement=True, id=16777409, type='Root'),
|
||||
'Whispering_Root-Leg_Eater': HKItemData(advancement=True, id=16777405, type='Root'),
|
||||
'Whispering_Root-Mantis_Village': HKItemData(advancement=True, id=16777406, type='Root'),
|
||||
'Whispering_Root-Queens_Gardens': HKItemData(advancement=True, id=16777408, type='Root'),
|
||||
'Whispering_Root-Resting_Grounds': HKItemData(advancement=True, id=16777412, type='Root'),
|
||||
'Whispering_Root-Spirits_Glade': HKItemData(advancement=True, id=16777413, type='Root'),
|
||||
'Whispering_Root-Waterways': HKItemData(advancement=True, id=16777410, type='Root'),
|
||||
'World_Sense': HKItemData(advancement=False, id=16777220, type='Dreamer')}
|
||||
|
||||
lookup_id_to_name:Dict[int, str] = {data.id: item_name for item_name, data in item_table.items() if data.type != 'Event'}
|
||||
lookup_type_to_names:Dict[str, Set[str]] = {}
|
||||
class HKItemData(NamedTuple):
|
||||
advancement: bool
|
||||
id: int
|
||||
type: str
|
||||
|
||||
|
||||
for i, (item_name, item_type) in enumerate(items.items(), start=0x1000000):
|
||||
item_table[item_name] = HKItemData(advancement=item_name in logic_items or item_name in item_effects,
|
||||
id=i, type=item_type)
|
||||
|
||||
lookup_id_to_name: Dict[int, str] = {data.id: item_name for item_name, data in item_table.items()}
|
||||
lookup_type_to_names: Dict[str, Set[str]] = {}
|
||||
for item, item_data in item_table.items():
|
||||
lookup_type_to_names.setdefault(item_data.type, set()).add(item)
|
|
@ -1,308 +0,0 @@
|
|||
# generated by https://github.com/Berserker66/HollowKnight.RandomizerMod/blob/master/extract_data.py
|
||||
# do not edit manually
|
||||
|
||||
lookup_id_to_name = \
|
||||
{ 17825793: 'Lurien',
|
||||
17825794: 'Monomon',
|
||||
17825795: 'Herrah',
|
||||
17825796: 'World_Sense',
|
||||
17825798: 'Mothwing_Cloak',
|
||||
17825799: 'Mantis_Claw',
|
||||
17825800: 'Crystal_Heart',
|
||||
17825801: 'Monarch_Wings',
|
||||
17825802: 'Shade_Cloak',
|
||||
17825803: "Isma's_Tear",
|
||||
17825804: 'Dream_Nail',
|
||||
17825805: 'Dream_Gate',
|
||||
17825806: 'Awoken_Dream_Nail',
|
||||
17825807: 'Vengeful_Spirit',
|
||||
17825808: 'Shade_Soul',
|
||||
17825809: 'Desolate_Dive',
|
||||
17825810: 'Descending_Dark',
|
||||
17825811: 'Howling_Wraiths',
|
||||
17825812: 'Abyss_Shriek',
|
||||
17825813: 'Cyclone_Slash',
|
||||
17825814: 'Dash_Slash',
|
||||
17825815: 'Great_Slash',
|
||||
17825816: 'Focus',
|
||||
17825817: 'Gathering_Swarm',
|
||||
17825818: 'Wayward_Compass',
|
||||
17825819: 'Grubsong',
|
||||
17825820: 'Stalwart_Shell',
|
||||
17825821: 'Baldur_Shell',
|
||||
17825822: 'Fury_of_the_Fallen',
|
||||
17825823: 'Quick_Focus',
|
||||
17825824: 'Lifeblood_Heart',
|
||||
17825825: 'Lifeblood_Core',
|
||||
17825826: "Defender's_Crest",
|
||||
17825827: 'Flukenest',
|
||||
17825828: 'Thorns_of_Agony',
|
||||
17825829: 'Mark_of_Pride',
|
||||
17825830: 'Steady_Body',
|
||||
17825831: 'Heavy_Blow',
|
||||
17825832: 'Sharp_Shadow',
|
||||
17825833: 'Spore_Shroom',
|
||||
17825834: 'Longnail',
|
||||
17825835: 'Shaman_Stone',
|
||||
17825836: 'Soul_Catcher',
|
||||
17825837: 'Soul_Eater',
|
||||
17825838: 'Glowing_Womb',
|
||||
17825839: 'Fragile_Heart',
|
||||
17825840: 'Fragile_Greed',
|
||||
17825841: 'Fragile_Strength',
|
||||
17825842: "Nailmaster's_Glory",
|
||||
17825843: "Joni's_Blessing",
|
||||
17825844: 'Shape_of_Unn',
|
||||
17825845: 'Hiveblood',
|
||||
17825846: 'Dream_Wielder',
|
||||
17825847: 'Dashmaster',
|
||||
17825848: 'Quick_Slash',
|
||||
17825849: 'Spell_Twister',
|
||||
17825850: 'Deep_Focus',
|
||||
17825851: "Grubberfly's_Elegy",
|
||||
17825852: 'Queen_Fragment',
|
||||
17825853: 'King_Fragment',
|
||||
17825854: 'Void_Heart',
|
||||
17825855: 'Sprintmaster',
|
||||
17825856: 'Dreamshield',
|
||||
17825857: 'Weaversong',
|
||||
17825858: 'Grimmchild',
|
||||
17825859: 'City_Crest',
|
||||
17825860: 'Lumafly_Lantern',
|
||||
17825861: 'Tram_Pass',
|
||||
17825862: 'Simple_Key-Sly',
|
||||
17825863: 'Simple_Key-Basin',
|
||||
17825864: 'Simple_Key-City',
|
||||
17825865: 'Simple_Key-Lurker',
|
||||
17825866: "Shopkeeper's_Key",
|
||||
17825867: 'Elegant_Key',
|
||||
17825868: 'Love_Key',
|
||||
17825869: "King's_Brand",
|
||||
17825870: 'Godtuner',
|
||||
17825871: "Collector's_Map",
|
||||
17825872: 'Mask_Shard-Sly1',
|
||||
17825873: 'Mask_Shard-Sly2',
|
||||
17825874: 'Mask_Shard-Sly3',
|
||||
17825875: 'Mask_Shard-Sly4',
|
||||
17825876: 'Mask_Shard-Seer',
|
||||
17825877: 'Mask_Shard-5_Grubs',
|
||||
17825878: 'Mask_Shard-Brooding_Mawlek',
|
||||
17825879: 'Mask_Shard-Crossroads_Goam',
|
||||
17825880: 'Mask_Shard-Stone_Sanctuary',
|
||||
17825881: "Mask_Shard-Queen's_Station",
|
||||
17825882: 'Mask_Shard-Deepnest',
|
||||
17825883: 'Mask_Shard-Waterways',
|
||||
17825884: 'Mask_Shard-Enraged_Guardian',
|
||||
17825885: 'Mask_Shard-Hive',
|
||||
17825886: 'Mask_Shard-Grey_Mourner',
|
||||
17825887: 'Mask_Shard-Bretta',
|
||||
17825888: 'Vessel_Fragment-Sly1',
|
||||
17825889: 'Vessel_Fragment-Sly2',
|
||||
17825890: 'Vessel_Fragment-Seer',
|
||||
17825891: 'Vessel_Fragment-Greenpath',
|
||||
17825892: 'Vessel_Fragment-City',
|
||||
17825893: 'Vessel_Fragment-Crossroads',
|
||||
17825894: 'Vessel_Fragment-Basin',
|
||||
17825895: 'Vessel_Fragment-Deepnest',
|
||||
17825896: 'Vessel_Fragment-Stag_Nest',
|
||||
17825897: 'Charm_Notch-Shrumal_Ogres',
|
||||
17825898: 'Charm_Notch-Fog_Canyon',
|
||||
17825899: 'Charm_Notch-Colosseum',
|
||||
17825900: 'Charm_Notch-Grimm',
|
||||
17825901: 'Pale_Ore-Basin',
|
||||
17825902: 'Pale_Ore-Crystal_Peak',
|
||||
17825903: 'Pale_Ore-Nosk',
|
||||
17825904: 'Pale_Ore-Seer',
|
||||
17825905: 'Pale_Ore-Grubs',
|
||||
17825906: 'Pale_Ore-Colosseum',
|
||||
17825907: '200_Geo-False_Knight_Chest',
|
||||
17825908: '380_Geo-Soul_Master_Chest',
|
||||
17825909: '655_Geo-Watcher_Knights_Chest',
|
||||
17825910: '85_Geo-Greenpath_Chest',
|
||||
17825911: '620_Geo-Mantis_Lords_Chest',
|
||||
17825912: '150_Geo-Resting_Grounds_Chest',
|
||||
17825913: '80_Geo-Crystal_Peak_Chest',
|
||||
17825914: '160_Geo-Weavers_Den_Chest',
|
||||
17825916: 'Rancid_Egg-Sly',
|
||||
17825917: 'Rancid_Egg-Grubs',
|
||||
17825918: 'Rancid_Egg-Sheo',
|
||||
17825919: 'Rancid_Egg-Fungal_Core',
|
||||
17825920: "Rancid_Egg-Queen's_Gardens",
|
||||
17825921: 'Rancid_Egg-Blue_Lake',
|
||||
17825922: 'Rancid_Egg-Crystal_Peak_Dive_Entrance',
|
||||
17825923: 'Rancid_Egg-Crystal_Peak_Dark_Room',
|
||||
17825924: 'Rancid_Egg-Crystal_Peak_Tall_Room',
|
||||
17825925: 'Rancid_Egg-City_of_Tears_Left',
|
||||
17825926: 'Rancid_Egg-City_of_Tears_Pleasure_House',
|
||||
17825927: "Rancid_Egg-Beast's_Den",
|
||||
17825928: 'Rancid_Egg-Dark_Deepnest',
|
||||
17825929: "Rancid_Egg-Weaver's_Den",
|
||||
17825930: 'Rancid_Egg-Near_Quick_Slash',
|
||||
17825931: "Rancid_Egg-Upper_Kingdom's_Edge",
|
||||
17825932: 'Rancid_Egg-Waterways_East',
|
||||
17825933: 'Rancid_Egg-Waterways_Main',
|
||||
17825934: 'Rancid_Egg-Waterways_West_Bluggsac',
|
||||
17825935: 'Rancid_Egg-Waterways_West_Pickup',
|
||||
17825936: "Wanderer's_Journal-Cliffs",
|
||||
17825937: "Wanderer's_Journal-Greenpath_Stag",
|
||||
17825938: "Wanderer's_Journal-Greenpath_Lower",
|
||||
17825939: "Wanderer's_Journal-Fungal_Wastes_Thorns_Gauntlet",
|
||||
17825940: "Wanderer's_Journal-Above_Mantis_Village",
|
||||
17825941: "Wanderer's_Journal-Crystal_Peak_Crawlers",
|
||||
17825942: "Wanderer's_Journal-Resting_Grounds_Catacombs",
|
||||
17825943: "Wanderer's_Journal-King's_Station",
|
||||
17825944: "Wanderer's_Journal-Pleasure_House",
|
||||
17825945: "Wanderer's_Journal-City_Storerooms",
|
||||
17825946: "Wanderer's_Journal-Ancient_Basin",
|
||||
17825947: "Wanderer's_Journal-Kingdom's_Edge_Entrance",
|
||||
17825948: "Wanderer's_Journal-Kingdom's_Edge_Camp",
|
||||
17825949: "Wanderer's_Journal-Kingdom's_Edge_Requires_Dive",
|
||||
17825950: 'Hallownest_Seal-Crossroads_Well',
|
||||
17825951: 'Hallownest_Seal-Grubs',
|
||||
17825952: 'Hallownest_Seal-Greenpath',
|
||||
17825953: 'Hallownest_Seal-Fog_Canyon_West',
|
||||
17825954: 'Hallownest_Seal-Fog_Canyon_East',
|
||||
17825955: "Hallownest_Seal-Queen's_Station",
|
||||
17825956: 'Hallownest_Seal-Fungal_Wastes_Sporgs',
|
||||
17825957: 'Hallownest_Seal-Mantis_Lords',
|
||||
17825958: 'Hallownest_Seal-Seer',
|
||||
17825959: 'Hallownest_Seal-Resting_Grounds_Catacombs',
|
||||
17825960: "Hallownest_Seal-King's_Station",
|
||||
17825961: 'Hallownest_Seal-City_Rafters',
|
||||
17825962: 'Hallownest_Seal-Soul_Sanctum',
|
||||
17825963: 'Hallownest_Seal-Watcher_Knight',
|
||||
17825964: 'Hallownest_Seal-Deepnest_By_Mantis_Lords',
|
||||
17825965: "Hallownest_Seal-Beast's_Den",
|
||||
17825966: "Hallownest_Seal-Queen's_Gardens",
|
||||
17825967: "King's_Idol-Grubs",
|
||||
17825968: "King's_Idol-Cliffs",
|
||||
17825969: "King's_Idol-Crystal_Peak",
|
||||
17825970: "King's_Idol-Glade_of_Hope",
|
||||
17825971: "King's_Idol-Dung_Defender",
|
||||
17825972: "King's_Idol-Great_Hopper",
|
||||
17825973: "King's_Idol-Pale_Lurker",
|
||||
17825974: "King's_Idol-Deepnest",
|
||||
17825975: 'Arcane_Egg-Seer',
|
||||
17825976: 'Arcane_Egg-Lifeblood_Core',
|
||||
17825977: 'Arcane_Egg-Shade_Cloak',
|
||||
17825978: 'Arcane_Egg-Birthplace',
|
||||
17825979: 'Whispering_Root-Crossroads',
|
||||
17825980: 'Whispering_Root-Greenpath',
|
||||
17825981: 'Whispering_Root-Leg_Eater',
|
||||
17825982: 'Whispering_Root-Mantis_Village',
|
||||
17825983: 'Whispering_Root-Deepnest',
|
||||
17825984: 'Whispering_Root-Queens_Gardens',
|
||||
17825985: 'Whispering_Root-Kingdoms_Edge',
|
||||
17825986: 'Whispering_Root-Waterways',
|
||||
17825987: 'Whispering_Root-City',
|
||||
17825988: 'Whispering_Root-Resting_Grounds',
|
||||
17825989: 'Whispering_Root-Spirits_Glade',
|
||||
17825990: 'Whispering_Root-Crystal_Peak',
|
||||
17825991: 'Whispering_Root-Howling_Cliffs',
|
||||
17825992: 'Whispering_Root-Ancestral_Mound',
|
||||
17825993: 'Whispering_Root-Hive',
|
||||
17825994: 'Boss_Essence-Elder_Hu',
|
||||
17825995: 'Boss_Essence-Xero',
|
||||
17825996: 'Boss_Essence-Gorb',
|
||||
17825997: 'Boss_Essence-Marmu',
|
||||
17825998: 'Boss_Essence-No_Eyes',
|
||||
17825999: 'Boss_Essence-Galien',
|
||||
17826000: 'Boss_Essence-Markoth',
|
||||
17826001: 'Boss_Essence-Failed_Champion',
|
||||
17826002: 'Boss_Essence-Soul_Tyrant',
|
||||
17826003: 'Boss_Essence-Lost_Kin',
|
||||
17826004: 'Boss_Essence-White_Defender',
|
||||
17826005: 'Boss_Essence-Grey_Prince_Zote',
|
||||
17826006: 'Grub-Crossroads_Acid',
|
||||
17826007: 'Grub-Crossroads_Center',
|
||||
17826008: 'Grub-Crossroads_Stag',
|
||||
17826009: 'Grub-Crossroads_Spike',
|
||||
17826010: 'Grub-Crossroads_Guarded',
|
||||
17826011: 'Grub-Greenpath_Cornifer',
|
||||
17826012: 'Grub-Greenpath_Journal',
|
||||
17826013: 'Grub-Greenpath_MMC',
|
||||
17826014: 'Grub-Greenpath_Stag',
|
||||
17826015: 'Grub-Fog_Canyon',
|
||||
17826016: 'Grub-Fungal_Bouncy',
|
||||
17826017: 'Grub-Fungal_Spore_Shroom',
|
||||
17826018: 'Grub-Deepnest_Mimic',
|
||||
17826019: 'Grub-Deepnest_Nosk',
|
||||
17826020: 'Grub-Deepnest_Spike',
|
||||
17826021: 'Grub-Dark_Deepnest',
|
||||
17826022: "Grub-Beast's_Den",
|
||||
17826023: "Grub-Kingdom's_Edge_Oro",
|
||||
17826024: "Grub-Kingdom's_Edge_Camp",
|
||||
17826025: 'Grub-Hive_External',
|
||||
17826026: 'Grub-Hive_Internal',
|
||||
17826027: 'Grub-Basin_Requires_Wings',
|
||||
17826028: 'Grub-Basin_Requires_Dive',
|
||||
17826029: 'Grub-Waterways_Main',
|
||||
17826030: 'Grub-Waterways_East',
|
||||
17826031: 'Grub-Waterways_Requires_Tram',
|
||||
17826032: 'Grub-City_of_Tears_Left',
|
||||
17826033: 'Grub-Soul_Sanctum',
|
||||
17826034: "Grub-Watcher's_Spire",
|
||||
17826035: 'Grub-City_of_Tears_Guarded',
|
||||
17826036: "Grub-King's_Station",
|
||||
17826037: 'Grub-Resting_Grounds',
|
||||
17826038: 'Grub-Crystal_Peak_Below_Chest',
|
||||
17826039: 'Grub-Crystallized_Mound',
|
||||
17826040: 'Grub-Crystal_Peak_Spike',
|
||||
17826041: 'Grub-Crystal_Peak_Mimic',
|
||||
17826042: 'Grub-Crystal_Peak_Crushers',
|
||||
17826043: 'Grub-Crystal_Heart',
|
||||
17826044: 'Grub-Hallownest_Crown',
|
||||
17826045: 'Grub-Howling_Cliffs',
|
||||
17826046: "Grub-Queen's_Gardens_Stag",
|
||||
17826047: "Grub-Queen's_Gardens_Marmu",
|
||||
17826048: "Grub-Queen's_Gardens_Top",
|
||||
17826049: 'Grub-Collector_1',
|
||||
17826050: 'Grub-Collector_2',
|
||||
17826051: 'Grub-Collector_3',
|
||||
17826052: 'Crossroads_Map',
|
||||
17826053: 'Greenpath_Map',
|
||||
17826054: 'Fog_Canyon_Map',
|
||||
17826055: 'Fungal_Wastes_Map',
|
||||
17826056: 'Deepnest_Map-Upper',
|
||||
17826057: 'Deepnest_Map-Right_[Gives_Quill]',
|
||||
17826058: 'Ancient_Basin_Map',
|
||||
17826059: "Kingdom's_Edge_Map",
|
||||
17826060: 'City_of_Tears_Map',
|
||||
17826061: 'Royal_Waterways_Map',
|
||||
17826062: 'Howling_Cliffs_Map',
|
||||
17826063: 'Crystal_Peak_Map',
|
||||
17826064: "Queen's_Gardens_Map",
|
||||
17826065: 'Resting_Grounds_Map',
|
||||
17826066: 'Dirtmouth_Stag',
|
||||
17826067: 'Crossroads_Stag',
|
||||
17826068: 'Greenpath_Stag',
|
||||
17826069: "Queen's_Station_Stag",
|
||||
17826070: "Queen's_Gardens_Stag",
|
||||
17826071: 'City_Storerooms_Stag',
|
||||
17826072: "King's_Station_Stag",
|
||||
17826073: 'Resting_Grounds_Stag',
|
||||
17826074: 'Distant_Village_Stag',
|
||||
17826075: 'Hidden_Station_Stag',
|
||||
17826076: 'Stag_Nest_Stag',
|
||||
17826077: "Lifeblood_Cocoon-King's_Pass",
|
||||
17826078: 'Lifeblood_Cocoon-Ancestral_Mound',
|
||||
17826079: 'Lifeblood_Cocoon-Greenpath',
|
||||
17826080: 'Lifeblood_Cocoon-Fog_Canyon_West',
|
||||
17826081: 'Lifeblood_Cocoon-Mantis_Village',
|
||||
17826082: 'Lifeblood_Cocoon-Failed_Tramway',
|
||||
17826083: 'Lifeblood_Cocoon-Galien',
|
||||
17826084: "Lifeblood_Cocoon-Kingdom's_Edge",
|
||||
17826085: 'Grimmkin_Flame-City_Storerooms',
|
||||
17826086: 'Grimmkin_Flame-Greenpath',
|
||||
17826087: 'Grimmkin_Flame-Crystal_Peak',
|
||||
17826088: "Grimmkin_Flame-King's_Pass",
|
||||
17826089: 'Grimmkin_Flame-Resting_Grounds',
|
||||
17826090: "Grimmkin_Flame-Kingdom's_Edge",
|
||||
17826091: 'Grimmkin_Flame-Fungal_Core',
|
||||
17826092: 'Grimmkin_Flame-Ancient_Basin',
|
||||
17826093: 'Grimmkin_Flame-Hive',
|
||||
17826094: 'Grimmkin_Flame-Brumm'}
|
||||
|
||||
|
||||
|
||||
lookup_name_to_id = {location_name: location_id for location_id, location_name in lookup_id_to_name.items()}
|
|
@ -1,39 +1,138 @@
|
|||
import typing
|
||||
from .ExtractedData import logic_options, starts, pool_options
|
||||
from Options import Option, DefaultOnToggle, Toggle, Choice, Range
|
||||
|
||||
from Options import Option, DefaultOnToggle, Toggle
|
||||
# This way the dynamic start names are picked up by the MetaClass Choice belongs to
|
||||
StartLocation = type("StartLocation", (Choice,), {
|
||||
"option_" + start: i for i, start in enumerate(starts)} | {"auto_display_name": False})
|
||||
|
||||
hollow_knight_randomize_options: typing.Dict[str, type(Option)] = {
|
||||
"RandomizeDreamers": DefaultOnToggle,
|
||||
"RandomizeSkills": DefaultOnToggle,
|
||||
"RandomizeCharms": DefaultOnToggle,
|
||||
"RandomizeKeys": DefaultOnToggle,
|
||||
"RandomizeGeoChests": Toggle,
|
||||
"RandomizeMaskShards": DefaultOnToggle,
|
||||
"RandomizeVesselFragments": DefaultOnToggle,
|
||||
"RandomizeCharmNotches": Toggle,
|
||||
"RandomizePaleOre": DefaultOnToggle,
|
||||
"RandomizeRancidEggs": Toggle,
|
||||
"RandomizeRelics": DefaultOnToggle,
|
||||
"RandomizeMaps": Toggle,
|
||||
"RandomizeStags": Toggle,
|
||||
"RandomizeGrubs": Toggle,
|
||||
"RandomizeWhisperingRoots": Toggle,
|
||||
"RandomizeRocks": Toggle,
|
||||
"RandomizeSoulTotems": Toggle,
|
||||
"RandomizePalaceTotems": Toggle,
|
||||
"RandomizeLoreTablets": Toggle,
|
||||
"RandomizeLifebloodCocoons": Toggle,
|
||||
"RandomizeFlames": Toggle
|
||||
default_on = {
|
||||
"RandomizeDreamers",
|
||||
"RandomizeSkills",
|
||||
"RandomizeCharms",
|
||||
"RandomizeKeys",
|
||||
"RandomizeMaskShards",
|
||||
"RandomizeVesselFragments",
|
||||
"RandomizePaleOre",
|
||||
"RandomizeRelics"
|
||||
}
|
||||
hollow_knight_skip_options: typing.Dict[str, type(Option)] = {
|
||||
"MILDSKIPS": Toggle,
|
||||
"SPICYSKIPS": Toggle,
|
||||
"FIREBALLSKIPS": Toggle,
|
||||
"ACIDSKIPS": Toggle,
|
||||
"SPIKETUNNELS": Toggle,
|
||||
"DARKROOMS": Toggle,
|
||||
"CURSED": Toggle,
|
||||
"SHADESKIPS": Toggle,
|
||||
|
||||
# not supported at this time
|
||||
disabled = {
|
||||
"RandomizeFocus",
|
||||
"RandomizeSwim",
|
||||
"RandomizeMimics",
|
||||
"RandomizeNail",
|
||||
|
||||
}
|
||||
|
||||
hollow_knight_randomize_options: typing.Dict[str, type(Option)] = {}
|
||||
|
||||
for option_name, option_data in pool_options.items():
|
||||
extra_data = {"items": option_data[0], "locations": option_data[1]}
|
||||
if option_name in default_on:
|
||||
option = type(option_name, (DefaultOnToggle,), extra_data)
|
||||
else:
|
||||
option = type(option_name, (Toggle,), extra_data)
|
||||
hollow_knight_randomize_options[option_name] = option
|
||||
|
||||
hollow_knight_logic_options: typing.Dict[str, type(Option)] = {
|
||||
option_name: Toggle for option_name in logic_options.values() if
|
||||
option_name not in hollow_knight_randomize_options
|
||||
and option_name != "RandomizeCharmNotches"}
|
||||
|
||||
|
||||
class MinimumGrubPrice(Range):
|
||||
display_name = "Minimum Grub Price"
|
||||
range_start = 1
|
||||
range_end = 46
|
||||
default = 1
|
||||
|
||||
|
||||
class MaximumGrubPrice(MinimumGrubPrice):
|
||||
display_name = "Maximum Grub Price"
|
||||
default = 23
|
||||
|
||||
|
||||
class MinimumEssencePrice(Range):
|
||||
display_name = "Minimum Essence Price"
|
||||
range_start = 1
|
||||
range_end = 2800
|
||||
default = 1
|
||||
|
||||
|
||||
class MaximumEssencePrice(MinimumEssencePrice):
|
||||
display_name = "Maximum Essence Price"
|
||||
default = 1400
|
||||
|
||||
|
||||
class MinimumEggPrice(Range):
|
||||
display_name = "Minimum Egg Price"
|
||||
range_start = 1
|
||||
range_end = 21
|
||||
default = 1
|
||||
|
||||
|
||||
class MaximumEggPrice(MinimumEggPrice):
|
||||
display_name = "Maximum Egg Price"
|
||||
default = 10
|
||||
|
||||
|
||||
class MinimumCharmPrice(Range):
|
||||
"""For Salubra's Charm-count based locations."""
|
||||
display_name = "Minimum Charm Requirement"
|
||||
range_start = 1
|
||||
range_end = 40
|
||||
default = 1
|
||||
|
||||
|
||||
class MaximumCharmPrice(MinimumCharmPrice):
|
||||
default = 20
|
||||
|
||||
|
||||
class RandomCharmCosts(Range):
|
||||
"""Total Cost of all Charms together. Set to -1 for vanilla costs. Vanilla sums to 90."""
|
||||
|
||||
display_name = "Random Charm Costs"
|
||||
range_start = -1
|
||||
range_end = 240
|
||||
default = -1
|
||||
vanilla_costs: typing.List[int] = [1, 1, 1, 2, 2, 2, 3, 2, 3, 1, 3, 1, 3, 1, 2, 2, 1, 2, 3, 2,
|
||||
4, 2, 2, 2, 3, 1, 4, 2, 4, 1, 2, 3, 2, 4, 3, 5, 1, 3, 2, 2]
|
||||
charm_count: int = len(vanilla_costs)
|
||||
|
||||
def get_costs(self, random_source) -> typing.List[int]:
|
||||
if -1 == self.value:
|
||||
return self.vanilla_costs
|
||||
else:
|
||||
charms = [0]*self.charm_count
|
||||
for x in range(self.value):
|
||||
index = random_source.randint(0, self.charm_count-1)
|
||||
while charms[index] > 5:
|
||||
index = random_source.randint(0, self.charm_count-1)
|
||||
charms[index] += 1
|
||||
return charms
|
||||
|
||||
|
||||
class EggShopSlots(Range):
|
||||
"""For each slot, add a location to the Egg Shop and a Geo drop to the item pool."""
|
||||
|
||||
display_name = "Egg Shop Item Slots"
|
||||
range_end = 16
|
||||
|
||||
|
||||
hollow_knight_options: typing.Dict[str, type(Option)] = {
|
||||
**hollow_knight_randomize_options,
|
||||
**hollow_knight_logic_options,
|
||||
"start_location": StartLocation,
|
||||
"minimum_grub_price": MinimumGrubPrice,
|
||||
"maximum_grub_price": MaximumGrubPrice,
|
||||
"minimum_essence_price": MinimumEssencePrice,
|
||||
"maximum_essence_price": MaximumEssencePrice,
|
||||
"minimum_egg_price": MinimumEggPrice,
|
||||
"maximum_egg_price": MaximumEggPrice,
|
||||
"minimum_charm_price": MinimumCharmPrice,
|
||||
"maximum_charm_price": MaximumCharmPrice,
|
||||
"random_charm_costs": RandomCharmCosts,
|
||||
"egg_shop_slots": EggShopSlots,
|
||||
}
|
||||
hollow_knight_options: typing.Dict[str, type(Option)] = {**hollow_knight_randomize_options,
|
||||
**hollow_knight_skip_options}
|
|
@ -1,13 +1,25 @@
|
|||
# generated by https://github.com/Berserker66/HollowKnight.RandomizerMod/blob/master/extract_data.py
|
||||
# do not edit manually
|
||||
from .ExtractedData import region_names, exits, connectors
|
||||
|
||||
|
||||
def create_regions(world, player: int):
|
||||
from . import create_region
|
||||
from .Items import item_table
|
||||
from .Locations import lookup_name_to_id
|
||||
world.regions += [
|
||||
create_region(world, player, 'Menu', None, ['Hollow Nest S&Q']),
|
||||
create_region(world, player, 'Hollow Nest', [location for location in lookup_name_to_id] +
|
||||
[item_name for item_name, item_data in item_table.items() if item_data.type == "Event"])
|
||||
]
|
||||
from . import create_region, HKLocation, HKItem
|
||||
world.regions.append(create_region(world, player, 'Menu', None, ['Hollow Nest S&Q']))
|
||||
for region in region_names:
|
||||
world.regions.append(create_region(world, player, region, [],
|
||||
exits.get(region, [])))
|
||||
for entrance_name, exit_name in connectors.items():
|
||||
if exit_name:
|
||||
target_region = world.get_entrance(exit_name, player).parent_region
|
||||
world.get_entrance(entrance_name, player).connect(target_region)
|
||||
if not entrance_name.endswith("_R"):
|
||||
# a traversable entrance puts the name of the target door "into logic".
|
||||
loc = HKLocation(player, exit_name, None, target_region)
|
||||
loc.place_locked_item(HKItem(exit_name,
|
||||
not exit_name.startswith("White_Palace_"),
|
||||
None, "Event", player))
|
||||
target_region.locations.append(loc)
|
||||
else:
|
||||
ent = world.get_entrance(entrance_name, player)
|
||||
ent.parent_region.exits.remove(ent)
|
||||
|
||||
|
||||
|
|
2088
worlds/hk/Rules.py
2088
worlds/hk/Rules.py
File diff suppressed because it is too large
Load Diff
|
@ -1,7 +0,0 @@
|
|||
import typing
|
||||
|
||||
|
||||
class HKItemData(typing.NamedTuple):
|
||||
advancement: bool
|
||||
id: int
|
||||
type: str
|
|
@ -1,111 +1,262 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import typing
|
||||
from collections import Counter
|
||||
|
||||
logger = logging.getLogger("Hollow Knight")
|
||||
|
||||
from .Locations import lookup_name_to_id
|
||||
from .Items import item_table, lookup_type_to_names
|
||||
from .Regions import create_regions
|
||||
from .Rules import set_rules
|
||||
from .Options import hollow_knight_options
|
||||
from .Options import hollow_knight_options, hollow_knight_randomize_options
|
||||
from .ExtractedData import locations, starts, multi_locations, location_to_region_lookup, \
|
||||
event_names, item_effects, connectors, one_ways
|
||||
|
||||
from BaseClasses import Region, Entrance, Location, MultiWorld, Item, RegionType
|
||||
from ..AutoWorld import World, LogicMixin
|
||||
|
||||
white_palace_locations = {
|
||||
"Soul_Totem-Path_of_Pain_Below_Thornskip",
|
||||
"Soul_Totem-White_Palace_Final",
|
||||
"Lore_Tablet-Path_of_Pain_Entrance",
|
||||
"Soul_Totem-Path_of_Pain_Left_of_Lever",
|
||||
"Soul_Totem-Path_of_Pain_Hidden",
|
||||
"Soul_Totem-Path_of_Pain_Entrance",
|
||||
"Soul_Totem-Path_of_Pain_Final",
|
||||
"Soul_Totem-White_Palace_Entrance",
|
||||
"Soul_Totem-Path_of_Pain_Below_Lever",
|
||||
"Lore_Tablet-Palace_Throne",
|
||||
"Soul_Totem-Path_of_Pain_Second",
|
||||
"Soul_Totem-White_Palace_Left",
|
||||
"Lore_Tablet-Palace_Workshop",
|
||||
"Soul_Totem-White_Palace_Hub",
|
||||
"Journal_Entry-Seal_of_Binding",
|
||||
"Soul_Totem-White_Palace_Right",
|
||||
"King_Fragment",
|
||||
# Events:
|
||||
"Palace_Entrance_Lantern_Lit",
|
||||
"Palace_Left_Lantern_Lit",
|
||||
"Palace_Right_Lantern_Lit",
|
||||
"Warp-Path_of_Pain_Complete",
|
||||
"Defeated_Path_of_Pain_Arena",
|
||||
"Palace_Atrium_Gates_Opened",
|
||||
"Completed_Path_of_Pain",
|
||||
"Warp-White_Palace_Atrium_to_Palace_Grounds",
|
||||
"Warp-White_Palace_Entrance_to_Palace_Grounds",
|
||||
# Event-Regions:
|
||||
"White_Palace_03_hub",
|
||||
"White_Palace_13",
|
||||
"White_Palace_01",
|
||||
# Event-Transitions:
|
||||
"White_Palace_12[bot1]", "White_Palace_12[bot1]", "White_Palace_03_hub[bot1]", "White_Palace_16[left2]",
|
||||
"White_Palace_16[left2]", "White_Palace_11[door2]", "White_Palace_11[door2]", "White_Palace_18[top1]",
|
||||
"White_Palace_18[top1]", "White_Palace_15[left1]", "White_Palace_15[left1]", "White_Palace_05[left2]",
|
||||
"White_Palace_05[left2]", "White_Palace_14[bot1]", "White_Palace_14[bot1]", "White_Palace_13[left2]",
|
||||
"White_Palace_13[left2]", "White_Palace_03_hub[left1]", "White_Palace_03_hub[left1]", "White_Palace_15[right2]",
|
||||
"White_Palace_15[right2]", "White_Palace_06[top1]", "White_Palace_06[top1]", "White_Palace_03_hub[bot1]",
|
||||
"White_Palace_08[right1]", "White_Palace_08[right1]", "White_Palace_03_hub[right1]", "White_Palace_03_hub[right1]",
|
||||
"White_Palace_01[right1]", "White_Palace_01[right1]", "White_Palace_08[left1]", "White_Palace_08[left1]",
|
||||
"White_Palace_19[left1]", "White_Palace_19[left1]", "White_Palace_04[right2]", "White_Palace_04[right2]",
|
||||
"White_Palace_01[left1]", "White_Palace_01[left1]", "White_Palace_17[right1]", "White_Palace_17[right1]",
|
||||
"White_Palace_07[bot1]", "White_Palace_07[bot1]", "White_Palace_20[bot1]", "White_Palace_20[bot1]",
|
||||
"White_Palace_03_hub[left2]", "White_Palace_03_hub[left2]", "White_Palace_18[right1]", "White_Palace_18[right1]",
|
||||
"White_Palace_05[right1]", "White_Palace_05[right1]", "White_Palace_17[bot1]", "White_Palace_17[bot1]",
|
||||
"White_Palace_09[right1]", "White_Palace_09[right1]", "White_Palace_16[left1]", "White_Palace_16[left1]",
|
||||
"White_Palace_13[left1]", "White_Palace_13[left1]", "White_Palace_06[bot1]", "White_Palace_06[bot1]",
|
||||
"White_Palace_15[right1]", "White_Palace_15[right1]", "White_Palace_06[left1]", "White_Palace_06[left1]",
|
||||
"White_Palace_05[right2]", "White_Palace_05[right2]", "White_Palace_04[top1]", "White_Palace_04[top1]",
|
||||
"White_Palace_19[top1]", "White_Palace_19[top1]", "White_Palace_14[right1]", "White_Palace_14[right1]",
|
||||
"White_Palace_03_hub[top1]", "White_Palace_03_hub[top1]", "Grubfather_2", "White_Palace_13[left3]",
|
||||
"White_Palace_13[left3]", "White_Palace_02[left1]", "White_Palace_02[left1]", "White_Palace_12[right1]",
|
||||
"White_Palace_12[right1]", "White_Palace_07[top1]", "White_Palace_07[top1]", "White_Palace_05[left1]",
|
||||
"White_Palace_05[left1]", "White_Palace_13[right1]", "White_Palace_13[right1]", "White_Palace_01[top1]",
|
||||
"White_Palace_01[top1]",
|
||||
|
||||
}
|
||||
|
||||
|
||||
class HKWorld(World):
|
||||
game: str = "Hollow Knight"
|
||||
options = hollow_knight_options
|
||||
|
||||
item_name_to_id = {name: data.id for name, data in item_table.items() if data.type != "Event"}
|
||||
location_name_to_id = lookup_name_to_id
|
||||
item_name_to_id = {name: data.id for name, data in item_table.items()}
|
||||
location_name_to_id = {location_name: location_id for location_id, location_name in
|
||||
enumerate(locations, start=0x1000000)}
|
||||
|
||||
hidden = True
|
||||
ranges: typing.Dict[str, typing.Tuple[int, int]]
|
||||
shops = {"Egg_Shop": "egg", "Grubfather": "grub", "Seer": "essence", "Salubra_(Requires_Charms)": "charm"}
|
||||
charm_costs: typing.List[int]
|
||||
data_version = 2
|
||||
|
||||
allow_white_palace = False
|
||||
|
||||
def __init__(self, world, player):
|
||||
super(HKWorld, self).__init__(world, player)
|
||||
self.created_multi_locations: typing.Dict[str, int] = Counter()
|
||||
self.ranges = {}
|
||||
|
||||
def generate_early(self):
|
||||
world = self.world
|
||||
self.charm_costs = world.random_charm_costs[self.player].get_costs(world.random)
|
||||
world.exclude_locations[self.player].value.update(white_palace_locations)
|
||||
world.local_items[self.player].value.add("Mimic_Grub")
|
||||
for vendor, unit in self.shops.items():
|
||||
mini = getattr(world, f"minimum_{unit}_price")[self.player]
|
||||
maxi = getattr(world, f"maximum_{unit}_price")[self.player]
|
||||
# if minimum > maximum, set minimum to maximum
|
||||
mini.value = min(mini.value, maxi.value)
|
||||
self.ranges[unit] = mini.value, maxi.value
|
||||
world.push_precollected(HKItem(starts[world.start_location[self.player].current_key],
|
||||
True, None, "Event", self.player))
|
||||
|
||||
def create_regions(self):
|
||||
menu_region: Region = create_region(self.world, self.player, 'Menu')
|
||||
self.world.regions.append(menu_region)
|
||||
|
||||
def generate_basic(self):
|
||||
# Link regions
|
||||
self.world.get_entrance('Hollow Nest S&Q', self.player).connect(self.world.get_region('Hollow Nest', self.player))
|
||||
for event_name in event_names:
|
||||
loc = HKLocation(self.player, event_name, None, menu_region)
|
||||
loc.place_locked_item(HKItem(event_name,
|
||||
self.allow_white_palace or event_name not in white_palace_locations,
|
||||
None, "Event", self.player))
|
||||
menu_region.locations.append(loc)
|
||||
for entry_transition, exit_transition in connectors.items():
|
||||
if exit_transition:
|
||||
# if door logic fulfilled -> award vanilla target as event
|
||||
loc = HKLocation(self.player, entry_transition, None, menu_region)
|
||||
loc.place_locked_item(HKItem(exit_transition,
|
||||
self.allow_white_palace or exit_transition not in white_palace_locations,
|
||||
None, "Event", self.player))
|
||||
menu_region.locations.append(loc)
|
||||
|
||||
# Generate item pool
|
||||
pool = []
|
||||
for item_name, item_data in item_table.items():
|
||||
item = self.create_item(item_name)
|
||||
def create_items(self):
|
||||
# Generate item pool and associated locations (paired in HK)
|
||||
pool: typing.List[HKItem] = []
|
||||
geo_replace: typing.Set[str] = set()
|
||||
if self.world.RemoveSpellUpgrades[self.player]:
|
||||
geo_replace.add("Abyss_Shriek")
|
||||
geo_replace.add("Shade_Soul")
|
||||
geo_replace.add("Descending_Dark")
|
||||
|
||||
if item_data.type == "Event":
|
||||
event_location = self.world.get_location(item_name, self.player)
|
||||
self.world.push_item(event_location, item, collect=False)
|
||||
event_location.event = True
|
||||
event_location.locked = True
|
||||
if item.name == "King's_Pass":
|
||||
self.world.push_precollected(item)
|
||||
elif item_data.type == "Cursed":
|
||||
if self.world.CURSED[self.player]:
|
||||
pool.append(item)
|
||||
else:
|
||||
# fill Focus Location with Focus and add it to start inventory as well.
|
||||
event_location = self.world.get_location(item_name, self.player)
|
||||
self.world.push_item(event_location, item)
|
||||
event_location.event = True
|
||||
event_location.locked = True
|
||||
|
||||
elif item_data.type == "Fake":
|
||||
pass
|
||||
elif item_data.type in not_shufflable_types:
|
||||
location = self.world.get_location(item_name, self.player)
|
||||
self.world.push_item(location, item, collect=False)
|
||||
location.event = item.advancement
|
||||
location.locked = True
|
||||
for option_key, option in hollow_knight_randomize_options.items():
|
||||
if getattr(self.world, option_key)[self.player]:
|
||||
for item_name, location_name in zip(option.items, option.locations):
|
||||
if item_name in geo_replace:
|
||||
item_name = "Geo_Rock-Default"
|
||||
if location_name in white_palace_locations:
|
||||
self.create_location(location_name).place_locked_item(self.create_item(item_name))
|
||||
else:
|
||||
self.create_location(location_name)
|
||||
pool.append(self.create_item(item_name))
|
||||
else:
|
||||
target = option_to_type_lookup[item.type]
|
||||
shuffle_it = getattr(self.world, target)
|
||||
if shuffle_it[self.player]:
|
||||
pool.append(item)
|
||||
else:
|
||||
location = self.world.get_location(item_name, self.player)
|
||||
self.world.push_item(location, item, collect=False)
|
||||
location.event = item.advancement
|
||||
location.locked = True
|
||||
logger.debug(f"Placed {item_name} to vanilla for player {self.player}")
|
||||
|
||||
for item_name, location_name in zip(option.items, option.locations):
|
||||
item = self.create_item(item_name)
|
||||
if location_name == "Start":
|
||||
self.world.push_precollected(item)
|
||||
else:
|
||||
self.create_location(location_name).place_locked_item(item)
|
||||
for i in range(self.world.egg_shop_slots[self.player].value):
|
||||
self.create_location("Egg_Shop")
|
||||
pool.append(self.create_item("Geo_Rock-Default"))
|
||||
if not self.allow_white_palace:
|
||||
loc = self.world.get_location("King_Fragment", self.player)
|
||||
if loc.item and loc.item.name == loc.name:
|
||||
loc.item.advancement = False
|
||||
self.world.itempool += pool
|
||||
|
||||
def set_rules(self):
|
||||
set_rules(self.world, self.player)
|
||||
|
||||
def create_regions(self):
|
||||
create_regions(self.world, self.player)
|
||||
world = self.world
|
||||
player = self.player
|
||||
if world.logic[player] != 'nologic':
|
||||
world.completion_condition[player] = lambda state: state.has('DREAMER', player, 3)
|
||||
set_rules(self)
|
||||
|
||||
def fill_slot_data(self):
|
||||
slot_data = {}
|
||||
|
||||
options = slot_data["options"] = {}
|
||||
for option_name in self.options:
|
||||
option = getattr(self.world, option_name)[self.player]
|
||||
slot_data[option_name] = int(option.value)
|
||||
options[option_name] = int(option.value)
|
||||
|
||||
# 32 bit int
|
||||
slot_data["seed"] = self.world.slot_seeds[self.player].randint(-2147483647, 2147483646)
|
||||
|
||||
for shop, unit in self.shops.items():
|
||||
slot_data[f"{unit}_costs"] = {
|
||||
f"{shop}_{i}":
|
||||
self.world.get_location(f"{shop}_{i}", self.player).cost
|
||||
for i in range(1, 1 + self.created_multi_locations[shop])
|
||||
}
|
||||
|
||||
slot_data["notch_costs"] = self.charm_costs
|
||||
|
||||
return slot_data
|
||||
|
||||
def create_item(self, name: str) -> Item:
|
||||
def create_item(self, name: str) -> HKItem:
|
||||
item_data = item_table[name]
|
||||
return HKItem(name, item_data.advancement, item_data.id, item_data.type, self.player)
|
||||
|
||||
def create_location(self, name: str) -> HKLocation:
|
||||
unit = self.shops.get(name, None)
|
||||
if unit:
|
||||
cost = self.world.random.randint(*self.ranges[unit])
|
||||
else:
|
||||
cost = 0
|
||||
if name in multi_locations:
|
||||
self.created_multi_locations[name] += 1
|
||||
name += f"_{self.created_multi_locations[name]}"
|
||||
|
||||
def create_region(world: MultiWorld, player: int, name: str, locations=None, exits=None):
|
||||
region = self.world.get_region("Menu", self.player)
|
||||
loc = HKLocation(self.player, name, self.location_name_to_id[name], region)
|
||||
if unit:
|
||||
loc.unit = unit
|
||||
loc.cost = cost
|
||||
region.locations.append(loc)
|
||||
return loc
|
||||
|
||||
def collect(self, state, item: HKItem) -> bool:
|
||||
change = super(HKWorld, self).collect(state, item)
|
||||
|
||||
for effect_name, effect_value in item_effects.get(item.name, {}).items():
|
||||
state.prog_items[effect_name, item.player] += effect_value
|
||||
|
||||
return change
|
||||
|
||||
def remove(self, state, item: HKItem) -> bool:
|
||||
change = super(HKWorld, self).remove(state, item)
|
||||
|
||||
for effect_name, effect_value in item_effects.get(item.name, {}).items():
|
||||
if state.prog_items[effect_name, item.player] == effect_value:
|
||||
del state.prog_items[effect_name, item.player]
|
||||
state.prog_items[effect_name, item.player] -= effect_value
|
||||
|
||||
return change
|
||||
|
||||
|
||||
def create_region(world: MultiWorld, player: int, name: str, location_names=None, exits=None) -> Region:
|
||||
ret = Region(name, RegionType.Generic, name, player)
|
||||
ret.world = world
|
||||
if locations:
|
||||
for location in locations:
|
||||
loc_id = lookup_name_to_id.get(location, 0)
|
||||
if location_names:
|
||||
for location in location_names:
|
||||
loc_id = HKWorld.location_name_to_id.get(location, None)
|
||||
location = HKLocation(player, location, loc_id, ret)
|
||||
ret.locations.append(location)
|
||||
if exits:
|
||||
for exit in exits:
|
||||
ret.exits.append(Entrance(player, exit, ret))
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
class HKLocation(Location):
|
||||
game: str = "Hollow Knight"
|
||||
cost: int = 0
|
||||
unit: typing.Optional[str] = None
|
||||
|
||||
def __init__(self, player: int, name: str, address=None, parent=None):
|
||||
super(HKLocation, self).__init__(player, name, address if address else None, parent)
|
||||
def __init__(self, player: int, name: str, code=None, parent=None):
|
||||
super(HKLocation, self).__init__(player, name, code if code else None, parent)
|
||||
|
||||
|
||||
class HKItem(Item):
|
||||
|
@ -114,51 +265,20 @@ class HKItem(Item):
|
|||
def __init__(self, name, advancement, code, type, player: int = None):
|
||||
super(HKItem, self).__init__(name, advancement, code if code else None, player)
|
||||
self.type = type
|
||||
if name == "Mimic_Grub":
|
||||
self.trap = True
|
||||
|
||||
|
||||
not_shufflable_types = {"Essence_Boss"}
|
||||
class HKLogicMixin(LogicMixin):
|
||||
world: MultiWorld
|
||||
|
||||
option_to_type_lookup = {
|
||||
"Root": "RandomizeWhisperingRoots",
|
||||
"Dreamer": "RandomizeDreamers",
|
||||
"Geo": "RandomizeGeoChests",
|
||||
"Skill": "RandomizeSkills",
|
||||
"Map": "RandomizeMaps",
|
||||
"Relic": "RandomizeRelics",
|
||||
"Charm": "RandomizeCharms",
|
||||
"Notch": "RandomizeCharmNotches",
|
||||
"Key": "RandomizeKeys",
|
||||
"Stag": "RandomizeStags",
|
||||
"Flame": "RandomizeFlames",
|
||||
"Grub": "RandomizeGrubs",
|
||||
"Cocoon": "RandomizeLifebloodCocoons",
|
||||
"Mask": "RandomizeMaskShards",
|
||||
"Ore": "RandomizePaleOre",
|
||||
"Egg": "RandomizeRancidEggs",
|
||||
"Vessel": "RandomizeVesselFragments",
|
||||
}
|
||||
def _hk_notches(self, player: int, *notches: int) -> int:
|
||||
return sum(self.world.worlds[player].charm_costs[notch] for notch in notches)
|
||||
|
||||
def _kh_option(self, player: int, option_name: str) -> int:
|
||||
if option_name == "RandomizeCharmNotches":
|
||||
return self.world.random_charm_costs[player] != -1
|
||||
return getattr(self.world, option_name)[player].value
|
||||
|
||||
class HKLogic(LogicMixin):
|
||||
# these are all wip
|
||||
def _hk_has_essence(self, player: int, count: int):
|
||||
return self.prog_items["Dream_Nail", player]
|
||||
# return self.prog_items["Essence", player] >= count
|
||||
|
||||
def _hk_has_grubs(self, player: int, count: int):
|
||||
found = 0
|
||||
for item_name in lookup_type_to_names["Grub"]:
|
||||
found += self.prog_items[item_name, player]
|
||||
if found >= count:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def _hk_has_flames(self, player: int, count: int):
|
||||
found = 0
|
||||
for item_name in lookup_type_to_names["Flame"]:
|
||||
found += self.prog_items[item_name, player]
|
||||
if found >= count:
|
||||
return True
|
||||
|
||||
return False
|
||||
def _kh_start(self, player, start_location: str) -> bool:
|
||||
return self.world.start_location[player] == start_location
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
astunparse>=1.6.3; python_version <= '3.8'
|
Loading…
Reference in New Issue