Fix trock entrances when intensity >= 3

Keysanity menu countdowns
Standard rain state
Multi-entrance dungeon bosses
This dungeon/universl key drops skip pose
More rupee candidates to remove for retro
This commit is contained in:
aerinon
2020-11-19 16:26:45 -07:00
parent b8dc174f87
commit f5327bc0e6
12 changed files with 256 additions and 64 deletions

View File

@@ -1499,6 +1499,10 @@ class Portal(object):
self.deadEnd = False self.deadEnd = False
self.light_world = 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): def change_door(self, new_door):
if new_door != self.door: if new_door != self.door:
self.default = False self.default = False

View File

@@ -369,6 +369,9 @@ def choose_portals(world, player):
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)
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(): for target_region, possible_portals in info.required_passage.items():
candidates = find_portal_candidates(master_door_list, dungeon, need_passage=True, crossed=cross_flag, candidates = find_portal_candidates(master_door_list, dungeon, need_passage=True, crossed=cross_flag,
bk_shuffle=bk_shuffle) 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())] filtered_choices = [x for x in choices if any(y not in world.inaccessible_regions[player] for y in originating[key][x].keys())]
else: else:
filtered_choices = dest_choices filtered_choices = dest_choices
if len(filtered_choices) == 0:
raise Exception('No valid destinations')
choice = random.choice(filtered_choices) choice = random.choice(filtered_choices)
r_name = portal.door.entrance.parent_region.name r_name = portal.door.entrance.parent_region.name
split_map[key][choice].append(r_name) split_map[key][choice].append(r_name)
@@ -650,6 +655,8 @@ def within_dungeon(world, player):
target = portal.door.entrance.parent_region target = portal.door.entrance.parent_region
connect_simple_door(world, 'Sanctuary Mirror Route', target, player) 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): def handle_split_dungeons(dungeon_builders, recombinant_builders, entrances_map, builder_info):
dungeon_entrances, split_dungeon_entrances, world, player = builder_info dungeon_entrances, split_dungeon_entrances, world, player = builder_info
@@ -943,6 +950,7 @@ def cross_dungeon(world, player):
palette_assignment(world, player) palette_assignment(world, player)
refine_hints(dungeon_builders) refine_hints(dungeon_builders)
refine_boss_exits(world, player)
def assign_cross_keys(dungeon_builders, 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] 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): def convert_to_sectors(region_names, world, player):
region_list = convert_regions(region_names, world, player) region_list = convert_regions(region_names, world, player)
sectors = [] sectors = []
@@ -1806,6 +1852,15 @@ def explore_state(state, world, player):
state.add_all_doors_check_unattached(connect_region, 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): def check_if_regions_visited(state, check_paths):
valid = False valid = False
breaking_region = None breaking_region = None

View File

@@ -1,34 +1,78 @@
# New Features # New Features
* Lobby shuffle added as Intensity level 3 ## Lobby shuffle added as Intensity level 3
* Can now be found in the spoiler
* Palette changes: * Standard notes:
* Certain doors/transition no longer have an effect on the palette choice (dead ends mostly or just bridges) * The sanctuary is vanilla, and will be missing the exit door until Zelda is rescued
* Sanctuary palette back to the adjacent rooms to Sanctuary (sanctuary stays the dungeon color for now) * In entrance shuffle the hyrule castle left and right exit door will be missing until Zelda is rescued. This
* Sewer palette comes back for part of Hyrule Castle for areas "near" the sewer dropdown replaces the rails that used to block those lobby exits
* Known issues: * In non-entrance shuffle, Agahnims tower can be in logic if you have cape and/or Master sword, but you are never
* Palettes aren't perfect required to beat Agahnim 1 until Zelda is rescued.
May add a way to turn off palette "fixing" * Open notes:
* Some ugly colors * The Sanctuary is limited to be in a LW dungeon unless you have ER Crossed or higher enabled
* Invisible floors can be see in many palettes * Mirroring from the Sanctuary to the new "Sanctuary" lobby is now in logic, as is exiting there.
* --keydropshuffle added (coming to the GUI soon). This add 33 new locations to the game where keys are found under pots * 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 and where enemies drop keys. This includes 32 small key location and the ball and chain guard who normally drop the HC
Big Key. Big Key.
* Overall location count updated
* Setting mentioned in spoiler * Overall location count updated
* Known issue: * Setting mentioned in spoiler
* GT Big Key count needs to be updated * Minor change: if a key is Universal or for that dungeon, then if will use the old mechanics of picking up the key without
* --mixed_travel setting added an entire pose and should be obtainable with the hookshot or boomerang as before
* Due to Hammerjump, Hovering in PoD Arena, and the Mire Big Key Chest bomb jump two sections of a supertile that are
## --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 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 * 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. 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. * 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. * 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 ### 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 #### Temporary debug features
@@ -37,12 +81,12 @@ otherwise unconnected logically can be reach using these glitches. To prevent th
# Bug Fixes # Bug Fixes
* 2.0.12u * 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) * Another fix for animated tiles (fairy fountains)
* GT Big Key stat fixed on credits * 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 * 2.0.11u
* Fix output path setting in settings.json * Fix output path setting in settings.json
* Fix trock entrances when intensity <= 2 * Fix trock entrances when intensity <= 2

