Пример #1
0
def evade_mblock(fout):
    evade_mblock_sub = Substitution()
    evade_mblock_sub.bytestring = bytes([
        0xF0, 0x17, 0x20, 0x5A, 0x4B, 0xC9, 0x40, 0xB0, 0x9C, 0xB9, 0xFD, 0x3D,
        0x09, 0x04, 0x99, 0xFD, 0x3D, 0x80, 0x92, 0xB9, 0x55, 0x3B, 0x48, 0x80,
        0x43, 0xB9, 0x54, 0x3B, 0x48, 0xEA
    ])
    evade_mblock_sub.set_location(0x2232C)
    evade_mblock_sub.write(fout)
Пример #2
0
def make_palette_repair(fout, main_palette_changes):
    repair_sub = Substitution()
    bytestring = []
    for c in sorted(main_palette_changes):
        _, after = main_palette_changes[c]
        bytestring.extend([0x43, c, after])
    repair_sub.bytestring = bytestring + [0xFE]
    repair_sub.set_location(0xCB154)  # Narshe secret entrance
    repair_sub.write(fout)
Пример #3
0
def vanish_doom(fout):
    vanish_doom_sub = Substitution()
    vanish_doom_sub.bytestring = bytes([
        0xAD, 0xA2, 0x11, 0x89, 0x02, 0xF0, 0x07, 0xB9, 0xA1, 0x3A, 0x89, 0x04,
        0xD0, 0x6E, 0xA5, 0xB3, 0x10, 0x1C, 0xB9, 0xE4, 0x3E, 0x89, 0x10, 0xF0,
        0x15, 0xAD, 0xA4, 0x11, 0x0A, 0x30, 0x07, 0xAD, 0xA2, 0x11, 0x4A, 0x4C,
        0xB3, 0x22, 0xB9, 0xFC, 0x3D, 0x09, 0x10, 0x99, 0xFC, 0x3D, 0xAD, 0xA3,
        0x11, 0x89, 0x02, 0xD0, 0x0F, 0xB9, 0xF8, 0x3E, 0x10, 0x0A, 0xC2, 0x20,
        0xB9, 0x18, 0x30, 0x04, 0xA6, 0x4C, 0xE5, 0x22
    ])
    vanish_doom_sub.set_location(0x22215)
    vanish_doom_sub.write(fout)
Пример #4
0
def change_swdtech_speed(fout, random: Random, speed: str = "Vanilla"):
    swdtech_speed = 0x03
    if speed.lower() == "fastest":
        swdtech_speed = 0x00
    elif speed.lower() == "faster":
        swdtech_speed = 0x01
    elif speed.lower() == "fast":
        swdtech_speed = 0x02
    elif speed.lower() == "random":
        swdtech_speed = random.randint(0, 3)
    css_sub = Substitution()
    css_sub.set_location(0x017D87)
    css_sub.bytestring = bytes([swdtech_speed])
    css_sub.write(fout)
Пример #5
0
def change_cursed_shield_battles(fout, random: Random, amount: int = None):
    ccsb_sub = Substitution()
    ccsb_sub.set_location(0x025FF7)  # C25FF7
    if not amount or amount == "random":
        base_cursed_shield_battle_amount = 48
        standard_deviation_number = 16 * RANDOM_MULTIPLIER
        if standard_deviation_number == 0:
            # Tierless - could be anything!
            amount = random.randint(1, 256)
        else:
            amount = max(1, int(random.gauss(base_cursed_shield_battle_amount, standard_deviation_number)))
    else:
        amount = int(amount)
    ccsb_sub.bytestring = bytes([amount])
    ccsb_sub.write(fout)
Пример #6
0
def allergic_dog(fout):
    # auto-float doesn't remove Interceptor
    allergic_dog_sub = Substitution()
    allergic_dog_sub.set_location(0x391c4)
    allergic_dog_sub.bytestring = bytes([
        0x20,
        0xF2,
        0x93,  # JSR $93F2  		; Define Y
        0xAD,
        0x32,
        0x30,  # LDA $3032  		; Gear status immunity
        0x20,
        0xEC,
        0x91,  # JSR $91EC  		; Cure affected ailments
        0xAD,
        0x34,
        0x30,  # LDA $3034  		; Gear-granted status
        0x19,
        0x15,
        0x00,  # ORA $0015,Y		; Add actor status
        0x4A,  # LSR A      		; Auto Float or Rage?
        0x90,
        0x15,  # BCC $15    		; Exit if not
        0xB9,
        0x15,
        0x00,  # LDA $0015,Y		; Actor status
        0x29,
        0x40,  # AND #$40   		; Get Interceptor
        0x85,
        0xE0,  # STA $E0    		; Memorize it
        0xAD,
        0x34,
        0x30,  # LDA $3034  		; Gear-granted status
        0x29,
        0x01,  # AND #$01   		; Auto Float?
        0xF0,
        0x02,  # BEQ $02    		; Skip next line if not
        0xA9,
        0x81,  # LDA #$81   		; Enable Rage, Float
        0x05,
        0xE0,  # ORA $E0    		; Add Interceptor back
        0x99,
        0x15,
        0x00,  # STA $0015,Y		; Set actor status
        0x60  # RTS
    ])
    allergic_dog_sub.write(fout)
def randomize_poem(fout):
    poems = []

    with open_mei_fallback(POEMS_TABLE, encoding='utf8') as poems_file:
        current_poem = []
        page_break = False
        wait = 0
        for line in poems_file:
            line = line.split('#')[0].strip()

            if not line:
                if current_poem:
                    page_break = True
                continue

            if line.startswith("---") and current_poem:
                current_poem.append("<wait 390 frames><wait 1 frame>")
                wait += 1
                poems.append(("".join(current_poem), wait))
                current_poem = []
                page_break = False
                wait = 0
                continue

            if page_break:
                current_poem.append(POEM_PAGE_BREAK)
                wait += 1
                page_break = False
            elif current_poem:
                current_poem.append("<line>")
            current_poem.append(line)

    if not poems:
        return

    text, wait = random.choice(poems)
    set_dialogue(0x9FC, text)
    wait = min(wait * 26 + 2, 255)

    # Adjust wait to be long enough for the poem
    wait_sub = Substitution()
    wait_sub.set_location(0xC401D)
    wait_sub.bytestring = bytes([0xB5, wait])
    wait_sub.write(fout)
Пример #8
0
 def make_challenge_event(loc, ptr):
     bg = ch_bgs.pop()
     formids = random.sample(challenges[loc.restrank], 2)
     formations = [get_formation(formid) for formid in formids]
     for formid in formids:
         challenges[loc.restrank].remove(formid)
     setcands = [f for f in get_fsets() if f.setid >= 0x100 and f.unused]
     fset = setcands.pop()
     fset.formids = formids
     fset.write_data(fout)
     timer = max(
         [e.stats['hp'] for f in formations for e in f.present_enemies])
     reverse = False
     if timer >= 32768:
         reverse = True
         timer = 65535 - timer
     timer = max(timer, 3600)
     half = None
     while half is None or random.randint(1, 5) == 5:
         half = timer // 2
         timer = half + random.randint(0, half) + random.randint(0, half)
     if reverse:
         timer = 65535 - timer
     timer = int(round(timer / 1800.0))
     timer = max(2, min(timer, 36))
     timer = timer * 1800
     timer = [timer & 0xFF, timer >> 8]
     addr1 = ptr + 10 - 0xa0000
     addr2 = ptr + (len(enemy_template) - 1) - 0xa0000
     addr1 = [addr1 & 0xFF, (addr1 >> 8) & 0xFF, addr1 >> 16]
     addr2 = [addr2 & 0xFF, (addr2 >> 8) & 0xFF, addr2 >> 16]
     bytestring = list(enemy_template)
     bytestring[4:7] = addr1
     bytestring[7:10] = addr2
     bytestring[11:13] = timer
     bytestring[17] = fset.setid & 0xFF
     bytestring[18] = bg
     assert None not in bytestring
     sub = Substitution()
     sub.set_location(ptr)
     sub.bytestring = bytes(bytestring)
     sub.write(fout)
     return ptr + len(enemy_template)
Пример #9
0
def banon_life3(fout):
    banon_sub = Substitution()
    banon_sub.set_location(0x206bf)
    banon_sub.bytestring = [
        0x89,
        0xC2,  # BIT #$C2       (Check for Dead, Zombie, or Petrify status)
        #06C1
        0xF0,
        0x09,  # BEQ $06CC      (branch if none set)
        #06C3
        0xBD,
        0x19,
        0x30,  # LDA $3019,X
        #06C6
        0x0C,
        0x3A,
        0x3A,  # TSB $3A3A      (add to bitfield of dead-ish or escaped monsters)
        #06C9
        0x20,
        0xC8,
        0x07,  # JSR $07C8      (Clear Zinger, Love Token, and Charm bonds, and
        #                 clear applicable Quick variables)
        #06CC
        0xBD,
        0xE4,
        0x3E,  # LDA $3EE4,X
        #06CF
        0x10,
        0x2F,  # BPL $0700      (Branch if alive)
        #06D1
        0x20,
        0x10,
        0x07,  # JSR $0710   (If Wound status set on mid-Jump entity, replace
        #              it with Air Anchor effect so they can land first)
        #06D4
        0xBD,
        0xE4,
        0x3E,  # LDA $3EE4,X
        #06D7
        0x89,
        0x02,  # BIT #$02
        #06D9
        0xF0,
        0x03,  # BEQ $06DE      (branch if no Zombie Status)
        #06DB
        0x20,
        0x28,
        0x07,  # JSR $0728      (clear Wound status, and some other bit)
        #06DE
        0xBD,
        0xE4,
        0x3E,  # LDA $3EE4,X
        #06E1
        0x10,
        0x1D,  # BPL $0700      (Branch if alive)
        #06E3
        0xBD,
        0xF9,
        0x3E,  # LDA $3EF9,X
        #06E6
        0x89,
        0x04,  # BIT #$04
        #06E8
        0xF0,
        0x05,  # BEQ $06EF      (branch if no Life 3 status)
        #06EA
        0x20,
        0x99,
        0x07,  # JSR $0799      (prepare Life 3 revival)
        #06ED
        0x80,
        0x11,  # BRA $0700
        #06EF
        0xE0,
        0x08,  # CPX #$08
        #06F1
        0xB0,
        0x0C,  # BCS $06E4      (branch if monster)
        #06F3
        0xBD,
        0xD8,
        0x3E,  # LDA $3ED8,X    (Which character)
        #06F6
        0xC9,
        0x0E,  # CMP #$0E
        #06F8
        0xD0,
        0x06,  # BNE $0700      (Branch if not Banon)
        #06FA
        0xA9,
        0x06,  # LDA #$06
        #06FC
        0x8D,
        0x6E,
        0x3A,  # STA $3A6E      (Banon fell... "End of combat" method #6)
        #06FF
        0xEA,
    ]
    banon_sub.write(fout)
Пример #10
0
def show_coliseum_rewards(fout):
    rewards_sub = Substitution()
    rewards_sub.set_location(0x37FD0)
    rewards_sub.bytestring = bytes([0x4C, 0x00, 0xF9])
    rewards_sub.write(fout)

    rewards_sub.set_location(0x3F900)
    rewards_sub.bytestring = bytes([
        0xA5, 0x26, 0xC9, 0x71, 0xF0, 0x0D, 0xC9, 0x72, 0xF0, 0x09, 0x20, 0xB9,
        0x80, 0x20, 0xD9, 0x7F, 0x4C, 0xE6, 0x7F, 0x20, 0x3B, 0xF9, 0x20, 0x49,
        0xF9, 0x20, 0xAB, 0xF9, 0x20, 0x50, 0xF9, 0x20, 0x66, 0xF9, 0x20, 0x49,
        0xF9, 0x20, 0x97, 0xF9, 0x20, 0x50, 0xF9, 0x20, 0x61, 0xF9, 0x20, 0x49,
        0xF9, 0x20, 0x78, 0xF9, 0x20, 0x50, 0xF9, 0x20, 0x66, 0xF9, 0x60, 0x7B,
        0xA5, 0xE5, 0xA8, 0xB9, 0x69, 0x18, 0x8D, 0x05, 0x02, 0x20, 0x2C, 0xB2,
        0x60, 0xA2, 0x8B, 0x9E, 0x8E, 0x81, 0x21, 0x60, 0x20, 0xD9, 0x7F, 0x60,
        0xA2, 0x0D, 0x00, 0x8D, 0x80, 0x21, 0xCA, 0xD0, 0xFA, 0x9C, 0x80, 0x21,
        0x60, 0xA2, 0x02, 0x00, 0x80, 0x03, 0xA2, 0x1A, 0x00, 0xC2, 0x20, 0x8A,
        0x18, 0x6F, 0x89, 0x9E, 0x7E, 0x8F, 0x89, 0x9E, 0x7E, 0xE2, 0x20, 0x60,
        0xAD, 0x09, 0x02, 0xD0, 0x0E, 0xAD, 0x05, 0x02, 0xC9, 0xFF, 0xF0, 0x0D,
        0xAD, 0x07, 0x02, 0x20, 0x68, 0xC0, 0x60, 0xA9, 0xBF, 0x20, 0x54, 0xF9,
        0x60, 0xA9, 0xFF, 0x20, 0x54, 0xF9, 0x60, 0xAD, 0x05, 0x02, 0xC9, 0xFF,
        0xF0, 0x04, 0xA9, 0xC1, 0x80, 0x02, 0xA9, 0xFF, 0x8D, 0x80, 0x21, 0x9C,
        0x80, 0x21, 0x60, 0xAD, 0x05, 0x02, 0xC9, 0xFF, 0xF0, 0x07, 0xAD, 0x05,
        0x02, 0x20, 0x68, 0xC0, 0x60, 0xA9, 0xFF, 0x20, 0x54, 0xF9, 0x60, 0xFF
    ])
    rewards_sub.write(fout)
