diff --git a/logic/dungeon7.py b/logic/dungeon7.py index 5fc05c14..d21ce6aa 100644 --- a/logic/dungeon7.py +++ b/logic/dungeon7.py @@ -100,7 +100,7 @@ def __init__(self, options, world_setup, r): # floor 2 north after_a_stairs.connect(ball_access, POWER_BRACELET, back=False) after_a_stairs.connect(ne_pillar, POWER_BRACELET, back=None) # intended method is to pull lever - after_a_stairs.connect(pegs_before_ball, "SWITCH7B_RANGE", back=False) + after_a_stairs.connect(pegs_before_ball, OR("SWITCH7A", "SWITCH7B_RANGE"), back=False) # SWITCH7A here might eventually cause trouble with stairs shuffle? after_b_stairs.connect(ne_pillar, "SWITCH7A", back=OR("SWITCH7B_RANGE", "SWITCH7C")) ne_pillar.connect(ne_pillar_chest5, POWER_BRACELET, back=False) ne_pillar.connect(ne_pillar_fall, "D7_BALL", back=False) @@ -120,7 +120,8 @@ def __init__(self, options, world_setup, r): after_d_stairs.connect(tile_room, back=False) after_d_stairs.connect(after_d_stairs_drop2, r.miniboss_requirements["HINOX"], back=False) after_d_stairs.connect(sw_pillar_toak_clear, r.enemy_requirements["THREE_OF_A_KIND"], back=False) #NOTE: add bracelet method if rom patched - after_d_stairs.connect((se_pillar_switch_midrange, se_pillar_switch_range), OR(BOOMERANG, BOW, BOMB, MAGIC_ROD), back=False) + after_d_stairs.connect(se_pillar_switch_midrange, OR(BOOMERANG, BOW, BOMB, MAGIC_ROD), back=False) + after_d_stairs.connect(se_pillar_switch_range, OR(BOOMERANG, BOW, BOMB), back=False) # hit switch and get on pegs by east exit after_d_stairs.connect(pegs_before_ball, "SWITCH7C_RANGE", back=None) after_d_stairs.connect(keylock_ledge, FOUND(KEY7, 3)) keylock_ledge.connect((se_pillar, pegs_before_ball, after_d_stairs), back=False) @@ -172,7 +173,7 @@ def __init__(self, options, world_setup, r): after_c_stairs.connect(after_c_stairs_chest2, BOMB, back=False) after_c_stairs.connect(spike_corridor, r.damage_boost) # forced damage so this cannot be in normal logic after_d_stairs.connect(se_pillar_switch_midrange, AND(FEATHER, SWORD), back=False) # jump and swing sword from below rail NOTE: add bracelet method if rom patched - after_d_stairs.connect(se_pillar_switch_range, OR(BOOMERANG, BOW, BOMB, MAGIC_ROD), back=False) # hit switch and get on pegs by east exit + after_d_stairs.connect(se_pillar_switch_range, MAGIC_ROD, back=False) # hit switch and get on pegs by east exit after_d_stairs.connect(sw_pillar_toak_clear, "D7_BALL", back=False) # throw the ball to solve three-of-a-kind and spawn the chest for location in (after_d_stairs, bombwall_pit, sw_pillar): location.connect(sw_pillar_toak_clear, BOMB, back=False) # push a block if needed and solve the three-of-a-kind puzzle with bombs diff --git a/logic/overworld.py b/logic/overworld.py index 89d65560..35374add 100644 --- a/logic/overworld.py +++ b/logic/overworld.py @@ -13,7 +13,8 @@ def __init__(self, options, world_setup, r): Location().add(FishingMinigame()).connect(mabe_village, AND(r.bush, FOUND("RUPEES", 50))) # fishing game, heart piece is directly done by the minigame. Location().add(Seashell(0x0A3)).connect(mabe_village, r.bush) # bushes below the shop Location().add(Seashell(0x0D2)).connect(mabe_village, PEGASUS_BOOTS) # smash into tree next to lv1 - Location().add(Song(0x092)).connect(mabe_village, OCARINA) # Marins song + marin_song = Location().add(Song(0x092)) + mabe_village.connect(marin_song, OCARINA, back=False) Location().add(KeyHole(0x0D3, TAIL_CAVE_OPENED)).connect(mabe_village, TAIL_KEY) # Marins song rooster_cave = Location("Rooster Cave") Location().add(DroppedKey(0x1E4)).connect(rooster_cave, AND(OCARINA, SONG3)) @@ -286,6 +287,7 @@ def __init__(self, options, world_setup, r): animal_village = Location("Animal Village") animal_village.connect(Location().add(TradeSequenceItem(0x0CD, TRADING_ITEM_FISHING_HOOK)), TRADING_ITEM_BROOM) + animal_village.connect(marin_song, OCARINA, back=False) cookhouse = Location("Bear Chef's House") cookhouse.connect(Location().add(TradeSequenceItem(0x2D7, TRADING_ITEM_PINEAPPLE)), TRADING_ITEM_HONEYCOMB) goathouse = Location("Goat's House") @@ -629,6 +631,8 @@ def __init__(self, options, world_setup, r): self._addEntranceRequirement("castle_jump_cave", r.pit_buffer_boots) # pit buffer to clip bottom wall and boots bonk across prairie_cave_secret_exit.connect(prairie_cave, AND(BOMB, OR(r.boots_bonk_pit, r.hookshot_spam_pit))) # hookshot spam or boots bonk across pits can go from left to right by pit buffering on top of the bottom wall then boots bonk across richard_cave_chest.connect(richard_cave, r.damage_boost) # use the zol on the other side of the pit to damage boost across (requires damage from pit + zol) + richard_cave_chest.connect(richard_cave, r.boots_bonk) # bonk over the pit instead of damage boosting + ukuku_prairie.connect(dungeon3_entrance, AND(r.jesus_buffer, r.jesus_buffer_hookshot), back=False) # boots bonk from the right into a jesus buffer down to the bottom wall, then bonk all the way across. Hookshot is needed to restart the buffer after transitions castle_secret_entrance_right.connect(castle_secret_entrance_left, OR(r.boots_bonk_2d_spikepit, r.bracelet_bounce_2d_spikepit, r.toadstool_bounce_2d_spikepit)) # use bracelet or toadstool to damage boost off of spikes and get through passageway. Also need to hold A button when bouncing off spikes or goombas left_bay_area.connect(ghost_hut_outside, r.pit_buffer_boots) # multiple pit buffers to bonk across the bottom wall left_bay_area.connect(ukuku_prairie, r.hookshot_clip_block, back=False) # clip through the donuts blocking the path next to prairie plateau cave by hookshotting up and killing the two moblins that way which clips you further up two times. This is enough to move right diff --git a/logic/requirements.py b/logic/requirements.py index 3cf844c3..1874fbe0 100644 --- a/logic/requirements.py +++ b/logic/requirements.py @@ -26,6 +26,16 @@ def __repr__(self) -> str: def remove(self, item) -> None: if item in self.__items: self.__items.remove(item) + elif item in self.__children: + self.__children.remove(item) + + def add(self, item) -> None: + if isinstance(item, str): + if item not in self.__items: + self.__items.append(item) + else: + if item not in self.__children: + self.__children.append(item) def test(self, inventory) -> bool: for item in self.__items: @@ -70,6 +80,16 @@ def __repr__(self) -> str: def remove(self, item) -> None: if item in self.__items: self.__items.remove(item) + elif item in self.__children: + self.__children.remove(item) + + def add(self, item) -> None: + if isinstance(item, str): + if item not in self.__items: + self.__items.append(item) + else: + if item not in self.__children: + self.__children.append(item) def test(self, inventory) -> bool: for item in self.__items: @@ -374,11 +394,17 @@ def __init__(self, options): if options.hardmode == "ohko": self.miniboss_requirements["ROLLING_BONES"] = OR(BOW, MAGIC_ROD, BOOMERANG, AND(FEATHER, self.attack_hookshot)) # should not deal with roller damage if options.bowwow != "normal": - # We cheat in bowwow mode, we pretend we have the sword, as bowwow can pretty much do all what the sword ca$ # Except for taking out bushes (and crystal pillars are removed) + # We cheat in bowwow mode, we pretend we have the sword, as bowwow can pretty much do all what the sword can + # Except for taking out bushes (and crystal pillars are removed) self.bush.remove(SWORD) self.pit_bush.remove(SWORD) self.hit_switch.remove(SWORD) self.hit_switch_color.remove(SWORD) + # 2 swords means we picked up a real one + self.bush.add(COUNT(SWORD, 2)) + self.pit_bush.add(COUNT(SWORD, 2)) + self.hit_switch.add(COUNT(SWORD, 2)) + self.hit_switch_color.add(COUNT(SWORD, 2)) if options.logic == "casual": # In casual mode, remove the more complex kill methods self.bush.remove(MAGIC_POWDER)