fix(logic): exception for vanilla mire key door layout, crystal switches can be reached with two keys, just can't tell which one was chosen

This commit is contained in:
aerinon
2024-04-12 17:32:35 -06:00
parent d8199742db
commit ebd86e80d7
4 changed files with 45 additions and 8 deletions

View File

@@ -695,7 +695,7 @@ class CollectionState(object):
@staticmethod @staticmethod
def valid_crystal(door, new_crystal_state): def valid_crystal(door, new_crystal_state):
return (not door.crystal or door.crystal == CrystalBarrier.Either or new_crystal_state == CrystalBarrier.Either return (not door.crystal or door.crystal == CrystalBarrier.Either or new_crystal_state == CrystalBarrier.Either
or new_crystal_state == door.crystal) or new_crystal_state == door.crystal or door.alternative_crystal_rule)
def check_key_doors_in_dungeons(self, rrp, player): def check_key_doors_in_dungeons(self, rrp, player):
for dungeon_name, checklist in self.dungeons_to_check[player].items(): for dungeon_name, checklist in self.dungeons_to_check[player].items():
@@ -1828,6 +1828,7 @@ class Door(object):
self.bigKey = False # There's a big key door on this side self.bigKey = False # There's a big key door on this side
self.ugly = False # Indicates that it can't be seen from the front (e.g. back of a big key door) self.ugly = False # Indicates that it can't be seen from the front (e.g. back of a big key door)
self.crystal = CrystalBarrier.Null # How your crystal state changes if you use this door self.crystal = CrystalBarrier.Null # How your crystal state changes if you use this door
self.alternative_crystal_rule = False
self.req_event = None # if a dungeon event is required for this door - swamp palace mostly self.req_event = None # if a dungeon event is required for this door - swamp palace mostly
self.controller = None self.controller = None
self.dependents = [] self.dependents = []
@@ -3209,3 +3210,4 @@ class KeyRuleType(FastEnum):
WorstCase = 0 WorstCase = 0
AllowSmall = 1 AllowSmall = 1
Lock = 2 Lock = 2
CrystalAlternative = 3

View File

@@ -20,7 +20,7 @@ from DungeonGenerator import create_dungeon_builders, split_dungeon_builder, sim
from DungeonGenerator import dungeon_portals, dungeon_drops, connect_doors, count_reserved_locations from DungeonGenerator import dungeon_portals, dungeon_drops, connect_doors, count_reserved_locations
from DungeonGenerator import valid_region_to_explore from DungeonGenerator import valid_region_to_explore
from KeyDoorShuffle import analyze_dungeon, build_key_layout, validate_key_layout, determine_prize_lock from KeyDoorShuffle import analyze_dungeon, build_key_layout, validate_key_layout, determine_prize_lock
from KeyDoorShuffle import validate_bk_layout from KeyDoorShuffle import validate_bk_layout, DoorRules
from Utils import ncr, kth_combination from Utils import ncr, kth_combination
@@ -263,7 +263,7 @@ def vanilla_key_logic(world, player):
log_key_logic(builder.name, key_layout.key_logic) log_key_logic(builder.name, key_layout.key_logic)
# special adjustments for vanilla # special adjustments for vanilla
if world.keyshuffle[player] != 'universal': if world.keyshuffle[player] != 'universal':
if world.mode[player] != 'standard' and world.dropshuffle[player] == 'none' : if world.mode[player] != 'standard' and world.dropshuffle[player] == 'none':
# adjust hc doors # adjust hc doors
def adjust_hc_door(door_rule): def adjust_hc_door(door_rule):
if door_rule.new_rules[KeyRuleType.WorstCase] == 3: if door_rule.new_rules[KeyRuleType.WorstCase] == 3:
@@ -279,9 +279,28 @@ def vanilla_key_logic(world, player):
if pod_front.new_rules[KeyRuleType.WorstCase] == 6: if pod_front.new_rules[KeyRuleType.WorstCase] == 6:
pod_front.new_rules[KeyRuleType.WorstCase] = 1 pod_front.new_rules[KeyRuleType.WorstCase] = 1
pod_front.small_key_num = 1 pod_front.small_key_num = 1
# adjust mire key logic - this currently cannot be done dynamically
create_alternative_door_rules('Mire Hub Upper Blue Barrier', 2, 'Misery Mire', world, player)
create_alternative_door_rules('Mire Hub Lower Blue Barrier', 2, 'Misery Mire', world, player)
create_alternative_door_rules('Mire Hub Right Blue Barrier', 2, 'Misery Mire', world, player)
create_alternative_door_rules('Mire Hub Top Blue Barrier', 2, 'Misery Mire', world, player)
create_alternative_door_rules('Mire Hub Switch Blue Barrier N', 2, 'Misery Mire', world, player)
create_alternative_door_rules('Mire Hub Switch Blue Barrier S', 2, 'Misery Mire', world, player)
create_alternative_door_rules('Mire Map Spot Blue Barrier', 2, 'Misery Mire', world, player)
create_alternative_door_rules('Mire Map Spike Side Blue Barrier', 2, 'Misery Mire', world, player)
create_alternative_door_rules('Mire Crystal Dead End Left Barrier', 2, 'Misery Mire', world, player)
create_alternative_door_rules('Mire Crystal Dead End Right Barrier', 2, 'Misery Mire', world, player)
# gt logic? I'm unsure it needs adjusting # gt logic? I'm unsure it needs adjusting
def create_alternative_door_rules(door, amount, dungeon, world, player):
rules = DoorRules(0, True)
world.key_logic[player][dungeon].door_rules[door] = rules
rules.new_rules[KeyRuleType.CrystalAlternative] = amount
world.get_door(door, player).alternative_crystal_rule = True
def validate_vanilla_reservation(dungeon, world, player): def validate_vanilla_reservation(dungeon, world, player):
return validate_key_layout(world.key_layout[player][dungeon.name], world, player) return validate_key_layout(world.key_layout[player][dungeon.name], world, player)

