diff --git a/worlds/dark_souls_3/Items.py b/worlds/dark_souls_3/Items.py new file mode 100644 index 00000000..e7ba2ecf --- /dev/null +++ b/worlds/dark_souls_3/Items.py @@ -0,0 +1,17 @@ +from BaseClasses import Item +from worlds.dark_souls_3.data.items_data import item_tables + + +class DarkSouls3Item(Item): + game: str = "Dark Souls III" + + @staticmethod + def get_name_to_id() -> dict: + base_id = 100000 + table_offset = 100 + + output = {} + for i, table in enumerate(item_tables): + output.update({name: id for id, name in enumerate(table, base_id + (table_offset * i))}) + + return output diff --git a/worlds/dark_souls_3/Locations.py b/worlds/dark_souls_3/Locations.py new file mode 100644 index 00000000..0ba84e36 --- /dev/null +++ b/worlds/dark_souls_3/Locations.py @@ -0,0 +1,17 @@ +from BaseClasses import Location +from worlds.dark_souls_3.data.locations_data import location_tables + + +class DarkSouls3Location(Location): + game: str = "Dark Souls III" + + @staticmethod + def get_name_to_id() -> dict: + base_id = 100000 + table_offset = 100 + + output = {} + for i, table in enumerate(location_tables): + output.update({name: id for id, name in enumerate(table, base_id + (table_offset * i))}) + + return output diff --git a/worlds/dark_souls_3/__init__.py b/worlds/dark_souls_3/__init__.py index 1ded4203..df56306c 100644 --- a/worlds/dark_souls_3/__init__.py +++ b/worlds/dark_souls_3/__init__.py @@ -2,9 +2,11 @@ import json import os +from .Items import DarkSouls3Item +from .Locations import DarkSouls3Location from .Options import dark_souls_options -from .data.items_data import weapons_upgrade_5_table, weapons_upgrade_10_table, item_dictionary_table, key_items_list -from .data.locations_data import location_dictionary_table, cemetery_of_ash_table, fire_link_shrine_table, \ +from .data.items_data import weapons_upgrade_5_table, weapons_upgrade_10_table, item_dictionary, key_items_list +from .data.locations_data import location_dictionary, 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, \ @@ -51,10 +53,11 @@ class DarkSouls3World(World): remote_items: bool = False remote_start_inventory: bool = False web = DarkSouls3Web() - data_version = 2 + data_version = 3 base_id = 100000 - item_name_to_id = {name: id for id, name in enumerate(item_dictionary_table, base_id)} - location_name_to_id = {name: id for id, name in enumerate(location_dictionary_table, base_id)} + required_client_version = (0, 3, 6) + item_name_to_id = DarkSouls3Item.get_name_to_id() + location_name_to_id = DarkSouls3Location.get_name_to_id() def __init__(self, world: MultiWorld, player: int): super().__init__(world, player) @@ -79,7 +82,6 @@ class DarkSouls3World(World): self.world.regions.append(menu_region) # Create all Vanilla regions of Dark Souls III - 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) @@ -104,9 +106,7 @@ class DarkSouls3World(World): # 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) + self.world.get_entrance("New Game", 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", @@ -209,6 +209,8 @@ class DarkSouls3World(World): lambda state: state.has("Jailer's Key Ring", self.player)) set_rule(self.world.get_location("ID: Covetous Gold Serpent Ring", self.player), lambda state: state.has("Old Cell Key", self.player)) + set_rule(self.world.get_location("ID: Karla's Ashes", self.player), + lambda state: state.has("Jailer's Key Ring", self.player)) black_hand_gotthard_corpse_rule = lambda state: \ (state.can_reach("AL: Cinders of a Lord - Aldrich", "Location", self.player) and state.can_reach("PC: Cinders of a Lord - Yhorm the Giant", "Location", self.player)) @@ -237,18 +239,18 @@ class DarkSouls3World(World): def generate_output(self, output_directory: str): # Depending on the specified option, modify items hexadecimal value to add an upgrade level - item_dictionary = item_dictionary_table.copy() + item_dictionary_copy = item_dictionary.copy() if self.world.randomize_weapons_level[self.player]: # Randomize some weapons upgrades for name in weapons_upgrade_5_table.keys(): if self.world.random.randint(0, 100) < 33: value = self.world.random.randint(1, 5) - item_dictionary[name] += value + item_dictionary_copy[name] += value for name in weapons_upgrade_10_table.keys(): if self.world.random.randint(0, 100) < 33: value = self.world.random.randint(1, 10) - item_dictionary[name] += value + item_dictionary_copy[name] += value # Create the mandatory lists to generate the player's output file items_id = [] @@ -262,7 +264,7 @@ class DarkSouls3World(World): items_address.append(item_dictionary[location.item.name]) if location.player == self.player: - locations_address.append(location_dictionary_table[location.name]) + locations_address.append(location_dictionary[location.name]) locations_id.append(location.address) if location.item.player == self.player: locations_target.append(item_dictionary[location.item.name]) @@ -289,11 +291,3 @@ class DarkSouls3World(World): 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) - - -class DarkSouls3Location(Location): - game: str = "Dark Souls III" - - -class DarkSouls3Item(Item): - game: str = "Dark Souls III" diff --git a/worlds/dark_souls_3/data/items_data.py b/worlds/dark_souls_3/data/items_data.py index 9add1882..e951b674 100644 --- a/worlds/dark_souls_3/data/items_data.py +++ b/worlds/dark_souls_3/data/items_data.py @@ -52,6 +52,7 @@ weapons_upgrade_5_table = { "Storm Curved Sword": 0x003E4180, "Dragonslayer Swordspear": 0x008BC540, "Sage's Crystal Staff": 0x00C8CE40, + "Irithyll Rapier": 0x002E8A10 } weapons_upgrade_10_table = { @@ -131,7 +132,7 @@ shields_table = { "Golden Wing Crest Shield": 0x0143CAA0, "Ancient Dragon Greatshield": 0x013599D0, "Spirit Tree Crest Shield": 0x014466E0, - + "Red and White Round Shield": 0x01343A40, } goods_table = { @@ -244,6 +245,10 @@ armor_table = { "Shadow Garb": 0x14D3FA28, "Shadow Gauntlets": 0x14D3FE10, "Shadow Leggings": 0x14D401F8, + "Outrider Knight Helm": 0x1328B740, + "Outrider Knight Armor": 0x1328BB28, + "Outrider Knight Gauntlets": 0x1328BF10, + "Outrider Knight Leggings": 0x1328C2F8, } rings_table = { @@ -292,6 +297,7 @@ rings_table = { "Red Tearstone Ring": 0x20004ECA, "Dragonscale Ring": 0x2000515E, "Knight Slayer's Ring": 0x20005000, + "Magic Stoneplate Ring": 0x20004E66, } spells_table = { @@ -313,6 +319,7 @@ spells_table = { "Divine Pillars of Light": 0x4038C340, "Great Magic Barrier": 0x40365628, "Great Magic Shield": 0x40144F38, + "Crystal Scroll": 0x40000856, } misc_items_table = { @@ -359,6 +366,10 @@ misc_items_table = { "Dragon Chaser's Ashes": 0x40000867, "Twinkling Dragon Torso Stone": 0x40000184, "Braille Divine Tome of Lothric": 0x40000848, + "Irina's Ashes": 0x40000843, + "Karla's Ashes": 0x40000842, + "Cornyx's Ashes": 0x40000841, + "Orbeck's Ashes": 0x40000840 } key_items_list = { @@ -380,4 +391,6 @@ key_items_list = { "Jailer's Key Ring", } -item_dictionary_table = {**weapons_upgrade_5_table, **weapons_upgrade_10_table, **shields_table, **armor_table, **rings_table, **spells_table, **misc_items_table, **goods_table} +item_tables = [weapons_upgrade_5_table, weapons_upgrade_10_table, shields_table, armor_table, rings_table, spells_table, misc_items_table, goods_table] + +item_dictionary = {**weapons_upgrade_5_table, **weapons_upgrade_10_table, **shields_table, **armor_table, **rings_table, **spells_table, **misc_items_table, **goods_table} diff --git a/worlds/dark_souls_3/data/locations_data.py b/worlds/dark_souls_3/data/locations_data.py index 384da049..855b4a9a 100644 --- a/worlds/dark_souls_3/data/locations_data.py +++ b/worlds/dark_souls_3/data/locations_data.py @@ -5,9 +5,6 @@ Regular expression parser https://regex101.com/r/XdtiLR/2 List of locations https://darksouls3.wiki.fextralife.com/Locations """ -cemetery_of_ash_table = { -} - fire_link_shrine_table = { # "FS: Coiled Sword": 0x40000859, You can still light the Firelink Shrine fire whether you have it or not, useless "FS: Broken Straight Sword": 0x001EF9B0, @@ -92,6 +89,9 @@ undead_settlement_table = { "US: Soul of the Rotted Greatwood": 0x400002D7, "US: Hawk Ring": 0x20004F92, "US: Warrior of Sunlight Covenant": 0x20002738, + "US: Red and White Round Shield": 0x01343A40, + "US: Irina's Ashes": 0x40000843, + "US: Cornyx's Ashes": 0x40000841 } road_of_sacrifice_table = { @@ -149,6 +149,7 @@ road_of_sacrifice_table = { "RS: Grass Crest Shield": 0x01437C80, "RS: Soul of a Crystal Sage": 0x400002CB, "RS: Great Swamp Ring": 0x20004F10, + "RS: Orbeck's Ashes": 0x40000840 } cathedral_of_the_deep_table = { @@ -315,6 +316,7 @@ irithyll_dungeon_table = { "ID: Jailer's Key Ring": 0x400007D8, "ID: Dusk Crown Ring": 0x20004F4C, "ID: Dark Clutch Ring": 0x20005028, + "ID: Karla's Ashes": 0x40000842 } profaned_capital_table = { @@ -359,6 +361,7 @@ lothric_castle_table = { "LC: Caitha's Chime": 0x00CA06C0, "LC: Braille Divine Tome of Lothric": 0x40000848, "LC: Knight's Ring": 0x20004FEC, + "LC: Irithyll Rapier": 0x002E8A10, "LC: Sunlight Straight Sword": 0x00203230, "LC: Soul of Dragonslayer Armour": 0x400002D1, @@ -375,6 +378,7 @@ consumed_king_garden_table = { "CKG: Shadow Leggings": 0x14D401F8, "CKG: Claw": 0x00A7D8C0, "CKG: Soul of Consumed Oceiros": 0x400002CE, + "CKG: Magic Stoneplate Ring": 0x20004E66, # "CKG: Path of the Dragon Gesture": 0x40002346, I can't technically randomize it as it is a gesture and not an item } @@ -393,6 +397,11 @@ grand_archives_table = { "GA: Cinders of a Lord - Lothric Prince": 0x4000084E, "GA: Soul of the Twin Princes": 0x400002DB, "GA: Sage's Crystal Staff": 0x00C8CE40, + "GA: Outrider Knight Helm": 0x1328B740, + "GA: Outrider Knight Armor": 0x1328BB28, + "GA: Outrider Knight Gauntlets": 0x1328BF10, + "GA: Outrider Knight Leggings": 0x1328C2F8, + "GA: Crystal Scroll": 0x40000856, } untended_graves_table = { @@ -428,7 +437,12 @@ archdragon_peak_table = { "AP: Havel's Greatshield": 0x013376F0, } -location_dictionary_table = {**cemetery_of_ash_table, **fire_link_shrine_table, **firelink_shrine_bell_tower_table, **high_wall_of_lothric, **undead_settlement_table, **road_of_sacrifice_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, **consumed_king_garden_table, - **grand_archives_table, **untended_graves_table, **archdragon_peak_table} +location_tables = [fire_link_shrine_table, firelink_shrine_bell_tower_table, high_wall_of_lothric, undead_settlement_table, road_of_sacrifice_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, consumed_king_garden_table, + grand_archives_table, untended_graves_table, archdragon_peak_table] + +location_dictionary = {**fire_link_shrine_table, **firelink_shrine_bell_tower_table, **high_wall_of_lothric, **undead_settlement_table, **road_of_sacrifice_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, **consumed_king_garden_table, + **grand_archives_table, **untended_graves_table, **archdragon_peak_table}