-Disallowed Swamp Lobby in Hyrule Castle in Standard mode

-Prevent defeating Aga 1 before Zelda is delivered to the Sanctuary. (He can't take damage)
-Fix for Ice Jelly room when going backward and enemizer is on
-Fix for inverted - don't start as a bunny in Dark Sanctuary
-Fix for non-ER Inverted with Lobby shuffle. Aga Tower's exit works properly now.
This commit is contained in:
aerinon
2021-02-05 15:05:16 -07:00
parent 74a8ec6486
commit f83b28adb6
10 changed files with 51 additions and 24 deletions

View File

@@ -1214,6 +1214,7 @@ class Door(object):
self.passage = True self.passage = True
self.dungeonLink = None self.dungeonLink = None
self.bk_shuffle_req = False self.bk_shuffle_req = False
self.standard_restrict = False # flag if portal is not allowed in HC in standard
# self.incognitoPos = -1 # self.incognitoPos = -1
# self.sectorLink = False # self.sectorLink = False

View File

@@ -357,6 +357,7 @@ def choose_portals(world, player):
if world.doorShuffle[player] in ['basic', 'crossed']: if world.doorShuffle[player] in ['basic', 'crossed']:
cross_flag = world.doorShuffle[player] == 'crossed' cross_flag = world.doorShuffle[player] == 'crossed'
bk_shuffle = world.bigkeyshuffle[player] bk_shuffle = world.bigkeyshuffle[player]
std_flag = world.mode[player] == 'standard'
# roast incognito doors # roast incognito doors
world.get_room(0x60, player).delete(5) world.get_room(0x60, player).delete(5)
world.get_room(0x60, player).change(2, DoorKind.DungeonEntrance) world.get_room(0x60, player).change(2, DoorKind.DungeonEntrance)
@@ -369,13 +370,14 @@ def choose_portals(world, player):
region_map = defaultdict(list) region_map = defaultdict(list)
reachable_portals = [] reachable_portals = []
inaccessible_portals = [] inaccessible_portals = []
hc_flag = std_flag and dungeon == 'Hyrule Castle'
for portal in portal_list: for portal in portal_list:
placeholder = world.get_region(portal + ' Portal', player) placeholder = world.get_region(portal + ' Portal', player)
portal_region = placeholder.exits[0].connected_region portal_region = placeholder.exits[0].connected_region
name = portal_region.name name = portal_region.name
if portal_region.type == RegionType.LightWorld: if portal_region.type == RegionType.LightWorld:
world.get_portal(portal, player).light_world = True world.get_portal(portal, player).light_world = True
if name in world.inaccessible_regions[player]: if name in world.inaccessible_regions[player] or (hc_flag and portal != 'Hyrule Castle South'):
name_key = 'Desert Ledge' if name == 'Desert Palace Entrance (North) Spot' else name name_key = 'Desert Ledge' if name == 'Desert Palace Entrance (North) Spot' else name
region_map[name_key].append(portal) region_map[name_key].append(portal)
inaccessible_portals.append(portal) inaccessible_portals.append(portal)
@@ -397,7 +399,8 @@ def choose_portals(world, player):
portal_assignment = defaultdict(list) portal_assignment = defaultdict(list)
for dungeon, info in info_map.items(): for dungeon, info in info_map.items():
outstanding_portals = list(dungeon_portals[dungeon]) outstanding_portals = list(dungeon_portals[dungeon])
if dungeon == 'Hyrule Castle' and world.mode[player] == 'standard': hc_flag = std_flag and dungeon == 'Hyrule Castle'
if hc_flag:
sanc = world.get_portal('Sanctuary', player) sanc = world.get_portal('Sanctuary', player)
sanc.destination = True sanc.destination = True
clean_up_portal_assignment(portal_assignment, dungeon, sanc, master_door_list, outstanding_portals) clean_up_portal_assignment(portal_assignment, dungeon, sanc, master_door_list, outstanding_portals)
@@ -425,7 +428,7 @@ def choose_portals(world, player):
the_rest = info.total - len(portal_assignment[dungeon]) the_rest = info.total - len(portal_assignment[dungeon])
for i in range(0, the_rest): for i in range(0, the_rest):
candidates = find_portal_candidates(master_door_list, dungeon, crossed=cross_flag, candidates = find_portal_candidates(master_door_list, dungeon, crossed=cross_flag,
bk_shuffle=bk_shuffle) bk_shuffle=bk_shuffle, standard=hc_flag)
choice, portal = assign_portal(candidates, outstanding_portals, world, player) choice, portal = assign_portal(candidates, outstanding_portals, world, player)
clean_up_portal_assignment(portal_assignment, dungeon, portal, master_door_list, outstanding_portals) clean_up_portal_assignment(portal_assignment, dungeon, portal, master_door_list, outstanding_portals)
@@ -536,23 +539,20 @@ def disconnect_portal(portal, world, player):
chosen_door.entranceFlag = False chosen_door.entranceFlag = False
def find_portal_candidates(door_list, dungeon, need_passage=False, dead_end_allowed=False, crossed=False, bk_shuffle=False): def find_portal_candidates(door_list, dungeon, need_passage=False, dead_end_allowed=False, crossed=False,
filter_list = [x for x in door_list if bk_shuffle or not x.bk_shuffle_req] bk_shuffle=False, standard=False):
if need_passage: ret = [x for x in door_list if bk_shuffle or not x.bk_shuffle_req]
if crossed: if crossed:
return [x for x in filter_list if x.passage and (x.dungeonLink is None or x.entrance.parent_region.dungeon.name == dungeon)] ret = [x for x in ret if not x.dungeonLink or x.entrance.parent_region.dungeon.name == dungeon]
else:
return [x for x in filter_list if x.passage and x.entrance.parent_region.dungeon.name == dungeon]
elif dead_end_allowed:
if crossed:
return [x for x in filter_list if x.dungeonLink is None or x.entrance.parent_region.dungeon.name == dungeon]
else:
return [x for x in filter_list if x.entrance.parent_region.dungeon.name == dungeon]
else: else:
if crossed: ret = [x for x in ret if x.entrance.parent_region.dungeon.name == dungeon]
return [x for x in filter_list if (not x.dungeonLink or x.entrance.parent_region.dungeon.name == dungeon) and not x.deadEnd] if need_passage:
else: ret = [x for x in ret if x.passage]
return [x for x in filter_list if x.entrance.parent_region.dungeon.name == dungeon and not x.deadEnd] if not dead_end_allowed:
ret = [x for x in ret if not x.deadEnd]
if standard:
ret = [x for x in ret if not x.standard_restrict]
return ret
def assign_portal(candidates, possible_portals, world, player): def assign_portal(candidates, possible_portals, world, player):

View File

@@ -1306,6 +1306,7 @@ def create_doors(world, player):
world.get_door("GT Bob\'s Room SE", player).passage = False world.get_door("GT Bob\'s Room SE", player).passage = False
world.get_door('PoD Mimics 2 SW', player).bk_shuffle_req = True world.get_door('PoD Mimics 2 SW', player).bk_shuffle_req = True
world.get_door('Desert Tiles 2 SE', player).bk_shuffle_req = True # key-drop note (todo) world.get_door('Desert Tiles 2 SE', player).bk_shuffle_req = True # key-drop note (todo)
world.get_door('Swamp Lobby S', player).standard_restricted = True # key-drop note (todo)
# can't unlink from boss right now # can't unlink from boss right now
world.get_door('Hera Lobby S', player).dungeonLink = 'Tower of Hera' world.get_door('Hera Lobby S', player).dungeonLink = 'Tower of Hera'

View File

@@ -9,6 +9,12 @@ Big thanks to Catobat for doing all the hard work.
# Bug Fixes # Bug Fixes
* 0.3.0.2-u
* Disallowed Swamp Lobby in Hyrule Castle in Standard mode
* Prevent defeating Aga 1 before Zelda is delivered to the Sanctuary. (He can't take damage)
* Fix for Ice Jelly room when going backward and enemizer is on
* Fix for inverted - don't start as a bunny in Dark Sanctuary
* Fix for non-ER Inverted with Lobby shuffle. Aga Tower's exit works properly now.
* 0.3.0.1-u * 0.3.0.1-u
* Problem with lobbies on re-rolls corrected * Problem with lobbies on re-rolls corrected
* Potential playthrough problem addressed * Potential playthrough problem addressed

11
Rom.py
View File

@@ -711,6 +711,12 @@ def patch_rom(world, rom, player, team, enemized):
if dr_flags & DROptions.Town_Portal and world.mode[player] == 'inverted': if dr_flags & DROptions.Town_Portal and world.mode[player] == 'inverted':
rom.write_byte(0x138006, 1) rom.write_byte(0x138006, 1)
# swap in non-ER Lobby Shuffle Inverted - but only then
if world.mode[player] == 'inverted' and world.intensity[player] >= 3 and world.doorShuffle[player] != 'vanilla' and world.shuffle[player] == 'vanilla':
aga_portal = world.get_portal('Agahnims Tower', player)
gt_portal = world.get_portal('Ganons Tower', player)
aga_portal.exit_offset, gt_portal.exit_offset = gt_portal.exit_offset, aga_portal.exit_offset
for portal in world.dungeon_portals[player]: for portal in world.dungeon_portals[player]:
if not portal.default: if not portal.default:
offset = portal.ent_offset offset = portal.ent_offset
@@ -2093,8 +2099,9 @@ def set_inverted_mode(world, player, rom):
if world.shuffle[player] == 'vanilla': if world.shuffle[player] == 'vanilla':
rom.write_byte(0xDBB73 + 0x23, 0x37) # switch AT and GT rom.write_byte(0xDBB73 + 0x23, 0x37) # switch AT and GT
rom.write_byte(0xDBB73 + 0x36, 0x24) rom.write_byte(0xDBB73 + 0x36, 0x24)
write_int16(rom, 0x15AEE + 2*0x38, 0x00E0) if world.doorShuffle[player] == 'vanilla' or world.intensity[player] < 3:
write_int16(rom, 0x15AEE + 2*0x25, 0x000C) write_int16(rom, 0x15AEE + 2*0x38, 0x00E0)
write_int16(rom, 0x15AEE + 2*0x25, 0x000C)
if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull']: if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull']:
rom.write_byte(0x15B8C, 0x6C) rom.write_byte(0x15B8C, 0x6C)
rom.write_byte(0xDBB73 + 0x00, 0x53) # switch bomb shop and links house rom.write_byte(0xDBB73 + 0x00, 0x53) # switch bomb shop and links house

View File

@@ -252,6 +252,7 @@ def create_rooms(world, player):
world.get_room(0x77, player).swap(0, 1) # fixes Hera Lobby Key Stairs - entrance now at pos 0 world.get_room(0x77, player).swap(0, 1) # fixes Hera Lobby Key Stairs - entrance now at pos 0
if world.enemy_shuffle[player] != 'none': if world.enemy_shuffle[player] != 'none':
world.get_room(0xc0, player).change(0, DoorKind.Normal) # fix this kill room if enemizer is on world.get_room(0xc0, player).change(0, DoorKind.Normal) # fix this kill room if enemizer is on
world.get_room(0x0e, player).change(1, DoorKind.TrapTriggerable) # fix this kill room if enemizer is on
def reset_rooms(world, player): def reset_rooms(world, player):
@@ -369,7 +370,7 @@ class DoorKind(Enum):
IncognitoEntrance = 0x12 IncognitoEntrance = 0x12
DungeonChanger = 0x14 DungeonChanger = 0x14
ToggleFlag = 0x16 ToggleFlag = 0x16
Trap = 0x18 Trap = 0x18 # both sides trapped
UnknownD6 = 0x1A UnknownD6 = 0x1A
SmallKey = 0x1C SmallKey = 0x1C
BigKey = 0x1E BigKey = 0x1E
@@ -382,8 +383,8 @@ class DoorKind(Enum):
Bombable = 0x2E Bombable = 0x2E
BlastWall = 0x30 BlastWall = 0x30
Hidden = 0x32 Hidden = 0x32
TrapTriggerable = 0x36 TrapTriggerable = 0x36 # right side trap or south side trap
Trap2 = 0x38 Trap2 = 0x38 # left side trap or north side trap
NormalLow2 = 0x40 NormalLow2 = 0x40
TrapTriggerableLow = 0x44 TrapTriggerableLow = 0x44
Warp = 0x46 Warp = 0x46

View File

@@ -1,5 +1,6 @@
CheckDarkWorldSanc: CheckDarkWorldSanc:
STA $A0 : STA $048E ; what we wrote over STA $A0 : STA $048E ; what we wrote over
LDA.l InvertedMode : BNE +
LDA.l SancDarkWorldFlag : BEQ + LDA.l SancDarkWorldFlag : BEQ +
SEP #$30 SEP #$30
LDA $A0 : CMP #$12 : BNE ++ LDA $A0 : CMP #$12 : BNE ++

View File

@@ -170,6 +170,9 @@ JSL CheckDarkWorldSanc : NOP
org $01891e ; <- Bank 01.asm : 991 Dungeon_LoadType2Object (LDA $00 : XBA : AND.w #$00FF) org $01891e ; <- Bank 01.asm : 991 Dungeon_LoadType2Object (LDA $00 : XBA : AND.w #$00FF)
JSL RainPrevention : NOP #2 JSL RainPrevention : NOP #2
org $1edabf ; <- sprite_energy_ball.asm : 86-7 Sprite_EnergyBall (LDA.b #$10 : LDX.b #$00)
JSL StandardAgaDmg
; These two, if enabled together, have implications for vanilla BK doors in IP/Hera/Mire ; These two, if enabled together, have implications for vanilla BK doors in IP/Hera/Mire
; IPBJ is common enough to consider not doing this. Mire is not a concern for vanilla - maybe glitched modes ; IPBJ is common enough to consider not doing this. Mire is not a concern for vanilla - maybe glitched modes
; Hera BK door back can be seen with Pot clipping - likely useful for no logic seeds ; Hera BK door back can be seen with Pot clipping - likely useful for no logic seeds

View File

@@ -142,3 +142,10 @@ RainPrevention:
PLA : LDA #$0008 : RTL PLA : LDA #$0008 : RTL
.done PLA : RTL .done PLA : RTL
; A should be how much dmg to do to Aga when leaving this function
StandardAgaDmg:
LDX.b #$00 ; part of what we wrote over
LDA.l $7EF3C6 : AND #$04 : BEQ + ; zelda's not been rescued
LDA.b #$10 ; hurt him!
+ RTL ; A is zero if the AND results in zero and then Agahnim's invincible!

Binary file not shown.