 c4572964ec
			
		
	
	c4572964ec
	
	
	
		
			
			* Fixing inclusion checking error * Fixing typo, limiting valid keys to valid keys * Adding space * Add period
		
			
				
	
	
		
			541 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			541 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import logging
 | |
| from typing import List
 | |
| 
 | |
| from BaseClasses import Tutorial, ItemClassification
 | |
| from Fill import fill_restrictive
 | |
| from worlds.LauncherComponents import Component, components, Type, launch_subprocess
 | |
| from worlds.AutoWorld import World, WebWorld
 | |
| from .Items import *
 | |
| from .Locations import *
 | |
| from .Names import ItemName, LocationName, RegionName
 | |
| from .OpenKH import patch_kh2
 | |
| from .Options import KingdomHearts2Options
 | |
| from .Regions import create_regions, connect_regions
 | |
| from .Rules import *
 | |
| from .Subclasses import KH2Item
 | |
| 
 | |
| 
 | |
| def launch_client():
 | |
|     from .Client import launch
 | |
|     launch_subprocess(launch, name="KH2Client")
 | |
| 
 | |
| 
 | |
| components.append(Component("KH2 Client", "KH2Client", func=launch_client, component_type=Type.CLIENT))
 | |
| 
 | |
| 
 | |
| class KingdomHearts2Web(WebWorld):
 | |
|     tutorials = [Tutorial(
 | |
|             "Multiworld Setup Guide",
 | |
|             "A guide to playing Kingdom Hearts 2 Final Mix with Archipelago.",
 | |
|             "English",
 | |
|             "setup_en.md",
 | |
|             "setup/en",
 | |
|             ["JaredWeakStrike"]
 | |
|     )]
 | |
| 
 | |
| 
 | |
| class KH2World(World):
 | |
|     """
 | |
|     Kingdom Hearts II is an action role-playing game developed and published by Square Enix and released in 2005.
 | |
|     It is the sequel to Kingdom Hearts and Kingdom Hearts: Chain of Memories, and like the two previous games,
 | |
|     focuses on Sora and his friends' continued battle against the Darkness.
 | |
|     """
 | |
|     game = "Kingdom Hearts 2"
 | |
|     web = KingdomHearts2Web()
 | |
| 
 | |
|     required_client_version = (0, 4, 4)
 | |
|     options_dataclass = KingdomHearts2Options
 | |
|     options: KingdomHearts2Options
 | |
|     item_name_to_id = {item: item_id
 | |
|                        for item_id, item in enumerate(item_dictionary_table.keys(), 0x130000)}
 | |
|     location_name_to_id = {item: location
 | |
|                            for location, item in enumerate(all_locations.keys(), 0x130000)}
 | |
| 
 | |
|     item_name_groups = item_groups
 | |
|     location_name_groups = location_groups
 | |
| 
 | |
|     visitlocking_dict: Dict[str, int]
 | |
|     plando_locations: Dict[str, str]
 | |
|     lucky_emblem_amount: int
 | |
|     lucky_emblem_required: int
 | |
|     bounties_required: int
 | |
|     bounties_amount: int
 | |
|     filler_items: List[str]
 | |
|     item_quantity_dict: Dict[str, int]
 | |
|     local_items: Dict[int, int]
 | |
|     sora_ability_dict: Dict[str, int]
 | |
|     goofy_ability_dict: Dict[str, int]
 | |
|     donald_ability_dict: Dict[str, int]
 | |
|     total_locations: int
 | |
| 
 | |
|     # growth_list: list[str]
 | |
| 
 | |
|     def __init__(self, multiworld: "MultiWorld", player: int):
 | |
|         super().__init__(multiworld, player)
 | |
|         # random_super_boss_list List[str]
 | |
|         # has to be in __init__ or else other players affect each other's bounties
 | |
|         self.random_super_boss_list = list()
 | |
|         self.growth_list = list()
 | |
|         # lists of KH2Item
 | |
|         self.keyblade_ability_pool = list()
 | |
| 
 | |
|         self.goofy_get_bonus_abilities = list()
 | |
|         self.goofy_weapon_abilities = list()
 | |
|         self.donald_get_bonus_abilities = list()
 | |
|         self.donald_weapon_abilities = list()
 | |
| 
 | |
|         self.slot_data_goofy_weapon = dict()
 | |
