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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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
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)
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)
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)
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)
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
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)
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)
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)