Archipelago/worlds/smw/Rom.py

976 lines
51 KiB
Python
Raw Normal View History

import Utils
from worlds.Files import APDeltaPatch
from .Aesthetics import generate_shuffled_header_data, generate_shuffled_ow_palettes
from .Levels import level_info_dict, full_bowser_rooms, standard_bowser_rooms, submap_boss_rooms, ow_boss_rooms
from .Names.TextBox import generate_goal_text, title_text_mapping, generate_text_box
USHASH = 'cdd3c8c37322978ca8669b34bc89c804'
ROM_PLAYER_LIMIT = 65535
import hashlib
import os
import math
ability_rom_data = {
0xBC0003: [[0x1F2C, 0x7]], # Run 0x80
0xBC0004: [[0x1F2C, 0x6]], # Carry 0x40
0xBC0005: [[0x1F2C, 0x2]], # Swim 0x04
0xBC0006: [[0x1F2C, 0x3]], # Spin Jump 0x08
0xBC0007: [[0x1F2C, 0x5]], # Climb 0x20
0xBC0008: [[0x1F2C, 0x1]], # Yoshi 0x02
0xBC0009: [[0x1F2C, 0x4]], # P-Switch 0x10
#0xBC000A: [[]]
0xBC000B: [[0x1F2D, 0x3]], # P-Balloon 0x08
0xBC000D: [[0x1F2D, 0x4]], # Super Star 0x10
}
item_rom_data = {
0xBC0001: [0x18E4, 0x1], # 1-Up Mushroom
0xBC0002: [0x1F24, 0x1, 0x1F], # Yoshi Egg
0xBC0012: [0x1F26, 0x1, 0x09], # Boss Token
0xBC000E: [0x1F28, 0x1, 0x1C], # Yellow Switch Palace
0xBC000F: [0x1F27, 0x1, 0x1C], # Green Switch Palace
0xBC0010: [0x1F2A, 0x1, 0x1C], # Red Switch Palace
0xBC0011: [0x1F29, 0x1, 0x1C], # Blue Switch Palace
}
trap_rom_data = {
0xBC0013: [0x0086, 0x1, 0x0E], # Ice Trap
0xBC0014: [0x18BD, 0x7F, 0x18], # Stun Trap
0xBC0016: [0x0F31, 0x1], # Timer Trap
}
class SMWDeltaPatch(APDeltaPatch):
hash = USHASH
game = "Super Mario World"
patch_file_ending = ".apsmw"
@classmethod
def get_source_data(cls) -> bytes:
return get_base_rom_bytes()
class LocalRom:
def __init__(self, file, patch=True, vanillaRom=None, name=None, hash=None):
self.name = name
self.hash = hash
self.orig_buffer = None
with open(file, 'rb') as stream:
self.buffer = Utils.read_snes_rom(stream)
def read_bit(self, address: int, bit_number: int) -> bool:
bitflag = (1 << bit_number)
return ((self.buffer[address] & bitflag) != 0)
def read_byte(self, address: int) -> int:
return self.buffer[address]
def read_bytes(self, startaddress: int, length: int) -> bytes:
return self.buffer[startaddress:startaddress + length]
def write_byte(self, address: int, value: int):
self.buffer[address] = value
def write_bytes(self, startaddress: int, values):
self.buffer[startaddress:startaddress + len(values)] = values
def write_to_file(self, file):
with open(file, 'wb') as outfile:
outfile.write(self.buffer)
def read_from_file(self, file):
with open(file, 'rb') as stream:
self.buffer = bytearray(stream.read())
def handle_ability_code(rom):
# Lock Abilities
#rom.write_byte(0xC581, 0x01) # No Stars
#rom.write_byte(0x62E6, 0x01) # No Star Music
#rom.write_byte(0xC300, 0x01) # No P-Balloons
#rom.write_byte(0xC305, 0x01) # No P-Balloons
# Run
rom.write_bytes(0x5977, bytearray([0x22, 0x10, 0xBA, 0x03])) # JSL $03BA10
rom.write_bytes(0x597B, bytearray([0xEA] * 0x04))
RUN_SUB_ADDR = 0x01BA10
rom.write_bytes(RUN_SUB_ADDR + 0x00, bytearray([0xDA])) # PHX
rom.write_bytes(RUN_SUB_ADDR + 0x01, bytearray([0x08])) # PHP
rom.write_bytes(RUN_SUB_ADDR + 0x02, bytearray([0x90, 0x03])) # BCC +0x03
rom.write_bytes(RUN_SUB_ADDR + 0x04, bytearray([0xC8])) # INY
rom.write_bytes(RUN_SUB_ADDR + 0x05, bytearray([0xA9, 0x70])) # LDA #70
rom.write_bytes(RUN_SUB_ADDR + 0x07, bytearray([0xAA])) # TAX
rom.write_bytes(RUN_SUB_ADDR + 0x08, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C
rom.write_bytes(RUN_SUB_ADDR + 0x0B, bytearray([0x89, 0x80])) # BIT #80
rom.write_bytes(RUN_SUB_ADDR + 0x0D, bytearray([0xF0, 0x04])) # BEQ +0x04
rom.write_bytes(RUN_SUB_ADDR + 0x0F, bytearray([0x8A])) # TXA
rom.write_bytes(RUN_SUB_ADDR + 0x10, bytearray([0x8D, 0xE4, 0x13])) # STA $13E4
rom.write_bytes(RUN_SUB_ADDR + 0x13, bytearray([0x8A])) # TXA
rom.write_bytes(RUN_SUB_ADDR + 0x14, bytearray([0x28])) # PLP
rom.write_bytes(RUN_SUB_ADDR + 0x15, bytearray([0xFA])) # PLX
rom.write_bytes(RUN_SUB_ADDR + 0x16, bytearray([0x6B])) # RTL
# End Run
# Purple Block Carry
rom.write_bytes(0x726F, bytearray([0x22, 0x28, 0xBA, 0x03])) # JSL $03BA28
rom.write_bytes(0x7273, bytearray([0xEA] * 0x02))
PURPLE_BLOCK_CARRY_SUB_ADDR = 0x01BA28
rom.write_bytes(PURPLE_BLOCK_CARRY_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
rom.write_bytes(PURPLE_BLOCK_CARRY_SUB_ADDR + 0x01, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C
rom.write_bytes(PURPLE_BLOCK_CARRY_SUB_ADDR + 0x04, bytearray([0x89, 0x40])) # BIT #40
rom.write_bytes(PURPLE_BLOCK_CARRY_SUB_ADDR + 0x06, bytearray([0xF0, 0x09])) # BEQ +0x09
rom.write_bytes(PURPLE_BLOCK_CARRY_SUB_ADDR + 0x08, bytearray([0x28])) # PLP
rom.write_bytes(PURPLE_BLOCK_CARRY_SUB_ADDR + 0x09, bytearray([0xAD, 0x8F, 0x14])) # LDA $148F
rom.write_bytes(PURPLE_BLOCK_CARRY_SUB_ADDR + 0x0C, bytearray([0x0D, 0x7A, 0x18])) # ORA $187A
rom.write_bytes(PURPLE_BLOCK_CARRY_SUB_ADDR + 0x0F, bytearray([0x80, 0x03])) # BRA +0x03
rom.write_bytes(PURPLE_BLOCK_CARRY_SUB_ADDR + 0x11, bytearray([0x28])) # PLP
rom.write_bytes(PURPLE_BLOCK_CARRY_SUB_ADDR + 0x12, bytearray([0xA9, 0x01])) # LDA #01
rom.write_bytes(PURPLE_BLOCK_CARRY_SUB_ADDR + 0x14, bytearray([0x6B])) # RTL
# End Purple Block Carry
# Springboard Carry
rom.write_bytes(0xE6DA, bytearray([0x22, 0x40, 0xBA, 0x03])) # JSL $03BA40
rom.write_bytes(0xE6DE, bytearray([0xEA] * 0x04))
SPRINGBOARD_CARRY_SUB_ADDR = 0x01BA40
rom.write_bytes(SPRINGBOARD_CARRY_SUB_ADDR + 0x00, bytearray([0x48])) # PHA
rom.write_bytes(SPRINGBOARD_CARRY_SUB_ADDR + 0x01, bytearray([0x08])) # PHP
rom.write_bytes(SPRINGBOARD_CARRY_SUB_ADDR + 0x02, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C
rom.write_bytes(SPRINGBOARD_CARRY_SUB_ADDR + 0x05, bytearray([0x89, 0x40])) # BIT #40
rom.write_bytes(SPRINGBOARD_CARRY_SUB_ADDR + 0x07, bytearray([0xF0, 0x08])) # BEQ +0x08
rom.write_bytes(SPRINGBOARD_CARRY_SUB_ADDR + 0x09, bytearray([0xA9, 0x0B])) # LDA #0B
rom.write_bytes(SPRINGBOARD_CARRY_SUB_ADDR + 0x0B, bytearray([0x9D, 0xC8, 0x14])) # STA $14C8, X
rom.write_bytes(SPRINGBOARD_CARRY_SUB_ADDR + 0x0E, bytearray([0x9E, 0x02, 0x16])) # STZ $1602, X
rom.write_bytes(SPRINGBOARD_CARRY_SUB_ADDR + 0x11, bytearray([0x28])) # PLP
rom.write_bytes(SPRINGBOARD_CARRY_SUB_ADDR + 0x12, bytearray([0x68])) # PLA
rom.write_bytes(SPRINGBOARD_CARRY_SUB_ADDR + 0x13, bytearray([0x6B])) # RTL
# End Springboard Carry
# Shell Carry
rom.write_bytes(0xAA66, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C
rom.write_bytes(0xAA69, bytearray([0x89, 0x40])) # BIT #40
rom.write_bytes(0xAA6B, bytearray([0xF0, 0x07])) # BEQ +0x07
rom.write_bytes(0xAA6D, bytearray([0x22, 0x60, 0xBA, 0x03])) # JSL $03BA60
rom.write_bytes(0xAA71, bytearray([0xEA] * 0x02))
SHELL_CARRY_SUB_ADDR = 0x01BA60
rom.write_bytes(SHELL_CARRY_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
rom.write_bytes(SHELL_CARRY_SUB_ADDR + 0x01, bytearray([0xA9, 0x0B])) # LDA #0B
rom.write_bytes(SHELL_CARRY_SUB_ADDR + 0x03, bytearray([0x9D, 0xC8, 0x14])) # STA $14C8, X
rom.write_bytes(SHELL_CARRY_SUB_ADDR + 0x06, bytearray([0xEE, 0x70, 0x14])) # INC $1470
rom.write_bytes(SHELL_CARRY_SUB_ADDR + 0x09, bytearray([0xA9, 0x0B])) # LDA #08
rom.write_bytes(SHELL_CARRY_SUB_ADDR + 0x0B, bytearray([0x8D, 0x98, 0x14])) # STA $1498
rom.write_bytes(SHELL_CARRY_SUB_ADDR + 0x0E, bytearray([0x28])) # PLP
rom.write_bytes(SHELL_CARRY_SUB_ADDR + 0x0F, bytearray([0x6B])) # RTL
# End Shell Carry
# Yoshi Carry
rom.write_bytes(0xF309, bytearray([0x22, 0x70, 0xBA, 0x03])) # JSL $03BA70
rom.write_bytes(0xF30D, bytearray([0xEA] * 0x06))
YOSHI_CARRY_SUB_ADDR = 0x01BA70
rom.write_bytes(YOSHI_CARRY_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
rom.write_bytes(YOSHI_CARRY_SUB_ADDR + 0x01, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C
rom.write_bytes(YOSHI_CARRY_SUB_ADDR + 0x04, bytearray([0x89, 0x40])) # BIT #40
rom.write_bytes(YOSHI_CARRY_SUB_ADDR + 0x06, bytearray([0xF0, 0x0A])) # BEQ +0x0A
rom.write_bytes(YOSHI_CARRY_SUB_ADDR + 0x08, bytearray([0xA9, 0x12])) # LDA #12
rom.write_bytes(YOSHI_CARRY_SUB_ADDR + 0x0A, bytearray([0x8D, 0xA3, 0x14])) # STA $14A3
rom.write_bytes(YOSHI_CARRY_SUB_ADDR + 0x0D, bytearray([0xA9, 0x21])) # LDA #21
rom.write_bytes(YOSHI_CARRY_SUB_ADDR + 0x0F, bytearray([0x8D, 0xFC, 0x1D])) # STA $1DFC
rom.write_bytes(YOSHI_CARRY_SUB_ADDR + 0x12, bytearray([0x28])) # PLP
rom.write_bytes(YOSHI_CARRY_SUB_ADDR + 0x13, bytearray([0x6B])) # RTL
# End Yoshi Carry
# Climb
rom.write_bytes(0x4D72, bytearray([0x5C, 0x88, 0xBA, 0x03])) # JML $03BA88
rom.write_bytes(0x4D76, bytearray([0xEA] * 0x03))
CLIMB_SUB_ADDR = 0x01BA88
rom.write_bytes(CLIMB_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
rom.write_bytes(CLIMB_SUB_ADDR + 0x01, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C
rom.write_bytes(CLIMB_SUB_ADDR + 0x04, bytearray([0x89, 0x20])) # BIT #20
rom.write_bytes(CLIMB_SUB_ADDR + 0x06, bytearray([0xF0, 0x09])) # BEQ +0x09
rom.write_bytes(CLIMB_SUB_ADDR + 0x08, bytearray([0xA5, 0x8B])) # LDA $8B
rom.write_bytes(CLIMB_SUB_ADDR + 0x0A, bytearray([0x85, 0x74])) # STA $74
rom.write_bytes(CLIMB_SUB_ADDR + 0x0C, bytearray([0x28])) # PLP
rom.write_bytes(CLIMB_SUB_ADDR + 0x0D, bytearray([0x5C, 0x17, 0xDB, 0x00])) # JML $00DB17
rom.write_bytes(CLIMB_SUB_ADDR + 0x11, bytearray([0x28])) # PLP
rom.write_bytes(CLIMB_SUB_ADDR + 0x12, bytearray([0x5C, 0x76, 0xCD, 0x00])) # JML $00CD76
# End Climb
# Climb Rope
rom.write_bytes(0xDA33, bytearray([0x22, 0x70, 0xBC, 0x03])) # JSL $03BC70
CLIMB_ROPE_SUB_ADDR = 0x01BC70
rom.write_bytes(CLIMB_ROPE_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
rom.write_bytes(CLIMB_ROPE_SUB_ADDR + 0x01, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C
rom.write_bytes(CLIMB_ROPE_SUB_ADDR + 0x04, bytearray([0x89, 0x20])) # BIT #20
rom.write_bytes(CLIMB_ROPE_SUB_ADDR + 0x06, bytearray([0xF0, 0x07])) # BEQ +0x07
rom.write_bytes(CLIMB_ROPE_SUB_ADDR + 0x08, bytearray([0x28])) # PLP
rom.write_bytes(CLIMB_ROPE_SUB_ADDR + 0x09, bytearray([0xA9, 0xB0])) # LDA #B0
rom.write_bytes(CLIMB_ROPE_SUB_ADDR + 0x0B, bytearray([0x85, 0x7D])) # STA $7D
rom.write_bytes(CLIMB_ROPE_SUB_ADDR + 0x0D, bytearray([0x80, 0x01])) # BRA +0x01
rom.write_bytes(CLIMB_ROPE_SUB_ADDR + 0x0F, bytearray([0x28])) # PLP
rom.write_bytes(CLIMB_ROPE_SUB_ADDR + 0x10, bytearray([0x6B])) # RTL
# End Climb Rope
# P-Switch
rom.write_bytes(0xAB1A, bytearray([0x22, 0xA0, 0xBA, 0x03])) # JSL $03BAA0
rom.write_bytes(0xAB1E, bytearray([0xEA] * 0x01))
P_SWITCH_SUB_ADDR = 0x01BAA0
rom.write_bytes(P_SWITCH_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
rom.write_bytes(P_SWITCH_SUB_ADDR + 0x01, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C
rom.write_bytes(P_SWITCH_SUB_ADDR + 0x04, bytearray([0x89, 0x10])) # BIT #10
rom.write_bytes(P_SWITCH_SUB_ADDR + 0x06, bytearray([0xF0, 0x04])) # BEQ +0x04
rom.write_bytes(P_SWITCH_SUB_ADDR + 0x08, bytearray([0xA9, 0xB0])) # LDA #B0
rom.write_bytes(P_SWITCH_SUB_ADDR + 0x0A, bytearray([0x80, 0x02])) # BRA +0x02
rom.write_bytes(P_SWITCH_SUB_ADDR + 0x0C, bytearray([0xA9, 0x01])) # LDA #01
rom.write_bytes(P_SWITCH_SUB_ADDR + 0x0E, bytearray([0x99, 0xAD, 0x14])) # STA $14AD
rom.write_bytes(P_SWITCH_SUB_ADDR + 0x11, bytearray([0x28])) # PLP
rom.write_bytes(P_SWITCH_SUB_ADDR + 0x12, bytearray([0x6B])) # RTL
# End P-Switch
# Spin Jump
rom.write_bytes(0x5645, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C
rom.write_bytes(0x5648, bytearray([0x89, 0x08])) # BIT #08
rom.write_bytes(0x564A, bytearray([0xF0, 0x12])) # BEQ +0x12
rom.write_bytes(0x564C, bytearray([0x22, 0xB8, 0xBA, 0x03])) # JSL $03BAB8
SPIN_JUMP_SUB_ADDR = 0x01BAB8
rom.write_bytes(SPIN_JUMP_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
rom.write_bytes(SPIN_JUMP_SUB_ADDR + 0x01, bytearray([0x1A])) # INC
rom.write_bytes(SPIN_JUMP_SUB_ADDR + 0x02, bytearray([0x8D, 0x0D, 0x14])) # STA $140D
rom.write_bytes(SPIN_JUMP_SUB_ADDR + 0x05, bytearray([0xA9, 0x04])) # LDA #04
rom.write_bytes(SPIN_JUMP_SUB_ADDR + 0x07, bytearray([0x8D, 0xFC, 0x1D])) # STA $1DFC
rom.write_bytes(SPIN_JUMP_SUB_ADDR + 0x0A, bytearray([0xA4, 0x76])) # LDY #76
rom.write_bytes(SPIN_JUMP_SUB_ADDR + 0x0C, bytearray([0x28])) # PLP
rom.write_bytes(SPIN_JUMP_SUB_ADDR + 0x0D, bytearray([0x6B])) # RTL
# End Spin Jump
# Spin Jump from Water
rom.write_bytes(0x6A89, bytearray([0x22, 0xF8, 0xBB, 0x03])) # JSL $03BBF8
rom.write_bytes(0x6A8D, bytearray([0xEA] * 0x05))
SPIN_JUMP_WATER_SUB_ADDR = 0x01BBF8
rom.write_bytes(SPIN_JUMP_WATER_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
rom.write_bytes(SPIN_JUMP_WATER_SUB_ADDR + 0x01, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C
rom.write_bytes(SPIN_JUMP_WATER_SUB_ADDR + 0x04, bytearray([0x89, 0x08])) # BIT #08
rom.write_bytes(SPIN_JUMP_WATER_SUB_ADDR + 0x06, bytearray([0xF0, 0x09])) # BEQ +0x09
rom.write_bytes(SPIN_JUMP_WATER_SUB_ADDR + 0x08, bytearray([0x1A])) # INC
rom.write_bytes(SPIN_JUMP_WATER_SUB_ADDR + 0x09, bytearray([0x8D, 0x0D, 0x14])) # STA $140D
rom.write_bytes(SPIN_JUMP_WATER_SUB_ADDR + 0x0C, bytearray([0xA9, 0x04])) # LDA #04
rom.write_bytes(SPIN_JUMP_WATER_SUB_ADDR + 0x0E, bytearray([0x8D, 0xFC, 0x1D])) # STA $1DFC
rom.write_bytes(SPIN_JUMP_WATER_SUB_ADDR + 0x11, bytearray([0x28])) # PLP
rom.write_bytes(SPIN_JUMP_WATER_SUB_ADDR + 0x12, bytearray([0x6B])) # RTL
# End Spin Jump from Water
# Spin Jump from Springboard
rom.write_bytes(0xE693, bytearray([0x22, 0x0C, 0xBC, 0x03])) # JSL $03BC0C
rom.write_bytes(0xE697, bytearray([0xEA] * 0x01))
SPIN_JUMP_SPRING_SUB_ADDR = 0x01BC0C
rom.write_bytes(SPIN_JUMP_SPRING_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
rom.write_bytes(SPIN_JUMP_SPRING_SUB_ADDR + 0x01, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C
rom.write_bytes(SPIN_JUMP_SPRING_SUB_ADDR + 0x04, bytearray([0x89, 0x08])) # BIT #08
rom.write_bytes(SPIN_JUMP_SPRING_SUB_ADDR + 0x06, bytearray([0xF0, 0x05])) # BEQ +0x05
rom.write_bytes(SPIN_JUMP_SPRING_SUB_ADDR + 0x08, bytearray([0xA9, 0x01])) # LDA #01
rom.write_bytes(SPIN_JUMP_SPRING_SUB_ADDR + 0x0A, bytearray([0x8D, 0x0D, 0x14])) # STA $140D
rom.write_bytes(SPIN_JUMP_SPRING_SUB_ADDR + 0x0D, bytearray([0x28])) # PLP
rom.write_bytes(SPIN_JUMP_SPRING_SUB_ADDR + 0x0E, bytearray([0x6B])) # RTL
# End Spin Jump from Springboard
# Swim
rom.write_bytes(0x5A25, bytearray([0x22, 0xC8, 0xBA, 0x03])) # JSL $03BAC8
rom.write_bytes(0x5A29, bytearray([0xEA] * 0x04))
SWIM_SUB_ADDR = 0x01BAC8
rom.write_bytes(SWIM_SUB_ADDR + 0x00, bytearray([0x48])) # PHA
rom.write_bytes(SWIM_SUB_ADDR + 0x01, bytearray([0x08])) # PHP
rom.write_bytes(SWIM_SUB_ADDR + 0x02, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C
rom.write_bytes(SWIM_SUB_ADDR + 0x05, bytearray([0x89, 0x04])) # BIT #04
rom.write_bytes(SWIM_SUB_ADDR + 0x07, bytearray([0xF0, 0x0C])) # BEQ +0x0C
rom.write_bytes(SWIM_SUB_ADDR + 0x09, bytearray([0x28])) # PLP
rom.write_bytes(SWIM_SUB_ADDR + 0x0A, bytearray([0x68])) # PLA
rom.write_bytes(SWIM_SUB_ADDR + 0x0B, bytearray([0xDD, 0x84, 0xD9])) # CMP $D489, X
rom.write_bytes(SWIM_SUB_ADDR + 0x0E, bytearray([0xB0, 0x03])) # BCS +0x03
rom.write_bytes(SWIM_SUB_ADDR + 0x10, bytearray([0xBD, 0x84, 0xD9])) # LDA $D489, X
rom.write_bytes(SWIM_SUB_ADDR + 0x13, bytearray([0x80, 0x0A])) # BRA +0x0A
rom.write_bytes(SWIM_SUB_ADDR + 0x15, bytearray([0x28])) # PLP
rom.write_bytes(SWIM_SUB_ADDR + 0x16, bytearray([0x68])) # PLA
rom.write_bytes(SWIM_SUB_ADDR + 0x17, bytearray([0xDD, 0xBE, 0xDE])) # CMP $DEBE, X
rom.write_bytes(SWIM_SUB_ADDR + 0x1A, bytearray([0xB0, 0x03])) # BCS +0x03
rom.write_bytes(SWIM_SUB_ADDR + 0x1C, bytearray([0xBD, 0xBE, 0xDE])) # LDA $DEBE, X
rom.write_bytes(SWIM_SUB_ADDR + 0x1F, bytearray([0x6B])) # RTL
# End Swim
# Item Swim
rom.write_bytes(0x59D7, bytearray([0x22, 0xE8, 0xBA, 0x03])) # JSL $03BAE8
rom.write_bytes(0x59DB, bytearray([0xEA] * 0x02))
SWIM_SUB_ADDR = 0x01BAE8
rom.write_bytes(SWIM_SUB_ADDR + 0x00, bytearray([0x48])) # PHA
rom.write_bytes(SWIM_SUB_ADDR + 0x01, bytearray([0x08])) # PHP
rom.write_bytes(SWIM_SUB_ADDR + 0x02, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C
rom.write_bytes(SWIM_SUB_ADDR + 0x05, bytearray([0x89, 0x04])) # BIT #04
rom.write_bytes(SWIM_SUB_ADDR + 0x07, bytearray([0xF0, 0x0A])) # BEQ +0x0A
rom.write_bytes(SWIM_SUB_ADDR + 0x09, bytearray([0x28])) # PLP
rom.write_bytes(SWIM_SUB_ADDR + 0x0A, bytearray([0x68])) # PLA
rom.write_bytes(SWIM_SUB_ADDR + 0x0B, bytearray([0xC9, 0xF0])) # CMP #F0
rom.write_bytes(SWIM_SUB_ADDR + 0x0D, bytearray([0xB0, 0x02])) # BCS +0x02
rom.write_bytes(SWIM_SUB_ADDR + 0x0F, bytearray([0xA9, 0xF0])) # LDA #F0
rom.write_bytes(SWIM_SUB_ADDR + 0x11, bytearray([0x80, 0x08])) # BRA +0x08
rom.write_bytes(SWIM_SUB_ADDR + 0x13, bytearray([0x28])) # PLP
rom.write_bytes(SWIM_SUB_ADDR + 0x14, bytearray([0x68])) # PLA
rom.write_bytes(SWIM_SUB_ADDR + 0x15, bytearray([0xC9, 0xFF])) # CMP #FF
rom.write_bytes(SWIM_SUB_ADDR + 0x17, bytearray([0xB0, 0x02])) # BCS +0x02
rom.write_bytes(SWIM_SUB_ADDR + 0x19, bytearray([0xA9, 0x00])) # LDA #00
rom.write_bytes(SWIM_SUB_ADDR + 0x1B, bytearray([0x6B])) # RTL
# End Item Swim
# Yoshi
rom.write_bytes(0x109FB, bytearray([0x22, 0x08, 0xBB, 0x03])) # JSL $03BB08
rom.write_bytes(0x109FF, bytearray([0xEA] * 0x02))
YOSHI_SUB_ADDR = 0x01BB08
rom.write_bytes(YOSHI_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
rom.write_bytes(YOSHI_SUB_ADDR + 0x01, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C
rom.write_bytes(YOSHI_SUB_ADDR + 0x04, bytearray([0x89, 0x02])) # BIT #02
rom.write_bytes(YOSHI_SUB_ADDR + 0x06, bytearray([0xF0, 0x06])) # BEQ +0x06
rom.write_bytes(YOSHI_SUB_ADDR + 0x08, bytearray([0x28])) # PLP
rom.write_bytes(YOSHI_SUB_ADDR + 0x09, bytearray([0xB9, 0xA1, 0x88])) # LDA $88A1, Y
rom.write_bytes(YOSHI_SUB_ADDR + 0x0C, bytearray([0x80, 0x04])) # BRA +0x04
rom.write_bytes(YOSHI_SUB_ADDR + 0x0E, bytearray([0x28])) # PLP
rom.write_bytes(YOSHI_SUB_ADDR + 0x0F, bytearray([0xB9, 0xA2, 0x88])) # LDA $88A2, Y
rom.write_bytes(YOSHI_SUB_ADDR + 0x12, bytearray([0x9D, 0x1C, 0x15])) # STA $151C, X
rom.write_bytes(YOSHI_SUB_ADDR + 0x15, bytearray([0x6B])) # RTL
# End Yoshi
# Baby Yoshi
rom.write_bytes(0xA2B8, bytearray([0x22, 0x20, 0xBB, 0x03])) # JSL $03BB20
rom.write_bytes(0xA2BC, bytearray([0xEA] * 0x01))
rom.write_bytes(0x1C05F, bytearray([0x22, 0x20, 0xBB, 0x03])) # JSL $03BB20
rom.write_bytes(0x1C063, bytearray([0xEA] * 0x01))
YOSHI_SUB_ADDR = 0x01BB20
rom.write_bytes(YOSHI_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
rom.write_bytes(YOSHI_SUB_ADDR + 0x01, bytearray([0x9C, 0x1E, 0x14])) # STZ $141E
rom.write_bytes(YOSHI_SUB_ADDR + 0x04, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C
rom.write_bytes(YOSHI_SUB_ADDR + 0x07, bytearray([0x89, 0x02])) # BIT #02
rom.write_bytes(YOSHI_SUB_ADDR + 0x09, bytearray([0xF0, 0x05])) # BEQ +0x05
rom.write_bytes(YOSHI_SUB_ADDR + 0x0B, bytearray([0x28])) # PLP
rom.write_bytes(YOSHI_SUB_ADDR + 0x0C, bytearray([0xA9, 0x35])) # LDA #35
rom.write_bytes(YOSHI_SUB_ADDR + 0x0E, bytearray([0x80, 0x03])) # BRA +0x03
rom.write_bytes(YOSHI_SUB_ADDR + 0x10, bytearray([0x28])) # PLP
rom.write_bytes(YOSHI_SUB_ADDR + 0x11, bytearray([0xA9, 0x70])) # LDA #70
rom.write_bytes(YOSHI_SUB_ADDR + 0x13, bytearray([0x6B])) # RTL
# End Baby Yoshi
# Midway Gate
rom.write_bytes(0x72E4, bytearray([0x22, 0x38, 0xBB, 0x03])) # JSL $03BB38
MIDWAY_GATE_SUB_ADDR = 0x01BB38
rom.write_bytes(MIDWAY_GATE_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
rom.write_bytes(MIDWAY_GATE_SUB_ADDR + 0x01, bytearray([0xAD, 0x2D, 0x1F])) # LDA $1F2D
rom.write_bytes(MIDWAY_GATE_SUB_ADDR + 0x04, bytearray([0x89, 0x01])) # BIT #01
rom.write_bytes(MIDWAY_GATE_SUB_ADDR + 0x06, bytearray([0xF0, 0x07])) # BEQ +0x07
rom.write_bytes(MIDWAY_GATE_SUB_ADDR + 0x08, bytearray([0x28])) # PLP
rom.write_bytes(MIDWAY_GATE_SUB_ADDR + 0x09, bytearray([0xA9, 0x01])) # LDA #01
rom.write_bytes(MIDWAY_GATE_SUB_ADDR + 0x0B, bytearray([0x85, 0x19])) # STA $19
rom.write_bytes(MIDWAY_GATE_SUB_ADDR + 0x0D, bytearray([0x80, 0x01])) # BRA +0x01
rom.write_bytes(MIDWAY_GATE_SUB_ADDR + 0x0F, bytearray([0x28])) # PLP
rom.write_bytes(MIDWAY_GATE_SUB_ADDR + 0x10, bytearray([0x6B])) # RTL
# End Midway Gate
# Mushroom
rom.write_bytes(0x5156, bytearray([0x22, 0x50, 0xBB, 0x03])) # JSL $03BB50
rom.write_bytes(0x515A, bytearray([0xEA] * 0x04))
MUSHROOM_SUB_ADDR = 0x01BB50
rom.write_bytes(MUSHROOM_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
rom.write_bytes(MUSHROOM_SUB_ADDR + 0x01, bytearray([0xAD, 0x2D, 0x1F])) # LDA $1F2D
rom.write_bytes(MUSHROOM_SUB_ADDR + 0x04, bytearray([0x89, 0x01])) # BIT #01
rom.write_bytes(MUSHROOM_SUB_ADDR + 0x06, bytearray([0xF0, 0x05])) # BEQ +0x05
rom.write_bytes(MUSHROOM_SUB_ADDR + 0x08, bytearray([0x28])) # PLP
rom.write_bytes(MUSHROOM_SUB_ADDR + 0x09, bytearray([0xE6, 0x19])) # INC $19
rom.write_bytes(MUSHROOM_SUB_ADDR + 0x0B, bytearray([0x80, 0x01])) # BRA +0x01
rom.write_bytes(MUSHROOM_SUB_ADDR + 0x0D, bytearray([0x28])) # PLP
rom.write_bytes(MUSHROOM_SUB_ADDR + 0x0E, bytearray([0xA9, 0x00])) # LDA #00
rom.write_bytes(MUSHROOM_SUB_ADDR + 0x10, bytearray([0x85, 0x71])) # STA $72
rom.write_bytes(MUSHROOM_SUB_ADDR + 0x12, bytearray([0x64, 0x9D])) # STZ $9D
rom.write_bytes(MUSHROOM_SUB_ADDR + 0x14, bytearray([0x6B])) # RTL
# End Mushroom
# Take Damage
rom.write_bytes(0x5142, bytearray([0x22, 0x65, 0xBB, 0x03])) # JSL $03BB65
rom.write_bytes(0x5146, bytearray([0x60] * 0x01)) # RTS
DAMAGE_SUB_ADDR = 0x01BB65
rom.write_bytes(DAMAGE_SUB_ADDR + 0x00, bytearray([0x8D, 0x97, 0x14])) # STA $1497
rom.write_bytes(DAMAGE_SUB_ADDR + 0x03, bytearray([0x80, 0xF4])) # BRA -0x0C
# End Take Damage
# Fire Flower Cycle
rom.write_bytes(0x5187, bytearray([0x22, 0x6A, 0xBB, 0x03])) # JSL $03BB6A
rom.write_bytes(0x518B, bytearray([0x60] * 0x01)) # RTS
PALETTE_CYCLE_SUB_ADDR = 0x01BB6A
rom.write_bytes(PALETTE_CYCLE_SUB_ADDR + 0x00, bytearray([0xCE, 0x9B, 0x14])) # DEC $149B
rom.write_bytes(PALETTE_CYCLE_SUB_ADDR + 0x03, bytearray([0xF0, 0xEF])) # BEQ -0x11
rom.write_bytes(PALETTE_CYCLE_SUB_ADDR + 0x05, bytearray([0x6B])) # RTL
# End Fire Flower Cycle
# Pipe Exit
rom.write_bytes(0x526D, bytearray([0x22, 0x70, 0xBB, 0x03])) # JSL $03BB70
rom.write_bytes(0x5271, bytearray([0x60, 0xEA] * 0x01)) # RTS, NOP
PIPE_EXIT_SUB_ADDR = 0x01BB70
rom.write_bytes(PIPE_EXIT_SUB_ADDR + 0x00, bytearray([0x9C, 0x19, 0x14])) # STZ $1419
rom.write_bytes(PIPE_EXIT_SUB_ADDR + 0x03, bytearray([0xA9, 0x00])) # LDA #00
rom.write_bytes(PIPE_EXIT_SUB_ADDR + 0x05, bytearray([0x85, 0x71])) # STA $72
rom.write_bytes(PIPE_EXIT_SUB_ADDR + 0x07, bytearray([0x64, 0x9D])) # STZ $9D
rom.write_bytes(PIPE_EXIT_SUB_ADDR + 0x09, bytearray([0x6B])) # RTL
# End Pipe Exit
# Cape Transform
rom.write_bytes(0x5168, bytearray([0x22, 0x7A, 0xBB, 0x03])) # JSL $03BB7A
rom.write_bytes(0x516C, bytearray([0xEA] * 0x01)) # RTS, NOP
rom.write_bytes(0x516D, bytearray([0xF0, 0xD1])) # BEQ -0x2F
CAPE_TRANSFORM_SUB_ADDR = 0x01BB7A
rom.write_bytes(CAPE_TRANSFORM_SUB_ADDR + 0x00, bytearray([0xA5, 0x19])) # LDA $19
rom.write_bytes(CAPE_TRANSFORM_SUB_ADDR + 0x02, bytearray([0x4A])) # LSR
rom.write_bytes(CAPE_TRANSFORM_SUB_ADDR + 0x03, bytearray([0xD0, 0xDF])) # BNE -0x21
rom.write_bytes(CAPE_TRANSFORM_SUB_ADDR + 0x05, bytearray([0x6B])) # RTL
# End Cape Transform
# Fire Flower
rom.write_bytes(0xC5F7, bytearray([0x22, 0x80, 0xBB, 0x03])) # JSL $03BB80
FIRE_FLOWER_SUB_ADDR = 0x01BB80
rom.write_bytes(FIRE_FLOWER_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
rom.write_bytes(FIRE_FLOWER_SUB_ADDR + 0x01, bytearray([0xAD, 0x2D, 0x1F])) # LDA $1F2D
rom.write_bytes(FIRE_FLOWER_SUB_ADDR + 0x04, bytearray([0x89, 0x02])) # BIT #02
rom.write_bytes(FIRE_FLOWER_SUB_ADDR + 0x06, bytearray([0xF0, 0x07])) # BEQ +0x07
rom.write_bytes(FIRE_FLOWER_SUB_ADDR + 0x08, bytearray([0x28])) # PLP
rom.write_bytes(FIRE_FLOWER_SUB_ADDR + 0x09, bytearray([0xA9, 0x03])) # LDA #03
rom.write_bytes(FIRE_FLOWER_SUB_ADDR + 0x0B, bytearray([0x85, 0x19])) # STA $19
rom.write_bytes(FIRE_FLOWER_SUB_ADDR + 0x0D, bytearray([0x80, 0x01])) # BRA +0x01
rom.write_bytes(FIRE_FLOWER_SUB_ADDR + 0x0F, bytearray([0x28])) # PLP
rom.write_bytes(FIRE_FLOWER_SUB_ADDR + 0x10, bytearray([0x6B])) # RTL
# End Fire Flower
# Cape
rom.write_bytes(0xC598, bytearray([0x22, 0x91, 0xBB, 0x03])) # JSL $03BB91
CAPE_SUB_ADDR = 0x01BB91
rom.write_bytes(CAPE_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
rom.write_bytes(CAPE_SUB_ADDR + 0x01, bytearray([0xAD, 0x2D, 0x1F])) # LDA $1F2D
rom.write_bytes(CAPE_SUB_ADDR + 0x04, bytearray([0x89, 0x04])) # BIT #04
rom.write_bytes(CAPE_SUB_ADDR + 0x06, bytearray([0xF0, 0x07])) # BEQ +0x07
rom.write_bytes(CAPE_SUB_ADDR + 0x08, bytearray([0x28])) # PLP
rom.write_bytes(CAPE_SUB_ADDR + 0x09, bytearray([0xA9, 0x02])) # LDA #02
rom.write_bytes(CAPE_SUB_ADDR + 0x0B, bytearray([0x85, 0x19])) # STA $19
rom.write_bytes(CAPE_SUB_ADDR + 0x0D, bytearray([0x80, 0x01])) # BRA +0x01
rom.write_bytes(CAPE_SUB_ADDR + 0x0F, bytearray([0x28])) # PLP
rom.write_bytes(CAPE_SUB_ADDR + 0x10, bytearray([0x6B])) # RTL
# End Cape
# P-Balloon
rom.write_bytes(0xC2FF, bytearray([0x22, 0xA2, 0xBB, 0x03])) # JSL $03BBA2
rom.write_bytes(0xC303, bytearray([0xEA] * 0x06))
P_BALLOON_SUB_ADDR = 0x01BBA2
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x01, bytearray([0xAD, 0x2D, 0x1F])) # LDA $1F2D
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x04, bytearray([0x89, 0x08])) # BIT #08
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x06, bytearray([0xF0, 0x0D])) # BEQ +0x0D
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x08, bytearray([0x28])) # PLP
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x09, bytearray([0xA9, 0x09])) # LDA #09
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x0B, bytearray([0x8D, 0xF3, 0x13])) # STA $13F3
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x0E, bytearray([0xA9, 0xFF])) # LDA #FF
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x10, bytearray([0x8D, 0x91, 0x18])) # STA $1891
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x13, bytearray([0x80, 0x0B])) # BRA +0x0B
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x15, bytearray([0x28])) # PLP
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x16, bytearray([0xA9, 0x01])) # LDA #01
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x18, bytearray([0x8D, 0xF3, 0x13])) # STA $13F3
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x1B, bytearray([0xA9, 0x01])) # LDA #01
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x1D, bytearray([0x8D, 0x91, 0x18])) # STA $1891
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x20, bytearray([0x6B])) # RTL
# End P-Balloon
# Star
rom.write_bytes(0xC580, bytearray([0x22, 0xC8, 0xBB, 0x03])) # JSL $03BBC8
rom.write_bytes(0xC584, bytearray([0xEA] * 0x01))
STAR_SUB_ADDR = 0x01BBC8
rom.write_bytes(STAR_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
rom.write_bytes(STAR_SUB_ADDR + 0x01, bytearray([0xAD, 0x2D, 0x1F])) # LDA $1F2D
rom.write_bytes(STAR_SUB_ADDR + 0x04, bytearray([0x89, 0x10])) # BIT #10
rom.write_bytes(STAR_SUB_ADDR + 0x06, bytearray([0xF0, 0x08])) # BEQ +0x08
rom.write_bytes(STAR_SUB_ADDR + 0x08, bytearray([0x28])) # PLP
rom.write_bytes(STAR_SUB_ADDR + 0x09, bytearray([0xA9, 0xFF])) # LDA #FF
rom.write_bytes(STAR_SUB_ADDR + 0x0B, bytearray([0x8D, 0x90, 0x14])) # STA $1490
rom.write_bytes(STAR_SUB_ADDR + 0x0E, bytearray([0x80, 0x06])) # BRA +0x06
rom.write_bytes(STAR_SUB_ADDR + 0x10, bytearray([0x28])) # PLP
rom.write_bytes(STAR_SUB_ADDR + 0x11, bytearray([0xA9, 0x01])) # LDA #01
rom.write_bytes(STAR_SUB_ADDR + 0x13, bytearray([0x8D, 0x90, 0x14])) # STA $1490
rom.write_bytes(STAR_SUB_ADDR + 0x16, bytearray([0x6B])) # RTL
# End Star
# Star Timer
rom.write_bytes(0x62E3, bytearray([0x22, 0xE0, 0xBB, 0x03])) # JSL $03BBE0
STAR_TIMER_SUB_ADDR = 0x01BBE0
rom.write_bytes(STAR_TIMER_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
rom.write_bytes(STAR_TIMER_SUB_ADDR + 0x01, bytearray([0xAD, 0x2D, 0x1F])) # LDA $1F2D
rom.write_bytes(STAR_TIMER_SUB_ADDR + 0x04, bytearray([0x89, 0x10])) # BIT #10
rom.write_bytes(STAR_TIMER_SUB_ADDR + 0x06, bytearray([0xF0, 0x07])) # BEQ +0x07
rom.write_bytes(STAR_TIMER_SUB_ADDR + 0x08, bytearray([0x28])) # PLP
rom.write_bytes(STAR_TIMER_SUB_ADDR + 0x09, bytearray([0xA5, 0x13])) # LDA $13
rom.write_bytes(STAR_TIMER_SUB_ADDR + 0x0B, bytearray([0xC0, 0x1E])) # CPY #1E
rom.write_bytes(STAR_TIMER_SUB_ADDR + 0x0D, bytearray([0x80, 0x05])) # BRA +0x05
rom.write_bytes(STAR_TIMER_SUB_ADDR + 0x0F, bytearray([0x28])) # PLP
rom.write_bytes(STAR_TIMER_SUB_ADDR + 0x10, bytearray([0xA5, 0x13])) # LDA $13
rom.write_bytes(STAR_TIMER_SUB_ADDR + 0x12, bytearray([0xC0, 0x01])) # CPY #01
rom.write_bytes(STAR_TIMER_SUB_ADDR + 0x14, bytearray([0x6B])) # RTL
# End Star Timer
return
def handle_yoshi_box(rom):
rom.write_bytes(0xEC3D, bytearray([0xEA] * 0x03)) # NOP Lines that cause Yoshi Rescue Box normally
rom.write_bytes(0x2B20F, bytearray([0x20, 0x60, 0xDC])) # JSR $05DC60
YOSHI_BOX_SUB_ADDR = 0x02DC60
rom.write_bytes(YOSHI_BOX_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
rom.write_bytes(YOSHI_BOX_SUB_ADDR + 0x01, bytearray([0xAD, 0x26, 0x14])) # LDA $1426
rom.write_bytes(YOSHI_BOX_SUB_ADDR + 0x04, bytearray([0xC9, 0x03])) # CMP #03
rom.write_bytes(YOSHI_BOX_SUB_ADDR + 0x06, bytearray([0xF0, 0x06])) # BEQ +0x06
rom.write_bytes(YOSHI_BOX_SUB_ADDR + 0x08, bytearray([0x28])) # PLP
rom.write_bytes(YOSHI_BOX_SUB_ADDR + 0x09, bytearray([0xB9, 0xD9, 0xA5])) # LDA $A5B9, Y
rom.write_bytes(YOSHI_BOX_SUB_ADDR + 0x0C, bytearray([0x80, 0x08])) # BRA +0x08
rom.write_bytes(YOSHI_BOX_SUB_ADDR + 0x0E, bytearray([0x28])) # PLP
rom.write_bytes(YOSHI_BOX_SUB_ADDR + 0x0F, bytearray([0xDA])) # PHX
rom.write_bytes(YOSHI_BOX_SUB_ADDR + 0x10, bytearray([0xBB])) # TYX
rom.write_bytes(YOSHI_BOX_SUB_ADDR + 0x11, bytearray([0xBF, 0x00, 0xC2, 0x7E])) # LDA $7EC200, X
rom.write_bytes(YOSHI_BOX_SUB_ADDR + 0x15, bytearray([0xFA])) # PLX
rom.write_bytes(YOSHI_BOX_SUB_ADDR + 0x16, bytearray([0x60])) # RTS
return
def handle_bowser_damage(rom):
rom.write_bytes(0x1A509, bytearray([0x20, 0x50, 0xBC])) # JSR $03BC50
BOWSER_BALLS_SUB_ADDR = 0x01BC50
rom.write_bytes(BOWSER_BALLS_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
rom.write_bytes(BOWSER_BALLS_SUB_ADDR + 0x01, bytearray([0xAD, 0x48, 0x0F])) # LDA $F48
rom.write_bytes(BOWSER_BALLS_SUB_ADDR + 0x04, bytearray([0xCF, 0xA1, 0xBF, 0x03])) # CMP $03BFA1
rom.write_bytes(BOWSER_BALLS_SUB_ADDR + 0x08, bytearray([0x90, 0x06])) # BCC +0x06
rom.write_bytes(BOWSER_BALLS_SUB_ADDR + 0x0A, bytearray([0x28])) # PLP
rom.write_bytes(BOWSER_BALLS_SUB_ADDR + 0x0B, bytearray([0xEE, 0xB8, 0x14])) # INC $14B8
rom.write_bytes(BOWSER_BALLS_SUB_ADDR + 0x0E, bytearray([0x80, 0x01])) # BRA +0x01
rom.write_bytes(BOWSER_BALLS_SUB_ADDR + 0x10, bytearray([0x28])) # PLP
rom.write_bytes(BOWSER_BALLS_SUB_ADDR + 0x11, bytearray([0x60])) # RTS
return
def handle_level_shuffle(rom, active_level_dict):
rom.write_bytes(0x37600, bytearray([0x00] * 0x800)) # Duplicate Level Table
rom.write_bytes(0x2D89C, bytearray([0x00, 0xF6, 0x06])) # Level Load Pointer
rom.write_bytes(0x20F46, bytearray([0x00, 0xF6, 0x06])) # Mid Gate Pointer
rom.write_bytes(0x20E7B, bytearray([0x00, 0xF6, 0x06])) # Level Name Pointer
rom.write_bytes(0x21543, bytearray([0x00, 0xF6, 0x06])) # Also Level Name Pointer?
rom.write_bytes(0x20F64, bytearray([0x00, 0xF6, 0x06])) # Level Beaten Pointer
### Fix Translevel Check
rom.write_bytes(0x2D8AE, bytearray([0x20, 0x00, 0xDD])) # JSR $DD00
rom.write_bytes(0x2D8B1, bytearray([0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA])) # NOP NOP NOP NOP NOP
rom.write_bytes(0x2D7CB, bytearray([0x20, 0x00, 0xDD])) # JSR $DD00
rom.write_bytes(0x2D7CE, bytearray([0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA])) # NOP NOP NOP NOP NOP
rom.write_bytes(0x2DD00, bytearray([0xDA])) # PHX
rom.write_bytes(0x2DD01, bytearray([0x08])) # PHP
rom.write_bytes(0x2DD02, bytearray([0xE2, 0x30])) # SEP #30
rom.write_bytes(0x2DD04, bytearray([0xAE, 0xBF, 0x13])) # LDX $13BF
rom.write_bytes(0x2DD07, bytearray([0xE0, 0x25])) # CPX #25
rom.write_bytes(0x2DD09, bytearray([0x90, 0x04])) # BCC $DD0F
rom.write_bytes(0x2DD0B, bytearray([0xA2, 0x01])) # LDX #01
rom.write_bytes(0x2DD0D, bytearray([0x80, 0x02])) # BRA $DD11
rom.write_bytes(0x2DD0F, bytearray([0xA2, 0x00])) # LDX #00
rom.write_bytes(0x2DD11, bytearray([0x86, 0x0F])) # STX $0F
rom.write_bytes(0x2DD13, bytearray([0x28])) # PLP
rom.write_bytes(0x2DD14, bytearray([0xFA])) # PLX
rom.write_bytes(0x2DD15, bytearray([0x60])) # RTS
### End Fix Translevel Check
### Fix Snake Blocks
rom.write_bytes(0x192FB, bytearray([0x20, 0x1D, 0xBC])) # JSR $03BC1D
SNAKE_BLOCKS_SUB_ADDR = 0x01BC1D
rom.write_bytes(SNAKE_BLOCKS_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
rom.write_bytes(SNAKE_BLOCKS_SUB_ADDR + 0x01, bytearray([0xAD, 0xBF, 0x13])) # LDA $13BF
rom.write_bytes(SNAKE_BLOCKS_SUB_ADDR + 0x04, bytearray([0xC9, 0x20])) # CMP #20
rom.write_bytes(SNAKE_BLOCKS_SUB_ADDR + 0x06, bytearray([0xF0, 0x05])) # BEQ +0x05
rom.write_bytes(SNAKE_BLOCKS_SUB_ADDR + 0x08, bytearray([0x28])) # PLP
rom.write_bytes(SNAKE_BLOCKS_SUB_ADDR + 0x09, bytearray([0xA9, 0x01])) # LDA #01
rom.write_bytes(SNAKE_BLOCKS_SUB_ADDR + 0x0B, bytearray([0x80, 0x03])) # BRA +0x03
rom.write_bytes(SNAKE_BLOCKS_SUB_ADDR + 0x0D, bytearray([0x28])) # PLP
rom.write_bytes(SNAKE_BLOCKS_SUB_ADDR + 0x0E, bytearray([0xA9, 0x00])) # LDA #00
rom.write_bytes(SNAKE_BLOCKS_SUB_ADDR + 0x10, bytearray([0x60])) # RTS
### End Fix Snake Blocks
for level_id, level_data in level_info_dict.items():
if level_id not in active_level_dict.keys():
continue
tile_id = active_level_dict[level_id]
tile_data = level_info_dict[tile_id]
if level_id > 0x80:
level_id = level_id - 0x50
rom.write_byte(tile_data.levelIDAddress, level_id)
rom.write_byte(0x2D608 + level_id, tile_data.eventIDValue)
for level_id, tile_id in active_level_dict.items():
rom.write_byte(0x37F70 + level_id, tile_id)
def handle_collected_paths(rom):
rom.write_bytes(0x1F5B, bytearray([0x22, 0x30, 0xBC, 0x03])) # JSL $03BC30
rom.write_bytes(0x1F5F, bytearray([0xEA] * 0x02))
COLLECTED_PATHS_SUB_ADDR = 0x01BC30
rom.write_bytes(COLLECTED_PATHS_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
rom.write_bytes(COLLECTED_PATHS_SUB_ADDR + 0x01, bytearray([0xAD, 0x00, 0x01])) # LDA $0100
rom.write_bytes(COLLECTED_PATHS_SUB_ADDR + 0x04, bytearray([0xC9, 0x0B])) # CMP #0B
rom.write_bytes(COLLECTED_PATHS_SUB_ADDR + 0x06, bytearray([0xD0, 0x04])) # BNE +0x04
rom.write_bytes(COLLECTED_PATHS_SUB_ADDR + 0x08, bytearray([0x22, 0xAD, 0xDA, 0x04])) # JSL $04DAAD
rom.write_bytes(COLLECTED_PATHS_SUB_ADDR + 0x0C, bytearray([0x28])) # PLP
rom.write_bytes(COLLECTED_PATHS_SUB_ADDR + 0x0D, bytearray([0xEE, 0x00, 0x01])) # INC $0100
rom.write_bytes(COLLECTED_PATHS_SUB_ADDR + 0x10, bytearray([0xAD, 0xAF, 0x0D])) # LDA $0DAF
rom.write_bytes(COLLECTED_PATHS_SUB_ADDR + 0x13, bytearray([0x6B])) # RTL
def handle_vertical_scroll(rom):
rom.write_bytes(0x285BA, bytearray([0x22, 0x90, 0xBC, 0x03])) # JSL $03BC90
VERTICAL_SCROLL_SUB_ADDR = 0x01BC90
rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x00, bytearray([0x4A])) # LSR
rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x01, bytearray([0x4A])) # LSR
rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x02, bytearray([0x4A])) # LSR
rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x03, bytearray([0x4A])) # LSR
rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x04, bytearray([0x08])) # PHP
rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x05, bytearray([0xC9, 0x02])) # CMP #02
rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x07, bytearray([0xD0, 0x02])) # BNE +0x02
rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x09, bytearray([0xA9, 0x01])) # LDA #01
rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x0B, bytearray([0x28])) # PLP
rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x0C, bytearray([0x6B])) # RTL
def handle_music_shuffle(rom, world, player):
from .Aesthetics import generate_shuffled_level_music, generate_shuffled_ow_music, level_music_address_data, ow_music_address_data
shuffled_level_music = generate_shuffled_level_music(world, player)
for i in range(len(shuffled_level_music)):
rom.write_byte(level_music_address_data[i], shuffled_level_music[i])
shuffled_ow_music = generate_shuffled_ow_music(world, player)
for i in range(len(shuffled_ow_music)):
for addr in ow_music_address_data[i]:
rom.write_byte(addr, shuffled_ow_music[i])
def handle_mario_palette(rom, world, player):
from .Aesthetics import mario_palettes, fire_mario_palettes, ow_mario_palettes
chosen_palette = world.mario_palette[player].value
rom.write_bytes(0x32C8, bytes(mario_palettes[chosen_palette]))
rom.write_bytes(0x32F0, bytes(fire_mario_palettes[chosen_palette]))
rom.write_bytes(0x359C, bytes(ow_mario_palettes[chosen_palette]))
def handle_swap_donut_gh_exits(rom):
rom.write_bytes(0x2567C, bytes([0xC0]))
rom.write_bytes(0x25873, bytes([0xA9]))
rom.write_bytes(0x25875, bytes([0x85]))
rom.write_bytes(0x25954, bytes([0x92]))
rom.write_bytes(0x25956, bytes([0x0A]))
rom.write_bytes(0x25E31, bytes([0x00, 0x00, 0xD8, 0x04, 0x24, 0x00, 0x98, 0x04, 0x48, 0x00, 0xD8, 0x03, 0x6C, 0x00, 0x56, 0x03,
0x90, 0x00, 0x56, 0x03, 0xB4, 0x00, 0x56, 0x03, 0x10, 0x05, 0x18, 0x05, 0x28, 0x09, 0x24, 0x05,
0x38, 0x0B, 0x14, 0x07, 0xEC, 0x09, 0x12, 0x05, 0xF0, 0x09, 0xD2, 0x04, 0xF4, 0x09, 0x92, 0x04]))
rom.write_bytes(0x26371, bytes([0x32]))
def handle_bowser_rooms(rom, world, player: int):
if world.bowser_castle_rooms[player] == "random_two_room":
chosen_rooms = world.per_slot_randoms[player].sample(standard_bowser_rooms, 2)
rom.write_byte(0x3A680, chosen_rooms[0].roomID)
rom.write_byte(0x3A684, chosen_rooms[0].roomID)
rom.write_byte(0x3A688, chosen_rooms[0].roomID)
rom.write_byte(0x3A68C, chosen_rooms[0].roomID)
for i in range(1, len(chosen_rooms)):
rom.write_byte(chosen_rooms[i-1].exitAddress, chosen_rooms[i].roomID)
rom.write_byte(chosen_rooms[len(chosen_rooms)-1].exitAddress, 0xBD)
elif world.bowser_castle_rooms[player] == "random_five_room":
chosen_rooms = world.per_slot_randoms[player].sample(standard_bowser_rooms, 5)
rom.write_byte(0x3A680, chosen_rooms[0].roomID)
rom.write_byte(0x3A684, chosen_rooms[0].roomID)
rom.write_byte(0x3A688, chosen_rooms[0].roomID)
rom.write_byte(0x3A68C, chosen_rooms[0].roomID)
for i in range(1, len(chosen_rooms)):
rom.write_byte(chosen_rooms[i-1].exitAddress, chosen_rooms[i].roomID)
rom.write_byte(chosen_rooms[len(chosen_rooms)-1].exitAddress, 0xBD)
elif world.bowser_castle_rooms[player] == "gauntlet":
chosen_rooms = standard_bowser_rooms.copy()
world.per_slot_randoms[player].shuffle(chosen_rooms)
rom.write_byte(0x3A680, chosen_rooms[0].roomID)
rom.write_byte(0x3A684, chosen_rooms[0].roomID)
rom.write_byte(0x3A688, chosen_rooms[0].roomID)
rom.write_byte(0x3A68C, chosen_rooms[0].roomID)
for i in range(1, len(chosen_rooms)):
rom.write_byte(chosen_rooms[i-1].exitAddress, chosen_rooms[i].roomID)
rom.write_byte(chosen_rooms[len(chosen_rooms)-1].exitAddress, 0xBD)
elif world.bowser_castle_rooms[player] == "labyrinth":
bowser_rooms_copy = full_bowser_rooms.copy()
entrance_point = bowser_rooms_copy.pop(0)
world.per_slot_randoms[player].shuffle(bowser_rooms_copy)
rom.write_byte(entrance_point.exitAddress, bowser_rooms_copy[0].roomID)
for i in range(0, len(bowser_rooms_copy) - 1):
rom.write_byte(bowser_rooms_copy[i].exitAddress, bowser_rooms_copy[i+1].roomID)
rom.write_byte(bowser_rooms_copy[len(bowser_rooms_copy)-1].exitAddress, 0xBD)
def handle_boss_shuffle(rom, world, player):
if world.boss_shuffle[player] == "simple":
submap_boss_rooms_copy = submap_boss_rooms.copy()
ow_boss_rooms_copy = ow_boss_rooms.copy()
world.per_slot_randoms[player].shuffle(submap_boss_rooms_copy)
world.per_slot_randoms[player].shuffle(ow_boss_rooms_copy)
for i in range(len(submap_boss_rooms_copy)):
rom.write_byte(submap_boss_rooms[i].exitAddress, submap_boss_rooms_copy[i].roomID)
for i in range(len(ow_boss_rooms_copy)):
rom.write_byte(ow_boss_rooms[i].exitAddress, ow_boss_rooms_copy[i].roomID)
if ow_boss_rooms[i].exitAddressAlt is not None:
rom.write_byte(ow_boss_rooms[i].exitAddressAlt, ow_boss_rooms_copy[i].roomID)
elif world.boss_shuffle[player] == "full":
for i in range(len(submap_boss_rooms)):
chosen_boss = world.per_slot_randoms[player].choice(submap_boss_rooms)
rom.write_byte(submap_boss_rooms[i].exitAddress, chosen_boss.roomID)
for i in range(len(ow_boss_rooms)):
chosen_boss = world.per_slot_randoms[player].choice(ow_boss_rooms)
rom.write_byte(ow_boss_rooms[i].exitAddress, chosen_boss.roomID)
if ow_boss_rooms[i].exitAddressAlt is not None:
rom.write_byte(ow_boss_rooms[i].exitAddressAlt, chosen_boss.roomID)
elif world.boss_shuffle[player] == "singularity":
chosen_submap_boss = world.per_slot_randoms[player].choice(submap_boss_rooms)
chosen_ow_boss = world.per_slot_randoms[player].choice(ow_boss_rooms)
for i in range(len(submap_boss_rooms)):
rom.write_byte(submap_boss_rooms[i].exitAddress, chosen_submap_boss.roomID)
for i in range(len(ow_boss_rooms)):
rom.write_byte(ow_boss_rooms[i].exitAddress, chosen_ow_boss.roomID)
if ow_boss_rooms[i].exitAddressAlt is not None:
rom.write_byte(ow_boss_rooms[i].exitAddressAlt, chosen_ow_boss.roomID)
def patch_rom(world, rom, player, active_level_dict):
goal_text = generate_goal_text(world, player)
rom.write_bytes(0x2A6E2, goal_text)
rom.write_byte(0x2B1D8, 0x80)
intro_text = generate_text_box("Bowser has stolen all of Mario's abilities. Can you help Mario travel across Dinosaur land to get them back and save the Princess from him?")
rom.write_bytes(0x2A5D9, intro_text)
handle_bowser_rooms(rom, world, player)
handle_boss_shuffle(rom, world, player)
# Prevent Title Screen Deaths
rom.write_byte(0x1C6A, 0x80)
# Title Screen Text
player_name_bytes = bytearray()
player_name = world.get_player_name(player)
for i in range(16):
char = " "
if i < len(player_name):
char = world.get_player_name(player)[i]
upper_char = char.upper()
if upper_char not in title_text_mapping:
for byte in title_text_mapping["."]:
player_name_bytes.append(byte)
else:
for byte in title_text_mapping[upper_char]:
player_name_bytes.append(byte)
rom.write_bytes(0x2B7F1, player_name_bytes) # MARIO A
rom.write_bytes(0x2B726, player_name_bytes) # MARIO A
rom.write_bytes(0x2B815, bytearray([0xFC, 0x38] * 0x10)) # MARIO B
rom.write_bytes(0x2B74A, bytearray([0xFC, 0x38] * 0x10)) # MARIO B
rom.write_bytes(0x2B839, bytearray([0x71, 0x31, 0x74, 0x31, 0x2D, 0x31, 0x84, 0x30,
0x82, 0x30, 0x6F, 0x31, 0x73, 0x31, 0x70, 0x31,
0x71, 0x31, 0x75, 0x31, 0x83, 0x30, 0xFC, 0x38,
0xFC, 0x38, 0xFC, 0x38, 0xFC, 0x38, 0xFC, 0x38])) # MARIO C
rom.write_bytes(0x2B76E, bytearray([0xFC, 0x38] * 0x10)) # MARIO C
rom.write_bytes(0x2B79E, bytearray([0xFC, 0x38] * 0x05)) # EMPTY
rom.write_bytes(0x2B7AE, bytearray([0xFC, 0x38] * 0x05)) # EMPTY
rom.write_bytes(0x2B8A8, bytearray([0xFC, 0x38] * 0x0D)) # 2 PLAYER GAME
rom.write_bytes(0x2B85D, bytearray([0xFC, 0x38] * 0x0A)) # ERASE
rom.write_bytes(0x2B88E, bytearray([0x2C, 0x31, 0x73, 0x31, 0x75, 0x31, 0x82, 0x30, 0x30, 0x31, 0xFC, 0x38, 0x31, 0x31, 0x73, 0x31,
0x73, 0x31, 0x7C, 0x30, 0xFC, 0x38, 0xFC, 0x38, 0xFC, 0x38])) # 1 Player Game
rom.write_bytes(0x2B6D7, bytearray([0xFC, 0x38, 0xFC, 0x38, 0x16, 0x38, 0x18, 0x38, 0x0D, 0x38, 0xFC, 0x38, 0x0B, 0x38, 0x22, 0x38,
0xFC, 0x38, 0x19, 0x38, 0x18, 0x38, 0x1B, 0x38, 0x22, 0x38, 0x10, 0x38, 0x18, 0x38, 0x17, 0x38,
0x0E, 0x38, 0xFC, 0x38, 0xFC, 0x38])) # Mod by PoryGone
# Title Options
rom.write_bytes(0x1E6A, bytearray([0x01]))
rom.write_bytes(0x1E6C, bytearray([0x01]))
rom.write_bytes(0x1E6E, bytearray([0x01]))
# Always allow Start+Select
rom.write_bytes(0x2267, bytearray([0xEA, 0xEA]))
# Always bring up save prompt on beating a level
if world.autosave[player]:
rom.write_bytes(0x20F93, bytearray([0x00]))
if world.overworld_speed[player] == "fast":
rom.write_bytes(0x21414, bytearray([0x20, 0x10]))
elif world.overworld_speed[player] == "slow":
rom.write_bytes(0x21414, bytearray([0x05, 0x05]))
# Starting Life Count
rom.write_bytes(0x1E25, bytearray([world.starting_life_count[player].value - 1]))
# Repurpose Bonus Stars counter for Boss Token or Yoshi Eggs
rom.write_bytes(0x3F1AA, bytearray([0x00] * 0x20))
# Delete Routine that would copy Mario position data over repurposed Luigi save data
rom.write_bytes(0x20F9F, bytearray([0xEA] * 0x3D))
# Prevent Switch Palaces setting the Switch Palace flags
rom.write_bytes(0x6EC9A, bytearray([0xEA, 0xEA]))
rom.write_bytes(0x6EB1, bytearray([0xEA, 0xEA]))
rom.write_bytes(0x6EB4, bytearray([0xEA, 0xEA, 0xEA]))
handle_ability_code(rom)
handle_yoshi_box(rom)
handle_bowser_damage(rom)
handle_collected_paths(rom)
handle_vertical_scroll(rom)
# Handle Level Shuffle
handle_level_shuffle(rom, active_level_dict)
# Handle Music Shuffle
if world.music_shuffle[player] != "none":
handle_music_shuffle(rom, world, player)
generate_shuffled_ow_palettes(rom, world, player)
generate_shuffled_header_data(rom, world, player)
if world.swap_donut_gh_exits[player]:
handle_swap_donut_gh_exits(rom)
handle_mario_palette(rom, world, player)
# Store all relevant option results in ROM
rom.write_byte(0x01BFA0, world.goal[player].value)
if world.goal[player].value == 0:
rom.write_byte(0x01BFA1, world.bosses_required[player].value)
else:
rom.write_byte(0x01BFA1, 0x7F)
required_yoshi_eggs = max(math.floor(
world.number_of_yoshi_eggs[player].value * (world.percentage_of_yoshi_eggs[player].value / 100.0)), 1)
rom.write_byte(0x01BFA2, required_yoshi_eggs)
#rom.write_byte(0x01BFA3, world.display_sent_item_popups[player].value)
rom.write_byte(0x01BFA4, world.display_received_item_popups[player].value)
rom.write_byte(0x01BFA5, world.death_link[player].value)
rom.write_byte(0x01BFA6, world.dragon_coin_checks[player].value)
rom.write_byte(0x01BFA7, world.swap_donut_gh_exits[player].value)
from Utils import __version__
rom.name = bytearray(f'SMW{__version__.replace(".", "")[0:3]}_{player}_{world.seed:11}\0', 'utf8')[:21]
rom.name.extend([0] * (21 - len(rom.name)))
rom.write_bytes(0x7FC0, rom.name)
def get_base_rom_bytes(file_name: str = "") -> bytes:
base_rom_bytes = getattr(get_base_rom_bytes, "base_rom_bytes", None)
if not base_rom_bytes:
file_name = get_base_rom_path(file_name)
base_rom_bytes = bytes(Utils.read_snes_rom(open(file_name, "rb")))
basemd5 = hashlib.md5()
basemd5.update(base_rom_bytes)
if USHASH != basemd5.hexdigest():
raise Exception('Supplied Base Rom does not match known MD5 for US(1.0) release. '
'Get the correct game and version, then dump it')
get_base_rom_bytes.base_rom_bytes = base_rom_bytes
return base_rom_bytes
def get_base_rom_path(file_name: str = "") -> str:
options = Utils.get_options()
if not file_name:
file_name = options["smw_options"]["rom_file"]
if not os.path.exists(file_name):
file_name = Utils.user_path(file_name)
return file_name