From db874ec6d61c4146a246a437282f8e9e42b2bac1 Mon Sep 17 00:00:00 2001 From: espaspw Date: Mon, 3 Aug 2026 00:14:44 -0700 Subject: [PATCH 1/3] Rename Defeat Tania to Tania --- worlds/little_witch_nobeta/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/little_witch_nobeta/__init__.py b/worlds/little_witch_nobeta/__init__.py index b8100993c91a..88eb8a8f7cdf 100644 --- a/worlds/little_witch_nobeta/__init__.py +++ b/worlds/little_witch_nobeta/__init__.py @@ -297,7 +297,7 @@ def generate_basic(self): (self.multiworld.get_location("Secret Passage - Enraged Armor", self.player) .place_locked_item(self.create_item("Enraged Armor Token"))) - (self.multiworld.get_location("Underground - Defeat tania", self.player) + (self.multiworld.get_location("Underground - Tania", self.player) .place_locked_item(self.create_item("Tania Token"))) (self.multiworld.get_location("Lava Ruins - Monica", self.player) From 92ca7d3c16c7df4a4758a36bcb0dc7c122b086a0 Mon Sep 17 00:00:00 2001 From: espaspw Date: Mon, 3 Aug 2026 00:15:29 -0700 Subject: [PATCH 2/3] Sync with NobetaLogic --- worlds/little_witch_nobeta/locations.py | 26 ++++++++++++-- worlds/little_witch_nobeta/regions.py | 6 ++-- worlds/little_witch_nobeta/rules.py | 46 ++++++++++++++----------- 3 files changed, 53 insertions(+), 25 deletions(-) diff --git a/worlds/little_witch_nobeta/locations.py b/worlds/little_witch_nobeta/locations.py index db48df50c81e..66ce86fc1af5 100644 --- a/worlds/little_witch_nobeta/locations.py +++ b/worlds/little_witch_nobeta/locations.py @@ -49,6 +49,9 @@ def __init__(self, player: int, name="", code=None, parent=None): secret_passage_start_locations: Dict[str, str] = { "Secret Passage - 35. Dwarven Metalwork in pot after first drop": "Lore", +} + +secret_passage_first_fire_barrier_switch_room_locations: Dict[str, str] = { "Secret Passage - 36. High Elf's Mana Ring in pot beside destructible wall": "Lore", "Secret Passage - 11. Broken Queen Doll from enemy behind destructible wall": "Lore", "Secret Passage - Absorption spell chest behind destructible wall": "Chest", @@ -58,12 +61,15 @@ def __init__(self, player: int, name="", code=None, parent=None): secret_passage_after_first_fire_barrier_locations: Dict[str, str] = { "Secret Passage - 37. Forest Elf's Vest from enemy before hole in floor": "Lore", "Secret Passage - Wind spell chest in alcove during fall": "Chest", + "Secret Passage - 38. Dark Elf's Ear Sample from pot at magic barrier": "Lore", +} + +secret_passage_after_secret_passage_gate_locations: Dict[str, str] = { "Secret Passage - Ice spell chest behind breakable wall after fall": "Chest", "Secret Passage - 4. Unknown House Banner from big enemy at spiral stairs": "Lore", "Secret Passage - Secret area shortcut gate switch": "Metal Gate", "Secret Passage - Fire spell chest at second fire barrier magic switch": "Chest", "Secret Passage - Second fire barrier magic switch": "Barrier", - "Secret Passage - 38. Dark Elf's Ear Sample from pot at magic barrier": "Lore", } secret_passage_before_enraged_armor_locations: Dict[str, str] = { @@ -127,7 +133,7 @@ def __init__(self, player: int, name="", code=None, parent=None): } underground_tania_locations: Dict[str, str] = { - "Underground - Defeat tania": "Bosses", + "Underground - Tania": "Bosses", "Underground - Tania boss arena barrier": "Barrier", "Underground - Tania shortcut switch on Tania side": "Metal Gate", "Underground - 98. Lost Maiden's Soul Shard from Tania": "Lore", @@ -422,7 +428,9 @@ def __init__(self, player: int, name="", code=None, parent=None): **shrine_armor_hall_locations, **shrine_underground_shortcut_locations, **secret_passage_start_locations, + **secret_passage_first_fire_barrier_switch_room_locations, **secret_passage_after_first_fire_barrier_locations, + **secret_passage_after_secret_passage_gate_locations, **secret_passage_before_enraged_armor_locations, **secret_passage_enraged_armor_locations, **secret_passage_boss_shortcut_locations, @@ -487,7 +495,7 @@ def __init__(self, player: int, name="", code=None, parent=None): "Secret Passage - Enraged Armor", "Shrine - Specter Armor", "Spirit Realm - Vanessa V2", - "Underground - Defeat tania", + "Underground - Tania", }, "Lore": { "Abyss - 102. Lost Maiden's Crafted Soul Shard from Nonota", @@ -776,12 +784,24 @@ def append_locations(world: "LWNWorld"): region = world.multiworld.get_region("Secret passage - Start", world.player) add_location_to_region(location_name, location_id, group_name, region, world) + for location_name in secret_passage_first_fire_barrier_switch_room_locations: + location_id = location_name_to_id[location_name] + group_name = secret_passage_first_fire_barrier_switch_room_locations[location_name] + region = world.multiworld.get_region("Secret passage - First fire barrier switch room", world.player) + add_location_to_region(location_name, location_id, group_name, region, world) + for location_name in secret_passage_after_first_fire_barrier_locations: location_id = location_name_to_id[location_name] group_name = secret_passage_after_first_fire_barrier_locations[location_name] region = world.multiworld.get_region("Secret passage - After first fire barrier", world.player) add_location_to_region(location_name, location_id, group_name, region, world) + for location_name in secret_passage_after_secret_passage_gate_locations: + location_id = location_name_to_id[location_name] + group_name = secret_passage_after_secret_passage_gate_locations[location_name] + region = world.multiworld.get_region("Secret passage - After secret passage gate", world.player) + add_location_to_region(location_name, location_id, group_name, region, world) + for location_name in secret_passage_before_enraged_armor_locations: location_id = location_name_to_id[location_name] group_name = secret_passage_before_enraged_armor_locations[location_name] diff --git a/worlds/little_witch_nobeta/regions.py b/worlds/little_witch_nobeta/regions.py index ee60c05a7279..172792c73a16 100644 --- a/worlds/little_witch_nobeta/regions.py +++ b/worlds/little_witch_nobeta/regions.py @@ -15,8 +15,10 @@ class LWNRegion(Region): "Shrine - Cat Room": {"Shrine - After first magic switch", "Shrine - Armor Hall"}, "Shrine - Armor Hall": {"Secret passage - Start", "Secret passage - After first fire barrier", "Secret Passage - Boss Shortcut", "Shrine - Underground shortcut", "Shrine - Cat Room", "Underground - Start"}, "Shrine - Underground shortcut": {"Shrine - Armor Hall", "Underground - Shrine shortcut"}, - "Secret passage - Start": {"Shrine - Armor Hall", "Secret passage - After first fire barrier"}, - "Secret passage - After first fire barrier": {"Secret passage - Start", "Secret Passage - Dark Tunnel shortcut", "Shrine - Armor Hall", "Secret Passage - Before Enraged Armor"}, + "Secret passage - Start": {"Secret passage - First fire barrier switch room"}, + "Secret passage - First fire barrier switch room": {"Secret passage - After first fire barrier"}, + "Secret passage - After first fire barrier": {"Secret passage - First fire barrier switch room", "Secret passage - After secret passage gate", "Secret Passage - Before Enraged Armor"}, + "Secret passage - After secret passage gate": {"Secret passage - After first fire barrier", "Secret Passage - Dark Tunnel shortcut", "Shrine - Armor Hall"}, "Secret Passage - Before Enraged Armor": {"Secret passage - After first fire barrier", "Secret Passage - Enraged Armor"}, "Secret Passage - Enraged Armor": {"Secret Passage - Boss Shortcut", "Secret Passage - Before Enraged Armor"}, "Secret Passage - Boss Shortcut": {"Shrine - Armor Hall", "Secret Passage - Enraged Armor"}, diff --git a/worlds/little_witch_nobeta/rules.py b/worlds/little_witch_nobeta/rules.py index 2f860436dfa2..07a2c0677f55 100644 --- a/worlds/little_witch_nobeta/rules.py +++ b/worlds/little_witch_nobeta/rules.py @@ -80,7 +80,9 @@ def set_region_rules(world: "LWNWorld") -> None: world.set_rule(multiworld.get_entrance("Shrine - After first magic switch -> Shrine - Start", player), has_barrier("Shrine First Magic Barrier")) world.set_rule(multiworld.get_entrance("Shrine - Cat Room -> Shrine - After first magic switch", player), - has_barrier("Shrine Second Magic Barrier")) + (has_barrier("Shrine Second Magic Barrier") + & (has_barrier("Shrine Meet Cat Magic Barrier") + | barrier_vanilla))) world.set_rule(multiworld.get_entrance("Shrine - Cat Room -> Shrine - Armor Hall", player), (has_barrier("Shrine Meet Cat Magic Barrier") | barrier_vanilla)) @@ -95,7 +97,7 @@ def set_region_rules(world: "LWNWorld") -> None: world.set_rule(multiworld.get_entrance("Shrine - Armor Hall -> Shrine - Underground shortcut", player), has_gate("Shrine Underground Shortcut Gate")) world.set_rule(multiworld.get_entrance("Shrine - Armor Hall -> Shrine - Cat Room", player), - has_barrier("Shrine Meet Cat Magic Barrier")) + True_()) world.set_rule(multiworld.get_entrance("Shrine - Armor Hall -> Underground - Start", player), (skip_boss_enabled | ((boss_souls_vanilla @@ -112,23 +114,27 @@ def set_region_rules(world: "LWNWorld") -> None: | gate_vanilla)) world.set_rule(multiworld.get_entrance("Shrine - Underground shortcut -> Underground - Shrine shortcut", player), True_()) - world.set_rule(multiworld.get_entrance("Secret passage - Start -> Shrine - Armor Hall", player), - has_barrier("Secret Passage Entrance Magic Barrier")) - world.set_rule(multiworld.get_entrance("Secret passage - Start -> Secret passage - After first fire barrier", player), + world.set_rule(multiworld.get_entrance("Secret passage - Start -> Secret passage - First fire barrier switch room", player), + True_()) + world.set_rule(multiworld.get_entrance("Secret passage - First fire barrier switch room -> Secret passage - After first fire barrier", player), (has_barrier("Secret Passage First Fire Barrier") | (has_fire_or_thunder & barrier_vanilla))) - world.set_rule(multiworld.get_entrance("Secret passage - After first fire barrier -> Secret passage - Start", player), + world.set_rule(multiworld.get_entrance("Secret passage - After first fire barrier -> Secret passage - First fire barrier switch room", player), has_barrier("Secret Passage First Fire Barrier")) - world.set_rule(multiworld.get_entrance("Secret passage - After first fire barrier -> Secret Passage - Dark Tunnel shortcut", player), - has_gate("Secret Passage Dark Tunnel Shortcut Gate")) - world.set_rule(multiworld.get_entrance("Secret passage - After first fire barrier -> Shrine - Armor Hall", player), - (has_gate("Shrine Secret Area Shortcut Gate") - | gate_vanilla)) + world.set_rule(multiworld.get_entrance("Secret passage - After first fire barrier -> Secret passage - After secret passage gate", player), + True_()) world.set_rule(multiworld.get_entrance("Secret passage - After first fire barrier -> Secret Passage - Before Enraged Armor", player), (has_barrier("Secret Passage Second Fire Barrier") | (has_fire_or_thunder & barrier_vanilla))) + world.set_rule(multiworld.get_entrance("Secret passage - After secret passage gate -> Secret passage - After first fire barrier", player), + has_fire_or_thunder) + world.set_rule(multiworld.get_entrance("Secret passage - After secret passage gate -> Secret Passage - Dark Tunnel shortcut", player), + has_gate("Secret Passage Dark Tunnel Shortcut Gate")) + world.set_rule(multiworld.get_entrance("Secret passage - After secret passage gate -> Shrine - Armor Hall", player), + (has_gate("Shrine Secret Area Shortcut Gate") + | gate_vanilla)) world.set_rule(multiworld.get_entrance("Secret Passage - Before Enraged Armor -> Secret passage - After first fire barrier", player), (has_barrier("Secret Passage Second Fire Barrier") | (has_fire_or_thunder @@ -264,14 +270,14 @@ def set_region_rules(world: "LWNWorld") -> None: True_()) world.set_rule(multiworld.get_entrance("Lava Ruins - Scissor Enemy Room -> Lava Ruins - After magic platforms", player), (has_barrier("Lava Ruins Scissor Enemy Lift") - | (barrier_vanilla - & Has("Arcane")))) + | barrier_vanilla)) world.set_rule(multiworld.get_entrance("Lava Ruins - Scissor Enemy Room -> Lava Ruins - After scissor enemy barrier", player), (has_barrier("Lava Ruins Scissor Enemy Barrier") | barrier_vanilla)) world.set_rule(multiworld.get_entrance("Lava Ruins - Scissor Enemy Room -> Lava Ruins - Lift Magic Switch Room", player), (has_barrier("Lava Ruins Scissor Enemy Barrier") - | barrier_vanilla)) + | barrier_vanilla + | HasAny("Arcane", "Thunder"))) world.set_rule(multiworld.get_entrance("Lava Ruins - Scissor Enemy Room -> Lava Ruins - Scissor Enemy Battle", player), True_()) world.set_rule(multiworld.get_entrance("Lava Ruins - After scissor enemy barrier -> Lava Ruins - After Fire Barrier", player), @@ -342,10 +348,8 @@ def set_region_rules(world: "LWNWorld") -> None: world.set_rule(multiworld.get_entrance("Dark Tunnel - Start -> Lava Ruins - Path to dark tunnel", player), True_()) world.set_rule(multiworld.get_entrance("Dark Tunnel - Start -> Dark Tunnel - After first gate", player), - (has_gate("Dark Tunnel First Gate") - | gate_vanilla - | (Has("Wind") - & [OptionFilter(SkipsInLogic, "Dark Tunnel Hat Skip", "contains")]))) + (Has("Wind") + & [OptionFilter(SkipsInLogic, "Dark Tunnel Hat Skip", "contains")])) world.set_rule(multiworld.get_entrance("Dark Tunnel - After first magic barrier -> Dark Tunnel - Start", player), has_barrier("Dark Tunnel First Magic Barrier")) world.set_rule(multiworld.get_entrance("Dark Tunnel - After first magic barrier -> Dark Tunnel - After first gate", player), @@ -622,7 +626,7 @@ def set_location_rules(world: "LWNWorld") -> None: if options.barrier_behaviour.value == options.barrier_behaviour.option_randomized: world.set_rule(multiworld.get_location("Underground - After fire magic switch", player), Has("Ice")) - world.set_rule(multiworld.get_location("Underground - Defeat tania", player), + world.set_rule(multiworld.get_location("Underground - Tania", player), (boss_souls_vanilla | Has("Tania Soul")) & (boss_req_none @@ -672,7 +676,9 @@ def set_location_rules(world: "LWNWorld") -> None: world.set_rule(multiworld.get_location("Lava Ruins - Fire magic switch", player), has_fire_or_thunder) world.set_rule(multiworld.get_location("Lava Ruins - Jumping puzzle arcane chest at moving ring gauntlet", player), - Has("Wind")) + (has_barrier("Lava Ruins Moving Ring") + | barrier_vanilla) + & Has("Wind")) world.set_rule(multiworld.get_location("Lava Ruins - Monica", player), (boss_souls_vanilla | Has("Monica Soul")) From 69da3ad69fa55f96165699dbbf2ef858e72aaa30 Mon Sep 17 00:00:00 2001 From: espaspw Date: Tue, 4 Aug 2026 01:34:56 -0700 Subject: [PATCH 3/3] Add support for condensed magic and max magic level options - Condensed magic turns all magic of one type (like Fire) up to max level into a single item - Max level added to determine highest magic level of every magic type, to add flexibility in difficulty Magic master goals now only expect up the set max magic level - BossRequirementsDifficulty reworked for "easy" option to determine unique types of magic rather than total number of magic upgrade to make it work with condensed magic and max level options - This commit includes the change from NobetaLogic --- worlds/little_witch_nobeta/__init__.py | 14 +++-- worlds/little_witch_nobeta/options.py | 26 ++++++++- worlds/little_witch_nobeta/rules.py | 76 +++++++++++++++----------- 3 files changed, 75 insertions(+), 41 deletions(-) diff --git a/worlds/little_witch_nobeta/__init__.py b/worlds/little_witch_nobeta/__init__.py index 88eb8a8f7cdf..457b5859b47d 100644 --- a/worlds/little_witch_nobeta/__init__.py +++ b/worlds/little_witch_nobeta/__init__.py @@ -173,12 +173,14 @@ def create_items(self): else: self.multiworld.push_precollected(wind_spell) - # Generate 4 extra of all progressive and useful items - for item in magic_items.keys(): - for _ in range(4): - lwn_item = self.create_item(item) - item_pool.append(lwn_item) - + # Generate duplicate magic items up to max magic level + if self.options.condensed_magic == Toggle.option_false: + for item in magic_items.keys(): + for _ in range(self.options.max_magic_level.value - 1): + lwn_item = self.create_item(item) + item_pool.append(lwn_item) + + # Generate 4 extra of all useful items for item in useful_items.keys(): for _ in range(4): lwn_item = self.create_item(item) diff --git a/worlds/little_witch_nobeta/options.py b/worlds/little_witch_nobeta/options.py index 9d631049ea62..c8083bdd0695 100644 --- a/worlds/little_witch_nobeta/options.py +++ b/worlds/little_witch_nobeta/options.py @@ -9,7 +9,7 @@ class Goal(Choice): """ The Goal of the game. [Vanilla] Reaching and beating Nonota will end the game. - [Magic Master] All attack magics (arcane, ice, fire and thunder) must be level 5 before Nonota can be reached. + [Magic Master] All attack magics (arcane, ice, fire and thunder) must be at the max set level before Nonota can be reached. [Boss Hunt] All boss tokens gained by defeating bosses need to be collected before Nonota can be reached. [Lore Keeper] All lore items must be collected before Nonota can be reached. """ @@ -26,7 +26,7 @@ class AbyssTrialRequirement(Choice): Requirement to open the final teleport in Abyss to reach Nonota. [Vanilla] The three switches at the end of each trial must be destroyed. [Randomized Item] Requires three trial clear items, which are placed in the item pool. - [Magic Master] All attack magics (arcane, ice, fire and thunder) must be level 5. + [Magic Master] All attack magics (arcane, ice, fire and thunder) must be at the max set level. [Boss Hunt] All boss tokens gained by defeating bosses need to be collected. [Lore Keeper] All lore items must be collected. """ @@ -228,6 +228,24 @@ class WindRequirements(Choice): default = option_start_without +class CondensedMagic(DefaultOffToggle): + """ + Turns each magic type into a single item which grants up to the max magic level. + If start with arcane or absorption is enabled, those will also start at max level. + This is for players who prefer checks with higher stakes. + """ + display_name = "Condensed Magic" + +class MaxMagicLevel(Range): + """ + The maximum level for each magic type. A lower number means less magic items in the pool and a less powerful Nobeta. + Magic Master goals will only require up to this max level, and condensed magic will grant up to this level as well. + """ + display_name = "Max Magic Level" + range_start = 1 + range_end = 5 + default = 5 + class SkipsInLogic(OptionSet): """ List of in-bound and glitchless skips to be considered in logic. @@ -374,6 +392,7 @@ class DeathLink(DefaultOffToggle): ]), OptionGroup("Logic Options", [ WindRequirements, + CondensedMagic, RandomizeBossSouls, RandomizeBossTokens, SkippableBosses, @@ -395,6 +414,7 @@ class DeathLink(DefaultOffToggle): ]), OptionGroup("Difficulty Options", [ BossRequirementsDifficulty, + MaxMagicLevel, NoArcane, NoManaRegeneration, StartWithAbsorption, @@ -433,6 +453,8 @@ class LWNOptions(PerGameCommonOptions): randomize_crystal_balls: RandomizeCrystalBalls randomize_crystals: RandomizeCrystals wind_requirements: WindRequirements + condensed_magic: CondensedMagic + max_magic_level: MaxMagicLevel skips_in_logic: SkipsInLogic entrance_randomization: EntranceRandomization starting_area: StartingArea diff --git a/worlds/little_witch_nobeta/rules.py b/worlds/little_witch_nobeta/rules.py index 07a2c0677f55..0344f00985f2 100644 --- a/worlds/little_witch_nobeta/rules.py +++ b/worlds/little_witch_nobeta/rules.py @@ -5,6 +5,8 @@ MagicPuzzleGateBehaviour, ShortcutGateBehaviour, WindRequirements, + CondensedMagic, + MaxMagicLevel, TrialKeys, Goal, AbyssTrialRequirement, @@ -18,6 +20,7 @@ ) from rule_builder.rules import Has, HasAny, HasAll, HasAllCounts, HasGroup, HasGroupUnique, CanReachRegion, True_ from rule_builder.options import OptionFilter +from rule_builder.field_resolvers import FromOption if TYPE_CHECKING: from . import LWNWorld @@ -26,7 +29,14 @@ has_fire_or_thunder = HasAny("Fire", "Thunder") has_wind_or_skip = Has("Wind") | [OptionFilter(WindRequirements, WindRequirements.option_less_wind_requirements)] has_wind_or_damage_boost = Has("Wind") | (Has("Fire") & [OptionFilter(WindRequirements, WindRequirements.option_less_wind_requirements)]) -has_goal_requirements = ((HasAllCounts({"Arcane": 5, "Fire": 5, "Thunder": 5, "Ice": 5}) +has_magic_master_requirements = (HasAllCounts({"Arcane": 1, "Fire": 1, "Thunder": 1, "Ice": 1}) + & [OptionFilter(CondensedMagic, CondensedMagic.option_true)] + | (Has("Arcane", count = FromOption(MaxMagicLevel)) + & Has("Fire", count = FromOption(MaxMagicLevel)) + & Has("Thunder", count = FromOption(MaxMagicLevel)) + & Has("Ice", count = FromOption(MaxMagicLevel))) + & [OptionFilter(CondensedMagic, CondensedMagic.option_false)]) +has_goal_requirements = ((has_magic_master_requirements & [OptionFilter(Goal, Goal.option_magic_master)]) | (HasAll("Specter Armor Token", "Tania Token", "Monica Token", "Enraged Armor Token", "Vanessa Token", "Vanessa V2 Token") & [OptionFilter(Goal, Goal.option_boss_hunt)]) @@ -34,7 +44,7 @@ | (HasGroupUnique("Lore", 102) & [OptionFilter(Goal, Goal.option_lore_keeper), OptionFilter(RandomizeLore, RandomizeLore.option_vanilla)]) | (HasGroupUnique("Lore", 103) & [OptionFilter(Goal, Goal.option_lore_keeper), OptionFilter(RandomizeLore, RandomizeLore.option_randomized)]) | [OptionFilter(Goal, Goal.option_vanilla)]) -has_abyss_trial_requirements = ((HasAllCounts({"Arcane": 5, "Fire": 5, "Thunder": 5, "Ice": 5}) +has_abyss_trial_requirements = ((has_magic_master_requirements & [OptionFilter(AbyssTrialRequirement, AbyssTrialRequirement.option_magic_master)]) | (HasAll("Specter Armor Token", "Tania Token", "Monica Token", "Enraged Armor Token", "Vanessa Token", "Vanessa V2 Token") & [OptionFilter(AbyssTrialRequirement, AbyssTrialRequirement.option_boss_hunt)]) @@ -150,7 +160,7 @@ def set_region_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 5) + & HasGroupUnique("Attack Magics", 3) & Has("Mana Absorption"))) & barrier_vanilla))) world.set_rule(multiworld.get_entrance("Secret Passage - Enraged Armor -> Secret Passage - Before Enraged Armor", player), @@ -164,7 +174,7 @@ def set_region_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 5) + & HasGroupUnique("Attack Magics", 3) & Has("Mana Absorption")))))) world.set_rule(multiworld.get_entrance("Secret Passage - Boss Shortcut -> Shrine - Armor Hall", player), (has_gate("Shrine Secret Boss Shortcut Gate") @@ -248,7 +258,7 @@ def set_region_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 3) + & HasGroupUnique("Attack Magics", 2) & Has("Mana Absorption"))))))) world.set_rule(multiworld.get_entrance("Lava Ruins - Start -> Lava Ruins - After magic platforms", player), (has_barrier("Lava Ruins Magic Platforms") @@ -325,7 +335,7 @@ def set_region_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 4) + & HasGroupUnique("Attack Magics", 2) & Has("Mana Absorption"))))) world.set_rule(multiworld.get_entrance("Lava Ruins - Monica warp -> Lava Ruins - Path to dark tunnel", player), (has_gate("Lava Ruins Monica Warp Gate") @@ -408,7 +418,7 @@ def set_region_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 5) + & HasGroupUnique("Attack Magics", 2) & Has("Mana Absorption")))))) world.set_rule(multiworld.get_entrance("Dark Tunnel - After bridge collapse -> Secret Passage - Dark Tunnel shortcut", player), True_()) @@ -442,7 +452,7 @@ def set_region_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 5) + & HasGroupUnique("Attack Magics", 3) & Has("Mana Absorption"))) & barrier_vanilla))) world.set_rule(multiworld.get_entrance("Spirit Realm - After first Seal -> Spirit Realm - Seal", player), @@ -458,7 +468,7 @@ def set_region_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 5) + & HasGroupUnique("Attack Magics", 3) & Has("Mana Absorption"))) & barrier_vanilla))) world.set_rule(multiworld.get_entrance("Spirit Realm - After second Seal -> Spirit Realm - After first Seal", player), @@ -491,7 +501,7 @@ def set_region_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 5) + & HasGroupUnique("Attack Magics", 3) & Has("Mana Absorption")))))) world.set_rule(multiworld.get_entrance("Abyss -> Abyss - After first teleport", player), True_()) @@ -578,7 +588,7 @@ def set_location_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 5) + & HasGroupUnique("Attack Magics", 3) & Has("Mana Absorption")))) if world.options.randomize_lore.value != world.options.randomize_lore.option_no_lore: world.set_rule(multiworld.get_location("Secret Passage - 56. Knight Kingdom Crown from Enraged Armor", player), @@ -591,7 +601,7 @@ def set_location_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 5) + & HasGroupUnique("Attack Magics", 3) & Has("Mana Absorption")))) world.set_rule(multiworld.get_location("Secret Passage - Teleport from Enraged Armor", player), (boss_souls_vanilla @@ -603,7 +613,7 @@ def set_location_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 5) + & HasGroupUnique("Attack Magics", 3) & Has("Mana Absorption")))) if options.barrier_behaviour.value == options.barrier_behaviour.option_randomized: world.set_rule(multiworld.get_location("Secret Passage - Defeat Enraged Armor barrier", player), @@ -616,7 +626,7 @@ def set_location_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 5) + & HasGroupUnique("Attack Magics", 3) & Has("Mana Absorption")))) world.set_rule(multiworld.get_location("Underground - Arcane chest at bridge jumping puzzle", player), has_wind_or_skip) @@ -636,7 +646,7 @@ def set_location_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 3) + & HasGroupUnique("Attack Magics", 2) & Has("Mana Absorption")))) if options.barrier_behaviour.value == options.barrier_behaviour.option_randomized: world.set_rule(multiworld.get_location("Underground - Tania boss arena barrier", player), @@ -649,7 +659,7 @@ def set_location_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 3) + & HasGroupUnique("Attack Magics", 2) & Has("Mana Absorption")))) if world.options.randomize_lore.value != world.options.randomize_lore.option_no_lore: world.set_rule(multiworld.get_location("Underground - 98. Lost Maiden's Soul Shard from Tania", player), @@ -662,7 +672,7 @@ def set_location_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 3) + & HasGroupUnique("Attack Magics", 2) & Has("Mana Absorption")))) world.set_rule(multiworld.get_location("Lava Ruins - Chest on scaffolding", player), has_wind_or_damage_boost) @@ -689,7 +699,7 @@ def set_location_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 4) + & HasGroupUnique("Attack Magics", 2) & Has("Mana Absorption")))) if options.barrier_behaviour.value == options.barrier_behaviour.option_randomized: world.set_rule(multiworld.get_location("Lava Ruins - Monica boss arena barrier", player), @@ -702,7 +712,7 @@ def set_location_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 4) + & HasGroupUnique("Attack Magics", 2) & Has("Mana Absorption")))) if world.options.randomize_lore.value != world.options.randomize_lore.option_no_lore: world.set_rule(multiworld.get_location("Lava Ruins - 34. Bestian Ear from Monica", player), @@ -715,7 +725,7 @@ def set_location_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 4) + & HasGroupUnique("Attack Magics", 2) & Has("Mana Absorption")))) if world.options.randomize_lore.value != world.options.randomize_lore.option_no_lore: world.set_rule(multiworld.get_location("Lava Ruins - 33. Bestian Palm from Monica", player), @@ -728,7 +738,7 @@ def set_location_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 4) + & HasGroupUnique("Attack Magics", 2) & Has("Mana Absorption")))) if world.options.randomize_lore.value != world.options.randomize_lore.option_no_lore: world.set_rule(multiworld.get_location("Lava Ruins - 99. Child's Soul Shard from Monica", player), @@ -741,7 +751,7 @@ def set_location_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 4) + & HasGroupUnique("Attack Magics", 2) & Has("Mana Absorption")))) if world.options.randomize_lore.value != world.options.randomize_lore.option_no_lore: world.set_rule(multiworld.get_location("Dark Tunnel - 39. Dark Elf's Short Bow from barrel on scaffolding", player), @@ -778,7 +788,7 @@ def set_location_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 5) + & HasGroupUnique("Attack Magics", 2) & Has("Mana Absorption")))) if world.options.randomize_lore.value != world.options.randomize_lore.option_no_lore: world.set_rule(multiworld.get_location("Dark Tunnel - 100. King's Final Honor from Vanessa", player), @@ -791,7 +801,7 @@ def set_location_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 5) + & HasGroupUnique("Attack Magics", 2) & Has("Mana Absorption")))) if world.options.randomize_lore.value != world.options.randomize_lore.option_no_lore: world.set_rule(multiworld.get_location("Dark Tunnel - 78. Ancient Throne Rune from Vanessa", player), @@ -804,7 +814,7 @@ def set_location_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 5) + & HasGroupUnique("Attack Magics", 2) & Has("Mana Absorption")))) if world.options.randomize_lore.value != world.options.randomize_lore.option_no_lore: world.set_rule(multiworld.get_location("Dark Tunnel - 77. The Throne from Vanessa", player), @@ -817,7 +827,7 @@ def set_location_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 5) + & HasGroupUnique("Attack Magics", 2) & Has("Mana Absorption")))) world.set_rule(multiworld.get_location("Spirit Realm - Ice spell chest in right side alcove", player), Has("Wind")) @@ -839,7 +849,7 @@ def set_location_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 5) + & HasGroupUnique("Attack Magics", 3) & Has("Mana Absorption"))) if options.barrier_behaviour.value == options.barrier_behaviour.option_randomized: world.set_rule(multiworld.get_location("Spirit Realm - Second Seal magic barrier", player), @@ -850,7 +860,7 @@ def set_location_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 5) + & HasGroupUnique("Attack Magics", 3) & Has("Mana Absorption"))) if options.barrier_behaviour.value == options.barrier_behaviour.option_randomized: world.set_rule(multiworld.get_location("Spirit Realm - Elevator magic switch", player), @@ -890,7 +900,7 @@ def set_location_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 5) + & HasGroupUnique("Attack Magics", 3) & Has("Mana Absorption")))) if world.options.randomize_lore.value != world.options.randomize_lore.option_no_lore: world.set_rule(multiworld.get_location("Spirit Realm - 101. Proud King's Crafted Soul Shard from Vanessa V2", player), @@ -903,7 +913,7 @@ def set_location_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 5) + & HasGroupUnique("Attack Magics", 3) & Has("Mana Absorption")))) world.set_rule(multiworld.get_location("Spirit Realm - Thunder spell from Vanessa V2", player), (boss_souls_vanilla @@ -915,7 +925,7 @@ def set_location_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 5) + & HasGroupUnique("Attack Magics", 3) & Has("Mana Absorption")))) if world.options.randomize_lore.value != world.options.randomize_lore.option_no_lore: world.set_rule(multiworld.get_location("Abyss - 83. Castle Blueprint from crystal on brittle ledge", player), @@ -980,7 +990,7 @@ def set_location_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 7) + & HasGroupUnique("Attack Magics", 4) & Has("Mana Absorption")))) world.set_rule(multiworld.get_location("Abyss - Nonota", player), has_goal_requirements @@ -991,5 +1001,5 @@ def set_location_rules(world: "LWNWorld") -> None: & HasGroup("Attack Magics") & Has("Mana Absorption")) | (boss_req_easy - & HasGroup("Attack Magics", 7) + & HasGroupUnique("Attack Magics", 4) & Has("Mana Absorption"))))