|         self.slot_data_sora_weapon = dict()
 | |
|         self.slot_data_donald_weapon = dict()
 | |
| 
 | |
|     def fill_slot_data(self) -> dict:
 | |
|         for ability in self.slot_data_sora_weapon:
 | |
|             if ability in self.sora_ability_dict and self.sora_ability_dict[ability] >= 1:
 | |
|                 self.sora_ability_dict[ability] -= 1
 | |
|         self.donald_ability_dict = {k: v.quantity for k, v in DonaldAbility_Table.items()}
 | |
|         for ability in self.slot_data_donald_weapon:
 | |
|             if ability in self.donald_ability_dict and self.donald_ability_dict[ability] >= 1:
 | |
|                 self.donald_ability_dict[ability] -= 1
 | |
|         self.goofy_ability_dict = {k: v.quantity for k, v in GoofyAbility_Table.items()}
 | |
|         for ability in self.slot_data_goofy_weapon:
 | |
|             if ability in self.goofy_ability_dict and self.goofy_ability_dict[ability] >= 1:
 | |
|                 self.goofy_ability_dict[ability] -= 1
 | |
| 
 | |
|         slot_data = self.options.as_dict("Goal", "FinalXemnas", "LuckyEmblemsRequired", "BountyRequired")
 | |
|         slot_data.update({
 | |
|             "hitlist":                [],  # remove this after next update
 | |
|             "PoptrackerVersionCheck": 4.3,
 | |
|             "KeybladeAbilities":      self.sora_ability_dict,
 | |
|             "StaffAbilities":         self.donald_ability_dict,
 | |
|             "ShieldAbilities":        self.goofy_ability_dict,
 | |
|         })
 | |
|         return slot_data
 | |
| 
 | |
|     def create_item(self, name: str) -> Item:
 | |
|         """
 | |
|         Returns created KH2Item
 | |
|         """
 | |
|         # data = item_dictionary_table[name]
 | |
|         if name in progression_set:
 | |
|             item_classification = ItemClassification.progression
 | |
|         elif name in useful_set:
 | |
|             item_classification = ItemClassification.useful
 | |
|         else:
 | |
|             item_classification = ItemClassification.filler
 | |
|         created_item = KH2Item(name, item_classification, self.item_name_to_id[name], self.player)
 | |
| 
 | |
|         return created_item
 | |
| 
 | |
|     def create_event_item(self, name: str) -> Item:
 | |
|         item_classification = ItemClassification.progression
 | |
|         created_item = KH2Item(name, item_classification, None, self.player)
 | |
|         return created_item
 | |
| 
 | |
|     def create_items(self) -> None:
 | |
|         """
 | |
|         Fills ItemPool and manages schmovement, random growth, visit locking and random starting visit locking.
 | |
|         """
 | |
|         self.visitlocking_dict = visit_locking_dict["AllVisitLocking"].copy()
 | |
|         if self.options.Schmovement != "level_0":
 | |
|             for _ in range(self.options.Schmovement.value):
 | |
|                 for name in Movement_Table.keys():
 | |
|                     self.item_quantity_dict[name] -= 1
 | |
|                     self.growth_list.remove(name)
 | |
|                     self.multiworld.push_precollected(self.create_item(name))
 | |
| 
 | |
|         if self.options.RandomGrowth:
 | |
|             max_growth = min(self.options.RandomGrowth.value, len(self.growth_list))
 | |
|             for _ in range(max_growth):
 | |
|                 random_growth = self.random.choice(self.growth_list)
 | |
|                 self.item_quantity_dict[random_growth] -= 1
 | |
|                 self.growth_list.remove(random_growth)
 | |
|                 self.multiworld.push_precollected(self.create_item(random_growth))
 | |
| 
 | |
|         if self.options.Visitlocking == "no_visit_locking":
 | |
|             for item, amount in visit_locking_dict["AllVisitLocking"].items():
 | |
|                 for _ in range(amount):
 | |
|                     self.multiworld.push_precollected(self.create_item(item))
 | |
|                     self.item_quantity_dict[item] -= 1
 | |
|                     self.visitlocking_dict[item] -= 1
 | |
|                     if self.visitlocking_dict[item] == 0:
 | |
|                         self.visitlocking_dict.pop(item)
 | |
| 
 | |
