Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make sure we can actually reach clips in HMG #165

Open
wants to merge 5 commits into
base: DoorDevUnstable
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions Fill.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,37 @@ def fill(base_state, items, key_pool):
fill_restrictive(world, base_state, shuffled_locations, items, key_pool, True)

all_state_base = world.get_all_state()
for player in range(1, world.players + 1):
if world.logic[player] == 'hybridglitches' and world.keyshuffle[i.player] in ['none', 'nearby'] \
and world.pottery[player] not in ['none', 'cave']:
# remove 2 keys from main pool
count_to_remove = 2
to_remove = []
for wix, wi in enumerate(smalls):
if wi.name == 'Small Key (Swamp Palace)' and wi.player == player:
to_remove.append(wix)
if count_to_remove == len(to_remove):
break
for wix in reversed(to_remove):
del smalls[wix]
# remove 2 swamp locations from pool
hybrid_locations = []
to_remove = []
for i, loc in enumerate(shuffled_locations):
if loc.name in ['Swamp Palace - Trench 1 Pot Key', 'Swamp Palace - Pot Row Pot Key'] and loc.player == player:
to_remove.append(i)
hybrid_locations.append(loc)
if count_to_remove == len(to_remove):
break
for i in reversed(to_remove):
shuffled_locations.pop(i)
# place 2 HMG keys
hybrid_state_base = all_state_base.copy()
for x in bigs + smalls + prizes + others:
hybrid_state_base.collect(x, True)
hybrid_smalls = [ItemFactory('Small Key (Swamp Palace)', player)] * 2
fill(hybrid_state_base, hybrid_smalls, hybrid_locations, unplaced_smalls)

big_state_base = all_state_base.copy()
for x in smalls + others:
big_state_base.collect(x, True)
Expand Down
10 changes: 0 additions & 10 deletions ItemList.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,16 +368,6 @@ def generate_itempool(world, player):
or (item.map and world.mapshuffle[player])
or (item.compass and world.compassshuffle[player]))])

if world.logic[player] == 'hybridglitches' and world.pottery[player] not in ['none', 'cave']:
keys_to_remove = 2
to_remove = []
for wix, wi in enumerate(world.itempool):
if wi.name == 'Small Key (Swamp Palace)' and wi.player == player:
to_remove.append(wix)
if keys_to_remove == len(to_remove):
break
for wix in reversed(to_remove):
del world.itempool[wix]

# logic has some branches where having 4 hearts is one possible requirement (of several alternatives)
# rather than making all hearts/heart pieces progression items (which slows down generation considerably)
Expand Down
6 changes: 3 additions & 3 deletions Rom.py
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,9 @@ def patch_rom(world, rom, player, team, is_mystery=False):
if location.item.name in valid_pot_items and location.item.player == player:
location.pot.item = valid_pot_items[location.item.name]
else:
code = handle_native_dungeon(location, itemid)
code = itemid
if world.pottery[player] == 'none' or location.locked:
code = handle_native_dungeon(location, itemid)
standing_item_flag = 0x80
if location.item.player != player:
standing_item_flag |= 0x40
Expand All @@ -452,8 +454,6 @@ def patch_rom(world, rom, player, team, is_mystery=False):

if not location.crystal:
if location.item is not None:
# Keys in their native dungeon should use the original item code for keys
itemid = handle_native_dungeon(location, itemid)
if world.remote_items[player]:
itemid = list(location_table.keys()).index(location.name) + 1
assert itemid < 0x100
Expand Down
40 changes: 23 additions & 17 deletions UnderworldGlitchRules.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ def create_hmg_entrances_regions(world, player):
ip_clip_entrance = Entrance(player, "Ice Bomb Drop Clip", ip_bomb_top_reg)
ip_bomb_top_reg.exits.append(ip_clip_entrance)


