def fixAll(rom): # Prevent soft locking in the first mountain cave if we do not have a feather re = RoomEditor(rom, 0x2B7) re.removeObject(3, 3) re.store(rom) # Prevent getting stuck in the sidescroll room in the beginning of dungeon 5 re = RoomEditor(rom, 0x1A9) re.objects[6].count = 7 re.store(rom) # Cave that allows you to escape from D4 without flippers, make it no longer require a feather re = RoomEditor(rom, 0x1EA) re.objects[9].count = 8 re.removeObject(5, 4) re.moveObject(4, 4, 7, 5) re.store(rom) # D3 west side room requires feather to get the key. But feather is not required to unlock the door, potentially softlocking you. re = RoomEditor(rom, 0x155) re.changeObject(4, 1, 0xcf) re.changeObject(4, 6, 0xd0) re.store(rom) # D3 boots room requires boots to escape re = RoomEditor(rom, 0x146) re.removeObject(5, 6) re.store(rom) allowRaftGameWithoutFlippers(rom) # We cannot access thes holes in logic: # removeBirdKeyHoleDrop(rom) fixDoghouse(rom) flameThrowerShieldRequirement(rom) fixLessThen3MaxHealth(rom)
def addBetaRoom(rom): re = RoomEditor(rom, 0x1FC) re.objects[-1].target_y -= 0x10 re.store(rom) re = RoomEditor(rom, 0x038) re.changeObject(5, 1, 0xE1) re.removeObject(0, 0) re.removeObject(0, 1) re.removeObject(0, 2) re.removeObject(6, 1) re.objects.append(ObjectVertical(0, 0, 0x38, 3)) re.objects.append(ObjectWarp(1, 0x1F, 0x1FC, 0x50, 0x7C)) re.store(rom) rom.room_sprite_data_indoor[0x0FC] = rom.room_sprite_data_indoor[0x1A1]
def allowRaftGameWithoutFlippers(rom): # Allow jumping down the waterfall in the raft game without the flippers. rom.patch(0x02, 0x2E8F, ASM("ld a, [$DB0C]"), ASM("ld a, $01"), fill_nop=True) # Change the room that goes back up to the raft game from the bottom, so we no longer need flippers re = RoomEditor(rom, 0x1F7) re.changeObject(3, 2, 0x1B) re.changeObject(2, 3, 0x1B) re.changeObject(3, 4, 0x1B) re.changeObject(4, 5, 0x1B) re.changeObject(6, 6, 0x1B) re.store(rom)
def getCleanBossRoom(rom, dungeon_nr): re = RoomEditor(rom, BOSS_ROOMS[dungeon_nr][0]) new_objects = [] for obj in re.objects: if isinstance(obj, ObjectWarp): continue if obj.type_id == 0xBE: # Remove staircases continue if obj.type_id == 0x06: # Remove lava continue if obj.type_id == 0x1c: # Change D1 pits into normal pits obj.type_id = 0x01 if obj.type_id == 0x1e: # Change D1 pits into normal pits obj.type_id = 0xaf if obj.type_id == 0x1f: # Change D1 pits into normal pits obj.type_id = 0xb0 if obj.type_id == 0xF5: # Change open doors into closing doors. obj.type_id = 0xF1 new_objects.append(obj) # Make D4 room a valid fighting room by removing most content. if dungeon_nr == 3: new_objects = new_objects[:2] + [ Object(1, 1, 0xAC), Object(8, 1, 0xAC), Object(1, 6, 0xAC), Object(8, 6, 0xAC) ] # D7 has an empty room we use for most bosses, but it needs some adjustments. if dungeon_nr == 6: # Move around the unused and instrument room. rom.banks[0x14][0x03a0 + 6 + 1 * 8] = 0x00 rom.banks[0x14][0x03a0 + 7 + 2 * 8] = 0x2C rom.banks[0x14][0x03a0 + 7 + 3 * 8] = 0x23 rom.banks[0x14][0x03a0 + 6 + 5 * 8] = 0x00 rom.banks[0x14][0x0520 + 7 + 2 * 8] = 0x2C rom.banks[0x14][0x0520 + 7 + 3 * 8] = 0x23 rom.banks[0x14][0x0520 + 6 + 5 * 8] = 0x00 re.floor_object &= 0x0F new_objects += [ Object(4, 0, 0xF0), Object(1, 6, 0xBE), ObjectWarp(1, dungeon_nr, 0x22E, 24, 16) ] # Set the stairs towards the eagle tower top to our new room. r = RoomEditor(rom, 0x22E) r.objects[-1] = ObjectWarp(1, dungeon_nr, re.room, 24, 112) r.store(rom) # Remove the normal door to the instrument room r = RoomEditor(rom, 0x22e) r.removeObject(4, 0) r.store(rom) rom.banks[0x14][0x22e - 0x100] = 0x00 r = RoomEditor(rom, 0x22c) r.changeObject(0, 7, 0x03) r.changeObject(2, 7, 0x03) r.store(rom) re.objects = new_objects re.entities = [] return re
def fixBowwow(rom, everywhere=False): ### BowWow patches rom.patch(0x03, 0x1E0E, ASM("ld [$DB56], a"), "", fill_nop=True ) # Do not mark BowWow as kidnapped after we complete dungeon 1. rom.patch(0x15, 0x06B6, ASM("ld a, [$DB56]\ncp $80"), ASM("xor a"), fill_nop=True) # always load the moblin boss rom.patch(0x03, 0x182D, ASM("ld a, [$DB56]\ncp $80"), ASM("ld a, [$DAE2]\nand $10") ) # load the cave moblins if the chest is not opened rom.patch(0x07, 0x3947, ASM("ld a, [$DB56]\ncp $80"), ASM("ld a, [$DAE2]\nand $10") ) # load the cave moblin with sword if the chest is not opened # Modify the moblin cave to contain a chest at the end, which contains bowwow re = RoomEditor(rom, 0x2E2) re.removeEntities(0x6D) re.changeObject(8, 3, 0xA0) re.store(rom) # Place bowwow in the chest table rom.banks[0x14][0x560 + 0x2E2] = 0x81 # Patch bowwow follower sprite to be used from 2nd vram bank rom.patch( 0x05, 0x001C, b"40034023" b"42034223" b"44034603" b"48034A03" b"46234423" b"4A234823" b"4C034C23", b"500B502B" b"520B522B" b"540B560B" b"580B5A0B" b"562B542B" b"5A2B582B" b"5C0B5C2B") # Patch to use the chain sprite from second vram bank (however, the chain bugs out various things) rom.patch( 0x05, 0x0282, ASM("ld a, $4E\njr nz, $02\nld a, $7E\nld [de], a\ninc de\nld a, $00"), ASM("ld a, $5E\nld [de], a\ninc de\nld a, $08"), fill_nop=True) # Never load the bowwow tiles in the first VRAM bank, as we do not need them. rom.patch(0x00, 0x2EB0, ASM("ld a, [$DB56]\ncp $01\nld a, $A4\njr z, $18"), "", fill_nop=True) # Patch the location where bowwow stores chain X/Y positions so it does not conflict with a lot of other things rom.patch(0x05, 0x00BE, ASM("ld hl, $D100"), ASM("ld hl, $D180")) rom.patch(0x05, 0x0275, ASM("ld hl, $D100"), ASM("ld hl, $D180")) rom.patch(0x05, 0x03AD, ASM("ld [$D100], a"), ASM("ld [$D180], a")) rom.patch(0x05, 0x03BD, ASM("ld de, $D100"), ASM("ld de, $D180")) rom.patch(0x05, 0x049F, ASM("ld hl, $D100"), ASM("ld hl, $D180")) rom.patch(0x05, 0x04C2, ASM("ld a, [$D100]"), ASM("ld a, [$D180]")) rom.patch(0x05, 0x03C0, ASM("ld hl, $D101"), ASM("ld hl, $D181")) rom.patch(0x05, 0x0418, ASM("ld [$D106], a"), ASM("ld [$D186], a")) rom.patch(0x05, 0x0423, ASM("ld de, $D106"), ASM("ld de, $D186")) rom.patch(0x05, 0x0426, ASM("ld hl, $D105"), ASM("ld hl, $D185")) rom.patch(0x19, 0x3A4E, ASM("ld hl, $D100"), ASM("ld hl, $D180")) rom.patch(0x19, 0x3A5A, ASM("ld hl, $D110"), ASM("ld hl, $D190")) rom.patch(0x05, 0x00D9, ASM("ld hl, $D110"), ASM("ld hl, $D190")) rom.patch(0x05, 0x026E, ASM("ld hl, $D110"), ASM("ld hl, $D190")) rom.patch(0x05, 0x03BA, ASM("ld [$D110], a"), ASM("ld [$D190], a")) rom.patch(0x05, 0x03DD, ASM("ld de, $D110"), ASM("ld de, $D190")) rom.patch(0x05, 0x0480, ASM("ld hl, $D110"), ASM("ld hl, $D190")) rom.patch(0x05, 0x04B5, ASM("ld a, [$D110]"), ASM("ld a, [$D190]")) rom.patch(0x05, 0x03E0, ASM("ld hl, $D111"), ASM("ld hl, $D191")) rom.patch(0x05, 0x0420, ASM("ld [$D116], a"), ASM("ld [$D196], a")) rom.patch(0x05, 0x044d, ASM("ld de, $D116"), ASM("ld de, $D196")) rom.patch(0x05, 0x0450, ASM("ld hl, $D115"), ASM("ld hl, $D195")) rom.patch(0x05, 0x0039, ASM("ld [$D154], a"), "", fill_nop=True ) # normally this stores the index to bowwow, for the kiki fight rom.patch(0x05, 0x013C, ASM("ld [$D150], a"), ASM("ld [$D197], a")) rom.patch(0x05, 0x0144, ASM("ld [$D151], a"), ASM("ld [$D198], a")) rom.patch(0x05, 0x02F9, ASM("ld [$D152], a"), ASM("ld [$D199], a")) rom.patch(0x05, 0x0335, ASM("ld a, [$D152]"), ASM("ld a, [$D199]")) rom.patch(0x05, 0x0485, ASM("ld a, [$D151]"), ASM("ld a, [$D198]")) rom.patch(0x05, 0x04A4, ASM("ld a, [$D150]"), ASM("ld a, [$D197]")) # Patch the bowwow create code to call our custom check of we are in swamp function. if everywhere: # Load followers in dungeons, caves, etc rom.patch(0x01, 0x1FC1, ASM("ret z"), "", fill_nop=True) rom.patch(0x01, 0x1FC4, ASM("ret z"), "", fill_nop=True) rom.patch(0x01, 0x1FC7, ASM("ret z"), "", fill_nop=True) rom.patch(0x01, 0x1FCA, ASM("ret c"), "", fill_nop=True) # dungeon rom.patch(0x01, 0x1FBC, ASM("ret nz"), "", fill_nop=True) # sidescroller else: # Patch the bowwow create code to call our custom check of we are in swamp function. rom.patch( 0x01, 0x211F, ASM("ldh a, [$F6]\ncp $A7\nret z\nld a, [$DB56]\ncp $01\njr nz, $36" ), ASM(""" ld a, $07 rst 8 ld a, e and a ret z """), fill_nop=True) # Patch bowwow to not stay around when we move from map to map rom.patch(0x05, 0x0049, 0x0054, ASM(""" cp [hl] jr z, Continue ld hl, $C280 add hl, bc ld [hl], b ret Continue: """), fill_nop=True) # Patch madam meow meow to not take bowwow rom.patch(0x06, 0x1BD7, ASM("ld a, [$DB66]\nand $02"), ASM("ld a, $00\nand $02"), fill_nop=True) # Patch kiki not to react to bowwow, as bowwow is not with link at this map rom.patch(0x07, 0x18A8, ASM("ld a, [$DB56]\ncp $01"), ASM("ld a, $00\ncp $01"), fill_nop=True) # Patch the color dungeon entrance not to check for bowwow rom.patch(0x02, 0x340D, ASM("ld hl, $DB56\nor [hl]"), "", fill_nop=True) # Patch richard to ignore bowwow rom.patch(0x06, 0x006C, ASM("ld a, [$DB56]"), ASM("xor a"), fill_nop=True) # Patch to modify how bowwow eats enemies, normally it just unloads them, but we call our handler in bank 3E rom.patch(0x05, 0x03A0, 0x03A8, ASM(""" push bc ld b, d ld c, e ld a, $08 rst 8 pop bc ret """), fill_nop=True) rom.patch(0x05, 0x0387, ASM("ld a, $03\nldh [$F2], a"), "", fill_nop=True) # remove the default chomp sfx # Various enemies rom.banks[0x14][0x1218 + 0xC5] = 0x01 # Urchin rom.banks[0x14][0x1218 + 0x93] = 0x01 # MadBomber rom.banks[0x14][0x1218 + 0x51] = 0x01 # Swinging ball&chain golden leaf enemy rom.banks[0x14][0x1218 + 0xF2] = 0x01 # Color dungeon flying hopper rom.banks[0x14][0x1218 + 0xF3] = 0x01 # Color dungeon hopper rom.banks[0x14][0x1218 + 0xE9] = 0x01 # Color dungeon shell rom.banks[0x14][0x1218 + 0xEA] = 0x01 # Color dungeon shell rom.banks[0x14][0x1218 + 0xEB] = 0x01 # Color dungeon shell rom.banks[0x14][0x1218 + 0xEC] = 0x01 # Color dungeon thing rom.banks[0x14][0x1218 + 0xED] = 0x01 # Color dungeon thing rom.banks[0x14][0x1218 + 0xEE] = 0x01 # Color dungeon thing rom.banks[0x14][0x1218 + 0x87] = 0x01 # Lanmola (for D4 key) rom.banks[0x14][0x1218 + 0x88] = 0x01 # Armos knight (for D6 key) rom.banks[0x14][0x1218 + 0x16] = 0x01 # Spark rom.banks[0x14][0x1218 + 0x17] = 0x01 # Spark rom.banks[0x14][0x1218 + 0x2C] = 0x01 # Spiked beetle rom.banks[0x14][0x1218 + 0x90] = 0x01 # Three of a kind (screw these guys) rom.banks[0x14][0x1218 + 0x18] = 0x01 # Pols voice rom.banks[0x14][0x1218 + 0x50] = 0x01 # Boo buddy rom.banks[0x14][0x1218 + 0xA2] = 0x01 # Pirana plant rom.banks[0x14][0x1218 + 0x52] = 0x01 # Tractor device rom.banks[0x14][0x1218 + 0x53] = 0x01 # Tractor device (D3) rom.banks[0x14][0x1218 + 0x55] = 0x01 # Bounding bombite rom.banks[0x14][0x1218 + 0x56] = 0x01 # Timer bombite rom.banks[0x14][0x1218 + 0x57] = 0x01 # Pairod rom.banks[0x14][0x1218 + 0x15] = 0x01 # Antifairy rom.banks[0x14][0x1218 + 0xA0] = 0x01 # Peahat rom.banks[0x14][0x1218 + 0x9C] = 0x01 # Star rom.banks[0x14][0x1218 + 0xA1] = 0x01 # Snake rom.banks[0x14][0x1218 + 0xBD] = 0x01 # Vire rom.banks[0x14][0x1218 + 0xE4] = 0x01 # Moblin boss # Bosses rom.banks[0x14][0x1218 + 0x59] = 0x01 # Moldorm rom.banks[0x14][0x1218 + 0x5C] = 0x01 # Genie rom.banks[0x14][0x1218 + 0x5B] = 0x01 # Slime Eye rom.patch(0x04, 0x0AC4, ASM("ld [hl], $28"), ASM("ld [hl], $FF")) # give more time before slimeeye unsplits rom.patch(0x04, 0x0B05, ASM("ld [hl], $50"), ASM("ld [hl], $FF")) # give more time before slimeeye unsplits rom.banks[0x14][0x1218 + 0x65] = 0x01 # Angler fish rom.banks[0x14][0x1218 + 0x5D] = 0x01 # Slime eel rom.banks[0x14][0x1218 + 0x5A] = 0x01 # Facade rom.banks[0x14][0x1218 + 0x63] = 0x01 # Eagle rom.banks[0x14][0x1218 + 0x62] = 0x01 # Hot head rom.banks[0x14][0x1218 + 0xF9] = 0x01 # Hardhit beetle rom.banks[0x14][0x1218 + 0xE6] = 0x01 # Nightmare # Minibosses rom.banks[0x14][0x1218 + 0x81] = 0x01 # Rolling bones rom.banks[0x14][0x1218 + 0x89] = 0x01 # Hinox rom.banks[0x14][0x1218 + 0x8E] = 0x01 # Cue ball rom.banks[0x14][0x1218 + 0x5E] = 0x01 # Gnoma rom.banks[0x14][0x1218 + 0x5F] = 0x01 # Master stalfos rom.banks[0x14][0x1218 + 0x92] = 0x01 # Smasher rom.banks[0x14][0x1218 + 0xBC] = 0x01 # Grim creeper rom.banks[0x14][0x1218 + 0xBE] = 0x01 # Blaino rom.banks[0x14][0x1218 + 0xF8] = 0x01 # Giant buzz blob rom.banks[0x14][0x1218 + 0xF4] = 0x01 # Avalaunch # NPCs rom.banks[0x14][0x1218 + 0x6F] = 0x01 # Dog rom.banks[0x14][0x1218 + 0x6E] = 0x01 # Butterfly rom.banks[0x14][0x1218 + 0x6C] = 0x01 # Cucco rom.banks[0x14][0x1218 + 0x70] = 0x01 # Kid rom.banks[0x14][0x1218 + 0x71] = 0x01 # Kid rom.banks[0x14][0x1218 + 0x72] = 0x01 # Kid rom.banks[0x14][0x1218 + 0x73] = 0x01 # Kid rom.banks[0x14][0x1218 + 0xD0] = 0x01 # Animal rom.banks[0x14][0x1218 + 0xD1] = 0x01 # Animal rom.banks[0x14][0x1218 + 0xD2] = 0x01 # Animal rom.banks[0x14][0x1218 + 0xD3] = 0x01 # Animal rom.banks[0x14][0x1218 + 0xFA] = 0x01 # Photographer