Hollow Knight: 0.4.5 doc revamp and default options tweaks (#2982)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
This commit is contained in:
parent
80d7ac4164
commit
74ac66b032
|
@ -1,4 +1,5 @@
|
||||||
import typing
|
import typing
|
||||||
|
import re
|
||||||
from .ExtractedData import logic_options, starts, pool_options
|
from .ExtractedData import logic_options, starts, pool_options
|
||||||
from .Rules import cost_terms
|
from .Rules import cost_terms
|
||||||
|
|
||||||
|
@ -11,12 +12,16 @@ if typing.TYPE_CHECKING:
|
||||||
else:
|
else:
|
||||||
Random = typing.Any
|
Random = typing.Any
|
||||||
|
|
||||||
|
|
||||||
locations = {"option_" + start: i for i, start in enumerate(starts)}
|
locations = {"option_" + start: i for i, start in enumerate(starts)}
|
||||||
# This way the dynamic start names are picked up by the MetaClass Choice belongs to
|
# This way the dynamic start names are picked up by the MetaClass Choice belongs to
|
||||||
StartLocation = type("StartLocation", (Choice,), {"__module__": __name__, "auto_display_name": False, **locations,
|
StartLocation = type("StartLocation", (Choice,), {
|
||||||
"__doc__": "Choose your start location. "
|
"__module__": __name__,
|
||||||
"This is currently only locked to King's Pass."})
|
"auto_display_name": False,
|
||||||
|
"display_name": "Start Location",
|
||||||
|
"__doc__": "Choose your start location. "
|
||||||
|
"This is currently only locked to King's Pass.",
|
||||||
|
**locations,
|
||||||
|
})
|
||||||
del (locations)
|
del (locations)
|
||||||
|
|
||||||
option_docstrings = {
|
option_docstrings = {
|
||||||
|
@ -49,8 +54,7 @@ option_docstrings = {
|
||||||
"RandomizeBossEssence": "Randomize boss essence drops, such as those for defeating Warrior Dreams, into the item "
|
"RandomizeBossEssence": "Randomize boss essence drops, such as those for defeating Warrior Dreams, into the item "
|
||||||
"pool and open their locations\n for randomization.",
|
"pool and open their locations\n for randomization.",
|
||||||
"RandomizeGrubs": "Randomize Grubs into the item pool and open their locations for randomization.",
|
"RandomizeGrubs": "Randomize Grubs into the item pool and open their locations for randomization.",
|
||||||
"RandomizeMimics": "Randomize Mimic Grubs into the item pool and open their locations for randomization."
|
"RandomizeMimics": "Randomize Mimic Grubs into the item pool and open their locations for randomization.",
|
||||||
"Mimic Grubs are always placed\n in your own game.",
|
|
||||||
"RandomizeMaps": "Randomize Maps into the item pool. This causes Cornifer to give you a message allowing you to see"
|
"RandomizeMaps": "Randomize Maps into the item pool. This causes Cornifer to give you a message allowing you to see"
|
||||||
" and buy an item\n that is randomized into that location as well.",
|
" and buy an item\n that is randomized into that location as well.",
|
||||||
"RandomizeStags": "Randomize Stag Stations unlocks into the item pool as well as placing randomized items "
|
"RandomizeStags": "Randomize Stag Stations unlocks into the item pool as well as placing randomized items "
|
||||||
|
@ -99,8 +103,12 @@ default_on = {
|
||||||
"RandomizeKeys",
|
"RandomizeKeys",
|
||||||
"RandomizeMaskShards",
|
"RandomizeMaskShards",
|
||||||
"RandomizeVesselFragments",
|
"RandomizeVesselFragments",
|
||||||
|
"RandomizeCharmNotches",
|
||||||
"RandomizePaleOre",
|
"RandomizePaleOre",
|
||||||
"RandomizeRelics"
|
"RandomizeRancidEggs"
|
||||||
|
"RandomizeRelics",
|
||||||
|
"RandomizeStags",
|
||||||
|
"RandomizeLifebloodCocoons"
|
||||||
}
|
}
|
||||||
|
|
||||||
shop_to_option = {
|
shop_to_option = {
|
||||||
|
@ -117,6 +125,7 @@ shop_to_option = {
|
||||||
|
|
||||||
hollow_knight_randomize_options: typing.Dict[str, type(Option)] = {}
|
hollow_knight_randomize_options: typing.Dict[str, type(Option)] = {}
|
||||||
|
|
||||||
|
splitter_pattern = re.compile(r'(?<!^)(?=[A-Z])')
|
||||||
for option_name, option_data in pool_options.items():
|
for option_name, option_data in pool_options.items():
|
||||||
extra_data = {"__module__": __name__, "items": option_data[0], "locations": option_data[1]}
|
extra_data = {"__module__": __name__, "items": option_data[0], "locations": option_data[1]}
|
||||||
if option_name in option_docstrings:
|
if option_name in option_docstrings:
|
||||||
|
@ -125,6 +134,7 @@ for option_name, option_data in pool_options.items():
|
||||||
option = type(option_name, (DefaultOnToggle,), extra_data)
|
option = type(option_name, (DefaultOnToggle,), extra_data)
|
||||||
else:
|
else:
|
||||||
option = type(option_name, (Toggle,), extra_data)
|
option = type(option_name, (Toggle,), extra_data)
|
||||||
|
option.display_name = splitter_pattern.sub(" ", option_name)
|
||||||
globals()[option.__name__] = option
|
globals()[option.__name__] = option
|
||||||
hollow_knight_randomize_options[option.__name__] = option
|
hollow_knight_randomize_options[option.__name__] = option
|
||||||
|
|
||||||
|
@ -133,11 +143,14 @@ for option_name in logic_options.values():
|
||||||
if option_name in hollow_knight_randomize_options:
|
if option_name in hollow_knight_randomize_options:
|
||||||
continue
|
continue
|
||||||
extra_data = {"__module__": __name__}
|
extra_data = {"__module__": __name__}
|
||||||
|
# some options, such as elevator pass, appear in logic_options despite explicitly being
|
||||||
|
# handled below as classes.
|
||||||
if option_name in option_docstrings:
|
if option_name in option_docstrings:
|
||||||
extra_data["__doc__"] = option_docstrings[option_name]
|
extra_data["__doc__"] = option_docstrings[option_name]
|
||||||
option = type(option_name, (Toggle,), extra_data)
|
option = type(option_name, (Toggle,), extra_data)
|
||||||
globals()[option.__name__] = option
|
option.display_name = splitter_pattern.sub(" ", option_name)
|
||||||
hollow_knight_logic_options[option.__name__] = option
|
globals()[option.__name__] = option
|
||||||
|
hollow_knight_logic_options[option.__name__] = option
|
||||||
|
|
||||||
|
|
||||||
class RandomizeElevatorPass(Toggle):
|
class RandomizeElevatorPass(Toggle):
|
||||||
|
@ -269,11 +282,11 @@ class RandomCharmCosts(NamedRange):
|
||||||
random_source.shuffle(charms)
|
random_source.shuffle(charms)
|
||||||
return charms
|
return charms
|
||||||
else:
|
else:
|
||||||
charms = [0]*self.charm_count
|
charms = [0] * self.charm_count
|
||||||
for x in range(self.value):
|
for x in range(self.value):
|
||||||
index = random_source.randint(0, self.charm_count-1)
|
index = random_source.randint(0, self.charm_count - 1)
|
||||||
while charms[index] > 5:
|
while charms[index] > 5:
|
||||||
index = random_source.randint(0, self.charm_count-1)
|
index = random_source.randint(0, self.charm_count - 1)
|
||||||
charms[index] += 1
|
charms[index] += 1
|
||||||
return charms
|
return charms
|
||||||
|
|
||||||
|
@ -404,6 +417,7 @@ class WhitePalace(Choice):
|
||||||
|
|
||||||
class ExtraPlatforms(DefaultOnToggle):
|
class ExtraPlatforms(DefaultOnToggle):
|
||||||
"""Places additional platforms to make traveling throughout Hallownest more convenient."""
|
"""Places additional platforms to make traveling throughout Hallownest more convenient."""
|
||||||
|
display_name = "Extra Platforms"
|
||||||
|
|
||||||
|
|
||||||
class AddUnshuffledLocations(Toggle):
|
class AddUnshuffledLocations(Toggle):
|
||||||
|
@ -413,6 +427,7 @@ class AddUnshuffledLocations(Toggle):
|
||||||
Note: This will increase the number of location checks required to purchase
|
Note: This will increase the number of location checks required to purchase
|
||||||
hints to the total maximum.
|
hints to the total maximum.
|
||||||
"""
|
"""
|
||||||
|
display_name = "Add Unshuffled Locations"
|
||||||
|
|
||||||
|
|
||||||
class DeathLinkShade(Choice):
|
class DeathLinkShade(Choice):
|
||||||
|
@ -430,6 +445,7 @@ class DeathLinkShade(Choice):
|
||||||
option_shadeless = 1
|
option_shadeless = 1
|
||||||
option_shade = 2
|
option_shade = 2
|
||||||
default = 2
|
default = 2
|
||||||
|
display_name = "Deathlink Shade Handling"
|
||||||
|
|
||||||
|
|
||||||
class DeathLinkBreaksFragileCharms(Toggle):
|
class DeathLinkBreaksFragileCharms(Toggle):
|
||||||
|
@ -439,6 +455,7 @@ class DeathLinkBreaksFragileCharms(Toggle):
|
||||||
** Self-death fragile charm behavior is not changed; if a self-death normally breaks fragile charms in vanilla, it
|
** Self-death fragile charm behavior is not changed; if a self-death normally breaks fragile charms in vanilla, it
|
||||||
will continue to do so.
|
will continue to do so.
|
||||||
"""
|
"""
|
||||||
|
display_name = "Deathlink Breaks Fragile Charms"
|
||||||
|
|
||||||
|
|
||||||
class StartingGeo(Range):
|
class StartingGeo(Range):
|
||||||
|
@ -462,18 +479,20 @@ class CostSanity(Choice):
|
||||||
alias_yes = 1
|
alias_yes = 1
|
||||||
option_shopsonly = 2
|
option_shopsonly = 2
|
||||||
option_notshops = 3
|
option_notshops = 3
|
||||||
display_name = "Cost Sanity"
|
display_name = "Costsanity"
|
||||||
|
|
||||||
|
|
||||||
class CostSanityHybridChance(Range):
|
class CostSanityHybridChance(Range):
|
||||||
"""The chance that a CostSanity cost will include two components instead of one, e.g. Grubs + Essence"""
|
"""The chance that a CostSanity cost will include two components instead of one, e.g. Grubs + Essence"""
|
||||||
range_end = 100
|
range_end = 100
|
||||||
default = 10
|
default = 10
|
||||||
|
display_name = "Costsanity Hybrid Chance"
|
||||||
|
|
||||||
|
|
||||||
cost_sanity_weights: typing.Dict[str, type(Option)] = {}
|
cost_sanity_weights: typing.Dict[str, type(Option)] = {}
|
||||||
for term, cost in cost_terms.items():
|
for term, cost in cost_terms.items():
|
||||||
option_name = f"CostSanity{cost.option}Weight"
|
option_name = f"CostSanity{cost.option}Weight"
|
||||||
|
display_name = f"Costsanity {cost.option} Weight"
|
||||||
extra_data = {
|
extra_data = {
|
||||||
"__module__": __name__, "range_end": 1000,
|
"__module__": __name__, "range_end": 1000,
|
||||||
"__doc__": (
|
"__doc__": (
|
||||||
|
@ -486,10 +505,10 @@ for term, cost in cost_terms.items():
|
||||||
extra_data["__doc__"] += " Geo costs will never be chosen for Grubfather, Seer, or Egg Shop."
|
extra_data["__doc__"] += " Geo costs will never be chosen for Grubfather, Seer, or Egg Shop."
|
||||||
|
|
||||||
option = type(option_name, (Range,), extra_data)
|
option = type(option_name, (Range,), extra_data)
|
||||||
|
option.display_name = display_name
|
||||||
globals()[option.__name__] = option
|
globals()[option.__name__] = option
|
||||||
cost_sanity_weights[option.__name__] = option
|
cost_sanity_weights[option.__name__] = option
|
||||||
|
|
||||||
|
|
||||||
hollow_knight_options: typing.Dict[str, type(Option)] = {
|
hollow_knight_options: typing.Dict[str, type(Option)] = {
|
||||||
**hollow_knight_randomize_options,
|
**hollow_knight_randomize_options,
|
||||||
RandomizeElevatorPass.__name__: RandomizeElevatorPass,
|
RandomizeElevatorPass.__name__: RandomizeElevatorPass,
|
||||||
|
|
|
@ -8,7 +8,9 @@ config file.
|
||||||
## What does randomization do to this game?
|
## What does randomization do to this game?
|
||||||
|
|
||||||
Randomization swaps around the locations of items. The items being swapped around are chosen within your YAML.
|
Randomization swaps around the locations of items. The items being swapped around are chosen within your YAML.
|
||||||
Shop costs are presently always randomized.
|
Shop costs are presently always randomized. Items which could be randomized, but are not, will remain unmodified in
|
||||||
|
their usual locations. In particular, when the items at Grubfather and Seer are partially randomized, randomized items
|
||||||
|
will be obtained from a chest in the room, while unrandomized items will be given by the NPC as normal.
|
||||||
|
|
||||||
## What Hollow Knight items can appear in other players' worlds?
|
## What Hollow Knight items can appear in other players' worlds?
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
## Required Software
|
## Required Software
|
||||||
* Download and unzip the Lumafly Mod Manager from the [Lumafly website](https://themulhima.github.io/Lumafly/).
|
* Download and unzip the Lumafly Mod Manager from the [Lumafly website](https://themulhima.github.io/Lumafly/).
|
||||||
* A legal copy of Hollow Knight.
|
* A legal copy of Hollow Knight.
|
||||||
|
* Steam, Gog, and Xbox Game Pass versions of the game are supported.
|
||||||
|
* Windows, Mac, and Linux (including Steam Deck) are supported.
|
||||||
|
|
||||||
## Installing the Archipelago Mod using Lumafly
|
## Installing the Archipelago Mod using Lumafly
|
||||||
1. Launch Lumafly and ensure it locates your Hollow Knight installation directory.
|
1. Launch Lumafly and ensure it locates your Hollow Knight installation directory.
|
||||||
|
@ -10,25 +12,25 @@
|
||||||
* If desired, also install "Archipelago Map Mod" to use as an in-game tracker.
|
* If desired, also install "Archipelago Map Mod" to use as an in-game tracker.
|
||||||
3. Launch the game, you're all set!
|
3. Launch the game, you're all set!
|
||||||
|
|
||||||
### What to do if Lumafly fails to find your XBox Game Pass installation directory
|
### What to do if Lumafly fails to find your installation directory
|
||||||
1. Enter the XBox app and move your mouse over "Hollow Knight" on the left sidebar.
|
1. Find the directory manually.
|
||||||
2. Click the three points then click "Manage".
|
* Xbox Game Pass:
|
||||||
3. Go to the "Files" tab and select "Browse...".
|
1. Enter the XBox app and move your mouse over "Hollow Knight" on the left sidebar.
|
||||||
4. Click "Hollow Knight", then "Content", then click the path bar and copy it.
|
2. Click the three points then click "Manage".
|
||||||
5. Run Lumafly as an administrator and, when it asks you for the path, paste what you copied in step 4.
|
3. Go to the "Files" tab and select "Browse...".
|
||||||
|
4. Click "Hollow Knight", then "Content", then click the path bar and copy it.
|
||||||
#### Alternative Method:
|
* Steam:
|
||||||
1. Click on your profile then "Settings".
|
1. You likely put your Steam library in a non-standard place. If this is the case, you probably know where
|
||||||
2. Go to the "General" tab and select "CHANGE FOLDER".
|
it is. Find your steam library and then find the Hollow Knight folder and copy the path.
|
||||||
3. Look for a folder where you want to install the game (preferably inside a folder on your desktop) and copy the path.
|
* Windows - `C:\Program Files (x86)\Steam\steamapps\common\Hollow Knight`
|
||||||
4. Run Lumafly as an administrator and, when it asks you for the path, paste what you copied in step 3.
|
* Linux/Steam Deck - ~/.local/share/Steam/steamapps/common/Hollow Knight
|
||||||
|
* Mac - ~/Library/Application Support/Steam/steamapps/common/Hollow Knight/hollow_knight.app
|
||||||
Note: The path folder needs to have the "Hollow Knight_Data" folder inside.
|
2. Run Lumafly as an administrator and, when it asks you for the path, paste the path you copied.
|
||||||
|
|
||||||
## Configuring your YAML File
|
## Configuring your YAML File
|
||||||
### What is a YAML and why do I need one?
|
### What is a YAML and why do I need one?
|
||||||
You can see the [basic multiworld setup guide](/tutorial/Archipelago/setup/en) here on the Archipelago website to learn
|
An YAML file is the way that you provide your player options to Archipelago.
|
||||||
about why Archipelago uses YAML files and what they're for.
|
See the [basic multiworld setup guide](/tutorial/Archipelago/setup/en) here on the Archipelago website to learn more.
|
||||||
|
|
||||||
### Where do I get a YAML?
|
### Where do I get a YAML?
|
||||||
You can use the [game options page for Hollow Knight](/games/Hollow%20Knight/player-options) here on the Archipelago
|
You can use the [game options page for Hollow Knight](/games/Hollow%20Knight/player-options) here on the Archipelago
|
||||||
|
@ -44,9 +46,7 @@ website to generate a YAML using a graphical interface.
|
||||||
* If you are waiting for a countdown then wait for it to lapse before hitting Start.
|
* If you are waiting for a countdown then wait for it to lapse before hitting Start.
|
||||||
* Or hit Start then pause the game once you're in it.
|
* Or hit Start then pause the game once you're in it.
|
||||||
|
|
||||||
## Commands
|
## Hints and other commands
|
||||||
While playing the multiworld you can interact with the server using various commands listed in the
|
While playing in a multiworld, you can interact with the server using various commands listed in the
|
||||||
[commands guide](/tutorial/Archipelago/commands/en). As this game does not have an in-game text client at the moment,
|
[commands guide](/tutorial/Archipelago/commands/en). You can use the Archipelago Text Client to do this,
|
||||||
You can optionally connect to the multiworld using the text client, which can be found in the
|
which is included in the latest release of the [Archipelago software](https://github.com/ArchipelagoMW/Archipelago/releases/latest).
|
||||||
[main Archipelago installation](https://github.com/ArchipelagoMW/Archipelago/releases) as Archipelago Text Client to
|
|
||||||
enter these commands.
|
|
||||||
|
|
Loading…
Reference in New Issue