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

175 lines
8.2 KiB
Python

from worlds.AutoWorld import World
from .Data import ALL_PLANTS, LEVEL_LOCATIONS
import itertools
expected_level_loadouts = {}
def can_clear_level(state, world, player, level_data):
if level_data["choose"]:
location_data = LEVEL_LOCATIONS[level_data["location"]]
at_night = location_data["at_night"]
has_pool = location_data["has_pool"]
on_roof = location_data["on_roof"]
#Non-negotiables
forced_items = []
if has_pool:
forced_items.append("Lily Pad")
if on_roof:
forced_items.append("Flower Pot")
if level_data["name"] == "Mini-games: Pogo Party":
forced_items.append("Roof Cleaners")
if level_data["name"] == "Bonus Levels: Grave Danger" or (level_data["type"] == "survival" and at_night and not has_pool):
forced_items.append("Grave Buster")
if level_data["name"] == "Mini-games: Bobsled Bonanza" and "Zomboni" in level_data["zombies"]:
forced_items.append("Spikeweed")
if not all(state.has(item, player) for item in forced_items):
return False
forced_plants = [item for item in forced_items if item in ALL_PLANTS]
#Remaining seed slots
number_of_seed_slots = state.count("Extra Seed Slot", player) + 1
if level_data["type"] == "survival":
number_of_seed_slots *= 2
usable_slots = number_of_seed_slots - len(forced_plants)
if usable_slots < 0:
return False
#Build possible loadouts
possible_combinations = {}
#Attackers
if not on_roof:
possible_combinations["attacker"] = [["Peashooter"], ["Chomper"], ["Snow Pea"], ["Repeater"], ["Split Pea"], ["Cactus"], ["Cabbage-pult"], ["Kernel-pult"], ["Starfruit"]]
if at_night:
possible_combinations["attacker"].append(["Fume-shroom"])
else:
possible_combinations["attacker"] = [["Cabbage-pult"], ["Kernel-pult"], ["Melon-pult"]]
if world.options.easy_upgrade_plants.value:
possible_combinations["attacker"].append(["Winter Melon"])
#Cloudy Day attackers
if level_data["type"] == "cloudy":
possible_combinations["cloudy"] = [["Peashooter"], ["Snow Pea"], ["Repeater"], ["Cactus"], ["Cabbage-pult"], ["Kernel-pult"]]
#Sun producers
if level_data["type"] != "adventure" or level_data["flags"] > 1:
if at_night:
possible_combinations["sun"] = [["Sun-shroom"]]
else:
possible_combinations["sun"] = [["Sunflower"]]
#Wall plants
if level_data["type"] == "survival" or any(zombie in level_data["zombies"] for zombie in ["PeaHead", "GatlingHead", "TallnutHead"]):
possible_combinations["wall"] = [["Wall-nut"], ["Tall-nut"], ["Pumpkin"]]
#AOE plants
if level_data["type"] == "survival" or level_data["name"] == "Minigames: Last Stand" or "GigaGargantuar" in level_data["zombies"]:
possible_combinations["aoe"] = [["Repeater", "Torchwood"], ["Threepeater", "Torchwood"], ["Melon-pult"]]
if world.options.easy_upgrade_plants.value:
possible_combinations["aoe"].append(["Winter Melon"])
if at_night:
possible_combinations["aoe"].append(["Fume-shroom"])
else:
possible_combinations["aoe"].append(["Fume-shroom", "Coffee Bean"])
#Night plants
if at_night:
possible_combinations["night"] = [["Puff-shroom", "Fume-shroom"], ["Scaredy-shroom", "Fume-shroom"], ["Puff-shroom", "Scaredy-shroom"]]
#Multi-lane
if level_data["name"] == "Bonus Levels: Unsodded":
possible_combinations["lanes"] = [["Threepeater"], ["Starfruit"]]
#Balloon
if "Balloon" in level_data["zombies"]:
possible_combinations["balloon"] = [["Cactus"], ["Blover"]]
if has_pool:
possible_combinations["balloon"].append(["Cattail"])
#Shields
if any(zombie in level_data["zombies"] for zombie in ["ScreenDoor", "Ladder", "TrashCan"]):
possible_combinations["shield"] = [["Cabbage-pult"], ["Kernel-pult"]]
if at_night:
possible_combinations["shield"] += [["Fume-shroom"], ["Magnet-shroom"]]
else:
possible_combinations["shield"] += [["Fume-shroom", "Coffee Bean"], ["Magnet-shroom", "Coffee Bean"]]
#Digger
if "Digger" in level_data["zombies"]:
possible_combinations["digger"] = [["Starfruit"], ["Split Pea"]]
if has_pool:
possible_combinations["digger"].append(["Cattail"])
if at_night:
possible_combinations["digger"].append(["Magnet-shroom"])
else:
possible_combinations["digger"].append(["Magnet-shroom", "Coffee Bean"])
#Snorkel
if "Snorkel" in level_data["zombies"]:
possible_combinations["snorkel"] = [["Cabbage-pult"], ["Kernel-pult"], ["Melon-pult"], ["Wall-nut"], ["Tall-nut"], ["Pumpkin"]]
if world.options.easy_upgrade_plants.value:
possible_combinations["snorkel"].append(["Winter Melon"])
#Pogo
if "Pogo" in level_data["zombies"]:
possible_combinations["pogo"] = [["Split Pea"], ["Starfruit"], ["Tall-nut"]]
if at_night:
possible_combinations["pogo"].append(["Magnet-shroom"])
else:
possible_combinations["pogo"].append(["Magnet-shroom", "Coffee Bean"])
if has_pool:
possible_combinations["pogo"].append(["Cattail"])
#Football
if any(zombie in level_data["zombies"] for zombie in ["Football"]):
possible_combinations["football"] = [["Cherry Bomb"], ["Squash"], ["Jalapeno"], ["Wall-nut"], ["Tall-nut"], ["Pumpkin"]]
if at_night:
possible_combinations["football"].append(["Magnet-shroom"])
else:
possible_combinations["football"].append(["Magnet-shroom", "Coffee Bean"])
#Zomboni
if any(zombie in level_data["zombies"] for zombie in ["Zomboni"]):
possible_combinations["zomboni"] = [["Cherry Bomb"], ["Squash"], ["Jalapeno"]]
if not on_roof:
possible_combinations["zomboni"].append(["Spikeweed"])
#Gargantuar
if any(zombie in level_data["zombies"] for zombie in ["Gargantuar", "GigaGargantuar"]):
possible_combinations["garg"] = [["Cherry Bomb", "Squash"], ["Squash", "Jalapeno"], ["Jalapeno", "Cherry Bomb"]]
unlocked_plants = {plant for plant in ALL_PLANTS if state.has(plant, player)}
choosable_combinations = {}
for req, combos in possible_combinations.items():
valid = [combo for combo in combos if all(p in unlocked_plants for p in combo)]
if not valid:
return False #Don't have the plants unlocked in order to meet this requirement
choosable_combinations[req] = valid
selected_plants = set(forced_plants)
for req in sorted(choosable_combinations, key=lambda r: len(choosable_combinations[r])):
combos = sorted(choosable_combinations[req], key=lambda combo: len([p for p in combo if p not in selected_plants])) #Try to re-use plants where possible
for combo in combos:
new_plants = [p for p in combo if p not in selected_plants]
if len(selected_plants) + len(new_plants) <= number_of_seed_slots:
selected_plants.update(combo)
break
else: #You cannot fit the requirement in
return False
expected_level_loadouts[level_data['name']] = selected_plants
return True
def set_rules(world: World) -> None:
player = world.player
multiworld = world.multiworld
multiworld.completion_condition[player] = lambda state: state.has("Music Video", player)
for x in range(8, world.options.shop_items.value):
amount_of_restocks_required = int(x / 8)
multiworld.get_location(f"Crazy Dave's Twiddydinkies: Item #{str(x + 1)}", player).access_rule = lambda state, req=amount_of_restocks_required: (state.has("Twiddydinkies Restock", player, req))