Skip to content

Commit

Permalink
Merge branch 'kdl3' into silvris/kdl3
Browse files Browse the repository at this point in the history
  • Loading branch information
Silvris authored Aug 26, 2023
2 parents 5ad4389 + aa9640c commit 03d26b8
Show file tree
Hide file tree
Showing 8 changed files with 71 additions and 66 deletions.
19 changes: 12 additions & 7 deletions worlds/kdl3/Regions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@

from BaseClasses import Region
from worlds.AutoWorld import World
from worlds.generic.Rules import add_item_rule
from .Locations import KDL3Location
from .Names import LocationName
from .Options import BossShuffle
from .Room import Room
from ..generic.Rules import add_item_rule

if typing.TYPE_CHECKING:
from . import KDL3World

default_levels = {
1: [0x770001, 0x770002, 0x770003, 0x770004, 0x770005, 0x770006, 0x770200],
Expand All @@ -34,7 +37,7 @@ def generate_valid_level(level, stage, possible_stages, slot_random):
return new_stage


def generate_rooms(world: World, door_shuffle: bool, level_regions: typing.Dict[int, Region]):
def generate_rooms(world: "KDL3World", door_shuffle: bool, level_regions: typing.Dict[int, Region]):
level_names = {LocationName.level_names[level]: level for level in LocationName.level_names}
room_data = json.loads(get_data(__name__, os.path.join("data", "Rooms.json")))
rooms: typing.Dict[str, Room] = dict()
Expand All @@ -44,7 +47,8 @@ def generate_rooms(world: World, door_shuffle: bool, level_regions: typing.Dict[
room_entry["animal_pointers"], room_entry["enemies"], room_entry["entity_load"],
room_entry["consumables"], room_entry["consumables_pointer"])
room.add_locations({location: world.location_name_to_id[location] if location in world.location_name_to_id else
None for location in room_entry["locations"] if not any([x in location for x in ["1-Up", "Maxim"]]) or
None for location in room_entry["locations"]
if not any([x in location for x in ["1-Up", "Maxim"]]) or
world.multiworld.consumables[world.player]}, KDL3Location)
rooms[room.name] = room
for location in room.locations:
Expand Down Expand Up @@ -86,16 +90,17 @@ def generate_rooms(world: World, door_shuffle: bool, level_regions: typing.Dict[
proper_stage = world.player_levels[level][stage]
level_regions[level].add_exits([first_rooms[proper_stage].name],
{first_rooms[proper_stage].name:
(lambda state: True) if world.multiworld.open_world[world.player] or
stage == 0 else lambda state, level=level, stage=stage: state.has(
(lambda state: True) if world.multiworld.open_world[world.player] or
stage == 0 else lambda state, level=level,
stage=stage: state.has(
f"{LocationName.level_names_inverse[level]} "
f"{f'{stage}'}"
f" - Stage Completion", world.player)})
else:
level_regions[level].add_exits([first_rooms[0x770200 + level - 1].name])


def generate_valid_levels(world: World, enforce_world: bool, enforce_pattern: bool) -> dict:
def generate_valid_levels(world: "KDL3World", enforce_world: bool, enforce_pattern: bool) -> dict:
levels: typing.Dict[int, typing.List[typing.Optional[int]]] = {
1: [None for _ in range(7)],
2: [None for _ in range(7)],
Expand Down Expand Up @@ -188,7 +193,7 @@ def generate_valid_levels(world: World, enforce_world: bool, enforce_pattern: bo
return levels


def create_levels(world: World) -> None:
def create_levels(world: "KDL3World") -> None:
menu = Region("Menu", world.player, world.multiworld)
level1 = Region("Grass Land", world.player, world.multiworld)
level2 = Region("Ripple Field", world.player, world.multiworld)
Expand Down
2 changes: 1 addition & 1 deletion worlds/kdl3/Rom.py
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ def patch(self, target: str):


def patch_rom(multiworld: MultiWorld, player: int, rom: RomData, heart_stars_required: int,
boss_requirements: Dict[int, int], shuffled_levels: Dict[int, List[int]], bb_boss_enabled: Dict[int, int],
boss_requirements: Dict[int, int], shuffled_levels: Dict[int, List[int]], bb_boss_enabled: List[bool],
copy_abilities: Dict[str, str], slot_random: Random):
# increase BWRAM by 0x8000
rom.write_byte(0x7FD8, 0x06)
Expand Down
2 changes: 1 addition & 1 deletion worlds/kdl3/Rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def can_reach_cutter(state: "CollectionState", player: int) -> bool:

def can_assemble_rob(state: "CollectionState", player: int, copy_abilities: typing.Dict[str, str]):
# check animal requirements
if not can_reach_coo(state, player) and can_reach_kine(state, player):
if not (can_reach_coo(state, player) and can_reach_kine(state, player)):
return False
for abilities, bukisets in EnemyAbilities.enemy_restrictive[1:5]:
iterator = iter(x for x in bukisets if copy_abilities[x] in abilities)
Expand Down
52 changes: 26 additions & 26 deletions worlds/kdl3/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,32 @@ def get_trap_item_name(self) -> str:
self.multiworld.ability_trap_weight[self.player]])[0]

def pre_fill(self) -> None:
if self.multiworld.copy_ability_randomization[self.player]:
# randomize copy abilities
valid_abilities = list(copy_ability_access_table.keys())
enemies_to_set = list(self.copy_abilities.keys())
# now for the edge cases
for abilities, enemies in enemy_restrictive:
available_enemies = list()
for enemy in enemies:
if enemy not in enemies_to_set:
if self.copy_abilities[enemy] in abilities:
break
else:
available_enemies.append(enemy)
else:
chosen_enemy = self.random.choice(available_enemies)
chosen_ability = self.random.choice(tuple(abilities))
self.copy_abilities[chosen_enemy] = chosen_ability
enemies_to_set.remove(chosen_enemy)
# place remaining
for enemy in enemies_to_set:
self.copy_abilities[enemy] = self.random \
.choice(valid_abilities)

for enemy in enemy_mapping:
self.multiworld.get_location(enemy, self.player) \
.place_locked_item(self.create_item(self.copy_abilities[enemy_mapping[enemy]]))
# fill animals
if self.multiworld.animal_randomization[self.player] != 0:
spawns = [animal for animal in animal_friend_spawns.keys() if
Expand Down Expand Up @@ -146,32 +172,6 @@ def pre_fill(self) -> None:
self.multiworld.get_location(animal, self.player) \
.place_locked_item(self.create_item(animal_friends[animal]))

if self.multiworld.copy_ability_randomization[self.player]:
# randomize copy abilities
valid_abilities = list(copy_ability_access_table.keys())
enemies_to_set = list(self.copy_abilities.keys())
# now for the edge cases
for abilities, enemies in enemy_restrictive:
available_enemies = list()
for enemy in enemies:
if enemy not in enemies_to_set:
if self.copy_abilities[enemy] in abilities:
break
else:
available_enemies.append(enemy)
else:
chosen_enemy = self.random.choice(available_enemies)
chosen_ability = self.random.choice(tuple(abilities))
self.copy_abilities[chosen_enemy] = chosen_ability
enemies_to_set.remove(chosen_enemy)
# place remaining
for enemy in enemies_to_set:
self.copy_abilities[enemy] = self.random \
.choice(valid_abilities)

for enemy in enemy_mapping:
self.multiworld.get_location(enemy, self.player) \
.place_locked_item(self.create_item(self.copy_abilities[enemy_mapping[enemy]]))

def create_items(self) -> None:
itempool = []
Expand Down
10 changes: 5 additions & 5 deletions worlds/kdl3/test/TestGoal.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ def testGoal(self):
self.assertBeatable(False)
heart_stars = self.get_items_by_name("Heart Star")
self.collect(heart_stars[0:14])
self.assertEqual(self.count("Heart Star"), 14)
self.assertEqual(self.count("Heart Star"), 14, str(self.multiworld.seed))
self.assertBeatable(False)
self.collect(heart_stars[14:15])
self.assertEqual(self.count("Heart Star"), 15)
self.assertEqual(self.count("Heart Star"), 15, str(self.multiworld.seed))
self.assertBeatable(True)
self.remove([self.get_item_by_name("Love-Love Rod")])
self.collect_by_name("Kine") # Ensure a little more progress, but leave out cutter and burning
Expand All @@ -39,16 +39,16 @@ def testGoal(self):
self.assertBeatable(False)
heart_stars = self.get_items_by_name("Heart Star")
self.collect(heart_stars[0:14])
self.assertEqual(self.count("Heart Star"), 14)
self.assertEqual(self.count("Heart Star"), 14, str(self.multiworld.seed))
self.assertBeatable(False)
self.collect(heart_stars[14:15])
self.assertEqual(self.count("Heart Star"), 15)
self.assertEqual(self.count("Heart Star"), 15, str(self.multiworld.seed))
self.assertBeatable(False)
self.collect_by_name(["Burning", "Cutter", "Kine"])
self.assertBeatable(True)
self.remove([self.get_item_by_name("Love-Love Rod")])
self.collect(heart_stars)
self.assertEqual(self.count("Heart Star"), 30)
self.assertEqual(self.count("Heart Star"), 30, str(self.multiworld.seed))
self.assertBeatable(True)

def testKine(self):
Expand Down
11 changes: 5 additions & 6 deletions worlds/kdl3/test/TestLocations.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ def testSimpleHeartStars(self):
def run_location_test(self, location: str, itempool: typing.List[str]):
items = itempool.copy()
while len(itempool) > 0:
assert not self.can_reach_location(location)
self.assertFalse(self.can_reach_location(location), str(self.multiworld.seed))
self.collect_by_name(itempool.pop())
assert self.can_reach_location(location)
self.assertTrue(self.can_reach_location(location), str(self.multiworld.seed))
self.remove(self.get_items_by_name(items))


Expand All @@ -59,11 +59,10 @@ class TestShiro(KDL3TestBase):
}

def testShiro(self):
assert not self.can_reach_location("Iceberg 5 - Shiro")
self.assertFalse(self.can_reach_location("Iceberg 5 - Shiro"), str(self.multiworld.seed))
self.collect_by_name("Nago")
assert not self.can_reach_location("Iceberg 5 - Shiro")
self.assertFalse(self.can_reach_location("Iceberg 5 - Shiro"), str(self.multiworld.seed))
# despite Shiro only requiring Nago for logic, it cannot be in logic because our two accessible stages
# do not actually give the player access to Nago, thus we need Kine to pass 2-5
self.collect_by_name("Kine")
assert self.can_reach_location("Iceberg 5 - Shiro")

self.assertTrue(self.can_reach_location("Iceberg 5 - Shiro"), str(self.multiworld.seed))
36 changes: 18 additions & 18 deletions worlds/kdl3/test/TestShuffles.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@ def testGoal(self):
self.assertBeatable(False)
heart_stars = self.get_items_by_name("Heart Star")
self.collect(heart_stars[0:14])
self.assertEqual(self.count("Heart Star"), 14)
self.assertEqual(self.count("Heart Star"), 14, str(self.multiworld.seed))
self.assertBeatable(False)
self.collect(heart_stars[14:15])
self.assertEqual(self.count("Heart Star"), 15)
self.assertEqual(self.count("Heart Star"), 15, str(self.multiworld.seed))
self.assertBeatable(False)
self.collect_by_name(["Burning", "Cutter", "Kine"])
self.assertBeatable(True)
self.remove([self.get_item_by_name("Love-Love Rod")])
self.collect(heart_stars)
self.assertEqual(self.count("Heart Star"), 30)
self.assertEqual(self.count("Heart Star"), 30, str(self.multiworld.seed))
self.assertBeatable(True)

def testKine(self):
Expand Down Expand Up @@ -61,7 +61,7 @@ def testValidAbilitiesForROB(self):
required_abilities.append(tuple(potential_abilities))
collected_abilities = list()
for group in required_abilities:
self.assertFalse(len(group) == 0)
self.assertFalse(len(group) == 0, str(self.multiworld.seed))
collected_abilities.append(group[0])
self.collect_by_name([ability.replace(" Ability", "") for ability in collected_abilities])
if "Parasol Ability" not in collected_abilities or "Stone Ability" not in collected_abilities:
Expand All @@ -70,10 +70,10 @@ def testValidAbilitiesForROB(self):

if "Cutter Ability" not in collected_abilities:
# we can't actually reach 3-6 without Cutter
assert not self.can_reach_location("Sand Canyon 6 - Professor Hector & R.O.B")
self.assertFalse(self.can_reach_location("Sand Canyon 6 - Professor Hector & R.O.B"), str(self.multiworld.seed))
self.collect_by_name(["Cutter"])

assert self.can_reach_location("Sand Canyon 6 - Professor Hector & R.O.B")
self.assertTrue(self.can_reach_location("Sand Canyon 6 - Professor Hector & R.O.B"), str(self.multiworld.seed))


class TestAnimalShuffle(KDL3TestBase):
Expand All @@ -90,16 +90,16 @@ def testGoal(self):
self.assertBeatable(False)
heart_stars = self.get_items_by_name("Heart Star")
self.collect(heart_stars[0:14])
self.assertEqual(self.count("Heart Star"), 14)
self.assertEqual(self.count("Heart Star"), 14, str(self.multiworld.seed))
self.assertBeatable(False)
self.collect(heart_stars[14:15])
self.assertEqual(self.count("Heart Star"), 15)
self.assertEqual(self.count("Heart Star"), 15, str(self.multiworld.seed))
self.assertBeatable(False)
self.collect_by_name(["Burning", "Cutter", "Kine"])
self.assertBeatable(True)
self.remove([self.get_item_by_name("Love-Love Rod")])
self.collect(heart_stars)
self.assertEqual(self.count("Heart Star"), 30)
self.assertEqual(self.count("Heart Star"), 30, str(self.multiworld.seed))
self.assertBeatable(True)

def testKine(self):
Expand All @@ -115,9 +115,9 @@ def testBurning(self):
self.assertBeatable(False)

def testLockedAnimals(self):
self.assertTrue(self, self.multiworld.get_location("Ripple Field 5 - Animal 2", 1).item.name == "Pitch Spawn")
self.assertTrue(self, self.multiworld.get_location("Iceberg 4 - Animal 1", 1).item.name == "ChuChu Spawn")
self.assertTrue(self, self.multiworld.get_location("Sand Canyon 6 - Animal 1", 1).item.name in {"Kine Spawn", "Coo Spawn"})
self.assertTrue(self.multiworld.get_location("Ripple Field 5 - Animal 2", 1).item.name == "Pitch Spawn")
self.assertTrue(self.multiworld.get_location("Iceberg 4 - Animal 1", 1).item.name == "ChuChu Spawn")
self.assertTrue(self.multiworld.get_location("Sand Canyon 6 - Animal 1", 1).item.name in {"Kine Spawn", "Coo Spawn"})


class TestAllShuffle(KDL3TestBase):
Expand All @@ -135,16 +135,16 @@ def testGoal(self):
self.assertBeatable(False)
heart_stars = self.get_items_by_name("Heart Star")
self.collect(heart_stars[0:14])
self.assertEqual(self.count("Heart Star"), 14)
self.assertEqual(self.count("Heart Star"), 14, str(self.multiworld.seed))
self.assertBeatable(False)
self.collect(heart_stars[14:15])
self.assertEqual(self.count("Heart Star"), 15)
self.assertEqual(self.count("Heart Star"), 15, str(self.multiworld.seed))
self.assertBeatable(False)
self.collect_by_name(["Burning", "Cutter", "Kine"])
self.assertBeatable(True)
self.remove([self.get_item_by_name("Love-Love Rod")])
self.collect(heart_stars)
self.assertEqual(self.count("Heart Star"), 30)
self.assertEqual(self.count("Heart Star"), 30, str(self.multiworld.seed))
self.assertBeatable(True)

def testKine(self):
Expand All @@ -160,6 +160,6 @@ def testBurning(self):
self.assertBeatable(False)

def testLockedAnimals(self):
self.assertTrue(self, self.multiworld.get_location("Ripple Field 5 - Animal 2", 1).item.name == "Pitch Spawn")
self.assertTrue(self, self.multiworld.get_location("Iceberg 4 - Animal 1", 1).item.name == "ChuChu Spawn")
self.assertTrue(self, self.multiworld.get_location("Sand Canyon 6 - Animal 1", 1).item.name in {"Kine Spawn", "Coo Spawn"})
self.assertTrue(self.multiworld.get_location("Ripple Field 5 - Animal 2", 1).item.name == "Pitch Spawn")
self.assertTrue(self.multiworld.get_location("Iceberg 4 - Animal 1", 1).item.name == "ChuChu Spawn")
self.assertTrue(self.multiworld.get_location("Sand Canyon 6 - Animal 1", 1).item.name in {"Kine Spawn", "Coo Spawn"})
5 changes: 3 additions & 2 deletions worlds/kdl3/test/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
from BaseClasses import MultiWorld, PlandoOptions
from test.TestBase import WorldTestBase
from test.general import gen_steps
from ... import AutoWorld
from ...AutoWorld import call_all
from worlds import AutoWorld
from worlds.AutoWorld import call_all


class KDL3TestBase(WorldTestBase):
game = "Kirby's Dream Land 3"
Expand Down

0 comments on commit 03d26b8

Please sign in to comment.