1037 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			1037 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| 
								 | 
							
								from ..backgroundEditor import BackgroundEditor
							 | 
						||
| 
								 | 
							
								from ..roomEditor import RoomEditor, ObjectWarp
							 | 
						||
| 
								 | 
							
								from ..assembler import ASM
							 | 
						||
| 
								 | 
							
								from ..locations.constants import *
							 | 
						||
| 
								 | 
							
								from ..utils import formatText
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Few unused rooms that we can use the room status variables for to store data.
							 | 
						||
| 
								 | 
							
								UNUSED_ROOMS = [0x15D, 0x17E, 0x17F, 0x1AD]
							 | 
						||
| 
								 | 
							
								next_bit_flag_index = 0
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def getUnusedBitFlag():
							 | 
						||
| 
								 | 
							
								    global next_bit_flag_index
							 | 
						||
| 
								 | 
							
								    addr = UNUSED_ROOMS[next_bit_flag_index // 8] + 0xD800
							 | 
						||
| 
								 | 
							
								    bit_nr = next_bit_flag_index & 0x07
							 | 
						||
| 
								 | 
							
								    mask = 1 << bit_nr
							 | 
						||
| 
								 | 
							
								    next_bit_flag_index += 1
							 | 
						||
| 
								 | 
							
								    check_code = checkMemoryMask("$%04x" % (addr), "$%02x" % (mask))
							 | 
						||
| 
								 | 
							
								    set_code = "ld hl, $%04x\nset %d, [hl]" % (addr, bit_nr)
							 | 
						||
| 
								 | 
							
								    return check_code, set_code
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class Goal:
							 | 
						||
| 
								 | 
							
								    def __init__(self, description, code, tile_info, *, kill_code=None, group=None, extra_patches=None):
							 | 
						||
| 
								 | 
							
								        self.description = description
							 | 
						||
| 
								 | 
							
								        self.code = code
							 | 
						||
| 
								 | 
							
								        self.tile_info = tile_info
							 | 
						||
| 
								 | 
							
								        self.kill_code = kill_code
							 | 
						||
| 
								 | 
							
								        self.group = group
							 | 
						||
| 
								 | 
							
								        self.extra_patches = extra_patches or []
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class TileInfo:
							 | 
						||
| 
								 | 
							
								    def __init__(self, index1, index2=None, index3=None, index4=None, *, shift4=False, colormap=None, flipH=False):
							 | 
						||
| 
								 | 
							
								        self.index1 = index1
							 | 
						||
| 
								 | 
							
								        self.index2 = index2 if index2 is not None else self.index1 + 1
							 | 
						||
| 
								 | 
							
								        self.index3 = index3
							 | 
						||
| 
								 | 
							
								        self.index4 = index4
							 | 
						||
| 
								 | 
							
								        if self.index3 is None:
							 | 
						||
| 
								 | 
							
								            self.index3 = self.index1 if flipH else self.index1 + 2
							 | 
						||
| 
								 | 
							
								        if self.index4 is None:
							 | 
						||
| 
								 | 
							
								            self.index4 = self.index2 if flipH else self.index1 + 3
							 | 
						||
| 
								 | 
							
								        self.shift4 = shift4
							 | 
						||
| 
								 | 
							
								        self.colormap = colormap
							 | 
						||
| 
								 | 
							
								        self.flipH = flipH
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def getTile(self, rom, idx):
							 | 
						||
| 
								 | 
							
								        return rom.banks[0x2C + idx // 0x400][(idx % 0x400) * 0x10:((idx % 0x400) + 1) * 0x10]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def get(self, rom):
							 | 
						||
| 
								 | 
							
								        data = self.getTile(rom, self.index1) + self.getTile(rom, self.index2) + self.getTile(rom,
							 | 
						||
| 
								 | 
							
								                                                                                              self.index3) + self.getTile(
							 | 
						||
| 
								 | 
							
								            rom, self.index4)
							 | 
						||
| 
								 | 
							
								        if self.shift4:
							 | 
						||
| 
								 | 
							
								            a = []
							 | 
						||
| 
								 | 
							
								            b = []
							 | 
						||
| 
								 | 
							
								            for c in data[0:32]:
							 | 
						||
| 
								 | 
							
								                a.append(c >> 4)
							 | 
						||
| 
								 | 
							
								                b.append((c << 4) & 0xFF)
							 | 
						||
| 
								 | 
							
								            data = bytes(a + b)
							 | 
						||
| 
								 | 
							
								        if self.flipH:
							 | 
						||
| 
								 | 
							
								            a = []
							 | 
						||
| 
								 | 
							
								            for c in data[32:64]:
							 | 
						||
| 
								 | 
							
								                d = 0
							 | 
						||
| 
								 | 
							
								                for bit in range(8):
							 | 
						||
| 
								 | 
							
								                    if c & (1 << bit):
							 | 
						||
| 
								 | 
							
								                        d |= 0x80 >> bit
							 | 
						||
| 
								 | 
							
								                a.append(d)
							 | 
						||
| 
								 | 
							
								            data = data[0:32] + bytes(a)
							 | 
						||
| 
								 | 
							
								        if self.colormap:
							 | 
						||
| 
								 | 
							
								            d = []
							 | 
						||
| 
								 | 
							
								            for n in range(0, 64, 2):
							 | 
						||
| 
								 | 
							
								                a = data[n]
							 | 
						||
| 
								 | 
							
								                b = data[n + 1]
							 | 
						||
| 
								 | 
							
								                for bit in range(8):
							 | 
						||
| 
								 | 
							
								                    col = 0
							 | 
						||
| 
								 | 
							
								                    if a & (1 << bit):
							 | 
						||
| 
								 | 
							
								                        col |= 1
							 | 
						||
| 
								 | 
							
								                    if b & (1 << bit):
							 | 
						||
| 
								 | 
							
								                        col |= 2
							 | 
						||
| 
								 | 
							
								                    col = self.colormap[col]
							 | 
						||
| 
								 | 
							
								                    a &= ~(1 << bit)
							 | 
						||
| 
								 | 
							
								                    b &= ~(1 << bit)
							 | 
						||
| 
								 | 
							
								                    if col & 1:
							 | 
						||
| 
								 | 
							
								                        a |= 1 << bit
							 | 
						||
| 
								 | 
							
								                    if col & 2:
							 | 
						||
| 
								 | 
							
								                        b |= 1 << bit
							 | 
						||
| 
								 | 
							
								                d.append(a)
							 | 
						||
| 
								 | 
							
								                d.append(b)
							 | 
						||
| 
								 | 
							
								            data = bytes(d)
							 | 
						||
| 
								 | 
							
								        return data
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								ITEM_TILES = {
							 | 
						||
| 
								 | 
							
								    BOMB: TileInfo(0x80, shift4=True),
							 | 
						||
| 
								 | 
							
								    POWER_BRACELET: TileInfo(0x82, shift4=True),
							 | 
						||
| 
								 | 
							
								    SWORD: TileInfo(0x84, shift4=True),
							 | 
						||
| 
								 | 
							
								    SHIELD: TileInfo(0x86, shift4=True),
							 | 
						||
| 
								 | 
							
								    BOW: TileInfo(0x88, shift4=True),
							 | 
						||
| 
								 | 
							
								    HOOKSHOT: TileInfo(0x8A, shift4=True),
							 | 
						||
| 
								 | 
							
								    MAGIC_ROD: TileInfo(0x8C, shift4=True),
							 | 
						||
| 
								 | 
							
								    MAGIC_POWDER: TileInfo(0x8E, shift4=True),
							 | 
						||
| 
								 | 
							
								    OCARINA: TileInfo(0x4E90, shift4=True),
							 | 
						||
| 
								 | 
							
								    FEATHER: TileInfo(0x4E92, shift4=True),
							 | 
						||
| 
								 | 
							
								    FLIPPERS: TileInfo(0x94, shift4=True),
							 | 
						||
| 
								 | 
							
								    SHOVEL: TileInfo(0x96, shift4=True),
							 | 
						||
| 
								 | 
							
								    PEGASUS_BOOTS: TileInfo(0x98, shift4=True),
							 | 
						||
| 
								 | 
							
								    SEASHELL: TileInfo(0x9E, shift4=True),
							 | 
						||
| 
								 | 
							
								    MEDICINE: TileInfo(0xA0, shift4=True),
							 | 
						||
| 
								 | 
							
								    BOOMERANG: TileInfo(0xA4, shift4=True),
							 | 
						||
| 
								 | 
							
								    TOADSTOOL: TileInfo(0x28C, shift4=True),
							 | 
						||
| 
								 | 
							
								    GOLD_LEAF: TileInfo(0xCA, shift4=True),
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def checkMemoryEqualCode(location, value):
							 | 
						||
| 
								 | 
							
								    return """
							 | 
						||
| 
								 | 
							
								        ld a, [%s]
							 | 
						||
| 
								 | 
							
								        cp %s
							 | 
						||
| 
								 | 
							
								        ret
							 | 
						||
| 
								 | 
							
								    """ % (location, value)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def checkMemoryNotZero(*locations):
							 | 
						||
| 
								 | 
							
								    if len(locations) == 1:
							 | 
						||
| 
								 | 
							
								        return """
							 | 
						||
| 
								 | 
							
								            ld  a, [%s]
							 | 
						||
| 
								 | 
							
								            and a
							 | 
						||
| 
								 | 
							
								            jp   flipZ
							 | 
						||
| 
								 | 
							
								        """ % (locations[0])
							 | 
						||
| 
								 | 
							
								    code = ""
							 | 
						||
| 
								 | 
							
								    for location in locations:
							 | 
						||
| 
								 | 
							
								        code += """
							 | 
						||
| 
								 | 
							
								            ld  a, [%s]
							 | 
						||
| 
								 | 
							
								            and a
							 | 
						||
| 
								 | 
							
								            jp  z, flipZ
							 | 
						||
| 
								 | 
							
								        """ % (location)
							 | 
						||
| 
								 | 
							
								    code += "jp flipZ"
							 | 
						||
| 
								 | 
							
								    return code
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def checkMemoryMask(location, mask):
							 | 
						||
| 
								 | 
							
								    if isinstance(location, tuple):
							 | 
						||
| 
								 | 
							
								        code = ""
							 | 
						||
| 
								 | 
							
								        for loc in location:
							 | 
						||
| 
								 | 
							
								            code += """
							 | 
						||
| 
								 | 
							
								                ld  a, [%s]
							 | 
						||
| 
								 | 
							
								                and %s
							 | 
						||
| 
								 | 
							
								                jp  z, clearZ
							 | 
						||
| 
								 | 
							
								            """ % (loc, mask)
							 | 
						||
| 
								 | 
							
								        code += "jp setZ"
							 | 
						||
| 
								 | 
							
								        return code
							 | 
						||
| 
								 | 
							
								    return """
							 | 
						||
| 
								 | 
							
								        ld  a, [%s]
							 | 
						||
| 
								 | 
							
								        and %s
							 | 
						||
| 
								 | 
							
								        jp   flipZ
							 | 
						||
| 
								 | 
							
								    """ % (location, mask)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def checkForSeashellsCode(count):
							 | 
						||
| 
								 | 
							
								    return """
							 | 
						||
| 
								 | 
							
								        ld  a, [wSeashellsCount]
							 | 
						||
| 
								 | 
							
								        cp  $%02x
							 | 
						||
| 
								 | 
							
								        jp  nc, setZ
							 | 
						||
| 
								 | 
							
								        ld  a, [$DAE9]
							 | 
						||
| 
								 | 
							
								        and $10
							 | 
						||
| 
								 | 
							
								        jp  flipZ
							 | 
						||
| 
								 | 
							
								    """ % (count)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def checkMemoryEqualGreater(location, count):
							 | 
						||
| 
								 | 
							
								    return """
							 | 
						||
| 
								 | 
							
								        ld  a, [%s]
							 | 
						||
| 
								 | 
							
								        cp  %s
							 | 
						||
| 
								 | 
							
								        jp  nc, setZ
							 | 
						||
| 
								 | 
							
								        jp  clearZ
							 | 
						||
| 
								 | 
							
								    """ % (location, count)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def InventoryGoal(item, *, memory_location=None, msg=None, group=None):
							 | 
						||
| 
								 | 
							
								    if memory_location is not None:
							 | 
						||
| 
								 | 
							
								        code = checkMemoryNotZero(memory_location)
							 | 
						||
| 
								 | 
							
								    elif item in INVENTORY_MAP:
							 | 
						||
| 
								 | 
							
								        code = """
							 | 
						||
| 
								 | 
							
								            ld   hl, $DB00
							 | 
						||
| 
								 | 
							
								            ld   e, INV_SIZE
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        .checkLoop:
							 | 
						||
| 
								 | 
							
								            ldi  a, [hl]
							 | 
						||
| 
								 | 
							
								            cp   $%s
							 | 
						||
| 
								 | 
							
								            ret  z ; item found, return with zero flag set to indicate goal done.
							 | 
						||
| 
								 | 
							
								            dec  e
							 | 
						||
| 
								 | 
							
								            jr   nz, .checkLoop
							 | 
						||
| 
								 | 
							
								            rra ; clear z flag
							 | 
						||
| 
								 | 
							
								            ret
							 | 
						||
| 
								 | 
							
								        """ % (INVENTORY_MAP[item])
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        code = """
							 | 
						||
| 
								 | 
							
								            rra ; clear z flag
							 | 
						||
| 
								 | 
							
								            ret
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								    if msg is None:
							 | 
						||
| 
								 | 
							
								        msg = "Find the {%s}" % (item)
							 | 
						||
| 
								 | 
							
								    return Goal(msg, code, ITEM_TILES[item], group=group)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def KillGoal(description, entity_id, tile_info):
							 | 
						||
| 
								 | 
							
								    check_code, set_code = getUnusedBitFlag()
							 | 
						||
| 
								 | 
							
								    return Goal(description, check_code, tile_info, kill_code="""
							 | 
						||
| 
								 | 
							
								        cp  $%02x
							 | 
						||
| 
								 | 
							
								        jr  nz, skip_%02x
							 | 
						||
| 
								 | 
							
								        %s
							 | 
						||
| 
								 | 
							
								        jp  done
							 | 
						||
| 
								 | 
							
								    skip_%02x:
							 | 
						||
| 
								 | 
							
								    """ % (entity_id, entity_id, set_code, entity_id))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def MonkeyGoal(description, tile_info):
							 | 
						||
| 
								 | 
							
								    check_code, set_code = getUnusedBitFlag()
							 | 
						||
| 
								 | 
							
								    return Goal(description, check_code, tile_info, extra_patches=[
							 | 
						||
| 
								 | 
							
								        (0x15, 0x36EC, 0x36EF, ASM("jp $7FCE")),
							 | 
						||
| 
								 | 
							
								        (0x15, 0x3FCE, "00" * 8, ASM("""
							 | 
						||
| 
								 | 
							
								            ld   [hl], $FA
							 | 
						||
| 
								 | 
							
								            %s
							 | 
						||
| 
								 | 
							
								            ret
							 | 
						||
| 
								 | 
							
								        """ % (set_code)))
							 | 
						||
| 
								 | 
							
								    ])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def BuzzBlobTalkGoal(description, tile_info):
							 | 
						||
| 
								 | 
							
								    check_code, set_code = getUnusedBitFlag()
							 | 
						||
| 
								 | 
							
								    return Goal(description, check_code, tile_info, extra_patches=[
							 | 
						||
| 
								 | 
							
								        (0x18, 0x37C9, ASM("call $237C"), ASM("call $7FDE")),
							 | 
						||
| 
								 | 
							
								        (0x18, 0x3FDE, "00" * 11, ASM("""
							 | 
						||
| 
								 | 
							
								            call $237C
							 | 
						||
| 
								 | 
							
								            ld   [hl], $FA
							 | 
						||
| 
								 | 
							
								            %s
							 | 
						||
| 
								 | 
							
								            ret
							 | 
						||
| 
								 | 
							
								        """ % (set_code)))
							 | 
						||
| 
								 | 
							
								    ])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def KillDethlGoal(description, tile_info):
							 | 
						||
| 
								 | 
							
								    check_code, set_code = getUnusedBitFlag()
							 | 
						||
| 
								 | 
							
								    return Goal(description, check_code, tile_info, extra_patches=[
							 | 
						||
| 
								 | 
							
								        (0x15, 0x0606, 0x060B, ASM(set_code)),
							 | 
						||
| 
								 | 
							
								    ])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def FishDaPondGoal(description, tile_info):
							 | 
						||
| 
								 | 
							
								    check_code, set_code = getUnusedBitFlag()
							 | 
						||
| 
								 | 
							
								    return Goal(description, check_code, tile_info, extra_patches=[
							 | 
						||
| 
								 | 
							
								        (0x04, 0x21F7, 0x21FC, ASM(set_code)),
							 | 
						||
| 
								 | 
							
								    ])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								BINGO_GOALS = [
							 | 
						||
| 
								 | 
							
								    InventoryGoal(BOOMERANG),
							 | 
						||
| 
								 | 
							
								    InventoryGoal(HOOKSHOT),
							 | 
						||
| 
								 | 
							
								    InventoryGoal(MAGIC_ROD),
							 | 
						||
| 
								 | 
							
								    InventoryGoal(PEGASUS_BOOTS),
							 | 
						||
| 
								 | 
							
								    InventoryGoal(FEATHER),
							 | 
						||
| 
								 | 
							
								    InventoryGoal(POWER_BRACELET),
							 | 
						||
| 
								 | 
							
								    Goal("Find the L2 {POWER_BRACELET}", checkMemoryEqualCode("$DB43", "2"), TileInfo(0x82, 0x83, 0x06, 0xB2)),
							 | 
						||
| 
								 | 
							
								    InventoryGoal(FLIPPERS, memory_location="wHasFlippers"),
							 | 
						||
| 
								 | 
							
								    InventoryGoal(OCARINA),
							 | 
						||
| 
								 | 
							
								    InventoryGoal(MEDICINE, memory_location="wHasMedicine", msg="Have the {MEDICINE}"),
							 | 
						||
| 
								 | 
							
								    InventoryGoal(BOW),
							 | 
						||
| 
								 | 
							
								    InventoryGoal(SHOVEL),
							 | 
						||
| 
								 | 
							
								    # InventoryGoal(MAGIC_POWDER),
							 | 
						||
| 
								 | 
							
								    InventoryGoal(TOADSTOOL, msg="Have the {TOADSTOOL}", group="witch"),
							 | 
						||
| 
								 | 
							
								    Goal("Find the L2 {SHIELD}", checkMemoryEqualCode("$DB44", "2"), TileInfo(0x86, 0x87, 0x06, 0xB2)),
							 | 
						||
| 
								 | 
							
								    Goal("Find 10 Secret Seashells", checkForSeashellsCode(10), ITEM_TILES[SEASHELL]),
							 | 
						||
| 
								 | 
							
								    Goal("Find the L2 {SWORD}", checkMemoryEqualCode("$DB4E", "2"), TileInfo(0x84, 0x85, 0x06, 0xB2)),
							 | 
						||
| 
								 | 
							
								    Goal("Find the {TAIL_KEY}", checkMemoryNotZero("$DB11"), TileInfo(0xC0, shift4=True)),
							 | 
						||
| 
								 | 
							
								    Goal("Find the {SLIME_KEY}", checkMemoryNotZero("$DB15"), TileInfo(0x28E, shift4=True)),
							 | 
						||
| 
								 | 
							
								    Goal("Find the {ANGLER_KEY}", checkMemoryNotZero("$DB12"), TileInfo(0xC2, shift4=True)),
							 | 
						||
| 
								 | 
							
								    Goal("Find the {FACE_KEY}", checkMemoryNotZero("$DB13"), TileInfo(0xC4, shift4=True)),
							 | 
						||
| 
								 | 
							
								    Goal("Find the {BIRD_KEY}", checkMemoryNotZero("$DB14"), TileInfo(0xC6, shift4=True)),
							 | 
						||
| 
								 | 
							
								    # {"description": "Marin's Cucco Killing Text"},
							 | 
						||
| 
								 | 
							
								    # {"description": "Pick up Crane Game Owner"},
							 | 
						||
| 
								 | 
							
								    BuzzBlobTalkGoal("Talk to a buzz blob", TileInfo(0x179C, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    # {"description": "Moblin King"},
							 | 
						||
| 
								 | 
							
								    Goal("Turtle Rock Entrance Boss", checkMemoryMask("$D810", "$20"),
							 | 
						||
| 
								 | 
							
								         TileInfo(0x1413, flipH=True, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Kill Master Stalfos", checkMemoryMask("$D980", "$10"), TileInfo(0x1622, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    # {"description": "Gohma"},
							 | 
						||
| 
								 | 
							
								    # {"description": "Grim Creeper"},
							 | 
						||
| 
								 | 
							
								    # {"description": "Blaino"},
							 | 
						||
| 
								 | 
							
								    KillDethlGoal("Kill Dethl", TileInfo(0x1B38, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    # {"description": "Rooster"},
							 | 
						||
| 
								 | 
							
								    # {"description": "Marin"},
							 | 
						||
| 
								 | 
							
								    # {"description": "Bow-wow"},
							 | 
						||
| 
								 | 
							
								    # {"description": "Return Bow-wow"},
							 | 
						||
| 
								 | 
							
								    # {"description": "8 Heart Pieces"},
							 | 
						||
| 
								 | 
							
								    # {"description": "12 Heart Pieces"},
							 | 
						||
| 
								 | 
							
								    Goal("{BOMB} upgrade", checkMemoryEqualCode("$DB77", "$60"), TileInfo(0x80, 0x81, 0x06, 0xA3)),
							 | 
						||
| 
								 | 
							
								    Goal("Arrow upgrade", checkMemoryEqualCode("$DB78", "$60"), TileInfo(0x88, 0x89, 0x06, 0xA3)),
							 | 
						||
| 
								 | 
							
								    Goal("{MAGIC_POWDER} upgrade", checkMemoryEqualCode("$DB76", "$40"), TileInfo(0x8E, 0x8F, 0x06, 0xA3)),
							 | 
						||
| 
								 | 
							
								    # {"description": "Steal From Shop 5 Times"},
							 | 
						||
| 
								 | 
							
								    KillGoal("Kill the giant ghini", 0x11, TileInfo(0x08A6, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Got the Ballad of the Wind Fish", checkMemoryMask("$DB49", "4"),
							 | 
						||
| 
								 | 
							
								         TileInfo(0x298, flipH=True, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Got the Manbo's Mambo", checkMemoryMask("$DB49", "2"), TileInfo(0x29A, flipH=True, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Got the Frog's Song of Soul", checkMemoryMask("$DB49", "1"),
							 | 
						||
| 
								 | 
							
								         TileInfo(0x29C, flipH=True, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Map and Compass in Tail Cave", checkMemoryNotZero("$DB16", "$DB17"), TileInfo(0x1BD0, index4=0xB1)),
							 | 
						||
| 
								 | 
							
								    Goal("Map and Compass in Bottle Grotto", checkMemoryNotZero("$DB1B", "$DB1C"), TileInfo(0x1BD0, index4=0xB2)),
							 | 
						||
| 
								 | 
							
								    Goal("Map and Compass in Key Cavern", checkMemoryNotZero("$DB20", "$DB21"), TileInfo(0x1BD0, index4=0xB3)),
							 | 
						||
| 
								 | 
							
								    Goal("Map and Compass in Angler's Tunnel", checkMemoryNotZero("$DB25", "$DB26"), TileInfo(0x1BD0, index4=0xB4)),
							 | 
						||
| 
								 | 
							
								    Goal("Map and Compass in Catfish's Maw", checkMemoryNotZero("$DB2A", "$DB2B"), TileInfo(0x1BD0, index4=0xB5)),
							 | 
						||
| 
								 | 
							
								    Goal("Map and Compass in Face Shrine", checkMemoryNotZero("$DB2F", "$DB30"), TileInfo(0x1BD0, index4=0xB6)),
							 | 
						||
| 
								 | 
							
								    Goal("Map and Compass in Eagle's Tower", checkMemoryNotZero("$DB34", "$DB35"), TileInfo(0x1BD0, index4=0xB7)),
							 | 
						||
| 
								 | 
							
								    Goal("Map and Compass in Turtle Rock", checkMemoryNotZero("$DB39", "$DB3A"), TileInfo(0x1BD0, index4=0xB8)),
							 | 
						||
| 
								 | 
							
								    Goal("Map and Compass in Color Dungeon", checkMemoryNotZero("$DDDA", "$DDDB"), TileInfo(0x1BD0, index4=0xB0)),
							 | 
						||
| 
								 | 
							
								    # {"description": "Talk to all Owl Statues in Tail Cave"},
							 | 
						||
| 
								 | 
							
								    # {"description": "Talk to all Owl Statues in Bottle Grotto"},
							 | 
						||
| 
								 | 
							
								    # {"description": "Talk to all Owl Statues in Key Cavern"},
							 | 
						||
| 
								 | 
							
								    # {"description": "Talk to all Owl Statues in Angler's Tunnel"},
							 | 
						||
| 
								 | 
							
								    # {"description": "Talk to all Owl Statues in Catfish's Maw"},
							 | 
						||
| 
								 | 
							
								    # {"description": "Talk to all Owl Statues in Face Shrine"},
							 | 
						||
| 
								 | 
							
								    # {"description": "Talk to all Owl Statues in Eagle's Tower"},
							 | 
						||
| 
								 | 
							
								    # {"description": "Talk to all Owl Statues in Turtle Rock"},
							 | 
						||
| 
								 | 
							
								    # {"description": "Talk to all Owl Statues in Color Dungeon"},
							 | 
						||
| 
								 | 
							
								    # {"description": "Defeat 2 Sets of 3-Of-A-Kind (D1, D7)"},
							 | 
						||
| 
								 | 
							
								    # {"description": "Stand 6 HorseHeads in D6"},
							 | 
						||
| 
								 | 
							
								    Goal("Find the 5 Golden Leaves", checkMemoryEqualGreater("wGoldenLeaves", "5"), ITEM_TILES[GOLD_LEAF]),
							 | 
						||
| 
								 | 
							
								    # {"description": "Defeat Mad Bomber (outside Kanalet Castle)"},
							 | 
						||
| 
								 | 
							
								    # {"description": "Totaka's Song in Richard's Villa"},
							 | 
						||
| 
								 | 
							
								    Goal("Get the Yoshi Doll", checkMemoryMask("$DAA0", "$20"), TileInfo(0x9A)),
							 | 
						||
| 
								 | 
							
								    # {"description": "Save Papahl on the mountain"},
							 | 
						||
| 
								 | 
							
								    Goal("Give the banana to Kiki", checkMemoryMask("$D87B", "$20"), TileInfo(0x1670, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Have 99 or less rupees", checkMemoryEqualCode("$DB5D", "0"), TileInfo(0xA6, 0xA7, shift4=True), group="rupees"),
							 | 
						||
| 
								 | 
							
								    Goal("Have 900 or more rupees", checkMemoryEqualGreater("$DB5D", "9"), TileInfo(0xA6, 0xA7, 0xA6, 0xA7), group="rupees"),
							 | 
						||
| 
								 | 
							
								    MonkeyGoal("Bonk the Beach Monkey", TileInfo(0x1946, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    # {"description": "Kill an enemy after transforming"},
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Goal("Got the Red Tunic", checkMemoryMask("wCollectedTunics", "1"),
							 | 
						||
| 
								 | 
							
								         TileInfo(0x2400, 0x0D11, 0x2400, 0x2401, flipH=True, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Got the Blue Tunic", checkMemoryMask("wCollectedTunics", "2"),
							 | 
						||
| 
								 | 
							
								         TileInfo(0x2400, 0x0D01, 0x2400, 0x2401, flipH=True, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Buy the first shop item", checkMemoryMask("$DAA1", "$10"), TileInfo(0x0880, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Buy the second shop item", checkMemoryMask("$DAA1", "$20"), TileInfo(0x0880, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Find the {INSTRUMENT1}", checkMemoryMask("$DB65", "2"), TileInfo(0x1500, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Find the {INSTRUMENT2}", checkMemoryMask("$DB66", "2"), TileInfo(0x1504, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Find the {INSTRUMENT3}", checkMemoryMask("$DB67", "2"), TileInfo(0x1508, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Find the {INSTRUMENT4}", checkMemoryMask("$DB68", "2"), TileInfo(0x150C, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Find the {INSTRUMENT5}", checkMemoryMask("$DB69", "2"), TileInfo(0x1510, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Find the {INSTRUMENT6}", checkMemoryMask("$DB6A", "2"), TileInfo(0x1514, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Find the {INSTRUMENT7}", checkMemoryMask("$DB6B", "2"), TileInfo(0x1518, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Find the {INSTRUMENT8}", checkMemoryMask("$DB6C", "2"), TileInfo(0x151C, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    # {"description": "Moldorm", "group": "d1"},
							 | 
						||
| 
								 | 
							
								    # {"description": "Genie in a Bottle", "group": "d2"},
							 | 
						||
| 
								 | 
							
								    # {"description": "Slime Eyes", "group": "d3"},
							 | 
						||
| 
								 | 
							
								    # {"description": "Angler Fish", "group": "d4"},
							 | 
						||
| 
								 | 
							
								    # {"description": "Slime Eel", "group": "d5"},
							 | 
						||
| 
								 | 
							
								    # {"description": "Facade", "group": "d6"},
							 | 
						||
| 
								 | 
							
								    # {"description": "Evil Eagle", "group": "d7"},
							 | 
						||
| 
								 | 
							
								    # {"description": "Hot Head", "group": "d8"},
							 | 
						||
| 
								 | 
							
								    # {"description": "2 Followers at the same time", "group": "multifollower"},
							 | 
						||
| 
								 | 
							
								    # {"description": "3 Followers at the same time", "group": "multifollower"},
							 | 
						||
| 
								 | 
							
								    Goal("Visit the 4 Fountain Fairies", checkMemoryMask(("$D853", "$D9AC", "$D9F3", "$D9FB"), "$80"),
							 | 
						||
| 
								 | 
							
								         TileInfo(0x20, shift4=True, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Have at least 8 Heart Containers", checkMemoryEqualGreater("$DB5B", "8"), TileInfo(0xAA, flipH=True), group="Health"),
							 | 
						||
| 
								 | 
							
								    Goal("Have at least 9 Heart Containers", checkMemoryEqualGreater("$DB5B", "9"), TileInfo(0xAA, flipH=True), group="Health"),
							 | 
						||
| 
								 | 
							
								    Goal("Have at least 10 Heart Containers", checkMemoryEqualGreater("$DB5B", "10"), TileInfo(0xAA, flipH=True), group="Health"),
							 | 
						||
| 
								 | 
							
								    Goal("Got photo 1: Here Stands A Brave Man", checkMemoryMask("$DC0C", "$01"), TileInfo(0x3008, 0x0D0F, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Got photo 2: Looking over the sea with Marin", checkMemoryMask("$DC0C", "$02"), TileInfo(0x08F0, 0x0D0F, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Got photo 3: Heads up!", checkMemoryMask("$DC0C", "$04"), TileInfo(0x0E6A, 0x0D0F, 0x0E6B, 0x0E7B)),
							 | 
						||
| 
								 | 
							
								    Goal("Got photo 4: Say Mushroom!", checkMemoryMask("$DC0C", "$08"), TileInfo(0x0E60, 0x0D0F, 0x0E61, 0x0E71)),
							 | 
						||
| 
								 | 
							
								    Goal("Got photo 5: Ulrira's Secret!", checkMemoryMask("$DC0C", "$10"),
							 | 
						||
| 
								 | 
							
								         TileInfo(0x1461, 0x1464, 0x1463, 0x0D0F, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Got photo 6: Playing with Bowwow!", checkMemoryMask("$DC0C", "$20"),
							 | 
						||
| 
								 | 
							
								         TileInfo(0x1A42, 0x0D0F, 0x1A42, 0x1A43, flipH=True, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Got photo 7: Thief!", checkMemoryMask("$DC0C", "$40"), TileInfo(0x0880, 0x0D0F, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Got photo 8: Be more careful next time!", checkMemoryMask("$DC0C", "$80"), TileInfo(0x14E0, index4=0x0D0F, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Got photo 9: I Found Zora!", checkMemoryMask("$DC0D", "$01"),
							 | 
						||
| 
								 | 
							
								         TileInfo(0x1906, 0x0D0F, 0x1906, 0x1907, flipH=True, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Got photo 10: Richard at Kanalet Castle", checkMemoryMask("$DC0D", "$02"), TileInfo(0x15B0, 0x0D0F, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Got photo 11: Ghost", checkMemoryMask("$DC0D", "$04"), TileInfo(0x1980, 0x0D0F, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Got photo 12: Close Call", checkMemoryMask("$DC0D", "$08"), TileInfo(0x0FED, 0x0D0F, 0x0FED, 0x0FFD)),
							 | 
						||
| 
								 | 
							
								    # {"description": "Collect 4 Pictures", "group": "pics"},
							 | 
						||
| 
								 | 
							
								    # {"description": "Collect 5 Pictures", "group": "pics"},
							 | 
						||
| 
								 | 
							
								    # {"description": "Collect 6 Pictures", "group": "pics"},
							 | 
						||
| 
								 | 
							
								    Goal("Open the 4 Overworld Warp Holes", checkMemoryMask(("$D801", "$D82C", "$D895", "$D8EC"), "$80"),
							 | 
						||
| 
								 | 
							
								         TileInfo(0x3E, 0x3E, 0x3E, 0x3E, colormap=[2, 1, 3, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Finish the Raft Minigame", checkMemoryMask("$D87F", "$80"), TileInfo(0x087C, flipH=True, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Kill the Ball and Chain Trooper", checkMemoryMask("$DAC6", "$10"), TileInfo(0x09A4, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Destroy all Pillars with the Ball", checkMemoryMask(("$DA14", "$DA15", "$DA18", "$DA19"), "$20"),
							 | 
						||
| 
								 | 
							
								         TileInfo(0x166C, flipH=True)),
							 | 
						||
| 
								 | 
							
								    FishDaPondGoal("Fish the pond empty", TileInfo(0x0A00, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    KillGoal("Kill the Anti-Kirby", 0x91, TileInfo(0x1550, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    KillGoal("Kill a Rolling Bones", 0x81, TileInfo(0x0AB6, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    KillGoal("Kill a Hinox", 0x89, TileInfo(0x1542, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    KillGoal("Kill a Stone Hinox", 0xF4, TileInfo(0x2482, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    KillGoal("Kill a Dodongo", 0x60, TileInfo(0x0AA0, flipH=True, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    KillGoal("Kill a Cue Ball", 0x8E, TileInfo(0x1566, flipH=True, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    KillGoal("Kill a Smasher", 0x92, TileInfo(0x1576, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Goal("Save Marin on the Mountain Bridge", checkMemoryMask("$D808", "$10"), TileInfo(0x1A6C, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Save Raccoon Tarin", checkMemoryMask("$D851", "$10"), TileInfo(0x1888, colormap=[2, 3, 1, 0])),
							 | 
						||
| 
								 | 
							
								    Goal("Trade the {TOADSTOOL} with the witch", checkMemoryMask("$DAA2", "$20"), TileInfo(0x0A30, colormap=[2, 3, 1, 0]), group="witch"),
							 | 
						||
| 
								 | 
							
								]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def randomizeGoals(rnd, options):
							 | 
						||
| 
								 | 
							
								    goals = BINGO_GOALS.copy()
							 | 
						||
| 
								 | 
							
								    rnd.shuffle(goals)
							 | 
						||
| 
								 | 
							
								    has_group = set()
							 | 
						||
| 
								 | 
							
								    for n in range(len(goals)):
							 | 
						||
| 
								 | 
							
								        if goals[n].group:
							 | 
						||
| 
								 | 
							
								            if goals[n].group in has_group:
							 | 
						||
| 
								 | 
							
								                goals[n] = None
							 | 
						||
| 
								 | 
							
								            else:
							 | 
						||
| 
								 | 
							
								                has_group.add(goals[n].group)
							 | 
						||
| 
								 | 
							
								    goals = [goal for goal in goals if goal is not None]
							 | 
						||
| 
								 | 
							
								    return goals[:25]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def setBingoGoal(rom, goals, mode):
							 | 
						||
| 
								 | 
							
								    assert len(goals) == 25
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for goal in goals:
							 | 
						||
| 
								 | 
							
								        for bank, addr, current, target in goal.extra_patches:
							 | 
						||
| 
								 | 
							
								            rom.patch(bank, addr, current, target)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Setup the bingo card visuals
							 | 
						||
| 
								 | 
							
								    be = BackgroundEditor(rom, 0x15)
							 | 
						||
| 
								 | 
							
								    ba = BackgroundEditor(rom, 0x15, attributes=True)
							 | 
						||
| 
								 | 
							
								    for y in range(18):
							 | 
						||
| 
								 | 
							
								        for x in range(20):
							 | 
						||
| 
								 | 
							
								            be.tiles[0x9800 + x + y * 0x20] = (x + (y & 2)) % 4 | ((y % 2) * 4)
							 | 
						||
| 
								 | 
							
								            ba.tiles[0x9800 + x + y * 0x20] = 0x01
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for y in range(5):
							 | 
						||
| 
								 | 
							
								        for x in range(5):
							 | 
						||
| 
								 | 
							
								            idx = x + y * 5
							 | 
						||
| 
								 | 
							
								            be.tiles[0x9843 + x * 3 + y * 3 * 0x20] = 8 + idx * 4
							 | 
						||
| 
								 | 
							
								            be.tiles[0x9844 + x * 3 + y * 3 * 0x20] = 10 + idx * 4
							 | 
						||
| 
								 | 
							
								            be.tiles[0x9863 + x * 3 + y * 3 * 0x20] = 9 + idx * 4
							 | 
						||
| 
								 | 
							
								            be.tiles[0x9864 + x * 3 + y * 3 * 0x20] = 11 + idx * 4
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            ba.tiles[0x9843 + x * 3 + y * 3 * 0x20] = 0x03
							 | 
						||
| 
								 | 
							
								            ba.tiles[0x9844 + x * 3 + y * 3 * 0x20] = 0x03
							 | 
						||
| 
								 | 
							
								            ba.tiles[0x9863 + x * 3 + y * 3 * 0x20] = 0x03
							 | 
						||
| 
								 | 
							
								            ba.tiles[0x9864 + x * 3 + y * 3 * 0x20] = 0x03
							 | 
						||
| 
								 | 
							
								    be.store(rom)
							 | 
						||
| 
								 | 
							
								    ba.store(rom)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    tiles = rom.banks[0x30][0x3000:0x3040] + rom.banks[0x30][0x3100:0x3140]
							 | 
						||
| 
								 | 
							
								    for goal in goals:
							 | 
						||
| 
								 | 
							
								        tiles += goal.tile_info.get(rom)
							 | 
						||
| 
								 | 
							
								    rom.banks[0x30][0x3000:0x3000 + len(tiles)] = tiles
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Patch the mural palette to have more useful entries for us
							 | 
						||
| 
								 | 
							
								    rom.patch(0x21, 0x36EE, ASM("dw $7C00, $7C00, $7C00, $7C00"), ASM("dw $7FFF, $56b5, $294a, $0000"))
							 | 
						||
| 
								 | 
							
								    rom.patch(0x21, 0x36F6, ASM("dw $7C00, $7C00, $7C00, $7C00"), ASM("dw $43f0, $32ac, $1946, $0000"))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Patch the face shrine mural handler stage 4, we want to jump to bank 0x0C, which normally contains
							 | 
						||
| 
								 | 
							
								    # DMG graphics, but gives us a lot of room for our own code and graphics.
							 | 
						||
| 
								 | 
							
								    rom.patch(0x01, 0x2B81, 0x2B99, ASM("""
							 | 
						||
| 
								 | 
							
								        ld   a,  $0D
							 | 
						||
| 
								 | 
							
								        ld   hl, $4000
							 | 
						||
| 
								 | 
							
								        push hl
							 | 
						||
| 
								 | 
							
								        jp   $080C ; switch bank
							 | 
						||
| 
								 | 
							
								    """), fill_nop=True)
							 | 
						||
| 
								 | 
							
								    # Fix that the mural is always centered on screen, instead offset it properly
							 | 
						||
| 
								 | 
							
								    rom.patch(0x18, 0x1E3D, ASM("add hl, bc\nld [hl], $50"), ASM("call $7FD6"))
							 | 
						||
| 
								 | 
							
								    rom.patch(0x18, 0x3FD6, "00" * 8, ASM("""
							 | 
						||
| 
								 | 
							
								        add hl, bc
							 | 
						||
| 
								 | 
							
								        ld  a, [hl]
							 | 
						||
| 
								 | 
							
								        and $F0
							 | 
						||
| 
								 | 
							
								        add a, $0F
							 | 
						||
| 
								 | 
							
								        ld  [hl], a
							 | 
						||
| 
								 | 
							
								        ret
							 | 
						||
| 
								 | 
							
								    """))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # In stage 5, just exit the mural without waiting for a button press.
							 | 
						||
| 
								 | 
							
								    rom.patch(0x01, 0x2B9E, ASM("jr z, $07"), "", fill_nop=True)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Our custom stage 4
							 | 
						||
| 
								 | 
							
								    rom.patch(0x0D, 0x0000, 0x3000, ASM("""
							 | 
						||
| 
								 | 
							
								wState := $C3C4 ; Our internal state, guaranteed to be 0 on the first entry.
							 | 
						||
| 
								 | 
							
								wCursorX := $D100
							 | 
						||
| 
								 | 
							
								wCursorY := $D101
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    call mainHandler
							 | 
						||
| 
								 | 
							
								    ; Make sure we return with bank 1 active.
							 | 
						||
| 
								 | 
							
								    ld   a, $01
							 | 
						||
| 
								 | 
							
								    jp   $080C ; switch bank
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								mainHandler:
							 | 
						||
| 
								 | 
							
								    ld   a, [wState]
							 | 
						||
| 
								 | 
							
								    rst  0
							 | 
						||
| 
								 | 
							
								    dw   init
							 | 
						||
| 
								 | 
							
								    dw   checkGoalDone
							 | 
						||
| 
								 | 
							
								    dw   chooseSquare
							 | 
						||
| 
								 | 
							
								    dw   waitDialogDone
							 | 
						||
| 
								 | 
							
								    dw   finishGame
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								init:
							 | 
						||
| 
								 | 
							
								    xor  a
							 | 
						||
| 
								 | 
							
								    ld   [wCursorX], a
							 | 
						||
| 
								 | 
							
								    ld   [wCursorY], a
							 | 
						||
| 
								 | 
							
								    inc  a
							 | 
						||
| 
								 | 
							
								    ld   [wState], a
							 | 
						||
| 
								 | 
							
								    di
							 | 
						||
| 
								 | 
							
								    ldh  [$4F], a ; 2nd vram bank
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ld   hl, $9843
							 | 
						||
| 
								 | 
							
								    ld   c, 25
							 | 
						||
| 
								 | 
							
								    ld   b, $00
							 | 
						||
| 
								 | 
							
								.checkDoneLoop:
							 | 
						||
| 
								 | 
							
								    push bc
							 | 
						||
| 
								 | 
							
								    push hl
							 | 
						||
| 
								 | 
							
								    ld   a, b
							 | 
						||
| 
								 | 
							
								    call goalCheck
							 | 
						||
| 
								 | 
							
								    pop  hl
							 | 
						||
| 
								 | 
							
								    jr   nz, .notDone
							 | 
						||
| 
								 | 
							
								.statWait1:
							 | 
						||
| 
								 | 
							
								    ldh  a, [$41] ;STAT
							 | 
						||
| 
								 | 
							
								    and  $02
							 | 
						||
| 
								 | 
							
								    jr   nz, .statWait1 
							 | 
						||
| 
								 | 
							
								    ld   a, $04
							 | 
						||
| 
								 | 
							
								    ldi  [hl], a
							 | 
						||
| 
								 | 
							
								    ldd  [hl], a
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ld   bc, $0020
							 | 
						||
| 
								 | 
							
								    add  hl, bc
							 | 
						||
| 
								 | 
							
								.statWait2:
							 | 
						||
| 
								 | 
							
								    ldh  a, [$41] ;STAT
							 | 
						||
| 
								 | 
							
								    and  $02
							 | 
						||
| 
								 | 
							
								    jr   nz, .statWait2 
							 | 
						||
| 
								 | 
							
								    ld   a, $04
							 | 
						||
| 
								 | 
							
								    ldi  [hl], a
							 | 
						||
| 
								 | 
							
								    ldd  [hl], a
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ld   bc, $FFE0
							 | 
						||
| 
								 | 
							
								    add  hl, bc
							 | 
						||
| 
								 | 
							
								.notDone:
							 | 
						||
| 
								 | 
							
								    inc  hl
							 | 
						||
| 
								 | 
							
								    inc  hl
							 | 
						||
| 
								 | 
							
								    inc  hl
							 | 
						||
| 
								 | 
							
								    ld   a, l
							 | 
						||
| 
								 | 
							
								    and  $1F
							 | 
						||
| 
								 | 
							
								    cp   $12
							 | 
						||
| 
								 | 
							
								    jr   nz, .noRowSkip
							 | 
						||
| 
								 | 
							
								    ld   bc, $0060 - 5*3
							 | 
						||
| 
								 | 
							
								    add  hl, bc
							 | 
						||
| 
								 | 
							
								.noRowSkip:
							 | 
						||
| 
								 | 
							
								    pop  bc
							 | 
						||
| 
								 | 
							
								    inc  b
							 | 
						||
| 
								 | 
							
								    dec  c
							 | 
						||
| 
								 | 
							
								    jr   nz, .checkDoneLoop
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    xor  a
							 | 
						||
| 
								 | 
							
								    ldh  [$4F], a ; 1st vram bank
							 | 
						||
| 
								 | 
							
								    ei
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								checkGoalDone:
							 | 
						||
| 
								 | 
							
								    ld   a, $02
							 | 
						||
| 
								 | 
							
								    ld   [wState], a
							 | 
						||
| 
								 | 
							
								    ; Check if the egg event is already triggered
							 | 
						||
| 
								 | 
							
								    ld   a, [$D806]
							 | 
						||
| 
								 | 
							
								    and  $10
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    call checkAnyGoal
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ; Goal done, give a message and goto state to finish the game
							 | 
						||
| 
								 | 
							
								    ld   a, $04
							 | 
						||
| 
								 | 
							
								    ld   [wState], a
							 | 
						||
| 
								 | 
							
								    ld   a, $E7 
							 | 
						||
| 
								 | 
							
								    call $2385 ; open dialog 
							 | 
						||
| 
								 | 
							
								    ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								chooseSquare:
							 | 
						||
| 
								 | 
							
								    ld   hl, $C000 ; oam buffer
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ; Draw the cursor
							 | 
						||
| 
								 | 
							
								    ld   a, [wCursorY]
							 | 
						||
| 
								 | 
							
								    call multiA24
							 | 
						||
| 
								 | 
							
								    add  a, $27
							 | 
						||
| 
								 | 
							
								    ldi  [hl], a
							 | 
						||
| 
								 | 
							
								    ld   a, [wCursorX]
							 | 
						||
| 
								 | 
							
								    call multiA24
							 | 
						||
| 
								 | 
							
								    add  a, $24
							 | 
						||
| 
								 | 
							
								    ldi  [hl], a
							 | 
						||
| 
								 | 
							
								    ld   a, $A2
							 | 
						||
| 
								 | 
							
								    ldi  [hl], a
							 | 
						||
| 
								 | 
							
								    ld   a, $02
							 | 
						||
| 
								 | 
							
								    ldi  [hl], a
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ldh  a, [$CC] ; button presses
							 | 
						||
| 
								 | 
							
								    bit  0, a
							 | 
						||
| 
								 | 
							
								    jr   nz, .right
							 | 
						||
| 
								 | 
							
								    bit  1, a
							 | 
						||
| 
								 | 
							
								    jr   nz, .left
							 | 
						||
| 
								 | 
							
								    bit  2, a
							 | 
						||
| 
								 | 
							
								    jr   nz, .up
							 | 
						||
| 
								 | 
							
								    bit  3, a
							 | 
						||
| 
								 | 
							
								    jr   nz, .down
							 | 
						||
| 
								 | 
							
								    bit  4, a
							 | 
						||
| 
								 | 
							
								    jr   nz, .showText
							 | 
						||
| 
								 | 
							
								    bit  5, a
							 | 
						||
| 
								 | 
							
								    jr   nz, exitMural
							 | 
						||
| 
								 | 
							
								    bit  7, a
							 | 
						||
| 
								 | 
							
								    jr   nz, exitMural
							 | 
						||
| 
								 | 
							
								    ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.right:
							 | 
						||
| 
								 | 
							
								    ld   a, [wCursorX]
							 | 
						||
| 
								 | 
							
								    cp   $04
							 | 
						||
| 
								 | 
							
								    ret  z
							 | 
						||
| 
								 | 
							
								    inc  a
							 | 
						||
| 
								 | 
							
								    ld   [wCursorX], a
							 | 
						||
| 
								 | 
							
								    ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.left:
							 | 
						||
| 
								 | 
							
								    ld   a, [wCursorX]
							 | 
						||
| 
								 | 
							
								    and  a
							 | 
						||
| 
								 | 
							
								    ret  z
							 | 
						||
| 
								 | 
							
								    dec  a
							 | 
						||
| 
								 | 
							
								    ld   [wCursorX], a
							 | 
						||
| 
								 | 
							
								    ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.down:
							 | 
						||
| 
								 | 
							
								    ld   a, [wCursorY]
							 | 
						||
| 
								 | 
							
								    cp   $04
							 | 
						||
| 
								 | 
							
								    ret  z
							 | 
						||
| 
								 | 
							
								    inc  a
							 | 
						||
| 
								 | 
							
								    ld   [wCursorY], a
							 | 
						||
| 
								 | 
							
								    ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.up:
							 | 
						||
| 
								 | 
							
								    ld   a, [wCursorY]
							 | 
						||
| 
								 | 
							
								    and  a
							 | 
						||
| 
								 | 
							
								    ret  z
							 | 
						||
| 
								 | 
							
								    dec  a
							 | 
						||
| 
								 | 
							
								    ld   [wCursorY], a
							 | 
						||
| 
								 | 
							
								    ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.showText:
							 | 
						||
| 
								 | 
							
								    ld   a, [wCursorY]
							 | 
						||
| 
								 | 
							
								    ld   c, a
							 | 
						||
| 
								 | 
							
								    add  a, a
							 | 
						||
| 
								 | 
							
								    add  a, a
							 | 
						||
| 
								 | 
							
								    add  a, c
							 | 
						||
| 
								 | 
							
								    ld   c, a
							 | 
						||
| 
								 | 
							
								    ld   a, [wCursorX]
							 | 
						||
| 
								 | 
							
								    add  a, c
							 | 
						||
| 
								 | 
							
								    add  a, a
							 | 
						||
| 
								 | 
							
								    ld   l, a
							 | 
						||
| 
								 | 
							
								    ld   h, $00
							 | 
						||
| 
								 | 
							
								    ld   de, messageTable
							 | 
						||
| 
								 | 
							
								    add  hl, de
							 | 
						||
| 
								 | 
							
								    ldi  a, [hl]
							 | 
						||
| 
								 | 
							
								    ld   h, [hl]
							 | 
						||
| 
								 | 
							
								    ld   l, a
							 | 
						||
| 
								 | 
							
								    ld   de, wCustomMessage
							 | 
						||
| 
								 | 
							
								.copyLoop:
							 | 
						||
| 
								 | 
							
								    ldi  a, [hl]
							 | 
						||
| 
								 | 
							
								    ld   [de], a
							 | 
						||
| 
								 | 
							
								    inc  de
							 | 
						||
| 
								 | 
							
								    inc  a
							 | 
						||
| 
								 | 
							
								    jr   nz, .copyLoop
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ld   a, $C9 
							 | 
						||
| 
								 | 
							
								    call $2385 ; open dialog 
							 | 
						||
| 
								 | 
							
								    ld   a, $03
							 | 
						||
| 
								 | 
							
								    ld   [wState], a
							 | 
						||
| 
								 | 
							
								    ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								waitDialogDone:
							 | 
						||
| 
								 | 
							
								    ld   a, [$C19F] ; dialog state
							 | 
						||
| 
								 | 
							
								    and  a
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    ld   a, $02 ; choose square
							 | 
						||
| 
								 | 
							
								    ld   [wState], a
							 | 
						||
| 
								 | 
							
								    ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								finishGame:
							 | 
						||
| 
								 | 
							
								    ld   a, [$C19F] ; dialog state
							 | 
						||
| 
								 | 
							
								    and  a
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    ldh  a, [$CC] ; button presses
							 | 
						||
| 
								 | 
							
								    and  a
							 | 
						||
| 
								 | 
							
								    ret  z
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    ; Goto "credits"
							 | 
						||
| 
								 | 
							
								    xor  a
							 | 
						||
| 
								 | 
							
								    ld   [$DB96], a 
							 | 
						||
| 
								 | 
							
								    inc  a
							 | 
						||
| 
								 | 
							
								    ld   [$DB95], a
							 | 
						||
| 
								 | 
							
								    ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								exitMural:
							 | 
						||
| 
								 | 
							
								    ld   hl, $DB96 ;gameplay subtype 
							 | 
						||
| 
								 | 
							
								    inc  [hl]
							 | 
						||
| 
								 | 
							
								    ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								multiA24:
							 | 
						||
| 
								 | 
							
								    ld   c, a
							 | 
						||
| 
								 | 
							
								    add  a, a
							 | 
						||
| 
								 | 
							
								    add  a, c
							 | 
						||
| 
								 | 
							
								    add  a, a
							 | 
						||
| 
								 | 
							
								    add  a, a
							 | 
						||
| 
								 | 
							
								    add  a, a
							 | 
						||
| 
								 | 
							
								    ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								flipZ:
							 | 
						||
| 
								 | 
							
								    jr   nz, setZ
							 | 
						||
| 
								 | 
							
								clearZ: 
							 | 
						||
| 
								 | 
							
								    rra
							 | 
						||
| 
								 | 
							
								    ret
							 | 
						||
| 
								 | 
							
								setZ:
							 | 
						||
| 
								 | 
							
								    cp   a
							 | 
						||
| 
								 | 
							
								    ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								checkAnyGoal:
							 | 
						||
| 
								 | 
							
								#IF {mode}
							 | 
						||
| 
								 | 
							
								    call goalcheck_0
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_1
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_2
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_3
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_4
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_5
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_6
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_7
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_8
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_9
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_10
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_11
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_12
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_13
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_14
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_15
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_16
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_17
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_18
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_19
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_20
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_21
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_22
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_23
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_24
							 | 
						||
| 
								 | 
							
								    ret
							 | 
						||
| 
								 | 
							
								#ELSE
							 | 
						||
| 
								 | 
							
								    call checkGoalRow1
							 | 
						||
| 
								 | 
							
								    ret  z
							 | 
						||
| 
								 | 
							
								    call checkGoalRow2
							 | 
						||
| 
								 | 
							
								    ret  z
							 | 
						||
| 
								 | 
							
								    call checkGoalRow3
							 | 
						||
| 
								 | 
							
								    ret  z
							 | 
						||
| 
								 | 
							
								    call checkGoalRow4
							 | 
						||
| 
								 | 
							
								    ret  z
							 | 
						||
| 
								 | 
							
								    call checkGoalRow5
							 | 
						||
| 
								 | 
							
								    ret  z
							 | 
						||
| 
								 | 
							
								    call checkGoalCol1
							 | 
						||
| 
								 | 
							
								    ret  z
							 | 
						||
| 
								 | 
							
								    call checkGoalCol2
							 | 
						||
| 
								 | 
							
								    ret  z
							 | 
						||
| 
								 | 
							
								    call checkGoalCol3
							 | 
						||
| 
								 | 
							
								    ret  z
							 | 
						||
| 
								 | 
							
								    call checkGoalCol4
							 | 
						||
| 
								 | 
							
								    ret  z
							 | 
						||
| 
								 | 
							
								    call checkGoalCol5
							 | 
						||
| 
								 | 
							
								    ret  z
							 | 
						||
| 
								 | 
							
								    call checkGoalDiagonal0
							 | 
						||
| 
								 | 
							
								    ret  z
							 | 
						||
| 
								 | 
							
								    call checkGoalDiagonal1
							 | 
						||
| 
								 | 
							
								    ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								checkGoalRow1:
							 | 
						||
| 
								 | 
							
								    call goalcheck_0
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_1
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_2
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_3
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_4
							 | 
						||
| 
								 | 
							
								    ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								checkGoalRow2:
							 | 
						||
| 
								 | 
							
								    call goalcheck_5
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_6
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_7
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_8
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_9
							 | 
						||
| 
								 | 
							
								    ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								checkGoalRow3:
							 | 
						||
| 
								 | 
							
								    call goalcheck_10
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_11
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_12
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_13
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_14
							 | 
						||
| 
								 | 
							
								    ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								checkGoalRow4:
							 | 
						||
| 
								 | 
							
								    call goalcheck_15
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_16
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_17
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_18
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_19
							 | 
						||
| 
								 | 
							
								    ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								checkGoalRow5:
							 | 
						||
| 
								 | 
							
								    call goalcheck_20
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_21
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_22
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_23
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_24
							 | 
						||
| 
								 | 
							
								    ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								checkGoalCol1:
							 | 
						||
| 
								 | 
							
								    call goalcheck_0
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_5
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_10
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_15
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_20
							 | 
						||
| 
								 | 
							
								    ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								checkGoalCol2:
							 | 
						||
| 
								 | 
							
								    call goalcheck_1
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_6
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_11
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_16
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_21
							 | 
						||
| 
								 | 
							
								    ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								checkGoalCol3:
							 | 
						||
| 
								 | 
							
								    call goalcheck_2
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_7
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_12
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_17
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_22
							 | 
						||
| 
								 | 
							
								    ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								checkGoalCol4:
							 | 
						||
| 
								 | 
							
								    call goalcheck_3
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_8
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_13
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_18
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_23
							 | 
						||
| 
								 | 
							
								    ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								checkGoalCol5:
							 | 
						||
| 
								 | 
							
								    call goalcheck_4
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_9
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_14
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_19
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_24
							 | 
						||
| 
								 | 
							
								    ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								checkGoalDiagonal0:
							 | 
						||
| 
								 | 
							
								    call goalcheck_0
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_6
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_12
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_18
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_24
							 | 
						||
| 
								 | 
							
								    ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								checkGoalDiagonal1:
							 | 
						||
| 
								 | 
							
								    call goalcheck_4
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_8
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_12
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_16
							 | 
						||
| 
								 | 
							
								    ret  nz
							 | 
						||
| 
								 | 
							
								    call goalcheck_20
							 | 
						||
| 
								 | 
							
								    ret
							 | 
						||
| 
								 | 
							
								#ENDIF
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								messageTable:
							 | 
						||
| 
								 | 
							
								""".format(mode=1 if mode == "bingo-full" else 0) +
							 | 
						||
| 
								 | 
							
								    "\n".join(["dw message_%d" % (n) for n in range(25)]) + "\n" +
							 | 
						||
| 
								 | 
							
								    "\n".join(["message_%d:\n  db m\"%s\"" % (n, goal.description) for n, goal in
							 | 
						||
| 
								 | 
							
								               enumerate(goals)]) + "\n" +
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    goalCheck:
							 | 
						||
| 
								 | 
							
								        rst  0
							 | 
						||
| 
								 | 
							
								    """ +
							 | 
						||
| 
								 | 
							
								    "\n".join(["dw goalcheck_%d" % (n) for n in range(25)]) + "\n" +
							 | 
						||
| 
								 | 
							
								    "\n".join(["goalcheck_%d:\n  %s\n" % (n, goal.code) for n, goal in
							 | 
						||
| 
								 | 
							
								               enumerate(goals)]) + "\n", 0x4000), fill_nop=True)
							 | 
						||
| 
								 | 
							
								    rom.texts[0xE7] = formatText("BINGO!\nPress any button to finish.")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Patch the game to call a bit of our code when an enemy is killed by patching into the drop item handling
							 | 
						||
| 
								 | 
							
								    rom.patch(0x00, 0x3F50, ASM("ld a, $03\nld [$C113], a\nld [$2100], a\ncall $55CF"), ASM("""
							 | 
						||
| 
								 | 
							
								        ld a, $0D
							 | 
						||
| 
								 | 
							
								        ld [$C113], a
							 | 
						||
| 
								 | 
							
								        ld [$2100], a
							 | 
						||
| 
								 | 
							
								        call $7000
							 | 
						||
| 
								 | 
							
								    """))
							 | 
						||
| 
								 | 
							
								    rom.patch(0x0D, 0x3000, 0x4000, ASM("""
							 | 
						||
| 
								 | 
							
								        ldh  a, [$EB] ; active entity
							 | 
						||
| 
								 | 
							
								    """ + "\n".join([goal.kill_code for goal in goals if goal.kill_code is not None]) + """
							 | 
						||
| 
								 | 
							
								done:   ; Return to normal item drop handler
							 | 
						||
| 
								 | 
							
								        ld   a,  $03   ;normal drop item handler bank
							 | 
						||
| 
								 | 
							
								        ld   hl, $55CF ;normal drop item handler address
							 | 
						||
| 
								 | 
							
								        push hl
							 | 
						||
| 
								 | 
							
								        jp   $080F ; switch bank
							 | 
						||
| 
								 | 
							
								    """, 0x7000), fill_nop=True)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Patch Dethl to warp you outside
							 | 
						||
| 
								 | 
							
								    rom.patch(0x15, 0x0682, 0x069B, ASM("""
							 | 
						||
| 
								 | 
							
								        ld   a, $0B
							 | 
						||
| 
								 | 
							
								        ld   [$DB95], a
							 | 
						||
| 
								 | 
							
								        call $0C7D
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        ld   a, $07
							 | 
						||
| 
								 | 
							
								        ld   [$DB96], a
							 | 
						||
| 
								 | 
							
								    """), fill_nop=True)
							 | 
						||
| 
								 | 
							
								    re = RoomEditor(rom, 0x274)
							 | 
						||
| 
								 | 
							
								    re.objects += [ObjectWarp(0, 0, 0x06, 0x58, 0x40)] * 4
							 | 
						||
| 
								 | 
							
								    re.store(rom)
							 | 
						||
| 
								 | 
							
								    # Patch the egg to be always open
							 | 
						||
| 
								 | 
							
								    rom.patch(0x00, 0x31f5, ASM("ld a, [$D806]\nand $10\njr z, $25"), ASM(""), fill_nop=True)
							 | 
						||
| 
								 | 
							
								    rom.patch(0x20, 0x2dea, ASM("ld a, [$D806]\nand $10\njr z, $29"), ASM(""), fill_nop=True)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Patch unused entity 4C into our bingo board.
							 | 
						||
| 
								 | 
							
								    rom.patch(0x03, 0x004C, "41", "82")
							 | 
						||
| 
								 | 
							
								    rom.patch(0x03, 0x0147, "00", "98")
							 | 
						||
| 
								 | 
							
								    rom.patch(0x20, 0x00e4, "000000", ASM("dw $5e1b\ndb $18"))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Add graphics for our bingo board to 2nd WRAM bank.
							 | 
						||
| 
								 | 
							
								    rom.banks[0x3F][0x3700:0x3780] = rom.banks[0x32][0x1500:0x1580]
							 | 
						||
| 
								 | 
							
								    rom.banks[0x3F][0x3728:0x373A] = b'\x55\xAA\x00\xFF\x55\xAA\x00\xFF\x55\xAA\x00\xFF\x55\xAA\x00\xFF\x00\xFF'
							 | 
						||
| 
								 | 
							
								    rom.banks[0x3F][0x3748:0x375A] = b'\x55\xAA\x00\xFF\x55\xAA\x00\xFF\x55\xAA\x00\xFF\x55\xAA\x00\xFF\x00\xFF'
							 | 
						||
| 
								 | 
							
								    rom.patch(0x18, 0x1E0B,
							 | 
						||
| 
								 | 
							
								              "00F85003" + "00005203" + "00085403" + "00105603",
							 | 
						||
| 
								 | 
							
								              "00F8F00B" + "0000F20B" + "0008F40B" + "0010F60B")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Add the bingo board to marins house
							 | 
						||
| 
								 | 
							
								    re = RoomEditor(rom, 0x2A3)
							 | 
						||
| 
								 | 
							
								    re.entities.append((2, 0, 0x4C))
							 | 
						||
| 
								 | 
							
								    re.store(rom)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Add the bingo board to the room before the egg
							 | 
						||
| 
								 | 
							
								    re = RoomEditor(rom, 0x016)
							 | 
						||
| 
								 | 
							
								    re.removeObject(4, 5)
							 | 
						||
| 
								 | 
							
								    re.entities.append((3, 4, 0x4C))
							 | 
						||
| 
								 | 
							
								    re.updateOverlay()
							 | 
						||
| 
								 | 
							
								    re.store(rom)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Remove the egg event from the egg room (no bomb triggers for you!)
							 | 
						||
| 
								 | 
							
								    re = RoomEditor(rom, 0x006)
							 | 
						||
| 
								 | 
							
								    re.entities = []
							 | 
						||
| 
								 | 
							
								    re.store(rom)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    rom.texts[0xCF] = formatText("""
							 | 
						||
| 
								 | 
							
								        Bingo!
							 | 
						||
| 
								 | 
							
								        Young lad, I mean... #####, the hero!
							 | 
						||
| 
								 | 
							
								        You have bingo!
							 | 
						||
| 
								 | 
							
								        You have proven your wisdom, courage and power!
							 | 
						||
| 
								 | 
							
								        ... ... ... ...
							 | 
						||
| 
								 | 
							
								        As part of the Wind Fish's spirit, I am the guardian of his dream world...
							 | 
						||
| 
								 | 
							
								        But one day, we decided to have a bingo game.
							 | 
						||
| 
								 | 
							
								        Then you, #####, came to win the bingo...
							 | 
						||
| 
								 | 
							
								        Thank you, #####...
							 | 
						||
| 
								 | 
							
								        My work is done...
							 | 
						||
| 
								 | 
							
								        The Wind Fish will wake soon.
							 | 
						||
| 
								 | 
							
								        Good bye...Bingo!
							 | 
						||
| 
								 | 
							
								    """)
							 | 
						||
| 
								 | 
							
								    rom.texts[0xCE] = rom.texts[0xCF]
							 |