diff --git a/BaseClasses.py b/BaseClasses.py index fa501b73..fd0d0ed9 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -1215,6 +1215,7 @@ class Door(object): self.passage = True self.dungeonLink = None self.bk_shuffle_req = False + self.standard_restrict = False # flag if portal is not allowed in HC in standard # self.incognitoPos = -1 # self.sectorLink = False diff --git a/DoorShuffle.py b/DoorShuffle.py index 97e7d234..5c05698f 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -357,6 +357,7 @@ def choose_portals(world, player): if world.doorShuffle[player] in ['basic', 'crossed']: cross_flag = world.doorShuffle[player] == 'crossed' bk_shuffle = world.bigkeyshuffle[player] + std_flag = world.mode[player] == 'standard' # roast incognito doors world.get_room(0x60, player).delete(5) world.get_room(0x60, player).change(2, DoorKind.DungeonEntrance) @@ -369,13 +370,14 @@ def choose_portals(world, player): region_map = defaultdict(list) reachable_portals = [] inaccessible_portals = [] + hc_flag = std_flag and dungeon == 'Hyrule Castle' for portal in portal_list: placeholder = world.get_region(portal + ' Portal', player) portal_region = placeholder.exits[0].connected_region name = portal_region.name if portal_region.type == RegionType.LightWorld: 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 region_map[name_key].append(portal) inaccessible_portals.append(portal) @@ -397,7 +399,8 @@ def choose_portals(world, player): portal_assignment = defaultdict(list) for dungeon, info in info_map.items(): 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.destination = True 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]) for i in range(0, the_rest): 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) 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 -def find_portal_candidates(door_list, dungeon, need_passage=False, dead_end_allowed=False, crossed=False, bk_shuffle=False): - filter_list = [x for x in door_list if bk_shuffle or not x.bk_shuffle_req] - if need_passage: - 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)] - 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] +def find_portal_candidates(door_list, dungeon, need_passage=False, dead_end_allowed=False, crossed=False, + bk_shuffle=False, standard=False): + ret = [x for x in door_list if bk_shuffle or not x.bk_shuffle_req] + if crossed: + ret = [x for x in ret if not x.dungeonLink or x.entrance.parent_region.dungeon.name == dungeon] else: - if crossed: - return [x for x in filter_list if (not x.dungeonLink or x.entrance.parent_region.dungeon.name == dungeon) and not x.deadEnd] - else: - return [x for x in filter_list if x.entrance.parent_region.dungeon.name == dungeon and not x.deadEnd] + ret = [x for x in ret if x.entrance.parent_region.dungeon.name == dungeon] + if need_passage: + ret = [x for x in ret if x.passage] + 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): diff --git a/Doors.py b/Doors.py index 3bc41766..c3cc969d 100644 --- a/Doors.py +++ b/Doors.py @@ -1306,6 +1306,7 @@ def create_doors(world, player): 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('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 world.get_door('Hera Lobby S', player).dungeonLink = 'Tower of Hera' diff --git a/Main.py b/Main.py index 8c079b6d..25b81153 100644 --- a/Main.py +++ b/Main.py @@ -26,7 +26,7 @@ from Fill import sell_potions, sell_keys, balance_multiworld_progression, balanc from ItemList import generate_itempool, difficulties, fill_prizes, customize_shops from Utils import output_path, parse_player_names -__version__ = '0.3.1.0-u' +__version__ = '0.3.1.1-u' class EnemizerError(RuntimeError): pass diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 60cb59c8..5bac936d 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -132,6 +132,12 @@ Big thanks to Catobat for doing all the hard work. # Bug Fixes +* 0.3.1.1-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 * Problem with lobbies on re-rolls corrected * Potential playthrough problem addressed diff --git a/Rom.py b/Rom.py index 79fbbea7..290d9d01 100644 --- a/Rom.py +++ b/Rom.py @@ -27,7 +27,7 @@ from EntranceShuffle import door_addresses, exit_ids JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '932e67ddea0800d1415f34e7de3bc1af' +RANDOMIZERBASEHASH = '6a4096235f682b7e4e1a65f274c7037b' class JsonRom(object): @@ -711,6 +711,12 @@ def patch_rom(world, rom, player, team, enemized): if dr_flags & DROptions.Town_Portal and world.mode[player] == 'inverted': 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]: if not portal.default: offset = portal.ent_offset @@ -2106,8 +2112,9 @@ def set_inverted_mode(world, player, rom): if world.shuffle[player] == 'vanilla': rom.write_byte(0xDBB73 + 0x23, 0x37) # switch AT and GT rom.write_byte(0xDBB73 + 0x36, 0x24) - write_int16(rom, 0x15AEE + 2*0x38, 0x00E0) - write_int16(rom, 0x15AEE + 2*0x25, 0x000C) + if world.doorShuffle[player] == 'vanilla' or world.intensity[player] < 3: + write_int16(rom, 0x15AEE + 2*0x38, 0x00E0) + write_int16(rom, 0x15AEE + 2*0x25, 0x000C) if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull']: rom.write_byte(0x15B8C, 0x6C) rom.write_byte(0xDBB73 + 0x00, 0x53) # switch bomb shop and links house diff --git a/RoomData.py b/RoomData.py index 3fe8d594..f3c82576 100644 --- a/RoomData.py +++ b/RoomData.py @@ -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 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(0x0e, player).change(1, DoorKind.TrapTriggerable) # fix this kill room if enemizer is on def reset_rooms(world, player): @@ -369,7 +370,7 @@ class DoorKind(Enum): IncognitoEntrance = 0x12 DungeonChanger = 0x14 ToggleFlag = 0x16 - Trap = 0x18 + Trap = 0x18 # both sides trapped UnknownD6 = 0x1A SmallKey = 0x1C BigKey = 0x1E @@ -382,8 +383,8 @@ class DoorKind(Enum): Bombable = 0x2E BlastWall = 0x30 Hidden = 0x32 - TrapTriggerable = 0x36 - Trap2 = 0x38 + TrapTriggerable = 0x36 # right side trap or south side trap + Trap2 = 0x38 # left side trap or north side trap NormalLow2 = 0x40 TrapTriggerableLow = 0x44 Warp = 0x46 diff --git a/asm/dr_lobby.asm b/asm/dr_lobby.asm index c2f08fa6..cf3ed694 100644 --- a/asm/dr_lobby.asm +++ b/asm/dr_lobby.asm @@ -1,5 +1,6 @@ CheckDarkWorldSanc: STA $A0 : STA $048E ; what we wrote over + LDA.l InvertedMode : BNE + LDA.l SancDarkWorldFlag : BEQ + SEP #$30 LDA $A0 : CMP #$12 : BNE ++ diff --git a/asm/drhooks.asm b/asm/drhooks.asm index 1aa62dde..c4939e9d 100644 --- a/asm/drhooks.asm +++ b/asm/drhooks.asm @@ -170,6 +170,9 @@ JSL CheckDarkWorldSanc : NOP org $01891e ; <- Bank 01.asm : 991 Dungeon_LoadType2Object (LDA $00 : XBA : AND.w #$00FF) 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 ; 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 diff --git a/asm/overrides.asm b/asm/overrides.asm index d47d565f..28eb7f91 100644 --- a/asm/overrides.asm +++ b/asm/overrides.asm @@ -142,3 +142,10 @@ RainPrevention: PLA : LDA #$0008 : 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! + diff --git a/data/base2current.bps b/data/base2current.bps index 022cd3e4..4674a063 100644 Binary files a/data/base2current.bps and b/data/base2current.bps differ