|         elif self.options.Visitlocking == "second_visit_locking":
 | |
|             for item in visit_locking_dict["2VisitLocking"]:
 | |
|                 self.item_quantity_dict[item] -= 1
 | |
|                 self.visitlocking_dict[item] -= 1
 | |
|                 if self.visitlocking_dict[item] == 0:
 | |
|                     self.visitlocking_dict.pop(item)
 | |
|                 self.multiworld.push_precollected(self.create_item(item))
 | |
| 
 | |
|         for _ in range(self.options.RandomVisitLockingItem.value):
 | |
|             if sum(self.visitlocking_dict.values()) <= 0:
 | |
|                 break
 | |
|             visitlocking_set = list(self.visitlocking_dict.keys())
 | |
|             item = self.random.choice(visitlocking_set)
 | |
|             self.item_quantity_dict[item] -= 1
 | |
|             self.visitlocking_dict[item] -= 1
 | |
|             if self.visitlocking_dict[item] == 0:
 | |
|                 self.visitlocking_dict.pop(item)
 | |
|             self.multiworld.push_precollected(self.create_item(item))
 | |
| 
 | |
|         itempool = [self.create_item(item) for item, data in self.item_quantity_dict.items() for _ in range(data)]
 | |
| 
 | |
|         # Creating filler for unfilled locations
 | |
|         itempool += [self.create_filler() for _ in range(self.total_locations - len(itempool))]
 | |
| 
 | |
|         self.multiworld.itempool += itempool
 | |
| 
 | |
|     def generate_early(self) -> None:
 | |
|         """
 | |
|         Determines the quantity of items and maps plando locations to items.
 | |
|         """
 | |
|         # Item: Quantity Map
 | |
|         # Example. Quick Run: 4
 | |
|         self.total_locations = len(all_locations.keys())
 | |
|         for x in range(4):
 | |
|             self.growth_list.extend(Movement_Table.keys())
 | |
| 
 | |
|         self.item_quantity_dict = {item: data.quantity for item, data in item_dictionary_table.items()}
 | |
|         self.sora_ability_dict = {k: v.quantity for dic in [SupportAbility_Table, ActionAbility_Table] for k, v in
 | |
|                                   dic.items()}
 | |
|         # Dictionary to mark locations with their plandoed item
 | |
|         # Example. Final Xemnas: Victory
 | |
|         # 3 random support abilities because there are left over slots
 | |
|         support_abilities = list(SupportAbility_Table.keys())
 | |
|         for _ in range(6):
 | |
|             random_support_ability = self.random.choice(support_abilities)
 | |
|             self.item_quantity_dict[random_support_ability] += 1
 | |
|             self.sora_ability_dict[random_support_ability] += 1
 | |
| 
 | |
|         self.plando_locations = dict()
 | |
|         self.starting_invo_verify()
 | |
| 
 | |
|         for k, v in self.options.CustomItemPoolQuantity.value.items():
 | |
|             # kh2's items cannot hold more than a byte
 | |
|             if 255 > v > self.item_quantity_dict[k] and k in default_itempool_option.keys():
 | |
|                 self.item_quantity_dict[k] = v
 | |
|             elif 255 <= v:
 | |
|                 logging.warning(
 | |
|                         f"{self.player} has too many {k} in their CustomItemPool setting. Setting to default quantity")
 | |
|         # Option to turn off Promise Charm Item
 | |
|         if not self.options.Promise_Charm:
 | |
|             del self.item_quantity_dict[ItemName.PromiseCharm]
 | |
| 
 | |
|         if not self.options.AntiForm:
 | |
|             del self.item_quantity_dict[ItemName.AntiForm]
 | |
| 
 | |
|         self.set_excluded_locations()
 | |
| 
 | |
|         if self.options.Goal not in ["hitlist", "three_proofs"]:
 | |
|             self.lucky_emblem_amount = self.options.LuckyEmblemsAmount.value
 | |
|             self.lucky_emblem_required = self.options.LuckyEmblemsRequired.value
 | |
|             self.emblem_verify()
 | |
| 
 | |
|         # hitlist
 | |
|         if self.options.Goal not in ["lucky_emblem_hunt", "three_proofs"]:
 | |
|             self.random_super_boss_list.extend(exclusion_table["Hitlist"])
 | |
|             self.bounties_amount = self.options.BountyAmount.value
 | |