Пример #11
0
def no_kutan_skip(fout):
    no_kutan_skip_sub = Substitution()
    no_kutan_skip_sub.set_location(0xAEBC2)
    no_kutan_skip_sub.bytestring = bytes([0x27, 0x01])
    no_kutan_skip_sub.write(fout)
Пример #12
0
def death_abuse(fout):
    death_abuse_sub = Substitution()
    death_abuse_sub.bytestring = bytes([0x60])
    death_abuse_sub.set_location(0xC515)
    death_abuse_sub.write(fout)
Пример #13
0
    def write_data(self, fout, cutscene_skip=False):
        content_command_dict = {0x80: 0x6E, 0x40: 0x6D, 0x20: 0x6F}

        event_item_sub = Substitution()
        location = self.cutscene_skip_pointer if cutscene_skip and self.cutscene_skip_pointer else self.pointer
        event_item_sub.set_location(location)
        event_item_sub.bytestring = bytearray([])

        if self.content_type in content_command_dict:
            if not self.text or (cutscene_skip and self.cutscene_skip_pointer):
                event_item_sub.bytestring.append(0x80)
            else:
                event_item_sub.bytestring.append(
                    content_command_dict[self.content_type])
            event_item_sub.bytestring.append(self.contents)
        else:
            event_item_sub.bytestring.extend([0xFD, 0xFD])  # Do nothing
        if not cutscene_skip or not self.cutscene_skip_pointer:
            event_item_sub.bytestring.extend(self.postfix_bytes)
        event_item_sub.write(fout)

        duplicate_dict = duplicate_event_item_skip_dict if cutscene_skip else duplicate_event_item_dict
        if self.pointer in duplicate_dict:
            prev_pointer = self.pointer
            self.pointer = duplicate_dict[self.pointer]
            self.write_data(fout)
            self.pointer = prev_pointer
        elif self.pointer == 0xCD59E:
            event_item_sub.bytestring = bytes([
                0x94,  # Pause 60 frames
                0x66 if self.content_type == 0x40 else 0x67,
                0xE5,
                0xC6,
                self.
                contents,  # Show text 0x06E5 at bottom, no text box, with item self.contents
                0xFE
            ])  # return
            event_item_sub.set_location(0x10CF4A)
            event_item_sub.write(fout)

            # Change Lone Wolf text to say item placeholder instead of gold hairpin
            text = (
                "<line>Grrrr…<line>"
                "You’ll never get this<line>" +
                ("“<item>”!" if self.content_type == 0x40 else "“<GP>00 GP”!"))
            set_dialogue(0x6e5, text)

            # Because it takes up more slightly space
            # move Lone Wolf talking into a subroutine
            event_item_sub.bytestring = bytes([0xB2, 0x4A, 0xCF, 0x06])
            event_item_sub.set_location(0xCD581)
            event_item_sub.write(fout)
Пример #14
0
def extend_item_breaks(fout):
    break_sub = Substitution()
    break_sub.set_location(0x22735)
    break_sub.bytestring = bytes([0x22, 0x13, 0x30, 0xF0])
    break_sub.write(fout)

    break_sub.set_location(0x22743)
    break_sub.bytestring = bytes([0x30, 0x05])
    break_sub.write(fout)

    break_sub.set_location(0x2274A)
    break_sub.bytestring = bytes([0xAD, 0x10, 0x34])
    break_sub.write(fout)

    break_sub.set_location(0x229ED)
    break_sub.bytestring = bytes([0x22, 0x00, 0x30, 0xF0, 0xEA, 0xEA])
    break_sub.write(fout)

    break_sub.set_location(0x23658)
    break_sub.bytestring = bytes([0xAD, 0x7E, 0x3A])
    break_sub.write(fout)

    break_sub.set_location(0x303000)
    break_sub.bytestring = bytes([
        0xBD, 0xA4, 0x3B, 0x29, 0x0C, 0x0A, 0x0A, 0x0A, 0x0A, 0x8D, 0x89, 0x3A,
        0xBD, 0x34, 0x3D, 0x8D, 0x7E, 0x3A, 0x6B, 0x08, 0xBF, 0x12, 0x50, 0xD8,
        0x8D, 0x10, 0x34, 0xBF, 0x13, 0x50, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A, 0x28,
        0x29, 0xC0, 0x6B
    ])
    break_sub.write(fout)
Пример #15
0
def unhardcode_tintinabar(fout):
    # Apply Lenophis's unhardcoded tintinabar patch (solo version)
    tintinabar_sub = Substitution()
    tintinabar_sub.set_location(0x4A57)
    tintinabar_sub.bytestring = bytes([
        0x89, 0x40, 0xF0, 0x5C, 0x29, 0x07, 0xCD, 0x6D, 0x1A, 0xD0, 0x55, 0x20,
        0xE8, 0xAE, 0xB9, 0x14, 0x16, 0x89, 0xC2, 0xD0, 0x4B, 0x20, 0x0D, 0xDF,
        0xF0, 0x19, 0xB9, 0x1C, 0x16, 0x4A, 0x4A, 0xC2, 0x21, 0x29, 0xFF, 0x00,
        0x79, 0x09, 0x16, 0xC5, 0x1E, 0x90, 0x02, 0xA5, 0x1E, 0x99, 0x09, 0x16,
        0x7B, 0xE2, 0x20, 0xB9, 0x14, 0x16, 0x29, 0x04, 0xF0, 0x26, 0x7B, 0xA9,
        0x0F, 0x8D, 0xF0, 0x11, 0xC2, 0x20, 0xEB, 0x8D, 0x96, 0x07, 0xC2, 0x20,
        0xA5, 0x1E, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x85, 0x1E, 0xB9, 0x09, 0x16,
        0x38, 0xE5, 0x1E, 0xF0, 0x02, 0xB0, 0x02, 0x7B, 0x1A, 0x99, 0x09, 0x16,
        0xC2, 0x21, 0x98, 0x69, 0x25, 0x00, 0xA8, 0x7B, 0xE2, 0x20, 0xE8, 0xE0,
        0x10, 0x00, 0xD0, 0x8D, 0xFA, 0x86, 0x24, 0xFA, 0x86, 0x22, 0xFA, 0x86,
        0x20, 0xFA, 0x86, 0x1E, 0x28, 0x6B
    ])
    tintinabar_sub.write(fout)

    tintinabar_sub.set_location(0x6CF8)
    tintinabar_sub.bytestring = bytes([
        0x8C, 0x48, 0x14, 0x64, 0x1B, 0xB9, 0x67, 0x08, 0x0A, 0x10, 0x11, 0x4A,
        0x29, 0x07, 0xCD, 0x6D, 0x1A, 0xD0, 0x09, 0xA5, 0x1B, 0x22, 0x77, 0x0E,
        0xC2, 0x20, 0xF6, 0xDE, 0xC2, 0x21, 0x98, 0x69, 0x29, 0x00, 0xA8, 0xE2,
        0x20, 0xE6, 0x1B, 0xC0, 0x90, 0x02, 0xD0, 0xD9, 0x7B, 0x60
    ])
    tintinabar_sub.write(fout)

    tintinabar_sub.set_location(0xDEF6)
    tintinabar_sub.bytestring = bytes([
        0xAD, 0xD8, 0x11, 0x10, 0x11, 0xA5, 0x1B, 0x5A, 0x1A, 0xA8, 0xC2, 0x20,
        0x38, 0x7B, 0x2A, 0x88, 0xD0, 0xFC, 0x0C, 0x48, 0x14, 0x7A, 0x60, 0x8C,
        0x04, 0x42, 0xA9, 0x25, 0x8D, 0x06, 0x42, 0x22, 0xD4, 0x4A, 0xC0, 0x7B,
        0xAD, 0x14, 0x42, 0xDA, 0x1A, 0xAA, 0xC2, 0x20, 0x38, 0x7B, 0x2A, 0xCA,
        0xD0, 0xFC, 0xFA, 0x2C, 0x48, 0x14, 0xE2, 0x20, 0x60
    ])
    tintinabar_sub.write(fout)

    tintinabar_sub.set_location(0x31DA9)
    tintinabar_sub.bytestring = bytes([
        0x10, 0x03, 0x4C, 0x62, 0x2E, 0xA5, 0x09, 0x89, 0x02, 0xF0, 0x03, 0x4C,
        0xC6, 0x2E, 0x10, 0x0F, 0x9C, 0x05, 0x02, 0x20, 0xA9, 0x0E, 0x20, 0xC9,
        0x1D, 0x7B, 0x3A, 0x85, 0x27, 0x64, 0x26, 0x60, 0x9C, 0xDF, 0x11, 0x9C,
        0x48, 0x14, 0x9C, 0x49, 0x14, 0xA2, 0x03, 0x00, 0xB5, 0x69, 0x30, 0x07,
        0x22, 0x77, 0x0E, 0xC2, 0x20, 0x6C, 0xF1, 0xCA, 0x10, 0xF2, 0x60, 0x00,
        0xD0, 0xF0, 0x60
    ])
    tintinabar_sub.write(fout)

    tintinabar_sub.set_location(0x3F16C)
    tintinabar_sub.bytestring = bytes([
        0xAD, 0xD8, 0x11, 0x10, 0x12, 0x7B, 0xB5, 0x69, 0x1A, 0xA8, 0x38, 0x7B,
        0xC2, 0x20, 0x2A, 0x88, 0xD0, 0xFC, 0x0C, 0x48, 0x14, 0xE2, 0x20, 0x60
    ])
    tintinabar_sub.write(fout)
def allocate_espers(ancient_cave, espers, characters, fout, replacements=None):
    char_ids = list(range(12)) + [13]  # everyone but Gogo

    characters = [c for c in characters if c.id in char_ids]

    chars_for_esper = []
    max_rank = max(espers, key=lambda e: e.rank).rank
    crusader_id = 15
    ragnarok_id = 16
    if replacements:
        crusader_id = replacements[crusader_id].id
        ragnarok_id = replacements[ragnarok_id].id

    for e in espers:
        num_users = 1
        if e.id not in [crusader_id, ragnarok_id
                        ] and random.randint(1, 25) >= 25 - max_rank + e.rank:
            num_users += 1
            while num_users < 15 and random.choice([True] + [False] *
                                                   (e.rank + 2)):
                num_users += 1
        users = random.sample(characters, num_users)
        chars_for_esper.append([c.id for c in users])

    if not ancient_cave:
        odin_id = 11
        raiden_id = 12
        if replacements:
            odin_id = replacements[odin_id].id
            raiden_id = replacements[raiden_id].id

        chars_for_esper[raiden_id] = chars_for_esper[
            odin_id]  # make Odin and Raiden equippable by the same person/people

    char_mask_for_esper = [
        reduce(lambda x, y: x | y,
               [1 << char_id for char_id in chars_for_esper[e.id]])
        for e in espers
    ]

    for e in espers:
        e.chars = ", ".join(
            [c.newname for c in characters if c.id in chars_for_esper[e.id]])

    # do substitution
    esper_allocator_sub = Substitution()
    esper_allocator_sub.set_location(0x31B61)
    esper_allocator_sub.bytestring = [0x20, 0x00, 0xF8]
    esper_allocator_sub.write(fout)

    esper_allocator_sub.set_location(0x35524)
    esper_allocator_sub.bytestring = [0x20, 0x07, 0xF8]
    esper_allocator_sub.write(fout)

    esper_allocator_sub.set_location(0x358E1)
    esper_allocator_sub.write(fout)

    esper_allocator_sub.set_location(0x359B1)
    esper_allocator_sub.write(fout)

    esper_allocator_sub.set_location(0x35593)
    esper_allocator_sub.bytestring = [0xA9, 0x2C]
    esper_allocator_sub.write(fout)

    esper_allocator_sub.set_location(0x355B2)
    esper_allocator_sub.bytestring = [0x20, 0x2E, 0xF8]
    esper_allocator_sub.write(fout)

    esper_allocator_sub.set_location(0x358E8)
    esper_allocator_sub.bytestring = [0xC9, 0x20, 0xF0, 0x16]
    esper_allocator_sub.write(fout)

    esper_allocator_sub.set_location(0x3F800)

    esper_allocator_sub.bytestring = [
        0xAA, 0xB5, 0x69, 0x8D, 0xF8, 0x1C, 0x60, 0xDA, 0x08, 0x85, 0xE0, 0x0A,
        0xAA, 0xE2, 0x10, 0xDA, 0xAD, 0xF8, 0x1C, 0x0A, 0xAA, 0xC2, 0x20, 0xBF,
        0x67, 0x9C, 0xC3, 0xFA, 0x3F, 0x58, 0xF8, 0xC3, 0xF0, 0x05, 0x28, 0xFA,
        0x4C, 0x76, 0x55, 0x28, 0xFA, 0xA9, 0x28, 0x4C, 0x95, 0x55, 0xBD, 0x02,
        0x16, 0xC9, 0x80, 0xB0, 0x0F, 0xFA, 0xA6, 0x00, 0xBF, 0x4B, 0xF8, 0xC3,
        0xF0, 0x07, 0x8D, 0x80, 0x21, 0xE8, 0x80, 0xF4, 0x60, 0x9C, 0x80, 0x21,
        0x4C, 0xD9, 0x7F, 0x82, 0x9A, 0xA7, 0xC3, 0xAD, 0xFF, 0x9E, 0xAA, 0xAE,
        0xA2, 0xA9, 0xBE, 0x00
    ] + [
        i for sublist in map(int2bytes, char_mask_for_esper) for i in sublist
    ]
    esper_allocator_sub.write(fout)
Пример #17
0
def manage_coral(fout):

    f = open_mei_fallback(CORAL_TABLE)
    coralnames = sorted(
        set(sanitize_coral([line.strip() for line in f.readlines()])))
    f.close()

    sprite_log = ""

    newcoralname = random.choice(coralnames)
    sprite_log += str("Coral: ").ljust(17) + string.capwords(
        str(newcoralname)) + "\n"
    coraldescription1 = "Piece of " + newcoralname.lower() + ","
    coraldescription2 = "found near Ebot's Rock."

    load_patch_file("coral")
    set_dialogue_var("coralsub", newcoralname)

    newcoralnamebytes = name_to_bytes(newcoralname, 12)
    coraldescription1 = name_to_bytes(coraldescription1, 24)
    coraldescription2 = name_to_bytes(coraldescription2, 26)

    coraldescription = coraldescription1 + bytes([0x01]) + coraldescription2

    coral_sub = Substitution()
    coral_sub.set_location(0xEFC08)  ##change the name when opening a chest
    coral_sub.bytestring = newcoralnamebytes
    coral_sub.write(fout)

    coral_sub.set_location(0xEFD7F)  ##Change the name in the description
    coral_sub.bytestring = coraldescription
    coral_sub.write(fout)

    return sprite_log
Пример #18
0
def fewer_flashes(fout):
    anti_seizure_sub = Substitution()

    # ------------- Attack Animations -------------
    #
    # Removing Final Kefka Death Flashing
    #
    anti_seizure_sub.set_location(0x10023B)  # D0023B
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x100241)  # D00241
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x100249)  # D00249
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x10024F)  # D0024F
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    #
    # Removing Boss Death Flashing
    #
    anti_seizure_sub.set_location(0x100477)  # D00477
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x10047D)  # D0047D
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x100485)  # D00485
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x100498)  # D00498
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    #
    # Removing Magicite Transformation Flash
    #
    anti_seizure_sub.set_location(0x100F31)  # D00F31
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x100F40)  # D00F40
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    #
    # Removing Ice 3 Flash
    #
    anti_seizure_sub.set_location(0x101979)  # D01979
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x10197C)  # D0197C
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x10197F)  # D0197F
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x101982)  # D01982
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x101985)  # D01985
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x101988)  # D01988
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x10198B)  # D0198B
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x10198E)  # D0198E
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x101991)  # D01991
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    #
    # Removing Fire 3 Flash
    #
    anti_seizure_sub.set_location(0x1019FB)  # D019FB
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x101A1D)  # D01A1D
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    #
    # Removing Phantasm Flash
    #
    anti_seizure_sub.set_location(0x101E08)  # D01E08
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x101E0E)  # D01E0E
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x101E20)  # D01E20
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x101E28)  # D01E28
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    #
    # Removing Tiger Break Flash
    #
    anti_seizure_sub.set_location(0x10240E)  # D0240E
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x102412)  # D02412
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x102416)  # D02416
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    #
    # Removing Diffuser Flash
    #
    anti_seizure_sub.set_location(0x103AEB)  # D03AEB
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x103AEE)  # D03AEE
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x103AF1)  # D03AF1
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x103AF4)  # D03AF4
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x103AF7)  # D03AF7
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x103AFA)  # D03AFA
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x103AFD)  # D03AFD
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x103B00)  # D03B00
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x103B03)  # D03B00
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    #
    # Removing Cat Rain Flash
    #
    anti_seizure_sub.set_location(0x102678)  # D02678
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x10267C)  # D0267C
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    #
    # Removing Unknown Script 1's Flash
    #
    anti_seizure_sub.set_location(0x1026EF)  # D026EF
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x1026FB)  # D026FB
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    #
    # Removing Mirager Flash
    #
    anti_seizure_sub.set_location(0x102792)  # D02792
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x102796)  # D02796
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    #
    # Removing Sabre Soul Flash
    #
    anti_seizure_sub.set_location(0x1027D4)  # D027D4
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x1027DB)  # D027DB
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    #
    # Removing Back Blade Flash
    #
    anti_seizure_sub.set_location(0x1028D4)  # D028D4
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x1028E0)  # D028E0
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    #
    # Removing Royal Shock Flash
    #
    anti_seizure_sub.set_location(0x102968)  # D02968
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x10296C)  # D0296C
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x102974)  # D02974
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    #
    # Removing Unknown Script 2's Flash
    #
    anti_seizure_sub.set_location(0x102AAE)  # D02AAE
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x102AB2)  # D02AB2
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    #
    # Removing Absolute Zero Flash
    #
    anti_seizure_sub.set_location(0x102BFF)  # D02BFF
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x102C03)  # D02C03
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    #
    # Removing Unknown Script 3's Flash
    #
    anti_seizure_sub.set_location(0x1030CB)  # D030CB
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x1030CF)  # D030CF
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    #
    # Removing Reverse Polarity Flash
    #
    anti_seizure_sub.set_location(0x10328C)  # D0328C
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x103293)  # D03293
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    #
    # Removing Rippler Flash
    #
    anti_seizure_sub.set_location(0x1033C7)  # D033C7
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x1033CB)  # D033CB
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    #
    # Removing Step Mine Flash
    #
    anti_seizure_sub.set_location(0x1034DA)  # D034DA
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x1034E1)  # D034E1
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    #
    # Removing Unknown Script 4's Flash
    #
    anti_seizure_sub.set_location(0x1035E7)  # D035E7
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x1035F7)  # D035F7
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    #
    # Removing Schiller Flash
    #
    anti_seizure_sub.set_location(0x10380B)
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    # This commented out code is for vanilla Schiller, which BC is no longer using
    # anti_seizure_sub.set_location(0x10381A)  # D0381A
    # anti_seizure_sub.bytestring = bytes([0xE0])
    # anti_seizure_sub.write(fout)

    # anti_seizure_sub.set_location(0x10381E)  # D0381E
    # anti_seizure_sub.bytestring = bytes([0xF0])
    # anti_seizure_sub.write(fout)

    #
    # Removing Wall Change Flash
    #
    anti_seizure_sub.set_location(0x10399F)  # D0399F
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x1039A4)  # D039A4
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x1039AA)  # D039AA
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x1039B0)  # D039B0
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x1039B6)  # D039B6
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x1039BC)  # D039BC
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x1039C2)  # D039C2
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x1039C8)  # D039C8
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x1039CE)  # D039CE
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x1039D5)  # D039D5
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    #
    # Removing Ultima Flash
    #
    anti_seizure_sub.set_location(0x1056EE)  # D056EE
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x1056F6)  # D056F6
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    #
    # Removing Bolt 3/Giga Volt Flash
    #
    anti_seizure_sub.set_location(0x10588F)  # D0588F
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x105894)  # D05894
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x105897)  # D05897
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x10589A)  # D0589A
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x10589D)  # D0589D
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x1058A2)  # D058A2
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x1058A7)  # D058A7
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x1058AC)  # D058AC
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x1058B1)  # D058B1
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    #
    # Removing X-Zone Flash
    #
    anti_seizure_sub.set_location(0x105A5E)  # D05A5E
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x105A6B)  # D05A6B
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x105A7A)  # D05A7A
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    #
    # Removing Dispel Flash
    #
    anti_seizure_sub.set_location(0x105DC3)  # D05DC3
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x105DCA)  # D05DCA
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x105DD3)  # D05DD3
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x105DDC)  # D05DDC
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x105DE5)  # D05DE5
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x105DEE)  # D05DEE
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    #
    # Removing Pep Up/Break Flash
    #
    anti_seizure_sub.set_location(0x1060EB)  # D060EB
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x1060EF)  # D060EF
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    #
    # Removing Shock Flash
    #
    anti_seizure_sub.set_location(0x1068BF)  # D068BF
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x1068D1)  # D068D1
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    #
    # Removing Bum Rush Flashes
    #
    # Flash 1
    anti_seizure_sub.set_location(0x106C7F)  # D06C7F
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x106C88)  # D06C88
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    # Flash 2
    anti_seizure_sub.set_location(0x106C96)  # D06C96
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x106C9F)  # D06C9F
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    # Other Bum Rush Background Sets - possibly unnecessary
    anti_seizure_sub.set_location(0x106C3F)  # D06C3F
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x106C48)  # D06C48
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x106C54)  # D06C54
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x106C88)  # D06C87
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    #
    # Removing Quadra Slam/Slice Flash
    #
    # White Flash
    anti_seizure_sub.set_location(0x1073DD)  # D073DD
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x1073EF)  # D073EF
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x1073F4)  # D073F4
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    # Green Flash
    anti_seizure_sub.set_location(0x107403)  # D07403
    anti_seizure_sub.bytestring = bytes([0x40])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x107425)  # D07425
    anti_seizure_sub.bytestring = bytes([0x50])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x10742A)  # D0742A
    anti_seizure_sub.bytestring = bytes([0x50])
    anti_seizure_sub.write(fout)

    # Blue Flash
    anti_seizure_sub.set_location(0x107437)  # D07437
    anti_seizure_sub.bytestring = bytes([0x20])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x107459)  # D07459
    anti_seizure_sub.bytestring = bytes([0x30])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x10745E)  # D0745E
    anti_seizure_sub.bytestring = bytes([0x30])
    anti_seizure_sub.write(fout)

    # Red Flash
    anti_seizure_sub.set_location(0x107491)  # D07491
    anti_seizure_sub.bytestring = bytes([0x80])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x1074B3)  # D074B3
    anti_seizure_sub.bytestring = bytes([0x90])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x1074B8)  # D074B8
    anti_seizure_sub.bytestring = bytes([0x90])
    anti_seizure_sub.write(fout)

    #
    # Removing Slash Flash
    #
    anti_seizure_sub.set_location(0x1074F5)  # D074F5
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x1074FE)  # D074FE
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x107508)  # D07508
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    #
    # Removing Flash Flash
    #
    anti_seizure_sub.set_location(0x107851)  # D07851
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x10785D)  # D0785D
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    # ------------- Battle Event Scripts -------------
    #
    # Battle Event Script $15
    #
    anti_seizure_sub.set_location(0x10B887)  # D0B887
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x10B88D)  # D0B88D
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x10B894)  # D0B894
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x10B89A)  # D0B89A
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x10B8A1)  # D0B8A1
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x10B8A7)  # D0B8A7
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x10B8AE)  # D0B8AE
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x10B8B4)  # D0B8B4
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x10BCF5)  # D0BCF5
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x10BCF9)  # D0BCF9
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    #
    # Battle Event Script $19
    #
    anti_seizure_sub.set_location(0x10C7A4)  # D0C7A4
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x10C7AA)  # D0C7AA
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x10C7B1)  # D0C7B1
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x10C7B7)  # D0C7B7
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x10C7BE)  # D0C7BE
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x10C7C4)  # D0C7C4
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x10C7CB)  # D0C7CB
    anti_seizure_sub.bytestring = bytes([0xE0])
    anti_seizure_sub.write(fout)

    anti_seizure_sub.set_location(0x10C7D1)  # D0C7D1
    anti_seizure_sub.bytestring = bytes([0xF0])
    anti_seizure_sub.write(fout)
Пример #19
0
def patch_doom_gaze(fout, addr, offset=0xA0000):
    """
    Add an option to the Falcon's wheel to search out Doom Gaze
    """
    rel_addr = addr - offset

    sub = Substitution()

    dst = rel_addr.to_bytes(3, "little")
    sub.set_location(0xA009D)
    sub.bytestring = b"\xb2" + dst
    sub.write(fout)

    sub.set_location(0xAF56E)
    dst = (rel_addr + 7).to_bytes(3, "little")
    sub.bytestring = b"\xb2" + dst + b"\xfe" + b"\xfd" * 5
    sub.write(fout)

    # displaced code + DG dead bit
    sub.set_location(addr)
    sub.bytestring = b"\x3d\x12\x41\x12\xd0\xe2\xfe"
    sub.write(fout)

    # dialog box manager
    b1 = (rel_addr + 0x1D).to_bytes(3, "little")
    b2 = (rel_addr + 0x27).to_bytes(3, "little")
    sub.set_location(addr + 0x7)
    sub.bytestring = b"\xc1\xe2\x80\xa4\x00" + b1 \
                   + b"\x4b\xa5\x86\xb6\x8d\xf5\x00" + b2 \
                   + b"\xb3\x5e\x00\xfe"
    sub.write(fout)

    # lift-off choice handler
    sub.set_location(addr + 0x1D)
    sub.bytestring = b"\x4b\x2a\x85\xb6\x8d\xf5\x00\xb3\x5e\x00"
    sub.write(fout)

    # doom gaze encounter event
    sub.set_location(addr + 0x27)
    sub.bytestring = b"\x6a\x01\x04\x9e\x33\x01\x29\x58\x0c\x30\x4c\x20\x2c" + \
                     b"\x10\x24\x10\x34\x10\x54\x10\x49\x24\x40\xa0\x24\x30" + \
                     b"\x34\x40\x54\x30\x40\x80\x49\x60\x40\x80\x24\x30\xd9" + \
                     b"\xd2\x11\x36\x11\x08\xc0\x4d\x5d\x29\xb2\xa9\x5e\x00" + \
                     b"\xb7\x48\xe3\x00\x00\x96\xc0\x27\x01\x9d\x00\x00"
    sub.write(fout)
Пример #20
0
def manage_ancient(options_, fout, sourcefile, form_music_overrides={}):
    change_battle_commands = [41, 42, 43]
    if not options_.shuffle_commands:
        alrs = AutoLearnRageSub(require_gau=True)
        alrs.set_location(0x23b73)
        alrs.write(fout)

        enable_morph_sub = Substitution()
        enable_morph_sub.bytestring = bytes([0xEA] * 2)
        enable_morph_sub.set_location(0x25410)
        enable_morph_sub.write(fout)

        enable_mpoint_sub = Substitution()
        enable_mpoint_sub.bytestring = bytes([0xEA] * 2)
        enable_mpoint_sub.set_location(0x25E38)
        enable_mpoint_sub.write(fout)

        change_battle_commands += list(range(18, 28))

    moogle_commands = [
        0x03, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x10,
        0x12, 0x13, 0x16, 0x18, 0x1a, 0x1b, 0x1d
    ]
    for i in change_battle_commands:
        commands = random.sample(moogle_commands, 2)
        c = get_character(i)
        c.battle_commands = [0x00, commands[0], commands[1], 0x01]
        c.write_battle_commands(fout)

    for i in [32, 33]:
        c = get_character(i)
        c.battle_commands = [0x00, 0x1D, 0xFF, 0x01]
        c.write_battle_commands(fout)

    characters = get_characters()
    gau = [c for c in characters if c.id == 11][0]
    if not options_.replace_commands and gau.battle_commands[1] in [
            0x11, None
    ]:
        gau.battle_commands[1] = 0xFF
        gau.write_battle_commands(fout)

    to_dummy = [get_item(0xF6), get_item(0xF7)]
    dummy_names = ["Pebble", "Tissue"]
    for dummy_name, item in zip(dummy_names, to_dummy):
        name = bytes([0xFF]) + name_to_bytes(dummy_name, 12)
        item.dataname = name
        item.price = 4
        item.itemtype = 6
        item.write_stats(fout)
    blank_sub = Substitution()
    blank_sub.set_location(0x2D76C1)
    blank_sub.bytestring = bytearray([0xFF] * (0x2D76F5 - blank_sub.location))
    blank_sub.bytestring[blank_sub.size // 2] = 0
    blank_sub.write(fout)

    goddess_save_sub = Substitution()
    goddess_save_sub.bytestring = bytes([0xFD, 0xFD])
    goddess_save_sub.set_location(0xC170A)
    goddess_save_sub.write(fout)
    goddess_save_sub.set_location(0xC1743)
    goddess_save_sub.write(fout)
    goddess_save_sub.set_location(0xC1866)
    goddess_save_sub.write(fout)

    # decrease exp needed for level up
    if options_.is_code_active('racecave'):
        maxlevel = 49
        divisor = 12.0
    elif options_.is_code_active('speedcave'):
        maxlevel = 49
        divisor = 8.0
    else:
        maxlevel = 49
        divisor = 2.0

    for level in range(maxlevel):
        ratio = (float(level) / maxlevel)**2
        ratio = min(ratio, 1.0)
        xptr = 0x2d8220 + (level * 2)
        fout.seek(xptr)
        exp = read_multi(fout, length=2)
        newexp = (exp / divisor)
        remaining = exp - newexp
        newexp = int(round(newexp + (ratio * remaining)))
        newexp = max(newexp, 1)
        fout.seek(xptr)
        write_multi(fout, newexp, length=2)

    startsub = Substitution()
    startsub.bytestring = bytearray([
        0xD7,
        0xF3,  # remove Daryl
        0xD5,
        0xF0,  # remove Terra from party
        0xD5,
        0xE0,  # remove Terra from party
        0xDC,
        0x7E,  # fix ending? $1F4F bit 6
        0xB8,
        0x43,  # show magic points after battle
        0x3F,
        0x0E,
        0x00,
        0x3F,
        0x0F,
        0x00,
    ])
    if options_.is_code_active('racecave'):
        num_starting = 9 + random.randint(0, 2) + random.randint(0, 1)
    elif options_.is_code_active('speedcave'):
        num_starting = 4 + random.randint(0, 3) + random.randint(0, 2)
    else:
        num_starting = 4 + random.randint(0, 1) + random.randint(0, 1)
    starting = random.sample(list(range(14)), num_starting)
    for c in starting:
        startsub.bytestring += bytearray([0xD4, 0xF0 | c])
        startsub.bytestring += bytearray([0xD4, 0xE0 | c])

    for c in characters:
        i = c.id
        cptr = 0x2d7ca0 + 0x15 + (i * 22)
        fout.flush()
        fout.seek(cptr)
        level = ord(fout.read(1))
        level &= 0xF3
        if i >= 14 or options_.is_code_active(
                "speedcave") and i not in starting:
            level |= 0b1000
        fout.seek(cptr)
        fout.write(bytes([level]))
    fout.seek(0xa5e74)
    fout.write(b'\x00')  # remove Terra's magitek

    tempcands = [
        14, 15,
        random.choice(list(range(18, 28))),
        random.choice([32, 33])
    ]
    if options_.is_code_active('speedcave'):
        tempcands.append(random.choice([16, 17]))
        tempcands.append(random.choice([41, 42, 43]))
    charcands = list(range(14)) + random.sample(tempcands, 2)
    chargraphics = {
        14: 0x11,
        15: 0x10,
        16: 0x14,
        17: 0x14,
        32: 0xE,
        33: 0xE,
        41: 0x15,
        42: 0x15,
        43: 0x15
    }
    for c in range(14):
        chargraphics[c] = c
    for c in range(18, 28):
        chargraphics[c] = 0xA
    for n, i in enumerate(charcands):
        c = [x for x in characters if x.id == i][0]
        if i in chargraphics:
            g = chargraphics[i]
        else:
            g = i
        startsub.bytestring.extend(
            [0x7F, n, i, 0x37, n, g, 0x43, n, c.palette, 0x40, n, i])
        c.slotid = n

    runaway = random.choice([
        c for c in characters if hasattr(c, "slotid") and c.id == c.slotid
    ]).slotid
    if runaway in starting:
        byte, bit = runaway // 8, runaway % 8
        mem_addr = ((0x1b + byte) << 3) | bit
        startsub.bytestring += bytearray([0xD7, mem_addr])
    shadow_leaving_sub = Substitution()
    shadow_leaving_sub.set_location(0x248A6)
    shadow_leaving_sub.bytestring = bytearray([
        0x1C,
        0xDE + (runaway // 8),
        0x1E,  # TRB $1ede
        0x20,
        0xE3,
        0x47,
        0xAD,
        0xFB + (runaway // 8),
        0x1E,  # LDA $1efb
        0x09,
        1 << (runaway % 8),  # ORA #$08
        0x8D,
        0xFB + (runaway // 8),
        0x1E,  # STA $1efb
        0xAD,
        0xDE + (runaway // 8),
        0x1E,  # LDA $1ede
        0x29,
        0xFF ^ (1 << (runaway % 8)),  # AND #$F7
        0x8D,
        0xDE + (runaway // 8),
        0x1E,  # STA $1ede
    ])
    while len(shadow_leaving_sub.bytestring) < 23:
        shadow_leaving_sub.bytestring.append(0xEA)
    shadow_leaving_sub.bytestring += bytearray([0xA9, 0xFE, 0x20, 0x92, 0x07])
    shadow_leaving_sub.write(fout)
    shadow_leaving_sub.set_location(0x24861)
    shadow_leaving_sub.bytestring = bytearray([
        0xAE,
        runaway,
        0x30,
        0x30,
        0x26,
        0x20,
        0x5A,
        0x4B,
        0xC9,
        random.choice([0x20, 0x10, 0x8, 0x4, 0x2, 0x1]),
        0xB0,
        0x1F,
        0xAD,
        0x1F,
        0x20,
        0xD0,
        0x1A,
        0xAD,
        0x76,
        0x3A,
        0xC9,
        0x02,
        0x90,
        0x13,
        0xBD,
        0xE4,
        0x3E,
        0x89,
        0xC2,
        0xD0,
        0x0C,
        0xA9,
        1 << (runaway % 8),
        0x2C,
        0xBD + (runaway // 8),
        0x3E,
        0xD0,
        0x05,
        0x2C,
        0xDE + (runaway // 8),
        0x1E,
    ])
    shadow_leaving_sub.write(fout)
    shadow_leaving_sub.set_location(0x10A851)
    shadow_leaving_sub.bytestring = bytearray([
        0x0E,
        0x03,
        runaway,
        0x6A,
        0xA8,
        0x0F,
        0x11,
        0x01,
        0xFB,
        0x0E,
        0x03,
        runaway,
        0x7E,
        0xA8,
        0x0F,
        0x01,
        0xFC,
        0x0E,
        0x03,
        runaway,
        0x92,
        0xA8,
        0x0F,
        0x10,
        0xFF,
    ])
    shadow_leaving_sub.write(fout)
    shadow_leaving_sub.bytestring = bytearray([runaway])
    shadow_leaving_sub.set_location(0x10FC2F)
    shadow_leaving_sub.write(fout)
    shadow_leaving_sub.set_location(0x10FC5D)
    shadow_leaving_sub.write(fout)

    esperevents = [
        "Ramuh", "Ifrit", "Shiva", "Siren", "Terrato", "Shoat", "Maduin",
        "Bismark", "Stray", "Palidor", "Tritoch", "Odin", "Raiden", "Bahamut",
        "Alexandr", "Crusader", "Ragnarok", "Kirin", "ZoneSeek", "Carbunkl",
        "Phantom", "Sraphim", "Golem", "Unicorn", "Fenrir", "Starlet",
        "Phoenix"
    ]
    esperevents = dict([(n, i) for (i, n) in enumerate(esperevents)])
    espers = list(get_espers(sourcefile))
    num_espers = 3
    for i in range(num_espers):
        if options_.is_code_active("speedcave"):
            esperrank = 999
        else:
            esperrank = 0
            while random.randint(1, 3) == 3:
                esperrank += 1
        candidates = [e for e in espers if e.rank <= esperrank]
        esper = random.choice(candidates)
        espers.remove(esper)
        event_value = esperevents[esper.name] + 0x36
        startsub.bytestring += bytearray([0x86, event_value])
    for i in range(27):  # espers
        byte, bit = i // 8, i % 8
        mem_addr = ((0x17 + byte) << 3) | bit
        startsub.bytestring += bytearray([0xD6, mem_addr])
    for i in range(16):  # characters
        if i in starting:
            continue
        byte, bit = i // 8, i % 8
        mem_addr = ((0x1b + byte) << 3) | bit
        startsub.bytestring += bytearray([0xD6, mem_addr])
    startsub.bytestring += bytearray([
        0xB2,
        0x09,
        0x21,
        0x02,  # start on airship
    ])
    startsub.bytestring.append(0xFE)
    startsub.set_location(0xADD1E)
    startsub.write(fout)

    startsub0 = Substitution()
    startsub0.bytestring = bytearray([0xB2, 0x1E, 0xDD, 0x00, 0xFE])
    startsub0.set_location(0xC9A4F)
    startsub0.write(fout)

    set_airship_sub = Substitution()
    set_airship_sub.bytestring = bytearray([0xB2, 0xD6, 0x02, 0x00, 0xFE])
    set_airship_sub.set_location(0xAF53A)  # need first branch for button press
    set_airship_sub.write(fout)

    tower_msg_sub = Substitution()
    tower_msg_sub.bytestring = bytearray([0xD6, 0xE6, 0xD6,
                                          0xE7])  # reset temp chars
    while len(tower_msg_sub.bytestring) < 12:
        tower_msg_sub.bytestring.append(0xFD)
    tower_msg_sub.set_location(0xA03A7)
    tower_msg_sub.write(fout)

    from locationrandomizer import NPCBlock, EventBlock
    falcon = get_location(0xb)
    save_point = NPCBlock(pointer=None, locid=falcon.locid)
    attributes = {
        "graphics": 0x6f,
        "palette": 6,
        "x": 20,
        "y": 8,
        "show_on_vehicle": False,
        "speed": 0,
        "event_addr": 0x5eb3,
        "facing": 3,
        "no_turn_when_speaking": False,
        "layer_priority": 0,
        "special_anim": 2,
        "memaddr": 0,
        "membit": 0,
        "bg2_scroll": 0,
        "move_type": 0,
        "sprite_priority": 1,
        "vehicle": 0
    }
    for key, value in attributes.items():
        setattr(save_point, key, value)
    save_point.set_id(len(falcon.npcs))
    falcon.npcs.append(save_point)
    save_event = EventBlock(pointer=None, locid=falcon.locid)
    attributes = {"event_addr": 0x29aeb, "x": 20, "y": 8}
    for key, value in attributes.items():
        setattr(save_event, key, value)
    falcon.events.append(save_event)
    partyswitch = NPCBlock(pointer=None, locid=falcon.locid)
    attributes = {
        "graphics": 0x17,
        "palette": 0,
        "x": 16,
        "y": 6,
        "show_on_vehicle": False,
        "speed": 0,
        "event_addr": 0x047d,
        "facing": 2,
        "no_turn_when_speaking": False,
        "layer_priority": 0,
        "special_anim": 0,
        "memaddr": 0,
        "membit": 0,
        "bg2_scroll": 0,
        "move_type": 0,
        "sprite_priority": 0,
        "vehicle": 0,
        "npcid": 2
    }
    for key, value in attributes.items():
        setattr(partyswitch, key, value)
    falcon.npcs.append(partyswitch)

    pilot = random.choice([s for s in starting if s < 12])
    pilot_sub = Substitution()
    pilot_sub.bytestring = bytearray([0x3D, pilot, 0x45, 0x3F, pilot, 0x01])
    for i in range(14):
        if i == pilot:
            continue
        pilot_sub.bytestring += bytearray([0x3F, i, 0x00])
    pilot_sub.set_location(0xC2110)
    pilot_sub.write(fout)

    if options_.is_code_active("racecave"):
        randomize_tower(filename=sourcefile, ancient=True, nummaps=50)
    elif options_.is_code_active("speedcave"):
        randomize_tower(filename=sourcefile, ancient=True, nummaps=85)
    else:
        randomize_tower(filename=sourcefile, ancient=True, nummaps=300)
    manage_map_names(fout)

    unused_enemies = [u for u in get_monsters() if u.id in REPLACE_ENEMIES]

    def safe_boss_validator(formation):
        if formation.is_fanatics:
            return False
        if set(formation.present_enemies) & set(unused_enemies):
            return False
        if formation.formid in NOREPLACE_FORMATIONS:
            return False
        if not (any([m.boss_death for m in formation.present_enemies])
                or formation.get_music() in [1, 2, 5]):
            return False
        if formation.get_music() == 0:
            return False
        if formation.formid in [0x1b0, 0x1b3, 0x1d9, 0x1db, 0x1d7]:
            return False
        if formation.formid in [
                0x1a4, 0x1d4, 0x1d5, 0x1d6, 0x1e4, 0x1e2, 0x1ff, 0x1bd, 0x1be
        ]:
            return False
        if (options_.is_code_active("racecave")
                and formation.formid in [0x162, 0x1c8, 0x1d3]):
            return False
        return True

    def challenge_battle_validator(formation):
        if len(formation.present_enemies) == 0:
            return False
        if set(formation.present_enemies) & set(unused_enemies):
            return False
        if formation.formid in NOREPLACE_FORMATIONS:
            return False
        if formation.battle_event:
            return False
        if formation.formid in [
                0x1a4, 0x1ff, 0x1bd, 0x1d7, 0x200, 0x201, 0x23f
        ]:
            return False
        if formation.get_music() == 0:
            if any([
                    f for f in formations
                    if f.formid != formation.formid and set(f.enemy_ids) ==
                    set(formation.enemy_ids) and f.get_music() != 0
            ]):
                return False
        best_drop = formation.get_best_drop()
        if best_drop and (best_drop.price <= 2 or best_drop.price >= 30000
                          or options_.is_code_active("madworld")):
            return True
        return False

    formations = sorted(get_formations(), key=lambda f: f.rank())
    enemy_formations = [
        f for f in formations if f.is_fanatics or (
            f.present_enemies and not f.has_event and not f.has_boss)
    ]
    enemy_formations = [
        f for f in enemy_formations
        if f.formid not in REPLACE_FORMATIONS + NOREPLACE_FORMATIONS
    ]
    boss_formations = [f for f in formations if safe_boss_validator(f)]
    used_formations = []

    challenges = sorted(
        [f for f in formations if challenge_battle_validator(f)],
        key=lambda f: f.get_best_drop().rank())[-48:]
    challenges = sorted(random.sample(challenges, 24), key=lambda f: f.rank())
    challenges = [f.formid for f in challenges]
    challenges = {
        1: challenges[:6],
        2: challenges[6:12],
        3: challenges[12:18],
        4: challenges[18:24]
    }
    ch_bgs = list(range(0x31)) + [0x36, 0x37]
    waters = [0xD, 0x1F, 0x23]
    snows = [0x12]
    ch_bgs = random.sample(ch_bgs, 10) + [random.choice(waters), snows[0]]
    random.shuffle(ch_bgs)

    for l in get_locations():
        if not hasattr(l, "ancient_rank"):
            l.entrance_set.entrances = []
            l.entrance_set.longentrances = []
            l.chests = []
            l.attacks = 0
            l.write_data(fout)

    pointer = 0xB4E35
    if options_.is_code_active('racecave'):
        candidates = [c for c in starting if c != runaway]
        leaders = random.sample(candidates, 3)
        subptr = pointer - 0xa0000
        leader_sub = Substitution()

        # makes switching impossible and makes row change instant
        # could freeze the game d+pad and A on same frame tho
        leader_sub.set_location(0x324b7)
        leader_sub.bytestring = bytes([0xEA, 0xEA, 0xEA])
        leader_sub.write(fout)
        leader_sub.set_location(0x32473)
        leader_sub.bytestring = bytes([0xEA, 0xEA])
        leader_sub.write(fout)

        leader_sub.set_location(0xa02da)
        leader_sub.bytestring = bytes(
            [0xB2, subptr & 0xFF, (subptr >> 8) & 0xFF, subptr >> 16])
        leader_sub.write(fout)
        leader_sub.set_location(pointer)
        leader_sub.bytestring = bytearray([])
        locked = 0
        for i, c in enumerate(leaders):
            leader_sub.bytestring += bytearray([0x3F, c, i + 1])
            locked |= (1 << c)
        for c in range(16):
            if c in leaders:
                continue
            leader_sub.bytestring += bytearray([0x3F, c, 0x00])
            leader_sub.bytestring += bytearray([0x3E, c])
        leader_sub.bytestring += bytearray(
            [0x47, 0xE1, 0xB2, 0x0B, 0xC9, 0x00, 0x45])
        for i, c in enumerate(leaders):
            leader_sub.bytestring += bytearray([0x3F, c, 0])
            leader_sub.bytestring += bytearray([0x3F, c, i + 1])
        leader_sub.bytestring += bytearray(
            [0x99, 0x03, locked & 0xFF, locked >> 8])
        for i in [14, 15]:
            byte, bit = i // 8, i % 8
            mem_addr = ((0x1b + byte) << 3) | bit
            leader_sub.bytestring += bytearray([0xD6, mem_addr])
        leader_sub.bytestring += bytearray([0x96, 0xFE])
        leader_sub.write(fout)
        pswitch_ptr = pointer - 0xa0000
        pointer += len(leader_sub.bytestring)

    espersubs = {}
    for esper, event_value in esperevents.items():
        byte, bit = event_value // 8, event_value % 8
        mem_addr = ((0x17 + byte) << 3) | bit
        espersub = Substitution()
        espersub.set_location(pointer)
        espersub.bytestring = [
            0xF4, 0x8D, 0x86, event_value + 0x36, 0xD7, mem_addr, 0x3E, None,
            0xFE
        ]
        espersubs[esper] = espersub
        pointer += espersub.size

    inn_template = [
        0x4B, None, None, 0x4B, 0x11, 0x81, 0xB6, None, None, None, None, None,
        None, 0xFE
    ]
    inn_template2 = [
        0x85, None, None, 0xC0, 0xBE, 0x81, 0xFF, 0x69, 0x01, 0x31, 0x84, 0xC3,
        0x8F, 0x84, 0xFF, 0xF4, 0x2C, 0x73, 0x30, 0x0E, 0x01, 0x02, 0x06, 0x16,
        0x31, 0x86, 0xC3, 0x9C, 0x80, 0x8D, 0xCE, 0xFF, 0xB2, 0x67, 0xCF, 0x00,
        0xF0, 0xB8, 0xFA, 0x31, 0x85, 0xD5, 0x36, 0x05, 0xCE, 0xFF, 0xB2, 0x96,
        0xCF, 0x00, 0xFE
    ]

    prices = {
        1: (500, 0xA6E),
        2: (2000, 0xA71),
        3: (8000, 0xA5F),
        4: (30000, 0xA64)
    }

    if options_.is_code_active("racecave"):
        partyswitch_template = [
            0x4B, None, None, 0x4B, 0x86, 0x83, 0xB6, None, None, None, None,
            None, None, 0xFE
        ]

        partyswitch_template2 = [
            0x85, None, None, 0xC0,
            0xBE, 0x81, 0xFF, 0x69, 0x01, 0xB2, pswitch_ptr & 0xFF,
            (pswitch_ptr >> 8) & 0xFF, pswitch_ptr >> 16, 0xFE
        ]

    save_template = [
        0x4B, None, None, 0x4B, 0x24, 0x85, 0xB6, None, None, None, None, None,
        None, 0xFE
    ]
    save_template2 = [
        0x85, None, None, 0xC0, 0xBE, 0x81, 0xFF, 0x69, 0x01, 0xB2, 0xEB, 0x9A,
        0x02, 0xFE
    ]

    enemy_template = [
        0x4B, 0x0B, 0x07, 0xB6, None, None, None, None, None, None, 0xA0, None,
        None, 0xB3, 0x5E, 0x70, 0x4D, None, None, 0xA1, 0x00, 0x96, 0x5C, 0xFE
    ]

    def make_challenge_event(loc, ptr):
        bg = ch_bgs.pop()
        formids = random.sample(challenges[loc.restrank], 2)
        formations = [get_formation(formid) for formid in formids]
        for formid in formids:
            challenges[loc.restrank].remove(formid)
        setcands = [f for f in get_fsets() if f.setid >= 0x100 and f.unused]
        fset = setcands.pop()
        fset.formids = formids
        fset.write_data(fout)
        timer = max(
            [e.stats['hp'] for f in formations for e in f.present_enemies])
        reverse = False
        if timer >= 32768:
            reverse = True
            timer = 65535 - timer
        timer = max(timer, 3600)
        half = None
        while half is None or random.randint(1, 5) == 5:
            half = timer // 2
            timer = half + random.randint(0, half) + random.randint(0, half)
        if reverse:
            timer = 65535 - timer
        timer = int(round(timer / 1800.0))
        timer = max(2, min(timer, 36))
        timer = timer * 1800
        timer = [timer & 0xFF, timer >> 8]
        addr1 = ptr + 10 - 0xa0000
        addr2 = ptr + (len(enemy_template) - 1) - 0xa0000
        addr1 = [addr1 & 0xFF, (addr1 >> 8) & 0xFF, addr1 >> 16]
        addr2 = [addr2 & 0xFF, (addr2 >> 8) & 0xFF, addr2 >> 16]
        bytestring = list(enemy_template)
        bytestring[4:7] = addr1
        bytestring[7:10] = addr2
        bytestring[11:13] = timer
        bytestring[17] = fset.setid & 0xFF
        bytestring[18] = bg
        assert None not in bytestring
        sub = Substitution()
        sub.set_location(ptr)
        sub.bytestring = bytes(bytestring)
        sub.write(fout)
        return ptr + len(enemy_template)

    shops = get_shops(sourcefile)
    shopranks = {}
    itemshops = [s for s in shops if s.shoptype_pretty in ["items", "misc"]]
    othershops = [s for s in shops if s not in itemshops]
    othershops = othershops[random.randint(0, len(othershops) // 2):]
    itemshops = sorted(random.sample(itemshops, 5), key=lambda p: p.rank())
    othershops = sorted(random.sample(othershops, 7), key=lambda p: p.rank())
    for i in range(1, 5):
        if i > 1:
            shopranks[i] = othershops[:2] + itemshops[:1]
            othershops = othershops[2:]
            itemshops = itemshops[1:]
        else:
            shopranks[i] = othershops[:1] + itemshops[:2]
            othershops = othershops[1:]
            itemshops = itemshops[2:]
        assert len(shopranks[i]) == 3
        random.shuffle(shopranks[i])
    shopranks[random.randint(1, 4)][random.randint(0, 2)] = None

    levelmusic = {}
    dungeonmusics = [23, 24, 33, 35, 55, 71, 40, 41, 75, 77, 78]
    random.shuffle(dungeonmusics)
    for i in range(5):
        levelmusic[i] = dungeonmusics.pop()

    locations = [l for l in get_locations() if hasattr(l, "ancient_rank")]
    locations = sorted(locations, key=lambda l: l.ancient_rank)
    restlocs = [l for l in locations if hasattr(l, "restrank")]
    ban_musics = [0, 36, 56, 57, 58, 73, 74, 75] + list(levelmusic.values())
    restmusics = [m for m in range(1, 85) if m not in ban_musics]
    random.shuffle(restmusics)

    optional_chars = [c for c in characters if hasattr(c, "slotid")]
    optional_chars = [
        c for c in optional_chars
        if c.slotid == runaway or (c.id not in starting and c.id in charcands)
    ]
    if options_.is_code_active("speedcave"):
        while len(optional_chars) < 24:
            if random.choice([True, True, False]):
                supplement = [
                    c for c in optional_chars
                    if c.id >= 14 or c.slotid == runaway
                ]
            else:
                supplement = list(optional_chars)
            supplement = sorted(set(supplement), key=lambda c: c.id)
            optional_chars.append(random.choice(supplement))
    random.shuffle(optional_chars)

    ptr = pointer - 0xA0000
    c0, b0, a0 = ptr & 0xFF, (ptr >> 8) & 0xFF, ptr >> 16
    ptr = (pointer + 10) - 0xA0000
    c1, b1, a1 = ptr & 0xFF, (ptr >> 8) & 0xFF, ptr >> 16
    ptr = (pointer + 20) - 0xA0000
    c2, b2, a2 = ptr & 0xFF, (ptr >> 8) & 0xFF, ptr >> 16
    num_in_party_sub = Substitution()
    num_in_party_sub.set_location(0xAC654)
    num_in_party_sub.bytestring = [0xB2, c0, b0, a0]
    num_in_party_sub.write(fout)
    num_in_party_sub.set_location(pointer)
    num_in_party_sub.bytestring = bytes([
        0xC0, 0xAE, 0x01, c1, b1, a1, 0xB2, 0x80, 0xC6, 0x00, 0xC0, 0xAF, 0x01,
        c2, b2, a2, 0xB2, 0x80, 0xC6, 0x00, 0xD3, 0xA3, 0xD3, 0xA2, 0xFE
    ])
    num_in_party_sub.write(fout)
    pointer += len(num_in_party_sub.bytestring)
    ally_addrs = {}
    for chosen in set(optional_chars):
        byte, bit = chosen.slotid // 8, chosen.slotid % 8
        mem_addr = ((0x1b + byte) << 3) | bit
        allysub = Substitution()
        for party_id in range(1, 4):
            for npc_id in range(4, 6):
                allysub.set_location(pointer)
                allysub.bytestring = [
                    0xB2,
                    0xC1,
                    0xC5,
                    0x00,  # set caseword
                    0xC0,
                    0xA3,
                    0x81,
                    None,
                    None,
                    None
                ]
                allysub.bytestring += [
                    0xD4, 0xF0 | chosen.slotid, 0xD4, 0xE0 | chosen.slotid,
                    0xD7, mem_addr
                ]
                if chosen.id >= 14 or options_.is_code_active("speedcave"):
                    allysub.bytestring += [
                        0x77, chosen.slotid, 0x8b, chosen.slotid, 0x7F, 0x8c,
                        chosen.slotid, 0x7F, 0x88, chosen.slotid, 0x00, 0x00
                    ]
                allysub.bytestring += [
                    0x3E, 0x10 | npc_id, 0x3D, chosen.slotid, 0x3F,
                    chosen.slotid, party_id, 0x47, 0x45, 0xF4, 0xD0, 0xFE
                ]
                pointer = pointer + len(allysub.bytestring)
                uptr = (pointer - 1) - 0xa0000
                a, b, c = (uptr >> 16, (uptr >> 8) & 0xFF, uptr & 0xFF)
                allysub.bytestring[7:10] = [c, b, a]
                allysub.write(fout)
                event_addr = (allysub.location - 0xa0000) & 0x3FFFF
                ally_addrs[chosen.id, party_id, npc_id] = event_addr

    npc_palettes = get_npc_palettes()
    for g in npc_palettes:
        npc_palettes[g] = [v for v in npc_palettes[g] if 0 <= v <= 5]
    for g in range(14, 63):
        if g not in npc_palettes or not npc_palettes[g]:
            npc_palettes[g] = list(range(6))

    def make_paysub(template, template2, loc, ptr):
        sub = Substitution()
        sub.set_location(ptr)
        price, message = prices[loc.restrank]
        message |= 0x8000
        sub.bytestring = list(template)
        ptr += len(template)
        price = [price & 0xFF, price >> 8]
        message = [message & 0xFF, message >> 8]
        p = (ptr - 0xA0000) & 0x3FFFF
        p2 = p - 1
        ptrbytes = [p & 0xFF, (p >> 8) & 0xFF, p >> 16]
        ptrbytes2 = [p2 & 0xFF, (p2 >> 8) & 0xFF, p2 >> 16]
        mapid = [loc.locid & 0xFF, loc.locid >> 8]
        mapid[1] |= 0x23
        sub.bytestring[1:3] = message
        sub.bytestring[7:10] = ptrbytes
        sub.bytestring[10:13] = ptrbytes2
        assert None not in sub.bytestring
        assert len(sub.bytestring) == 14
        sub.bytestring += template2
        ptr += len(template2)
        sub.bytestring[15:17] = price
        assert None not in sub.bytestring
        sub.bytestring = bytes(sub.bytestring)
        sub.write(fout)
        return sub

    random.shuffle(restlocs)
    for l in restlocs:
        assert l.ancient_rank == 0
        l.music = restmusics.pop()
        l.make_warpable()

        innsub = make_paysub(inn_template, inn_template2, l, pointer)
        pointer += innsub.size
        savesub = make_paysub(save_template, save_template2, l, pointer)
        pointer += savesub.size
        if options_.is_code_active('racecave'):
            pswitch_sub = make_paysub(partyswitch_template,
                                      partyswitch_template2, l, pointer)
            pointer += pswitch_sub.size

        event_addr = (innsub.location - 0xa0000) & 0x3FFFF
        innkeeper = NPCBlock(pointer=None, locid=l.locid)
        graphics = random.randint(14, 62)
        palette = random.choice(npc_palettes[graphics])
        attributes = {
            "graphics": graphics,
            "palette": palette,
            "x": 52,
            "y": 16,
            "show_on_vehicle": False,
            "speed": 0,
            "event_addr": event_addr,
            "facing": 2,
            "no_turn_when_speaking": False,
            "layer_priority": 0,
            "special_anim": 0,
            "memaddr": 0,
            "membit": 0,
            "bg2_scroll": 0,
            "move_type": 0,
            "sprite_priority": 0,
            "vehicle": 0
        }
        for key, value in attributes.items():
            setattr(innkeeper, key, value)
        l.npcs.append(innkeeper)

        unequipper = NPCBlock(pointer=None, locid=l.locid)
        attributes = {
            "graphics": 0x1e,
            "palette": 3,
            "x": 49,
            "y": 16,
            "show_on_vehicle": False,
            "speed": 0,
            "event_addr": 0x23510,
            "facing": 2,
            "no_turn_when_speaking": False,
            "layer_priority": 0,
            "special_anim": 0,
            "memaddr": 0,
            "membit": 0,
            "bg2_scroll": 0,
            "move_type": 0,
            "sprite_priority": 0,
            "vehicle": 0
        }
        for key, value in attributes.items():
            setattr(unequipper, key, value)
        l.npcs.append(unequipper)

        event_addr = (savesub.location - 0xa0000) & 0x3FFFF
        pay_to_save = NPCBlock(pointer=None, locid=l.locid)
        attributes = {
            "graphics": 0x6f,
            "palette": 6,
            "x": 47,
            "y": 4,
            "show_on_vehicle": False,
            "speed": 0,
            "event_addr": event_addr,
            "facing": 3,
            "no_turn_when_speaking": False,
            "layer_priority": 0,
            "special_anim": 2,
            "memaddr": 0,
            "membit": 0,
            "bg2_scroll": 0,
            "move_type": 0,
            "sprite_priority": 0,
            "vehicle": 0
        }
        for key, value in attributes.items():
            setattr(pay_to_save, key, value)
        l.npcs.append(pay_to_save)

        if l.restrank == 4:
            final_loc = get_location(412)
            if len(final_loc.npcs) < 2:
                final_save = NPCBlock(pointer=None, locid=l.locid)
                attributes = {
                    "graphics": 0x6f,
                    "palette": 6,
                    "x": 82,
                    "y": 43,
                    "show_on_vehicle": False,
                    "speed": 0,
                    "event_addr": event_addr,
                    "facing": 3,
                    "no_turn_when_speaking": False,
                    "layer_priority": 0,
                    "special_anim": 2,
                    "memaddr": 0,
                    "membit": 0,
                    "bg2_scroll": 0,
                    "move_type": 0,
                    "sprite_priority": 0,
                    "vehicle": 0,
                    "npcid": 1
                }
                for key, value in attributes.items():
                    setattr(final_save, key, value)
                final_loc.npcs.append(final_save)

        shop = shopranks[l.restrank].pop()
        if shop is not None:
            shopsub = Substitution()
            shopsub.set_location(pointer)
            shopsub.bytestring = bytes([0x9B, shop.shopid, 0xFE])
            shopsub.write(fout)
            pointer += len(shopsub.bytestring)
            event_addr = (shopsub.location - 0xa0000) & 0x3FFFF
        else:
            event_addr = 0x178cb
            colsub = Substitution()
            colsub.set_location(0xb78ea)
            colsub.bytestring = bytes([0x59, 0x04, 0x5C, 0xFE])
            colsub.write(fout)
        shopkeeper = NPCBlock(pointer=None, locid=l.locid)
        graphics = random.randint(14, 62)
        palette = random.choice(npc_palettes[graphics])
        attributes = {
            "graphics": graphics,
            "palette": palette,
            "x": 39,
            "y": 11,
            "show_on_vehicle": False,
            "speed": 0,
            "event_addr": event_addr,
            "facing": 1,
            "no_turn_when_speaking": False,
            "layer_priority": 0,
            "special_anim": 0,
            "memaddr": 0,
            "membit": 0,
            "bg2_scroll": 0,
            "move_type": 0,
            "sprite_priority": 0,
            "vehicle": 0
        }
        for key, value in attributes.items():
            setattr(shopkeeper, key, value)
        l.npcs.append(shopkeeper)

        if optional_chars:
            chosen = optional_chars.pop()
            assert chosen.palette is not None
            if chosen.id >= 14 and False:
                byte, bit = 0, 0
            else:
                byte, bit = (chosen.slotid // 8) + 0x1b, chosen.slotid % 8
            event_addr = ally_addrs[chosen.id, l.party_id, len(l.npcs)]
            ally = NPCBlock(pointer=None, locid=l.locid)
            attributes = {
                "graphics": chargraphics[chosen.id],
                "palette": chosen.palette,
                "x": 54,
                "y": 18,
                "show_on_vehicle": False,
                "speed": 0,
                "event_addr": event_addr,
                "facing": 2,
                "no_turn_when_speaking": False,
                "layer_priority": 0,
                "special_anim": 0,
                "memaddr": byte,
                "membit": bit,
                "bg2_scroll": 0,
                "move_type": 0,
                "sprite_priority": 0,
                "vehicle": 0
            }
            for key, value in attributes.items():
                setattr(ally, key, value)
            l.npcs.append(ally)
            if (len(optional_chars) == 12
                    or (len(optional_chars) > 0
                        and options_.is_code_active('speedcave'))):
                temp = optional_chars.pop()
                if chosen.id != temp.id:
                    chosen = temp
                    if chosen.id >= 14 and False:
                        byte, bit = 0, 0
                    else:
                        byte, bit = (chosen.slotid //
                                     8) + 0x1b, chosen.slotid % 8
                    event_addr = ally_addrs[chosen.id, l.party_id, len(l.npcs)]
                    attributes = {
                        "graphics": chargraphics[chosen.id],
                        "palette": chosen.palette,
                        "x": 53,
                        "y": 18,
                        "show_on_vehicle": False,
                        "speed": 0,
                        "event_addr": event_addr,
                        "facing": 2,
                        "no_turn_when_speaking": False,
                        "layer_priority": 0,
                        "special_anim": 0,
                        "memaddr": byte,
                        "membit": bit,
                        "bg2_scroll": 0,
                        "move_type": 0,
                        "sprite_priority": 0,
                        "vehicle": 0
                    }
                    ally = NPCBlock(pointer=None, locid=l.locid)
                    for key, value in attributes.items():
                        setattr(ally, key, value)
                    l.npcs.append(ally)

        if l.restrank == 1:
            num_espers = 3
        elif l.restrank in [2, 3]:
            num_espers = 2
        elif l.restrank == 4:
            num_espers = 1
        for i in range(num_espers):
            if len(espers) == 0:
                break
            if options_.is_code_active('speedcave'):
                candidates = espers
            else:
                esperrank = l.restrank
                if random.randint(1, 7) == 7:
                    esperrank += 1
                candidates = []
                while not candidates:
                    candidates = [e for e in espers if e.rank == esperrank]
                    if not candidates or random.randint(1, 3) == 3:
                        candidates = [e for e in espers if e.rank <= esperrank]
                    if not candidates:
                        esperrank += 1
            esper = random.choice(candidates)
            espers.remove(esper)
            espersub = espersubs[esper.name]
            index = espersub.bytestring.index(None)
            espersub.bytestring[index] = 0x10 | len(l.npcs)
            espersub.write(fout)
            event_addr = (espersub.location - 0xa0000) & 0x3FFFF
            event_value = esperevents[esper.name]
            byte, bit = event_value // 8, event_value % 8
            magicite = NPCBlock(pointer=None, locid=l.locid)
            attributes = {
                "graphics": 0x5B,
                "palette": 2,
                "x": 44 + i,
                "y": 16,
                "show_on_vehicle": False,
                "speed": 0,
                "event_addr": event_addr,
                "facing": 0,
                "no_turn_when_speaking": True,
                "layer_priority": 2,
                "special_anim": 2,
                "memaddr": byte + 0x17,
                "membit": bit,
                "bg2_scroll": 0,
                "move_type": 0,
                "sprite_priority": 0,
                "vehicle": 0
            }
            for key, value in attributes.items():
                setattr(magicite, key, value)
            l.npcs.append(magicite)

        event_addr = pointer - 0xa0000
        pointer = make_challenge_event(l, pointer)
        enemy = NPCBlock(pointer=None, locid=l.locid)
        attributes = {
            "graphics": 0x3e,
            "palette": 2,
            "x": 42,
            "y": 6,
            "show_on_vehicle": False,
            "speed": 0,
            "event_addr": event_addr,
            "facing": 2,
            "no_turn_when_speaking": False,
            "layer_priority": 0,
            "special_anim": 0,
            "memaddr": 0,
            "membit": 0,
            "bg2_scroll": 0,
            "move_type": 0,
            "sprite_priority": 0,
            "vehicle": 0
        }
        for key, value in attributes.items():
            setattr(enemy, key, value)
        l.npcs.append(enemy)

        if options_.is_code_active('racecave'):
            event_addr = (pswitch_sub.location - 0xa0000) & 0x3FFFF
            partyswitch = NPCBlock(pointer=None, locid=l.locid)
            attributes = {
                "graphics": 0x17,
                "palette": 0,
                "x": 55,
                "y": 16,
                "show_on_vehicle": False,
                "speed": 0,
                "event_addr": event_addr,
                "facing": 2,
                "no_turn_when_speaking": False,
                "layer_priority": 0,
                "special_anim": 0,
                "memaddr": 0,
                "membit": 0,
                "bg2_scroll": 0,
                "move_type": 0,
                "sprite_priority": 0,
                "vehicle": 0
            }
            for key, value in attributes.items():
                setattr(partyswitch, key, value)
            l.npcs.append(partyswitch)

    assert len(optional_chars) == 0

    if pointer >= 0xb6965:
        raise Exception("Cave events out of bounds. %x" % pointer)

    # lower encounter rate
    dungeon_rates = [
        0x38, 0, 0x20, 0, 0xb0, 0, 0x00, 1, 0x1c, 0, 0x10, 0, 0x58, 0, 0x80, 0
    ] + ([0] * 16)
    assert len(dungeon_rates) == 32
    encrate_sub = Substitution()
    encrate_sub.set_location(0xC2BF)
    encrate_sub.bytestring = bytes(dungeon_rates)
    encrate_sub.write(fout)

    maxrank = max(locations, key=lambda l: l.ancient_rank).ancient_rank
    for l in locations:
        if l not in restlocs and (l.npcs or l.events):
            for n in l.npcs:
                if n == final_save:
                    continue
                if n.graphics == 0x6F:
                    n.memaddr, n.membit, n.event_addr = 0x73, 1, 0x5EB3
                    success = False
                    for e in l.events:
                        if e.x % 128 == n.x % 128 and e.y % 128 == n.y % 128:
                            if success:
                                raise Exception("Duplicate events found.")
                            e.event_addr = 0x5EB3
                            success = True
                    if not success:
                        raise Exception("No corresponding event found.")
        for e in l.entrances:
            e.dest |= 0x800
        rank = l.ancient_rank
        l.name_id = min(rank, 0xFF)

        if not hasattr(l, "restrank"):
            if hasattr(l, "secret_treasure") and l.secret_treasure:
                pass
            elif l.locid == 334 or not hasattr(l, "routerank"):
                l.music = 58
            elif l.routerank in levelmusic:
                l.music = levelmusic[l.routerank]
            else:
                raise Exception

        l.setid = rank
        if rank == 0:
            l.attacks = 0
        elif rank > 0xFF:
            l.setid = random.randint(0xF0, 0xFF)
        else:

            def enrank(r):
                mr = min(maxrank, 0xFF)
                r = max(0, min(r, mr))
                if options_.is_code_active('racecave'):
                    half = r // 2
                    quarter = half // 2
                    r = (half + random.randint(0, quarter) +
                         random.randint(0, quarter))
                if r <= 0:
                    return 0
                elif r >= mr:
                    return 1.0
                ratio = float(r) / mr
                return ratio

            low = enrank(rank - 3)
            high = enrank(rank + 2)
            high = int(round(high * len(enemy_formations)))
            low = int(round(low * len(enemy_formations)))
            while high - low < 4:
                high = min(high + 1, len(enemy_formations))
                low = max(low - 1, 0)
            candidates = enemy_formations[low:high]
            chosen_enemies = random.sample(candidates, 4)

            chosen_enemies = sorted(chosen_enemies, key=lambda f: f.rank())

            if options_.is_code_active('racecave'):
                bossify = False
            elif rank >= maxrank * 0.9:
                bossify = True
            else:
                if options_.is_code_active('speedcave'):
                    thresh = 0.5
                else:
                    thresh = 0.1
                bossify = rank >= random.randint(int(maxrank * thresh),
                                                 int(maxrank * 0.9))
                bossify = bossify and random.randint(1, 3) == 3
            if bossify:
                formrank = chosen_enemies[0].rank()
                candidates = [
                    c for c in boss_formations if c.rank() >= formrank
                ]
                if candidates:
                    if rank < maxrank * 0.75:
                        candidates = candidates[:random.randint(2, 4)]
                    chosen_boss = random.choice(candidates)
                    chosen_enemies[3] = chosen_boss

            if options_.is_code_active('speedcave'):
                thresh, bossthresh = 2, 1
            else:
                # allow up to three of the same formation
                thresh, bossthresh = 3, 2
            for c in chosen_enemies:
                used_formations.append(c)
                if used_formations.count(c) >= bossthresh:
                    if c in boss_formations:
                        boss_formations.remove(c)
                    if used_formations.count(c) >= thresh:
                        if c in enemy_formations:
                            enemy_formations.remove(c)

            fset = get_fset(rank)
            fset.formids = [f.formid for f in chosen_enemies]
            for formation in fset.formations:
                if formation.get_music() == 0:
                    formation.set_music(6)
                    formation.set_continuous_music()
                    formation.write_data(fout)
            fset.write_data(fout)

        if not (hasattr(l, "secret_treasure") and l.secret_treasure):
            if options_.is_code_active('speedcave') or rank == 0:
                low = random.randint(0, 400)
                high = random.randint(low, low * 5)
                high = random.randint(low, high)
            else:
                low = rank * 2
                high = low * 1.5
                while random.choice([True, False, False]):
                    high = high * 1.5
            if rank < maxrank * 0.4:
                monster = False
            else:
                monster = None
            if 0 < rank < maxrank * 0.75:
                enemy_limit = sorted([f.rank() for f in fset.formations])[-2]
                enemy_limit *= 1.5
            else:
                enemy_limit = None
            l.unlock_chests(int(low),
                            int(high),
                            monster=monster,
                            guarantee_miab_treasure=True,
                            enemy_limit=enemy_limit,
                            uncapped_monsters=options_.is_code_active('bsiab'))

        l.write_data(fout)

    final_cut = Substitution()
    final_cut.set_location(0xA057D)
    final_cut.bytestring = bytearray([
        0x3F,
        0x0E,
        0x00,
        0x3F,
        0x0F,
        0x00,
    ])
    if not options_.is_code_active("racecave"):
        final_cut.bytestring += bytearray(
            [0x9D, 0x4D, 0x65, 0x33, 0xB2, 0xA9, 0x5E, 0x00])
    else:
        for i in range(16):
            final_cut.bytestring += bytearray([0x3F, i, 0x00])
        locked = 0
        protected = random.sample(starting, 4)
        assignments = {0: [], 1: [], 2: [], 3: []}
        for i, c in enumerate(protected):
            if 1 <= i <= 3 and random.choice([True, False]):
                assignments[i].append(c)

        chars = list(range(16))
        random.shuffle(chars)
        for c in chars:
            if c in protected:
                continue
            if c >= 14 and random.choice([True, False]):
                continue
            if random.choice([True, True, False]):
                i = random.randint(0, 3)
                if len(assignments[i]) >= 3:
                    continue
                elif len(assignments[i]) == 2 and random.choice([True, False]):
                    continue
                assignments[i].append(c)

        for key in assignments:
            for c in assignments[key]:
                locked |= (1 << c)
                if key > 0:
                    final_cut.bytestring += bytearray([0x3F, c, key])
        final_cut.bytestring += bytearray(
            [0x99, 0x03, locked & 0xFF, locked >> 8])
        from chestrandomizer import get_2pack
        event_bosses = {
            1: [0xC18A4, 0xC184B],
            2: [0xC16DD, 0xC171D, 0xC1756],
            3: [None, None, None]
        }
        fout.seek(0xA0F6F)
        fout.write(bytes([0x36]))
        candidates = sorted(boss_formations, key=lambda b: b.rank())
        candidates = [c for c in candidates if c.inescapable]
        candidates = candidates[random.randint(0, len(candidates) - 16):]
        chosens = random.sample(candidates, 8)
        chosens = sorted(chosens, key=lambda b: b.rank())
        for rank in sorted(event_bosses):
            num = len(event_bosses[rank])
            rankchosens, chosens = chosens[:num], chosens[num:]
            assert len(rankchosens) == num
            random.shuffle(rankchosens)
            if rank == 3:
                bgs = random.sample([
                    0x07, 0x0D, 0x17, 0x18, 0x19, 0x1C, 0x1F, 0x21, 0x22, 0x23,
                    0x29, 0x2C, 0x30, 0x36, 0x37
                ], 3)
            for i, (address,
                    chosen) in enumerate(zip(event_bosses[rank], rankchosens)):
                if rank == 3:
                    chosen.set_music(5)
                elif rank == 2:
                    chosen.set_music(2)
                else:
                    chosen.set_music(4)
                form_music_overrides[chosen.formid] = chosen.get_music()
                chosen.set_appearing([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13])
                fset = get_2pack(chosen)
                if address is not None:
                    fout.seek(address)
                    fout.write(bytes([fset.setid & 0xFF]))
                else:
                    bg = bgs.pop()
                    final_cut.bytestring += bytearray([
                        0x46, i + 1, 0x4D, fset.setid & 0xFF, bg, 0xB2, 0xA9,
                        0x5E, 0x00
                    ])

        assert len(chosens) == 0

    final_cut.bytestring += bytearray([0xB2, 0x64, 0x13, 0x00])
    final_cut.write(fout)
Пример #21
0
def cycle_statuses(fout):
    cycles_sub = Substitution()
    cycles_sub.set_location(0x012E4F) #C12E4F
    cycles_sub.bytestring = bytes([0x80, 0x2B])         #BRA $2E7C	    (+43)
    cycles_sub.write(fout)

    cycles_sub.set_location(0x012E5C) #C12E5C
    cycles_sub.bytestring = bytes([0x80, 0x1E])         #BRA $2E7C	    (+30)
    cycles_sub.write(fout)

    cycles_sub.set_location(0x012E69) #C12E69
    cycles_sub.bytestring = bytes([
        0x80, 0x11,             #2E69                   BRA $2E7C	    (+17)
        #Status checker for outline colours.
        0xB9, 0xA9, 0x2E,       #2E6B/2E6C/2E6D         LDA $2EA9,Y     get current outline in rotation
        0x24, 0x38,             #2E6E/2E6F              BIT $38         check against current status
        0xD0, 0x10,             #2E70/2E71              BNE set_color   (+16) branch if a match was found 0x012E82
        0x4A,                   #2E72                   LSR A           check next status
        0x69, 0x00,             #2E73/2E74              ADC #$00        maintain wait bit
        0x99, 0xA9, 0x2E,       #2E75/2E76/2E77         STA $2EA9,Y     update outline colour rotation
        0xC9, 0x04,             #2E78/2E79              CMP #$20        loop over 6 statuses
        0xB0, 0xF2,             #2E7A/2E7B              BCS $2E6E       (-14)
        0xA9, 0x80,             #2E7C/2E7D              LDA #$80        no match found, reset to Rflect
        0x99, 0xA9, 0x2E,       #2E7E/2E7F/2E80         STA $2EA9,Y
        0x60,                   #2E81       RTS
        #set_colour
        0x29, 0xFC,             #2E82/2E83              AND #$FC        clear wait bit
        0x20, 0x0F, 0x1A,       #2E84/2E85/2E86         JSR $1A0F
        0xBF, 0x8B, 0x2E, 0xC1, #2E87/2E88/2E89/2E8A    LDA.l           outline_color_table,X  ; get outline colour
        #outline_color_table
        0x80, 0x36,             #2D8B/2E8C              BRA $2EC3	    (+54) Implement outline colour
        0x04,                   #2E8D                   DB $04          Slow
        0x03,                   #2E8E                   DB $03          Haste
        0x07,                   #2E8F                   DB $07          Stop
        0x02,                   #2E90                   DB $02          Shell
        0x01,                   #2E91                   DB $01          Safe
        0x00,                   #2E92                   DB $00          Rflect
        0xB9, 0xA9, 0x2E,       #2E93/2E94/2E95         LDA $2EA9,Y     current outline color rotation
        0x4A,                   #2E96                   LSR A           move one step forward
        0xB0, 0xE3,             #2E97/2E98              BCS             reset_rotation (-29) if wait bit set, clear it, reset and exit
        0x29, 0xFC,             #2E99/2E9A              AND $FC         keep 6 bits
        0xF0, 0xDF,             #2E9B/2E9C              BEQ             reset_rotation (-11) if all clear, reset and exit
        0x24, 0x38,             #2E9D/2E9E              BIT             $38 - check current status
        0xF0, 0xF5,             #2E9F/2EA0              BEQ             rotation_loop (-11) loop until match found
        0x80, 0xDB,             #2EA1/2EA2              BRA             update_rotation (-37) update outline rotation 0x012E7E
        0xEA, 0xEA, 0xEA, 0xEA, #2EA3/2EA4/2EA5/2EA6    NOP
        0xEA, 0xEA, 0xEA, 0xEA, #2EA7/2EA8/2EA9/2EAA    NOP
        0xEA, 0xEA, 0xEA, 0xEA, #2EAB/2EAC/2EAD/2EAE    NOP
        0xEA, 0xEA, 0xEA, 0xEA, #2EAF/2EB0/2EB1/2EB2    NOP
        0xEA                    #2EB3                   NOP
    ])
    cycles_sub.write(fout)
    
    cycles_sub.set_location(0x012ECF) #C12ECF
    cycles_sub.bytestring = bytes([
        #outline_control
        0xBF, 0xAA, 0xE3, 0xC2, #2ECF/2ED0/2ED1/2ED2    LDA $C2E3AA,X	Get colour change offset
        0x18,                   #2ED3                   CLC
        0x65, 0x2C,             #2ED4/2ED5              ADC $2C		    Add to current fade
        0x85, 0x36,             #2ED6/2ED7              STA $36		    Save here
        0x29, 0x3C,             #2ED8/2ED9              AND #$3C	    Isolate fade
        0x4A,                   #2EDA                   LSR A
        0x85, 0x2C,             #2EDB/2EDC              STA $2C		    Update fade
        0x64, 0x2D,             #2EDD/2EDE              STZ $2D
        0xA5, 0x36,             #2EDF                   LDA $36
        0x0A, 0x0A,             #2EE1/2EE2              ASL x2		    Is fade decreasing?
        0x90, 0x06,             #2EE3/2EE4              BCC $2EEB	    (+6) If so...
        0xA9, 0x1F,             #2EE5/2EE6              LDA #$1F	    ...subtract from 31
        0xE5, 0x2C,             #2EE7/2EE8              SBC $2C
        0x85, 0x2C,             #2EE9/2EEA              STA $2C
        0xA5, 0x2C,             #2EEB/2EEC              LDA $2C		    Get fade amount
        0xC9, 0x1F,             #2EED/2EEE              CMP #$1F	    Is it fully faded?
        0xD0, 0x06,             #2EEF/2EF0              BNE $2EF7       (+6) If so...
        0x20, 0x93, 0x2E,       #2EF1/2EF2              JSR $2E93       ...rotate colour
        0x80, 0x01,             #2EF3/2EF4              BRA $2EF7	    (+1)
        0xEA                    #2EF5                   NOP
    ])
    cycles_sub.write(fout)

    cycles_sub.set_location(0x02307D) #C2307D
    cycles_sub.bytestring = bytes([
        0xDA,                   #307D                   PHX			    Save party member index
        0xA5, 0xFE,             #307E/307F              LDA $FE		    Get row
        0x9D, 0xA1, 0x3A,       #3080/3081/3082         STA $3AA1,X	    Save to special props
        0xBD, 0xD9, 0x3E,       #3083/3084/3085         LDA $3ED9,X	    Preserve special sprite
        0x48,                   #3086                   PHA
        0xA3, 0x05,             #3087/3088              LDA $05,S		Get loop variable
        0x9D, 0xD9, 0x3E,       #3089/308A/308B         STA $3ED9,X	    Save to roster position
        0x7B,                   #308C                   TDC
        0x8A,                   #308D                   TXA
        0x0A, 0x0A, 0x0A, 0x0A, #308E/308F/3090/3091    ASL x4
        0xAA,                   #3092                   TAX
        0xA9, 0x06,             #3093/3094              LDA #$06
        0x85, 0xFE,             #3095/3096              STA $FE
        0x5A,                   #3097                   PHY			    Preserve Y-loop index
        0xB9, 0x01, 0x16,       #3098/3099/309A         LDA $1601,Y	    Get normal sprite & name
        0x9D, 0xAE, 0x2E,       #309B/309C/309D         STA $2EAE,X	    Store to display vars
        0xE8,                   #309E                   INX
        0xC8,                   #309F                   INY
        0xC6, 0xFE,             #30A0/30A1              DEC $FE		    7 iterations to loop
        0x10, 0xF4,             #30A2/30A3              BPL $3098	    (-12)
        0x7A,                   #30A4                   PLY			    Restore Y-loop index
        0x68,                   #30A5                   PLA			    Restore special sprite
        0xC9, 0xFF,             #30A6/30A7              CMP #$FF		Is it null?
        0xF0, 0x03,             #30A8/30A9              BEQ $30AD	    (+3) If not...
        0x9D, 0xA7, 0x2E,       #30AA/30AB              STA $2EA7,X	    ...overwrite sprite
        0xA9, 0x81,             #30AC/30AD              LDA #$81		Reflect + wait bit
        0x9D, 0xA2, 0x2E,       #30AE/30AF/30B0         STA $2EA2,X	    Init outline rotation
        0xA3, 0x03,             #30B1/30B2              LDA $03,S		Get character ID
        0x9D, 0xBF, 0x2E,       #30B3/30B4/30B5         STA $2EBF,X	    Save it
        0xC9, 0x0E,             #30B6/30B7              CMP #$0E		Banon or higher?
        0xC2, 0x20,             #30B8/30B9              REP #$20		16-bit A
        0xAA                    #30BA                   TAX			    Move to X
    ]) 
    cycles_sub.write(fout)
Пример #22
0
 def make_paysub(template, template2, loc, ptr):
     sub = Substitution()
     sub.set_location(ptr)
     price, message = prices[loc.restrank]
     message |= 0x8000
     sub.bytestring = list(template)
     ptr += len(template)
     price = [price & 0xFF, price >> 8]
     message = [message & 0xFF, message >> 8]
     p = (ptr - 0xA0000) & 0x3FFFF
     p2 = p - 1
     ptrbytes = [p & 0xFF, (p >> 8) & 0xFF, p >> 16]
     ptrbytes2 = [p2 & 0xFF, (p2 >> 8) & 0xFF, p2 >> 16]
     mapid = [loc.locid & 0xFF, loc.locid >> 8]
     mapid[1] |= 0x23
     sub.bytestring[1:3] = message
     sub.bytestring[7:10] = ptrbytes
     sub.bytestring[10:13] = ptrbytes2
     assert None not in sub.bytestring
     assert len(sub.bytestring) == 14
     sub.bytestring += template2
     ptr += len(template2)
     sub.bytestring[15:17] = price
     assert None not in sub.bytestring
     sub.bytestring = bytes(sub.bytestring)
     sub.write(fout)
     return sub
Пример #23
0
def no_dance_stumbles(fout):
    nds_sub = Substitution()
    nds_sub.set_location(0x0217A0) #C217A0
    nds_sub.bytestring = bytes([0xEA, 0xEA])            #No Op x2
    nds_sub.write(fout)
Пример #24
0
def mutate_event_items(fout,
                       cutscene_skip=False,
                       crazy_prices=False,
                       no_monsters=False,
                       uncapped_monsters=False):
    event_item_sub = Substitution()
    event_item_sub.set_location(0x9926)
    event_item_sub.bytestring = bytes(
        [0x8A, 0xD6, 0x99, 0xd6])  # pointer to new event commands 66 and 67
    event_item_sub.write(fout)
    event_item_sub.set_location(0x9934)
    event_item_sub.bytestring = bytes(
        [0x13, 0xD6, 0x26, 0xD6, 0x71,
         0xD6])  # pointers to new event commands 6D, 6E, and 6F
    event_item_sub.write(fout)

    event_item_sub.set_location(0xD613)
    event_item_sub.bytestring = bytes([
        # 6D : (2 bytes) Give item to party and show message "Received <Item>!"
        0xA5,
        0xEB,
        0x85,
        0x1A,
        0x8D,
        0x83,
        0x05,
        0x20,
        0xFC,
        0xAC,
        0x20,
        0x06,
        0x4D,
        0xA9,
        0x08,
        0x85,
        0xEB,
        0x80,
        0x59,

        # 6E (2 bytes) Give 100 * param GP to party and show message "Found <N> GP!" (It's 100 * param GP because that's what treasure chests do, but it doesn't need to be.)
        0xA5,
        0xEB,
        0x85,
        0x1A,
        0x8D,
        0x02,
        0x42,
        0xA9,
        0x64,
        0x8D,
        0x03,
        0x42,
        0xEA,
        0xEA,
        0xEA,
        0xAC,
        0x16,
        0x42,
        0x84,
        0x22,
        0x64,
        0x24,
        0xC2,
        0x21,
        0x98,
        0x6D,
        0x60,
        0x18,
        0x8D,
        0x60,
        0x18,
        0x7B,
        0xE2,
        0x20,
        0x6D,
        0x62,
        0x18,
        0x8D,
        0x62,
        0x18,
        0xC9,
        0x98,
        0x90,
        0x13,
        0xAE,
        0x60,
        0x18,
        0xE0,
        0x7F,
        0x96,
        0x90,
        0x0B,
        0xA2,
        0x7F,
        0x96,
        0x8E,
        0x60,
        0x18,
        0xA9,
        0x98,
        0x8D,
        0x62,
        0x18,
        0x20,
        0x06,
        0x4D,
        0x20,
        0xE5,
        0x02,
        0xA9,
        0x10,
        0x85,
        0xEB,
        0x80,
        0x0E,

        # 6F : (2 bytes) Show "Monster-in-a-box!" and start battle with formation from param
        0xA5,
        0xEB,
        0x85,
        0x1A,
        0x8D,
        0x89,
        0x07,
        0x20,
        0x06,
        0x4D,
        0xA9,
        0x40,
        0x85,
        0xEB,

        # Common code used by all three functions. Finishes setting parameters to jump into action B2 (call event subroutine)
        0x64,
        0xEC,
        0xA9,
        0x00,
        0x85,
        0xED,
        0xA9,
        0x02,
        0x4C,
        0xA3,
        0xB1,

        # 66 : (4 bytes) Show text $AAAA with item name $BB and wait for button press
        0xA5,
        0xED,
        0x85,
        0x1A,
        0x8D,
        0x83,
        0x05,
        0xA9,
        0x01,
        0x20,
        0x70,
        0x9B,
        0x4C,
        0xBC,
        0xA4,

        # 67 : (4 bytes) Show text $AAAA with number $BB and wait for button press
        0xA5,
        0xED,
        0x85,
        0x1A,
        0x85,
        0x22,
        0x64,
        0x24,
        0x20,
        0xE5,
        0x02,
        0xA9,
        0x01,
        0x20,
        0x70,
        0x9B,
        0x4C,
        0xBC,
        0xA4,
    ])
    event_item_sub.write(fout)

    fout.seek(0xC3243)
    phoenix_events = fout.read(0x3F)
    fout.seek(0xC324F)
    fout.write(phoenix_events)

    # End some text boxes early so they don't show the item.
    early_end_texts = [
        (0x137, "I understand your unease.<line>"
         "But even as we speak, innocent lives are being lost…<page>"
         "Please. We need your abilities.<line>"
         "This relic will keep you safe."),
        (0x13e, "BANON: A lucky charm. Take it!"),
        (0x30e, "I heard…<line>"
         "In my name you send Lola many things…<page>"
         "I wish to thank you.<line>"
         "Please accept this as a token of my appreciation."),
        (0x6ce, "Took the treasure from Lone Wolf, the pickpocket!"),
        (0x752, "And this is from the Emperor himself…"),
        (0x754,
         "Your behavior at the banquet was impeccable. Please take this as well!"
         )
    ]
    for index, text in early_end_texts:
        set_dialogue(index, text)

    for location in event_items_dict:
        for e in event_items_dict[location]:
            e.mutate_contents(cutscene_skip=cutscene_skip,
                              no_monsters=no_monsters,
                              uncapped_monsters=uncapped_monsters,
                              crazy_prices=crazy_prices)
            e.write_data(fout, cutscene_skip=cutscene_skip)
Пример #25
0
def sprint_shoes_break(fout):
    sprint_shoes_sub = Substitution()
    sprint_shoes_sub.set_location(0x2273D)
    sprint_shoes_sub.bytestring = bytes([0xE7])
    sprint_shoes_sub.write(fout)