Files
dockipelago/worlds/k64/rules.py
Jonathan Tinney 7971961166
Some checks failed
Analyze modified files / flake8 (push) Failing after 2m28s
Build / build-win (push) Has been cancelled
Build / build-ubuntu2204 (push) Has been cancelled
ctest / Test C++ ubuntu-latest (push) Has been cancelled
ctest / Test C++ windows-latest (push) Has been cancelled
Analyze modified files / mypy (push) Has been cancelled
Build and Publish Docker Images / Push Docker image to Docker Hub (push) Successful in 5m4s
Native Code Static Analysis / scan-build (push) Failing after 5m2s
type check / pyright (push) Successful in 1m7s
unittests / Test Python 3.11.2 ubuntu-latest (push) Failing after 16m23s
unittests / Test Python 3.12 ubuntu-latest (push) Failing after 28m19s
unittests / Test Python 3.13 ubuntu-latest (push) Failing after 14m49s
unittests / Test hosting with 3.13 on ubuntu-latest (push) Successful in 5m0s
unittests / Test Python 3.13 macos-latest (push) Has been cancelled
unittests / Test Python 3.11 windows-latest (push) Has been cancelled
unittests / Test Python 3.13 windows-latest (push) Has been cancelled
add schedule I, sonic 1/frontiers/heroes, spirit island
2026-04-02 23:46:36 -07:00

554 lines
26 KiB
Python

