def createDungeonOnlyOverworld(rom): # Skip the whole egg maze. rom.patch(0x14, 0x0453, "75", "73") # Some sprite patches (should generalize this) rom.room_sprite_data_overworld[0x72] = b'\xff\xff\xff\xff' rom.room_sprite_data_overworld[0x73] = rom.room_sprite_data_overworld[0x8C] rom.room_sprite_data_overworld[0xB1] = rom.room_sprite_data_overworld[0x92] instrument_rooms = [ 0x102, 0x12A, 0x159, 0x162, 0x182, 0x1B5, 0x22C, 0x230, 0x301 ] # Start with clearing all the maps, because this just generates a bunch of room in the rom. for n in range(0x100): re = RoomEditor(rom, n) re.entities = [] re.objects = [] if os.path.exists("patches/overworld/%02X.json" % (n)): re.loadFromJson("patches/overworld/%02X.json" % (n)) re.updateOverlay() entrances = list( filter( lambda obj: obj.type_id in (0xE1, 0xE2, 0xE3, 0xBA, 0xA8, 0xBE, 0xCB), re.objects)) for obj in re.objects: if isinstance(obj, ObjectWarp) and entrances: e = entrances.pop(0) other = RoomEditor(rom, obj.room) for o in other.objects: if isinstance(o, ObjectWarp) and o.warp_type == 0: o.room = n o.target_x = e.x * 16 + 8 o.target_y = e.y * 16 + 16 other.store(rom) if obj.room == 0x1F5: # Patch the boomang guy exit rom.patch( 0x0a, 0x3891, "E000F41820", "E000%02x%02x%02x" % (n, e.x * 16 + 8, e.y * 16 + 16)) if obj.warp_type == 1 and obj.map_nr < 8 or obj.map_nr == 0xFF: other = RoomEditor(rom, instrument_rooms[min(8, obj.map_nr)]) for o in other.objects: if isinstance(o, ObjectWarp) and o.warp_type == 0: o.room = n o.target_x = e.x * 16 + 8 o.target_y = e.y * 16 + 16 other.store(rom) if n == 0x06: re.objects.insert(0, Object(5, 3, 0xE1)) re.store(rom)
def cleanup(rom): # Remove unused rooms to make some space in the rom re = RoomEditor(rom, 0x2C4) re.objects = [] re.entities = [] re.store(rom, 0x2C4) re.store(rom, 0x2D4) re.store(rom, 0x277) re.store(rom, 0x278) re.store(rom, 0x279) rom.texts[0x02B] = b'' # unused text
def createDungeonOnlyOverworld(rom): # Skip the whole egg maze. rom.patch(0x14, 0x0453, "75", "73") instrument_rooms = [ 0x102, 0x12A, 0x159, 0x162, 0x182, 0x1B5, 0x22C, 0x230, 0x301 ] path = os.path.dirname(__file__) # Start with clearing all the maps, because this just generates a bunch of room in the rom. for n in range(0x100): re = RoomEditor(rom, n) re.entities = [] re.objects = [] if os.path.exists("%s/overworld/dive/%02X.json" % (path, n)): re.loadFromJson("%s/overworld/dive/%02X.json" % (path, n)) entrances = list( filter(lambda obj: obj.type_id in WARP_TYPE_IDS, re.objects)) for obj in re.objects: if isinstance(obj, ObjectWarp) and entrances: e = entrances.pop(0) other = RoomEditor(rom, obj.room) for o in other.objects: if isinstance(o, ObjectWarp) and o.warp_type == 0: o.room = n o.target_x = e.x * 16 + 8 o.target_y = e.y * 16 + 16 other.store(rom) if obj.room == 0x1F5: # Patch the boomang guy exit other = RoomEditor(rom, "Alt1F5") other.getWarps()[0].room = n other.getWarps()[0].target_x = e.x * 16 + 8 other.getWarps()[0].target_y = e.y * 16 + 16 other.store(rom) if obj.warp_type == 1 and (obj.map_nr < 8 or obj.map_nr == 0xFF ) and obj.room not in (0x1B0, 0x23A, 0x23D): other = RoomEditor(rom, instrument_rooms[min(8, obj.map_nr)]) for o in other.objects: if isinstance(o, ObjectWarp) and o.warp_type == 0: o.room = n o.target_x = e.x * 16 + 8 o.target_y = e.y * 16 + 16 other.store(rom) re.store(rom)
def setRaftGoal(rom): rom.texts[0x1A3] = formatText(b"Just sail away.") # Remove the egg and egg event handler. re = RoomEditor(rom, 0x006) for x in range(4, 7): for y in range(0, 4): re.removeObject(x, y) re.objects.append(ObjectHorizontal(4, 1, 0x4d, 3)) re.objects.append(ObjectHorizontal(4, 2, 0x03, 3)) re.objects.append(ObjectHorizontal(4, 3, 0x03, 3)) re.entities = [] re.updateOverlay() re.store(rom) re = RoomEditor(rom, 0x08D) re.objects[6].count = 4 re.objects[7].x += 2 re.objects[7].type_id = 0x2B re.objects[8].x += 2 re.objects[8].count = 2 re.objects[9].x += 1 re.objects[11] = ObjectVertical(7, 5, 0x37, 2) re.objects[12].x -= 1 re.objects[13].x -= 1 re.objects[14].x -= 1 re.objects[14].type_id = 0x34 re.objects[17].x += 3 re.objects[17].count -= 3 re.updateOverlay() re.overlay[7 + 60] = 0x33 re.store(rom) re = RoomEditor(rom, 0x0E9) re.objects[30].count = 1 re.objects[30].x += 2 re.overlay[7 + 70] = 0x0E re.overlay[8 + 70] = 0x0E re.store(rom) re = RoomEditor(rom, 0x0F9) re.objects = [ ObjectHorizontal(4, 0, 0x0E, 6), ObjectVertical(9, 0, 0xCA, 8), ObjectVertical(8, 0, 0x0E, 8), Object(3, 0, 0x38), Object(3, 1, 0x32), ObjectHorizontal(4, 1, 0x2C, 3), Object(7, 1, 0x2D), ObjectVertical(7, 2, 0x38, 5), Object(7, 7, 0x34), ObjectHorizontal(0, 7, 0x2F, 7), ObjectVertical(2, 3, 0xE8, 4), ObjectVertical(3, 2, 0xE8, 5), ObjectVertical(4, 2, 0xE8, 2), ObjectVertical(4, 4, 0x5C, 3), ObjectVertical(5, 2, 0x5C, 5), ObjectVertical(6, 2, 0x5C, 5), Object(6, 4, 0xC6), ObjectWarp(1, 0x1F, 0xF6, 136, 112) ] re.updateOverlay(True) re.entities.append((0, 0, 0x41)) re.store(rom) re = RoomEditor(rom, 0x1F6) re.objects[-1].target_x -= 16 re.store(rom) # Fix the raft graphics (this overrides some unused graphic tiles) rom.banks[0x31][0x21C0:0x2200] = rom.banks[0x2E][0x07C0:0x0800] # Patch the owl entity to run our custom end handling. rom.patch(0x06, 0x27F5, 0x2A77, ASM(""" ld a, [$DB95] cp $0B ret nz ; If map is not fully loaded, return ld a, [$C124] and a ret nz ; Check if we are moving off the bottom of the map ldh a, [$99] cp $7D ret c ; Move link back so it does not move off the map ld a, $7D ldh [$99], a xor a ld e, a ld d, a raftSearchLoop: ld hl, $C280 add hl, de ld a, [hl] and a jr z, .skipEntity ld hl, $C3A0 add hl, de ld a, [hl] cp $6A jr nz, .skipEntity ; Raft found, check if near the bottom of the screen. ld hl, $C210 add hl, de ld a, [hl] cp $70 jr nc, raftOffWorld .skipEntity: inc e ld a, e cp $10 jr nz, raftSearchLoop ret raftOffWorld: ; Switch to the end credits ld a, $01 ld [$DB95], a ld a, $00 ld [$DB96], a ret """), fill_nop=True) # We need to run quickly trough part of the credits, or else it bugs out # Skip the whole windfish part. rom.patch(0x17, 0x0D39, None, ASM("ld a, $18\nld [$D00E], a\nret")) # And skip the zoomed out laying on the log rom.patch(0x17, 0x20ED, None, ASM("ld a, $00")) # Finally skip some waking up on the log. rom.patch(0x17, 0x23BC, None, ASM("jp $4CD9")) rom.patch(0x17, 0x2476, None, ASM("jp $4CD9"))
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 changeMiniBosses(rom, mapping): # Fix avalaunch not working when entering a room from the left or right rom.patch(0x03, 0x0BE0, ASM(""" ld [hl], $50 ld hl, $C2D0 add hl, bc ld [hl], $00 jp $4B56 """), ASM(""" ld a, [hl] sub $08 ld [hl], a ld hl, $C2D0 add hl, bc ld [hl], b ; b is always zero here ret """), fill_nop=True) # Remove the powder fairy from giant buzz blob rom.patch(0x36, 0x14F7, ASM("jr nz, $05"), ASM("jr $05")) for target, name in mapping.items(): re = RoomEditor(rom, MINIBOSS_ROOMS[target]) re.entities = [e for e in re.entities if e[2] == 0x61] # Only keep warp, if available re.entities += MINIBOSS_ENTITIES[name] if re.room == 0x228 and name != "GRIM_CREEPER": for x in range(3, 7): for y in range(0, 3): re.removeObject(x, y) if name == "CUE_BALL": re.objects += [ Object(3, 3, 0x2c), ObjectHorizontal(4, 3, 0x22, 2), Object(6, 3, 0x2b), Object(3, 4, 0x2a), ObjectHorizontal(4, 4, 0x21, 2), Object(6, 4, 0x29), ] if name == "BLAINO": # BLAINO needs a warp object to hit you to the entrance of the dungeon. if len(re.getWarps()) < 1: # Default to start house. target = (0x10, 0x2A3, 0x50, 0x7c, 0x2A3) if 0x100 <= re.room < 0x11D: #D1 target = (0, 0x117, 80, 80) elif 0x11D <= re.room < 0x140: #D2 target = (1, 0x136, 80, 80) elif 0x140 <= re.room < 0x15D: #D3 target = (2, 0x152, 80, 80) elif 0x15D <= re.room < 0x180: #D4 target = (2, 0x174, 80, 80) elif 0x180 <= re.room < 0x1AC: #D5 target = (2, 0x1A1, 80, 80) elif 0x1B0 <= re.room < 0x1DE: #D6 target = (2, 0x1D4, 80, 80) elif 0x200 <= re.room < 0x22D: #D7 target = (6, 0x20E, 80, 80) elif 0x22D <= re.room < 0x26C: #D8 target = (7, 0x25D, 80, 80) elif re.room >= 0x300: #D0 target = (0xFF, 0x312, 80, 80) elif re.room == 0x2E1: #Moblin cave target = (0x15, 0x2F0, 0x50, 0x7C) re.objects.append(ObjectWarp(1, *target)) if name == "DODONGO": # Remove breaking floor tiles from the room. re.objects = [obj for obj in re.objects if obj.type_id != 0xDF] if name == "ROLLING_BONES" and target == 2: # Make rolling bones pass trough walls so it does not get stuck here. rom.patch(0x03, 0x02F1 + 0x81, "84", "95") re.store(rom)
def addMultiworldShop(rom): # Make a copy of the shop into GrandpaUlrira house shop_room = RoomEditor(rom, 0x2A1) re = RoomEditor(rom, 0x2A9) re.objects = [ obj for obj in shop_room.objects if obj.x is not None and obj.type_id != 0xCE ] + re.getWarps() re.entities = [(1, 6, 0x77), (2, 6, 0x77)] re.animation_id = shop_room.animation_id re.floor_object = shop_room.floor_object re.store(rom) # Fix the tileset rom.banks[0x20][0x2EB3 + 0x2A9 - 0x100] = rom.banks[0x20][0x2EB3 + 0x2A1 - 0x100] # Load the shopkeeper sprites instead of Grandpa sprites entityData.SPRITE_DATA[0x77] = entityData.SPRITE_DATA[0x4D] labels = {} rom.patch(0x06, 0x2860, "00" * 0x215, ASM( """ shopItemsHandler: ; Render the shop items ld h, $00 loop: ; First load links position to render the item at ldh a, [$98] ; LinkX ldh [$EE], a ; X ldh a, [$99] ; LinkY sub $0E ldh [$EC], a ; Y ; Check if this is the item we have picked up ld a, [$C509] ; picked up item in shop dec a cp h jr z, .renderCarry ld a, h swap a add a, $20 ldh [$EE], a ; X ld a, $30 ldh [$EC], a ; Y .renderCarry: ld a, h push hl ldh [$F1], a ; variant cp $03 jr nc, .singleSprite ld de, ItemsDualSpriteData call $3BC0 ; render sprite pair jr .renderDone .singleSprite: ld de, ItemsSingleSpriteData call $3C77 ; render sprite .renderDone: pop hl .skipItem: inc h ld a, $07 cp h jr nz, loop ; check if we want to pickup or drop an item ldh a, [$CC] and $30 ; A or B button call nz, checkForPickup ; check if we have an item ld a, [$C509] ; carry item and a ret z ; Set that link has picked something up ld a, $01 ld [$C15C], a call $0CAF ; reset spin attack... ; Check if we are trying to exit the shop and so drop our item. ldh a, [$99] cp $78 ret c xor a ld [$C509], a ret checkForPickup: ldh a, [$9E] ; direction cp $02 ret nz ldh a, [$99] ; LinkY cp $48 ret nc ld a, $13 ldh [$F2], a ; play SFX ld a, [$C509] ; picked up shop item and a jr nz, .drop ldh a, [$98] ; LinkX sub $08 swap a and $07 ld [$C509], a ; picked up shop item ret .drop: xor a ld [$C509], a ret ItemsDualSpriteData: db $60, $08, $60, $28 ; zol db $68, $09 ; chicken (left) ItemsSingleSpriteData: ; (first 3 entries are still dual sprites) db $6A, $09 ; chicken (right) db $14, $02, $14, $22 ; piece of power ;Real single sprite data starts here db $00, $0F ; bomb db $38, $0A ; rupees db $20, $0C ; medicine db $28, $0C ; heart ;------------------------------------trying to buy something starts here talkHandler: ld a, [$C509] ; carry item add a, a ret z ; check if we have something to buy sub $02 ld hl, itemNames ld e, a ld d, b ; b=0 add hl, de ld e, [hl] inc hl ld d, [hl] ld hl, wCustomMessage call appendString dec hl call padString ld de, postMessage call appendString dec hl ld a, $fe ld [hl], a ld de, $FFEF add hl, de ldh a, [$EE] swap a and $0F add a, $30 ld [hl], a ld a, $C9 call $2385 ; open dialog call $3B12 ; increase entity state ret appendString: ld a, [de] inc de and a ret z ldi [hl], a jr appendString padString: ld a, l and $0F ret z ld a, $20 ldi [hl], a jr padString itemNames: dw itemZol dw itemChicken dw itemPieceOfPower dw itemBombs dw itemRupees dw itemMedicine dw itemHealth postMessage: db "For player X? Yes No ", $00 itemZol: db m"Slime storm|100 {RUPEES}", $00 itemChicken: db m"Coccu party|50 {RUPEES}", $00 itemPieceOfPower: db m"Piece of Power|50 {RUPEES}", $00 itemBombs: db m"20 Bombs|50 {RUPEES}", $00 itemRupees: db m"100 {RUPEES}|200 {RUPEES}", $00 itemMedicine: db m"Medicine|100 {RUPEES}", $00 itemHealth: db m"Health refill|10 {RUPEES}", $00 TalkResultHandler: ld hl, ItemPriceTableBCD ld a, [$C509] dec a add a, a ld c, a ; b=0 add hl, bc ldi a, [hl] ld d, [hl] ld e, a ld a, [$DB5D] cp d ret c jr nz, .highEnough ld a, [$DB5E] cp e ret c .highEnough: ; Got enough money, take it. ld hl, ItemPriceTableDEC ld a, [$C509] dec a ld c, a ; b=0 add hl, bc ld a, [hl] ld [$DB92], a ; No longer picked up item xor a ld [$C509], a ret ItemPriceTableBCD: dw $0100, $0050, $0050, $0050, $0200, $0100, $0010 ItemPriceTableDEC: db $64, $32, $32, $32, $C8, $64, $0A """, 0x6860, labels), fill_nop=True) # Patch GrandpaUlrira to work as a multiworld shop rom.patch(0x06, 0x1C0E, 0x1C89, ASM( """ ld a, $01 ld [$C50A], a ; this stops link from using items ;Draw shopkeeper ld de, OwnerSpriteData call $3BC0 ; render sprite pair ldh a, [$E7] ; frame counter swap a and $01 call $3B0C ; set sprite variant ldh a, [$F0] and a jr nz, checkTalkingResult call $641A ; prevent link from moving into the sprite call $645D ; check if talking to NPC call c, ${TALKHANDLER:04x} ; talk handling ldh a, [$EE] ; X cp $18 ret nz ; Jump to other code which is placed on the old owl code. As we do not have enough space here. jp ${SHOPITEMSHANDLER:04x} checkTalkingResult: ld a, [$C19F] and a ret nz ; still taking call $3B12 ; increase entity state ld [hl], $00 ld a, [$C177] ; dialog selection and a ret nz jp ${TALKRESULTHANDLER:04x} OwnerSpriteData: ;db $60, $03, $62, $03, $62, $23, $60, $23 ; down db $64, $03, $66, $03, $66, $23, $64, $23 ; up ;db $68, $03, $6A, $03, $6C, $03, $6E, $03 ; left ;db $6A, $23, $68, $23, $6E, $23, $6C, $23 ; right """.format(**labels), 0x5C0E), fill_nop=True)
def addMultiworldShop(rom, this_player, player_count): # Make a copy of the shop into GrandpaUlrira house re = RoomEditor(rom, 0x2A9) re.objects = [ ObjectHorizontal(1, 1, 0x00, 8), ObjectHorizontal(1, 2, 0x00, 8), ObjectHorizontal(1, 3, 0xCD, 8), Object(2, 0, 0xC7), Object(7, 0, 0xC7), Object(7, 7, 0xFD), ] + re.getWarps() re.entities = [(0, 6, 0xD4)] for n in range(player_count): if n != this_player: re.entities.append((n + 1, 6, 0xD4)) re.animation_id = 0x04 re.floor_object = 0x0D re.store(rom) # Fix the tileset rom.banks[0x20][0x2EB3 + 0x2A9 - 0x100] = rom.banks[0x20][0x2EB3 + 0x2A1 - 0x100] re = RoomEditor(rom, 0x0B1) re.getWarps()[0].target_x = 128 re.store(rom) # Load the shopkeeper sprites entityData.SPRITE_DATA[0xD4] = entityData.SPRITE_DATA[0x4D] rom.patch(0x03, 0x01CF, "00", "98") # Fix the hitbox of the ghost to be 16x16 # Patch Ghost to work as a multiworld shop rom.patch(0x19, 0x1E18, 0x20B0, ASM( """ ld a, $01 ld [$C50A], a ; this stops link from using items ldh a, [$EE] ; X cp $08 ; Jump to other code which is placed on the old owl code. As we do not have enough space here. jp z, shopItemsHandler ;Draw shopkeeper ld de, OwnerSpriteData call $3BC0 ; render sprite pair ldh a, [$E7] ; frame counter swap a and $01 call $3B0C ; set sprite variant ldh a, [$F0] and a jr nz, checkTalkingResult call $7CA2 ; prevent link from moving into the sprite call $7CF0 ; check if talking to NPC call c, talkHandler ; talk handling ret checkTalkingResult: ld a, [$C19F] and a ret nz ; still taking call $3B12 ; increase entity state ld [hl], $00 ld a, [$C177] ; dialog selection and a ret nz jp TalkResultHandler OwnerSpriteData: ;db $60, $03, $62, $03, $62, $23, $60, $23 ; down db $64, $03, $66, $03, $66, $23, $64, $23 ; up ;db $68, $03, $6A, $03, $6C, $03, $6E, $03 ; left ;db $6A, $23, $68, $23, $6E, $23, $6C, $23 ; right shopItemsHandler: ; Render the shop items ld h, $00 loop: ; First load links position to render the item at ldh a, [$98] ; LinkX ldh [$EE], a ; X ldh a, [$99] ; LinkY sub $0E ldh [$EC], a ; Y ; Check if this is the item we have picked up ld a, [$C509] ; picked up item in shop dec a cp h jr z, .renderCarry ld a, h swap a add a, $20 ldh [$EE], a ; X ld a, $30 ldh [$EC], a ; Y .renderCarry: ld a, h push hl ldh [$F1], a ; variant cp $03 jr nc, .singleSprite ld de, ItemsDualSpriteData call $3BC0 ; render sprite pair jr .renderDone .singleSprite: ld de, ItemsSingleSpriteData call $3C77 ; render sprite .renderDone: pop hl .skipItem: inc h ld a, $07 cp h jr nz, loop ; check if we want to pickup or drop an item ldh a, [$CC] and $30 ; A or B button call nz, checkForPickup ; check if we have an item ld a, [$C509] ; carry item and a ret z ; Set that link has picked something up ld a, $01 ld [$C15C], a call $0CAF ; reset spin attack... ; Check if we are trying to exit the shop and so drop our item. ldh a, [$99] cp $78 ret c xor a ld [$C509], a ret checkForPickup: ldh a, [$9E] ; direction cp $02 ret nz ldh a, [$99] ; LinkY cp $48 ret nc ld a, $13 ldh [$F2], a ; play SFX ld a, [$C509] ; picked up shop item and a jr nz, .drop ldh a, [$98] ; LinkX sub $08 swap a and $07 ld [$C509], a ; picked up shop item ret .drop: xor a ld [$C509], a ret ItemsDualSpriteData: db $60, $08, $60, $28 ; zol db $68, $09 ; chicken (left) ItemsSingleSpriteData: ; (first 3 entries are still dual sprites) db $6A, $09 ; chicken (right) db $14, $02, $14, $22 ; piece of power ;Real single sprite data starts here db $00, $0F ; bomb db $38, $0A ; rupees db $20, $0C ; medicine db $28, $0C ; heart ;------------------------------------trying to buy something starts here talkHandler: ld a, [$C509] ; carry item add a, a ret z ; check if we have something to buy sub $02 ld hl, itemNames ld e, a ld d, b ; b=0 add hl, de ld e, [hl] inc hl ld d, [hl] ld hl, wCustomMessage call appendString dec hl call padString ld de, postMessage call appendString dec hl ld a, $fe ld [hl], a ld de, $FFEF add hl, de ldh a, [$EE] swap a and $0F add a, $30 ld [hl], a ld a, $C9 call $2385 ; open dialog call $3B12 ; increase entity state ret appendString: ld a, [de] inc de and a ret z ldi [hl], a jr appendString padString: ld a, l and $0F ret z ld a, $20 ldi [hl], a jr padString itemNames: dw itemZol dw itemChicken dw itemPieceOfPower dw itemBombs dw itemRupees dw itemMedicine dw itemHealth postMessage: db "For player X? Yes No ", $00 itemZol: db m"Slime storm|100 {RUPEES}", $00 itemChicken: db m"Coccu party|50 {RUPEES}", $00 itemPieceOfPower: db m"Piece of Power|50 {RUPEES}", $00 itemBombs: db m"10 Bombs|50 {RUPEES}", $00 itemRupees: db m"100 {RUPEES}|200 {RUPEES}", $00 itemMedicine: db m"Medicine|100 {RUPEES}", $00 itemHealth: db m"Health refill|10 {RUPEES}", $00 TalkResultHandler: ld hl, ItemPriceTableBCD ld a, [$C509] dec a add a, a ld c, a ; b=0 add hl, bc ldi a, [hl] ld d, [hl] ld e, a ld a, [$DB5D] cp d ret c jr nz, .highEnough ld a, [$DB5E] cp e ret c .highEnough: ; Got enough money, take it. ld hl, ItemPriceTableDEC ld a, [$C509] dec a ld c, a ; b=0 add hl, bc ld a, [hl] ld [$DB92], a ; set substract buffer ; Set the item to send ld hl, $DDFE ld a, [$C509] ; currently picked up item ldi [hl], a ldh a, [$EE] ; X position of NPC ldi [hl], a ld hl, $DDF7 set 2, [hl] ; No longer picked up item xor a ld [$C509], a ret ItemPriceTableBCD: dw $0100, $0050, $0050, $0050, $0200, $0100, $0010 ItemPriceTableDEC: db $64, $32, $32, $32, $C8, $64, $0A """, 0x5E18), fill_nop=True)
def bowwowMapPatches(rom): # Remove all the cystal things that can only be destroyed with a sword. for n in range(0x100, 0x2FF): re = RoomEditor(rom, n) re.objects = list(filter(lambda obj: obj.type_id != 0xDD, re.objects)) re.store(rom)