Archipelago/worlds/ladx/LADXR/patches/owl.py

147 lines
3.6 KiB
Python

from ..roomEditor import RoomEditor
from ..assembler import ASM
from ..utils import formatText
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.
# 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
# Undoing this, we use it for text shuffle now
#rom.texts[0x0D9] = b'\xff' # used by boomerang
# 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 upgradeDungeonOwlStatues(rom):
# Call our custom handler after the check for the stone beak
rom.patch(0x18, 0x1EA2, ASM("ldh a, [$F7]\ncp $FF\njr nz, $05"), ASM("ld a, $09\nrst 8\nret"), fill_nop=True)
def upgradeOverworldOwlStatues(rom):
# Replace the code that handles signs/owl statues on the overworld
# This removes a "have marin with you" special case to make some room for our custom owl handling.
rom.patch(0x00, 0x201A, ASM("""
cp $6F
jr z, $2B
cp $D4
jr z, $27
ld a, [$DB73]
and a
jr z, $08
ld a, $78
call $237C
jp $20CF
"""), ASM("""
cp $D4
jr z, $2B
cp $6F
jr nz, skip
ld a, $09
rst 8
jp $20CF
skip:
"""), fill_nop=True)