from worlds.generic.Rules import set_rule, add_rule
from worlds.AutoWorld import LogicMixin
from BaseClasses import MultiWorld
from copy import deepcopy
from .consumable_info import consumable_by_level
from .locations import star_locations
from .names import LocationName, ItemName
import typing
if typing.TYPE_CHECKING:
from . import K64World
from BaseClasses import CollectionState
burn_levels = [
"Pop Star 1",
"Pop Star 2",
"Pop Star 3",
"Rock Star 1",
"Rock Star 2",
"Rock Star 3",
"Aqua Star 1",
"Aqua Star 2",
"Neo Star 1",
"Neo Star 3",
"Neo Star 4",
"Shiver Star 1",
"Shiver Star 4",
"Ripple Star 1",
"Ripple Star 3",
]
needle_levels = [
"Pop Star 1",
"Pop Star 2",
"Pop Star 3",
"Rock Star 1",
"Rock Star 2",
"Aqua Star 1",
"Neo Star 3",
"Shiver Star 1",
"Shiver Star 2",
"Shiver Star 3",
"Ripple Star 1",
"Ripple Star 3",
]
bomb_levels = [
"Pop Star 1",
"Pop Star 2",
"Pop Star 3",
"Rock Star 4",
"Aqua Star 1",
"Aqua Star 2",
"Aqua Star 3",
"Aqua Star 4",
"Shiver Star 1",
"Shiver Star 2",
"Shiver Star 3",
"Shiver Star 4",
"Ripple Star 1",
"Ripple Star 3",
]
spark_levels = [
"Pop Star 2",
"Rock Star 2",
"Rock Star 4",
"Aqua Star 1",
"Aqua Star 2",
"Aqua Star 4",
"Shiver Star 2",
"Shiver Star 3",
"Ripple Star 1",
"Ripple Star 3",
]
cutter_levels = [
"Pop Star 1",
"Pop Star 2",
"Pop Star 3",
"Rock Star 2",
"Rock Star 3",
"Aqua Star 1",
"Aqua Star 3",
"Aqua Star 4",
"Neo Star 1",
"Neo Star 3",
"Shiver Star 2",
"Shiver Star 3",
"Shiver Star 4",
"Ripple Star 2",
"Ripple Star 3",
]
stone_levels = [
"Pop Star 2",
"Rock Star 1",
"Rock Star 2",
"Aqua Star 1",
"Aqua Star 2",
"Aqua Star 3",
"Neo Star 1",
"Neo Star 3",
"Neo Star 4",
"Shiver Star 1",
"Shiver Star 2",
"Shiver Star 3",
"Shiver Star 4",
"Ripple Star 1",
"Ripple Star 3",
]
ice_levels = [
"Pop Star 2",
"Rock Star 2",
"Rock Star 3",
"Aqua Star 1",
"Aqua Star 2",
"Neo Star 3",
"Shiver Star 1",
"Shiver Star 2",
"Shiver Star 3",
"Ripple Star 1",
"Ripple Star 3",
]
waddle_copy_levels = {
"Spark Ability": [
"Rock Star 1",
"Neo Star 2"
],
"Cutter Ability": [
"Aqua Star 2",
"Neo Star 2",
"Shiver Star 1"
]
}
dedede_copy_levels = {
"Burning Ability": [
"Aqua Star 3"
],
"Needle Ability": [
"Neo Star 4",
"Ripple Star 2",
],
"Bomb Ability": [
"Neo Star 4",
],
"Spark Ability": [
"Neo Star 4",
"Shiver Star 4",
],
"Cutter Ability": [
"Neo Star 4",
]
}
class K64LogicMixin(LogicMixin):
game: str = "Kirby 64 - The Crystal Shards"
k64_stale: dict[int, bool]
k64_level_state: dict[int, list[bool]]
def init_mixin(self, multiworld: MultiWorld):
k64_players = multiworld.get_game_players(self.game)
self.k64_stale = {player: True for player in k64_players}
self.k64_level_state = {player: [False, False, False, False, False, False] for player in k64_players}
def copy_mixin(self, other: "K64LogicMixin"):
other.k64_stale = self.k64_stale.copy()
other.k64_level_state = deepcopy(self.k64_level_state)
return other
def has_any_bomb(state: "CollectionState", player: int):
for specific, access in zip([ItemName.bomb, ItemName.bomb_bomb, ItemName.bomb_spark, ItemName.bomb_cutter,
ItemName.burn_bomb, ItemName.ice_bomb, ItemName.stone_bomb, ItemName.needle_bomb],
[["Bomb Ability"], ["Bomb Ability"], ["Bomb Ability", "Spark Ability"],
["Bomb Ability", "Cutter Ability"], ["Bomb Ability", "Burning Ability"],
["Bomb Ability", "Ice Ability"], ["Bomb Ability", "Stone Ability"],
["Bomb Ability", "Needle Ability"]]):
if state.has(specific, player) and state.has_all(access, player):
return True
return False
def has_any_stone(state: "CollectionState", player: int):
for specific, access in zip([ItemName.stone, ItemName.stone_stone, ItemName.stone_spark, ItemName.stone_cutter,
ItemName.burn_stone, ItemName.stone_ice, ItemName.stone_bomb, ItemName.stone_needle],
[["Stone Ability"], ["Stone Ability"], ["Stone Ability", "Spark Ability"],
["Stone Ability", "Cutter Ability"], ["Stone Ability", "Burning Ability"],
["Stone Ability", "Ice Ability"], ["Stone Ability", "Bomb Ability"],
["Stone Ability", "Needle Ability"]]):
if state.has(specific, player) and state.has_all(access, player):
return True
return False
def has_any_needle(state: "CollectionState", player: int):
for specific, access in zip([ItemName.needle, ItemName.needle_needle, ItemName.needle_spark, ItemName.needle_cutter,
ItemName.burn_needle, ItemName.ice_needle, ItemName.needle_bomb,
ItemName.stone_needle],
[["Needle Ability"], ["Needle Ability"], ["Needle Ability", "Spark Ability"],
["Needle Ability", "Cutter Ability"], ["Needle Ability", "Burning Ability"],
["Needle Ability", "Ice Ability"], ["Bomb Ability", "Needle Ability"],
["Stone Ability", "Needle Ability"]]):
if state.has(specific, player) and state.has_all(access, player):
return True
return False
def has_any_ice(state: "CollectionState", player: int):
# Used once, Refrigerator does not qualify
for specific, access in zip([ItemName.ice, ItemName.ice_ice, ItemName.ice_cutter,
ItemName.burn_ice, ItemName.ice_needle, ItemName.ice_bomb, ItemName.stone_ice],
[["Ice Ability"], ["Ice Ability"],
["Ice Ability", "Cutter Ability"], ["Ice Ability", "Burning Ability"],
["Needle Ability", "Ice Ability"], ["Bomb Ability", "Ice Ability"],
["Stone Ability", "Ice Ability"]]):
if state.has(specific, player) and state.has_all(access, player):
return True
return False
def has_any_burn(state: "CollectionState", player: int):
for specific, access in zip([ItemName.burn, ItemName.burn_burn, ItemName.burn_spark, ItemName.burn_cutter,
ItemName.burn_ice, ItemName.burn_needle, ItemName.burn_bomb, ItemName.burn_stone],
[["Burning Ability"], ["Burning Ability"], ["Burning Ability", "Spark Ability"],
["Burning Ability", "Cutter Ability"], ["Ice Ability", "Burning Ability"],
["Needle Ability", "Burning Ability"], ["Bomb Ability", "Burning Ability"],
["Stone Ability", "Burning Ability"]]):
if state.has(specific, player) and state.has_all(access, player):
return True
return False
def has_any_spark(state: "CollectionState", player: int):
for specific, access in zip([ItemName.spark, ItemName.spark_spark, ItemName.burn_spark, ItemName.spark_cutter,
ItemName.ice_spark, ItemName.needle_spark, ItemName.bomb_spark, ItemName.stone_spark],
[["Spark Ability"], ["Spark Ability"], ["Burning Ability", "Spark Ability"],
["Spark Ability", "Cutter Ability"], ["Ice Ability", "Spark Ability"],
["Needle Ability", "Spark Ability"], ["Bomb Ability", "Spark Ability"],
["Stone Ability", "Spark Ability"]]):
if state.has(specific, player) and state.has_all(access, player):
return True
return False
def has_any_cutter(state: "CollectionState", player: int):
for specific, access in zip([ItemName.cutter, ItemName.cutter_cutter, ItemName.spark_cutter, ItemName.burn_cutter,
ItemName.ice_cutter, ItemName.needle_cutter, ItemName.bomb_cutter,
ItemName.stone_cutter],
[["Cutter Ability"], ["Cutter Ability"], ["Cutter Ability", "Spark Ability"],
["Cutter Ability", "Burning Ability"], ["Ice Ability", "Cutter Ability"],
["Needle Ability", "Cutter Ability"], ["Bomb Ability", "Cutter Ability"],
["Stone Ability", "Cutter Ability"]]):
if state.has(specific, player) and state.has_all(access, player):
return True
return False
def has_great_cutter(state: "CollectionState", player: int, specific_ability: int):
if not state.has("Cutter Ability", player):
return False
if specific_ability:
return state.has(ItemName.cutter_cutter, player)
else:
return state.has(ItemName.cutter, player)
def has_geokinesis(state: "CollectionState", player: int, specific_ability: int):
if not state.has_all(["Stone Ability", "Spark Ability"], player):
return False
if specific_ability:
return state.has(ItemName.stone_spark, player) and state.has_any({ItemName.stone, ItemName.spark}, player)
else:
return state.has_all({ItemName.stone, ItemName.spark}, player)
def has_lightbulb(state: "CollectionState", player: int, specific_ability: int):
if not state.has_all(["Bomb Ability", "Spark Ability"], player):
return False
if specific_ability:
return state.has(ItemName.bomb_spark, player) and state.has_any({ItemName.bomb, ItemName.spark}, player)
else:
return state.has_all({ItemName.bomb, ItemName.spark}, player)
def has_exploding_snowman(state: "CollectionState", player: int, specific_ability: int):
if not state.has_all(["Bomb Ability", "Ice Ability"], player):
return False
if specific_ability:
return state.has(ItemName.ice_bomb, player) and state.has_any({ItemName.ice, ItemName.bomb}, player)
else:
return state.has_all({ItemName.ice, ItemName.bomb}, player)
def has_volcano(state: "CollectionState", player: int, specific_ability: int):
if not state.has_all(["Stone Ability", "Burning Ability"], player):
return False
if specific_ability:
return state.has(ItemName.burn_stone, player) and state.has_any({ItemName.stone, ItemName.burn}, player)
else:
return state.has_all({ItemName.stone, ItemName.burn}, player)
def has_shurikens(state: "CollectionState", player: int, specific_ability: int):
if not state.has_all(["Bomb Ability", "Cutter Ability"], player):
return False
if specific_ability:
return state.has(ItemName.bomb_cutter, player) and state.has_any({ItemName.bomb, ItemName.cutter}, player)
else:
return state.has_all({ItemName.bomb, ItemName.cutter}, player)
def has_stone_friends(state: "CollectionState", player: int, specific_ability: int):
if not state.has_all(["Stone Ability", "Cutter Ability"], player):
return False
if specific_ability:
return state.has(ItemName.stone_cutter, player) and state.has_any({ItemName.stone, ItemName.cutter}, player)
else:
return state.has_all({ItemName.stone, ItemName.cutter}, player)
def has_dynamite(state: "CollectionState", player: int, specific_ability: int):
if not state.has_all(["Stone Ability", "Bomb Ability"], player):
return False
if specific_ability:
return state.has(ItemName.stone_bomb, player) and state.has_any({ItemName.stone, ItemName.bomb}, player)
else:
return state.has_all({ItemName.stone, ItemName.bomb}, player)
def has_lightning_rod(state: "CollectionState", player: int, specific_ability: int):
if not state.has_all(["Needle Ability", "Spark Ability"], player):
return False
if specific_ability:
return state.has(ItemName.needle_spark, player) and state.has_any({ItemName.needle, ItemName.spark}, player)
else:
return state.has_all({ItemName.needle, ItemName.spark}, player)
def has_drill(state: "CollectionState", player: int, specific_ability: int):
if not state.has_all(["Stone Ability", "Needle Ability"], player):
return False
if specific_ability:
return state.has(ItemName.stone_needle, player) and state.has_any({ItemName.needle, ItemName.stone}, player)
else:
return state.has_all({ItemName.needle, ItemName.stone}, player)
def has_lightsaber(state: "CollectionState", player: int, specific_ability: int):
if not state.has_all(["Cutter Ability", "Spark Ability"], player):
return False
if specific_ability:
return state.has(ItemName.spark_cutter, player) and state.has_any({ItemName.cutter, ItemName.spark}, player)
else:
return state.has_all({ItemName.cutter, ItemName.spark}, player)
def has_exploding_gordo(state: "CollectionState", player: int, specific_ability: int):
if not state.has_all(["Bomb Ability", "Needle Ability"], player):
return False
if specific_ability:
return state.has(ItemName.needle_bomb, player) and state.has_any({ItemName.needle, ItemName.bomb}, player)
else:
return state.has_all({ItemName.needle, ItemName.bomb}, player)
def has_fire_arrows(state: "CollectionState", player: int, specific_ability: int):
if not state.has_all(["Burning Ability", "Needle Ability"], player):
return False
if specific_ability:
return state.has(ItemName.burn_needle, player) and state.has_any({ItemName.needle, ItemName.burn}, player)
else:
return state.has_all({ItemName.needle, ItemName.burn}, player)
def has_waddle_dee(state: "CollectionState", player: int):
return state.has(ItemName.waddle_dee, player)
def has_adeleine(state: "CollectionState", player: int):
return state.has(ItemName.adeleine, player)
def has_king_dedede(state: "CollectionState", player: int):
return state.has(ItemName.king_dedede, player)
def set_oneup_rules(world: "K64World"):
for location in (LocationName.neo_star_2_u1, LocationName.neo_star_2_u2):
set_rule(world.get_location(location), lambda state: has_waddle_dee(state, world.player))
for location in (LocationName.aqua_star_3_u1, LocationName.neo_star_4_u1, LocationName.ripple_star_2_u1, LocationName.ripple_star_2_u2):
set_rule(world.get_location(location), lambda state: has_king_dedede(state, world.player))
add_rule(world.get_location(LocationName.ripple_star_2_u2), lambda state: has_any_spark(state, world.player))
add_rule(world.get_location(LocationName.aqua_star_3_u1),
lambda state: has_stone_friends(state, world.player, world.options.split_power_combos.value))
def set_food_rules(world: "K64World"):
# Waddle Dee
for location in (LocationName.rock_star_1_f5, LocationName.aqua_star_2_f4, LocationName.aqua_star_2_f5,
LocationName.aqua_star_2_f6, LocationName.aqua_star_2_f7, LocationName.aqua_star_2_f8,
LocationName.aqua_star_2_f9, LocationName.aqua_star_2_f10, LocationName.aqua_star_2_f11,
LocationName.neo_star_2_f2, LocationName.neo_star_2_f3, LocationName.neo_star_2_f4,
LocationName.neo_star_2_f5, LocationName.neo_star_2_f6, LocationName.neo_star_2_f7,
LocationName.neo_star_2_f8, LocationName.neo_star_2_f9, LocationName.neo_star_2_f10,
LocationName.shiver_star_1_f4, LocationName.shiver_star_1_f5, LocationName.shiver_star_1_f6,
LocationName.shiver_star_1_f7, LocationName.shiver_star_1_f8, LocationName.shiver_star_1_f9,
LocationName.shiver_star_1_f10, LocationName.shiver_star_1_f11, LocationName.shiver_star_1_f12,):
set_rule(world.get_location(location), lambda state: has_waddle_dee(state, world.player))
# King Dedede
for location in (LocationName.rock_star_2_f7, LocationName.rock_star_2_f8, LocationName.rock_star_2_f9,
LocationName.rock_star_2_f10, LocationName.aqua_star_3_f3, LocationName.neo_star_4_f3,
LocationName.neo_star_4_f4, LocationName.neo_star_4_f5, LocationName.neo_star_4_f6,
LocationName.neo_star_4_f7, LocationName.neo_star_4_f8, LocationName.neo_star_4_f9,
LocationName.neo_star_4_f10, LocationName.neo_star_4_f11, LocationName.neo_star_4_f12,
LocationName.neo_star_4_f13, LocationName.neo_star_4_f14, LocationName.shiver_star_4_f3,
LocationName.shiver_star_4_f4, LocationName.shiver_star_4_f5, LocationName.shiver_star_4_f6,
LocationName.shiver_star_4_f7, LocationName.shiver_star_4_f8, LocationName.shiver_star_4_f9,
LocationName.shiver_star_4_f10, LocationName.shiver_star_4_f11, LocationName.shiver_star_4_f12,
LocationName.shiver_star_4_f13, LocationName.shiver_star_4_f14, LocationName.ripple_star_2_f3,
LocationName.ripple_star_2_f4, LocationName.ripple_star_2_f5, LocationName.ripple_star_2_f6,
LocationName.ripple_star_2_f7, LocationName.ripple_star_2_f8, LocationName.ripple_star_2_f9,
LocationName.ripple_star_2_f10, LocationName.ripple_star_2_f11):
set_rule(world.get_location(location), lambda state: has_king_dedede(state, world.player))
# Adeleine
for location in (LocationName.pop_star_3_f3, LocationName.aqua_star_1_f8, LocationName.dark_star_adeleine):
set_rule(world.get_location(location), lambda state: has_adeleine(state, world.player))
add_rule(world.get_location(LocationName.ripple_star_2_f10), lambda state: has_any_ice(state, world.player))
add_rule(world.get_location(LocationName.ripple_star_2_f11), lambda state: has_any_needle(state, world.player))
def set_star_rules(world: "K64World"):
# define the ranges for each level in question
waddle_dee_range_start = {
0x0004: 0x0455,
0x0009: 0x0508,
0x000D: 0x05C7,
0x0010: 0x0653,
}
dedede_range_start = {
0x0005: 0x0480,
0x000A: 0x054A,
0x000F: 0x061F,
0x0013: 0x06E3,
0x0015: 0x072E,
}
for level, start in waddle_dee_range_start.items():
for loc in range(start, consumable_by_level[level][1]):
if loc in star_locations:
set_rule(world.get_location(star_locations[loc]), lambda state: has_waddle_dee(state, world.player))
for level, start in dedede_range_start.items():
for loc in range(start, consumable_by_level[level][1]):
if loc in star_locations:
set_rule(world.get_location(star_locations[loc]), lambda state: has_king_dedede(state, world.player))
for location in (LocationName.aqua_star_1_t35, LocationName.aqua_star_1_t36,
LocationName.aqua_star_1_t37, LocationName.aqua_star_1_t38):
add_rule(world.get_location(location),
lambda state: has_exploding_snowman(state, world.player, world.options.split_power_combos.value))
for location in (LocationName.shiver_star_4_t6, LocationName.shiver_star_4_t7):
add_rule(world.get_location(location),
lambda state: has_drill(state, world.player, world.options.split_power_combos.value))
def set_rules(world: "K64World") -> None:
# Level 1
set_rule(world.get_location(LocationName.pop_star_1_s2), lambda state: has_any_bomb(state, world.player))
set_rule(world.get_location(LocationName.pop_star_3_s1),
lambda state: has_great_cutter(state, world.player, world.options.split_power_combos.value))
# Level 2
set_rule(world.get_location(LocationName.rock_star_1), lambda state: has_waddle_dee(state, world.player))
set_rule(world.get_location(LocationName.rock_star_1_s3),
lambda state: has_geokinesis(state, world.player, world.options.split_power_combos.value)
and has_waddle_dee(state, world.player))
set_rule(world.get_location(LocationName.rock_star_2), lambda state: has_king_dedede(state, world.player))
set_rule(world.get_location(LocationName.rock_star_2_s3), lambda state: has_king_dedede(state, world.player))
set_rule(world.get_location(LocationName.rock_star_3_s1), lambda state: has_any_stone(state, world.player))
set_rule(world.get_location(LocationName.rock_star_4_s2),
lambda state: has_lightbulb(state, world.player, world.options.split_power_combos.value))
# Level 3
set_rule(world.get_location(LocationName.aqua_star_1_s3),
lambda state: has_exploding_snowman(state, world.player, world.options.split_power_combos.value))
set_rule(world.get_location(LocationName.aqua_star_2_s1),
lambda state: has_volcano(state, world.player, world.options.split_power_combos.value))
for location in (LocationName.aqua_star_2, LocationName.aqua_star_2_s2, LocationName.aqua_star_2_s3):
set_rule(world.get_location(location), lambda state: has_waddle_dee(state, world.player))
for location in (LocationName.aqua_star_3, LocationName.aqua_star_3_s2, LocationName.aqua_star_3_s3):
set_rule(world.get_location(location), lambda state: has_king_dedede(state, world.player))
set_rule(world.get_location(LocationName.aqua_star_3_s1),
lambda state: has_shurikens(state, world.player, world.options.split_power_combos.value))
add_rule(world.get_location(LocationName.aqua_star_3_s3),
lambda state: has_stone_friends(state, world.player, world.options.split_power_combos.value))
# Level 4
for location in (LocationName.neo_star_2, LocationName.neo_star_2_s2, LocationName.neo_star_2_s3):
set_rule(world.get_location(location), lambda state: has_waddle_dee(state, world.player))
add_rule(world.get_location(LocationName.neo_star_2_s3),
lambda state: has_dynamite(state, world.player, world.options.split_power_combos.value))
set_rule(world.get_location(LocationName.neo_star_3_s1), lambda state: has_any_needle(state, world.player))
set_rule(world.get_location(LocationName.neo_star_3_s2), lambda state: has_adeleine(state, world.player))
for location in (LocationName.neo_star_4, LocationName.neo_star_4_s1,
LocationName.neo_star_4_s2, LocationName.neo_star_4_s3):
set_rule(world.get_location(location), lambda state: has_king_dedede(state, world.player))
add_rule(world.get_location(LocationName.neo_star_4_s2), lambda state: has_any_ice(state, world.player))
# Level 5
for location in (LocationName.shiver_star_1, LocationName.shiver_star_1_s1,
LocationName.shiver_star_1_s2, LocationName.shiver_star_1_s3):
set_rule(world.get_location(location), lambda state: has_waddle_dee(state, world.player))
add_rule(world.get_location(LocationName.shiver_star_1_s2), lambda state: has_any_burn(state, world.player))
set_rule(world.get_location(LocationName.shiver_star_2_s3),
lambda state: has_lightning_rod(state, world.player, world.options.split_power_combos.value))
set_rule(world.get_location(LocationName.shiver_star_3_s3), lambda state: has_adeleine(state, world.player))
set_rule(world.get_location(LocationName.shiver_star_4_s1),
lambda state: has_drill(state, world.player, world.options.split_power_combos.value))
for location in (LocationName.shiver_star_4, LocationName.shiver_star_4_s2, LocationName.shiver_star_4_s3):
set_rule(world.get_location(location), lambda state: has_king_dedede(state, world.player))
add_rule(world.get_location(LocationName.shiver_star_4_s2),
lambda state: has_lightsaber(state, world.player, world.options.split_power_combos.value))
# Level 6
set_rule(world.get_location(LocationName.ripple_star_1_s3),
lambda state: has_exploding_gordo(state, world.player, world.options.split_power_combos.value)
and state.has_any([ItemName.bomb, ItemName.needle], world.player)) # by default cannot carry enemy across
set_rule(world.get_location(LocationName.ripple_star_2_s1), lambda state: has_any_spark(state, world.player))
for location in (LocationName.ripple_star_2, LocationName.ripple_star_2_s2, LocationName.ripple_star_2_s3):
set_rule(world.get_location(location), lambda state: has_king_dedede(state, world.player))
add_rule(world.get_location(LocationName.ripple_star_2_s3), lambda state: has_any_cutter(state, world.player))
set_rule(world.get_location(LocationName.ripple_star_3_s2),
lambda state: has_fire_arrows(state, world.player, world.options.split_power_combos.value))
# Crystal Requirements
for i, level in zip(range(1, 7), world.boss_requirements):
set_rule(world.multiworld.get_entrance(f"To Level {i + 1}", world.player),
lambda state, j=level: state.has(ItemName.crystal_shard, world.player, j))
set_rule(world.multiworld.get_location(f"{LocationName.level_names[i]} - Boss Defeated", world.player),
lambda state, j=level: state.has(ItemName.crystal_shard, world.player, j))
# Consumables
if "1-Ups" in world.options.consumables:
set_oneup_rules(world)
if "Food" in world.options.consumables:
set_food_rules(world)
if "Stars" in world.options.consumables:
set_star_rules(world)
# Friend Requirement
add_rule(world.get_entrance("To Level 7"), lambda state: state.has_all([ItemName.waddle_dee, ItemName.adeleine,
ItemName.king_dedede], world.player))
world.multiworld.completion_condition[world.player] = lambda state: state.has(ItemName.ribbons_crystal,
world.player)