DS3: Version 3.0.0 (#3128)

* Update worlds/dark_souls_3/Locations.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Fix Covetous Silver Serpent Ring location

* Update location groups

This should cover pretty much all of the seriously hidden items. It
also splits out miniboss drops, mimic drops, and hostile NPC drops.

* Remove the "Guarded by Keys" group

On reflection, I don't think this is actually that useful. It'll also
get a lot muddier once we can randomize shops and ashes become
pseudo-"keys".

* Restore Knight Slayer's Ring classification

* Support infusions/upgrades in the new DS3 mod system

* Support random starting loadouts

* Make an item's NPC status orthogonal to its category

* Track location groups with flags

* Track Archipelago/Offline mismatches on the server

Also fix a few incorrect item names.

* Add additional locations that are now randomizable

* Don't put soul and multiple items in shops

* Add an option to enable whether NG+ items/locations are included

* Clean up useful item categorization

There are so many weapons in the game now, it doesn't make sense to
treat them all as useful

* Add more variety to filler items

* Iron out a few bugs and incompatibilities

* Fix more silly bugs

* Get tests passing

* Update options to cover new item types

Also recategorize some items.

* Verify the default values of `Option`s.

Since `Option.verify()` can handle normalization of option names, this allows options  to define defaults which rely on that normalization. For example, it allows a world to exclude certain locations by default.

This also makes it easier to catch errors if a world author accidentally sets an invalid default.

* Make a few more improvements and fixes

* Randomize Path of the Dragon

* Mark items that unlock checks as useful

These items all unlock missable checks, but they're still good to ahve in the game for variety's sake.

* Guarantee more NPC quests are completable

* Fix a syntax error

* Fix rule definition

* Support enemy randomization

* Support online Yhorm randomization

* Remove a completed TODO

* Fix tests

* Fix force_unique

* Add an option to smooth out upgrade item progression

* Add helpers for setting location/entrance rules

* Support smoother soul item progression

* Fill extra smoothing items into conditional locations as well as other worlds

* Add health item smoothing

* Handle infusions at item generation time

* Handle item upgrades at genreation time

* Fix Grave Warden's Ashes

* Don't overwrite old rules

* Randomize items based on spheres instead of DS3 locations

* Add a smoothing option for weapon upgrades

* Add rules for crow trades

* Small fixes

* Fix a few more bugs

* Fix more bugs

* Try to prevent Path of the Dragon from going somewhere it doesn't work

* Add the ability to provide enemy presets

* Various fixes and features

* Bug fixes

* Better Coiled Sword placement

* Structure DarkSouls3Location more like DarkSouls3Item

* Add events to make DS3's spheres more even

* Restructure locations to work like items do now

* Add rules for more missable locations

* Don't add two Storm Rulers

* Place Hawk Ring in Farron Keep

* Mark the Grass Crest Shield as useful

* Mark new progression items

* Fix a bug

* Support newer better Path of the Dragon code

* Don't lock the player out of Coiled Sword

* Don't create events for missable locations

* Don't throw strings

* Don't smooth event items

* Properly categorize Butcher Knife

* Be more careful about placing Yhorm in low-randomization scenarios

* Don't try to smooth DLC items with DLC disabled

* Fix another Yhorm bug

* Fix upgrade/infusion logic

* Remove the PoolType option

This distinction is no longer meaningful now that every location in
the game of each type is randomized

* Categorize HWL: Red Eye Orb as an NPC location

* Don't place Storm Ruler on CA: Coiled Sword

* Define flatten() locally to make this APWorld capable

* Fix some more Leonhard weirdness

* Fix unique item randomization

* Don't double Twin Dragon Greatshield

* Remove debugging print

* Don't add double Storm Ruler

Also remove now-redundant item sorting by category in create_items.

* Don't add double Storm Ruler

Also remove now-redundant item sorting by category in create_items.

* Add a missing dlc_enabled check

* Use nicer options syntax

* Bump data_version

* Mention where Yhorm is in which world

* Better handle excluded events

* Add a newline to Yhorm location

* Better way of handling excluded unradomized progression locations

* Fix a squidge of nondeterminism

* Only smooth items from this world

* Don't smooth progression weapons

* Remove a location that doesn't actually exist in-game

* Classify Power Within as useful

* Clarify location names

* Fix location requirements

* Clean up randomization options

* Properly name Coiled Sword location

* Add an option for configuring how missable items are handled

* Fix some bugs from location name updates

* Fix location guide link

* Fix a couple locations that were busted offline

* Update detailed location descriptions

* Fix some bugs when generating for a multiworld

* Inject Large Leather Shield

* Fix a few location issues

* Don't allow progression_skip_balancing for unnecessary locs

* Update some location info

* Don't uniquify the wrong items

* Fix some more location issues

* More location fixes

* Use hyphens instead of parens for location descriptions

* Update and fix more locations

* Fix Soul of Cinder boss name

* Fix some logic issues

* Add item groups and document item/location groups

* Fix the display name for "Impatient Mimics"

* Properly handle Transposing Kiln and Pyromancer's Flame

* Testing

* Some fixes to NPC quests, late basin, and transposing kiln

* Improve a couple location names

* Split out and improve missable NPC item logic

* Don't allow crow trades to have foreign items

* Fix a variable capture bug

* Make sure early items are accessible early even with early Castle

* Mark ID giant slave drops as missable

* Make sure late basin means that early items aren't behind it

* Make is_location_available explicitly private

* Add an _add_item_rule utility that checks availability

* Clear excluded items if excluded_locations == "unnecessary"

* Don't allow upgrades/infusions in crow trades

* Fix the documentation for deprecated options

* Create events for all excluded locations

This allows `can_reach` logic to work even if the locations are
randomized.

* Fix up Patches' and Siegward's logic based on some manual testing

* Factor out more sub-methods for setting location rules

* Oops, left these in

* Fixing name

* Left that in too

* Changing to NamedRange to support special_range_names

* Alphabetizing

* Don't call _is_location_available on foreign locations

* Add missing Leonhard items

* Changing late basin to have a post-small-doll option

* Update basin option, add logic for some of Leonhard Hawkwood and Orbeck

* Simplifying an option, fixing a copy-paste error

* Removing trailing whitespace

* Changing lost items to go into start inventory

* Revert Basin changes

* Oops

* Update Options.py

* Reverting small doll changes

* Farron Keep boss requirement logic

* Add Scroll for late_dlc

* Fixing excluded unnecessary locations

* Adding Priestess Ring as being after UG boss

* Removing missable from Corvian Titanite Slab

* Adding KFF Yhorm boss locks

* Screams about Creighton

* Elite Knight Set isn't permanently missable

* Adding Kiln requirement to KFF

* fixing valid_keys and item groups

* Fixing an option-checker

* Throwing unplaceable Storm Ruler into start inventory

* Update locations

* Refactor item injection

* Update setup doc

* Small fixes

* Fix another location name

* Fix injection calculation

* Inject guaranteed items along with progression items

* Mark boss souls as required for access to regions

This allows us to set quest requirements for boss souls and have them
automatically propagated to regions, means we need less machinery for
Yhorm bosses, and allows us to get rid of a few region-transition
events.

* Make sure Sirris's quest can be completed before Pontiff

* Removing unused list

* Changing dict to list

* Removing unused test

* Update __init__.py

* self.multiworld.random -> self.random (#9)

* Fix some miscellaneous location issues

* Rewrite the DS3 intro page/FAQ

* Removing modifying the itempool after fill (#7)

Co-authored-by: Natalie Weizenbaum <nweiz@google.com>

* Small fixes to the setup guide (#10)

Small fixes, adding an example for connecting

* Expanded Late Basin of Vows and Late DLC (#6)

* Add proper requirements for CD: Black Eye Orb

* Fix Aldrich's name

* Document the differences with the 2.x.x branch

* Don't crash if there are more items than locations in smoothing

* Apply suggestions from code review

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Code review

* Fix _replace_with_filler

* Don't use the shared flatten function in SM

* Track local items separately rather than iterating the multiworld

* Various formatting/docs changes suggested by PyCharm (#12)

* Drop deprecated options

* Rename "offline randomizer" to "static randomizer" which is clearer

* Move `enable_*_locations` under removed options.

* Avoid excluded locations for locally-filled items

* Adding Removed options to error (#14)

* Changes for WebHost options display and the options overhaul

* unpack iterators in item list (#13)

* Allow worlds to add options to prebuilt groups

Previously, this crashed because `typing.NamedTuple` fields such as
`group.name` aren't assignable. Now it will only fail for group names
that are actually incorrectly cased, and will fail with a better error
message.

* Style changes, rename exclude behavior options, remove guaranteed items option

* Spacing/Formatting (#18)

* Various Fixes (#19)

* Universally Track Yhorm (#20)

* Account for excluded and missable

* These are behaviors now

* This is singular, apparently

* Oops

* Fleshing out the priority process

* Missable Titanite Lizards and excluded locations (#22)

* Small style/efficiency changes

* Final passthrough fixes (#24)

* Use rich option formatting

* Make the behavior option values actual behaviors (#25)

* Use !=

* Remove unused flatten utility

* Some changes from review (#28)

* Fixing determinism and making smooth faster (#29)

* Style change

* PyCharm and Mypy fixes (#26)

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Change yhorm default (#30)

* Add indirect condition (#27)

* Update worlds/dark_souls_3/docs/locations_en.md

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Ship all item IDs to the client

This avoids issues where items might get skipped if, for instance,
they're only in the starting inventory.

* Make sure to send AP IDs for infused/upgraded weapons

* Make `RandomEnemyPresetOption` compatible with ArchipelagoMW/Archipelago#3280 (#31)

* Fix cast

* More typing and small fixes (#32)

---------

Co-authored-by: Scipio Wright <scipiowright@gmail.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
Co-authored-by: Exempt-Medic <ExemptMedic@Gmail.com>
Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
This commit is contained in:
Natalie Weizenbaum 2024-08-09 03:14:26 -07:00 committed by GitHub
parent 6803c373e5
commit 5efb3fd2b0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 9325 additions and 2359 deletions

View File

@ -0,0 +1,264 @@
# In almost all cases, we leave boss and enemy randomization up to the static randomizer. But for
# Yhorm specifically we need to know where he ends up in order to ensure that the Storm Ruler is
# available before his fight.
from dataclasses import dataclass, field
from typing import Set
@dataclass
class DS3BossInfo:
"""The set of locations a given boss location blocks access to."""
name: str
"""The boss's name."""
id: int
"""The game's ID for this particular boss."""
dlc: bool = False
"""This boss appears in one of the game's DLCs."""
before_storm_ruler: bool = False
"""Whether this location appears before it's possible to get Storm Ruler in vanilla.
This is used to determine whether it's safe to place Yhorm here if weapons
aren't randomized.
"""
locations: Set[str] = field(default_factory=set)
"""Additional individual locations that can't be accessed until the boss is dead."""
# Note: the static randomizer splits up some bosses into separate fights for separate phases, each
# of which can be individually replaced by Yhorm.
all_bosses = [
DS3BossInfo("Iudex Gundyr", 4000800, before_storm_ruler = True, locations = {
"CA: Coiled Sword - boss drop"
}),
DS3BossInfo("Vordt of the Boreal Valley", 3000800, before_storm_ruler = True, locations = {
"HWL: Soul of Boreal Valley Vordt"
}),
DS3BossInfo("Curse-rotted Greatwood", 3100800, locations = {
"US: Soul of the Rotted Greatwood",
"US: Transposing Kiln - boss drop",
"US: Wargod Wooden Shield - Pit of Hollows",
"FS: Hawkwood's Shield - gravestone after Hawkwood leaves",
"FS: Sunset Shield - by grave after killing Hodrick w/Sirris",
"US: Sunset Helm - Pit of Hollows after killing Hodrick w/Sirris",
"US: Sunset Armor - pit of hollows after killing Hodrick w/Sirris",
"US: Sunset Gauntlets - pit of hollows after killing Hodrick w/Sirris",
"US: Sunset Leggings - pit of hollows after killing Hodrick w/Sirris",
"FS: Sunless Talisman - Sirris, kill GA boss",
"FS: Sunless Veil - shop, Sirris quest, kill GA boss",
"FS: Sunless Armor - shop, Sirris quest, kill GA boss",
"FS: Sunless Gauntlets - shop, Sirris quest, kill GA boss",
"FS: Sunless Leggings - shop, Sirris quest, kill GA boss",
}),
DS3BossInfo("Crystal Sage", 3300850, locations = {
"RS: Soul of a Crystal Sage",
"FS: Sage's Big Hat - shop after killing RS boss",
"FS: Hawkwood's Shield - gravestone after Hawkwood leaves",
}),
DS3BossInfo("Deacons of the Deep", 3500800, locations = {
"CD: Soul of the Deacons of the Deep",
"CD: Small Doll - boss drop",
"FS: Hawkwood's Shield - gravestone after Hawkwood leaves",
}),
DS3BossInfo("Abyss Watchers", 3300801, before_storm_ruler = True, locations = {
"FK: Soul of the Blood of the Wolf",
"FK: Cinders of a Lord - Abyss Watcher",
"FS: Undead Legion Helm - shop after killing FK boss",
"FS: Undead Legion Armor - shop after killing FK boss",
"FS: Undead Legion Gauntlet - shop after killing FK boss",
"FS: Undead Legion Leggings - shop after killing FK boss",
"FS: Farron Ring - Hawkwood",
"FS: Hawkwood's Shield - gravestone after Hawkwood leaves",
}),
DS3BossInfo("High Lord Wolnir", 3800800, before_storm_ruler = True, locations = {
"CC: Soul of High Lord Wolnir",
"FS: Wolnir's Crown - shop after killing CC boss",
"CC: Homeward Bone - Irithyll bridge",
"CC: Pontiff's Right Eye - Irithyll bridge, miniboss drop",
}),
DS3BossInfo("Pontiff Sulyvahn", 3700850, locations = {
"IBV: Soul of Pontiff Sulyvahn",
}),
DS3BossInfo("Old Demon King", 3800830, locations = {
"SL: Soul of the Old Demon King",
}),
DS3BossInfo("Aldrich, Devourer of Gods", 3700800, locations = {
"AL: Soul of Aldrich",
"AL: Cinders of a Lord - Aldrich",
"FS: Smough's Helm - shop after killing AL boss",
"FS: Smough's Armor - shop after killing AL boss",
"FS: Smough's Gauntlets - shop after killing AL boss",
"FS: Smough's Leggings - shop after killing AL boss",
"AL: Sun Princess Ring - dark cathedral, after boss",
"FS: Leonhard's Garb - shop after killing Leonhard",
"FS: Leonhard's Gauntlets - shop after killing Leonhard",
"FS: Leonhard's Trousers - shop after killing Leonhard",
}),
DS3BossInfo("Dancer of the Boreal Valley", 3000899, locations = {
"HWL: Soul of the Dancer",
"FS: Dancer's Crown - shop after killing LC entry boss",
"FS: Dancer's Armor - shop after killing LC entry boss",
"FS: Dancer's Gauntlets - shop after killing LC entry boss",
"FS: Dancer's Leggings - shop after killing LC entry boss",
}),
DS3BossInfo("Dragonslayer Armour", 3010800, locations = {
"LC: Soul of Dragonslayer Armour",
"FS: Morne's Helm - shop after killing Eygon or LC boss",
"FS: Morne's Armor - shop after killing Eygon or LC boss",
"FS: Morne's Gauntlets - shop after killing Eygon or LC boss",
"FS: Morne's Leggings - shop after killing Eygon or LC boss",
"LC: Titanite Chunk - down stairs after boss",
}),
DS3BossInfo("Consumed King Oceiros", 3000830, locations = {
"CKG: Soul of Consumed Oceiros",
"CKG: Titanite Scale - tomb, chest #1",
"CKG: Titanite Scale - tomb, chest #2",
"CKG: Drakeblood Helm - tomb, after killing AP mausoleum NPC",
"CKG: Drakeblood Armor - tomb, after killing AP mausoleum NPC",
"CKG: Drakeblood Gauntlets - tomb, after killing AP mausoleum NPC",
"CKG: Drakeblood Leggings - tomb, after killing AP mausoleum NPC",
}),
DS3BossInfo("Champion Gundyr", 4000830, locations = {
"UG: Soul of Champion Gundyr",
"FS: Gundyr's Helm - shop after killing UG boss",
"FS: Gundyr's Armor - shop after killing UG boss",
"FS: Gundyr's Gauntlets - shop after killing UG boss",
"FS: Gundyr's Leggings - shop after killing UG boss",
"UG: Hornet Ring - environs, right of main path after killing FK boss",
"UG: Chaos Blade - environs, left of shrine",
"UG: Blacksmith Hammer - shrine, Andre's room",
"UG: Eyes of a Fire Keeper - shrine, Irina's room",
"UG: Coiled Sword Fragment - shrine, dead bonfire",
"UG: Soul of a Crestfallen Knight - environs, above shrine entrance",
"UG: Life Ring+3 - shrine, behind big throne",
"UG: Ring of Steel Protection+1 - environs, behind bell tower",
"FS: Ring of Sacrifice - Yuria shop",
"UG: Ember - shop",
"UG: Priestess Ring - shop",
"UG: Wolf Knight Helm - shop after killing FK boss",
"UG: Wolf Knight Armor - shop after killing FK boss",
"UG: Wolf Knight Gauntlets - shop after killing FK boss",
"UG: Wolf Knight Leggings - shop after killing FK boss",
}),
DS3BossInfo("Ancient Wyvern", 3200800),
DS3BossInfo("King of the Storm", 3200850, locations = {
"AP: Soul of the Nameless King",
"FS: Golden Crown - shop after killing AP boss",
"FS: Dragonscale Armor - shop after killing AP boss",
"FS: Golden Bracelets - shop after killing AP boss",
"FS: Dragonscale Waistcloth - shop after killing AP boss",
"AP: Titanite Slab - plaza",
"AP: Covetous Gold Serpent Ring+2 - plaza",
"AP: Dragonslayer Helm - plaza",
"AP: Dragonslayer Armor - plaza",
"AP: Dragonslayer Gauntlets - plaza",
"AP: Dragonslayer Leggings - plaza",
}),
DS3BossInfo("Nameless King", 3200851, locations = {
"AP: Soul of the Nameless King",
"FS: Golden Crown - shop after killing AP boss",
"FS: Dragonscale Armor - shop after killing AP boss",
"FS: Golden Bracelets - shop after killing AP boss",
"FS: Dragonscale Waistcloth - shop after killing AP boss",
"AP: Titanite Slab - plaza",
"AP: Covetous Gold Serpent Ring+2 - plaza",
"AP: Dragonslayer Helm - plaza",
"AP: Dragonslayer Armor - plaza",
"AP: Dragonslayer Gauntlets - plaza",
"AP: Dragonslayer Leggings - plaza",
}),
DS3BossInfo("Lothric, Younger Prince", 3410830, locations = {
"GA: Soul of the Twin Princes",
"GA: Cinders of a Lord - Lothric Prince",
}),
DS3BossInfo("Lorian, Elder Prince", 3410832, locations = {
"GA: Soul of the Twin Princes",
"GA: Cinders of a Lord - Lothric Prince",
"FS: Lorian's Helm - shop after killing GA boss",
"FS: Lorian's Armor - shop after killing GA boss",
"FS: Lorian's Gauntlets - shop after killing GA boss",
"FS: Lorian's Leggings - shop after killing GA boss",
}),
DS3BossInfo("Champion's Gravetender and Gravetender Greatwolf", 4500860, dlc = True,
locations = {"PW1: Valorheart - boss drop"}),
DS3BossInfo("Sister Friede", 4500801, dlc = True, locations = {
"PW2: Soul of Sister Friede",
"PW2: Titanite Slab - boss drop",
"PW1: Titanite Slab - Corvian",
"FS: Ordained Hood - shop after killing PW2 boss",
"FS: Ordained Dress - shop after killing PW2 boss",
"FS: Ordained Trousers - shop after killing PW2 boss",
}),
DS3BossInfo("Blackflame Friede", 4500800, dlc = True, locations = {
"PW2: Soul of Sister Friede",
"PW1: Titanite Slab - Corvian",
"FS: Ordained Hood - shop after killing PW2 boss",
"FS: Ordained Dress - shop after killing PW2 boss",
"FS: Ordained Trousers - shop after killing PW2 boss",
}),
DS3BossInfo("Demon Prince", 5000801, dlc = True, locations = {
"DH: Soul of the Demon Prince",
"DH: Small Envoy Banner - boss drop",
}),
DS3BossInfo("Halflight, Spear of the Church", 5100800, dlc = True, locations = {
"RC: Titanite Slab - mid boss drop",
"RC: Titanite Slab - ashes, NPC drop",
"RC: Titanite Slab - ashes, mob drop",
"RC: Filianore's Spear Ornament - mid boss drop",
"RC: Crucifix of the Mad King - ashes, NPC drop",
"RC: Shira's Crown - Shira's room after killing ashes NPC",
"RC: Shira's Armor - Shira's room after killing ashes NPC",
"RC: Shira's Gloves - Shira's room after killing ashes NPC",
"RC: Shira's Trousers - Shira's room after killing ashes NPC",
}),
DS3BossInfo("Darkeater Midir", 5100850, dlc = True, locations = {
"RC: Soul of Darkeater Midir",
"RC: Spears of the Church - hidden boss drop",
}),
DS3BossInfo("Slave Knight Gael 1", 5110801, dlc = True, locations = {
"RC: Soul of Slave Knight Gael",
"RC: Blood of the Dark Soul - end boss drop",
# These are accessible before you trigger the boss, but once you do you
# have to beat it before getting them.
"RC: Titanite Slab - ashes, mob drop",
"RC: Titanite Slab - ashes, NPC drop",
"RC: Sacred Chime of Filianore - ashes, NPC drop",
"RC: Crucifix of the Mad King - ashes, NPC drop",
"RC: Shira's Crown - Shira's room after killing ashes NPC",
"RC: Shira's Armor - Shira's room after killing ashes NPC",
"RC: Shira's Gloves - Shira's room after killing ashes NPC",
"RC: Shira's Trousers - Shira's room after killing ashes NPC",
}),
DS3BossInfo("Slave Knight Gael 2", 5110800, dlc = True, locations = {
"RC: Soul of Slave Knight Gael",
"RC: Blood of the Dark Soul - end boss drop",
# These are accessible before you trigger the boss, but once you do you
# have to beat it before getting them.
"RC: Titanite Slab - ashes, mob drop",
"RC: Titanite Slab - ashes, NPC drop",
"RC: Sacred Chime of Filianore - ashes, NPC drop",
"RC: Crucifix of the Mad King - ashes, NPC drop",
"RC: Shira's Crown - Shira's room after killing ashes NPC",
"RC: Shira's Armor - Shira's room after killing ashes NPC",
"RC: Shira's Gloves - Shira's room after killing ashes NPC",
"RC: Shira's Trousers - Shira's room after killing ashes NPC",
}),
DS3BossInfo("Lords of Cinder", 4100800, locations = {
"KFF: Soul of the Lords",
"FS: Billed Mask - Yuria after killing KFF boss",
"FS: Black Dress - Yuria after killing KFF boss",
"FS: Black Gauntlets - Yuria after killing KFF boss",
"FS: Black Leggings - Yuria after killing KFF boss"
}),
]
default_yhorm_location = DS3BossInfo("Yhorm the Giant", 3900800, locations = {
"PC: Soul of Yhorm the Giant",
"PC: Cinders of a Lord - Yhorm the Giant",
"PC: Siegbräu - Siegward after killing boss",
})

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,80 +1,78 @@
import typing from dataclasses import dataclass
import json
from typing import Any, Dict
from Options import Toggle, DefaultOnToggle, Option, Range, Choice, ItemDict, DeathLink from Options import Choice, DeathLink, DefaultOnToggle, ExcludeLocations, NamedRange, OptionDict, \
OptionGroup, PerGameCommonOptions, Range, Removed, Toggle
## Game Options
class RandomizeWeaponLocations(DefaultOnToggle): class EarlySmallLothricBanner(Choice):
"""Randomizes weapons (+76 locations)""" """Force Small Lothric Banner into an early sphere in your world or across all worlds."""
display_name = "Randomize Weapon Locations" display_name = "Early Small Lothric Banner"
option_off = 0
option_early_global = 1
option_early_local = 2
default = option_off
class RandomizeShieldLocations(DefaultOnToggle): class LateBasinOfVowsOption(Choice):
"""Randomizes shields (+24 locations)""" """Guarantee that you don't need to enter Lothric Castle until later in the run.
display_name = "Randomize Shield Locations"
- **Off:** You may have to enter Lothric Castle and the areas beyond it immediately after High
Wall of Lothric.
- **After Small Lothric Banner:** You may have to enter Lothric Castle after Catacombs of
Carthus.
- **After Small Doll:** You won't have to enter Lothric Castle until after Irithyll of the
Boreal Valley.
"""
display_name = "Late Basin of Vows"
option_off = 0
alias_false = 0
option_after_small_lothric_banner = 1
alias_true = 1
option_after_small_doll = 2
class RandomizeArmorLocations(DefaultOnToggle): class LateDLCOption(Choice):
"""Randomizes armor pieces (+97 locations)""" """Guarantee that you don't need to enter the DLC until later in the run.
display_name = "Randomize Armor Locations"
- **Off:** You may have to enter the DLC after Catacombs of Carthus.
- **After Small Doll:** You may have to enter the DLC after Irithyll of the Boreal Valley.
- **After Basin:** You won't have to enter the DLC until after Lothric Castle.
"""
display_name = "Late DLC"
option_off = 0
alias_false = 0
option_after_small_doll = 1
alias_true = 1
option_after_basin = 2
class RandomizeRingLocations(DefaultOnToggle): class EnableDLCOption(Toggle):
"""Randomizes rings (+49 locations)""" """Include DLC locations, items, and enemies in the randomized pools.
display_name = "Randomize Ring Locations"
To use this option, you must own both the "Ashes of Ariandel" and the "Ringed City" DLCs.
"""
display_name = "Enable DLC"
class RandomizeSpellLocations(DefaultOnToggle): class EnableNGPOption(Toggle):
"""Randomizes spells (+18 locations)""" """Include items and locations exclusive to NG+ cycles."""
display_name = "Randomize Spell Locations" display_name = "Enable NG+"
class RandomizeKeyLocations(DefaultOnToggle): ## Equipment
"""Randomizes items which unlock doors or bypass barriers"""
display_name = "Randomize Key Locations" class RandomizeStartingLoadout(DefaultOnToggle):
"""Randomizes the equipment characters begin with."""
display_name = "Randomize Starting Loadout"
class RandomizeBossSoulLocations(DefaultOnToggle): class RequireOneHandedStartingWeapons(DefaultOnToggle):
"""Randomizes Boss Souls (+18 Locations)""" """Require starting equipment to be usable one-handed."""
display_name = "Randomize Boss Soul Locations" display_name = "Require One-Handed Starting Weapons"
class RandomizeNPCLocations(Toggle):
"""Randomizes friendly NPC drops (meaning you will probably have to kill them) (+14 locations)"""
display_name = "Randomize NPC Locations"
class RandomizeMiscLocations(Toggle):
"""Randomizes miscellaneous items (ashes, tomes, scrolls, etc.) to the pool. (+36 locations)"""
display_name = "Randomize Miscellaneous Locations"
class RandomizeHealthLocations(Toggle):
"""Randomizes health upgrade items. (+21 locations)"""
display_name = "Randomize Health Upgrade Locations"
class RandomizeProgressiveLocationsOption(Toggle):
"""Randomizes upgrade materials and consumables such as the titanite shards, firebombs, resin, etc...
Instead of specific locations, these are progressive, so Titanite Shard #1 is the first titanite shard
you pick up, regardless of whether it's from an enemy drop late in the game or an item on the ground in the
first 5 minutes."""
display_name = "Randomize Progressive Locations"
class PoolTypeOption(Choice):
"""Changes which non-progression items you add to the pool
Shuffle: Items are picked from the locations being randomized
Various: Items are picked from a list of all items in the game, but are the same type of item they replace"""
display_name = "Pool Type"
option_shuffle = 0
option_various = 1
class GuaranteedItemsOption(ItemDict):
"""Guarantees that the specified items will be in the item pool"""
display_name = "Guaranteed Items"
class AutoEquipOption(Toggle): class AutoEquipOption(Toggle):
@ -83,47 +81,56 @@ class AutoEquipOption(Toggle):
class LockEquipOption(Toggle): class LockEquipOption(Toggle):
"""Lock the equipment slots so you cannot change your armor or your left/right weapons. Works great with the """Lock the equipment slots so you cannot change your armor or your left/right weapons.
Auto-equip option."""
Works great with the Auto-equip option.
"""
display_name = "Lock Equipment Slots" display_name = "Lock Equipment Slots"
class NoEquipLoadOption(Toggle):
"""Disable the equip load constraint from the game."""
display_name = "No Equip Load"
class NoWeaponRequirementsOption(Toggle): class NoWeaponRequirementsOption(Toggle):
"""Disable the weapon requirements by removing any movement or damage penalties. """Disable the weapon requirements by removing any movement or damage penalties, permitting you
Permitting you to use any weapon early""" to use any weapon early.
"""
display_name = "No Weapon Requirements" display_name = "No Weapon Requirements"
class NoSpellRequirementsOption(Toggle): class NoSpellRequirementsOption(Toggle):
"""Disable the spell requirements permitting you to use any spell""" """Disable the spell requirements permitting you to use any spell."""
display_name = "No Spell Requirements" display_name = "No Spell Requirements"
class NoEquipLoadOption(Toggle): ## Weapons
"""Disable the equip load constraint from the game"""
display_name = "No Equip Load"
class RandomizeInfusionOption(Toggle): class RandomizeInfusionOption(Toggle):
"""Enable this option to infuse a percentage of the pool of weapons and shields.""" """Enable this option to infuse a percentage of the pool of weapons and shields."""
display_name = "Randomize Infusion" display_name = "Randomize Infusion"
class RandomizeInfusionPercentageOption(Range): class RandomizeInfusionPercentageOption(NamedRange):
"""The percentage of weapons/shields in the pool to be infused if Randomize Infusion is toggled""" """The percentage of weapons/shields in the pool to be infused if Randomize Infusion is toggled.
"""
display_name = "Percentage of Infused Weapons" display_name = "Percentage of Infused Weapons"
range_start = 0 range_start = 0
range_end = 100 range_end = 100
default = 33 default = 33
# 3/155 weapons are infused in the base game, or about 2%
special_range_names = {"similar to base game": 2}
class RandomizeWeaponLevelOption(Choice): class RandomizeWeaponLevelOption(Choice):
"""Enable this option to upgrade a percentage of the pool of weapons to a random value between the minimum and """Enable this option to upgrade a percentage of the pool of weapons to a random value between
maximum levels defined. the minimum and maximum levels defined.
All: All weapons are eligible, both basic and epic - **All:** All weapons are eligible, both basic and epic
Basic: Only weapons that can be upgraded to +10 - **Basic:** Only weapons that can be upgraded to +10
Epic: Only weapons that can be upgraded to +5""" - **Epic:** Only weapons that can be upgraded to +5
"""
display_name = "Randomize Weapon Level" display_name = "Randomize Weapon Level"
option_none = 0 option_none = 0
option_all = 1 option_all = 1
@ -132,7 +139,7 @@ class RandomizeWeaponLevelOption(Choice):
class RandomizeWeaponLevelPercentageOption(Range): class RandomizeWeaponLevelPercentageOption(Range):
"""The percentage of weapons in the pool to be upgraded if randomize weapons level is toggled""" """The percentage of weapons in the pool to be upgraded if randomize weapons level is toggled."""
display_name = "Percentage of Randomized Weapons" display_name = "Percentage of Randomized Weapons"
range_start = 0 range_start = 0
range_end = 100 range_end = 100
@ -140,7 +147,7 @@ class RandomizeWeaponLevelPercentageOption(Range):
class MinLevelsIn5WeaponPoolOption(Range): class MinLevelsIn5WeaponPoolOption(Range):
"""The minimum upgraded value of a weapon in the pool of weapons that can only reach +5""" """The minimum upgraded value of a weapon in the pool of weapons that can only reach +5."""
display_name = "Minimum Level of +5 Weapons" display_name = "Minimum Level of +5 Weapons"
range_start = 0 range_start = 0
range_end = 5 range_end = 5
@ -148,7 +155,7 @@ class MinLevelsIn5WeaponPoolOption(Range):
class MaxLevelsIn5WeaponPoolOption(Range): class MaxLevelsIn5WeaponPoolOption(Range):
"""The maximum upgraded value of a weapon in the pool of weapons that can only reach +5""" """The maximum upgraded value of a weapon in the pool of weapons that can only reach +5."""
display_name = "Maximum Level of +5 Weapons" display_name = "Maximum Level of +5 Weapons"
range_start = 0 range_start = 0
range_end = 5 range_end = 5
@ -156,7 +163,7 @@ class MaxLevelsIn5WeaponPoolOption(Range):
class MinLevelsIn10WeaponPoolOption(Range): class MinLevelsIn10WeaponPoolOption(Range):
"""The minimum upgraded value of a weapon in the pool of weapons that can reach +10""" """The minimum upgraded value of a weapon in the pool of weapons that can reach +10."""
display_name = "Minimum Level of +10 Weapons" display_name = "Minimum Level of +10 Weapons"
range_start = 0 range_start = 0
range_end = 10 range_end = 10
@ -164,72 +171,308 @@ class MinLevelsIn10WeaponPoolOption(Range):
class MaxLevelsIn10WeaponPoolOption(Range): class MaxLevelsIn10WeaponPoolOption(Range):
"""The maximum upgraded value of a weapon in the pool of weapons that can reach +10""" """The maximum upgraded value of a weapon in the pool of weapons that can reach +10."""
display_name = "Maximum Level of +10 Weapons" display_name = "Maximum Level of +10 Weapons"
range_start = 0 range_start = 0
range_end = 10 range_end = 10
default = 10 default = 10
class EarlySmallLothricBanner(Choice): ## Item Smoothing
"""This option makes it so the user can choose to force the Small Lothric Banner into an early sphere in their world or
into an early sphere across all worlds.""" class SmoothSoulItemsOption(DefaultOnToggle):
display_name = "Early Small Lothric Banner" """Distribute soul items in a similar order as the base game.
option_off = 0
option_early_global = 1 By default, soul items will be distributed totally randomly. If this is set, less valuable soul
option_early_local = 2 items will generally appear in earlier spheres and more valuable ones will generally appear
default = option_off later.
"""
display_name = "Smooth Soul Items"
class LateBasinOfVowsOption(Toggle): class SmoothUpgradeItemsOption(DefaultOnToggle):
"""This option makes it so the Basin of Vows is still randomized, but guarantees you that you wont have to venture into """Distribute upgrade items in a similar order as the base game.
Lothric Castle to find your Small Lothric Banner to get out of High Wall of Lothric. So you may find Basin of Vows early,
but you wont have to fight Dancer to find your Small Lothric Banner.""" By default, upgrade items will be distributed totally randomly. If this is set, lower-level
display_name = "Late Basin of Vows" upgrade items will generally appear in earlier spheres and higher-level ones will generally
appear later.
"""
display_name = "Smooth Upgrade Items"
class LateDLCOption(Toggle): class SmoothUpgradedWeaponsOption(DefaultOnToggle):
"""This option makes it so you are guaranteed to find your Small Doll without having to venture off into the DLC, """Distribute upgraded weapons in a similar order as the base game.
effectively putting anything in the DLC in logic after finding both Contraption Key and Small Doll,
and being able to get into Irithyll of the Boreal Valley.""" By default, upgraded weapons will be distributed totally randomly. If this is set, lower-level
display_name = "Late DLC" weapons will generally appear in earlier spheres and higher-level ones will generally appear
later.
"""
display_name = "Smooth Upgraded Weapons"
class EnableDLCOption(Toggle): ### Enemies
"""To use this option, you must own both the ASHES OF ARIANDEL and the RINGED CITY DLC"""
display_name = "Enable DLC" class RandomizeEnemiesOption(DefaultOnToggle):
"""Randomize enemy and boss placements."""
display_name = "Randomize Enemies"
dark_souls_options: typing.Dict[str, Option] = { class SimpleEarlyBossesOption(DefaultOnToggle):
"enable_weapon_locations": RandomizeWeaponLocations, """Avoid replacing Iudex Gundyr and Vordt with late bosses.
"enable_shield_locations": RandomizeShieldLocations,
"enable_armor_locations": RandomizeArmorLocations, This excludes all bosses after Dancer of the Boreal Valley from these two boss fights. Disable
"enable_ring_locations": RandomizeRingLocations, it for a chance at a much harder early game.
"enable_spell_locations": RandomizeSpellLocations,
"enable_key_locations": RandomizeKeyLocations, This is ignored unless enemies are randomized.
"enable_boss_locations": RandomizeBossSoulLocations, """
"enable_npc_locations": RandomizeNPCLocations, display_name = "Simple Early Bosses"
"enable_misc_locations": RandomizeMiscLocations,
"enable_health_upgrade_locations": RandomizeHealthLocations,
"enable_progressive_locations": RandomizeProgressiveLocationsOption, class ScaleEnemiesOption(DefaultOnToggle):
"pool_type": PoolTypeOption, """Scale randomized enemy stats to match the areas in which they appear.
"guaranteed_items": GuaranteedItemsOption,
"auto_equip": AutoEquipOption, Disabling this will tend to make the early game much more difficult and the late game much
"lock_equip": LockEquipOption, easier.
"no_weapon_requirements": NoWeaponRequirementsOption,
"randomize_infusion": RandomizeInfusionOption, This is ignored unless enemies are randomized.
"randomize_infusion_percentage": RandomizeInfusionPercentageOption, """
"randomize_weapon_level": RandomizeWeaponLevelOption, display_name = "Scale Enemies"
"randomize_weapon_level_percentage": RandomizeWeaponLevelPercentageOption,
"min_levels_in_5": MinLevelsIn5WeaponPoolOption,
"max_levels_in_5": MaxLevelsIn5WeaponPoolOption, class RandomizeMimicsWithEnemiesOption(Toggle):
"min_levels_in_10": MinLevelsIn10WeaponPoolOption, """Mix Mimics into the main enemy pool.
"max_levels_in_10": MaxLevelsIn10WeaponPoolOption,
"early_banner": EarlySmallLothricBanner, If this is enabled, Mimics will be replaced by normal enemies who drop the Mimic rewards on
"late_basin_of_vows": LateBasinOfVowsOption, death, and Mimics will be placed randomly in place of normal enemies. It's recommended to enable
"late_dlc": LateDLCOption, Impatient Mimics as well if you enable this.
"no_spell_requirements": NoSpellRequirementsOption,
"no_equip_load": NoEquipLoadOption, This is ignored unless enemies are randomized.
"death_link": DeathLink, """
"enable_dlc": EnableDLCOption, display_name = "Randomize Mimics With Enemies"
}
class RandomizeSmallCrystalLizardsWithEnemiesOption(Toggle):
"""Mix small Crystal Lizards into the main enemy pool.
If this is enabled, Crystal Lizards will be replaced by normal enemies who drop the Crystal
Lizard rewards on death, and Crystal Lizards will be placed randomly in place of normal enemies.
This is ignored unless enemies are randomized.
"""
display_name = "Randomize Small Crystal Lizards With Enemies"
class ReduceHarmlessEnemiesOption(Toggle):
"""Reduce the frequency that "harmless" enemies appear.
Enable this to add a bit of extra challenge. This severely limits the number of enemies that are
slow to aggro, slow to attack, and do very little damage that appear in the enemy pool.
This is ignored unless enemies are randomized.
"""
display_name = "Reduce Harmless Enemies"
class AllChestsAreMimicsOption(Toggle):
"""Replace all chests with mimics that drop the same items.
If "Randomize Mimics With Enemies" is set, these chests will instead be replaced with random
enemies that drop the same items.
This is ignored unless enemies are randomized.
"""
display_name = "All Chests Are Mimics"
class ImpatientMimicsOption(Toggle):
"""Mimics attack as soon as you get close instead of waiting for you to open them.
This is ignored unless enemies are randomized.
"""
display_name = "Impatient Mimics"
class RandomEnemyPresetOption(OptionDict):
"""The YAML preset for the static enemy randomizer.
See the static randomizer documentation in `randomizer\\presets\\README.txt` for details.
Include this as nested YAML. For example:
.. code-block:: YAML
random_enemy_preset:
RemoveSource: Ancient Wyvern; Darkeater Midir
DontRandomize: Iudex Gundyr
"""
display_name = "Random Enemy Preset"
supports_weighting = False
default = {}
valid_keys = ["Description", "RecommendFullRandomization", "RecommendNoEnemyProgression",
"OopsAll", "Boss", "Miniboss", "Basic", "BuffBasicEnemiesAsBosses",
"DontRandomize", "RemoveSource", "Enemies"]
@classmethod
def get_option_name(cls, value: Dict[str, Any]) -> str:
return json.dumps(value)
## Item & Location
class DS3ExcludeLocations(ExcludeLocations):
"""Prevent these locations from having an important item."""
default = frozenset({"Hidden", "Small Crystal Lizards", "Upgrade", "Small Souls", "Miscellaneous"})
class ExcludedLocationBehaviorOption(Choice):
"""How to choose items for excluded locations in DS3.
- **Allow Useful:** Excluded locations can't have progression items, but they can have useful
items.
- **Forbid Useful:** Neither progression items nor useful items can be placed in excluded
locations.
- **Do Not Randomize:** Excluded locations always contain the same item as in vanilla Dark Souls
III.
A "progression item" is anything that's required to unlock another location in some game. A
"useful item" is something each game defines individually, usually items that are quite
desirable but not strictly necessary.
"""
display_name = "Excluded Locations Behavior"
option_allow_useful = 1
option_forbid_useful = 2
option_do_not_randomize = 3
default = 2
class MissableLocationBehaviorOption(Choice):
"""Which items can be placed in locations that can be permanently missed.
- **Allow Useful:** Missable locations can't have progression items, but they can have useful
items.
- **Forbid Useful:** Neither progression items nor useful items can be placed in missable
locations.
- **Do Not Randomize:** Missable locations always contain the same item as in vanilla Dark Souls
III.
A "progression item" is anything that's required to unlock another location in some game. A
"useful item" is something each game defines individually, usually items that are quite
desirable but not strictly necessary.
"""
display_name = "Missable Locations Behavior"
option_allow_useful = 1
option_forbid_useful = 2
option_do_not_randomize = 3
default = 2
@dataclass
class DarkSouls3Options(PerGameCommonOptions):
# Game Options
early_banner: EarlySmallLothricBanner
late_basin_of_vows: LateBasinOfVowsOption
late_dlc: LateDLCOption
death_link: DeathLink
enable_dlc: EnableDLCOption
enable_ngp: EnableNGPOption
# Equipment
random_starting_loadout: RandomizeStartingLoadout
require_one_handed_starting_weapons: RequireOneHandedStartingWeapons
auto_equip: AutoEquipOption
lock_equip: LockEquipOption
no_equip_load: NoEquipLoadOption
no_weapon_requirements: NoWeaponRequirementsOption
no_spell_requirements: NoSpellRequirementsOption
# Weapons
randomize_infusion: RandomizeInfusionOption
randomize_infusion_percentage: RandomizeInfusionPercentageOption
randomize_weapon_level: RandomizeWeaponLevelOption
randomize_weapon_level_percentage: RandomizeWeaponLevelPercentageOption
min_levels_in_5: MinLevelsIn5WeaponPoolOption
max_levels_in_5: MaxLevelsIn5WeaponPoolOption
min_levels_in_10: MinLevelsIn10WeaponPoolOption
max_levels_in_10: MaxLevelsIn10WeaponPoolOption
# Item Smoothing
smooth_soul_items: SmoothSoulItemsOption
smooth_upgrade_items: SmoothUpgradeItemsOption
smooth_upgraded_weapons: SmoothUpgradedWeaponsOption
# Enemies
randomize_enemies: RandomizeEnemiesOption
simple_early_bosses: SimpleEarlyBossesOption
scale_enemies: ScaleEnemiesOption
randomize_mimics_with_enemies: RandomizeMimicsWithEnemiesOption
randomize_small_crystal_lizards_with_enemies: RandomizeSmallCrystalLizardsWithEnemiesOption
reduce_harmless_enemies: ReduceHarmlessEnemiesOption
all_chests_are_mimics: AllChestsAreMimicsOption
impatient_mimics: ImpatientMimicsOption
random_enemy_preset: RandomEnemyPresetOption
# Item & Location
exclude_locations: DS3ExcludeLocations
excluded_location_behavior: ExcludedLocationBehaviorOption
missable_location_behavior: MissableLocationBehaviorOption
# Removed
pool_type: Removed
enable_weapon_locations: Removed
enable_shield_locations: Removed
enable_armor_locations: Removed
enable_ring_locations: Removed
enable_spell_locations: Removed
enable_key_locations: Removed
enable_boss_locations: Removed
enable_npc_locations: Removed
enable_misc_locations: Removed
enable_health_upgrade_locations: Removed
enable_progressive_locations: Removed
guaranteed_items: Removed
excluded_locations: Removed
missable_locations: Removed
option_groups = [
OptionGroup("Equipment", [
RandomizeStartingLoadout,
RequireOneHandedStartingWeapons,
AutoEquipOption,
LockEquipOption,
NoEquipLoadOption,
NoWeaponRequirementsOption,
NoSpellRequirementsOption,
]),
OptionGroup("Weapons", [
RandomizeInfusionOption,
RandomizeInfusionPercentageOption,
RandomizeWeaponLevelOption,
RandomizeWeaponLevelPercentageOption,
MinLevelsIn5WeaponPoolOption,
MaxLevelsIn5WeaponPoolOption,
MinLevelsIn10WeaponPoolOption,
MaxLevelsIn10WeaponPoolOption,
]),
OptionGroup("Item Smoothing", [
SmoothSoulItemsOption,
SmoothUpgradeItemsOption,
SmoothUpgradedWeaponsOption,
]),
OptionGroup("Enemies", [
RandomizeEnemiesOption,
SimpleEarlyBossesOption,
ScaleEnemiesOption,
RandomizeMimicsWithEnemiesOption,
RandomizeSmallCrystalLizardsWithEnemiesOption,
ReduceHarmlessEnemiesOption,
AllChestsAreMimicsOption,
ImpatientMimicsOption,
RandomEnemyPresetOption,
]),
OptionGroup("Item & Location Options", [
DS3ExcludeLocations,
ExcludedLocationBehaviorOption,
MissableLocationBehaviorOption,
])
]

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,97 @@
# python -m worlds.dark_souls_3.detailed_location_descriptions \
# worlds/dark_souls_3/detailed_location_descriptions.py
#
# This script downloads the static randomizer's descriptions for each location and adds them to
# the location documentation.
from collections import defaultdict
import html
import os
import re
import requests
import yaml
from .Locations import location_dictionary
location_re = re.compile(r'^([A-Z0-9]+): (.*?)(?:$| - )')
if __name__ == '__main__':
# TODO: update this to the main branch of the main randomizer once Archipelago support is merged
url = 'https://raw.githubusercontent.com/nex3/SoulsRandomizers/archipelago-server/dist/Base/annotations.txt'
response = requests.get(url)
if response.status_code != 200:
raise Exception(f"Got {response.status_code} when downloading static randomizer locations")
annotations = yaml.load(response.text, Loader=yaml.Loader)
static_to_archi_regions = {
area['Name']: area['Archipelago']
for area in annotations['Areas']
}
descriptions_by_key = {slot['Key']: slot['Text'] for slot in annotations['Slots']}
# A map from (region, item name) pairs to all the descriptions that match those pairs.
descriptions_by_location = defaultdict(list)
# A map from item names to all the descriptions for those item names.
descriptions_by_item = defaultdict(list)
for slot in annotations['Slots']:
region = static_to_archi_regions[slot['Area']]
for item in slot['DebugText']:
name = item.split(" - ")[0]
descriptions_by_location[(region, name)].append(slot['Text'])
descriptions_by_item[name].append(slot['Text'])
counts_by_location = {
location: len(descriptions) for (location, descriptions) in descriptions_by_location.items()
}
location_names_to_descriptions = {}
for location in location_dictionary.values():
if location.ap_code is None: continue
if location.static:
location_names_to_descriptions[location.name] = descriptions_by_key[location.static]
continue
match = location_re.match(location.name)
if not match:
raise Exception(f"Location name \"{location.name}\" doesn't match expected format.")
item_candidates = descriptions_by_item[match[2]]
if len(item_candidates) == 1:
location_names_to_descriptions[location.name] = item_candidates[0]
continue
key = (match[1], match[2])
if key not in descriptions_by_location:
raise Exception(f'No static randomizer location found matching "{match[1]}: {match[2]}".')
candidates = descriptions_by_location[key]
if len(candidates) == 0:
raise Exception(
f'There are only {counts_by_location[key]} locations in the static randomizer ' +
f'matching "{match[1]}: {match[2]}", but there are more in Archipelago.'
)
location_names_to_descriptions[location.name] = candidates.pop(0)
table = "<table><tr><th>Location name</th><th>Detailed description</th>\n"
for (name, description) in sorted(
location_names_to_descriptions.items(),
key = lambda pair: pair[0]
):
table += f"<tr><td>{html.escape(name)}</td><td>{html.escape(description)}</td></tr>\n"
table += "</table>\n"
with open(os.path.join(os.path.dirname(__file__), 'docs/locations_en.md'), 'r+') as f:
original = f.read()
start_flag = "<!-- begin location table -->\n"
start = original.index(start_flag) + len(start_flag)
end = original.index("<!-- end location table -->")
f.seek(0)
f.write(original[:start] + table + original[end:])
f.truncate()
print("Updated docs/locations_en.md!")

View File

@ -1,28 +1,201 @@
# Dark Souls III # Dark Souls III
Game Page | [Items] | [Locations]
[Items]: /tutorial/Dark%20Souls%20III/items/en
[Locations]: /tutorial/Dark%20Souls%20III/locations/en
## What do I need to do to randomize DS3?
See full instructions on [the setup page].
[the setup page]: /tutorial/Dark%20Souls%20III/setup/en
## Where is the options page? ## Where is the options page?
The [player options page for this game](../player-options) contains all the options you need to configure and export a The [player options page for this game][options] contains all the options you
config file. need to configure and export a config file.
[options]: ../player-options
## What does randomization do to this game? ## What does randomization do to this game?
Items that can be picked up from static corpses, taken from chests, or earned from defeating enemies or NPCs can be 1. All item locations are randomized, including those in the overworld, in
randomized. Common pickups like titanite shards or firebombs can be randomized as "progressive" items. That is, the shops, and dropped by enemies. Most locations can contain games from other
location "Titanite Shard #5" is the fifth titanite shard you pick up, no matter where it was from. This is also what worlds, and any items from your world can appear in other players' worlds.
happens when you randomize Estus Shards and Undead Bone Shards.
It's also possible to randomize the upgrade level of weapons and shields as well as their infusions (if they can have 2. By default, all enemies and bosses are randomized. This can be disabled by
one). Additionally, there are options that can make the randomized experience more convenient or more interesting, such as setting "Randomize Enemies" to false.
removing weapon requirements or auto-equipping whatever equipment you most recently received.
The goal is to find the four "Cinders of a Lord" items randomized into the multiworld and defeat the Soul of Cinder. 3. By default, the starting equipment for each class is randomized. This can be
disabled by setting "Randomize Starting Loadout" to false.
## What Dark Souls III items can appear in other players' worlds? 4. By setting the "Randomize Weapon Level" or "Randomize Infusion" options, you
can randomize whether the weapons you find will be upgraded or infused.
Practically anything can be found in other worlds including pieces of armor, upgraded weapons, key items, consumables, There are also options that can make playing the game more convenient or
spells, upgrade materials, etc... bring a new experience, like removing equip loads or auto-equipping weapons as
you pick them up. Check out [the options page][options] for more!
## What does another world's item look like in Dark Souls III? ## What's the goal?
In Dark Souls III, items which are sent to other worlds appear as Prism Stones. Your goal is to find the four "Cinders of a Lord" items randomized into the
multiworld and defeat the boss in the Kiln of the First Flame.
## Do I have to check every item in every area?
Dark Souls III has about 1500 item locations, which is a lot of checks for a
single run! But you don't necessarily need to check all of them. Locations that
you can potentially miss, such as rewards for failable quests or soul
transposition items, will _never_ have items required for any game to progress.
The following types of locations are also guaranteed not to contain progression
items by default:
* **Hidden:** Locations that are particularly difficult to find, such as behind
illusory walls, down hidden drops, and so on. Does not include large locations
like Untended Graves or Archdragon Peak.
* **Small Crystal Lizards:** Drops from small crystal lizards.
* **Upgrade:** Locations that contain upgrade items in vanilla, including
titanite, gems, and Shriving Stones.
* **Small Souls:** Locations that contain soul items in vanilla, not including
boss souls.
* **Miscellaneous:** Locations that contain generic stackable items in vanilla,
such as arrows, firebombs, buffs, and so on.
You can customize which locations are guaranteed not to contain progression
items by setting the `exclude_locations` field in your YAML to the [location
groups] you want to omit. For example, this is the default setting but without
"Hidden" so that hidden locations can contain progression items:
[location groups]: /tutorial/Dark%20Souls%20III/locations/en#location-groups
```yaml
Dark Souls III:
exclude_locations:
- Small Crystal Lizards
- Upgrade
- Small Souls
- Miscellaneous
```
This allows _all_ non-missable locations to have progression items, if you're in
for the long haul:
```yaml
Dark Souls III:
exclude_locations: []
```
## What if I don't want to do the whole game?
If you want a shorter DS3 randomizer experience, you can exclude entire regions
from containing progression items. The items and enemies from those regions will
still be included in the randomization pool, but none of them will be mandatory.
For example, the following configuration just requires you to play the game
through Irithyll of the Boreal Valley:
```yaml
Dark Souls III:
# Enable the DLC so it's included in the randomization pool
enable_dlc: true
exclude_locations:
# Exclude late-game and DLC regions
- Anor Londo
- Lothric Castle
- Consumed King's Garden
- Untended Graves
- Grand Archives
- Archdragon Peak
- Painted World of Ariandel
- Dreg Heap
- Ringed City
# Default exclusions
- Hidden
- Small Crystal Lizards
- Upgrade
- Small Souls
- Miscellaneous
```
## Where can I learn more about Dark Souls III locations?
Location names have to pack a lot of information into very little space. To
better understand them, check out the [location guide], which explains all the
names used in locations and provides more detailed descriptions for each
individual location.
[location guide]: /tutorial/Dark%20Souls%20III/locations/en
## Where can I learn more about Dark Souls III items?
Check out the [item guide], which explains the named groups available for items.
[item guide]: /tutorial/Dark%20Souls%20III/items/en
## What's new from 2.x.x?
Version 3.0.0 of the Dark Souls III Archipelago client has a number of
substantial differences with the older 2.x.x versions. Improvements include:
* Support for randomizing all item locations, not just unique items.
* Support for randomizing items in shops, starting loadouts, Path of the Dragon,
and more.
* Built-in integration with the enemy randomizer, including consistent seeding
for races.
* Support for the latest patch for Dark Souls III, 1.15.2. Older patches are
*not* supported.
* Optional smooth distribution for upgrade items, upgraded weapons, and soul
items so you're more likely to see weaker items earlier and more powerful
items later.
* More detailed location names that indicate where a location is, not just what
it replaces.
* Other players' item names are visible in DS3.
* If you pick up items while static, they'll still send once you reconnect.
However, 2.x.x YAMLs are not compatible with 3.0.0. You'll need to [generate a
new YAML configuration] for use with 3.x.x.
[generating a new YAML configuration]: /games/Dark%20Souls%20III/player-options
The following options have been removed:
* `enable_boss_locations` is now controlled by the `soul_locations` option.
* `enable_progressive_locations` was removed because all locations are now
individually randomized rather than replaced with a progressive list.
* `pool_type` has been removed. Since there are no longer any non-randomized
items in randomized categories, there's not a meaningful distinction between
"shuffle" and "various" mode.
* `enable_*_locations` options have all been removed. Instead, you can now add
[location group names] to the `exclude_locations` option to prevent them from
containing important items.
[location group names]: /tutorial/Dark%20Souls%20III/locations/en#location-groups
By default, the Hidden, Small Crystal Lizards, Upgrade, Small Souls, and
Miscellaneous groups are in `exclude_locations`. Once you've chosen your
excluded locations, you can set `excluded_locations: unrandomized` to preserve
the default vanilla item placements for all excluded locations.
* `guaranteed_items`: In almost all cases, all items from the base game are now
included somewhere in the multiworld.
In addition, the following options have changed:
* The location names used in options like `exclude_locations` have changed. See
the [location guide] for a full description.

View File

@ -0,0 +1,24 @@
# Dark Souls III Items
[Game Page] | Items | [Locations]
[Game Page]: /games/Dark%20Souls%20III/info/en
[Locations]: /tutorial/Dark%20Souls%20III/locations/en
## Item Groups
The Dark Souls III randomizer supports a number of item group names, which can
be used in YAML options like `local_items` to refer to many items at once:
* **Progression:** Items which unlock locations.
* **Cinders:** All four Cinders of a Lord. Once you have these four, you can
fight Soul of Cinder and win the game.
* **Miscellaneous:** Generic stackable items, such as arrows, firebombs, buffs,
and so on.
* **Unique:** Items that are unique per NG cycle, such as scrolls, keys, ashes,
and so on. Doesn't include equipment, spells, or souls.
* **Boss Souls:** Souls that can be traded with Ludleth, including Soul of
Rosaria.
* **Small Souls:** Soul items, not including boss souls.
* **Upgrade:** Upgrade items, including titanite, gems, and Shriving Stones.
* **Healing:** Undead Bone Shards and Estus Shards.

File diff suppressed because it is too large Load Diff

View File

@ -7,48 +7,49 @@
## Optional Software ## Optional Software
- [Dark Souls III Maptracker Pack](https://github.com/Br00ty/DS3_AP_Maptracker/releases/latest), for use with [Poptracker](https://github.com/black-sliver/PopTracker/releases) - Map tracker not yet updated for 3.0.0
## General Concept ## Setting Up
<span style="color:#ff7800"> First, download the client from the link above. It doesn't need to go into any particular directory;
**This mod can ban you permanently from the FromSoftware servers if used online.** it'll automatically locate _Dark Souls III_ in your Steam installation folder.
</span>
The Dark Souls III AP Client is a dinput8.dll triggered when launching Dark Souls III. This .dll file will launch a command
prompt where you can read information about your run and write any command to interact with the Archipelago server.
This client has only been tested with the Official Steam version of the game at version 1.15. It does not matter which DLCs are installed. However, you will have to downpatch your Dark Souls III installation from current patch. Version 3.0.0 of the randomizer _only_ supports the latest version of _Dark Souls III_, 1.15.2. This
is the latest version, so you don't need to do any downpatching! However, if you've already
downpatched your game to use an older version of the randomizer, you'll need to reinstall the latest
version before using this version.
## Downpatching Dark Souls III ### One-Time Setup
To downpatch DS3 for use with Archipelago, use the following instructions from the speedsouls wiki database. Before you first connect to a multiworld, you need to generate the local data files for your world's
randomized item and (optionally) enemy locations. You only need to do this once per multiworld.
1. Launch Steam (in online mode). 1. Before you first connect to a multiworld, run `randomizer\DS3Randomizer.exe`.
2. Press the Windows Key + R. This will open the Run window.
3. Open the Steam console by typing the following string: `steam://open/console`. Steam should now open in Console Mode.
4. Insert the string of the depot you wish to download. For the AP-supported v1.15, you will want to use: `download_depot 374320 374321 4471176929659548333`.
5. Steam will now download the depot. Note: There is no progress bar for the download in Steam, but it is still downloading in the background.
6. Back up your existing game executable (`DarkSoulsIII.exe`) found in `\Steam\steamapps\common\DARK SOULS III\Game`. Easiest way to do this is to move it to another directory. If you have file extensions enabled, you can instead rename the executable to `DarkSoulsIII.exe.bak`.
7. Return to the Steam console. Once the download is complete, it should say so along with the temporary local directory in which the depot has been stored. This is usually something like `\Steam\steamapps\content\app_XXXXXX\depot_XXXXXX`.
8. Take the `DarkSoulsIII.exe` from that folder and place it in `\Steam\steamapps\common\DARK SOULS III\Game`.
9. Back up and delete your save file (`DS30000.sl2`) in AppData. AppData is hidden by default. To locate it, press Windows Key + R, type `%appdata%` and hit enter. Alternatively: open File Explorer > View > Hidden Items and follow `C:\Users\<your_username>\AppData\Roaming\DarkSoulsIII\<numbers>`.
10. If you did all these steps correctly, you should be able to confirm your game version in the upper-left corner after launching Dark Souls III.
2. Put in your Archipelago room address (usually something like `archipelago.gg:12345`), your player
name (also known as your "slot name"), and your password if you have one.
## Installing the Archipelago mod 3. Click "Load" and wait a minute or two.
Get the `dinput8.dll` from the [Dark Souls III AP Client](https://github.com/Marechal-L/Dark-Souls-III-Archipelago-client/releases) and ### Running and Connecting the Game
add it at the root folder of your game (e.g. `SteamLibrary\steamapps\common\DARK SOULS III\Game`)
## Joining a MultiWorld Game To run _Dark Souls III_ in Archipelago mode:
1. Run Steam in offline mode to avoid being banned. 1. Start Steam. **Do not run in offline mode.** The mod will make sure you don't connect to the
2. Launch Dark Souls III. DS3 servers, and running Steam in offline mode will make certain scripted invaders fail to spawn.
3. Type in `/connect {SERVER_IP}:{SERVER_PORT} {SLOT_NAME} password:{PASSWORD}` in the "Windows Command Prompt" that opened. For example: `/connect archipelago.gg:38281 "Example Name" password:"Example Password"`. The password parameter is only necessary if your game requires one.
4. Once connected, create a new game, choose a class and wait for the others before starting.
5. You can quit and launch at anytime during a game.
## Where do I get a config file? 2. Run `launchmod_darksouls3.bat`. This will start _Dark Souls III_ as well as a command prompt that
you can use to interact with the Archipelago server.
3. Type `/connect {SERVER_IP}:{SERVER_PORT} {SLOT_NAME}` into the command prompt, with the
appropriate values filled in. For example: `/connect archipelago.gg:24242 PlayerName`.
4. Start playing as normal. An "Archipelago connected" message will appear onscreen once you have
control of your character and the connection is established.
## Frequently Asked Questions
### Where do I get a config file?
The [Player Options](/games/Dark%20Souls%20III/player-options) page on the website allows you to The [Player Options](/games/Dark%20Souls%20III/player-options) page on the website allows you to
configure your personal options and export them into a config file. configure your personal options and export them into a config file.

View File

@ -0,0 +1,27 @@
from test.TestBase import WorldTestBase
from worlds.dark_souls_3.Items import item_dictionary
from worlds.dark_souls_3.Locations import location_tables
from worlds.dark_souls_3.Bosses import all_bosses
class DarkSouls3Test(WorldTestBase):
game = "Dark Souls III"
def testLocationDefaultItems(self):
for locations in location_tables.values():
for location in locations:
if location.default_item_name:
self.assertIn(location.default_item_name, item_dictionary)
def testLocationsUnique(self):
names = set()
for locations in location_tables.values():
for location in locations:
self.assertNotIn(location.name, names)
names.add(location.name)
def testBossLocations(self):
all_locations = {location.name for locations in location_tables.values() for location in locations}
for boss in all_bosses:
for location in boss.locations:
self.assertIn(location, all_locations)

View File