| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  | from typing import Dict, List, Set, Any | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | from collections import Counter | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  | from BaseClasses import Region, Location, Item, Tutorial, ItemClassification | 
					
						
							|  |  |  | from Options import OptionError | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  | from worlds.AutoWorld import World, WebWorld | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  | from .Items import base_id, item_table, group_table, tears_list, reliquary_set | 
					
						
							|  |  |  | from .Locations import location_names | 
					
						
							|  |  |  | from .Rules import BlasRules | 
					
						
							|  |  |  | from worlds.generic.Rules import set_rule | 
					
						
							|  |  |  | from .Options import BlasphemousOptions, blas_option_groups | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  | from .Vanilla import unrandomized_dict, junk_locations, thorn_set, skill_dict | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  | from .region_data import regions, locations | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | class BlasphemousWeb(WebWorld): | 
					
						
							|  |  |  |     theme = "stone" | 
					
						
							|  |  |  |     tutorials = [Tutorial( | 
					
						
							|  |  |  |         "Multiworld Setup Guide", | 
					
						
							|  |  |  |         "A guide to setting up the Blasphemous randomizer connected to an Archipelago Multiworld", | 
					
						
							|  |  |  |         "English", | 
					
						
							|  |  |  |         "setup_en.md", | 
					
						
							|  |  |  |         "setup/en", | 
					
						
							|  |  |  |         ["TRPG"] | 
					
						
							|  |  |  |     )] | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |     option_groups = blas_option_groups | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class BlasphemousWorld(World): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Blasphemous is a challenging Metroidvania set in the cursed land of Cvstodia. Play as the Penitent One, trapped | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |     in an endless cycle of death and rebirth, and free the world from its terrible fate in your quest to break | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  |     your eternal damnation! | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |     game = "Blasphemous" | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  |     web = BlasphemousWeb() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     item_name_to_id = {item["name"]: (base_id + index) for index, item in enumerate(item_table)} | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |     location_name_to_id = {loc: (base_id + index) for index, loc in enumerate(location_names.values())} | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     item_name_groups = group_table | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |     options_dataclass = BlasphemousOptions | 
					
						
							|  |  |  |     options: BlasphemousOptions | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |     required_client_version = (0, 4, 7) | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, multiworld, player): | 
					
						
							|  |  |  |         super(BlasphemousWorld, self).__init__(multiworld, player) | 
					
						
							|  |  |  |         self.start_room: str = "D17Z01S01" | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         self.disabled_locations: List[str] = [] | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def create_item(self, name: str) -> "BlasphemousItem": | 
					
						
							|  |  |  |         item_id: int = self.item_name_to_id[name] | 
					
						
							|  |  |  |         id = item_id - base_id | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return BlasphemousItem(name, item_table[id]["classification"], item_id, player=self.player) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def create_event(self, event: str): | 
					
						
							|  |  |  |         return BlasphemousItem(event, ItemClassification.progression_skip_balancing, None, self.player) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_filler_item_name(self) -> str: | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         return self.random.choice(tears_list) | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |     def generate_early(self): | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         if not self.options.starting_location.randomized: | 
					
						
							|  |  |  |             if self.options.starting_location == "mourning_havoc" and self.options.difficulty < 2: | 
					
						
							|  |  |  |                 raise OptionError(f"[Blasphemous - '{self.player_name}'] " | 
					
						
							|  |  |  |                                 f"{self.options.starting_location} cannot be chosen if Difficulty is lower than Hard.") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (self.options.starting_location == "brotherhood" or self.options.starting_location == "mourning_havoc") \ | 
					
						
							|  |  |  |                 and self.options.dash_shuffle: | 
					
						
							|  |  |  |                     raise OptionError(f"[Blasphemous - '{self.player_name}'] " | 
					
						
							|  |  |  |                                     f"{self.options.starting_location} cannot be chosen if Shuffle Dash is enabled.") | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |              | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |             if self.options.starting_location == "grievance" and self.options.wall_climb_shuffle: | 
					
						
							|  |  |  |                 raise OptionError(f"[Blasphemous - '{self.player_name}'] " | 
					
						
							|  |  |  |                                 f"{self.options.starting_location} cannot be chosen if Shuffle Wall Climb is enabled.") | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |         else: | 
					
						
							|  |  |  |             locations: List[int] = [ 0, 1, 2, 3, 4, 5, 6 ] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |             if self.options.difficulty < 2: | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |                 locations.remove(6) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |             if self.options.dash_shuffle: | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |                 locations.remove(0) | 
					
						
							|  |  |  |                 if 6 in locations: | 
					
						
							|  |  |  |                     locations.remove(6) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |             if self.options.wall_climb_shuffle: | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |                 locations.remove(3) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |             if self.options.starting_location.value not in locations: | 
					
						
							|  |  |  |                 self.options.starting_location.value = self.random.choice(locations) | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |              | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  |          | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         if not self.options.dash_shuffle: | 
					
						
							|  |  |  |             self.multiworld.push_precollected(self.create_item("Dash Ability")) | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         if not self.options.wall_climb_shuffle: | 
					
						
							|  |  |  |             self.multiworld.push_precollected(self.create_item("Wall Climb Ability")) | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         if not self.options.boots_of_pleading: | 
					
						
							|  |  |  |             self.disabled_locations.append("RE401") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if not self.options.purified_hand: | 
					
						
							|  |  |  |             self.disabled_locations.append("RE402") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if self.options.skip_long_quests: | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |             for loc in junk_locations: | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |                 self.options.exclude_locations.value.add(loc) | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |         start_rooms: Dict[int, str] = { | 
					
						
							|  |  |  |             0: "D17Z01S01", | 
					
						
							|  |  |  |             1: "D01Z02S01", | 
					
						
							|  |  |  |             2: "D02Z03S09", | 
					
						
							|  |  |  |             3: "D03Z03S11", | 
					
						
							|  |  |  |             4: "D04Z03S01", | 
					
						
							|  |  |  |             5: "D06Z01S09", | 
					
						
							|  |  |  |             6: "D20Z02S09" | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         self.start_room = start_rooms[self.options.starting_location.value] | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |     def create_items(self): | 
					
						
							|  |  |  |         removed: int = 0 | 
					
						
							|  |  |  |         to_remove: List[str] = [ | 
					
						
							|  |  |  |             "Tears of Atonement (250)", | 
					
						
							|  |  |  |             "Tears of Atonement (300)", | 
					
						
							|  |  |  |             "Tears of Atonement (500)", | 
					
						
							|  |  |  |             "Tears of Atonement (500)", | 
					
						
							|  |  |  |             "Tears of Atonement (500)" | 
					
						
							|  |  |  |         ] | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |         skipped_items = [] | 
					
						
							|  |  |  |         junk: int = 0 | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         for item, count in self.options.start_inventory.value.items(): | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |             for _ in range(count): | 
					
						
							|  |  |  |                 skipped_items.append(item) | 
					
						
							|  |  |  |                 junk += 1 | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |         skipped_items.extend(unrandomized_dict.values()) | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         if self.options.thorn_shuffle == "vanilla": | 
					
						
							|  |  |  |             for _ in range(8): | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |                 skipped_items.append("Thorn Upgrade") | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         if self.options.dash_shuffle: | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |             skipped_items.append(to_remove[removed]) | 
					
						
							|  |  |  |             removed += 1 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         elif not self.options.dash_shuffle: | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |             skipped_items.append("Dash Ability") | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         if self.options.wall_climb_shuffle: | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |             skipped_items.append(to_remove[removed]) | 
					
						
							|  |  |  |             removed += 1 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         elif not self.options.wall_climb_shuffle: | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |             skipped_items.append("Wall Climb Ability") | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         if not self.options.reliquary_shuffle: | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |             skipped_items.extend(reliquary_set) | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         elif self.options.reliquary_shuffle: | 
					
						
							|  |  |  |             for _ in range(3): | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |                 skipped_items.append(to_remove[removed]) | 
					
						
							|  |  |  |                 removed += 1 | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         if not self.options.boots_of_pleading: | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |             skipped_items.append("Boots of Pleading") | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         if not self.options.purified_hand: | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |             skipped_items.append("Purified Hand of the Nun") | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         if self.options.start_wheel: | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |             skipped_items.append("The Young Mason's Wheel") | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         if not self.options.skill_randomizer: | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |             skipped_items.extend(skill_dict.values()) | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |         counter = Counter(skipped_items) | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         pool = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for item in item_table: | 
					
						
							|  |  |  |             count = item["count"] - counter[item["name"]] | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             if count <= 0: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             else: | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |                 for _ in range(count): | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  |                     pool.append(self.create_item(item["name"])) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |         for _ in range(junk): | 
					
						
							|  |  |  |             pool.append(self.create_item(self.get_filler_item_name())) | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         self.multiworld.itempool += pool | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |     def pre_fill(self): | 
					
						
							|  |  |  |         self.place_items_from_dict(unrandomized_dict) | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         if self.options.thorn_shuffle == "vanilla": | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |             self.place_items_from_set(thorn_set, "Thorn Upgrade") | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         if self.options.start_wheel: | 
					
						
							|  |  |  |             self.get_location("Beginning gift").place_locked_item(self.create_item("The Young Mason's Wheel")) | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         if not self.options.skill_randomizer: | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |             self.place_items_from_dict(skill_dict) | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         if self.options.thorn_shuffle == "local_only": | 
					
						
							|  |  |  |             self.options.local_items.value.add("Thorn Upgrade") | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  |          | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def place_items_from_set(self, location_set: Set[str], name: str): | 
					
						
							|  |  |  |         for loc in location_set: | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |             self.get_location(loc).place_locked_item(self.create_item(name)) | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def place_items_from_dict(self, option_dict: Dict[str, str]): | 
					
						
							|  |  |  |         for loc, item in option_dict.items(): | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |             self.get_location(loc).place_locked_item(self.create_item(item)) | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def create_regions(self) -> None: | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         multiworld = self.multiworld | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  |         player = self.player | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         created_regions: List[str] = [] | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         for r in regions: | 
					
						
							|  |  |  |             multiworld.regions.append(Region(r["name"], player, multiworld)) | 
					
						
							|  |  |  |             created_regions.append(r["name"]) | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         self.get_region("Menu").add_exits({self.start_room: "New Game"}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         blas_logic = BlasRules(self) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for r in regions: | 
					
						
							|  |  |  |             region = self.get_region(r["name"]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for e in r["exits"]: | 
					
						
							|  |  |  |                 region.add_exits({e["target"]}, {e["target"]: blas_logic.load_rule(True, r["name"], e)}) | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |             for l in [l for l in r["locations"] if l not in self.disabled_locations]: | 
					
						
							|  |  |  |                 region.add_locations({location_names[l]: self.location_name_to_id[location_names[l]]}, BlasphemousLocation) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for t in r["transitions"]: | 
					
						
							|  |  |  |                 if t == r["name"]: | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  |                  | 
					
						
							|  |  |  |                 if t in created_regions: | 
					
						
							|  |  |  |                     region.add_exits({t}) | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     multiworld.regions.append(Region(t, player, multiworld)) | 
					
						
							|  |  |  |                     created_regions.append(t) | 
					
						
							|  |  |  |                     region.add_exits({t}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for l in [l for l in locations if l["name"] not in self.disabled_locations]: | 
					
						
							|  |  |  |             location = self.get_location(location_names[l["name"]]) | 
					
						
							|  |  |  |             set_rule(location, blas_logic.load_rule(False, l["name"], l)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for rname, ename in blas_logic.indirect_conditions: | 
					
						
							|  |  |  |             self.multiworld.register_indirect_condition(self.get_region(rname), self.get_entrance(ename)) | 
					
						
							|  |  |  |         #from Utils import visualize_regions | 
					
						
							|  |  |  |         #visualize_regions(self.get_region("Menu"), "blasphemous_regions.puml") | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  |          | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         victory = Location(player, "His Holiness Escribar", None, self.get_region("D07Z01S03[W]")) | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  |         victory.place_locked_item(self.create_event("Victory")) | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         self.get_region("D07Z01S03[W]").locations.append(victory) | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         if self.options.ending == "ending_a": | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  |             set_rule(victory, lambda state: state.has("Thorn Upgrade", player, 8)) | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         elif self.options.ending == "ending_c": | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |             set_rule(victory, lambda state: state.has("Thorn Upgrade", player, 8) and | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  |                 state.has("Holy Wound of Abnegation", player)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         multiworld.completion_condition[self.player] = lambda state: state.has("Victory", player) | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |      | 
					
						
							|  |  |  |      | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  |     def fill_slot_data(self) -> Dict[str, Any]: | 
					
						
							|  |  |  |         slot_data: Dict[str, Any] = {} | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |         doors: Dict[str, str] = {} | 
					
						
							|  |  |  |         thorns: bool = True | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |         if self.options.thorn_shuffle == "vanilla": | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |             thorns = False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  |         config = { | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |             "LogicDifficulty": self.options.difficulty.value, | 
					
						
							|  |  |  |             "StartingLocation": self.options.starting_location.value, | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |             "VersionCreated": "AP", | 
					
						
							|  |  |  |              | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |             "UnlockTeleportation": bool(self.options.prie_dieu_warp.value), | 
					
						
							|  |  |  |             "AllowHints": bool(self.options.corpse_hints.value), | 
					
						
							|  |  |  |             "AllowPenitence": bool(self.options.penitence.value), | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |              | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |             "ShuffleReliquaries": bool(self.options.reliquary_shuffle.value), | 
					
						
							|  |  |  |             "ShuffleBootsOfPleading": bool(self.options.boots_of_pleading.value), | 
					
						
							|  |  |  |             "ShufflePurifiedHand": bool(self.options.purified_hand.value), | 
					
						
							|  |  |  |             "ShuffleDash": bool(self.options.dash_shuffle.value), | 
					
						
							|  |  |  |             "ShuffleWallClimb": bool(self.options.wall_climb_shuffle.value), | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |              | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |             "ShuffleSwordSkills": bool(self.options.wall_climb_shuffle.value), | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |             "ShuffleThorns": thorns, | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |             "JunkLongQuests": bool(self.options.skip_long_quests.value), | 
					
						
							|  |  |  |             "StartWithWheel": bool(self.options.start_wheel.value), | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |             "EnemyShuffleType": self.options.enemy_randomizer.value, | 
					
						
							|  |  |  |             "MaintainClass": bool(self.options.enemy_groups.value), | 
					
						
							|  |  |  |             "AreaScaling": bool(self.options.enemy_scaling.value), | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |             "BossShuffleType": 0, | 
					
						
							|  |  |  |             "DoorShuffleType": 0 | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  |         } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |         slot_data = { | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |             "locationinfo": [{"gameId": loc, "apId": (base_id + index)} for index, loc in enumerate(location_names)], | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:26 -06:00
										 |  |  |             "doors": doors, | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  |             "cfg": config, | 
					
						
							| 
									
										
										
										
											2024-08-20 17:18:28 -06:00
										 |  |  |             "ending": self.options.ending.value, | 
					
						
							|  |  |  |             "death_link": bool(self.options.death_link.value) | 
					
						
							| 
									
										
										
										
											2023-02-23 23:33:09 -07:00
										 |  |  |         } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |         return slot_data | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class BlasphemousItem(Item): | 
					
						
							|  |  |  |     game: str = "Blasphemous" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class BlasphemousLocation(Location): | 
					
						
							|  |  |  |     game: str = "Blasphemous" |