DS: Clean the code and fix "Late Basin of Vows" option

This commit is contained in:
Marechal-l
2022-07-12 12:24:16 +02:00
parent a025beac4e
commit fce87e34c6
7 changed files with 100 additions and 96 deletions

View File

@@ -4,7 +4,6 @@ from worlds.dark_souls_3.data.items_data import item_dictionary_table
class DarkSouls3Item(Item):
game: str = "Dark Souls III"
@staticmethod
def get_item_name_to_id() -> typing.Dict[str, int]:

View File

@@ -8,12 +8,6 @@ class LocationData(int):
class DarkSouls3Location(Location):
game: str = "Dark Souls III"
# override constructor to automatically mark event locations as such
def __init__(self, player: int, name='', code=None, parent=None):
super(DarkSouls3Location, self).__init__(player, name, code, parent)
self.event = code is None
@staticmethod
def get_location_name_to_id() -> typing.Dict[str, int]:

View File

@@ -1,16 +0,0 @@
# Dark Souls in [Archipelago](https://archipelago.gg)
## Abstract
- Extract the list of items (Weapons, Armors, KeyItems and Goods)
- Hardcode this list along rules on the Archipelago server
- The Archipelago server will shuffle and create a specific file for the Dark Souls client
- This file or seed will place the items to their locations
## Prerequisities
- onItemPicked event

View File