39
Rom.py
View File

@@ -26,7 +26,7 @@ from EntranceShuffle import door_addresses, exit_ids
JAP10HASH = '03a63945398191337e896e5771f77173' JAP10HASH = '03a63945398191337e896e5771f77173'
RANDOMIZERBASEHASH = 'f6be3fdaac906a2217e7ee328e27b95b' RANDOMIZERBASEHASH = '87fb1ec80d48487a84eac3a0a9bf9e04'
class JsonRom(object): class JsonRom(object):
@@ -648,16 +648,17 @@ def patch_rom(world, rom, player, team, enemized):
for name, layout in world.key_layout[player].items(): for name, layout in world.key_layout[player].items():
offset = compass_data[name][4]//2 offset = compass_data[name][4]//2
if world.retro[player]: 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: else:
rom.write_byte(0x13f01c+offset, layout.max_chests + layout.max_drops) # not currently used rom.write_byte(0x13f020+offset, layout.max_chests + layout.max_drops) # not currently used
rom.write_byte(0x13f02a+offset, layout.max_chests) rom.write_byte(0x13f030+offset, layout.max_chests)
builder = world.dungeon_layouts[player][name] builder = world.dungeon_layouts[player][name]
rom.write_byte(0x13f070+offset, builder.location_cnt % 10) rom.write_byte(0x13f080+offset, builder.location_cnt % 10)
rom.write_byte(0x13f07e+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 = 1 if builder.bk_required else 0
bk_status = 2 if builder.bk_provided else bk_status 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(): if player in world.sanc_portal.keys():
rom.write_byte(0x159a6, world.sanc_portal[player].ent_offset) rom.write_byte(0x159a6, world.sanc_portal[player].ent_offset)
sanc_region = world.sanc_portal[player].door.entrance.parent_region 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]) rom.write_byte(0x18005F, world.crystals_needed_for_ganon[player])
# block HC upstairs doors in rain state in standard mode # 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) rom.write_byte(0x18016A, 0x10 | ((0x01 if world.keyshuffle[player] else 0x00)
| (0x02 if world.compassshuffle[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 # fix trock doors for reverse entrances
if world.fix_trock_doors[player]: if world.fix_trock_doors[player]:
# do this unconditionally if world.get_door('TR Lazy Eyes SE', player).entranceFlag:
world.get_room(0x23, player).change(0, DoorKind.CaveEntrance) world.get_room(0x23, player).change(0, DoorKind.CaveEntrance)
world.get_room(0xd5, 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(0xFED31, 0x0E) # preopen bombable exit
rom.write_byte(0xFEE41, 0x0E) # preopen bombable exit rom.write_byte(0xFEE41, 0x0E) # preopen bombable exit

View File

@@ -263,6 +263,9 @@ class Room(object):
self.modified = False self.modified = False
self.palette = None self.palette = None
def position(self, door):
return self.doorList[door.doorListPos][0]
def kind(self, door): def kind(self, door):
return self.doorList[door.doorListPos][1] return self.doorList[door.doorListPos][1]

View File

@@ -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)) set_rule(world.get_entrance('Sanctuary S&Q', player), lambda state: state.can_reach('Sanctuary', 'Region', player))
# these are because of rails # these are because of rails
if world.shuffle[player] != 'vanilla': if world.shuffle[player] != 'vanilla':
# todo: # where ever these happen to be
set_rule(world.get_entrance('Hyrule Castle Exit (East)', player), lambda state: state.has('Zelda Delivered', player)) for portal_name in ['Hyrule Castle East', 'Hyrule Castle West']:
set_rule(world.get_entrance('Hyrule Castle Exit (West)', player), lambda state: state.has('Zelda Delivered', player)) entrance = world.get_portal(portal_name, player).door.entrance
set_rule(world.get_entrance('Sanctuary Exit', player), lambda state: state.has('Zelda Delivered', player)) 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? # too restrictive for crossed?
def uncle_item_rule(item): def uncle_item_rule(item):

View File

@@ -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 ; HC HC EP DP AT SP PD MM SW IP TH TT TR GT
org $27f000 org $27f000
CompassBossIndicator: CompassBossIndicator:
dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000
TotalKeys: ;27f01c TotalKeys: ;27f020
db $04, $04, $02, $04, $04, $06, $06, $06, $05, $06, $01, $03, $06, $08 db $04, $04, $02, $04, $04, $06, $06, $06, $05, $06, $01, $03, $06, $08, $00, $00
ChestKeys: ;27f02a ChestKeys: ;27f030
db $01, $01, $00, $01, $02, $01, $06, $03, $03, $02, $01, $01, $04, $04 db $01, $01, $00, $01, $02, $01, $06, $03, $03, $02, $01, $01, $04, $04, $00, $00
BigKeyStatus: ;27f038 (status 2 indicate BnC guard) BigKeyStatus: ;27f040 (status 2 indicate BnC guard)
dw $0002, $0002, $0001, $0001, $0000, $0001, $0001, $0001, $0001, $0001, $0001, $0001, $0001, $0001 dw $0002, $0002, $0001, $0001, $0000, $0001, $0001, $0001, $0001, $0001, $0001, $0001, $0001, $0001, $0000, $0000
DungeonReminderTable: ;27f054 DungeonReminderTable: ;27f060
dw $2D50, $2D50, $2D51, $2D52, $2D54, $2D56, $2D55, $2D5A, $2D57, $2D59, $2D53, $2D58, $2D5B, $2D5C dw $2D50, $2D50, $2D51, $2D52, $2D54, $2D56, $2D55, $2D5A, $2D57, $2D59, $2D53, $2D58, $2D5B, $2D5C, $0000, $0000
TotalLocationsLow: ;27f070 TotalLocationsLow: ;27f080
db $08, $08, $06, $06, $02, $00, $04, $08, $08, $08, $06, $08, $02, $07 db $08, $08, $06, $06, $02, $00, $04, $08, $08, $08, $06, $08, $02, $07, $00, $00
TotalLocationsHigh: ;27f07e TotalLocationsHigh: ;27f090
db $00, $00, $00, $00, $00, $01, $01, $00, $00, $00, $00, $00, $01, $02 db $00, $00, $00, $00, $00, $01, $01, $00, $00, $00, $00, $00, $01, $02, $00, $00
;27F08C 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 ; Vert 0,6,0 Horz 2,0,8
org $27f090 org $27f0b0
CoordIndex: ; Horizontal 1st CoordIndex: ; Horizontal 1st
db 2, 0 ; Coordinate Index $20-$23 db 2, 0 ; Coordinate Index $20-$23
OppCoordIndex: 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 $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 $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 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 org $27f100
TilesetTable: TilesetTable:

View File

@@ -156,6 +156,9 @@ JSL RetrieveBunnyState : NOP
org $02d9ce ; <- Bank02.asm : Dungeon_LoadEntrance 10829 (STA $A0 : STA $048E) org $02d9ce ; <- Bank02.asm : Dungeon_LoadEntrance 10829 (STA $A0 : STA $048E)
JSL CheckDarkWorldSanc : NOP 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 ; 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

@@ -95,12 +95,18 @@ DrHudDungeonItemsAdditions:
+ stx $00 + stx $00
txa : lsr : tax txa : lsr : tax
lda.w #$24f5 : sta $1644, y 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 jsr ConvertToDisplay2 : sta $1644, y
+ iny #2 : lda.w #$24f5 : sta $1644, y + iny #2 : lda.w #$24f5 : sta $1644, y
phx : ldx $00 phx : ldx $00
lda $7ef368 : and.l $0098c0, x : beq + ; must have map 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 bra .skipStack
+ plx + plx
.skipStack iny #2 .skipStack iny #2
@@ -131,15 +137,18 @@ DrHudDungeonItemsAdditions:
+ lda $7ef364 : and.l $0098c0, x : beq + ; must have compass + lda $7ef364 : and.l $0098c0, x : beq + ; must have compass
phx ; total chest counts phx ; total chest counts
txa : lsr : tax txa : lsr : tax
lda.l TotalLocationsHigh, x : jsr ConvertToDisplay2 : sta $1644, y : iny #2 sep #$30
lda.l TotalLocationsLow, x : jsr ConvertToDisplay2 : sta $1644, y 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 plx
bra .skipBlanks bra .skipBlanks
+ lda.w #$24f5 : sta $1644, y : iny #2 : sta $1644, y + lda.w #$24f5 : sta $1644, y : iny #2 : sta $1644, y
.skipBlanks iny #2 .skipBlanks iny #2
cpx #$001a : beq + cpx #$001a : beq +
lda.w #$24f5 : sta $1644, y ; blank out spot lda.w #$24f5 : sta $1644, y ; blank out spot
+ inx #2 : cpx #$001b : bcc - + inx #2 : cpx #$001b : !bge ++ : brl -
++ ++
plp : ply : plx : rtl plp : ply : plx : rtl
} }
@@ -203,4 +212,27 @@ HudHexToDec4DigitCopy:
DEC : BNE - DEC : BNE -
+ +
STY $07 ; Store 1s digit 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 RTS

View File

@@ -127,7 +127,7 @@ KeyGet:
phx phx
lda $040c : lsr : tax lda $040c : lsr : tax
lda $00 : cmp KeyTable, x : bne + lda $00 : cmp KeyTable, x : bne +
- plx : pla : rtl - JSL.l FullInventoryExternal : jsl CountChestKeyLong : plx : pla : rtl
+ cmp #$af : beq - ; universal key + cmp #$af : beq - ; universal key
cmp #$24 : beq - ; small key for this dungeon cmp #$24 : beq - ; small key for this dungeon
plx plx

View File

@@ -121,3 +121,22 @@ RetrieveBunnyState:
LDA $5F : BEQ + LDA $5F : BEQ +
STA $5D STA $5D
+ RTL + 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

Binary file not shown.