def removeOwlEvents(rom): # Remove all the owl events from the entity tables. for room in range(0x100): re = RoomEditor(rom, room) if re.hasEntity(0x41): re.removeEntities(0x41) re.store(rom) # Clear texts used by the owl. Potentially reused somewhere else. rom.texts[0x0D9] = b'\xff' # used by boomerang # 1 Used by empty chest (master stalfos message) # 9 used by keysanity items # 1 used by bowwow in chest # 1 used by item for other player message # 2 used by arrow chest messages # 2 used by tunics for idx in range(0x0BE, 0x0CE): rom.texts[idx] = b'\xff'
def doubleTrouble(rom): for n in range(0x316): if n == 0x2FF: continue re = RoomEditor(rom, n) # Bosses if re.hasEntity(0x59): # Moldorm (TODO; double heart container drop) re.removeEntities(0x59) re.entities += [(3, 2, 0x59), (4, 2, 0x59)] re.store(rom) if re.hasEntity(0x5C): # Ghini re.removeEntities(0x5C) re.entities += [(3, 2, 0x5C), (4, 2, 0x5C)] re.store(rom) if re.hasEntity(0x5B): # slime eye re.removeEntities(0x5B) re.entities += [(3, 2, 0x5B), (6, 2, 0x5B)] re.store(rom) if re.hasEntity(0x65): # angler fish re.removeEntities(0x65) re.entities += [(6, 2, 0x65), (6, 5, 0x65)] re.store(rom) # Slime eel bugs out on death if duplicated. # if re.hasEntity(0x5D): # slime eel # re.removeEntities(0x5D) # re.entities += [(6, 2, 0x5D), (6, 5, 0x5D)] # re.store(rom) if re.hasEntity( 0x5A): # facade (TODO: Drops two hearts, shared health?) re.removeEntities(0x5A) re.entities += [(2, 3, 0x5A), (6, 3, 0x5A)] re.store(rom) # Evil eagle causes a crash, and messes up the intro sequence and generally is just a mess if I spawn multiple # if re.hasEntity(0x63): # evil eagle # re.removeEntities(0x63) # re.entities += [(3, 4, 0x63), (2, 4, 0x63)] # re.store(rom) # # Remove that links movement is blocked # rom.patch(0x05, 0x2258, ASM("ldh [$A1], a"), "0000") # rom.patch(0x05, 0x1AE3, ASM("ldh [$A1], a"), "0000") # rom.patch(0x05, 0x1C5D, ASM("ldh [$A1], a"), "0000") # rom.patch(0x05, 0x1C8D, ASM("ldh [$A1], a"), "0000") # rom.patch(0x05, 0x1CAF, ASM("ldh [$A1], a"), "0000") if re.hasEntity(0x62): # hot head (TODO: Drops thwo hearts) re.removeEntities(0x62) re.entities += [(2, 2, 0x62), (4, 4, 0x62)] re.store(rom) if re.hasEntity(0xF9): # hardhit beetle re.removeEntities(0xF9) re.entities += [(2, 2, 0xF9), (5, 4, 0xF9)] re.store(rom) # Minibosses if re.hasEntity(0x89): re.removeEntities(0x89) re.entities += [(2, 3, 0x89), (6, 3, 0x89)] re.store(rom) if re.hasEntity(0x81): re.removeEntities(0x81) re.entities += [(2, 3, 0x81), (6, 3, 0x81)] re.store(rom) if re.hasEntity(0x60): dodongo = [e for e in re.entities if e[2] == 0x60] x = (dodongo[0][0] + dodongo[1][0]) // 2 y = (dodongo[0][1] + dodongo[1][1]) // 2 re.entities += [(x, y, 0x60)] re.store(rom) if re.hasEntity(0x8e): re.removeEntities(0x8e) re.entities += [(1, 1, 0x8e), (7, 1, 0x8e)] re.store(rom) if re.hasEntity(0x92): re.removeEntities(0x92) re.entities += [(2, 3, 0x92), (4, 3, 0x92)] re.store(rom) if re.hasEntity(0xf4): re.removeEntities(0xf4) re.entities += [(2, 1, 0xf4), (6, 1, 0xf4)] re.store(rom) if re.hasEntity(0xf8): re.removeEntities(0xf8) re.entities += [(2, 2, 0xf8), (6, 2, 0xf8)] re.store(rom) if re.hasEntity(0xe4): re.removeEntities(0xe4) re.entities += [(5, 2, 0xe4), (5, 5, 0xe4)] re.store(rom) if re.hasEntity(0x88): # Armos knight (TODO: double item drop) re.removeEntities(0x88) re.entities += [(3, 3, 0x88), (6, 3, 0x88)] re.store(rom) if re.hasEntity( 0x87 ): # Lanmola (TODO: killing one drops the item, and marks as done) re.removeEntities(0x87) re.entities += [(2, 2, 0x87), (1, 1, 0x87)] re.store(rom)
def removeOwlEvents(rom): # Remove all the owl events from the entity tables. for room in range(0x100): re = RoomEditor(rom, room) if re.hasEntity(0x41): re.removeEntities(0x41) re.store(rom) # Clear texts used by the owl. Potentially reused somewhere o else. rom.texts[0x0D9] = b'\xff' # used by boomerang # 1 Used by empty chest (master stalfos message) # 8 unused (0x0C0-0x0C7) # 1 used by bowwow in chest # 1 used by item for other player message # 2 used by arrow chest messages # 2 used by tunics for idx in range(0x0BE, 0x0CE): rom.texts[idx] = b'\xff' # Patch the owl entity into a ghost to allow refill of powder/bombs/arrows rom.texts[0xC0] = formatText("Everybody hates me, so I give away free things in the hope people will love me. Want something?", ask="Okay No") rom.texts[0xC1] = formatText("Good for you.") rom.patch(0x06, 0x27F5, 0x2A77, ASM(""" ; Check if we have powder or bombs. ld e, INV_SIZE ld hl, $DB00 loop: ldi a, [hl] cp $02 ; bombs jr z, hasProperItem cp $0C ; powder jr z, hasProperItem cp $05 ; bow jr z, hasProperItem dec e jr nz, loop ret hasProperItem: ; Render ghost ld de, sprite call $3BC0 call $64C6 ; check if game is busy (pops this stack frame if busy) ldh a, [$E7] ; frame counter swap a and $01 call $3B0C ; set entity sprite variant call $641A ; check collision ldh a, [$F0] ;entity state rst 0 dw waitForTalk dw talking waitForTalk: call $645D ; check if talked to ret nc ld a, $C0 call $2385 ; open dialog call $3B12 ; increase entity state ret talking: ; Check if we are still talking ld a, [$C19F] and a ret nz call $3B12 ; increase entity state ld [hl], $00 ; set to state 0 ld a, [$C177] ; get which option we selected and a ret nz ; Give powder ld a, [$DB4C] cp $10 jr nc, doNotGivePowder ld a, $10 ld [$DB4C], a doNotGivePowder: ld a, [$DB4D] cp $10 jr nc, doNotGiveBombs ld a, $10 ld [$DB4D], a doNotGiveBombs: ld a, [$DB45] cp $10 jr nc, doNotGiveArrows ld a, $10 ld [$DB45], a doNotGiveArrows: ld a, $C1 call $2385 ; open dialog ret sprite: db $76, $09, $78, $09, $7A, $09, $7C, $09 """, 0x67F5), fill_nop=True) rom.patch(0x20, 0x0322 + 0x41 * 2, "734A", "564B") # Remove the owl init handler re = RoomEditor(rom, 0x2A3) re.entities.append((7, 6, 0x41)) re.store(rom)
def read(self, rom): re = RoomEditor(rom, 0x0F2) if re.hasEntity(0x31): return SWORD return super().read(rom)
def removeOwlEvents(rom): # Remove all the owl events from the entity tables. for room in range(0x100): re = RoomEditor(rom, room) if re.hasEntity(0x41): re.removeEntities(0x41) re.store(rom) # Clear texts used by the owl. Potentially reused somewhere else. rom.texts[0x0D9] = b'\xff' # used by boomerang # 1 Used by empty chest (master stalfos message) # 8 unused (0x0C0-0x0C7) # 1 used by bowwow in chest # 1 used by item for other player message # 2 used by arrow chest messages # 2 used by tunics for idx in range(0x0BE, 0x0CE): rom.texts[idx] = b'\xff' # Patch the owl entity to allow refill of powder/bombs rom.texts[0xC0] = formatText("Hoot!\nHoot!\nOut of stock?", ask="Okay No") rom.texts[0xC1] = formatText( "Hoot!\nHoot! Hoot!\nHoot!\nHere are a few things for you.") rom.patch(0x06, 0x27F5, 0x2A77, ASM( """ ; Render owl ld de, sprite call $3BC0 call $64C6 ; check if game is busy (pops this stack frame if busy) ldh a, [$E7] ; frame counter cp $F0 jr c, eyesOpen ld a, $01 jr setSpriteVariant eyesOpen: xor a setSpriteVariant: call $3B0C ; set entity sprite variant call $641A ; check collision ldh a, [$F0] ;entity state rst 0 dw waitForTalk dw talking waitForTalk: call $645D ; check if talked to ret nc ld a, $C0 call $2385 ; open dialog call $3B12 ; increase entity state ret talking: ; Check if we are still talking ld a, [$C19F] and a ret nz call $3B12 ; increase entity state ld [hl], $00 ; set to state 0 ld a, [$C177] ; get which option we selected and a ret nz ; Give powder ld a, [$DB4C] cp $10 jr nc, doNotGivePowder ld a, $10 ld [$DB4C], a doNotGivePowder: ld a, [$DB4D] cp $10 jr nc, doNotGiveBombs ld a, $10 ld [$DB4D], a doNotGiveBombs: ld a, $C1 call $2385 ; open dialog ret sprite: db $78, $01, $78, $21, $7A, $01, $7A, $21 """, 0x67F5), fill_nop=True)