View File

@@ -142,7 +142,7 @@ These are now independent of retro mode and have three options: None, Random, an
# Patch Notes # Patch Notes
* 1.4.1.10u * 1.4.1.10u
* ? * Vanilla key logic: Fix for vanilla layout Misery Mire which allows more complex key logic. Locations blocked by crystal switch access is only locked by 2 keys thanks to that being the minimun in Mire to reach one of two crystal switches.
* Autotracking: Fix for chest turn counter with chest containing multiworld items (Thanks Hiimcody) * Autotracking: Fix for chest turn counter with chest containing multiworld items (Thanks Hiimcody)
* Rom: Code prettification and fixing byte designations by Codemann * Rom: Code prettification and fixing byte designations by Codemann
* 1.4.1.9u * 1.4.1.9u

View File

@@ -2332,10 +2332,13 @@ def add_key_logic_rules(world, player):
for d_name, d_logic in key_logic.items(): for d_name, d_logic in key_logic.items():
for door_name, rule in d_logic.door_rules.items(): for door_name, rule in d_logic.door_rules.items():
door_entrance = world.get_entrance(door_name, player) door_entrance = world.get_entrance(door_name, player)
add_rule(door_entrance, eval_func(door_name, d_name, player)) if not door_entrance.door.smallKey and door_entrance.door.crystal == CrystalBarrier.Blue:
if door_entrance.door.dependents: add_rule(door_entrance, eval_alternative_crystal(door_name, d_name, player), 'or')
for dep in door_entrance.door.dependents: else:
add_rule(dep.entrance, eval_func(door_name, d_name, player)) add_rule(door_entrance, eval_func(door_name, d_name, player))
if door_entrance.door.dependents:
for dep in door_entrance.door.dependents:
add_rule(dep.entrance, eval_func(door_name, d_name, player))
for location in d_logic.bk_restricted: for location in d_logic.bk_restricted:
if not location.forced_item: if not location.forced_item:
forbid_item(location, d_logic.bk_name, player) forbid_item(location, d_logic.bk_name, player)
@@ -2427,6 +2430,15 @@ def eval_small_key_door_strict_main(state, door_name, dungeon, player):
return state.has_sm_key_strict(key_layout.key_logic.small_key_name, player, number) return state.has_sm_key_strict(key_layout.key_logic.small_key_name, player, number)
def eval_alternative_crystal_main(state, door_name, dungeon, player):
key_logic = state.world.key_logic[player][dungeon]
door_rule = key_logic.door_rules[door_name]
for ruleType, number in door_rule.new_rules.items():
if ruleType == KeyRuleType.CrystalAlternative:
return state.has_sm_key(key_logic.small_key_name, player, number)
return False
def eval_small_key_door(door_name, dungeon, player): def eval_small_key_door(door_name, dungeon, player):
return lambda state: eval_small_key_door_main(state, door_name, dungeon, player) return lambda state: eval_small_key_door_main(state, door_name, dungeon, player)
@@ -2439,6 +2451,10 @@ def eval_small_key_door_strict(door_name, dungeon, player):
return lambda state: eval_small_key_door_strict_main(state, door_name, dungeon, player) return lambda state: eval_small_key_door_strict_main(state, door_name, dungeon, player)
def eval_alternative_crystal(door_name, dungeon, player):
return lambda state: eval_alternative_crystal_main(state, door_name, dungeon, player)
def allow_big_key_in_big_chest(bk_name, player): def allow_big_key_in_big_chest(bk_name, player):
return lambda state, item: item.name == bk_name and item.player == player return lambda state, item: item.name == bk_name and item.player == player