diff --git a/BaseClasses.py b/BaseClasses.py index d54a2fd1..b97f3db0 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -1499,6 +1499,10 @@ class Portal(object): self.deadEnd = False self.light_world = False + def change_boss_exit(self, exit_idx): + self.default = False + self.boss_exit_idx = exit_idx + def change_door(self, new_door): if new_door != self.door: self.default = False diff --git a/DoorShuffle.py b/DoorShuffle.py index bffd7dc7..383a9de9 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -369,6 +369,9 @@ def choose_portals(world, player): sanc = world.get_portal('Sanctuary', player) sanc.destination = True clean_up_portal_assignment(portal_assignment, dungeon, sanc, master_door_list, outstanding_portals) + for target_region, possible_portals in info.required_passage.items(): + info.required_passage[target_region] = [x for x in possible_portals if x != sanc.name] + info.required_passage = {x: y for x, y in info.required_passage.items() if len(y) > 0} for target_region, possible_portals in info.required_passage.items(): candidates = find_portal_candidates(master_door_list, dungeon, need_passage=True, crossed=cross_flag, bk_shuffle=bk_shuffle) @@ -596,6 +599,8 @@ def create_dungeon_entrances(world, player): filtered_choices = [x for x in choices if any(y not in world.inaccessible_regions[player] for y in originating[key][x].keys())] else: filtered_choices = dest_choices + if len(filtered_choices) == 0: + raise Exception('No valid destinations') choice = random.choice(filtered_choices) r_name = portal.door.entrance.parent_region.name split_map[key][choice].append(r_name) @@ -650,6 +655,8 @@ def within_dungeon(world, player): target = portal.door.entrance.parent_region connect_simple_door(world, 'Sanctuary Mirror Route', target, player) + refine_boss_exits(world, player) + def handle_split_dungeons(dungeon_builders, recombinant_builders, entrances_map, builder_info): dungeon_entrances, split_dungeon_entrances, world, player = builder_info @@ -943,6 +950,7 @@ def cross_dungeon(world, player): palette_assignment(world, player) refine_hints(dungeon_builders) + refine_boss_exits(world, player) def assign_cross_keys(dungeon_builders, world, player): @@ -1138,6 +1146,44 @@ def refine_hints(dungeon_builders): location.hint_text = dungeon_hints[name] +def refine_boss_exits(world, player): + for d_name, d_boss in {'Desert Palace': 'Desert Boss', + 'Skull Woods': 'Skull Boss', + 'Turtle Rock': 'TR Boss'}.items(): + possible_portals = [] + current_boss = None + for portal_name in dungeon_portals[d_name]: + portal = world.get_portal(portal_name, player) + if not portal.destination: + possible_portals.append(portal) + if portal.boss_exit_idx > -1: + current_boss = portal + if len(possible_portals) == 1: + if possible_portals[0] != current_boss: + possible_portals[0].change_boss_exit(current_boss.boss_exit_idx) + current_boss.change_boss_exit(-1) + else: + reachable_portals = [] + for portal in possible_portals: + start_area = portal.door.entrance.parent_region + state = ExplorationState(dungeon=d_name) + state.visit_region(start_area) + state.add_all_doors_check_unattached(start_area, world, player) + explore_state_not_inaccessible(state, world, player) + if state.visited_at_all(world.get_region(d_boss, player)): + reachable_portals.append(portal) + if len(reachable_portals) == 0: + reachable_portals = possible_portals + unreachable = world.inaccessible_regions[player] + filtered = [x for x in reachable_portals if x.door.entrance.connected_region.name not in unreachable] + if 0 < len(filtered) < len(reachable_portals): + reachable_portals = filtered + chosen_one = random.choice(reachable_portals) if len(reachable_portals) > 1 else reachable_portals[0] + if chosen_one != current_boss: + chosen_one.change_boss_exit(current_boss.boss_exit_idx) + current_boss.change_boss_exit(-1) + + def convert_to_sectors(region_names, world, player): region_list = convert_regions(region_names, world, player) sectors = [] @@ -1806,6 +1852,15 @@ def explore_state(state, world, player): state.add_all_doors_check_unattached(connect_region, world, player) +def explore_state_not_inaccessible(state, world, player): + while len(state.avail_doors) > 0: + door = state.next_avail_door().door + connect_region = world.get_entrance(door.name, player).connected_region + if state.can_traverse(door) and not state.visited(connect_region) and connect_region.type == RegionType.Dungeon: + state.visit_region(connect_region) + state.add_all_doors_check_unattached(connect_region, world, player) + + def check_if_regions_visited(state, check_paths): valid = False breaking_region = None diff --git a/RELEASENOTES.md b/RELEASENOTES.md index b96e4fc8..97de2d51 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,34 +1,78 @@ # New Features -* Lobby shuffle added as Intensity level 3 - * Can now be found in the spoiler - * Palette changes: - * Certain doors/transition no longer have an effect on the palette choice (dead ends mostly or just bridges) - * Sanctuary palette back to the adjacent rooms to Sanctuary (sanctuary stays the dungeon color for now) - * Sewer palette comes back for part of Hyrule Castle for areas "near" the sewer dropdown - * Known issues: - * Palettes aren't perfect - May add a way to turn off palette "fixing" - * Some ugly colors - * Invisible floors can be see in many palettes -* --keydropshuffle added (coming to the GUI soon). This add 33 new locations to the game where keys are found under pots +## Lobby shuffle added as Intensity level 3 + +* Standard notes: + * The sanctuary is vanilla, and will be missing the exit door until Zelda is rescued + * In entrance shuffle the hyrule castle left and right exit door will be missing until Zelda is rescued. This + replaces the rails that used to block those lobby exits + * In non-entrance shuffle, Agahnims tower can be in logic if you have cape and/or Master sword, but you are never + required to beat Agahnim 1 until Zelda is rescued. +* Open notes: + * The Sanctuary is limited to be in a LW dungeon unless you have ER Crossed or higher enabled + * Mirroring from the Sanctuary to the new "Sanctuary" lobby is now in logic, as is exiting there. + * In ER crossed or higher, if the Sanctuary is in the Dark World, Link starts as Bunny there until the Moon Pearl + is found. Nothing inside that dungeon is in logic until the Moon Pearl is found. (Unless it is a multi-entrance + dungeon that you can access from some LW entrance) +* Lobby list is found in the spoiler +* Exits for Multi-entrance dungeons after beating bosses now makes more sense. Generally you'll exit from a entrance + from which the boss can logically be reached. If there are multiple, ones that do not lead to regions only accessible + by connector are preferred. The exit is randomly chosen if there's no obvious preference. However, In certain poor + cases like Skull Woods in ER, sometimes an exit is chosen not because you can reach the boss from there, but to + prevent a potential forced S&Q. +* Palette changes: + * Certain doors/transition no longer have an effect on the palette choice (dead ends mostly or just bridges) + * Sanctuary palette used on the adjacent rooms to Sanctuary (Sanctuary stays the dungeon color for now) + * Sewer palette comes back for part of Hyrule Castle for areas "near" the sewer dropdown + * There is a setting to keep original palettes (--standardize_palettes original) +* Known issues: + * Palettes aren't perfect + * Some ugly colors + * Invisible floors can be see in many palettes + +## Key Drop Shuffle + +--keydropshuffle added. This add 33 new locations to the game where keys are found under pots and where enemies drop keys. This includes 32 small key location and the ball and chain guard who normally drop the HC Big Key. - * Overall location count updated - * Setting mentioned in spoiler - * Known issue: - * GT Big Key count needs to be updated -* --mixed_travel setting added - * Due to Hammerjump, Hovering in PoD Arena, and the Mire Big Key Chest bomb jump two sections of a supertile that are + +* Overall location count updated +* Setting mentioned in spoiler +* Minor change: if a key is Universal or for that dungeon, then if will use the old mechanics of picking up the key without +an entire pose and should be obtainable with the hookshot or boomerang as before + +## --mixed_travel setting +* Due to Hammerjump, Hovering in PoD Arena, and the Mire Big Key Chest bomb jump two sections of a supertile that are otherwise unconnected logically can be reach using these glitches. To prevent the player from unintentionally - * prevent: Rails are added the 3 spots to prevent this tricks. This setting is recommend for those learning - crossed dungeon mode to learn what is dangerous and what is not. No logic seeds ignore this setting. - * allow: The rooms are left alone and it is up to the discretion of the player whether to use these tricks or not. - * force: The two disjointed sections are forced to be in the same dungeon but never logically required to complete that game. + * prevent: Rails are added the 3 spots to prevent this tricks. This setting is recommend for those learning + crossed dungeon mode to learn what is dangerous and what is not. No logic seeds ignore this setting. + * allow: The rooms are left alone and it is up to the discretion of the player whether to use these tricks or not. + * force: The two disjointed sections are forced to be in the same dungeon but never logically required to complete that game. + +## Keysanity menu redesign + +Redesign of Keysanity Menu complete for crossed dungeon and moved out of experimental. +* First screen about Big Keys and Small Keys + * 1st Column: The map is required for information about the Big Key + * If you don't have the map, it'll be blank until you obtain the Big Key + * If have the map: + * 0 indicates there is no Big Key for that dungeon + * A red symbol indicates the Ball N Chain guard has the big key for that dungeon (does not apply in + --keydropshuffle) + * Blank if there a big key but you haven't found it yet + * 2nd Column displays the current number of keys for that dungeon. Suppressed in retro (always blank) + * 3rd Column only display if you have the map. It shows the number of keys left to collect for that dungeon. If + --keydropshuffle is off, this does not count key drops. If on, it does. + * (Note: the key columns can display up to 36 using the letters A-Z after 9) +* Second screen about Maps / Compass + * 1st Column: indicate if you have foudn the map of not for that dungeon + * 2nd and 3rd Column: You must have the compass to see these columns. A two-digit display that show you how + many chests are left in the dungeon. If -keydropshuffle is off, this does not count key drop. If on, it does. ### Experimental features -* Redesign of Keysanity Menu for Crossed Dungeon - soon to move out of experimental +* Only the random bomb doors and the item counter are currently experimental + * Item counter is suppressed in Triforce Hunt #### Temporary debug features @@ -37,12 +81,12 @@ otherwise unconnected logically can be reach using these glitches. To prevent th # Bug Fixes * 2.0.12u - * Option to keep original palettes in crossed dungeon mode - * If sanc if in a DW dungeon because of crossed+ ER, then you start in bunny form - * Mirroring from sanc to the portal is now in logic * Another fix for animated tiles (fairy fountains) * GT Big Key stat fixed on credits - * Todo: Standard logic fixes for lobbies + * Any denomination of rupee 20 or below can be removed to make room for Crossed Dungeon's extra dungeon items. This + helps retro generate more often. + * Fix for TR Lobbies in intensity 3 and ER shuffles that was causing a hardlock + * Standard ER logic revised for lobby shuffle and rain state considerations. * 2.0.11u * Fix output path setting in settings.json * Fix trock entrances when intensity <= 2 diff --git a/Rom.py b/Rom.py index fb6b7fb6..8073b8e8 100644 --- a/Rom.py +++ b/Rom.py @@ -26,7 +26,7 @@ from EntranceShuffle import door_addresses, exit_ids JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = 'f6be3fdaac906a2217e7ee328e27b95b' +RANDOMIZERBASEHASH = '87fb1ec80d48487a84eac3a0a9bf9e04' class JsonRom(object): @@ -648,16 +648,17 @@ def patch_rom(world, rom, player, team, enemized): for name, layout in world.key_layout[player].items(): offset = compass_data[name][4]//2 if world.retro[player]: - rom.write_byte(0x13f02a+offset, layout.max_chests + layout.max_drops) + rom.write_byte(0x13f030+offset, layout.max_chests + layout.max_drops) else: - rom.write_byte(0x13f01c+offset, layout.max_chests + layout.max_drops) # not currently used - rom.write_byte(0x13f02a+offset, layout.max_chests) + rom.write_byte(0x13f020+offset, layout.max_chests + layout.max_drops) # not currently used + rom.write_byte(0x13f030+offset, layout.max_chests) builder = world.dungeon_layouts[player][name] - rom.write_byte(0x13f070+offset, builder.location_cnt % 10) - rom.write_byte(0x13f07e+offset, builder.location_cnt // 10) + rom.write_byte(0x13f080+offset, builder.location_cnt % 10) + rom.write_byte(0x13f090+offset, builder.location_cnt // 10) + rom.write_byte(0x13f0a0+offset, builder.location_cnt) bk_status = 1 if builder.bk_required else 0 bk_status = 2 if builder.bk_provided else bk_status - rom.write_byte(0x13f038+offset*2, bk_status) + rom.write_byte(0x13f040+offset*2, bk_status) if player in world.sanc_portal.keys(): rom.write_byte(0x159a6, world.sanc_portal[player].ent_offset) sanc_region = world.sanc_portal[player].door.entrance.parent_region @@ -1282,7 +1283,21 @@ def patch_rom(world, rom, player, team, enemized): rom.write_byte(0x18005F, world.crystals_needed_for_ganon[player]) # block HC upstairs doors in rain state in standard mode - rom.write_byte(0x18008A, 0x01 if world.mode[player] == "standard" and world.shuffle[player] != 'vanilla' else 0x00) + prevent_rain = world.mode[player] == "standard" and world.shuffle[player] != 'vanilla' + rom.write_byte(0x18008A, 0x01 if prevent_rain else 0x00) + # block sanc door in rain state and the dungeon is not vanilla + rom.write_byte(0x13f0fa, 0x01 if world.mode[player] == "standard" and world.doorShuffle[player] != 'vanilla' else 0x00) + + if prevent_rain: + portals = [world.get_portal('Hyrule Castle East', player), world.get_portal('Hyrule Castle West', player)] + for idx, portal in enumerate(portals): + x = idx*2 + room_idx = portal.door.roomIndex + room = world.get_room(room_idx, player) + rom.write_byte(0x13f0f0+x, room_idx & 0xff) + rom.write_byte(0x13f0f1+x, (room_idx >> 8) & 0xff) + rom.write_byte(0x13f0f6+x, room.position(portal.door).value) + rom.write_byte(0x13f0f7+x, room.kind(portal.door).value) rom.write_byte(0x18016A, 0x10 | ((0x01 if world.keyshuffle[player] else 0x00) | (0x02 if world.compassshuffle[player] else 0x00) @@ -1415,9 +1430,11 @@ def patch_rom(world, rom, player, team, enemized): # fix trock doors for reverse entrances if world.fix_trock_doors[player]: - # do this unconditionally - world.get_room(0x23, player).change(0, DoorKind.CaveEntrance) - world.get_room(0xd5, player).change(0, DoorKind.CaveEntrance) + if world.get_door('TR Lazy Eyes SE', player).entranceFlag: + world.get_room(0x23, player).change(0, DoorKind.CaveEntrance) + if world.get_door('TR Eye Bridge SW', player).entranceFlag: + world.get_room(0xd5, player).change(0, DoorKind.CaveEntrance) + # do this unconditionally - gets overwritten by RoomData in doorShufflemodes rom.write_byte(0xFED31, 0x0E) # preopen bombable exit rom.write_byte(0xFEE41, 0x0E) # preopen bombable exit diff --git a/RoomData.py b/RoomData.py index c9bd6475..ac740c90 100644 --- a/RoomData.py +++ b/RoomData.py @@ -263,6 +263,9 @@ class Room(object): self.modified = False self.palette = None + def position(self, door): + return self.doorList[door.doorListPos][0] + def kind(self, door): return self.doorList[door.doorListPos][1] diff --git a/Rules.py b/Rules.py index 606e2c3d..bfae85ed 100644 --- a/Rules.py +++ b/Rules.py @@ -832,10 +832,13 @@ def standard_rules(world, player): set_rule(world.get_entrance('Sanctuary S&Q', player), lambda state: state.can_reach('Sanctuary', 'Region', player)) # these are because of rails if world.shuffle[player] != 'vanilla': - # todo: - set_rule(world.get_entrance('Hyrule Castle Exit (East)', player), lambda state: state.has('Zelda Delivered', player)) - set_rule(world.get_entrance('Hyrule Castle Exit (West)', player), lambda state: state.has('Zelda Delivered', player)) - set_rule(world.get_entrance('Sanctuary Exit', player), lambda state: state.has('Zelda Delivered', player)) + # where ever these happen to be + for portal_name in ['Hyrule Castle East', 'Hyrule Castle West']: + entrance = world.get_portal(portal_name, player).door.entrance + set_rule(entrance, lambda state: state.has('Zelda Delivered', player)) + set_rule(world.get_entrance('Sanctuary Exit', player), lambda state: state.has('Zelda Delivered', player)) + # zelda should be saved before agahnim is in play + set_rule(world.get_location('Agahnim 1', player), lambda state: state.has('Zelda Delivered', player)) # too restrictive for crossed? def uncle_item_rule(item): diff --git a/asm/doortables.asm b/asm/doortables.asm index 73a07c1d..40276be2 100644 --- a/asm/doortables.asm +++ b/asm/doortables.asm @@ -562,23 +562,26 @@ db $01, $02, $03, $04, $05, $06, $0a, $14 ; HC HC EP DP AT SP PD MM SW IP TH TT TR GT org $27f000 CompassBossIndicator: -dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 -TotalKeys: ;27f01c -db $04, $04, $02, $04, $04, $06, $06, $06, $05, $06, $01, $03, $06, $08 -ChestKeys: ;27f02a -db $01, $01, $00, $01, $02, $01, $06, $03, $03, $02, $01, $01, $04, $04 -BigKeyStatus: ;27f038 (status 2 indicate BnC guard) -dw $0002, $0002, $0001, $0001, $0000, $0001, $0001, $0001, $0001, $0001, $0001, $0001, $0001, $0001 -DungeonReminderTable: ;27f054 -dw $2D50, $2D50, $2D51, $2D52, $2D54, $2D56, $2D55, $2D5A, $2D57, $2D59, $2D53, $2D58, $2D5B, $2D5C -TotalLocationsLow: ;27f070 -db $08, $08, $06, $06, $02, $00, $04, $08, $08, $08, $06, $08, $02, $07 -TotalLocationsHigh: ;27f07e -db $00, $00, $00, $00, $00, $01, $01, $00, $00, $00, $00, $00, $01, $02 -;27F08C +dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 +TotalKeys: ;27f020 +db $04, $04, $02, $04, $04, $06, $06, $06, $05, $06, $01, $03, $06, $08, $00, $00 +ChestKeys: ;27f030 +db $01, $01, $00, $01, $02, $01, $06, $03, $03, $02, $01, $01, $04, $04, $00, $00 +BigKeyStatus: ;27f040 (status 2 indicate BnC guard) +dw $0002, $0002, $0001, $0001, $0000, $0001, $0001, $0001, $0001, $0001, $0001, $0001, $0001, $0001, $0000, $0000 +DungeonReminderTable: ;27f060 +dw $2D50, $2D50, $2D51, $2D52, $2D54, $2D56, $2D55, $2D5A, $2D57, $2D59, $2D53, $2D58, $2D5B, $2D5C, $0000, $0000 +TotalLocationsLow: ;27f080 +db $08, $08, $06, $06, $02, $00, $04, $08, $08, $08, $06, $08, $02, $07, $00, $00 +TotalLocationsHigh: ;27f090 +db $00, $00, $00, $00, $00, $01, $01, $00, $00, $00, $00, $00, $01, $02, $00, $00 +org $27f0a0 +TotalLocations: +db $08, $08, $06, $06, $02, $0a, $0e, $08, $08, $08, $06, $08, $0c, $1b, $00, $00 +; no more room here ; Vert 0,6,0 Horz 2,0,8 -org $27f090 +org $27f0b0 CoordIndex: ; Horizontal 1st db 2, 0 ; Coordinate Index $20-$23 OppCoordIndex: @@ -598,7 +601,16 @@ dw $007f, $0077 ; Left/Top camera bounds when at edge or layout frozen dw $0007, $000b ; Left/Top camera bounds when not frozen + appropriate low byte $22/$20 (preadj. by #$78/#$6c) dw $00ff, $010b ; Right/Bot camera bounds when not frozen + appropriate low byte $20/$22 dw $017f, $0187 ; Right/Bot camera bound when at edge or layout frozen -;27f0ae next free byte +;27f0ce next free byte + +org $27f0f0 +RemoveRainDoorsRoom: +dw $0060, $0062, $ffff ; ffff indicates end of list +RainDoorMatch: ; org $27f0f6 and f8 for now +dw $0081, $0061 ; not xba'd +BlockSanctuaryDoorInRain: ;27f0fa +dw $0000 + org $27f100 TilesetTable: diff --git a/asm/drhooks.asm b/asm/drhooks.asm index bde005d5..43802ce7 100644 --- a/asm/drhooks.asm +++ b/asm/drhooks.asm @@ -156,6 +156,9 @@ JSL RetrieveBunnyState : NOP org $02d9ce ; <- Bank02.asm : Dungeon_LoadEntrance 10829 (STA $A0 : STA $048E) JSL CheckDarkWorldSanc : NOP +org $01891e ; <- Bank 01.asm : 991 Dungeon_LoadType2Object (LDA $00 : XBA : AND.w #$00FF) +JSL RainPrevention : NOP #2 + ; 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/hudadditions.asm b/asm/hudadditions.asm index 4e5b316b..29da1e8c 100644 --- a/asm/hudadditions.asm +++ b/asm/hudadditions.asm @@ -95,12 +95,18 @@ DrHudDungeonItemsAdditions: + stx $00 txa : lsr : tax lda.w #$24f5 : sta $1644, y - lda.l $7ef37c, x : beq + + lda.l GenericKeys : bne + + lda.l $7ef37c, x : and #$00FF : beq + jsr ConvertToDisplay2 : sta $1644, y + iny #2 : lda.w #$24f5 : sta $1644, y phx : ldx $00 lda $7ef368 : and.l $0098c0, x : beq + ; must have map - plx : lda.l ChestKeys, x : jsr ConvertToDisplay2 : sta $1644, y ; small key totals + plx : sep #$30 : lda.l ChestKeys, x : sta $02 + lda.l GenericKeys : bne +++ + lda $02 : !sub $7ef4e0, x : sta $02 + +++ lda $02 + rep #$30 + jsr ConvertToDisplay2 : sta $1644, y ; small key totals bra .skipStack + plx .skipStack iny #2 @@ -131,15 +137,18 @@ DrHudDungeonItemsAdditions: + lda $7ef364 : and.l $0098c0, x : beq + ; must have compass phx ; total chest counts txa : lsr : tax - lda.l TotalLocationsHigh, x : jsr ConvertToDisplay2 : sta $1644, y : iny #2 - lda.l TotalLocationsLow, x : jsr ConvertToDisplay2 : sta $1644, y + sep #$30 + lda.l TotalLocations, x : !sub $7EF4BF, x : JSR HudHexToDec2DigitCopy + rep #$30 + lda $06 : jsr ConvertToDisplay2 : sta $1644, y : iny #2 + lda $07 : jsr ConvertToDisplay2 : sta $1644, y plx bra .skipBlanks + lda.w #$24f5 : sta $1644, y : iny #2 : sta $1644, y .skipBlanks iny #2 cpx #$001a : beq + lda.w #$24f5 : sta $1644, y ; blank out spot - + inx #2 : cpx #$001b : bcc - + + inx #2 : cpx #$001b : !bge ++ : brl - ++ plp : ply : plx : rtl } @@ -203,4 +212,27 @@ HudHexToDec4DigitCopy: DEC : BNE - + STY $07 ; Store 1s digit +RTS + +;================================================================================ +; 8-bit registers +; in: A(b) - Byte to Convert +; out: $06 - $07 (high - low) +;================================================================================ +HudHexToDec2DigitCopy: ; modified + PHY + LDY.b #$00 + - + CMP.b #10 : !BLT + + INY + SBC.b #10 : BRA - + + + STY $06 : LDY #$00 ; Store 10s digit and reset Y + CMP.b #1 : !BLT + + - + INY + DEC : BNE - + + + STY $07 ; Store 1s digit + PLY RTS \ No newline at end of file diff --git a/asm/keydropshuffle.asm b/asm/keydropshuffle.asm index f75434cf..7b64746f 100644 --- a/asm/keydropshuffle.asm +++ b/asm/keydropshuffle.asm @@ -127,7 +127,7 @@ KeyGet: phx lda $040c : lsr : tax lda $00 : cmp KeyTable, x : bne + - - plx : pla : rtl + - JSL.l FullInventoryExternal : jsl CountChestKeyLong : plx : pla : rtl + cmp #$af : beq - ; universal key cmp #$24 : beq - ; small key for this dungeon plx diff --git a/asm/overrides.asm b/asm/overrides.asm index 02955978..b29c6bc1 100644 --- a/asm/overrides.asm +++ b/asm/overrides.asm @@ -121,3 +121,22 @@ RetrieveBunnyState: LDA $5F : BEQ + STA $5D + RTL + +RainPrevention: + LDA $00 : XBA : AND #$00FF ; what we wrote over + PHA + LDA $7EF3C5 : AND #$00FF : CMP #$0002 : !BGE .done ; only in rain states (0 or 1) + LDA.l $7EF3C6 : AND #$0004 : BNE .done ; zelda's been rescued + LDA.l BlockSanctuaryDoorInRain : BEQ .done ;flagged + LDA $A0 : CMP #$0012 : BNE + ;we're in the sanctuary + LDA.l $7EF3CC : AND #$00FF : CMP #$0001 : BEQ .done ; zelda is following + LDA $00 : CMP #$02A1 : BNE .done + PLA : LDA #$0008 : RTL + + LDA.l BlockCastleDoorsInRain : BEQ .done ;flagged + LDX #$FFFE + - INX #2 : LDA.l RemoveRainDoorsRoom, X : CMP #$FFFF : BEQ .done + CMP $A0 : BNE - + LDA.l RainDoorMatch, X : CMP $00 : BNE - + PLA : LDA #$0008 : RTL + .done PLA : RTL + diff --git a/data/base2current.bps b/data/base2current.bps index 35790ec8..165e57dd 100644 Binary files a/data/base2current.bps and b/data/base2current.bps differ