From 7cd01df7d630b5374f335044c9b189ddb07eab66 Mon Sep 17 00:00:00 2001 From: Lyle Mantooth Date: Mon, 30 May 2022 01:03:30 -0400 Subject: [PATCH] Move Asar symbols into RomData. Add move_room_headers function for base_patch_generator. --- enemize/src/constants.rs | 2 +- enemize/src/lib.rs | 13 ++++++- enemize/src/rom.rs | 79 ++++++++++++++++++++++++++++++++++------ 3 files changed, 80 insertions(+), 14 deletions(-) diff --git a/enemize/src/constants.rs b/enemize/src/constants.rs index 716dfde..630ff5b 100644 --- a/enemize/src/constants.rs +++ b/enemize/src/constants.rs @@ -1,4 +1,4 @@ -pub const ROM_HEADER_BANK_LOCATION: usize = 0x0B5E7; +pub const ROOM_HEADER_BANK_LOCATION: usize = 0x0B5E7; pub const DUNGEON_HEADER_POINTER_TABLE: usize = 0x271E2; pub const DUNGEON_SPRITE_POINTER_TABLE: usize = 0x4D62E; pub const OBJECT_DATA_POINTER_TABLE: usize = 0xF8000; diff --git a/enemize/src/lib.rs b/enemize/src/lib.rs index 201bba8..e5c016e 100644 --- a/enemize/src/lib.rs +++ b/enemize/src/lib.rs @@ -7,6 +7,7 @@ use thiserror::Error; use crate::rom::RomData; +pub mod asar; pub mod bosses; pub mod constants; pub mod option_flags; @@ -41,12 +42,20 @@ impl PatchSet { }) } + pub fn add_patch(&mut self, patch: Patch) { + self.patches.push(patch); + } + + pub fn add_patches(&mut self, patches: Vec) { + self.patches.extend(patches); + } + pub fn filename(&self) -> &Path { self.filename.as_path() } - pub fn patch_rom(self, rom: &mut RomData) { - for patch in self.patches { + pub fn patch_rom(&self, rom: &mut RomData) { + for patch in self.patches.iter() { rom.patch_data(patch); } } diff --git a/enemize/src/rom.rs b/enemize/src/rom.rs index 2807194..8b7a2e0 100644 --- a/enemize/src/rom.rs +++ b/enemize/src/rom.rs @@ -4,6 +4,7 @@ use std::ops::Range; use anyhow::bail; +use crate::asar::{Symbols, snes_to_pc_address, pc_to_snes_address}; use crate::constants::*; use crate::option_flags::OptionFlags; use crate::Patch; @@ -28,8 +29,7 @@ pub const CHECKSUM_ADDRESS: usize = 0x7FDE; pub const RANDOMIZER_MODE_FLAG: usize = 0x180032; pub struct RomData { - pub enemizer_info_table_base_address: usize, - pub enemizer_option_flags_base_address: usize, + asar_symbols: Symbols, spoiler: String, rom_data: Vec, patch_data: BTreeMap, @@ -65,8 +65,8 @@ impl RomData { pub fn is_enemizer(&self) -> bool { self.rom_data.len() == ENEMIZER_FILE_LENGTH - && self.rom_data[self.enemizer_info_table_base_address + ENEMIZER_INFO_SEED_OFFSET] == b'E' - && self.rom_data[self.enemizer_info_table_base_address + ENEMIZER_INFO_SEED_OFFSET + 1] == b'N' + && self.rom_data[self.asar_symbols["enemizer_info_table"] + ENEMIZER_INFO_SEED_OFFSET] == b'E' + && self.rom_data[self.asar_symbols["enemizer_info_table"] + ENEMIZER_INFO_SEED_OFFSET + 1] == b'N' } fn assert_rom_length(&self) { @@ -79,7 +79,7 @@ impl RomData { pub fn derive_enemizer_seed(&mut self) -> anyhow::Result { if self.seed < 0 && self.is_enemizer() { - let seed_start = self.enemizer_info_table_base_address + ENEMIZER_INFO_SEED_OFFSET; + let seed_start = self.asar_symbols["enemizer_info_table"] + ENEMIZER_INFO_SEED_OFFSET; let seed_end = seed_start + ENEMIZER_INFO_SEED_LENGTH; let seed_bytes = &self.rom_data[seed_start..seed_end]; let seed_str = &std::str::from_utf8(seed_bytes)?.trim_end_matches('\0')[2..]; @@ -96,7 +96,7 @@ impl RomData { let seed_str = format!("EN{:<10}", seed); let bytes = seed_str.as_bytes().to_owned(); - let seed_start = self.enemizer_info_table_base_address + ENEMIZER_INFO_SEED_OFFSET; + let seed_start = self.asar_symbols["enemizer_info_table"] + ENEMIZER_INFO_SEED_OFFSET; let seed_end = seed_start + ENEMIZER_INFO_SEED_LENGTH; self.seed = seed; @@ -106,7 +106,7 @@ impl RomData { pub fn get_enemizer_version(&self) -> anyhow::Result<&str> { if self.is_enemizer() { - let version_start = self.enemizer_info_table_base_address + ENEMIZER_INFO_VERSION_OFFSET; + let version_start = self.asar_symbols["enemizer_info_table"] + ENEMIZER_INFO_VERSION_OFFSET; let version_end = version_start + ENEMIZER_INFO_VERSION_LENGTH; Ok(std::str::from_utf8(&self.rom_data[version_start..version_end])?) } else { @@ -120,7 +120,7 @@ impl RomData { let mut bytes = version.into_bytes(); bytes.resize(ENEMIZER_INFO_VERSION_LENGTH, 0); - let version_start = self.enemizer_info_table_base_address + ENEMIZER_INFO_VERSION_OFFSET; + let version_start = self.asar_symbols["enemizer_info_table"] + ENEMIZER_INFO_VERSION_OFFSET; let version_end = version_start + ENEMIZER_INFO_VERSION_LENGTH; self.set_rom_bytes(&bytes, version_start..version_end); self.set_patch_bytes(version_start..version_end) @@ -132,7 +132,7 @@ impl RomData { bail!("Option flags is too long to fit in the space allocated. Need to move data/code in asm file."); } - let flags_start = self.enemizer_info_table_base_address + ENEMIZER_INFO_FLAGS_OFFSET; + let flags_start = self.asar_symbols["enemizer_info_table"] + ENEMIZER_INFO_FLAGS_OFFSET; let flags_end = flags_start + bytes.len(); self.set_rom_bytes(&bytes, flags_start..flags_end); self.set_patch_bytes(flags_start..flags_end); @@ -142,7 +142,7 @@ impl RomData { pub fn get_info_flags(&self) -> Option { if self.is_enemizer() { - let flags_start = self.enemizer_info_table_base_address + ENEMIZER_INFO_FLAGS_OFFSET; + let flags_start = self.asar_symbols["enemizer_info_table"] + ENEMIZER_INFO_FLAGS_OFFSET; let flags_end = flags_start + ENEMIZER_INFO_FLAGS_LENGTH; OptionFlags::try_from_bytes(&self.rom_data[flags_start..flags_end]).ok() } else { @@ -150,15 +150,72 @@ impl RomData { } } + pub fn new(asar_symbols: Symbols, rom_data: Vec) -> Self { + Self { + asar_symbols, + spoiler: String::new(), + rom_data: rom_data, + patch_data: BTreeMap::new(), + seed: -1, + } + } + + fn get_flag(&self, offset: usize) -> bool { + let flag_idx = self.asar_symbols["EnemizerFlags"] + offset; + self.rom_data[flag_idx] == 1 + } + + fn set_flag(&mut self, offset: usize, val: bool) { + let flag_idx = self.asar_symbols["EnemizerFlags"] + offset; + self.rom_data[flag_idx] = if val { 1 } else { 0 }; + self.set_patch_bytes(flag_idx..(flag_idx + 1)); + } + pub fn patch_bytes(&mut self, address: usize, patch_data: Vec) { self.rom_data .splice(address..(address + patch_data.len()), patch_data); } - pub fn patch_data(&mut self, patch: Patch) { + pub fn patch_data(&mut self, patch: &Patch) { self.set_rom_bytes( &patch.patch_data, patch.address..(patch.address + patch.patch_data.len()), ); } + + pub fn move_room_headers(&mut self) { + let table_base = DUNGEON_HEADER_POINTER_TABLE; + let header_base = self.asar_symbols["rom_header_table"]; + + // Change room header bank (at 0xB5E7) to 0x04. + let new_room_bank = self.rom_data[self.asar_symbols["moved_room_header_bank_value_address"]]; + self.rom_data[ROOM_HEADER_BANK_LOCATION] = new_room_bank; + + // Copy header table. + for i in 0..320 { + // Get i'th room's pointer. + // Pointers are 16bits, with a hard-coded bank. + let room_pointer = [ + self.rom_data[table_base + (i * 2)], + self.rom_data[table_base + (i * 2) + 1], + 4, + 0 + ]; + let snes_address = u32::from_le_bytes(room_pointer); + let pc_address = snes_to_pc_address(snes_address); + + // Copy i'th room's headers to new room_header_table. + let header_start = header_base + (i * 14); + self.rom_data.copy_within(pc_address..(pc_address + 14), header_start); + } + + // Repoint the pointer table to the new header table. + for i in 0..320 { + let snes = pc_to_snes_address(header_base + (i * 14)).to_le_bytes(); + + assert_eq!(snes[2], new_room_bank, "We changed banks in the middle of moving the room headers! This should have been caught by dev team, unless you were playing with files you shouldn't touch."); + + self.rom_data[(table_base + (i * 2))..(table_base + (i * 2) + 1)].copy_from_slice(&snes[0..1]); + } + } }