Skip to content

Commit

Permalink
KH2: New Unit Test and better keyblade fill (ArchipelagoMW#1744)
Browse files Browse the repository at this point in the history
__init__:
 - Added exception for if the player has too many excluded abilities on keyblades.
 - Fixed Action Abilities only on keyblades from breaking.
 - Added proper support for ability quantity's instead of 1 of the ability 
 - Moved filling the localitems slot data to init instead of generate_output so I could easily unit test it

TestSlotData:
- Checks if the "localItems" part of slot data is filled. This is used for keeping track of local items and making sure nothing dupes
  • Loading branch information
JaredWeakStrike authored Apr 23, 2023
1 parent 62a265c commit 06a25a9
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 14 deletions.
8 changes: 2 additions & 6 deletions worlds/kh2/OpenKH.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
import zipfile

from .Items import item_dictionary_table, CheckDupingItems
from .Locations import all_locations, SoraLevels, exclusion_table, AllWeaponSlot
from .Names import LocationName
from .Locations import all_locations, SoraLevels, exclusion_table
from .XPValues import lvlStats, formExp, soraExp
from worlds.Files import APContainer

Expand Down Expand Up @@ -83,7 +82,7 @@ def increaseStat(i):
elif self.multiworld.LevelDepth[self.player] == "level_99":
levelsetting.extend(exclusion_table["Level99"])

elif self.multiworld.LevelDepth[self.player] in ["level_50_sanity", "level_99_sanity"]:
elif self.multiworld.LevelDepth[self.player] != "level_1":
levelsetting.extend(exclusion_table["Level50Sanity"])

if self.multiworld.LevelDepth[self.player] == "level_99_sanity":
Expand All @@ -96,9 +95,6 @@ def increaseStat(i):
data = all_locations[location.name]
if location.item.player == self.player:
itemcode = item_dictionary_table[location.item.name].kh2id
if location.item.name in slotDataDuping and \
location.name not in AllWeaponSlot:
self.LocalItems[location.address] = item_dictionary_table[location.item.name].code
else:
itemcode = 90 # castle map

Expand Down
35 changes: 27 additions & 8 deletions worlds/kh2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import logging

from .Items import *
from .Locations import all_locations, setup_locations, exclusion_table
from .Locations import all_locations, setup_locations, exclusion_table, AllWeaponSlot
from .Names import ItemName, LocationName
from .OpenKH import patch_kh2
from .Options import KH2_Options
Expand Down Expand Up @@ -62,8 +62,22 @@ def __init__(self, multiworld: "MultiWorld", player: int):
self.growth_list = list()
for x in range(4):
self.growth_list.extend(Movement_Table.keys())
self.slotDataDuping = set()
self.localItems = dict()

def fill_slot_data(self) -> dict:
for values in CheckDupingItems.values():
if isinstance(values, set):
self.slotDataDuping = self.slotDataDuping.union(values)
else:
for inner_values in values.values():
self.slotDataDuping = self.slotDataDuping.union(inner_values)
self.LocalItems = {location.address: item_dictionary_table[location.item.name].code
for location in self.multiworld.get_filled_locations(self.player)
if location.item.player == self.player
and location.item.name in self.slotDataDuping
and location.name not in AllWeaponSlot}

return {"hitlist": self.hitlist,
"LocalItems": self.LocalItems,
"Goal": self.multiworld.Goal[self.player].value,
Expand Down Expand Up @@ -132,7 +146,7 @@ def create_items(self) -> None:

# Creating filler for unfilled locations
itempool += [self.create_filler()
for _ in range(self.totalLocations-len(itempool))]
for _ in range(self.totalLocations - len(itempool))]
self.multiworld.itempool += itempool

def generate_early(self) -> None:
Expand Down Expand Up @@ -245,29 +259,33 @@ def keyblade_fill(self):
ItemName.FinishingPlus: 1}}