|             self.bounties_required = self.options.BountyRequired.value
 | |
| 
 | |
|             self.hitlist_verify()
 | |
| 
 | |
|             prio_hitlist = [location for location in self.options.priority_locations.value if
 | |
|                             location in self.random_super_boss_list]
 | |
|             for bounty in range(self.options.BountyAmount.value):
 | |
|                 if prio_hitlist:
 | |
|                     random_boss = self.random.choice(prio_hitlist)
 | |
|                     prio_hitlist.remove(random_boss)
 | |
|                 else:
 | |
|                     random_boss = self.random.choice(self.random_super_boss_list)
 | |
|                 self.plando_locations[random_boss] = ItemName.Bounty
 | |
|                 self.random_super_boss_list.remove(random_boss)
 | |
|                 self.total_locations -= 1
 | |
| 
 | |
|         self.donald_gen_early()
 | |
|         self.goofy_gen_early()
 | |
|         self.keyblade_gen_early()
 | |
| 
 | |
|         # final xemnas isn't a location anymore
 | |
|         # self.total_locations -= 1
 | |
| 
 | |
|         if self.options.WeaponSlotStartHint:
 | |
|             for location in all_weapon_slot:
 | |
|                 self.options.start_location_hints.value.add(location)
 | |
| 
 | |
|         if self.options.FillerItemsLocal:
 | |
|             for item in filler_items:
 | |
|                 self.options.local_items.value.add(item)
 | |
|         # By imitating remote this doesn't have to be plandoded filler anymore
 | |
|         #  for location in {LocationName.JunkMedal, LocationName.JunkMedal}:
 | |
|         #    self.plando_locations[location] = random_stt_item
 | |
|         if not self.options.SummonLevelLocationToggle:
 | |
|             self.total_locations -= 6
 | |
| 
 | |
|         self.total_locations -= self.level_subtraction()
 | |
| 
 | |
|     def pre_fill(self):
 | |
|         """
 | |
|         Plandoing Events and Fill_Restrictive for donald,goofy and sora
 | |
|         """
 | |
|         self.donald_pre_fill()
 | |
|         self.goofy_pre_fill()
 | |
|         self.keyblade_pre_fill()
 | |
| 
 | |
|         for location, item in self.plando_locations.items():
 | |
|             self.multiworld.get_location(location, self.player).place_locked_item(
 | |
|                     self.create_item(item))
 | |
| 
 | |
|     def create_regions(self):
 | |
|         """
 | |
|         Creates the Regions and Connects them.
 | |
|         """
 | |
|         create_regions(self)
 | |
|         connect_regions(self)
 | |
| 
 | |
|     def set_rules(self):
 | |
|         """
 | |
|         Sets the Logic for the Regions and Locations.
 | |
|         """
 | |
|         universal_logic = Rules.KH2WorldRules(self)
 | |
|         form_logic = Rules.KH2FormRules(self)
 | |
|         fight_rules = Rules.KH2FightRules(self)
 | |
|         fight_rules.set_kh2_fight_rules()
 | |
|         universal_logic.set_kh2_rules()
 | |
|         form_logic.set_kh2_form_rules()
 | |
| 
 | |
|     def generate_output(self, output_directory: str):
 | |
|         """
 | |
|         Generates the .zip for OpenKH (The KH Mod Manager)
 | |
|         """
 | |
|         patch_kh2(self, output_directory)
 | |
| 
 | |
|     def donald_gen_early(self):
 | |
|         random_prog_ability = self.random.choice([ItemName.Fantasia, ItemName.FlareForce])
 | |
|         donald_master_ability = [donald_ability for donald_ability in DonaldAbility_Table.keys() for _ in
 | |
|                                  range(self.item_quantity_dict[donald_ability]) if
 | |
|                                  donald_ability != random_prog_ability]
 | |
|         self.donald_weapon_abilities = []
 | |
|         self.donald_get_bonus_abilities = []
 | |
|         # fill goofy weapons first
 | |
|         for _ in range(15):
 | |
|             random_ability = self.random.choice(donald_master_ability)
 | |
|             donald_master_ability.remove(random_ability)
 | |
|             self.donald_weapon_abilities += [self.create_item(random_ability)]
 | |
|             self.item_quantity_dict[random_ability] -= 1
 | |
|             self.total_locations -= 1
 | |