@@ -44,15 +44,19 @@ class DarkSouls3World(World):
def create_item(self, name: str) -> Item:
data = self.item_name_to_id[name]
return DarkSouls3Item(name, ItemClassification.progression if name in key_items_list else ItemClassification.useful, data, self.player)
return DarkSouls3Item(
name, ItemClassification.progression if name in key_items_list else
ItemClassification.useful, data, self.player)
def create_regions(self):
menu_region = Region("Menu", RegionType.Generic, "Menu", self.player)
self.world.regions.append(menu_region)
# Create all Vanilla regions of Dark Souls 3
cemetery_of_ash_region = self.create_region("Cemetery Of Ash", cemetery_of_ash_table)
firelink_shrine_region = self.create_region("Firelink Shrine", fire_link_shrine_table)
firelink_shrine_bell_tower_region = self.create_region("Firelink Shrine Bell Tower", firelink_shrine_bell_tower_table)
firelink_shrine_bell_tower_region = self.create_region("Firelink Shrine Bell Tower",
firelink_shrine_bell_tower_table)
high_wall_of_lothric_region = self.create_region("High Wall of Lothric", high_wall_of_lothric)
undead_settlement_region = self.create_region("Undead Settlement", undead_settlement_table)
road_of_sacrifices_region = self.create_region("Road of Sacrifices", road_of_sacrifice_table)
@@ -61,7 +65,8 @@ class DarkSouls3World(World):
farron_keep_region = self.create_region("Farron Keep", farron_keep_table)
catacombs_of_carthus_region = self.create_region("Catacombs of Carthus", catacombs_of_carthus_table)
smouldering_lake_region = self.create_region("Smouldering Lake", smouldering_lake_table)
irithyll_of_the_boreal_valley_region = self.create_region("Irithyll of the Boreal Valley", irithyll_of_the_boreal_valley_table)
irithyll_of_the_boreal_valley_region = self.create_region("Irithyll of the Boreal Valley",
irithyll_of_the_boreal_valley_table)
irithyll_dungeon_region = self.create_region("Irithyll Dungeon", irithyll_dungeon_table)
profaned_capital_region = self.create_region("Profaned Capital", profaned_capital_table)
anor_londo_region = self.create_region("Anor Londo", anor_londo_table)
@@ -71,23 +76,28 @@ class DarkSouls3World(World):
archdragon_peak_region = self.create_region("Archdragon Peak", archdragon_peak_table)
kiln_of_the_first_flame_region = self.create_region("Kiln Of The First Flame", None)
# Entrances
# Create the entrance to connect those regions
menu_region.exits.append(Entrance(self.player, "New Game", menu_region))
self.world.get_entrance("New Game", self.player).connect(cemetery_of_ash_region)
cemetery_of_ash_region.exits.append(Entrance(self.player, "Goto Firelink Shrine", cemetery_of_ash_region))
self.world.get_entrance("Goto Firelink Shrine", self.player).connect(firelink_shrine_region)
firelink_shrine_region.exits.append(Entrance(self.player, "Goto High Wall of Lothric", firelink_shrine_region))
firelink_shrine_region.exits.append(Entrance(self.player, "Goto Kiln Of The First Flame", firelink_shrine_region))
firelink_shrine_region.exits.append(Entrance(self.player, "Goto Bell Tower", firelink_shrine_region))
firelink_shrine_region.exits.append(Entrance(self.player, "Goto High Wall of Lothric",
firelink_shrine_region))
firelink_shrine_region.exits.append(Entrance(self.player, "Goto Kiln Of The First Flame",
firelink_shrine_region))
firelink_shrine_region.exits.append(Entrance(self.player, "Goto Bell Tower",
firelink_shrine_region))
self.world.get_entrance("Goto High Wall of Lothric", self.player).connect(high_wall_of_lothric_region)
self.world.get_entrance("Goto Kiln Of The First Flame", self.player).connect(kiln_of_the_first_flame_region)
self.world.get_entrance("Goto Bell Tower", self.player).connect(firelink_shrine_bell_tower_region)
high_wall_of_lothric_region.exits.append(Entrance(self.player, "Goto Undead Settlement", high_wall_of_lothric_region))
high_wall_of_lothric_region.exits.append(Entrance(self.player, "Goto Lothric Castle", high_wall_of_lothric_region))
high_wall_of_lothric_region.exits.append(Entrance(self.player, "Goto Undead Settlement",
high_wall_of_lothric_region))
high_wall_of_lothric_region.exits.append(Entrance(self.player, "Goto Lothric Castle",
high_wall_of_lothric_region))
self.world.get_entrance("Goto Undead Settlement", self.player).connect(undead_settlement_region)
self.world.get_entrance("Goto Lothric Castle", self.player).connect(lothric_castle_region)
undead_settlement_region.exits.append(Entrance(self.player, "Goto Road Of Sacrifices", undead_settlement_region))
undead_settlement_region.exits.append(Entrance(self.player, "Goto Road Of Sacrifices",
undead_settlement_region))
self.world.get_entrance("Goto Road Of Sacrifices", self.player).connect(road_of_sacrifices_region)
road_of_sacrifices_region.exits.append(Entrance(self.player, "Goto Cathedral", road_of_sacrifices_region))
road_of_sacrifices_region.exits.append(Entrance(self.player, "Goto Farron keep", road_of_sacrifices_region))
@@ -95,27 +105,32 @@ class DarkSouls3World(World):
self.world.get_entrance("Goto Farron keep", self.player).connect(farron_keep_region)
farron_keep_region.exits.append(Entrance(self.player, "Goto Carthus catacombs", farron_keep_region))
self.world.get_entrance("Goto Carthus catacombs", self.player).connect(catacombs_of_carthus_region)
catacombs_of_carthus_region.exits.append(Entrance(self.player, "Goto Irithyll of the boreal", catacombs_of_carthus_region))
catacombs_of_carthus_region.exits.append(Entrance(self.player, "Goto Smouldering Lake", catacombs_of_carthus_region))
self.world.get_entrance("Goto Irithyll of the boreal", self.player).connect(irithyll_of_the_boreal_valley_region)
catacombs_of_carthus_region.exits.append(Entrance(self.player, "Goto Irithyll of the boreal",
catacombs_of_carthus_region))
catacombs_of_carthus_region.exits.append(Entrance(self.player, "Goto Smouldering Lake",
catacombs_of_carthus_region))
self.world.get_entrance("Goto Irithyll of the boreal", self.player).\
connect(irithyll_of_the_boreal_valley_region)
self.world.get_entrance("Goto Smouldering Lake", self.player).connect(smouldering_lake_region)
irithyll_of_the_boreal_valley_region.exits.append(Entrance(self.player, "Goto Irithyll dungeon", irithyll_of_the_boreal_valley_region))
irithyll_of_the_boreal_valley_region.exits.append(Entrance(self.player, "Goto Anor Londo", irithyll_of_the_boreal_valley_region))
irithyll_of_the_boreal_valley_region.exits.append(Entrance(self.player, "Goto Irithyll dungeon",
irithyll_of_the_boreal_valley_region))
irithyll_of_the_boreal_valley_region.exits.append(Entrance(self.player, "Goto Anor Londo",
irithyll_of_the_boreal_valley_region))
self.world.get_entrance("Goto Irithyll dungeon", self.player).connect(irithyll_dungeon_region)
self.world.get_entrance("Goto Anor Londo", self.player).connect(anor_londo_region)
irithyll_dungeon_region.exits.append(Entrance(self.player, "Goto Archdragon peak", irithyll_dungeon_region))
irithyll_dungeon_region.exits.append(Entrance(self.player, "Goto Profaned capital", irithyll_dungeon_region))
self.world.get_entrance("Goto Archdragon peak", self.player).connect(archdragon_peak_region)
self.world.get_entrance("Goto Profaned capital", self.player).connect(profaned_capital_region)
lothric_castle_region.exits.append(Entrance(self.player, "Goto Consumed King Garden", lothric_castle_region))
lothric_castle_region.exits.append(Entrance(self.player, "Goto Grand Archives", lothric_castle_region))
self.world.get_entrance("Goto Consumed King Garden", self.player).connect(consumed_king_garden_region)
self.world.get_entrance("Goto Grand Archives", self.player).connect(grand_archives_region)
consumed_king_garden_region.exits.append(Entrance(self.player, "Goto Untended Graves", consumed_king_garden_region))
consumed_king_garden_region.exits.append(Entrance(self.player, "Goto Untended Graves",
consumed_king_garden_region))
self.world.get_entrance("Goto Untended Graves", self.player).connect(untended_graves_region)
# For each region, add the associated locations retrieved from the corresponding location_table
def create_region(self, name, location_table) -> Region:
new_region = Region(name, RegionType.Generic, name, self.player)
if location_table is not None:
@@ -128,6 +143,7 @@ class DarkSouls3World(World):
def create_items(self):
for name, address in self.item_name_to_id.items():
# Specific items will be included in the item pool under certain conditions. See generate_basic
if name != "Basin of Vows" and name != "Path of the Dragon Gesture":
self.world.itempool += [self.create_item(name)]
@@ -135,23 +151,34 @@ class DarkSouls3World(World):
pass
def set_rules(self) -> None:
set_rule(self.world.get_entrance("Goto Bell Tower", self.player),
lambda state: state.has("Mortician's Ashes", self.player))
set_rule(self.world.get_entrance("Goto Undead Settlement", self.player),
lambda state: state.has("Small Lothric Banner", self.player))
set_rule(self.world.get_entrance("Goto Lothric Castle", self.player),
lambda state: state.has("Basin of Vows", self.player))
set_rule(self.world.get_location("HWL: Soul of the Dancer", self.player),
lambda state: state.has("Basin of Vows", self.player))
set_rule(self.world.get_entrance("Goto Irithyll of the boreal", self.player),
lambda state: state.has("Small Doll", self.player))
set_rule(self.world.get_entrance("Goto Archdragon peak", self.player),
lambda state: state.has("Path of the Dragon Gesture", self.player))
set_rule(self.world.get_entrance("Goto Profaned capital", self.player),
lambda state: state.has("Storm Ruler", self.player))
set_rule(self.world.get_entrance("Goto Grand Archives", self.player),
lambda state: state.has("Grand Archives Key", self.player))
set_rule(self.world.get_entrance("Goto Kiln Of The First Flame", self.player), lambda state:
# Define the access rules to the entrances
set_rule(
self.world.get_entrance("Goto Bell Tower", self.player),
lambda state: state.has("Mortician's Ashes", self.player))
set_rule(
self.world.get_entrance("Goto Undead Settlement", self.player),
lambda state: state.has("Small Lothric Banner", self.player))
set_rule(
self.world.get_entrance("Goto Lothric Castle", self.player),
lambda state: state.has("Basin of Vows", self.player))
set_rule(
self.world.get_location("HWL: Soul of the Dancer", self.player),
lambda state: state.has("Basin of Vows", self.player))
set_rule(
self.world.get_entrance("Goto Irithyll of the boreal", self.player),
lambda state: state.has("Small Doll", self.player))
set_rule(
self.world.get_entrance("Goto Archdragon peak", self.player),
lambda state: state.has("Path of the Dragon Gesture", self.player))
set_rule(
self.world.get_entrance("Goto Profaned capital", self.player),
lambda state: state.has("Storm Ruler", self.player))
set_rule(
self.world.get_entrance("Goto Grand Archives", self.player),
lambda state: state.has("Grand Archives Key", self.player))
set_rule(
self.world.get_entrance("Goto Kiln Of The First Flame", self.player), lambda state:
state.has("Cinders of a Lord - Abyss Watcher", self.player) and
state.has("Cinders of a Lord - Yhorm the Giant", self.player) and
state.has("Cinders of a Lord - Aldrich", self.player) and
@@ -164,23 +191,21 @@ class DarkSouls3World(World):
state.has("Cinders of a Lord - Lothric Prince", self.player)
def generate_basic(self):
# Depending on the specified option, add the Basin of Vows to a specific location or to the item pool
item = self.create_item("Basin of Vows")
if self.world.late_basin_of_vows[self.player]:
self.world.get_location("IBV: Soul of Pontiff Sulyvahn", self.player).place_locked_item(item)
else:
self.world.itempool += item
self.world.itempool += [item]
itempool_len = self.item_name_to_id.__len__()
# Fill item pool with additional items
item_pool_len = self.item_name_to_id.__len__()
total_required_locations = self.location_name_to_id.__len__()
# Fill item pool with the remaining
for i in range(itempool_len, total_required_locations):
for i in range(item_pool_len, total_required_locations):
self.world.itempool += [self.create_item("Soul of an Intrepid Hero")]
def generate_output(self, output_directory: str):
print(self.world.get_items().__len__())
# Depending on the specified option, modify items hexadecimal value to add an upgrade level
item_dictionary = item_dictionary_table.copy()
if self.world.randomize_weapons_level[self.player]:
# Randomize some weapons upgrades
@@ -194,23 +219,24 @@ class DarkSouls3World(World):
value = randint(1, 10)
item_dictionary[name] += value
itemsId = []
itemsAddress = []
locationsId = []
locationsAddress = []
locationsTarget = []
# Create the mandatory lists to generate the player's output file
items_id = []
items_address = []
locations_id = []
locations_address = []
locations_target = []
for location in self.world.get_filled_locations():
if location.item.player == self.player:
itemsId.append(location.item.code)
itemsAddress.append(item_dictionary[location.item.name])
items_id.append(location.item.code)
items_address.append(item_dictionary[location.item.name])
if location.player == self.player:
locationsAddress.append(dictionary_table[location.name])
locationsId.append(location.address)
locations_address.append(dictionary_table[location.name])
locations_id.append(location.address)
if location.item.player == self.player:
locationsTarget.append(item_dictionary[location.item.name])
locations_target.append(item_dictionary[location.item.name])
else:
locationsTarget.append(0)
locations_target.append(0)
data = {
"options": {
@@ -221,11 +247,11 @@ class DarkSouls3World(World):
"seed": self.world.seed_name, # to verify the server's multiworld
"slot": self.world.player_name[self.player], # to connect to server
"base_id": self.base_id, # to merge location and items lists
"locationsId": locationsId,
"locationsAddress": locationsAddress,
"locationsTarget": locationsTarget,
"itemsId": itemsId,
"itemsAddress": itemsAddress
"locationsId": locations_id,
"locationsAddress": locations_address,
"locationsTarget": locations_target,
"itemsId": items_id,
"itemsAddress": items_address
}
# generate the file
@@ -245,17 +271,11 @@ class DarkSouls3World(World):
data_version = 0
# ID of first item and location, could be hard-coded but code may be easier
# to read with this as a propery.
# to read with this as a property.
base_id = 100000
# Instead of dynamic numbering, IDs could be part of data.
# The following two dicts are required for the generation to know which
# items exist. They could be generated from json or something else. They can
# include events, but don't have to since events will be placed manually.
item_name_to_id = {name: id for id, name in enumerate(DarkSouls3Item.get_item_name_to_id(), base_id)}
location_name_to_id = {name: id for id, name in enumerate(DarkSouls3Location.get_location_name_to_id(), base_id)}

View File

@@ -1,6 +1,9 @@
# Regular expression to parse the Python list https://regex101.com/r/XdtiLR/2
# List of location https://darksouls3.wiki.fextralife.com/Locations
"""
Tools used to create this list :
List of all items https://docs.google.com/spreadsheets/d/1nK2g7g6XJ-qphFAk1tjP3jZtlXWDQY-ItKLa_sniawo/edit#gid=1551945791
Regular expression parser https://regex101.com/r/XdtiLR/2
List of locations https://darksouls3.wiki.fextralife.com/Locations
"""
weapons_upgrade_5_table = {
"Irithyll Straight Sword": 0x0020A760,

View File

@@ -1,5 +1,9 @@
# Regular expression to parse the Python list https://regex101.com/r/XdtiLR/2
# List of location https://darksouls3.wiki.fextralife.com/Locations
"""
Tools used to create this list :
List of all items https://docs.google.com/spreadsheets/d/1nK2g7g6XJ-qphFAk1tjP3jZtlXWDQY-ItKLa_sniawo/edit#gid=1551945791
Regular expression parser https://regex101.com/r/XdtiLR/2
List of locations https://darksouls3.wiki.fextralife.com/Locations
"""
cemetery_of_ash_table = {
}

View File

@@ -18,7 +18,7 @@ The randomization is performed by the AP.json file, an output file generated by
Get the dinput8.dll from the [Dark Souls 3 AP Client](https://github.com/Marechal-L/DarkSouls3-Archipelago-client).
Then you need to add the two following files at the root folder of your game
( e.g. "SteamLibrary\steamapps\common\DARK SOULS III\Game" ) :
( e.g. "SteamLibrary\steamapps\common\DARK SOULS III\Game" ):
- **dinput8.dll**
- **AP.json** renamed from the generated file AP-{SEED_NUMBER}-{PLAYER_NUMBER}-{PLAYER_NAME}.json