KH2: init cleanup and random visit locking fix and docs update. (#1652)
Random Visit Locking wasn't copying correctly init cleanup and moved itempool population to create_items Updated docs due to a lot of people having issues setting it up.
This commit is contained in:
parent
6059b5ef66
commit
81411a191c
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
from BaseClasses import Tutorial, ItemClassification
|
from BaseClasses import Tutorial, ItemClassification
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
@ -41,6 +40,10 @@ class KH2World(World):
|
||||||
|
|
||||||
def __init__(self, multiworld: "MultiWorld", player: int):
|
def __init__(self, multiworld: "MultiWorld", player: int):
|
||||||
super().__init__(multiworld, player)
|
super().__init__(multiworld, player)
|
||||||
|
self.visitlocking_dict = None
|
||||||
|
self.plando_locations = None
|
||||||
|
self.luckyemblemamount = None
|
||||||
|
self.luckyemblemrequired = None
|
||||||
self.BountiesRequired = None
|
self.BountiesRequired = None
|
||||||
self.BountiesAmount = None
|
self.BountiesAmount = None
|
||||||
self.hitlist = None
|
self.hitlist = None
|
||||||
|
@ -57,7 +60,6 @@ class KH2World(World):
|
||||||
self.growth_list = list()
|
self.growth_list = list()
|
||||||
for x in range(4):
|
for x in range(4):
|
||||||
self.growth_list.extend(Movement_Table.keys())
|
self.growth_list.extend(Movement_Table.keys())
|
||||||
self.visitlocking_dict = Progression_Dicts["AllVisitLocking"]
|
|
||||||
|
|
||||||
def fill_slot_data(self) -> dict:
|
def fill_slot_data(self) -> dict:
|
||||||
return {"hitlist": self.hitlist,
|
return {"hitlist": self.hitlist,
|
||||||
|
@ -78,11 +80,168 @@ class KH2World(World):
|
||||||
|
|
||||||
return created_item
|
return created_item
|
||||||
|
|
||||||
|
def create_items(self) -> None:
|
||||||
|
itempool: typing.List[Item] = []
|
||||||
|
|
||||||
|
self.visitlocking_dict = Progression_Dicts["AllVisitLocking"].copy()
|
||||||
|
if self.multiworld.Schmovement[self.player] != "level_0":
|
||||||
|
for _ in range(self.multiworld.Schmovement[self.player].value):
|
||||||
|
for name in {ItemName.HighJump, ItemName.QuickRun, ItemName.DodgeRoll, ItemName.AerialDodge,
|
||||||
|
ItemName.Glide}:
|
||||||
|
self.item_quantity_dict[name] -= 1
|
||||||
|
self.growth_list.remove(name)
|
||||||
|
self.multiworld.push_precollected(self.create_item(name))
|
||||||
|
|
||||||
|
if self.multiworld.RandomGrowth[self.player] != 0:
|
||||||
|
max_growth = min(self.multiworld.RandomGrowth[self.player].value, len(self.growth_list))
|
||||||
|
for _ in range(max_growth):
|
||||||
|
random_growth = self.multiworld.per_slot_randoms[self.player].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.multiworld.Visitlocking[self.player] == "no_visit_locking":
|
||||||
|
for item, amount in Progression_Dicts["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.multiworld.Visitlocking[self.player] == "second_visit_locking":
|
||||||
|
for item in Progression_Dicts["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.multiworld.RandomVisitLockingItem[self.player].value):
|
||||||
|
if sum(self.visitlocking_dict.values()) <= 0:
|
||||||
|
break
|
||||||
|
visitlocking_set = list(self.visitlocking_dict.keys())
|
||||||
|
item = self.multiworld.per_slot_randoms[self.player].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))
|
||||||
|
|
||||||
|
for item in item_dictionary_table:
|
||||||
|
data = self.item_quantity_dict[item]
|
||||||
|
itempool += [self.create_item(item) for _ in range(data)]
|
||||||
|
|
||||||
|
# Creating filler for unfilled locations
|
||||||
|
itempool += [self.create_filler()
|
||||||
|
for _ in range(self.totalLocations-len(itempool))]
|
||||||
|
self.multiworld.itempool += itempool
|
||||||
|
|
||||||
def generate_early(self) -> None:
|
def generate_early(self) -> None:
|
||||||
# Item Quantity dict because Abilities can be a problem for KH2's Software.
|
# Item Quantity dict because Abilities can be a problem for KH2's Software.
|
||||||
for item, data in item_dictionary_table.items():
|
for item, data in item_dictionary_table.items():
|
||||||
self.item_quantity_dict[item] = data.quantity
|
self.item_quantity_dict[item] = data.quantity
|
||||||
|
# Dictionary to mark locations with their plandoed item
|
||||||
|
# Example. Final Xemnas: Victory
|
||||||
|
self.plando_locations = dict()
|
||||||
|
self.hitlist = []
|
||||||
|
self.starting_invo_verify()
|
||||||
|
|
||||||
|
# Option to turn off Promise Charm Item
|
||||||
|
if not self.multiworld.Promise_Charm[self.player]:
|
||||||
|
self.item_quantity_dict[ItemName.PromiseCharm] = 0
|
||||||
|
|
||||||
|
self.set_excluded_locations()
|
||||||
|
|
||||||
|
if self.multiworld.Goal[self.player] == "lucky_emblem_hunt":
|
||||||
|
self.luckyemblemamount = self.multiworld.LuckyEmblemsAmount[self.player].value
|
||||||
|
self.luckyemblemrequired = self.multiworld.LuckyEmblemsRequired[self.player].value
|
||||||
|
self.emblem_verify()
|
||||||
|
|
||||||
|
# hitlist
|
||||||
|
elif self.multiworld.Goal[self.player] == "hitlist":
|
||||||
|
self.RandomSuperBoss.extend(exclusion_table["Hitlist"])
|
||||||
|
self.BountiesAmount = self.multiworld.BountyAmount[self.player].value
|
||||||
|
self.BountiesRequired = self.multiworld.BountyRequired[self.player].value
|
||||||
|
|
||||||
|
self.hitlist_verify()
|
||||||
|
|
||||||
|
for bounty in range(self.BountiesAmount):
|
||||||
|
randomBoss = self.multiworld.per_slot_randoms[self.player].choice(self.RandomSuperBoss)
|
||||||
|
self.plando_locations[randomBoss] = ItemName.Bounty
|
||||||
|
self.hitlist.append(self.location_name_to_id[randomBoss])
|
||||||
|
self.RandomSuperBoss.remove(randomBoss)
|
||||||
|
self.totalLocations -= 1
|
||||||
|
|
||||||
|
self.donald_fill()
|
||||||
|
self.goofy_fill()
|
||||||
|
self.keyblade_fill()
|
||||||
|
|
||||||
|
if self.multiworld.FinalXemnas[self.player]:
|
||||||
|
self.plando_locations[LocationName.FinalXemnas] = ItemName.Victory
|
||||||
|
else:
|
||||||
|
self.plando_locations[LocationName.FinalXemnas] = self.create_filler().name
|
||||||
|
|
||||||
|
# same item placed because you can only get one of these 2 locations
|
||||||
|
# they are both under the same flag so the player gets both locations just one of the two items
|
||||||
|
random_stt_item = self.create_filler().name
|
||||||
|
for location in {LocationName.JunkMedal, LocationName.JunkMedal}:
|
||||||
|
self.plando_locations[location] = random_stt_item
|
||||||
|
self.level_subtraction()
|
||||||
|
# subtraction from final xemnas and stt
|
||||||
|
self.totalLocations -= 3
|
||||||
|
|
||||||
|
def pre_fill(self):
|
||||||
|
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):
|
||||||
|
location_table = setup_locations()
|
||||||
|
create_regions(self.multiworld, self.player, location_table)
|
||||||
|
connect_regions(self.multiworld, self.player)
|
||||||
|
|
||||||
|
def set_rules(self):
|
||||||
|
set_rules(self.multiworld, self.player)
|
||||||
|
|
||||||
|
def generate_output(self, output_directory: str):
|
||||||
|
patch_kh2(self, output_directory)
|
||||||
|
|
||||||
|
def donald_fill(self):
|
||||||
|
for item in DonaldAbility_Table:
|
||||||
|
data = self.item_quantity_dict[item]
|
||||||
|
for _ in range(data):
|
||||||
|
self.donald_ability_pool.append(item)
|
||||||
|
self.item_quantity_dict[item] = 0
|
||||||
|
# 32 is the amount of donald abilities
|
||||||
|
while len(self.donald_ability_pool) < 32:
|
||||||
|
self.donald_ability_pool.append(
|
||||||
|
self.multiworld.per_slot_randoms[self.player].choice(self.donald_ability_pool))
|
||||||
|
# Placing Donald Abilities on donald locations
|
||||||
|
for donaldLocation in Locations.Donald_Checks.keys():
|
||||||
|
random_ability = self.multiworld.per_slot_randoms[self.player].choice(self.donald_ability_pool)
|
||||||
|
self.plando_locations[donaldLocation] = random_ability
|
||||||
|
self.totalLocations -= 1
|
||||||
|
self.donald_ability_pool.remove(random_ability)
|
||||||
|
|
||||||
|
def goofy_fill(self):
|
||||||
|
for item in GoofyAbility_Table.keys():
|
||||||
|
data = self.item_quantity_dict[item]
|
||||||
|
for _ in range(data):
|
||||||
|
self.goofy_ability_pool.append(item)
|
||||||
|
self.item_quantity_dict[item] = 0
|
||||||
|
# 32 is the amount of goofy abilities
|
||||||
|
while len(self.goofy_ability_pool) < 33:
|
||||||
|
self.goofy_ability_pool.append(
|
||||||
|
self.multiworld.per_slot_randoms[self.player].choice(self.goofy_ability_pool))
|
||||||
|
# Placing Goofy Abilities on goofy locations
|
||||||
|
for goofyLocation in Locations.Goofy_Checks.keys():
|
||||||
|
random_ability = self.multiworld.per_slot_randoms[self.player].choice(self.goofy_ability_pool)
|
||||||
|
self.plando_locations[goofyLocation] = random_ability
|
||||||
|
self.totalLocations -= 1
|
||||||
|
self.goofy_ability_pool.remove(random_ability)
|
||||||
|
|
||||||
|
def keyblade_fill(self):
|
||||||
if self.multiworld.KeybladeAbilities[self.player] == "support":
|
if self.multiworld.KeybladeAbilities[self.player] == "support":
|
||||||
self.sora_keyblade_ability_pool.extend(SupportAbility_Table.keys())
|
self.sora_keyblade_ability_pool.extend(SupportAbility_Table.keys())
|
||||||
elif self.multiworld.KeybladeAbilities[self.player] == "action":
|
elif self.multiworld.KeybladeAbilities[self.player] == "action":
|
||||||
|
@ -93,64 +252,65 @@ class KH2World(World):
|
||||||
self.sora_keyblade_ability_pool.extend(ActionAbility_Table.keys())
|
self.sora_keyblade_ability_pool.extend(ActionAbility_Table.keys())
|
||||||
self.sora_keyblade_ability_pool.extend(SupportAbility_Table.keys())
|
self.sora_keyblade_ability_pool.extend(SupportAbility_Table.keys())
|
||||||
|
|
||||||
for item, value in self.multiworld.start_inventory[self.player].value.items():
|
|
||||||
if item in ActionAbility_Table.keys() or item in SupportAbility_Table.keys() or exclusionItem_table["StatUps"]:
|
|
||||||
# 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
|
|
||||||
|
|
||||||
# Option to turn off Promise Charm Item
|
|
||||||
if not self.multiworld.Promise_Charm[self.player]:
|
|
||||||
self.item_quantity_dict[ItemName.PromiseCharm] = 0
|
|
||||||
|
|
||||||
for ability in self.multiworld.BlacklistKeyblade[self.player].value:
|
for ability in self.multiworld.BlacklistKeyblade[self.player].value:
|
||||||
if ability in self.sora_keyblade_ability_pool:
|
if ability in self.sora_keyblade_ability_pool:
|
||||||
self.sora_keyblade_ability_pool.remove(ability)
|
self.sora_keyblade_ability_pool.remove(ability)
|
||||||
|
|
||||||
# Option to turn off all superbosses. Can do this individually but its like 20+ checks
|
while len(self.sora_keyblade_ability_pool) < len(self.keyblade_slot_copy):
|
||||||
if not self.multiworld.SuperBosses[self.player] and not self.multiworld.Goal[self.player] == "hitlist":
|
self.sora_keyblade_ability_pool.append(
|
||||||
for superboss in exclusion_table["Datas"]:
|
self.multiworld.per_slot_randoms[self.player].choice(list(SupportAbility_Table.keys())))
|
||||||
self.multiworld.exclude_locations[self.player].value.add(superboss)
|
|
||||||
for superboss in exclusion_table["SuperBosses"]:
|
|
||||||
self.multiworld.exclude_locations[self.player].value.add(superboss)
|
|
||||||
|
|
||||||
# Option to turn off Olympus Colosseum Cups.
|
# Kingdom Key cannot have No Experience so plandoed here instead of checking 26 times if its kingdom key
|
||||||
if self.multiworld.Cups[self.player] == "no_cups":
|
random_ability = self.multiworld.per_slot_randoms[self.player].choice(self.sora_keyblade_ability_pool)
|
||||||
for cup in exclusion_table["Cups"]:
|
while random_ability == ItemName.NoExperience:
|
||||||
self.multiworld.exclude_locations[self.player].value.add(cup)
|
random_ability = self.multiworld.per_slot_randoms[self.player].choice(self.sora_keyblade_ability_pool)
|
||||||
# exclude only hades paradox. If cups and hades paradox then nothing is excluded
|
self.plando_locations[LocationName.KingdomKeySlot] = random_ability
|
||||||
elif self.multiworld.Cups[self.player] == "cups":
|
self.item_quantity_dict[random_ability] -= 1
|
||||||
self.multiworld.exclude_locations[self.player].value.add(LocationName.HadesCupTrophyParadoxCups)
|
self.sora_keyblade_ability_pool.remove(random_ability)
|
||||||
|
|
||||||
if self.multiworld.Goal[self.player] == "lucky_emblem_hunt":
|
# plando keyblades because they can only have abilities
|
||||||
luckyemblemamount = self.multiworld.LuckyEmblemsAmount[self.player].value
|
for keyblade in self.keyblade_slot_copy:
|
||||||
luckyemblemrequired = self.multiworld.LuckyEmblemsRequired[self.player].value
|
random_ability = self.multiworld.per_slot_randoms[self.player].choice(self.sora_keyblade_ability_pool)
|
||||||
if luckyemblemamount < luckyemblemrequired:
|
self.plando_locations[keyblade] = random_ability
|
||||||
logging.info(f"Lucky Emblem Amount {self.multiworld.LuckyEmblemsAmount[self.player].value} is less than required "
|
self.item_quantity_dict[random_ability] -= 1
|
||||||
|
self.sora_keyblade_ability_pool.remove(random_ability)
|
||||||
|
self.totalLocations -= 1
|
||||||
|
|
||||||
|
def starting_invo_verify(self):
|
||||||
|
for item, value in self.multiworld.start_inventory[self.player].value.items():
|
||||||
|
if item in ActionAbility_Table \
|
||||||
|
or item in SupportAbility_Table or exclusionItem_table["StatUps"]:
|
||||||
|
# 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):
|
||||||
|
if self.luckyemblemamount < self.luckyemblemrequired:
|
||||||
|
logging.info(
|
||||||
|
f"Lucky Emblem Amount {self.multiworld.LuckyEmblemsAmount[self.player].value} is less than required "
|
||||||
f"{self.multiworld.LuckyEmblemsRequired[self.player].value} for player {self.multiworld.get_file_safe_player_name(self.player)}."
|
f"{self.multiworld.LuckyEmblemsRequired[self.player].value} for player {self.multiworld.get_file_safe_player_name(self.player)}."
|
||||||
f" Setting amount to {self.multiworld.LuckyEmblemsRequired[self.player].value}")
|
f" Setting amount to {self.multiworld.LuckyEmblemsRequired[self.player].value}")
|
||||||
luckyemblemamount = max(luckyemblemamount, luckyemblemrequired)
|
luckyemblemamount = max(self.luckyemblemamount, self.luckyemblemrequired)
|
||||||
self.multiworld.LuckyEmblemsAmount[self.player].value = luckyemblemamount
|
self.multiworld.LuckyEmblemsAmount[self.player].value = luckyemblemamount
|
||||||
|
|
||||||
self.item_quantity_dict[ItemName.LuckyEmblem] = item_dictionary_table[ItemName.LuckyEmblem].quantity + luckyemblemamount
|
self.item_quantity_dict[ItemName.LuckyEmblem] = item_dictionary_table[
|
||||||
|
ItemName.LuckyEmblem].quantity + self.luckyemblemamount
|
||||||
# give this proof to unlock the final door once the player has the amount of lucky emblem required
|
# give this proof to unlock the final door once the player has the amount of lucky emblem required
|
||||||
self.item_quantity_dict[ItemName.ProofofNonexistence] = 0
|
self.item_quantity_dict[ItemName.ProofofNonexistence] = 0
|
||||||
|
|
||||||
# hitlist
|
def hitlist_verify(self):
|
||||||
elif self.multiworld.Goal[self.player] == "hitlist":
|
|
||||||
self.RandomSuperBoss.extend(exclusion_table["Hitlist"])
|
|
||||||
self.BountiesAmount = self.multiworld.BountyAmount[self.player].value
|
|
||||||
self.BountiesRequired = self.multiworld.BountyRequired[self.player].value
|
|
||||||
|
|
||||||
for location in self.multiworld.exclude_locations[self.player].value:
|
for location in self.multiworld.exclude_locations[self.player].value:
|
||||||
if location in self.RandomSuperBoss:
|
if location in self.RandomSuperBoss:
|
||||||
self.RandomSuperBoss.remove(location)
|
self.RandomSuperBoss.remove(location)
|
||||||
|
|
||||||
# Testing if the player has the right amount of Bounties for Completion.
|
# Testing if the player has the right amount of Bounties for Completion.
|
||||||
if len(self.RandomSuperBoss) < self.BountiesAmount:
|
if len(self.RandomSuperBoss) < self.BountiesAmount:
|
||||||
logging.info(f"{self.multiworld.get_file_safe_player_name(self.player)} has too many bounties than bosses."
|
logging.info(
|
||||||
|
f"{self.multiworld.get_file_safe_player_name(self.player)} has more bounties than bosses."
|
||||||
f" Setting total bounties to {len(self.RandomSuperBoss)}")
|
f" Setting total bounties to {len(self.RandomSuperBoss)}")
|
||||||
self.BountiesAmount = len(self.RandomSuperBoss)
|
self.BountiesAmount = len(self.RandomSuperBoss)
|
||||||
self.multiworld.BountyAmount[self.player].value = self.BountiesAmount
|
self.multiworld.BountyAmount[self.player].value = self.BountiesAmount
|
||||||
|
@ -171,139 +331,24 @@ class KH2World(World):
|
||||||
self.multiworld.start_hints[self.player].value.add(ItemName.Bounty)
|
self.multiworld.start_hints[self.player].value.add(ItemName.Bounty)
|
||||||
self.item_quantity_dict[ItemName.ProofofNonexistence] = 0
|
self.item_quantity_dict[ItemName.ProofofNonexistence] = 0
|
||||||
|
|
||||||
while len(self.sora_keyblade_ability_pool) < len(self.keyblade_slot_copy):
|
def set_excluded_locations(self):
|
||||||
self.sora_keyblade_ability_pool.append(
|
# Option to turn off all superbosses. Can do this individually but its like 20+ checks
|
||||||
self.multiworld.per_slot_randoms[self.player].choice(list(SupportAbility_Table.keys())))
|
if not self.multiworld.SuperBosses[self.player] and not self.multiworld.Goal[self.player] == "hitlist":
|
||||||
|
for superboss in exclusion_table["Datas"]:
|
||||||
|
self.multiworld.exclude_locations[self.player].value.add(superboss)
|
||||||
|
for superboss in exclusion_table["SuperBosses"]:
|
||||||
|
self.multiworld.exclude_locations[self.player].value.add(superboss)
|
||||||
|
|
||||||
for item in DonaldAbility_Table.keys():
|
# Option to turn off Olympus Colosseum Cups.
|
||||||
data = self.item_quantity_dict[item]
|
if self.multiworld.Cups[self.player] == "no_cups":
|
||||||
for _ in range(data):
|
for cup in exclusion_table["Cups"]:
|
||||||
self.donald_ability_pool.append(item)
|
self.multiworld.exclude_locations[self.player].value.add(cup)
|
||||||
self.item_quantity_dict[item] = 0
|
# exclude only hades paradox. If cups and hades paradox then nothing is excluded
|
||||||
# 32 is the amount of donald abilities
|
elif self.multiworld.Cups[self.player] == "cups":
|
||||||
while len(self.donald_ability_pool) < 32:
|
self.multiworld.exclude_locations[self.player].value.add(LocationName.HadesCupTrophyParadoxCups)
|
||||||
self.donald_ability_pool.append(self.multiworld.per_slot_randoms[self.player].choice(self.donald_ability_pool))
|
|
||||||
|
|
||||||
for item in GoofyAbility_Table.keys():
|
def level_subtraction(self):
|
||||||
data = self.item_quantity_dict[item]
|
# there are levels but level 1 is there for the yamls
|
||||||
for _ in range(data):
|
|
||||||
self.goofy_ability_pool.append(item)
|
|
||||||
self.item_quantity_dict[item] = 0
|
|
||||||
# 32 is the amount of goofy abilities
|
|
||||||
while len(self.goofy_ability_pool) < 33:
|
|
||||||
self.goofy_ability_pool.append(self.multiworld.per_slot_randoms[self.player].choice(self.goofy_ability_pool))
|
|
||||||
|
|
||||||
def generate_basic(self):
|
|
||||||
itempool: typing.List[KH2Item] = []
|
|
||||||
|
|
||||||
self.hitlist = list()
|
|
||||||
self.filler_items.extend(item_groups["Filler"])
|
|
||||||
|
|
||||||
if self.multiworld.FinalXemnas[self.player]:
|
|
||||||
self.multiworld.get_location(LocationName.FinalXemnas, self.player).place_locked_item(
|
|
||||||
self.create_item(ItemName.Victory))
|
|
||||||
else:
|
|
||||||
self.multiworld.get_location(LocationName.FinalXemnas, self.player).place_locked_item(
|
|
||||||
self.create_item(self.multiworld.per_slot_randoms[self.player].choice(self.filler_items)))
|
|
||||||
self.totalLocations -= 1
|
|
||||||
|
|
||||||
if self.multiworld.Goal[self.player] == "hitlist":
|
|
||||||
for bounty in range(self.BountiesAmount):
|
|
||||||
randomBoss = self.multiworld.per_slot_randoms[self.player].choice(self.RandomSuperBoss)
|
|
||||||
self.multiworld.get_location(randomBoss, self.player).place_locked_item(
|
|
||||||
self.create_item(ItemName.Bounty))
|
|
||||||
self.hitlist.append(self.location_name_to_id[randomBoss])
|
|
||||||
self.RandomSuperBoss.remove(randomBoss)
|
|
||||||
self.totalLocations -= 1
|
|
||||||
|
|
||||||
# Kingdom Key cannot have No Experience so plandoed here instead of checking 26 times if its kingdom key
|
|
||||||
random_ability = self.multiworld.per_slot_randoms[self.player].choice(self.sora_keyblade_ability_pool)
|
|
||||||
while random_ability == ItemName.NoExperience:
|
|
||||||
random_ability = self.multiworld.per_slot_randoms[self.player].choice(self.sora_keyblade_ability_pool)
|
|
||||||
self.multiworld.get_location(LocationName.KingdomKeySlot, self.player).place_locked_item(self.create_item(random_ability))
|
|
||||||
self.item_quantity_dict[random_ability] -= 1
|
|
||||||
self.sora_keyblade_ability_pool.remove(random_ability)
|
|
||||||
self.totalLocations -= 1
|
|
||||||
|
|
||||||
# plando keyblades because they can only have abilities
|
|
||||||
for keyblade in self.keyblade_slot_copy:
|
|
||||||
random_ability = self.multiworld.per_slot_randoms[self.player].choice(self.sora_keyblade_ability_pool)
|
|
||||||
self.multiworld.get_location(keyblade, self.player).place_locked_item(self.create_item(random_ability))
|
|
||||||
self.item_quantity_dict[random_ability] -= 1
|
|
||||||
self.sora_keyblade_ability_pool.remove(random_ability)
|
|
||||||
self.totalLocations -= 1
|
|
||||||
|
|
||||||
# Placing Donald Abilities on donald locations
|
|
||||||
for donaldLocation in Locations.Donald_Checks.keys():
|
|
||||||
random_ability = self.multiworld.per_slot_randoms[self.player].choice(self.donald_ability_pool)
|
|
||||||
self.multiworld.get_location(donaldLocation, self.player).place_locked_item(
|
|
||||||
self.create_item(random_ability))
|
|
||||||
self.totalLocations -= 1
|
|
||||||
self.donald_ability_pool.remove(random_ability)
|
|
||||||
|
|
||||||
# Placing Goofy Abilities on goofy locations
|
|
||||||
for goofyLocation in Locations.Goofy_Checks.keys():
|
|
||||||
random_ability = self.multiworld.per_slot_randoms[self.player].choice(self.goofy_ability_pool)
|
|
||||||
self.multiworld.get_location(goofyLocation, self.player).place_locked_item(self.create_item(random_ability))
|
|
||||||
self.totalLocations -= 1
|
|
||||||
self.goofy_ability_pool.remove(random_ability)
|
|
||||||
|
|
||||||
# same item placed because you can only get one of these 2 locations
|
|
||||||
# they are both under the same flag so the player gets both locations just one of the two items
|
|
||||||
random_stt_item = self.multiworld.per_slot_randoms[self.player].choice(self.filler_items)
|
|
||||||
self.multiworld.get_location(LocationName.JunkChampionBelt, self.player).place_locked_item(
|
|
||||||
self.create_item(random_stt_item))
|
|
||||||
self.multiworld.get_location(LocationName.JunkMedal, self.player).place_locked_item(
|
|
||||||
self.create_item(random_stt_item))
|
|
||||||
self.totalLocations -= 2
|
|
||||||
|
|
||||||
if self.multiworld.Schmovement[self.player] != "level_0":
|
|
||||||
for _ in range(self.multiworld.Schmovement[self.player].value):
|
|
||||||
for name in {ItemName.HighJump, ItemName.QuickRun, ItemName.DodgeRoll, ItemName.AerialDodge,
|
|
||||||
ItemName.Glide}:
|
|
||||||
self.item_quantity_dict[name] -= 1
|
|
||||||
self.growth_list.remove(name)
|
|
||||||
self.multiworld.push_precollected(self.create_item(name))
|
|
||||||
|
|
||||||
if self.multiworld.RandomGrowth[self.player] != 0:
|
|
||||||
max_growth = min(self.multiworld.RandomGrowth[self.player].value, len(self.growth_list))
|
|
||||||
for _ in range(max_growth):
|
|
||||||
random_growth = self.multiworld.per_slot_randoms[self.player].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))
|
|
||||||
|
|
||||||
# no visit locking
|
|
||||||
if self.multiworld.Visitlocking[self.player] == "no_visit_locking":
|
|
||||||
for item, amount in Progression_Dicts["AllVisitLocking"].items():
|
|
||||||
for _ in range(amount):
|
|
||||||
self.multiworld.push_precollected(self.create_item(item))
|
|
||||||
self.item_quantity_dict[item] -= 1
|
|
||||||
if self.visitlocking_dict[item] == 0:
|
|
||||||
self.visitlocking_dict.pop(item)
|
|
||||||
self.visitlocking_dict[item] -= 1
|
|
||||||
|
|
||||||
# first and second visit locking
|
|
||||||
elif self.multiworld.Visitlocking[self.player] == "second_visit_locking":
|
|
||||||
for item in Progression_Dicts["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.multiworld.RandomVisitLockingItem[self.player].value):
|
|
||||||
if sum(self.visitlocking_dict.values()) <= 0:
|
|
||||||
break
|
|
||||||
visitlocking_set = list(self.visitlocking_dict.keys())
|
|
||||||
item = self.multiworld.per_slot_randoms[self.player].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))
|
|
||||||
|
|
||||||
# there are levels but level 1 is there to keep code clean
|
|
||||||
if self.multiworld.LevelDepth[self.player] == "level_99_sanity":
|
if self.multiworld.LevelDepth[self.player] == "level_99_sanity":
|
||||||
# level 99 sanity
|
# level 99 sanity
|
||||||
self.totalLocations -= 1
|
self.totalLocations -= 1
|
||||||
|
@ -317,24 +362,5 @@ class KH2World(World):
|
||||||
# level 50/99 since they contain the same amount of levels
|
# level 50/99 since they contain the same amount of levels
|
||||||
self.totalLocations -= 76
|
self.totalLocations -= 76
|
||||||
|
|
||||||
for item in item_dictionary_table:
|
def get_filler_item_name(self) -> str:
|
||||||
data = self.item_quantity_dict[item]
|
return self.multiworld.random.choice([ItemName.PowerBoost, ItemName.MagicBoost, ItemName.DefenseBoost, ItemName.APBoost])
|
||||||
for _ in range(data):
|
|
||||||
itempool.append(self.create_item(item))
|
|
||||||
|
|
||||||
# Creating filler for unfilled locations
|
|
||||||
while len(itempool) < self.totalLocations:
|
|
||||||
item = self.multiworld.per_slot_randoms[self.player].choice(self.filler_items)
|
|
||||||
itempool += [self.create_item(item)]
|
|
||||||
self.multiworld.itempool += itempool
|
|
||||||
|
|
||||||
def create_regions(self):
|
|
||||||
location_table = setup_locations()
|
|
||||||
create_regions(self.multiworld, self.player, location_table)
|
|
||||||
connect_regions(self.multiworld, self.player)
|
|
||||||
|
|
||||||
def set_rules(self):
|
|
||||||
set_rules(self.multiworld, self.player)
|
|
||||||
|
|
||||||
def generate_output(self, output_directory: str):
|
|
||||||
patch_kh2(self, output_directory)
|
|
||||||
|
|
|
@ -72,36 +72,3 @@ With the help of Shananas, Num, and ZakTheRobot we have many QoL features such a
|
||||||
- Removal of Absent Silhouette and go straight into the Data Fights.
|
- Removal of Absent Silhouette and go straight into the Data Fights.
|
||||||
- And much more can be found at [Kingdom Hearts 2 GoA Overview](https://tommadness.github.io/KH2Randomizer/overview/)
|
- And much more can be found at [Kingdom Hearts 2 GoA Overview](https://tommadness.github.io/KH2Randomizer/overview/)
|
||||||
|
|
||||||
<h2 style="text-transform:none";>Recommendation</h2>
|
|
||||||
|
|
||||||
- Recommended making a save at the start of the GoA before opening anything. This will be the recommended file to load if/when your game crashes.
|
|
||||||
- If you don't want to have a save in the GoA. Disconnect the client, load the auto save, and then reconnect the client after it loads the auto save.
|
|
||||||
- Recommended to set fps limit to 60fps.
|
|
||||||
- Recommended to run the game in windows/borderless windowed mode. Fullscreen is stable but the game can crash if you alt-tab out.
|
|
||||||
- Recommend viewing [Requirements/logic sheet](https://docs.google.com/spreadsheets/d/1Embae0t7pIrbzvX-NRywk7bTHHEvuFzzQBUUpSUL7Ak/edit?usp=sharing)
|
|
||||||
|
|
||||||
<h2 style="text-transform:none";>F.A.Q.</h2>
|
|
||||||
|
|
||||||
- Why am I not getting magic?
|
|
||||||
- If you obtain magic, you will need to pause your game to have it show up in your inventory, then enter a new room for it to become properly usable.
|
|
||||||
- Why am I missing worlds/portals in the GoA?
|
|
||||||
- You are missing the required visit locking item to access the world/portal.
|
|
||||||
- What versions of Kingdom Hearts 2 are supported?
|
|
||||||
- Currently `only` the most up to date version on the Epic Game Store is supported `1.0.0.8_WW`. Emulator may be added in the future.
|
|
||||||
- Why did I crash?
|
|
||||||
- The port of Kingdom Hearts 2 can and will randomly crash, this is the fault of the game not the randomizer or the archipelago client.
|
|
||||||
- If you have a continuous/constant crash (in the same area/event every time) you will want to reverify your installed files. This can be done by doing the following: Open Epic Game Store --> Library --> Click Triple Dots --> Manage --> Verify
|
|
||||||
- Why am I getting dummy items or letters?
|
|
||||||
- You will need to get the `JaredWeakStrike/APCompanion` (you can find how to get this in the setup guide)
|
|
||||||
- Why is my HP/MP continuously increasing without stopping?
|
|
||||||
- You do not have `JaredWeakStrike/APCompanion` setup correctly. Make Sure it is above the GOA in the mod manager.
|
|
||||||
- Why am I not sending or receiving items?
|
|
||||||
- Make sure you are connected to the KH2 client and the correct room (for more information reference the setup guide)
|
|
||||||
- Why did I not load in to the correct visit
|
|
||||||
- You need to trigger a cutscene or visit The World That Never Was for it to update you have recevied the item.
|
|
||||||
- Why should I install the auto save mod at `KH2FM-Mods-equations19/auto-save`?
|
|
||||||
- Because Kingdom Hearts 2 is prone to crashes and will keep you from losing your progress.
|
|
||||||
- How do I load an auto save?
|
|
||||||
- To load an auto-save, hold down the Select or your equivalent on your prefered controller while choosing a file. Make sure to hold the button down the whole time.
|
|
||||||
- How do I do a soft reset?
|
|
||||||
- Hold L1+L2+R1+R2+Start or your equivalent on your prefered controller at the same time to immediately reset the game to the start screen.
|
|
||||||
|
|
|
@ -1,48 +1,98 @@
|
||||||
# Kingdom Hearts 2 Archipelago Setup Guide
|
# Kingdom Hearts 2 Archipelago Setup Guide
|
||||||
<h2 style="text-transform:none";>Quick Links</h2>
|
<h2 style="text-transform:none";>Quick Links</h2>
|
||||||
|
|
||||||
- [Main Page](../../../../games/Kingdom%20Hearts%202/info/en)
|
- [Game Info Page](../../../../games/Kingdom%20Hearts%202/info/en)
|
||||||
- [Settings Page](../../../../games/Kingdom%20Hearts%202/player-settings)
|
- [Player Settings Page](../../../../games/Kingdom%20Hearts%202/player-settings)
|
||||||
|
|
||||||
<h2 style="text-transform:none";>Setting up the Mod Manager</h2>
|
<h2 style="text-transform:none";>Required Software:</h2>
|
||||||
|
`Kingdom Hearts II Final Mix` from the [Epic Games Store](https://store.epicgames.com/en-US/discover/kingdom-hearts)
|
||||||
|
- Follow this Guide to set up these requirements [KH2Rando.com](https://tommadness.github.io/KH2Randomizer/setup/Panacea-ModLoader/)<br>
|
||||||
|
1. `3.0.0 OpenKH Mod Manager with Panacea`<br>
|
||||||
|
2. `Install mod from KH2FM-Mods-Num/GoA-ROM-Edition`<br>
|
||||||
|
3. `Setup Lua Backend From the 3.0.0 KH2Randomizer.exe per the setup guide linked above`<br>
|
||||||
|
|
||||||
Follow this Guide [KH2Rando.com](https://tommadness.github.io/KH2Randomizer/setup/Panacea-ModLoader/)
|
- Needed for Archipelago
|
||||||
|
1. [`ArchipelagoKH2Client.exe`](https://github.com/ArchipelagoMW/Archipelago/releases)<br>
|
||||||
|
2. `Install mod from JaredWeakStrike/APCompanion`<br>
|
||||||
|
3. `Install mod from KH2FM-Mods-equations19/auto-save`<br>
|
||||||
|
4. `AP Randomizer Seed`
|
||||||
|
<h3 style="text-transform:none";>Required: Archipelago Companion Mod</h3>
|
||||||
|
|
||||||
<h3 style="text-transform:none";>Loading A Seed</h3>
|
Load this mod just like the <b>GoA ROM</b> you did during the KH2 Rando setup. `JaredWeakStrike/APCompanion`<br>
|
||||||
|
Have this mod second-highest priority below the .zip seed.<br>
|
||||||
|
This mod is based upon Num's Garden of Assemblege Mod and requires it to work. Without Num this could not be possible.
|
||||||
|
|
||||||
When you generate a game you will see a download link for a KH2 .zip seed on the room page. Download the seed then open OpenKH Mod Manager and click the green plus and `Select and install Mod Archive`. Make sure the seed is on the top of the list (Highest Priority)
|
<h3 style="text-transform:none";>Required: Auto Save Mod</h3>
|
||||||
|
Load this mod just like the GoA ROM you did during the KH2 Rando setup. `KH2FM-Mods-equations19/auto-save` Location doesn't matter, required in case of crashes.
|
||||||
|
|
||||||
<h3 style="text-transform:none";>Archipelago Compainion Mod and recommended mods</h3>
|
<h3 style="text-transform:none";>Installing A Seed</h3>
|
||||||
|
|
||||||
Load this mod just like the GoA ROM you did during the KH2 Rando setup. `JaredWeakStrike/APCompanion` Have this mod second highest priority below the .zip seed
|
When you generate a game you will see a download link for a KH2 .zip seed on the room page. Download the seed then open OpenKH Mod Manager and click the green plus and `Select and install Mod Archive`.<br>
|
||||||
Load this mod just like the GoA ROM you did during the KH2 Rando setup. `KH2FM-Mods-equations19/auto-save` Location doesn't matter, recommended in case of crashes.
|
Make sure the seed is on the top of the list (Highest Priority)<br>
|
||||||
Load this mod just like the GoA ROM you did during the KH2 Rando setup. `KH2FM-Mods-equations19/soft-reset` Location doesn't matter, recommneded in case of soft locks.
|
After Installing the seed click `Mod Loader -> Build/Build and Run`. Every slot is a unique mod to install and will be needed be repatched for different slots/rooms.
|
||||||
|
|
||||||
|
<h2 style="text-transform:none";>What the Mod Manager Should Look Like.</h2>
|
||||||
|

|
||||||
|
|
||||||
<h2 style="text-transform:none";>Using the KH2 Client</h2>
|
<h2 style="text-transform:none";>Using the KH2 Client</h2>
|
||||||
|
|
||||||
Once you have started the game through OpenKH Mod Manager and are on the title screen run the ArchipelagoKH2Client.exe. When you successfully connect to the server the client will automatically hook into the game to send/receive checks. If the client ever loses connection to the game, it will also disconnect from the server and you will need to reconnect. Make sure the game is open whenever you try to connect the client to the server otherwise it will immediately disconnect you. Most checks will be sent to you anywhere outside of a load or cutscene but if you obtain magic, you will need to pause your game to have it show up in your inventory, then enter a new room for it to become properly usable.
|
Once you have started the game through OpenKH Mod Manager and are on the title screen run the [ArchipelagoKH2Client.exe](https://github.com/ArchipelagoMW/Archipelago/releases). <br>
|
||||||
|
When you successfully connect to the server the client will automatically hook into the game to send/receive checks. <br>
|
||||||
|
If the client ever loses connection to the game, it will also disconnect from the server and you will need to reconnect.<br>
|
||||||
|
`Make sure the game is open whenever you try to connect the client to the server otherwise it will immediately disconnect you.`<br>
|
||||||
|
Most checks will be sent to you anywhere outside a load or cutscene.<br>
|
||||||
|
`If you obtain magic, you will need to pause your game to have it show up in your inventory, then enter a new room for it to become properly usable.`
|
||||||
|
<br>
|
||||||
|
<h2 style="text-transform:none";>KH2 Client should look like this: </h2>
|
||||||
|

|
||||||
|
<br>
|
||||||
|
Enter `The room's port number` into the top box <b> where the x's are</b> and press "Connect". Follow the prompts there and you should be connected
|
||||||
|
|
||||||
<h2 style="text-transform:none";>Generating a game</h2>
|
|
||||||
|
|
||||||
<h3 style="text-transform:none";>What is a YAML?</h3>
|
<h2 style="text-transform:none";>Common Pitfalls</h2>
|
||||||
|
- Having an old GOA Lua Script in your `C:\Users\*YourName*\Documents\KINGDOM HEARTS HD 1.5+2.5 ReMIX\scripts\kh2` folder.
|
||||||
|
- Pressing F2 while in game should look like this. 
|
||||||
|
<br>
|
||||||
|
- Not having Lua Backend Configured Correctly.
|
||||||
|
- To fix this look over the guide at [KH2Rando.com](https://tommadness.github.io/KH2Randomizer/setup/Panacea-ModLoader/). Specifically the Lua Backend Configuration Step.
|
||||||
|
<br>
|
||||||
|
- Loading into Simulated Twilight Town Instead of the GOA.
|
||||||
|
- To fix this look over the guide at [KH2Rando.com](https://tommadness.github.io/KH2Randomizer/setup/Panacea-ModLoader/). Specifically the Panacea and Lua Backend Steps.
|
||||||
|
|
||||||
YAML is the file format which Archipelago uses in order to configure a player's world. It allows you to dictate which
|
|
||||||
game you will be playing as well as the settings you would like for that game.
|
|
||||||
|
|
||||||
YAML is a format very similar to JSON however it is made to be more human-readable. If you are ever unsure of the
|
<h2 style="text-transform:none";>Best Practices</h2>
|
||||||
validity of your YAML file you may check the file by uploading it to the check page on the Archipelago website. Check
|
|
||||||
page: [YAML Validation Page](/mysterycheck)
|
|
||||||
|
|
||||||
<h3 style="text-transform:none";>Creating a YAML</h3>
|
- Make a save at the start of the GoA before opening anything. This will be the file to select when loading an autosave if/when your game crashes.
|
||||||
|
- If you don't want to have a save in the GoA. Disconnect the client, load the auto save, and then reconnect the client after it loads the auto save.
|
||||||
|
- Set fps limit to 60fps.
|
||||||
|
- Run the game in windows/borderless windowed mode. Fullscreen is stable but the game can crash if you alt-tab out.
|
||||||
|
|
||||||
YAML files may be generated on the Archipelago website by visiting the games page and clicking the "Settings Page" link
|
<h2 style="text-transform:none";>Requirement/logic sheet</h2>
|
||||||
under any game. Clicking "Export Settings" in a game's settings page will download the YAML to your system. Games
|
Have any questions on what's in logic? This spreadsheet has the answer [Requirements/logic sheet](https://docs.google.com/spreadsheets/d/1Embae0t7pIrbzvX-NRywk7bTHHEvuFzzQBUUpSUL7Ak/edit?usp=sharing)
|
||||||
page: [Archipelago Games List](/games)
|
<h2 style="text-transform:none";>F.A.Q.</h2>
|
||||||
|
|
||||||
In a multiworld there must be one YAML per world. Any number of players can play on each world using either the game's
|
- Why am I getting wallpapered while going into a world for the first time?
|
||||||
native coop system or using Archipelago's coop support. Each world will hold one slot in the multiworld and will have a
|
- Your `Lua Backend` was not configured correctly. Look over the step in the [KH2Rando.com](https://tommadness.github.io/KH2Randomizer/setup/Panacea-ModLoader/) guide.
|
||||||
slot name and, if the relevant game requires it, files to associate it with that multiworld.
|
- Why am I not getting magic?
|
||||||
|
- If you obtain magic, you will need to pause your game to have it show up in your inventory, then enter a new room for it to become properly usable.
|
||||||
|
- Why am I missing worlds/portals in the GoA?
|
||||||
|
- You are missing the required visit locking item to access the world/portal.
|
||||||
|
- What versions of Kingdom Hearts 2 are supported?
|
||||||
|
- Currently `only` the most up to date version on the Epic Game Store is supported `1.0.0.8_WW`. Emulator may be added in the future.
|
||||||
|
- Why did I crash?
|
||||||
|
- The port of Kingdom Hearts 2 can and will randomly crash, this is the fault of the game not the randomizer or the archipelago client.
|
||||||
|
- If you have a continuous/constant crash (in the same area/event every time) you will want to reverify your installed files. This can be done by doing the following: Open Epic Game Store --> Library --> Click Triple Dots --> Manage --> Verify
|
||||||
|
- Why am I getting dummy items or letters?
|
||||||
|
- You will need to get the `JaredWeakStrike/APCompanion` (you can find how to get this if you scroll up)
|
||||||
|
- Why is my HP/MP continuously increasing without stopping?
|
||||||
|
- You do not have `JaredWeakStrike/APCompanion` setup correctly. Make Sure it is above the GOA in the mod manager.
|
||||||
|
- Why am I not sending or receiving items?
|
||||||
|
- Make sure you are connected to the KH2 client and the correct room (for more information scroll up)
|
||||||
|
- Why did I not load in to the correct visit
|
||||||
|
- You need to trigger a cutscene or visit The World That Never Was for it to update you have recevied the item.
|
||||||
|
- Why should I install the auto save mod at `KH2FM-Mods-equations19/auto-save`?
|
||||||
|
- Because Kingdom Hearts 2 is prone to crashes and will keep you from losing your progress.
|
||||||
|
- How do I load an auto save?
|
||||||
|
- To load an auto-save, hold down the Select or your equivalent on your prefered controller while choosing a file. Make sure to hold the button down the whole time.
|
||||||
|
|
||||||
If multiple people plan to play in one world cooperatively then they will only need one YAML for their coop world. If
|
|
||||||
each player is planning on playing their own game then they will each need a YAML.
|
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,4 @@
|
||||||
assets:
|
assets:
|
||||||
- method: binarc
|
|
||||||
multi:
|
|
||||||
- name: msg/us/jm.bar
|
|
||||||
- name: msg/uk/jm.bar
|
|
||||||
name: msg/jp/jm.bar
|
|
||||||
source:
|
|
||||||
- method: kh2msg
|
|
||||||
name: jm
|
|
||||||
source:
|
|
||||||
- language: en
|
|
||||||
name: jm.yml
|
|
||||||
type: list
|
|
||||||
- method: binarc
|
- method: binarc
|
||||||
name: 00battle.bin
|
name: 00battle.bin
|
||||||
source:
|
source:
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from . import KH2TestBase
|
from . import KH2TestBase
|
||||||
from ..Names import ItemName,LocationName,RegionName
|
from ..Names import ItemName
|
||||||
|
|
||||||
|
|
||||||
class TestDefault(KH2TestBase):
|
class TestDefault(KH2TestBase):
|
||||||
options = {}
|
options = {}
|
||||||
|
@ -18,10 +19,12 @@ class TestLuckyEmblem(KH2TestBase):
|
||||||
self.collect_all_but([ItemName.LuckyEmblem])
|
self.collect_all_but([ItemName.LuckyEmblem])
|
||||||
self.assertBeatable(True)
|
self.assertBeatable(True)
|
||||||
|
|
||||||
|
|
||||||
class TestHitList(KH2TestBase):
|
class TestHitList(KH2TestBase):
|
||||||
options = {
|
options = {
|
||||||
"Goal": 2,
|
"Goal": 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
def testEverything(self):
|
def testEverything(self):
|
||||||
self.collect_all_but([ItemName.Bounty])
|
self.collect_all_but([ItemName.Bounty])
|
||||||
self.assertBeatable(True)
|
self.assertBeatable(True)
|
||||||
|
|
Loading…
Reference in New Issue