|         self.slot_data_donald_weapon = [item_name.name for item_name in self.donald_weapon_abilities]
 | |
|         if not self.options.DonaldGoofyStatsanity:
 | |
|             # pre plando donald get bonuses
 | |
|             self.donald_get_bonus_abilities += [self.create_item(random_prog_ability)]
 | |
|             self.total_locations -= 1
 | |
|             for item_name in donald_master_ability:
 | |
|                 self.donald_get_bonus_abilities += [self.create_item(item_name)]
 | |
|                 self.item_quantity_dict[item_name] -= 1
 | |
|                 self.total_locations -= 1
 | |
| 
 | |
|     def goofy_gen_early(self):
 | |
|         random_prog_ability = self.random.choice([ItemName.Teamwork, ItemName.TornadoFusion])
 | |
|         goofy_master_ability = [goofy_ability for goofy_ability in GoofyAbility_Table.keys() for _ in
 | |
|                                 range(self.item_quantity_dict[goofy_ability]) if goofy_ability != random_prog_ability]
 | |
|         self.goofy_weapon_abilities = []
 | |
|         self.goofy_get_bonus_abilities = []
 | |
|         # fill goofy weapons first
 | |
|         for _ in range(15):
 | |
|             random_ability = self.random.choice(goofy_master_ability)
 | |
|             goofy_master_ability.remove(random_ability)
 | |
|             self.goofy_weapon_abilities += [self.create_item(random_ability)]
 | |
|             self.item_quantity_dict[random_ability] -= 1
 | |
|             self.total_locations -= 1
 | |
| 
 | |
|         self.slot_data_goofy_weapon = [item_name.name for item_name in self.goofy_weapon_abilities]
 | |
| 
 | |
|         if not self.options.DonaldGoofyStatsanity:
 | |
|             # pre plando goofy get bonuses
 | |
|             self.goofy_get_bonus_abilities += [self.create_item(random_prog_ability)]
 | |
|             self.total_locations -= 1
 | |
|             for item_name in goofy_master_ability:
 | |
|                 self.goofy_get_bonus_abilities += [self.create_item(item_name)]
 | |
|                 self.item_quantity_dict[item_name] -= 1
 | |
|                 self.total_locations -= 1
 | |
| 
 | |
|     def keyblade_gen_early(self):
 | |
|         keyblade_master_ability = [ability for ability in SupportAbility_Table.keys() if ability not in progression_set
 | |
|                                    for _ in range(self.item_quantity_dict[ability])]
 | |
|         self.keyblade_ability_pool = []
 | |
| 
 | |
|         for _ in range(len(Keyblade_Slots)):
 | |
|             random_ability = self.random.choice(keyblade_master_ability)
 | |
|             keyblade_master_ability.remove(random_ability)
 | |
|             self.keyblade_ability_pool += [self.create_item(random_ability)]
 | |
|             self.item_quantity_dict[random_ability] -= 1
 | |
|             self.total_locations -= 1
 | |
|         self.slot_data_sora_weapon = [item_name.name for item_name in self.keyblade_ability_pool]
 | |
| 
 | |
|     def goofy_pre_fill(self):
 | |
|         """
 | |
|         Removes donald locations from the location pool maps random donald items to be plandoded.
 | |
|         """
 | |
|         goofy_weapon_location_list = [self.multiworld.get_location(location, self.player) for location in
 | |
|                                       Goofy_Checks.keys() if Goofy_Checks[location].yml == "Keyblade"]
 | |
|         # take one of the 2 out
 | |
|         # randomize the list with only
 | |
|         for location in goofy_weapon_location_list:
 | |
|             random_ability = self.random.choice(self.goofy_weapon_abilities)
 | |
|             location.place_locked_item(random_ability)
 | |
|             self.goofy_weapon_abilities.remove(random_ability)
 | |
| 
 | |
|         if not self.options.DonaldGoofyStatsanity:
 | |
|             # plando goofy get bonuses
 | |
|             goofy_get_bonus_location_pool = [self.multiworld.get_location(location, self.player) for location in
 | |
|                                              Goofy_Checks.keys() if Goofy_Checks[location].yml != "Keyblade"]
 | |
|             for location in goofy_get_bonus_location_pool:
 | |
|                 self.random.choice(self.goofy_get_bonus_abilities)
 | |