elif self.multiworld.KeybladeAbilities[self.player] == "action":
self.sora_keyblade_ability_pool = {item: data for item, data in self.item_quantity_dict.items() if item in ActionAbility_Table}
self.sora_keyblade_ability_pool = {item: data for item, data in self.item_quantity_dict.items() if
item in ActionAbility_Table}
# there are too little action abilities so 2 random support abilities are placed
for _ in range(3):
randomSupportAbility = self.multiworld.per_slot_randoms[self.player].choice(list(SupportAbility_Table.keys()))
randomSupportAbility = self.multiworld.per_slot_randoms[self.player].choice(
list(SupportAbility_Table.keys()))
while randomSupportAbility in self.sora_keyblade_ability_pool:
randomSupportAbility = self.multiworld.per_slot_randoms[self.player].choice(
list(SupportAbility_Table.keys()))
list(SupportAbility_Table.keys()))
self.sora_keyblade_ability_pool[randomSupportAbility] = 1
else:
# both action and support on keyblades.
# TODO: make option to just exclude scom
self.sora_keyblade_ability_pool = {
**{item: data for item, data in self.item_quantity_dict.items() if item in SupportAbility_Table},
**{item: data for item, data in self.item_quantity_dict.items() if item in ActionAbility_Table},
**{ItemName.NegativeCombo: 1, ItemName.AirComboPlus: 1, ItemName.ComboPlus: 1, ItemName.FinishingPlus: 1}}
**{ItemName.NegativeCombo: 1, ItemName.AirComboPlus: 1, ItemName.ComboPlus: 1,
ItemName.FinishingPlus: 1}}

for ability in self.multiworld.BlacklistKeyblade[self.player].value:
if ability in self.sora_keyblade_ability_pool:
self.sora_keyblade_ability_pool.pop(ability)

# magic number for amount of keyblades
if sum(self.sora_keyblade_ability_pool.values()) < 28:
raise Exception(f"{self.multiworld.get_file_safe_player_name(self.player)} has too little Keyblade Abilities in the Keyblade Pool")
raise Exception(
f"{self.multiworld.get_file_safe_player_name(self.player)} has too little Keyblade Abilities in the Keyblade Pool")

self.valid_abilities = list(self.sora_keyblade_ability_pool.keys())
# Kingdom Key cannot have No Experience so plandoed here instead of checking 26 times if its kingdom key
Expand Down Expand Up @@ -379,4 +397,5 @@ def level_subtraction(self):
self.totalLocations -= 76

def get_filler_item_name(self) -> str:
return self.multiworld.random.choice([ItemName.PowerBoost, ItemName.MagicBoost, ItemName.DefenseBoost, ItemName.APBoost])
return self.multiworld.random.choice(
[ItemName.PowerBoost, ItemName.MagicBoost, ItemName.DefenseBoost, ItemName.APBoost])
21 changes: 21 additions & 0 deletions worlds/kh2/test/TestSlotData.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import unittest

from test.general import setup_solo_multiworld
from . import KH2TestBase
from .. import KH2World, all_locations, item_dictionary_table, CheckDupingItems, AllWeaponSlot, KH2Item
from ..Names import ItemName
from ... import AutoWorldRegister
from ...AutoWorld import call_all


class TestLocalItems(KH2TestBase):

def testSlotData(self):
gen_steps = ("generate_early", "create_regions", "create_items", "set_rules", "generate_basic", "pre_fill")
multiworld = setup_solo_multiworld(KH2World, gen_steps)
for location in multiworld.get_locations():
if location.item is None:
location.place_locked_item(multiworld.worlds[1].create_item(ItemName.NoExperience))
call_all(multiworld, "fill_slot_data")
slotdata = multiworld.worlds[1].fill_slot_data()
assert len(slotdata["LocalItems"]) > 0, f"{slotdata['LocalItems']} is empty"

0 comments on commit 06a25a9

Please sign in to comment.