Move Asar symbols into RomData.
Add move_room_headers function for base_patch_generator.
This commit is contained in:
		
							parent
							
								
									7a6689efd1
								
							
						
					
					
						commit
						7cd01df7d6
					
				
					 3 changed files with 80 additions and 14 deletions
				
			
		| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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<Patch>) {
 | 
			
		||||
        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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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<u8>,
 | 
			
		||||
    patch_data: BTreeMap<usize, u8>,
 | 
			
		||||
| 
						 | 
				
			
			@ -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<i32> {
 | 
			
		||||
        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<OptionFlags> {
 | 
			
		||||
        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<u8>) -> 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<u8>) {
 | 
			
		||||
        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]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue