From 81d953daa3071576df78b119ea4c746352d0ecab Mon Sep 17 00:00:00 2001 From: el-u <109771707+el-u@users.noreply.github.com> Date: Sat, 14 Jan 2023 14:29:54 +0100 Subject: [PATCH] alttp: add item rules for prize locations (#1380) --- worlds/alttp/Rules.py | 13 ++++++++- worlds/alttp/test/items/TestPrizes.py | 39 +++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 worlds/alttp/test/items/TestPrizes.py diff --git a/worlds/alttp/Rules.py b/worlds/alttp/Rules.py index d1413e21..e9f45c4c 100644 --- a/worlds/alttp/Rules.py +++ b/worlds/alttp/Rules.py @@ -1,9 +1,12 @@ import collections import logging +from typing import Iterator, Set + from worlds.alttp import OverworldGlitchRules from BaseClasses import RegionType, MultiWorld, Entrance -from worlds.alttp.Items import ItemFactory, progression_items, item_name_groups +from worlds.alttp.Items import ItemFactory, progression_items, item_name_groups, item_table from worlds.alttp.OverworldGlitchRules import overworld_glitches_rules, no_logic_rules +from worlds.alttp.Regions import location_table from worlds.alttp.UnderworldGlitchRules import underworld_glitches_rules from worlds.alttp.Bosses import GanonDefeatRule from worlds.generic.Rules import set_rule, add_rule, forbid_item, add_item_rule, item_in_locations, \ @@ -176,6 +179,14 @@ def dungeon_boss_rules(world, player): def global_rules(world, player): # ganon can only carry triforce add_item_rule(world.get_location('Ganon', player), lambda item: item.name == 'Triforce' and item.player == player) + # dungeon prizes can only be crystals/pendants + crystals_and_pendants: Set[str] = \ + {item for item, item_data in item_table.items() if item_data.type == "Crystal"} + prize_locations: Iterator[str] = \ + (locations for locations, location_data in location_table.items() if location_data[2] == True) + for prize_location in prize_locations: + add_item_rule(world.get_location(prize_location, player), + lambda item: item.name in crystals_and_pendants and item.player == player) # determines which S&Q locations are available - hide from paths since it isn't an in-game location world.get_region('Menu', player).can_reach_private = lambda state: True for exit in world.get_region('Menu', player).exits: diff --git a/worlds/alttp/test/items/TestPrizes.py b/worlds/alttp/test/items/TestPrizes.py new file mode 100644 index 00000000..5e729093 --- /dev/null +++ b/worlds/alttp/test/items/TestPrizes.py @@ -0,0 +1,39 @@ +from typing import List + +from BaseClasses import Item, Location +from test.TestBase import WorldTestBase + + +class TestPrizes(WorldTestBase): + game = "A Link to the Past" + + def test_item_rules(self): + prize_locations: List[Location] = [ + self.multiworld.get_location("Eastern Palace - Prize", 1), + self.multiworld.get_location("Desert Palace - Prize", 1), + self.multiworld.get_location("Tower of Hera - Prize", 1), + self.multiworld.get_location("Palace of Darkness - Prize", 1), + self.multiworld.get_location("Swamp Palace - Prize", 1), + self.multiworld.get_location("Thieves\' Town - Prize", 1), + self.multiworld.get_location("Skull Woods - Prize", 1), + self.multiworld.get_location("Ice Palace - Prize", 1), + self.multiworld.get_location("Misery Mire - Prize", 1), + self.multiworld.get_location("Turtle Rock - Prize", 1), + ] + prize_items: List[Item] = [ + self.get_item_by_name("Green Pendant"), + self.get_item_by_name("Blue Pendant"), + self.get_item_by_name("Red Pendant"), + self.get_item_by_name("Crystal 1"), + self.get_item_by_name("Crystal 2"), + self.get_item_by_name("Crystal 3"), + self.get_item_by_name("Crystal 4"), + self.get_item_by_name("Crystal 5"), + self.get_item_by_name("Crystal 6"), + self.get_item_by_name("Crystal 7"), + ] + + for item in self.multiworld.get_items(): + for prize_location in prize_locations: + self.assertEqual(item in prize_items, prize_location.item_rule(item), + f"{item} must {'' if item in prize_items else 'not '}be allowed in {prize_location}.")