mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-07-30 04:00:48 -07:00
337 lines
20 KiB
Python
337 lines
20 KiB
Python
# world/dark_souls_3/__init__.py
|
|
import json
|
|
import os
|
|
|
|
from random import randint
|
|
from .Options import dark_souls_options # the options we defined earlier
|
|
from .Items import DarkSouls3Item # data used below to add items to the World
|
|
from .Locations import DarkSouls3Location # same as above
|
|
from .data.items_data import weapons_table, item_dictionary_table
|
|
from .data.locations_data import key_items_list, dictionary_table, cemetery_of_ash_table, fire_link_shrine_table, \
|
|
high_wall_of_lothric, \
|
|
undead_settlement_table, road_of_sacrifice_table, consumed_king_garden_table, cathedral_of_the_deep_table, \
|
|
farron_keep_table, catacombs_of_carthus_table, smouldering_lake_table, irithyll_of_the_boreal_valley_table, \
|
|
irithyll_dungeon_table, profaned_capital_table, anor_londo_table, lothric_castle_table, grand_archives_table, \
|
|
untended_graves_table, archdragon_peak_table, firelink_shrine_bell_tower_table
|
|
from ..AutoWorld import World
|
|
from BaseClasses import MultiWorld, Location, Region, Item, RegionType, Entrance
|
|
from ..generic.Rules import set_rule
|
|
|
|
|
|
class DarkSouls3World(World):
|
|
"""Insert description of the world/game here."""
|
|
|
|
def __init__(self, world: MultiWorld, player: int):
|
|
super().__init__(world, player)
|
|
self.locked_items = []
|
|
self.locked_locations = []
|
|
|
|
def create_item(self, name: str) -> Item:
|
|
data = self.item_name_to_id[name]
|
|
return DarkSouls3Item(name, name in key_items_list, data, self.player)
|
|
|
|
def create_regions(self):
|
|
menu_region = Region("Menu", RegionType.Generic, "Menu", self.player)
|
|
self.world.regions.append(menu_region)
|
|
|
|
cemetery_of_ash_region = Region("Cemetery Of Ash", RegionType.Generic, "Cemetery Of Ash", self.player)
|
|
for name, address in self.location_name_to_id.items():
|
|
if cemetery_of_ash_table.get(name):
|
|
location = Location(self.player, name, address, cemetery_of_ash_region)
|
|
cemetery_of_ash_region.locations.append(location)
|
|
self.world.regions.append(cemetery_of_ash_region)
|
|
|
|
firelink_shrine_region = Region("Firelink Shrine", RegionType.Generic, "Firelink Shrine", self.player)
|
|
for name, address in self.location_name_to_id.items():
|
|
if fire_link_shrine_table.get(name):
|
|
location = Location(self.player, name, address, firelink_shrine_region)
|
|
firelink_shrine_region.locations.append(location)
|
|
self.world.regions.append(firelink_shrine_region)
|
|
|
|
firelink_shrine_bell_tower_region = Region("Firelink Shrine Bell Tower", RegionType.Generic, "Firelink Shrine Bell Tower", self.player)
|
|
for name, address in self.location_name_to_id.items():
|
|
if firelink_shrine_bell_tower_table.get(name):
|
|
location = Location(self.player, name, address, firelink_shrine_bell_tower_region)
|
|
firelink_shrine_bell_tower_region.locations.append(location)
|
|
self.world.regions.append(firelink_shrine_bell_tower_region)
|
|
|
|
high_wall_of_lothric_region = Region("High Wall of Lothric", RegionType.Generic, "High Wall of Lothric", self.player)
|
|
for name, address in self.location_name_to_id.items():
|
|
if high_wall_of_lothric.get(name):
|
|
location = Location(self.player, name, address, high_wall_of_lothric_region)
|
|
high_wall_of_lothric_region.locations.append(location)
|
|
self.world.regions.append(high_wall_of_lothric_region)
|
|
|
|
undead_settlement_region = Region("Undead Settlement", RegionType.Generic, "Undead Settlement", self.player)
|
|
for name, address in self.location_name_to_id.items():
|
|
if undead_settlement_table.get(name):
|
|
location = Location(self.player, name, address, undead_settlement_region)
|
|
undead_settlement_region.locations.append(location)
|
|
self.world.regions.append(undead_settlement_region)
|
|
|
|
road_of_sacrifices_region = Region("Road of Sacrifices", RegionType.Generic, "Road of Sacrifices", self.player)
|
|
for name, address in self.location_name_to_id.items():
|
|
if road_of_sacrifice_table.get(name):
|
|
location = Location(self.player, name, address, road_of_sacrifices_region)
|
|
road_of_sacrifices_region.locations.append(location)
|
|
self.world.regions.append(road_of_sacrifices_region)
|
|
|
|
consumed_king_garden_region = Region("Consumed King's Garden", RegionType.Generic, "Consumed King's Garden",
|
|
self.player)
|
|
for name, address in self.location_name_to_id.items():
|
|
if consumed_king_garden_table.get(name):
|
|
location = Location(self.player, name, address, consumed_king_garden_region)
|
|
consumed_king_garden_region.locations.append(location)
|
|
self.world.regions.append(consumed_king_garden_region)
|
|
|
|
cathedral_of_the_deep_region = Region("Cathedral of the Deep", RegionType.Generic, "Cathedral of the Deep",
|
|
self.player)
|
|
for name, address in self.location_name_to_id.items():
|
|
if cathedral_of_the_deep_table.get(name):
|
|
location = Location(self.player, name, address, cathedral_of_the_deep_region)
|
|
cathedral_of_the_deep_region.locations.append(location)
|
|
self.world.regions.append(cathedral_of_the_deep_region)
|
|
|
|
farron_keep_region = Region("Farron Keep", RegionType.Generic, "Farron Keep", self.player)
|
|
for name, address in self.location_name_to_id.items():
|
|
if farron_keep_table.get(name):
|
|
location = Location(self.player, name, address, farron_keep_region)
|
|
farron_keep_region.locations.append(location)
|
|
self.world.regions.append(farron_keep_region)
|
|
|
|
catacombs_of_carthus_region = Region("Catacombs of Carthus", RegionType.Generic, "Catacombs of Carthus", self.player)
|
|
for name, address in self.location_name_to_id.items():
|
|
if catacombs_of_carthus_table.get(name):
|
|
location = Location(self.player, name, address, catacombs_of_carthus_region)
|
|
catacombs_of_carthus_region.locations.append(location)
|
|
self.world.regions.append(catacombs_of_carthus_region)
|
|
|
|
smouldering_lake_region = Region("Smouldering Lake", RegionType.Generic, "Smouldering Lake", self.player)
|
|
for name, address in self.location_name_to_id.items():
|
|
if smouldering_lake_table.get(name):
|
|
location = Location(self.player, name, address, smouldering_lake_region)
|
|
smouldering_lake_region.locations.append(location)
|
|
self.world.regions.append(smouldering_lake_region)
|
|
|
|
irithyll_of_the_boreal_valley_region = Region("Irithyll of the Boreal Valley", RegionType.Generic,
|
|
"Irithyll of the Boreal Valley", self.player)
|
|
for name, address in self.location_name_to_id.items():
|
|
if irithyll_of_the_boreal_valley_table.get(name):
|
|
location = Location(self.player, name, address, irithyll_of_the_boreal_valley_region)
|
|
irithyll_of_the_boreal_valley_region.locations.append(location)
|
|
self.world.regions.append(irithyll_of_the_boreal_valley_region)
|
|
|
|
irithyll_dungeon_region = Region("Irithyll Dungeon", RegionType.Generic, "Irithyll Dungeon", self.player)
|
|
for name, address in self.location_name_to_id.items():
|
|
if irithyll_dungeon_table.get(name):
|
|
location = Location(self.player, name, address, irithyll_dungeon_region)
|
|
irithyll_dungeon_region.locations.append(location)
|
|
self.world.regions.append(irithyll_dungeon_region)
|
|
|
|
profaned_capital_region = Region("Profaned Capital", RegionType.Generic, "Profaned Capital", self.player)
|
|
for name, address in self.location_name_to_id.items():
|
|
if profaned_capital_table.get(name):
|
|
location = Location(self.player, name, address, profaned_capital_region)
|
|
profaned_capital_region.locations.append(location)
|
|
self.world.regions.append(profaned_capital_region)
|
|
|
|
anor_londo_region = Region("Anor Londo", RegionType.Generic, "Anor Londo", self.player)
|
|
for name, address in self.location_name_to_id.items():
|
|
if anor_londo_table.get(name):
|
|
location = Location(self.player, name, address, anor_londo_region)
|
|
anor_londo_region.locations.append(location)
|
|
self.world.regions.append(anor_londo_region)
|
|
|
|
lothric_castle_region = Region("Lothric Castle", RegionType.Generic, "Lothric Castle", self.player)
|
|
for name, address in self.location_name_to_id.items():
|
|
if lothric_castle_table.get(name):
|
|
location = Location(self.player, name, address, lothric_castle_region)
|
|
lothric_castle_region.locations.append(location)
|
|
self.world.regions.append(lothric_castle_region)
|
|
|
|
grand_archives_region = Region("Grand Archives", RegionType.Generic, "Grand Archives", self.player)
|
|
for name, address in self.location_name_to_id.items():
|
|
if grand_archives_table.get(name):
|
|
location = Location(self.player, name, address, grand_archives_region)
|
|
grand_archives_region.locations.append(location)
|
|
self.world.regions.append(grand_archives_region)
|
|
|
|
untended_graves_region = Region("Untended Graves", RegionType.Generic, "Untended Graves", self.player)
|
|
for name, address in self.location_name_to_id.items():
|
|
if untended_graves_table.get(name):
|
|
location = Location(self.player, name, address, untended_graves_region)
|
|
untended_graves_region.locations.append(location)
|
|
self.world.regions.append(untended_graves_region)
|
|
|
|
archdragon_peak_region = Region("Archdragon Peak", RegionType.Generic, "Archdragon Peak", self.player)
|
|
for name, address in self.location_name_to_id.items():
|
|
if archdragon_peak_table.get(name):
|
|
location = Location(self.player, name, address, archdragon_peak_region)
|
|
archdragon_peak_region.locations.append(location)
|
|
self.world.regions.append(archdragon_peak_region)
|
|
|
|
kiln_of_the_first_flame_region = Region("Kiln Of The First Flame", RegionType.Generic,
|
|
"Kiln Of The First Flame", self.player)
|
|
self.world.regions.append(kiln_of_the_first_flame_region)
|
|
|
|
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))
|
|
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))
|
|
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))
|
|
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))
|
|
self.world.get_entrance("Goto Cathedral", self.player).connect(cathedral_of_the_deep_region)
|
|
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)
|
|
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))
|
|
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))
|
|
self.world.get_entrance("Goto Untended Graves", self.player).connect(untended_graves_region)
|
|
|
|
def create_items(self):
|
|
for name, address in self.item_name_to_id.items():
|
|
self.world.itempool += [self.create_item(name)]
|
|
|
|
def generate_early(self):
|
|
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_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
|
|
state.has("Cinders of a Lord - Lothric Prince", self.player))
|
|
|
|
def generate_basic(self):
|
|
self.world.completion_condition[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\
|
|
state.has("Cinders of a Lord - Lothric Prince", self.player)
|
|
|
|
itempool_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):
|
|
self.world.itempool += [self.create_item("Soul of an Intrepid Hero")]
|
|
|
|
def generate_output(self, output_directory: str):
|
|
|
|
itemsId = []
|
|
itemsAddress = []
|
|
locationsId = []
|
|
locationsAddress = []
|
|
locationsTarget = []
|
|
for location in self.world.get_filled_locations(self.player):
|
|
locationsAddress.append(dictionary_table[location.name])
|
|
locationsId.append(location.address)
|
|
if location.item.player == self.player:
|
|
locationsTarget.append(item_dictionary_table[location.item.name])
|
|
else:
|
|
locationsTarget.append(0)
|
|
|
|
for location in self.world.get_filled_locations():
|
|
if location.item.player == self.player:
|
|
itemsId.append(location.item.code)
|
|
itemsAddress.append(item_dictionary_table[location.item.name])
|
|
|
|
|
|
data = {
|
|
"options": {
|
|
"auto_equip": (True if self.world.auto_equip[self.player] else False),
|
|
"lock_equip": (True if self.world.lock_equip[self.player] else False),
|
|
"no_weapon_requirements": (True if self.world.no_weapon_requirements[self.player] else False),
|
|
},
|
|
"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
|
|
}
|
|
|
|
# generate the file
|
|
filename = f"AP-{self.world.seed_name}-P{self.player}-{self.world.player_name[self.player]}.json"
|
|
with open(os.path.join(output_directory, filename), 'w') as outfile:
|
|
json.dump(data, outfile)
|
|
|
|
game: str = "Dark Souls III" # name of the game/world
|
|
options = dark_souls_options # options the player can set
|
|
topology_present: bool = True # show path to required location checks in spoiler
|
|
remote_items: bool = False # True if all items come from the server
|
|
remote_start_inventory: bool = False # True if start inventory comes from the server
|
|
|
|
# data_version is used to signal that items, locations or their names
|
|
# changed. Set this to 0 during development so other games' clients do not
|
|
# cache any texts, then increase by 1 for each release that makes changes.
|
|
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.
|
|
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_item_name_to_id(), base_id)}
|
|
|
|
for name in item_dictionary_table.keys():
|
|
if name in weapons_table and randint(0, 100) < 33:
|
|
value = randint(1, 10)
|
|
old = item_dictionary_table[name]
|
|
item_dictionary_table[name] += value
|
|
print(name + str(" +") + str(value) + str(" - ") + str(old) + str(" - ") + str(item_dictionary_table[name]))
|
|
|
|
|
|
|