Files
dockipelago/worlds/kss/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

304 lines
20 KiB
Python

import typing
from typing import TYPE_CHECKING
from .names import location_names, item_names
from .items import sub_game_completion
from worlds.generic.Rules import set_rule, add_rule
if TYPE_CHECKING:
from . import KSSWorld
from BaseClasses import CollectionState
def can_fight_wind(state: "CollectionState", player: int) -> bool:
return state.has_any([item_names.wing, item_names.jet, item_names.ninja], player)
def set_dyna_blade_rules(world: "KSSWorld") -> None:
set_rule(world.get_location(location_names.db_switch_1),
lambda state: state.has_any([item_names.mirror, item_names.beam], world.player) or
(state.has(item_names.plasma, world.player)
and state.has_any_count({item_names.dyna_blade_ex1: 1,
item_names.progressive_dyna_blade: 2}, world.player)))
set_rule(world.get_entrance("Mallow Castle -> Dyna Blade Bonus 1"),
lambda state: state.has(item_names.dyna_blade_ex1, world.player))
set_rule(world.get_entrance("Candy Mountain -> Dyna Blade Bonus 2"),
lambda state: state.has(item_names.dyna_blade_ex2, world.player))
if "Maxim Tomato" in world.options.consumables:
set_rule(world.get_location(location_names.db_pp_maxim_3),
lambda state: state.has(item_names.beam, world.player))
for location in (location_names.db_cm_maxim_1, location_names.db_cm_maxim_2):
set_rule(world.get_location(location), lambda state: state.has(item_names.fire, world.player))
if "1-Up" in world.options.consumables:
set_rule(world.get_location(location_names.db_pp_1up_1), lambda state: state.has(item_names.beam, world.player))
set_rule(world.get_location(location_names.db_mc_1up_1),
lambda state: (state.has_any([item_names.cutter, item_names.beam, item_names.bomb,
item_names.parasol, item_names.mirror, item_names.hammer,
item_names.sword], world.player))
or (state.has_any([item_names.yoyo, item_names.stone], world.player)
and state.has(item_names.progressive_dyna_blade, world.player, 2))
or (state.has(item_names.ninja, world.player)
and state.has(item_names.dyna_blade_ex1, world.player))
)
for location in (location_names.db_mc_1up_3, location_names.db_mc_1up_4, location_names.db_mc_1up_5):
set_rule(world.get_location(location),
lambda state: state.has(item_names.hammer, world.player)
or (state.has(item_names.stone, world.player) and
state.has(item_names.progressive_dyna_blade, world.player, 2)))
set_rule(world.get_location(location_names.db_cc_1up_2), lambda state: state.has_any([item_names.beam,
item_names.stone,
item_names.mirror,
item_names.hammer,
item_names.yoyo],
world.player))
set_rule(world.get_location(location_names.db_cm_1up_1),
lambda state: state.has_any([item_names.hammer, item_names.stone], world.player))
for location in (location_names.db_cm_1up_2, location_names.db_cm_1up_3,
location_names.db_cm_1up_4, location_names.db_cm_1up_5):
set_rule(world.get_location(location), lambda state: state.has(item_names.fire, world.player))
def set_great_cave_rules(world: "KSSWorld") -> None:
if hasattr(world.multiworld, "re_gen_passthrough"):
re_gen_passthrough: dict[str, typing.Any] = getattr(world.multiworld, "re_gen_passthrough")
if "Kirby Super Star" in re_gen_passthrough:
world.treasure_value = re_gen_passthrough["Kirby Super Star"]["treasure_value"]
# Delay setting these rules until we know for sure
if world.treasure_value:
set_rule(world.get_entrance("Sub-Tree -> Crystal"), lambda state: state.has("Gold", world.player,
world.treasure_value[0]))
set_rule(world.get_entrance("Crystal -> Old Tower"), lambda state: state.has("Gold", world.player,
world.treasure_value[1]))
set_rule(world.get_entrance("Old Tower -> Garden"), lambda state: state.has("Gold", world.player,
world.treasure_value[2]))
set_rule(world.get_location(location_names.tgco_complete), lambda state: state.has("Gold", world.player,
world.treasure_value[3]))
# Treasures
set_rule(world.get_location(location_names.tgco_treasure_4),
lambda state: state.has_any([item_names.wing, item_names.plasma], world.player))
set_rule(world.get_location(location_names.tgco_treasure_7),
lambda state: state.has_any([item_names.beam, item_names.wing, item_names.plasma], world.player))
set_rule(world.get_location(location_names.tgco_treasure_13),
lambda state: state.has_any([item_names.cutter, item_names.sword, item_names.wing], world.player))
set_rule(world.get_location(location_names.tgco_treasure_18),
lambda state: state.has_any([item_names.crash, item_names.yoyo,
item_names.bomb, item_names.beam], world.player))
set_rule(world.get_location(location_names.tgco_treasure_19),
lambda state: state.has_any([item_names.crash, item_names.yoyo,
item_names.bomb, item_names.beam], world.player))
set_rule(world.get_location(location_names.tgco_treasure_20),
lambda state: state.has_any([item_names.crash, item_names.yoyo,
item_names.bomb, item_names.beam], world.player))
set_rule(world.get_location(location_names.tgco_treasure_21),
lambda state: state.has_any([item_names.crash, item_names.yoyo,
item_names.bomb, item_names.beam], world.player))
set_rule(world.get_location(location_names.tgco_treasure_22),
lambda state: state.has_any([item_names.crash, item_names.yoyo,
item_names.bomb, item_names.beam], world.player))
set_rule(world.get_location(location_names.tgco_treasure_28),
lambda state: state.has_any([item_names.crash, item_names.yoyo,
item_names.bomb, item_names.beam], world.player))
set_rule(world.get_location(location_names.tgco_treasure_31),
lambda state: state.has_any([item_names.hammer, item_names.stone], world.player))
set_rule(world.get_location(location_names.tgco_treasure_32),
lambda state: state.has_any([item_names.hammer, item_names.stone], world.player)
and state.has(item_names.fire, world.player))
set_rule(world.get_location(location_names.tgco_treasure_33),
lambda state: state.has_any([item_names.hammer, item_names.stone], world.player))
set_rule(world.get_location(location_names.tgco_treasure_34),
lambda state: state.has_any([item_names.cutter, item_names.beam, item_names.hammer,
item_names.bomb, item_names.jet, item_names.wing, item_names.stone,
item_names.plasma, item_names.parasol], world.player))
set_rule(world.get_location(location_names.tgco_treasure_36),
lambda state: state.has_any([item_names.beam, item_names.yoyo, item_names.plasma], world.player))
set_rule(world.get_location(location_names.tgco_treasure_37),
lambda state: state.has_any([item_names.parasol, item_names.yoyo, item_names.beam, item_names.plasma,
item_names.hammer, item_names.stone, item_names.bomb], world.player))
set_rule(world.get_location(location_names.tgco_treasure_42),
lambda state: state.has(item_names.stone, world.player))
set_rule(world.get_location(location_names.tgco_treasure_43),
lambda state: state.has(item_names.plasma, world.player) or
(state.has_any([item_names.ninja, item_names.sword, item_names.wing], world.player)
and state.has(item_names.stone, world.player)))
set_rule(world.get_location(location_names.tgco_treasure_45),
lambda state: state.has_any([item_names.jet, item_names.fire], world.player))
set_rule(world.get_location(location_names.tgco_treasure_47),
lambda state: can_fight_wind(state, world.player))
set_rule(world.get_location(location_names.tgco_treasure_49),
lambda state: state.has(item_names.jet, world.player))
set_rule(world.get_location(location_names.tgco_treasure_52),
lambda state: state.has_any([item_names.parasol, item_names.wing, item_names.plasma], world.player))
set_rule(world.get_location(location_names.tgco_treasure_53),
lambda state: state.has(item_names.wheel, world.player))
set_rule(world.get_location(location_names.tgco_treasure_58),
lambda state: state.has_any([item_names.beam, item_names.crash], world.player))
set_rule(world.get_location(location_names.tgco_treasure_59),
lambda state: state.has_any([item_names.ninja, item_names.sword, item_names.wing, item_names.cutter],
world.player))
if "Maxim Tomato" in world.options.consumables:
set_rule(world.get_location(location_names.tgco_ot_maxim_11), lambda state: state.has_any([item_names.stone,
item_names.hammer],
world.player))
set_rule(world.get_location(location_names.tgco_ot_maxim_12),
lambda state: state.has_any([item_names.stone, item_names.hammer], world.player)
and state.has(item_names.fire, world.player))
set_rule(world.get_location(location_names.tgco_ga_maxim_1),
lambda state: can_fight_wind(state, world.player))
set_rule(world.get_location(location_names.tgco_ga_maxim_7),
lambda state: state.has_any([item_names.bomb, item_names.beam, item_names.mirror, item_names.plasma,
item_names.wing, item_names.jet, item_names.stone, item_names.yoyo,
item_names.sword, item_names.hammer], world.player))
set_rule(world.get_location(location_names.tgco_ga_maxim_8),
lambda state: state.has_any([item_names.sword, item_names.cutter, item_names.wing], world.player))
if "1-Up" in world.options.consumables:
set_rule(world.get_location(location_names.tgco_st_1up_1), lambda state: state.has_any([item_names.bomb,
item_names.beam],
world.player))
set_rule(world.get_location(location_names.tgco_st_1up_2), lambda state: state.has_any([item_names.wing,
item_names.cutter,
item_names.sword],
world.player))
set_rule(world.get_location(location_names.tgco_ot_1up_2),
lambda state: state.has_any([item_names.stone, item_names.hammer], world.player)
and state.has(item_names.fire, world.player))
for location in (location_names.tgco_ga_1up_3, location_names.tgco_ga_1up_4):
set_rule(world.get_location(location),
lambda state: state.has_any(
[item_names.bomb, item_names.beam, item_names.mirror, item_names.plasma,
item_names.wing, item_names.jet, item_names.stone, item_names.yoyo,
item_names.sword, item_names.hammer], world.player))
set_rule(world.get_location(location_names.tgco_ga_1up_5),
lambda state: state.has_any([item_names.sword, item_names.cutter, item_names.wing], world.player))
if world.options.essences:
set_rule(world.get_location(location_names.tgco_ot_mirror),
lambda state: state.has(item_names.plasma, world.player) or
(state.has_any([item_names.ninja, item_names.sword, item_names.wing], world.player)
and state.has(item_names.stone, world.player)))
def set_revenge_rules(world: "KSSWorld") -> None:
# Revenge of Meta Knight
set_rule(world.get_location(location_names.romk_chapter_3),
lambda state: state.has(item_names.fire, world.player))
set_rule(world.get_entrance("RoMK - Chapter 3 -> RoMK - Chapter 4"),
lambda state: state.has(item_names.fire, world.player))
set_rule(world.get_entrance("RoMK - Chapter 4 -> RoMK - Chapter 5"),
lambda state: state.has_any([item_names.beam, item_names.yoyo, item_names.jet, item_names.bomb],
world.player))
set_rule(world.get_location(location_names.romk_chapter_6),
lambda state: state.has_any([item_names.wing, item_names.suplex], world.player))
set_rule(world.get_entrance("RoMK - Chapter 6 -> RoMK - Chapter 7"),
lambda state: state.has_any([item_names.wing, item_names.suplex], world.player))
if "Maxim Tomato" in world.options.consumables:
set_rule(world.get_location(location_names.romk_c3_maxim_1),
lambda state: state.has_any([item_names.hammer, item_names.stone], world.player))
set_rule(world.get_location(location_names.romk_c6_maxim_2),
lambda state: state.has_any([item_names.yoyo, item_names.plasma], world.player)
and state.has_any([item_names.wing, item_names.suplex], world.player))
set_rule(world.get_location(location_names.romk_c6_maxim_3),
lambda state: state.has_any([item_names.wing, item_names.suplex], world.player))
if "1-Up" in world.options.consumables:
set_rule(world.get_location(location_names.romk_c3_1up_2),
lambda state: state.has_any([item_names.hammer, item_names.stone], world.player))
set_rule(world.get_location(location_names.romk_c6_1up_1),
lambda state: state.has_any([item_names.wing, item_names.suplex], world.player))
set_rule(world.get_location(location_names.romk_c6_1up_2),
lambda state: state.has_any([item_names.yoyo, item_names.plasma], world.player)
and state.has_any([item_names.wing, item_names.suplex], world.player))
if world.options.essences:
for location in (location_names.romk_c3_mirror, location_names.romk_c3_parasol, location_names.romk_c3_ninja):
set_rule(world.get_location(location), lambda state: state.has_any([item_names.hammer, item_names.stone],
world.player))
for location in (location_names.romk_c6_yoyo, location_names.romk_c6_bomb):
set_rule(world.get_location(location),
lambda state: state.has_any([item_names.wing, item_names.suplex], world.player))
def set_milky_way_wishes_rules(world: "KSSWorld") -> None:
if world.options.milky_way_wishes_mode == "local":
set_rule(world.get_location(location_names.mww_complete),
lambda state: state.has_all([item_names.floria, item_names.aqualiss,
item_names.skyhigh, item_names.hotbeat,
item_names.cavios, item_names.mecheye,
item_names.halfmoon], world.player))
else:
set_rule(world.get_location(location_names.mww_complete),
lambda state: state.has(item_names.rainbow_star, world.player, 7))
set_rule(world.get_location(location_names.mww_sword),
lambda state: state.has_any([item_names.beam, item_names.bomb, item_names.cutter, item_names.fire,
item_names.hammer, item_names.jet, item_names.mirror, item_names.parasol,
item_names.plasma, item_names.stone, item_names.wing, item_names.yoyo],
world.player))
set_rule(world.get_location(location_names.mww_wheel),
lambda state: state.has_any([item_names.fire, item_names.jet], world.player))
set_rule(world.get_location(location_names.mww_suplex),
lambda state: state.has_any([item_names.fighter, item_names.yoyo], world.player))
set_rule(world.get_location(location_names.mww_ninja),
lambda state: state.has_any([item_names.beam, item_names.cutter, item_names.fire, item_names.hammer,
item_names.jet, item_names.mirror, item_names.parasol, item_names.plasma,
item_names.stone, item_names.sword, item_names.wing, item_names.yoyo],
world.player))
if "Maxim Tomato" in world.options.consumables:
set_rule(world.get_location(location_names.mww_cv_maxim_3),
lambda state: state.has_any([item_names.hammer, item_names.stone], world.player))
set_rule(world.get_location(location_names.mww_me_maxim_1),
lambda state: state.has(item_names.wing, world.player))
set_rule(world.get_location(location_names.mww_me_maxim_3),
lambda state: state.has(item_names.plasma, world.player))
if "1-Up" in world.options.consumables:
set_rule(world.get_location(location_names.mww_aq_1up_2),
lambda state: state.has_any([item_names.jet, item_names.fire], world.player))
set_rule(world.get_location(location_names.mww_cv_1up_1),
lambda state: state.has_any([item_names.hammer, item_names.stone], world.player))
set_rule(world.get_location(location_names.mww_me_1up_2),
lambda state: state.has(item_names.wing, world.player))
for location in (location_names.mww_me_1up_3, location_names.mww_me_1up_4, location_names.mww_me_1up_5):
set_rule(world.get_location(location), lambda state: state.has(item_names.plasma, world.player))
def set_rules(world: "KSSWorld") -> None:
if "Dyna Blade" in world.options.included_subgames:
# Dyna Blade
set_dyna_blade_rules(world)
if "Revenge of Meta Knight" in world.options.included_subgames:
set_revenge_rules(world)
if "The Great Cave Offensive" in world.options.included_subgames:
set_great_cave_rules(world)
if "Milky Way Wishes" in world.options.included_subgames:
set_milky_way_wishes_rules(world)
if "The Arena" in world.options.included_subgames:
for i in range(10, 21):
set_rule(world.get_location(f"The Arena - {i} Straight Wins"),
lambda state: state.has_group_unique("Copy Ability", world.player, 5))
sub_game_complete = list(sub_game_completion.keys())
sub_game_required = []
for sub_game in sub_game_completion.keys():
if sub_game.rsplit(" - ")[0] in world.options.required_subgames:
sub_game_required.append(sub_game)
world.multiworld.completion_condition[world.player] = lambda state: \
state.has_all(sub_game_required, world.player) and state.has_from_list(
sub_game_complete, world.player, world.options.required_subgame_completions.value)