def connect_hmg_entrances_regions(world, player):
for spots in [
kikiskip_spots,
Expand All @@ -68,7 +67,7 @@ def connect_hmg_entrances_regions(world, player):
connection.connect(target)

# Add the new Ice path (back of bomb drop to front) to the world and model it properly
ip_clip_entrance = world.get_entrance('Ice Bomb Drop Clip', 1)
ip_clip_entrance = world.get_entrance('Ice Bomb Drop Clip', player)
clip_door = Door(player, "Ice Bomb Drop Clip", DoorType.Logical, ip_clip_entrance)
world.doors += [clip_door]
world.initialize_doors([clip_door])
Expand Down Expand Up @@ -174,20 +173,21 @@ def dungeon_reentry_rules(
def underworld_glitches_rules(world, player):
def mire_clip(state):
torches = world.get_region("Mire Torches Top", player)
return state.can_dash_clip(torches, player) or (
state.can_bomb_clip(torches, player) and state.has_fire_source(player)
)
return (state.can_dash_clip(torches, player)
or (state.can_bomb_clip(torches, player) and state.has_fire_source(player))
) and state.can_reach(torches, player)

def hera_clip(state):
hera = world.get_region("Hera 4F", player)
return state.can_bomb_clip(hera, player) or state.can_dash_clip(hera, player)
return (state.can_bomb_clip(hera, player) or state.can_dash_clip(hera, player)) \
and state.has("Flippers", player) and state.can_reach(hera) and mire_clip(state)

# We use these plus functool.partial because lambdas don't work in loops properly.
def bomb_clip(state, region, player):
return state.can_bomb_clip(region, player)
return state.can_bomb_clip(region, player) and state.can_reach(region, player)

def dash_clip(state, region, player):
return state.can_dash_clip(region, player)
return state.can_dash_clip(region, player) and state.can_reach(region, player)
# Bomb clips
for clip in (
kikiskip_spots
Expand Down Expand Up @@ -234,18 +234,24 @@ def dash_clip(state, region, player):
# Allow mire big key to be used in Hera
Rules.add_rule(
world.get_entrance("Hera Startile Corner NW", player),
lambda state: mire_clip(state) and state.has("Big Key (Misery Mire)", player),
lambda state: state.has("Big Key (Misery Mire)", player) and mire_clip(state),
combine="or",
)
Rules.add_rule(
world.get_location("Tower of Hera - Big Chest", player),
lambda state: mire_clip(state) and state.has("Big Key (Misery Mire)", player),
lambda state: state.has("Big Key (Misery Mire)", player) and mire_clip(state),
combine="or",
)
# This uses the mire clip because it's always expected to come from mire
Rules.set_rule(
world.get_entrance("Hera to Swamp Clip", player),
lambda state: mire_clip(state) and state.has("Flippers", player),
lambda state: state.has("Flippers", player) and mire_clip(state),
)
Rules.add_rule(
world.get_location("Swamp Palace - Big Chest", player),
lambda state: (state.has("Big Key (Misery Mire)", player) or state.has("Big Key (Tower of Hera)", player)) \
and state.has("Flippers", player) and mire_clip(state),
combine="or",
)
# We need to set _all_ swamp doors to be openable with mire keys, otherwise the small key can't be behind them - 6 keys because of Pots
# Flippers required for all of these doors to prevent locks when flooding
Expand All @@ -264,9 +270,9 @@ def dash_clip(state, region, player):
]:
Rules.add_rule(
world.get_entrance(door, player),
lambda state: mire_clip(state)
lambda state: state.has("Flippers", player)
and state.has("Small Key (Misery Mire)", player, count=6)
and state.has("Flippers", player),
and mire_clip(state),
combine="or",
)

Expand Down Expand Up @@ -294,16 +300,16 @@ def dash_clip(state, region, player):
)
),
}
inverted = world.mode[player] == "inverted"
inverted_dm = world.mode[player] == "inverted"

def hera_rule(state):
return (state.has("Moon Pearl", player) or not inverted) and rule_map.get(
return (state.has("Moon Pearl", player) or not inverted_dm) and rule_map.get(
world.get_entrance("Tower of Hera", player).connected_region.name,
lambda state: False,
)(state)

def gt_rule(state):
return (state.has("Moon Pearl", player) or inverted) and rule_map.get(
return (state.has("Moon Pearl", player) or inverted_dm) and rule_map.get(
world.get_entrance(("Ganons Tower"), player).connected_region.name,
lambda state: False,
)(state)
Expand All @@ -312,8 +318,8 @@ def mirrorless_moat_rule(state):
return (
state.can_reach("Old Man S&Q", "Entrance", player)
and state.has("Flippers", player)
and mire_clip(state)
and (hera_rule(state) or gt_rule(state))
and mire_clip(state)
)

Rules.add_rule(
Expand Down
4 changes: 3 additions & 1 deletion source/dungeon/EnemyList.py
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,9 @@ def sprite_data(self):
item_id = self.location.item.code if self.location.item is not None else 0x5A
code = 0xF9 if self.location.item.player != self.location.player else 0xF8
if code == 0xF8:
item_id = handle_native_dungeon(self.location, item_id)
world = self.location.parent_region.world
if world.dropshuffle[self.location.player] == 'none' or self.location.locked:
item_id = handle_native_dungeon(self.location, item_id)
data.append(item_id)
data.append(0 if code == 0xF8 else self.location.item.player)
data.append(code)
Expand Down
Loading