|                 random_ability = self.random.choice(self.goofy_get_bonus_abilities)
 | |
|                 location.place_locked_item(random_ability)
 | |
|                 self.goofy_get_bonus_abilities.remove(random_ability)
 | |
| 
 | |
|     def donald_pre_fill(self):
 | |
|         donald_weapon_location_list = [self.multiworld.get_location(location, self.player) for location in
 | |
|                                        Donald_Checks.keys() if Donald_Checks[location].yml == "Keyblade"]
 | |
| 
 | |
|         # take one of the 2 out
 | |
|         # randomize the list with only
 | |
|         for location in donald_weapon_location_list:
 | |
|             random_ability = self.random.choice(self.donald_weapon_abilities)
 | |
|             location.place_locked_item(random_ability)
 | |
|             self.donald_weapon_abilities.remove(random_ability)
 | |
| 
 | |
|         if not self.options.DonaldGoofyStatsanity:
 | |
|             # plando goofy get bonuses
 | |
|             donald_get_bonus_location_pool = [self.multiworld.get_location(location, self.player) for location in
 | |
|                                               Donald_Checks.keys() if Donald_Checks[location].yml != "Keyblade"]
 | |
|             for location in donald_get_bonus_location_pool:
 | |
|                 random_ability = self.random.choice(self.donald_get_bonus_abilities)
 | |
|                 location.place_locked_item(random_ability)
 | |
|                 self.donald_get_bonus_abilities.remove(random_ability)
 | |
| 
 | |
|     def keyblade_pre_fill(self):
 | |
|         """
 | |
|         Fills keyblade slots with abilities determined on player's setting
 | |
|         """
 | |
|         keyblade_locations = [self.multiworld.get_location(location, self.player) for location in Keyblade_Slots.keys()]
 | |
|         state = self.multiworld.get_all_state(False)
 | |
|         keyblade_ability_pool_copy = self.keyblade_ability_pool.copy()
 | |
|         fill_restrictive(self.multiworld, state, keyblade_locations, keyblade_ability_pool_copy, True, True, allow_excluded=True)
 | |
| 
 | |
|     def starting_invo_verify(self):
 | |
|         """
 | |
|         Making sure the player doesn't put too many abilities in their starting inventory.
 | |
|         """
 | |
|         for item, value in self.options.start_inventory.value.items():
 | |
|             if item in ActionAbility_Table \
 | |
|                     or item in SupportAbility_Table or item in exclusion_item_table["StatUps"] \
 | |
|                     or item in DonaldAbility_Table or item in GoofyAbility_Table:
 | |
|                 # cannot have more than the quantity for abilties
 | |
|                 if value > item_dictionary_table[item].quantity:
 | |
|                     logging.info(
 | |
|                             f"{self.multiworld.get_file_safe_player_name(self.player)} cannot have more than {item_dictionary_table[item].quantity} of {item}."
 | |
|                             f" Changing the amount to the max amount")
 | |
|                     value = item_dictionary_table[item].quantity
 | |
|                 self.item_quantity_dict[item] -= value
 | |
| 
 | |
|     def emblem_verify(self):
 | |
|         """
 | |
|         Making sure lucky emblems have amount>=required.
 | |
|         """
 | |
|         if self.lucky_emblem_amount < self.lucky_emblem_required:
 | |
|             logging.info(
 | |
|                     f"Lucky Emblem Amount {self.options.LuckyEmblemsAmount.value} is less than required "
 | |
|                     f"{self.options.LuckyEmblemsRequired.value} for player {self.multiworld.get_file_safe_player_name(self.player)}."
 | |
|                     f" Setting amount to {self.options.LuckyEmblemsRequired.value}")
 | |
|             luckyemblemamount = max(self.lucky_emblem_amount, self.lucky_emblem_required)
 | |
|             self.options.LuckyEmblemsAmount.value = luckyemblemamount
 | |
| 
 | |
|         self.item_quantity_dict[ItemName.LuckyEmblem] = self.options.LuckyEmblemsAmount.value
 | |
|         # give this proof to unlock the final door once the player has the amount of lucky emblem required
 | |
|         if ItemName.ProofofNonexistence in self.item_quantity_dict:
 | |
|             del self.item_quantity_dict[ItemName.ProofofNonexistence]
 | |
| 
 | |
|     def hitlist_verify(self):
 | |
|         """
 | |
|         Making sure hitlist have amount>=required.
 | |
|         """
 | |
|         for location in self.options.exclude_locations.value:
 | |
|             if location in self.random_super_boss_list:
 | |
|                 self.random_super_boss_list.remove(location)
 | |
| 
 | |
|         if not self.options.SummonLevelLocationToggle and LocationName.Summonlvl7 in self.random_super_boss_list:
 | |
|             self.random_super_boss_list.remove(LocationName.Summonlvl7)
 | |
| 
 | |
|         #  Testing if the player has the right amount of Bounties for Completion.
 | |
|         if len(self.random_super_boss_list) < self.bounties_amount:
 | |
|             logging.info(
 | |
|                     f"{self.multiworld.get_file_safe_player_name(self.player)} has more bounties than bosses."
 | |
|                     f" Setting total bounties to {len(self.random_super_boss_list)}")
 | |
|             self.bounties_amount = len(self.random_super_boss_list)
 | |
|             self.options.BountyAmount.value = self.bounties_amount
 | |
| 
 | |
|         if len(self.random_super_boss_list) < self.bounties_required:
 | |
|             logging.info(f"{self.multiworld.get_file_safe_player_name(self.player)} has too many required bounties."
 | |
|                          f" Setting required bounties to {len(self.random_super_boss_list)}")
 | |
|             self.bounties_required = len(self.random_super_boss_list)
 | |
|             self.options.BountyRequired.value = self.bounties_required
 | |
| 
 | |
|         if self.bounties_amount < self.bounties_required:
 | |
|             logging.info(
 | |
|                     f"Bounties Amount is less than required for player {self.multiworld.get_file_safe_player_name(self.player)}."
 | |
|                     f" Swapping Amount and Required")
 | |
|             temp = self.options.BountyRequired.value
 | |
|             self.options.BountyRequired.value = self.options.BountyAmount.value
 | |
|             self.options.BountyAmount.value = temp
 | |
| 
 | |
|         if self.options.BountyStartingHintToggle:
 | |
|             self.options.start_hints.value.add(ItemName.Bounty)
 | |
| 
 | |
|         if ItemName.ProofofNonexistence in self.item_quantity_dict:
 | |
|             del self.item_quantity_dict[ItemName.ProofofNonexistence]
 | |
| 
 | |
|     def set_excluded_locations(self):
 | |
|         """
 | |
|         Fills excluded_locations from player's settings.
 | |
|         """
 | |
|         # Option to turn off all superbosses. Can do this individually but its like 20+ checks
 | |
|         if not self.options.SuperBosses:
 | |
|             for superboss in exclusion_table["SuperBosses"]:
 | |
|                 self.options.exclude_locations.value.add(superboss)
 | |
| 
 | |
|         # Option to turn off Olympus Colosseum Cups.
 | |
|         if self.options.Cups == "no_cups":
 | |
|             for cup in exclusion_table["Cups"]:
 | |
|                 self.options.exclude_locations.value.add(cup)
 | |
|         # exclude only hades paradox. If cups and hades paradox then nothing is excluded
 | |
|         elif self.options.Cups == "cups":
 | |
|             self.options.exclude_locations.value.add(LocationName.HadesCupTrophyParadoxCups)
 | |
| 
 | |
|         if not self.options.AtlanticaToggle:
 | |
|             for loc in exclusion_table["Atlantica"]:
 | |
|                 self.options.exclude_locations.value.add(loc)
 | |
| 
 | |
|     def level_subtraction(self):
 | |
|         """
 | |
|        Determine how many locations are on sora's levels.
 | |
|        """
 | |
|         if self.options.LevelDepth == "level_50_sanity":
 | |
|             # level 50 sanity
 | |
|             return 49
 | |
|         elif self.options.LevelDepth == "level_1":
 | |
|             # level 1. No checks on levels
 | |
|             return 98
 | |
|         elif self.options.LevelDepth in ["level_50", "level_99"]:
 | |
|             # could be if leveldepth!= 99 sanity but this reads better imo
 | |
|             return 75
 | |
|         else:
 | |
|             return 0
 | |
| 
 | |
|     def get_filler_item_name(self) -> str:
 | |
|         """
 | |
|         Returns random filler item name.
 | |
|         """
 | |
|         return self.random.choice(filler_items)
 |