Compare commits

..

1 commit

Author SHA1 Message Date
Lyle Mantooth 9cb0e0b2bf
WIP 2022-06-02 11:55:41 -04:00
11 changed files with 301 additions and 551 deletions

5
.gitignore vendored
View file

@ -1,4 +1,3 @@
/target /target
asar_symbols.txt exported_symbols.txt
base_patch.json patchData.json
enemizer_base_patch.json

View file

@ -3,9 +3,9 @@ use std::fs::File;
use std::io::Read; use std::io::Read;
use std::path::Path; use std::path::Path;
use enemize::PatchSet;
use enemize::asar; use enemize::asar;
use enemize::rom::RomData; use enemize::rom::RomData;
use enemize::PatchSet;
fn main() -> Result<(), anyhow::Error> { fn main() -> Result<(), anyhow::Error> {
let mut args = env::args(); let mut args = env::args();

View file

@ -8,7 +8,7 @@ edition = "2021"
[dependencies] [dependencies]
anyhow = "1" anyhow = "1"
clap = { version = "3.1.18", features = ["derive"] } clap = { version = "3.1.18", features = ["derive"] }
rand = "0.8" rand_chacha = "0.3"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
thiserror = "1" thiserror = "1"

View file

@ -1,6 +1,6 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::fs::File; use std::fs::File;
use std::io::{BufRead, BufReader}; use std::io::{BufReader, BufRead};
use std::path::Path; use std::path::Path;
pub type Symbols = HashMap<String, usize>; pub type Symbols = HashMap<String, usize>;
@ -9,19 +9,14 @@ pub fn load_symbols(filename: &Path) -> anyhow::Result<Symbols> {
let file = File::open(filename)?; let file = File::open(filename)?;
let reader = BufReader::new(file); let reader = BufReader::new(file);
let symbols = reader let symbols = reader.lines().filter_map(|l| l.ok().and_then(|line| {
.lines()
.filter_map(|l| {
l.ok()
.and_then(|line| {
let mut words = line.split_ascii_whitespace(); let mut words = line.split_ascii_whitespace();
match (words.next(), words.next(), words.next()) { match (words.next(), words.next(), words.next()) {
// Get only two-word lines. // Get only two-word lines.
(Some(address), Some(symbol), None) => { (Some(address), Some(symbol), None) =>
Some((symbol.to_owned(), address.to_owned())) Some((symbol.to_owned(), address.to_owned())),
}
_ => None, _ => None
} }
}) })
.and_then(|(symbol, mut address)| { .and_then(|(symbol, mut address)| {
@ -35,9 +30,7 @@ pub fn load_symbols(filename: &Path) -> anyhow::Result<Symbols> {
let pc_address = snes_to_pc_address(snes_address); let pc_address = snes_to_pc_address(snes_address);
Some((symbol, pc_address)) Some((symbol, pc_address))
}) })).collect();
})
.collect();
Ok(symbols) Ok(symbols)
} }

View file

@ -1,12 +1,9 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use serde::{Deserialize, Serialize};
use crate::InvalidEnumError; use crate::InvalidEnumError;
#[derive(Clone, Copy, Debug, Deserialize, Serialize)] #[derive(Debug)]
#[repr(u8)] #[repr(u8)]
#[serde(into = "u8", try_from = "u8")]
pub enum BossType { pub enum BossType {
Kholdstare, Kholdstare,
Moldorm, Moldorm,
@ -25,29 +22,6 @@ pub enum BossType {
NoBoss = 255, NoBoss = 255,
} }
impl From<BossType> for u8 {
fn from(t: BossType) -> u8 {
use BossType::*;
match t {
Kholdstare => 0,
Moldorm => 1,
Mothula => 2,
Vitreous => 3,
Helmasaur => 4,
Armos => 5,
Lanmola => 6,
Blind => 7,
Arrghus => 8,
Trinexx => 9,
Agahnim => 10,
Agahnim2 => 11,
Ganon => 12,
NoBoss => 255,
}
}
}
impl TryFrom<u8> for BossType { impl TryFrom<u8> for BossType {
type Error = InvalidEnumError<Self>; type Error = InvalidEnumError<Self>;
@ -67,7 +41,8 @@ impl TryFrom<u8> for BossType {
11 => Ok(Self::Agahnim2), 11 => Ok(Self::Agahnim2),
12 => Ok(Self::Ganon), 12 => Ok(Self::Ganon),
255 => Ok(Self::NoBoss), 255 => Ok(Self::NoBoss),
_ => Err(InvalidEnumError(PhantomData)), _ => Err(InvalidEnumError(PhantomData))
} }
} }
} }

View file

@ -11,104 +11,104 @@ pub const RANDOM_SPRITE_GRAPHICS: usize = 0x300000;
pub const ENEMIZER_FILE_LENGTH: usize = 0x200000; pub const ENEMIZER_FILE_LENGTH: usize = 0x200000;
pub const HIDDEN_ENEMY_CHANCE_POOL: usize = 0xD7BBB; pub const HIDDEN_ENEMY_CHANCE_POOL: usize = 0xD7BBB;
pub(crate) const ORIGINAL_ROOM_POINTERS: [u8; 640] = [ pub(crate) const ORIGINAL_ROOM_POINTERS: [u8; 640] = [ 0x62, 0xF4, 0x6C, 0xF4, 0x7A, 0xF4, 0xDD, 0xF5, 0x85,
0x62, 0xF4, 0x6C, 0xF4, 0x7A, 0xF4, 0xDD, 0xF5, 0x85, 0xF4, 0x90, 0xF4, 0x90, 0xF4, 0x97, 0xF4, 0xF4, 0x90, 0xF4, 0x90, 0xF4, 0x97, 0xF4, 0xA2, 0xF4, 0xA9, 0xF4, 0xB5, 0xF4, 0xC0, 0xF4,
0xA2, 0xF4, 0xA9, 0xF4, 0xB5, 0xF4, 0xC0, 0xF4, 0xCB, 0xF4, 0xD8, 0xF4, 0xDF, 0xF4, 0xEA, 0xF4, 0xCB, 0xF4, 0xD8, 0xF4, 0xDF, 0xF4, 0xEA, 0xF4, 0xEA, 0xF4, 0xF1, 0xF4, 0xFC, 0xF4, 0x03,
0xEA, 0xF4, 0xF1, 0xF4, 0xFC, 0xF4, 0x03, 0xF5, 0x11, 0xF5, 0x18, 0xF5, 0x23, 0xF5, 0x2E, 0xF5, 0xF5, 0x11, 0xF5, 0x18, 0xF5, 0x23, 0xF5, 0x2E, 0xF5, 0x73, 0xFC, 0x3A, 0xF5, 0x41, 0xF5,
0x73, 0xFC, 0x3A, 0xF5, 0x41, 0xF5, 0x4D, 0xF5, 0x58, 0xF5, 0x63, 0xF5, 0x6E, 0xF5, 0x79, 0xF5, 0x4D, 0xF5, 0x58, 0xF5, 0x63, 0xF5, 0x6E, 0xF5, 0x79, 0xF5, 0x84, 0xF5, 0x8B, 0xF5, 0x8B,
0x84, 0xF5, 0x8B, 0xF5, 0x8B, 0xF5, 0x03, 0xF5, 0x92, 0xF5, 0x99, 0xF5, 0x99, 0xF5, 0xA6, 0xF5, 0xF5, 0x03, 0xF5, 0x92, 0xF5, 0x99, 0xF5, 0x99, 0xF5, 0xA6, 0xF5, 0xB2, 0xF5, 0xBD, 0xF5,
0xB2, 0xF5, 0xBD, 0xF5, 0xC4, 0xF5, 0xCB, 0xF5, 0x73, 0xFC, 0xD6, 0xF5, 0xD6, 0xF5, 0xDD, 0xF5, 0xC4, 0xF5, 0xCB, 0xF5, 0x73, 0xFC, 0xD6, 0xF5, 0xD6, 0xF5, 0xDD, 0xF5, 0xE4, 0xF5, 0xEF,
0xE4, 0xF5, 0xEF, 0xF5, 0xFB, 0xF5, 0x06, 0xF6, 0x0D, 0xF6, 0x18, 0xF6, 0x1F, 0xF6, 0x18, 0xF6, 0xF5, 0xFB, 0xF5, 0x06, 0xF6, 0x0D, 0xF6, 0x18, 0xF6, 0x1F, 0xF6, 0x18, 0xF6, 0x26, 0xF6,
0x26, 0xF6, 0x31, 0xF6, 0x3B, 0xF6, 0x46, 0xF6, 0x51, 0xF6, 0x58, 0xF6, 0x63, 0xF6, 0x6E, 0xF6, 0x31, 0xF6, 0x3B, 0xF6, 0x46, 0xF6, 0x51, 0xF6, 0x58, 0xF6, 0x63, 0xF6, 0x6E, 0xF6, 0x7A,
0x7A, 0xF6, 0x86, 0xF6, 0x91, 0xF6, 0x9D, 0xF6, 0xA4, 0xF6, 0xAB, 0xF6, 0xB6, 0xF6, 0xBD, 0xF6, 0xF6, 0x86, 0xF6, 0x91, 0xF6, 0x9D, 0xF6, 0xA4, 0xF6, 0xAB, 0xF6, 0xB6, 0xF6, 0xBD, 0xF6,
0xBD, 0xF6, 0xBD, 0xF6, 0xC4, 0xF6, 0xD0, 0xF6, 0xDA, 0xF6, 0xE5, 0xF6, 0xF0, 0xF6, 0xFB, 0xF6, 0xBD, 0xF6, 0xBD, 0xF6, 0xC4, 0xF6, 0xD0, 0xF6, 0xDA, 0xF6, 0xE5, 0xF6, 0xF0, 0xF6, 0xFB,
0x05, 0xF7, 0x13, 0xF7, 0x1E, 0xF7, 0x2C, 0xF7, 0x37, 0xF7, 0x42, 0xF7, 0x49, 0xF7, 0x50, 0xF7, 0xF6, 0x05, 0xF7, 0x13, 0xF7, 0x1E, 0xF7, 0x2C, 0xF7, 0x37, 0xF7, 0x42, 0xF7, 0x49, 0xF7,
0x57, 0xF7, 0x5E, 0xF7, 0x65, 0xF7, 0x6C, 0xF7, 0x73, 0xF7, 0x7E, 0xF7, 0x89, 0xF7, 0x94, 0xF7, 0x50, 0xF7, 0x57, 0xF7, 0x5E, 0xF7, 0x65, 0xF7, 0x6C, 0xF7, 0x73, 0xF7, 0x7E, 0xF7, 0x89,
0xA0, 0xF7, 0xA7, 0xF7, 0xA0, 0xF7, 0xB2, 0xF7, 0xBD, 0xF7, 0xC8, 0xF7, 0xD2, 0xF7, 0xDD, 0xF7, 0xF7, 0x94, 0xF7, 0xA0, 0xF7, 0xA7, 0xF7, 0xA0, 0xF7, 0xB2, 0xF7, 0xBD, 0xF7, 0xC8, 0xF7,
0xE4, 0xF7, 0xEB, 0xF7, 0xEB, 0xF7, 0xF7, 0xF7, 0x02, 0xF8, 0x0D, 0xF8, 0x14, 0xF8, 0x1F, 0xF8, 0xD2, 0xF7, 0xDD, 0xF7, 0xE4, 0xF7, 0xEB, 0xF7, 0xEB, 0xF7, 0xF7, 0xF7, 0x02, 0xF8, 0x0D,
0x1F, 0xF8, 0x2B, 0xF8, 0x36, 0xF8, 0x41, 0xF8, 0x48, 0xF8, 0x4F, 0xF8, 0x56, 0xF8, 0x63, 0xF8, 0xF8, 0x14, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x2B, 0xF8, 0x36, 0xF8, 0x41, 0xF8, 0x48, 0xF8,
0x70, 0xF8, 0x70, 0xF8, 0x70, 0xF8, 0x70, 0xF8, 0x7A, 0xF8, 0x81, 0xF8, 0x8B, 0xF8, 0x96, 0xF8, 0x4F, 0xF8, 0x56, 0xF8, 0x63, 0xF8, 0x70, 0xF8, 0x70, 0xF8, 0x70, 0xF8, 0x70, 0xF8, 0x7A,
0xA1, 0xF8, 0xAC, 0xF8, 0xAC, 0xF8, 0xB3, 0xF8, 0xBA, 0xF8, 0xC1, 0xF8, 0xC8, 0xF8, 0xC8, 0xF8, 0xF8, 0x81, 0xF8, 0x8B, 0xF8, 0x96, 0xF8, 0xA1, 0xF8, 0xAC, 0xF8, 0xAC, 0xF8, 0xB3, 0xF8,
0xD4, 0xF8, 0xD4, 0xF8, 0xDE, 0xF8, 0xDE, 0xF8, 0xE5, 0xF8, 0xF2, 0xF8, 0xF9, 0xF8, 0x04, 0xF9, 0xBA, 0xF8, 0xC1, 0xF8, 0xC8, 0xF8, 0xC8, 0xF8, 0xD4, 0xF8, 0xD4, 0xF8, 0xDE, 0xF8, 0xDE,
0x04, 0xF9, 0x0B, 0xF9, 0x16, 0xF9, 0x1D, 0xF9, 0x28, 0xF9, 0x28, 0xF9, 0x2F, 0xF9, 0x3A, 0xF9, 0xF8, 0xE5, 0xF8, 0xF2, 0xF8, 0xF9, 0xF8, 0x04, 0xF9, 0x04, 0xF9, 0x0B, 0xF9, 0x16, 0xF9,
0x45, 0xF9, 0x50, 0xF9, 0x5B, 0xF9, 0x5B, 0xF9, 0x65, 0xF9, 0x6C, 0xF9, 0x76, 0xF9, 0x81, 0xF9, 0x1D, 0xF9, 0x28, 0xF9, 0x28, 0xF9, 0x2F, 0xF9, 0x3A, 0xF9, 0x45, 0xF9, 0x50, 0xF9, 0x5B,
0x88, 0xF9, 0x93, 0xF9, 0x9A, 0xF9, 0x93, 0xF9, 0xA5, 0xF9, 0xAC, 0xF9, 0xB7, 0xF9, 0xC2, 0xF9, 0xF9, 0x5B, 0xF9, 0x65, 0xF9, 0x6C, 0xF9, 0x76, 0xF9, 0x81, 0xF9, 0x88, 0xF9, 0x93, 0xF9,
0xCC, 0xF9, 0xD3, 0xF9, 0xDD, 0xF9, 0xE4, 0xF9, 0xEF, 0xF9, 0xF6, 0xF9, 0xF6, 0xF9, 0x01, 0xFA, 0x9A, 0xF9, 0x93, 0xF9, 0xA5, 0xF9, 0xAC, 0xF9, 0xB7, 0xF9, 0xC2, 0xF9, 0xCC, 0xF9, 0xD3,
0x08, 0xFA, 0x14, 0xFA, 0x1E, 0xFA, 0x25, 0xFA, 0x2C, 0xFA, 0x37, 0xFA, 0x42, 0xFA, 0x0A, 0xF5, 0xF9, 0xDD, 0xF9, 0xE4, 0xF9, 0xEF, 0xF9, 0xF6, 0xF9, 0xF6, 0xF9, 0x01, 0xFA, 0x08, 0xFA,
0x4D, 0xFA, 0x54, 0xFA, 0x5B, 0xFA, 0x62, 0xFA, 0x69, 0xFA, 0x74, 0xFA, 0x74, 0xFA, 0x7F, 0xFA, 0x14, 0xFA, 0x1E, 0xFA, 0x25, 0xFA, 0x2C, 0xFA, 0x37, 0xFA, 0x42, 0xFA, 0x0A, 0xF5, 0x4D,
0x86, 0xFA, 0x92, 0xFA, 0x99, 0xFA, 0xA0, 0xFA, 0xA7, 0xFA, 0xB2, 0xFA, 0x0A, 0xF5, 0xB9, 0xFA, 0xFA, 0x54, 0xFA, 0x5B, 0xFA, 0x62, 0xFA, 0x69, 0xFA, 0x74, 0xFA, 0x74, 0xFA, 0x7F, 0xFA,
0xC0, 0xFA, 0xC7, 0xFA, 0xCE, 0xFA, 0xCE, 0xFA, 0xCE, 0xFA, 0xD5, 0xFA, 0xD5, 0xFA, 0xDF, 0xFA, 0x86, 0xFA, 0x92, 0xFA, 0x99, 0xFA, 0xA0, 0xFA, 0xA7, 0xFA, 0xB2, 0xFA, 0x0A, 0xF5, 0xB9,
0xDF, 0xFA, 0xEB, 0xFA, 0xF6, 0xFA, 0x01, 0xFB, 0x01, 0xFB, 0xB2, 0xFA, 0x0A, 0xF5, 0x01, 0xFB, 0xFA, 0xC0, 0xFA, 0xC7, 0xFA, 0xCE, 0xFA, 0xCE, 0xFA, 0xCE, 0xFA, 0xD5, 0xFA, 0xD5, 0xFA,
0x01, 0xFB, 0x08, 0xFB, 0x0F, 0xFB, 0xCE, 0xFA, 0xCE, 0xFA, 0x1A, 0xFB, 0x1A, 0xFB, 0x21, 0xFB, 0xDF, 0xFA, 0xDF, 0xFA, 0xEB, 0xFA, 0xF6, 0xFA, 0x01, 0xFB, 0x01, 0xFB, 0xB2, 0xFA, 0x0A,
0x2C, 0xFB, 0x37, 0xFB, 0x3E, 0xFB, 0x45, 0xFB, 0x4C, 0xFB, 0x4C, 0xFB, 0x53, 0xFB, 0x53, 0xFB, 0xF5, 0x01, 0xFB, 0x01, 0xFB, 0x08, 0xFB, 0x0F, 0xFB, 0xCE, 0xFA, 0xCE, 0xFA, 0x1A, 0xFB,
0x5A, 0xFB, 0x68, 0xFB, 0x68, 0xFB, 0x73, 0xFB, 0x7E, 0xFB, 0x7E, 0xFB, 0x8A, 0xFB, 0x94, 0xFB, 0x1A, 0xFB, 0x21, 0xFB, 0x2C, 0xFB, 0x37, 0xFB, 0x3E, 0xFB, 0x45, 0xFB, 0x4C, 0xFB, 0x4C,
0x53, 0xFB, 0x53, 0xFB, 0xA0, 0xFB, 0xA0, 0xFB, 0xA5, 0xFB, 0xA5, 0xFB, 0xAC, 0xFB, 0xAC, 0xFB, 0xFB, 0x53, 0xFB, 0x53, 0xFB, 0x5A, 0xFB, 0x68, 0xFB, 0x68, 0xFB, 0x73, 0xFB, 0x7E, 0xFB,
0xAC, 0xFB, 0xBA, 0xFB, 0xC1, 0xFB, 0xCC, 0xFB, 0xD7, 0xFB, 0xD7, 0xFB, 0xBA, 0xFB, 0xE3, 0xFB, 0x7E, 0xFB, 0x8A, 0xFB, 0x94, 0xFB, 0x53, 0xFB, 0x53, 0xFB, 0xA0, 0xFB, 0xA0, 0xFB, 0xA5,
0xEE, 0xFB, 0xFC, 0xFB, 0x03, 0xFC, 0x0A, 0xFC, 0x11, 0xFC, 0x18, 0xFC, 0x1F, 0xFC, 0x26, 0xFC, 0xFB, 0xA5, 0xFB, 0xAC, 0xFB, 0xAC, 0xFB, 0xAC, 0xFB, 0xBA, 0xFB, 0xC1, 0xFB, 0xCC, 0xFB,
0x2D, 0xFC, 0x34, 0xFC, 0x3B, 0xFC, 0x42, 0xFC, 0x49, 0xFC, 0x50, 0xFC, 0x57, 0xFC, 0xF5, 0xFB, 0xD7, 0xFB, 0xD7, 0xFB, 0xBA, 0xFB, 0xE3, 0xFB, 0xEE, 0xFB, 0xFC, 0xFB, 0x03, 0xFC, 0x0A,
0xF5, 0xFB, 0x5E, 0xFC, 0x65, 0xFC, 0x6C, 0xFC, 0x73, 0xFC, 0x73, 0xFC, 0x7A, 0xFC, 0x81, 0xFC, 0xFC, 0x11, 0xFC, 0x18, 0xFC, 0x1F, 0xFC, 0x26, 0xFC, 0x2D, 0xFC, 0x34, 0xFC, 0x3B, 0xFC,
0x0A, 0xFC, 0x88, 0xFC, 0x93, 0xFC, 0x9A, 0xFC, 0xF5, 0xFB, 0xA1, 0xFC, 0xAC, 0xFC, 0xB3, 0xFC, 0x42, 0xFC, 0x49, 0xFC, 0x50, 0xFC, 0x57, 0xFC, 0xF5, 0xFB, 0xF5, 0xFB, 0x5E, 0xFC, 0x65,
0xBA, 0xFC, 0x5E, 0xFC, 0x5E, 0xFC, 0xC1, 0xFC, 0xC8, 0xFC, 0xC8, 0xFC, 0xC8, 0xFC, 0xAC, 0xFC, 0xFC, 0x6C, 0xFC, 0x73, 0xFC, 0x73, 0xFC, 0x7A, 0xFC, 0x81, 0xFC, 0x0A, 0xFC, 0x88, 0xFC,
0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0x93, 0xFC, 0x9A, 0xFC, 0xF5, 0xFB, 0xA1, 0xFC, 0xAC, 0xFC, 0xB3, 0xFC, 0xBA, 0xFC, 0x5E,
0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xFC, 0x5E, 0xFC, 0xC1, 0xFC, 0xC8, 0xFC, 0xC8, 0xFC, 0xC8, 0xFC, 0xAC, 0xFC, 0xCF, 0xFC,
0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF,
]; 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC,
0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF, 0xFC, 0xCF,
0xFC];
pub(crate) const ORIGINAL_ROOM_BLOCKS: [u8; 576] = [ pub(crate) const ORIGINAL_ROOM_BLOCKS: [u8; 576] = [ 0x00, 0x49, 0x00, 0x00, 0x46, 0x49, 0x0C, 0x1D,
0x00, 0x49, 0x00, 0x00, 0x46, 0x49, 0x0C, 0x1D, 0x48, 0x49, 0x13, 0x1D, 0x46, 0x49, 0x13, 0x0E, 0x48, 0x49, 0x13, 0x1D, 0x46, 0x49, 0x13, 0x0E, 0x48, 0x49, 0x0C, 0x11, 0x48, 0x49, 0x0C, 0x10,
0x48, 0x49, 0x0C, 0x11, 0x48, 0x49, 0x0C, 0x10, 0x4F, 0x49, 0x4A, 0x50, 0x0E, 0x49, 0x4A, 0x11, 0x4F, 0x49, 0x4A, 0x50, 0x0E, 0x49, 0x4A, 0x11, 0x46, 0x49, 0x12, 0x00, 0x00, 0x49, 0x00, 0x50,
0x46, 0x49, 0x12, 0x00, 0x00, 0x49, 0x00, 0x50, 0x00, 0x49, 0x00, 0x11, 0x48, 0x49, 0x0C, 0x00, 0x00, 0x49, 0x00, 0x11, 0x48, 0x49, 0x0C, 0x00, 0x00, 0x00, 0x37, 0x36, 0x48, 0x49, 0x4C, 0x11,
0x00, 0x00, 0x37, 0x36, 0x48, 0x49, 0x4C, 0x11, 0x5D, 0x2C, 0x0C, 0x44, 0x00, 0x00, 0x4E, 0x00, 0x5D, 0x2C, 0x0C, 0x44, 0x00, 0x00, 0x4E, 0x00, 0x0F, 0x00, 0x12, 0x10, 0x00, 0x00, 0x00, 0x4C,
0x0F, 0x00, 0x12, 0x10, 0x00, 0x00, 0x00, 0x4C, 0x00, 0x0D, 0x17, 0x00, 0x16, 0x0D, 0x17, 0x1B, 0x00, 0x0D, 0x17, 0x00, 0x16, 0x0D, 0x17, 0x1B, 0x16, 0x0D, 0x17, 0x14, 0x15, 0x0D, 0x17, 0x15,
0x16, 0x0D, 0x17, 0x14, 0x15, 0x0D, 0x17, 0x15, 0x16, 0x0D, 0x18, 0x19, 0x16, 0x0D, 0x17, 0x19, 0x16, 0x0D, 0x18, 0x19, 0x16, 0x0D, 0x17, 0x19, 0x16, 0x0D, 0x00, 0x00, 0x16, 0x0D, 0x18, 0x1B,
0x16, 0x0D, 0x00, 0x00, 0x16, 0x0D, 0x18, 0x1B, 0x0F, 0x49, 0x4A, 0x11, 0x4B, 0x2A, 0x5C, 0x15, 0x0F, 0x49, 0x4A, 0x11, 0x4B, 0x2A, 0x5C, 0x15, 0x16, 0x49, 0x17, 0x1D, 0x00, 0x00, 0x00, 0x15,
0x16, 0x49, 0x17, 0x1D, 0x00, 0x00, 0x00, 0x15, 0x16, 0x0D, 0x17, 0x10, 0x16, 0x49, 0x12, 0x00, 0x16, 0x0D, 0x17, 0x10, 0x16, 0x49, 0x12, 0x00, 0x16, 0x49, 0x0C, 0x11, 0x00, 0x00, 0x12, 0x10,
0x16, 0x49, 0x0C, 0x11, 0x00, 0x00, 0x12, 0x10, 0x16, 0x0D, 0x00, 0x11, 0x16, 0x49, 0x0C, 0x00, 0x16, 0x0D, 0x00, 0x11, 0x16, 0x49, 0x0C, 0x00, 0x16, 0x0D, 0x4C, 0x11, 0x0E, 0x0D, 0x4A, 0x11,
0x16, 0x0D, 0x4C, 0x11, 0x0E, 0x0D, 0x4A, 0x11, 0x16, 0x1A, 0x17, 0x1B, 0x4F, 0x34, 0x4A, 0x50, 0x16, 0x1A, 0x17, 0x1B, 0x4F, 0x34, 0x4A, 0x50, 0x35, 0x4D, 0x65, 0x36, 0x4A, 0x34, 0x4E, 0x00,
0x35, 0x4D, 0x65, 0x36, 0x4A, 0x34, 0x4E, 0x00, 0x0E, 0x34, 0x4A, 0x11, 0x51, 0x34, 0x5D, 0x59, 0x0E, 0x34, 0x4A, 0x11, 0x51, 0x34, 0x5D, 0x59, 0x4B, 0x49, 0x4C, 0x11, 0x2D, 0x00, 0x00, 0x00,
0x4B, 0x49, 0x4C, 0x11, 0x2D, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x12, 0x59, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x12, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x49, 0x2B, 0x2D, 0x46, 0x49, 0x1C, 0x52,
0x47, 0x49, 0x2B, 0x2D, 0x46, 0x49, 0x1C, 0x52, 0x00, 0x49, 0x1C, 0x52, 0x5D, 0x49, 0x00, 0x52, 0x00, 0x49, 0x1C, 0x52, 0x5D, 0x49, 0x00, 0x52, 0x46, 0x49, 0x13, 0x52, 0x4B, 0x4D, 0x4A, 0x5A,
0x46, 0x49, 0x13, 0x52, 0x4B, 0x4D, 0x4A, 0x5A, 0x47, 0x49, 0x1C, 0x52, 0x4B, 0x4D, 0x39, 0x36, 0x47, 0x49, 0x1C, 0x52, 0x4B, 0x4D, 0x39, 0x36, 0x1F, 0x2C, 0x2E, 0x52, 0x1F, 0x2C, 0x2E, 0x1D,
0x1F, 0x2C, 0x2E, 0x52, 0x1F, 0x2C, 0x2E, 0x1D, 0x2F, 0x2C, 0x2E, 0x52, 0x2F, 0x2C, 0x2E, 0x31, 0x2F, 0x2C, 0x2E, 0x52, 0x2F, 0x2C, 0x2E, 0x31, 0x1F, 0x1E, 0x30, 0x52, 0x51, 0x49, 0x13, 0x00,
0x1F, 0x1E, 0x30, 0x52, 0x51, 0x49, 0x13, 0x00, 0x4F, 0x49, 0x13, 0x50, 0x4F, 0x4D, 0x4A, 0x50, 0x4F, 0x49, 0x13, 0x50, 0x4F, 0x4D, 0x4A, 0x50, 0x4B, 0x49, 0x4C, 0x2B, 0x1F, 0x20, 0x22, 0x53,
0x4B, 0x49, 0x4C, 0x2B, 0x1F, 0x20, 0x22, 0x53, 0x55, 0x3D, 0x42, 0x43, 0x1F, 0x1E, 0x23, 0x52, 0x55, 0x3D, 0x42, 0x43, 0x1F, 0x1E, 0x23, 0x52, 0x1F, 0x1E, 0x39, 0x3A, 0x1F, 0x1E, 0x3A, 0x3E,
0x1F, 0x1E, 0x39, 0x3A, 0x1F, 0x1E, 0x3A, 0x3E, 0x1F, 0x1E, 0x3C, 0x3D, 0x40, 0x1E, 0x27, 0x3F, 0x1F, 0x1E, 0x3C, 0x3D, 0x40, 0x1E, 0x27, 0x3F, 0x55, 0x1A, 0x42, 0x43, 0x1F, 0x1E, 0x2A, 0x52,
0x55, 0x1A, 0x42, 0x43, 0x1F, 0x1E, 0x2A, 0x52, 0x1F, 0x1E, 0x38, 0x52, 0x1F, 0x20, 0x28, 0x52, 0x1F, 0x1E, 0x38, 0x52, 0x1F, 0x20, 0x28, 0x52, 0x1F, 0x20, 0x26, 0x52, 0x1F, 0x2C, 0x25, 0x52,
0x1F, 0x20, 0x26, 0x52, 0x1F, 0x2C, 0x25, 0x52, 0x1F, 0x20, 0x27, 0x52, 0x1F, 0x1E, 0x29, 0x52, 0x1F, 0x20, 0x27, 0x52, 0x1F, 0x1E, 0x29, 0x52, 0x1F, 0x2C, 0x3B, 0x52, 0x46, 0x49, 0x24, 0x52,
0x1F, 0x2C, 0x3B, 0x52, 0x46, 0x49, 0x24, 0x52, 0x21, 0x41, 0x45, 0x33, 0x1F, 0x2C, 0x28, 0x31, 0x21, 0x41, 0x45, 0x33, 0x1F, 0x2C, 0x28, 0x31, 0x1F, 0x0D, 0x29, 0x52, 0x1F, 0x1E, 0x27, 0x52,
0x1F, 0x0D, 0x29, 0x52, 0x1F, 0x1E, 0x27, 0x52, 0x1F, 0x20, 0x27, 0x53, 0x48, 0x49, 0x13, 0x52, 0x1F, 0x20, 0x27, 0x53, 0x48, 0x49, 0x13, 0x52, 0x0E, 0x1E, 0x4A, 0x50, 0x1F, 0x20, 0x26, 0x53,
0x0E, 0x1E, 0x4A, 0x50, 0x1F, 0x20, 0x26, 0x53, 0x15, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x2A, 0x52, 0x15, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x2A, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x5D, 0x49, 0x00, 0x52, 0x55, 0x49, 0x42, 0x43, 0x5D, 0x49, 0x00, 0x52, 0x55, 0x49, 0x42, 0x43, 0x61, 0x62, 0x63, 0x50, 0x61, 0x62, 0x63, 0x50,
0x61, 0x62, 0x63, 0x50, 0x61, 0x62, 0x63, 0x50, 0x61, 0x62, 0x63, 0x50, 0x61, 0x62, 0x63, 0x50, 0x61, 0x62, 0x63, 0x50, 0x61, 0x62, 0x63, 0x50, 0x61, 0x62, 0x63, 0x50, 0x61, 0x62, 0x63, 0x50,
0x61, 0x62, 0x63, 0x50, 0x61, 0x62, 0x63, 0x50, 0x61, 0x56, 0x57, 0x50, 0x61, 0x62, 0x63, 0x50, 0x61, 0x56, 0x57, 0x50, 0x61, 0x62, 0x63, 0x50, 0x61, 0x62, 0x63, 0x50, 0x61, 0x56, 0x57, 0x50,
0x61, 0x62, 0x63, 0x50, 0x61, 0x56, 0x57, 0x50, 0x61, 0x56, 0x63, 0x50, 0x61, 0x56, 0x57, 0x50, 0x61, 0x56, 0x63, 0x50, 0x61, 0x56, 0x57, 0x50, 0x61, 0x56, 0x33, 0x50, 0x61, 0x56, 0x57, 0x50,
0x61, 0x56, 0x33, 0x50, 0x61, 0x56, 0x57, 0x50, 0x61, 0x62, 0x63, 0x50, 0x61, 0x62, 0x63, 0x50, 0x61, 0x62, 0x63, 0x50, 0x61, 0x62, 0x63, 0x50 ];
];
pub(crate) const ORIGINAL_OVERWORLD_BLOCKS: [u8; 272] = [ pub(crate) const ORIGINAL_OVERWORLD_BLOCKS: [u8; 272] = [ 0x07, 0x07, 0x07, 0x10, 0x10, 0x10, 0x10,
0x07, 0x07, 0x07, 0x10, 0x10, 0x10, 0x10, 0x10, 0x07, 0x07, 0x07, 0x10, 0x10, 0x10, 0x10, 0x04, 0x10, 0x07, 0x07, 0x07, 0x10, 0x10, 0x10, 0x10, 0x04, 0x06, 0x06, 0x00, 0x03, 0x03, 0x00, 0x0D,
0x06, 0x06, 0x00, 0x03, 0x03, 0x00, 0x0D, 0x0A, 0x06, 0x06, 0x01, 0x01, 0x01, 0x04, 0x05, 0x05, 0x0A, 0x06, 0x06, 0x01, 0x01, 0x01, 0x04, 0x05, 0x05, 0x06, 0x06, 0x06, 0x01, 0x01, 0x04, 0x05,
0x06, 0x06, 0x06, 0x01, 0x01, 0x04, 0x05, 0x05, 0x06, 0x09, 0x0F, 0x00, 0x00, 0x0B, 0x0B, 0x05, 0x05, 0x06, 0x09, 0x0F, 0x00, 0x00, 0x0B, 0x0B, 0x05, 0x08, 0x08, 0x0A, 0x04, 0x04, 0x04, 0x04,
0x08, 0x08, 0x0A, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x08, 0x0A, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x08, 0x0A, 0x04, 0x04, 0x04, 0x04, 0x04, 0x07, 0x07, 0x1A, 0x10, 0x10, 0x10, 0x10,
0x07, 0x07, 0x1A, 0x10, 0x10, 0x10, 0x10, 0x10, 0x07, 0x07, 0x1A, 0x10, 0x10, 0x10, 0x10, 0x04, 0x10, 0x07, 0x07, 0x1A, 0x10, 0x10, 0x10, 0x10, 0x04, 0x06, 0x06, 0x00, 0x03, 0x03, 0x00, 0x0D,
0x06, 0x06, 0x00, 0x03, 0x03, 0x00, 0x0D, 0x0A, 0x06, 0x06, 0x1C, 0x1C, 0x1C, 0x02, 0x05, 0x05, 0x0A, 0x06, 0x06, 0x1C, 0x1C, 0x1C, 0x02, 0x05, 0x05, 0x06, 0x06, 0x06, 0x1C, 0x1C, 0x00, 0x05,
0x06, 0x06, 0x06, 0x1C, 0x1C, 0x00, 0x05, 0x05, 0x06, 0x00, 0x0F, 0x00, 0x00, 0x23, 0x23, 0x05, 0x05, 0x06, 0x00, 0x0F, 0x00, 0x00, 0x23, 0x23, 0x05, 0x1F, 0x1F, 0x0A, 0x20, 0x20, 0x20, 0x20,
0x1F, 0x1F, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1F, 0x1F, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1F, 0x1F, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x13, 0x13, 0x17, 0x14, 0x14, 0x14, 0x14,
0x13, 0x13, 0x17, 0x14, 0x14, 0x14, 0x14, 0x14, 0x13, 0x13, 0x17, 0x14, 0x14, 0x14, 0x14, 0x16, 0x14, 0x13, 0x13, 0x17, 0x14, 0x14, 0x14, 0x14, 0x16, 0x15, 0x15, 0x12, 0x13, 0x13, 0x18, 0x16,
0x15, 0x15, 0x12, 0x13, 0x13, 0x18, 0x16, 0x16, 0x15, 0x15, 0x13, 0x26, 0x26, 0x13, 0x17, 0x17, 0x16, 0x15, 0x15, 0x13, 0x26, 0x26, 0x13, 0x17, 0x17, 0x15, 0x15, 0x15, 0x26, 0x26, 0x13, 0x17,
0x15, 0x15, 0x15, 0x26, 0x26, 0x13, 0x17, 0x17, 0x1B, 0x1D, 0x11, 0x13, 0x13, 0x18, 0x18, 0x17, 0x17, 0x1B, 0x1D, 0x11, 0x13, 0x13, 0x18, 0x18, 0x17, 0x16, 0x16, 0x13, 0x13, 0x13, 0x19, 0x19,
0x16, 0x16, 0x13, 0x13, 0x13, 0x19, 0x19, 0x19, 0x16, 0x16, 0x18, 0x13, 0x18, 0x19, 0x19, 0x19, 0x19, 0x16, 0x16, 0x18, 0x13, 0x18, 0x19, 0x19, 0x19, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x05, 0x05, 0x06, 0x09, 0x09, 0x09, 0x09,
0x05, 0x05, 0x06, 0x09, 0x09, 0x09, 0x09, 0x09, 0x05, 0x05, 0x06, 0x09, 0x09, 0x09, 0x09, 0x03, 0x09, 0x05, 0x05, 0x06, 0x09, 0x09, 0x09, 0x09, 0x03 ];
];

View file

@ -3,14 +3,11 @@ use std::io::prelude::*;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::time::Instant; use std::time::Instant;
use anyhow::{bail, ensure}; use anyhow::ensure;
use clap::Parser; use clap::Parser;
use enemize::{asar, rom::RomData}; use enemize::{asar, rom::RomData};
const ASAR_SYMBOLS: &'static str = "asar_symbols.txt";
const ENEMIZER_BASE_PATCH: &'static str = "enemizer_base_patch.json";
/// Randomizes enemy placements in The Legend of Zelda: A Link to the Past for the Super Nintendo /// Randomizes enemy placements in The Legend of Zelda: A Link to the Past for the Super Nintendo
/// Entertainment System /// Entertainment System
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
@ -37,7 +34,7 @@ fn main() -> anyhow::Result<()> {
let stopwatch = Instant::now(); let stopwatch = Instant::now();
let options = serde_json::from_reader(File::open(args.enemizer)?)?; let options = serde_json::from_reader(File::open(args.enemizer)?)?;
let symbols = load_symbols()?; let symbols = load_symbols(&args.rom)?;
let mut raw_data = vec![]; let mut raw_data = vec![];
let mut rom_file = File::open(args.rom)?; let mut rom_file = File::open(args.rom)?;
@ -45,24 +42,19 @@ fn main() -> anyhow::Result<()> {
raw_data.resize(2 * 1024 * 1024, 0); raw_data.resize(2 * 1024 * 1024, 0);
let mut rom = RomData::new(symbols, raw_data); let mut rom_data = RomData::new(symbols, raw_data);
ensure!(!rom.is_enemizer(), "It appears that the provided base ROM is already enemized. Please ensure you are using an original game ROM."); ensure!(!rom_data.is_enemizer(), "It appears that the provided base ROM is already enemized. Please ensure you are using an original game ROM.");
// Oh noes! The max seed number is twice as likely to show up as any other! // Oh noes! The max seed number is twice as likely to show up as any other!
// (That is, 2 out of 2 billion instead of 1.) // (That is, 2 out of 2billion instead of 1.)
let seed = args.seed.unwrap_or_else(|| rand::random()).saturating_abs(); let seed = args.seed.unwrap_or_else(|| rand::random()).saturating_abs();
rom.randomize(Path::new(ENEMIZER_BASE_PATCH), options, seed)?; //let randomized_rom = randomize_rom(seed, raw_data, options);
let mut out_file = File::create(&args.output)?;
if args.binary { if args.binary {
out_file.write_all(rom.get_rom_bytes())?;
out_file.flush()?;
println!("Generated SFC file {}", args.output.to_string_lossy());
} else { } else {
let patches = rom.generate_patch();
serde_json::to_writer(out_file, &patches)?;
} }
println!("Seed generated in: {}ms", stopwatch.elapsed().as_millis()); println!("Seed generated in: {}ms", stopwatch.elapsed().as_millis());
@ -70,13 +62,21 @@ fn main() -> anyhow::Result<()> {
Ok(()) Ok(())
} }
fn load_symbols() -> anyhow::Result<asar::Symbols> { fn load_symbols(rom: &Path) -> anyhow::Result<asar::Symbols> {
if let Err(_) = std::fs::metadata(ASAR_SYMBOLS) { let sym_path = rom.with_extension("sym");
bail!(
"Could not find symbols at {}. Did you run prepare.sh?", if let Err(_) = std::fs::metadata(&sym_path) {
ASAR_SYMBOLS let status = std::process::Command::new("asar")
); .arg("--no-title-check")
.arg("--fix-checksum=off")
.arg("--symbols=wla")
.arg("-Iassembly/src")
.arg("assembly/src/main.asm")
.arg(rom)
.status()?;
ensure!(status.success(), "could not generate symbols");
} }
asar::load_symbols(Path::new(ASAR_SYMBOLS)) asar::load_symbols(sym_path.as_path())
} }

View file

@ -3,12 +3,10 @@ use std::fmt;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::path::PathBuf; use std::path::PathBuf;
use serde::{Deserialize, Serialize};
use crate::bosses::BossType; use crate::bosses::BossType;
use crate::InvalidEnumError; use crate::InvalidEnumError;
#[derive(Debug, Default, Deserialize, Serialize)] #[derive(Debug, Default)]
pub struct ManualBosses { pub struct ManualBosses {
pub eastern_palace: String, pub eastern_palace: String,
pub desert_palace: String, pub desert_palace: String,
@ -28,8 +26,7 @@ pub struct ManualBosses {
pub ganon: String, pub ganon: String,
} }
#[derive(Clone, Copy, Debug, Deserialize, Serialize)] #[derive(Debug)]
#[serde(into = "u8", try_from = "u8")]
pub enum RandomizeEnemiesType { pub enum RandomizeEnemiesType {
Basic, Basic,
Normal, Normal,
@ -38,20 +35,6 @@ pub enum RandomizeEnemiesType {
Insanity, Insanity,
} }
impl From<RandomizeEnemiesType> for u8 {
fn from(t: RandomizeEnemiesType) -> u8 {
use RandomizeEnemiesType::*;
match t {
Basic => 0,
Normal => 1,
Hard => 2,
Chaos => 3,
Insanity => 4,
}
}
}
impl TryFrom<u8> for RandomizeEnemiesType { impl TryFrom<u8> for RandomizeEnemiesType {
type Error = InvalidEnumError<Self>; type Error = InvalidEnumError<Self>;
@ -62,31 +45,17 @@ impl TryFrom<u8> for RandomizeEnemiesType {
2 => Ok(Self::Hard), 2 => Ok(Self::Hard),
3 => Ok(Self::Chaos), 3 => Ok(Self::Chaos),
4 => Ok(Self::Insanity), 4 => Ok(Self::Insanity),
_ => Err(InvalidEnumError(PhantomData)), _ => Err(InvalidEnumError(PhantomData))
} }
} }
} }
#[derive(Clone, Copy, Debug, Deserialize, Serialize)] #[derive(Debug)]
#[serde(into = "u8", try_from = "u8")]
pub enum RandomizeEnemyHpType { pub enum RandomizeEnemyHpType {
Easy, Easy,
Medium, Medium,
Hard, Hard,
Patty, Patty
}
impl From<RandomizeEnemyHpType> for u8 {
fn from(t: RandomizeEnemyHpType) -> u8 {
use RandomizeEnemyHpType::*;
match t {
Easy => 0,
Medium => 1,
Hard => 2,
Patty => 3,
}
}
} }
impl TryFrom<u8> for RandomizeEnemyHpType { impl TryFrom<u8> for RandomizeEnemyHpType {
@ -98,29 +67,16 @@ impl TryFrom<u8> for RandomizeEnemyHpType {
1 => Ok(Self::Medium), 1 => Ok(Self::Medium),
2 => Ok(Self::Hard), 2 => Ok(Self::Hard),
3 => Ok(Self::Patty), 3 => Ok(Self::Patty),
_ => Err(InvalidEnumError(PhantomData)), _ => Err(InvalidEnumError(PhantomData))
} }
} }
} }
#[derive(Clone, Copy, Debug, Deserialize, Serialize)] #[derive(Debug)]
#[serde(into = "u8", try_from = "u8")]
pub enum RandomizeBossesType { pub enum RandomizeBossesType {
Basic, Basic,
Normal, Normal,
Chaos, Chaos
}
impl From<RandomizeBossesType> for u8 {
fn from(t: RandomizeBossesType) -> u8 {
use RandomizeBossesType::*;
match t {
Basic => 0,
Normal => 1,
Chaos => 2,
}
}
} }
impl TryFrom<u8> for RandomizeBossesType { impl TryFrom<u8> for RandomizeBossesType {
@ -131,21 +87,14 @@ impl TryFrom<u8> for RandomizeBossesType {
0 => Ok(Self::Basic), 0 => Ok(Self::Basic),
1 => Ok(Self::Normal), 1 => Ok(Self::Normal),
2 => Ok(Self::Chaos), 2 => Ok(Self::Chaos),
_ => Err(InvalidEnumError(PhantomData)), _ => Err(InvalidEnumError(PhantomData))
} }
} }
} }
#[derive(Clone, Copy, Debug, Deserialize, Serialize)] #[derive(Debug)]
#[serde(into = "u8", try_from = "u8")]
pub enum SwordType { pub enum SwordType {
Normal, Normal
}
impl From<SwordType> for u8 {
fn from(_t: SwordType) -> u8 {
0
}
} }
impl TryFrom<u8> for SwordType { impl TryFrom<u8> for SwordType {
@ -154,21 +103,14 @@ impl TryFrom<u8> for SwordType {
fn try_from(byte: u8) -> Result<Self, Self::Error> { fn try_from(byte: u8) -> Result<Self, Self::Error> {
match byte { match byte {
0 => Ok(Self::Normal), 0 => Ok(Self::Normal),
_ => Err(InvalidEnumError(PhantomData)), _ => Err(InvalidEnumError(PhantomData))
} }
} }
} }
#[derive(Clone, Copy, Debug, Deserialize, Serialize)] #[derive(Debug)]
#[serde(into = "u8", try_from = "u8")]
pub enum ShieldType { pub enum ShieldType {
Normal, Normal
}
impl From<ShieldType> for u8 {
fn from(_t: ShieldType) -> u8 {
0
}
} }
impl TryFrom<u8> for ShieldType { impl TryFrom<u8> for ShieldType {
@ -177,13 +119,12 @@ impl TryFrom<u8> for ShieldType {
fn try_from(byte: u8) -> Result<Self, Self::Error> { fn try_from(byte: u8) -> Result<Self, Self::Error> {
match byte { match byte {
0 => Ok(Self::Normal), 0 => Ok(Self::Normal),
_ => Err(InvalidEnumError(PhantomData)), _ => Err(InvalidEnumError(PhantomData))
} }
} }
} }
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] #[derive(Debug, PartialEq, Eq, Hash)]
#[serde(into = "u8", try_from = "u8")]
pub enum AbsorbableType { pub enum AbsorbableType {
Heart, Heart,
GreenRupee, GreenRupee,
@ -201,29 +142,6 @@ pub enum AbsorbableType {
BigKey, BigKey,
} }
impl From<AbsorbableType> for u8 {
fn from(t: AbsorbableType) -> u8 {
use AbsorbableType::*;
match t {
Heart => 0,
GreenRupee => 1,
BlueRupee => 2,
RedRupee => 3,
Bomb1 => 4,
Bomb4 => 5,
Bomb8 => 6,
SmallMagic => 7,
FullMagic => 8,
Arrow5 => 9,
Arrow10 => 10,
Fairy => 11,
Key => 12,
BigKey => 13,
}
}
}
impl TryFrom<u8> for AbsorbableType { impl TryFrom<u8> for AbsorbableType {
type Error = InvalidEnumError<Self>; type Error = InvalidEnumError<Self>;
@ -232,18 +150,17 @@ impl TryFrom<u8> for AbsorbableType {
0 => Ok(Self::Heart), 0 => Ok(Self::Heart),
1 => Ok(Self::GreenRupee), 1 => Ok(Self::GreenRupee),
2 => Ok(Self::BlueRupee), 2 => Ok(Self::BlueRupee),
3 => Ok(Self::RedRupee), 3 => Ok(Self::Bomb1),
4 => Ok(Self::Bomb1), 4 => Ok(Self::Bomb4),
5 => Ok(Self::Bomb4), 5 => Ok(Self::Bomb8),
6 => Ok(Self::Bomb8), 6 => Ok(Self::SmallMagic),
7 => Ok(Self::SmallMagic), 7 => Ok(Self::FullMagic),
8 => Ok(Self::FullMagic), 8 => Ok(Self::Arrow5),
9 => Ok(Self::Arrow5), 9 => Ok(Self::Arrow10),
10 => Ok(Self::Arrow10), 10 => Ok(Self::Fairy),
11 => Ok(Self::Fairy), 11 => Ok(Self::Key),
12 => Ok(Self::Key), 12 => Ok(Self::BigKey),
13 => Ok(Self::BigKey), _ => Err(InvalidEnumError(PhantomData))
_ => Err(InvalidEnumError(PhantomData)),
} }
} }
} }
@ -273,8 +190,7 @@ impl fmt::Display for AbsorbableType {
} }
} }
#[derive(Clone, Copy, Debug, Deserialize, Serialize)] #[derive(Debug)]
#[serde(into = "u8", try_from = "u8")]
pub enum HeartBeepSpeed { pub enum HeartBeepSpeed {
Normal, Normal,
Half, Half,
@ -288,19 +204,6 @@ impl Default for HeartBeepSpeed {
} }
} }
impl From<HeartBeepSpeed> for u8 {
fn from(speed: HeartBeepSpeed) -> u8 {
use HeartBeepSpeed::*;
match speed {
Normal => 0,
Half => 1,
Quarter => 2,
Off => 3,
}
}
}
impl TryFrom<u8> for HeartBeepSpeed { impl TryFrom<u8> for HeartBeepSpeed {
type Error = InvalidEnumError<Self>; type Error = InvalidEnumError<Self>;
@ -310,12 +213,12 @@ impl TryFrom<u8> for HeartBeepSpeed {
1 => Ok(Self::Half), 1 => Ok(Self::Half),
2 => Ok(Self::Quarter), 2 => Ok(Self::Quarter),
3 => Ok(Self::Off), 3 => Ok(Self::Off),
_ => Err(InvalidEnumError(PhantomData)), _ => Err(InvalidEnumError(PhantomData))
} }
} }
} }
#[derive(Clone, Copy, Debug, Deserialize, Serialize)] #[derive(Debug)]
pub enum BeeLevel { pub enum BeeLevel {
Level1, Level1,
Level2, Level2,
@ -338,19 +241,6 @@ impl fmt::Display for BeeLevel {
} }
} }
impl From<BeeLevel> for u8 {
fn from(level: BeeLevel) -> u8 {
use BeeLevel::*;
match level {
Level1 => 0,
Level2 => 1,
Level3 => 2,
Level4 => 3,
}
}
}
impl TryFrom<u8> for BeeLevel { impl TryFrom<u8> for BeeLevel {
type Error = InvalidEnumError<Self>; type Error = InvalidEnumError<Self>;
@ -360,13 +250,12 @@ impl TryFrom<u8> for BeeLevel {
1 => Ok(Self::Level2), 1 => Ok(Self::Level2),
2 => Ok(Self::Level3), 2 => Ok(Self::Level3),
3 => Ok(Self::Level4), 3 => Ok(Self::Level4),
_ => Err(InvalidEnumError(PhantomData)), _ => Err(InvalidEnumError(PhantomData))
} }
} }
} }
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug)]
#[serde(default, rename_all = "PascalCase")]
pub struct OptionFlags { pub struct OptionFlags {
pub randomize_enemies: bool, pub randomize_enemies: bool,
pub randomize_enemies_type: RandomizeEnemiesType, pub randomize_enemies_type: RandomizeEnemiesType,
@ -452,17 +341,16 @@ impl OptionFlags {
absorbable_types.insert(AbsorbableType::Heart, bytes[10] != 0); absorbable_types.insert(AbsorbableType::Heart, bytes[10] != 0);
absorbable_types.insert(AbsorbableType::GreenRupee, bytes[11] != 0); absorbable_types.insert(AbsorbableType::GreenRupee, bytes[11] != 0);
absorbable_types.insert(AbsorbableType::BlueRupee, bytes[12] != 0); absorbable_types.insert(AbsorbableType::BlueRupee, bytes[12] != 0);
absorbable_types.insert(AbsorbableType::RedRupee, bytes[13] != 0); absorbable_types.insert(AbsorbableType::Bomb1, bytes[13] != 0);
absorbable_types.insert(AbsorbableType::Bomb1, bytes[14] != 0); absorbable_types.insert(AbsorbableType::Bomb4, bytes[14] != 0);
absorbable_types.insert(AbsorbableType::Bomb4, bytes[15] != 0); absorbable_types.insert(AbsorbableType::Bomb8, bytes[15] != 0);
absorbable_types.insert(AbsorbableType::Bomb8, bytes[16] != 0); absorbable_types.insert(AbsorbableType::SmallMagic, bytes[16] != 0);
absorbable_types.insert(AbsorbableType::SmallMagic, bytes[17] != 0); absorbable_types.insert(AbsorbableType::FullMagic, bytes[17] != 0);
absorbable_types.insert(AbsorbableType::FullMagic, bytes[18] != 0); absorbable_types.insert(AbsorbableType::Arrow5, bytes[18] != 0);
absorbable_types.insert(AbsorbableType::Arrow5, bytes[19] != 0); absorbable_types.insert(AbsorbableType::Arrow10, bytes[19] != 0);
absorbable_types.insert(AbsorbableType::Arrow10, bytes[20] != 0); absorbable_types.insert(AbsorbableType::Fairy, bytes[20] != 0);
absorbable_types.insert(AbsorbableType::Fairy, bytes[21] != 0); absorbable_types.insert(AbsorbableType::Key, bytes[21] != 0);
absorbable_types.insert(AbsorbableType::Key, bytes[21] != 1); absorbable_types.insert(AbsorbableType::BigKey, bytes[22] != 0);
absorbable_types.insert(AbsorbableType::BigKey, bytes[23] != 0);
Ok(OptionFlags { Ok(OptionFlags {
randomize_enemies: bytes[0] != 0, randomize_enemies: bytes[0] != 0,
@ -476,55 +364,55 @@ impl OptionFlags {
enemies_absorbable: bytes[8] != 0, enemies_absorbable: bytes[8] != 0,
absorbable_spawn_rate: bytes[9], absorbable_spawn_rate: bytes[9],
absorbable_types, absorbable_types,
boss_madness: bytes[24] != 0, boss_madness: bytes[23] != 0,
randomize_bosses: bytes[25] != 0, randomize_bosses: bytes[24] != 0,
randomize_bosses_type: bytes[26].try_into()?, randomize_bosses_type: bytes[25].try_into()?,
randomize_boss_health: bytes[27] != 0, randomize_boss_health: bytes[26] != 0,
randomize_boss_health_min_amount: bytes[28], randomize_boss_health_min_amount: bytes[27],
randomize_boss_health_max_amount: bytes[29], randomize_boss_health_max_amount: bytes[28],
randomize_boss_damage: bytes[30] != 0, randomize_boss_damage: bytes[29] != 0,
randomize_boss_damage_min_amount: bytes[31], randomize_boss_damage_min_amount: bytes[30],
randomize_boss_damage_max_amount: bytes[32], randomize_boss_damage_max_amount: bytes[31],
randomize_boss_behavior: bytes[33] != 0, randomize_boss_behavior: bytes[32] != 0,
randomize_dungeon_palettes: bytes[34] != 0, randomize_dungeon_palettes: bytes[33] != 0,
set_blackout_mode: bytes[35] != 0, set_blackout_mode: bytes[34] != 0,
randomize_overworld_palettes: bytes[36] != 0, randomize_overworld_palettes: bytes[35] != 0,
randomize_sprite_palettes: bytes[37] != 0, randomize_sprite_palettes: bytes[36] != 0,
set_advanced_sprite_palettes: bytes[38] != 0, set_advanced_sprite_palettes: bytes[37] != 0,
puke_mode: bytes[39] != 0, puke_mode: bytes[38] != 0,
negative_mode: bytes[40] != 0, negative_mode: bytes[39] != 0,
grayscale_mode: bytes[41] != 0, grayscale_mode: bytes[40] != 0,
generate_spoilers: bytes[42] != 0, generate_spoilers: bytes[41] != 0,
randomize_link_sprite_palette: bytes[43] != 0, randomize_link_sprite_palette: bytes[42] != 0,
randomize_pots: bytes[44] != 0, randomize_pots: bytes[43] != 0,
shuffle_music: bytes[45] != 0, shuffle_music: bytes[44] != 0,
bootleg_magic: bytes[46] != 0, bootleg_magic: bytes[45] != 0,
debug_mode: bytes[47] != 0, debug_mode: bytes[46] != 0,
custom_bosses: bytes[48] != 0, custom_bosses: bytes[47] != 0,
heart_beep_speed: bytes[49].try_into()?, heart_beep_speed: bytes[48].try_into()?,
alternate_gfx: bytes[50] != 0, alternate_gfx: bytes[49] != 0,
// Skip byte 51 (shield_graphics) // Skip byte 50 (shield_graphics)
shuffle_enemy_damage_groups: bytes[52] != 0, shuffle_enemy_damage_groups: bytes[51] != 0,
enemy_damage_chaos_mode: bytes[53] != 0, enemy_damage_chaos_mode: bytes[52] != 0,
// Skip byte 54 (sword_graphics) // Skip byte 53 (sword_graphics)
bee_mizer: bytes[55] != 0, bee_mizer: bytes[54] != 0,
bees_level: bytes[56].try_into()?, bees_level: bytes[55].try_into()?,
debug_force_enemy: bytes[57] != 0, debug_force_enemy: bytes[56] != 0,
debug_force_enemy_id: bytes[58], debug_force_enemy_id: bytes[57],
debug_force_boss: bytes[59] != 0, debug_force_boss: bytes[58] != 0,
debug_force_boss_id: bytes[60].try_into()?, debug_force_boss_id: bytes[59].try_into()?,
debug_open_shutter_doors: bytes[61] != 0, debug_open_shutter_doors: bytes[60] != 0,
debug_force_enemy_damage_zero: bytes[62] != 0, debug_force_enemy_damage_zero: bytes[61] != 0,
debug_show_room_id_in_rupee_counter: bytes[63] != 0, debug_show_room_id_in_rupee_counter: bytes[62] != 0,
o_h_k_o: bytes[64] != 0, o_h_k_o: bytes[63] != 0,
randomize_tile_trap_pattern: bytes[65] != 0, randomize_tile_trap_pattern: bytes[64] != 0,
randomize_tile_trap_floor_tile: bytes[66] != 0, randomize_tile_trap_floor_tile: bytes[65] != 0,
allow_killable_thief: bytes[67] != 0, allow_killable_thief: bytes[66] != 0,
randomize_sprite_on_hit: bytes[68] != 0, randomize_sprite_on_hit: bytes[67] != 0,
hero_mode: bytes[69] != 0, hero_mode: bytes[68] != 0,
increase_brightness: bytes[70] != 0, increase_brightness: bytes[69] != 0,
mute_music_enable_msu_1: bytes[71] != 0, mute_music_enable_msu_1: bytes[70] != 0,
agahnim_bounce_balls: bytes[72] != 0, agahnim_bounce_balls: bytes[71] != 0,
..Default::default() ..Default::default()
}) })
} }
@ -543,90 +431,20 @@ impl OptionFlags {
bytes.push(self.enemies_absorbable as u8); bytes.push(self.enemies_absorbable as u8);
bytes.push(self.absorbable_spawn_rate); bytes.push(self.absorbable_spawn_rate);
bytes.push( bytes.push(self.absorbable_types.get(&AbsorbableType::Heart).copied().unwrap_or(false) as u8);
self.absorbable_types bytes.push(self.absorbable_types.get(&AbsorbableType::GreenRupee).copied().unwrap_or(false) as u8);
.get(&AbsorbableType::Heart) bytes.push(self.absorbable_types.get(&AbsorbableType::BlueRupee).copied().unwrap_or(false) as u8);
.copied() bytes.push(self.absorbable_types.get(&AbsorbableType::RedRupee).copied().unwrap_or(false) as u8);
.unwrap_or(false) as u8, bytes.push(self.absorbable_types.get(&AbsorbableType::Bomb1).copied().unwrap_or(false) as u8);
); bytes.push(self.absorbable_types.get(&AbsorbableType::Bomb4).copied().unwrap_or(false) as u8);
bytes.push( bytes.push(self.absorbable_types.get(&AbsorbableType::Bomb8).copied().unwrap_or(false) as u8);
self.absorbable_types bytes.push(self.absorbable_types.get(&AbsorbableType::SmallMagic).copied().unwrap_or(false) as u8);
.get(&AbsorbableType::GreenRupee) bytes.push(self.absorbable_types.get(&AbsorbableType::FullMagic).copied().unwrap_or(false) as u8);
.copied() bytes.push(self.absorbable_types.get(&AbsorbableType::Arrow5).copied().unwrap_or(false) as u8);
.unwrap_or(false) as u8, bytes.push(self.absorbable_types.get(&AbsorbableType::Arrow10).copied().unwrap_or(false) as u8);
); bytes.push(self.absorbable_types.get(&AbsorbableType::Fairy).copied().unwrap_or(false) as u8);
bytes.push( bytes.push(self.absorbable_types.get(&AbsorbableType::Key).copied().unwrap_or(false) as u8);
self.absorbable_types bytes.push(self.absorbable_types.get(&AbsorbableType::BigKey).copied().unwrap_or(false) as u8);
.get(&AbsorbableType::BlueRupee)
.copied()
.unwrap_or(false) as u8,
);
bytes.push(
self.absorbable_types
.get(&AbsorbableType::RedRupee)
.copied()
.unwrap_or(false) as u8,
);
bytes.push(
self.absorbable_types
.get(&AbsorbableType::Bomb1)
.copied()
.unwrap_or(false) as u8,
);
bytes.push(
self.absorbable_types
.get(&AbsorbableType::Bomb4)
.copied()
.unwrap_or(false) as u8,
);
bytes.push(
self.absorbable_types
.get(&AbsorbableType::Bomb8)
.copied()
.unwrap_or(false) as u8,
);
bytes.push(
self.absorbable_types
.get(&AbsorbableType::SmallMagic)
.copied()
.unwrap_or(false) as u8,
);
bytes.push(
self.absorbable_types
.get(&AbsorbableType::FullMagic)
.copied()
.unwrap_or(false) as u8,
);
bytes.push(
self.absorbable_types
.get(&AbsorbableType::Arrow5)
.copied()
.unwrap_or(false) as u8,
);
bytes.push(
self.absorbable_types
.get(&AbsorbableType::Arrow10)
.copied()
.unwrap_or(false) as u8,
);
bytes.push(
self.absorbable_types
.get(&AbsorbableType::Fairy)
.copied()
.unwrap_or(false) as u8,
);
bytes.push(
self.absorbable_types
.get(&AbsorbableType::Key)
.copied()
.unwrap_or(false) as u8,
);
bytes.push(
self.absorbable_types
.get(&AbsorbableType::BigKey)
.copied()
.unwrap_or(false) as u8,
);
bytes.push(self.boss_madness as u8); bytes.push(self.boss_madness as u8);
bytes.push(self.randomize_bosses as u8); bytes.push(self.randomize_bosses as u8);

View file

@ -1,22 +1,19 @@
use std::path::Path; use std::collections::HashMap;
use anyhow::ensure; use anyhow::{ensure, Result};
use crate::option_flags::OptionFlags; use crate::option_flags::OptionFlags;
use crate::rom::RomData; use crate::rom::RomData;
use crate::PatchSet;
pub struct Randomization {
rom: RomData,
option_flags: OptionFlags,
bosses_gfx_index: HashMap<String, u8>,
}
impl RomData { impl RomData {
pub fn randomize( pub fn randomize(&mut self, option_flags: OptionFlags, seed: i32) -> anyhow::Result<()> {
&mut self, ensure!(self.is_randomizer(), "Enemizer only supports randomizer ROMs for input.");
base_patch: &Path,
option_flags: OptionFlags,
seed: i32,
) -> anyhow::Result<()> {
ensure!(
self.is_randomizer(),
"Enemizer only supports randomizer ROMs for input."
);
ensure!(!self.is_race(), "Enemizer does not support race roms."); ensure!(!self.is_race(), "Enemizer does not support race roms.");
if self.is_enemizer() { if self.is_enemizer() {
@ -26,12 +23,8 @@ impl RomData {
self.set_enemizer_seed(seed); self.set_enemizer_seed(seed);
} }
self.expand_rom();
self.set_info_flags(option_flags)?; self.set_info_flags(option_flags)?;
let patches = PatchSet::load(base_patch)?;
patches.patch_rom(self);
Ok(()) Ok(())
} }
} }

View file

@ -4,15 +4,14 @@ use std::ops::Range;
use anyhow::bail; use anyhow::bail;
use crate::asar::{pc_to_snes_address, snes_to_pc_address, Symbols}; use crate::asar::{Symbols, snes_to_pc_address, pc_to_snes_address};
use crate::constants::*; use crate::constants::*;
use crate::option_flags::OptionFlags; use crate::option_flags::OptionFlags;
use crate::Patch; use crate::Patch;
pub const ENEMIZER_INFO_SEED_OFFSET: usize = 0; pub const ENEMIZER_INFO_SEED_OFFSET: usize = 0;
pub const ENEMIZER_INFO_SEED_LENGTH: usize = 12; pub const ENEMIZER_INFO_SEED_LENGTH: usize = 12;
pub const ENEMIZER_INFO_VERSION_OFFSET: usize = pub const ENEMIZER_INFO_VERSION_OFFSET: usize = ENEMIZER_INFO_SEED_OFFSET + ENEMIZER_INFO_SEED_LENGTH;
ENEMIZER_INFO_SEED_OFFSET + ENEMIZER_INFO_SEED_LENGTH;
pub const ENEMIZER_INFO_VERSION_LENGTH: usize = 8; pub const ENEMIZER_INFO_VERSION_LENGTH: usize = 8;
pub const ENEMIZER_INFO_FLAGS_OFFSET: usize = pub const ENEMIZER_INFO_FLAGS_OFFSET: usize =
ENEMIZER_INFO_VERSION_OFFSET + ENEMIZER_INFO_VERSION_LENGTH; ENEMIZER_INFO_VERSION_OFFSET + ENEMIZER_INFO_VERSION_LENGTH;
@ -49,8 +48,7 @@ impl RomData {
self.rom_data[ROOM_HEADER_BANK_LOCATION] = 0x04; self.rom_data[ROOM_HEADER_BANK_LOCATION] = 0x04;
let dungeon_header_range = let dungeon_header_range = DUNGEON_HEADER_POINTER_TABLE..(DUNGEON_HEADER_POINTER_TABLE + 640);
DUNGEON_HEADER_POINTER_TABLE..(DUNGEON_HEADER_POINTER_TABLE + 640);
self.rom_data[dungeon_header_range].copy_from_slice(&ORIGINAL_ROOM_POINTERS); self.rom_data[dungeon_header_range].copy_from_slice(&ORIGINAL_ROOM_POINTERS);
let room_range = 0x5B97..(0x5B97 + 576); let room_range = 0x5B97..(0x5B97 + 576);
@ -66,73 +64,61 @@ impl RomData {
let mut patches = vec![]; let mut patches = vec![];
for (&addr, &byte) in self.patch_data.iter() { for (&addr, &byte) in self.patch_data.iter() {
match patches match patches.last_mut().filter(|p: &&mut Patch| p.address + 1 == addr) {
.last_mut() None => patches.push(Patch { address: addr, patch_data: vec![byte] }),
.filter(|p: &&mut Patch| p.address + 1 == addr) Some(patch) => patch.patch_data.push(byte)
{
None => patches.push(Patch {
address: addr,
patch_data: vec![byte],
}),
Some(patch) => patch.patch_data.push(byte),
} }
} }
patches patches
} }
pub fn get_rom_bytes(&self) -> &[u8] {
&self.rom_data
}
fn set_rom_bytes(&mut self, bytes: &[u8], range: Range<usize>) { fn set_rom_bytes(&mut self, bytes: &[u8], range: Range<usize>) {
self.rom_data.splice(range, bytes.into_iter().map(|&b| b)); self.rom_data.splice(range, bytes.into_iter().map(|&b| b));
} }
fn set_patch_bytes(&mut self, range: Range<usize>) { fn set_patch_bytes(&mut self, range: Range<usize>) {
let slice = &self.rom_data[range.clone()]; let slice = &self.rom_data[range.clone()];
self.patch_data self.patch_data.extend(iter::zip(range, slice.into_iter().map(|&b| b)));
.extend(iter::zip(range, slice.into_iter().map(|&b| b)));
} }
pub fn is_enemizer(&self) -> bool { pub fn is_enemizer(&self) -> bool {
self.rom_data.len() == ENEMIZER_FILE_LENGTH self.rom_data.len() == ENEMIZER_FILE_LENGTH
&& self.rom_data[self.asar_symbols["enemizer_info_table"] + ENEMIZER_INFO_SEED_OFFSET] && self.rom_data[self.asar_symbols["enemizer_info_table"] + ENEMIZER_INFO_SEED_OFFSET] == b'E'
== b'E' && self.rom_data[self.asar_symbols["enemizer_info_table"] + ENEMIZER_INFO_SEED_OFFSET + 1] == b'N'
&& self.rom_data
[self.asar_symbols["enemizer_info_table"] + ENEMIZER_INFO_SEED_OFFSET + 1]
== b'N'
} }
pub fn is_randomizer(&self) -> bool { pub fn is_randomizer(&self) -> bool {
let acceptable = [ let acceptable = [
b"VT", // item rando // item rando
b"ER", // entrance rando b"VT",
b"DR", // door rando // entrance rando
b"BM", // Berserker's multiworld b"ER",
b"BD", // Berserker's multiworld doors // door rando
b"AP", // Archipelago b"DR",
b"AD", // Archipelago with door rando // Berserker's multiworld
b"BM",
// Berserker's multiworld doors
b"BD",
// Archipelago
b"AP",
// Archipelago with door rando
b"AD",
]; ];
acceptable acceptable.iter().any(|abbr| &abbr[..] == &self.rom_data[0x7FC0..0x7Fc1]) ||
.iter() (self.rom_data.len() >= 0x20_0000 &&
.any(|abbr| &abbr[..] == &self.rom_data[0x7FC0..0x7Fc1]) &self.rom_data[0x7FC0..0x7FCE] == b"ZELDANODENSETSU")
|| (self.rom_data.len() >= 0x20_0000
&& &self.rom_data[0x7FC0..0x7FCE] == b"ZELDANODENSETSU")
} }
pub fn is_race(&self) -> bool { pub fn is_race(&self) -> bool {
self.is_randomizer() self.is_randomizer() &&
&& (&self.rom_data[0x180213..0x180214] == &[1, 0] (&self.rom_data[0x180213..0x180214] == &[1, 0] ||
|| &self.rom_data[0x7FC0..0x7FC9] == b"VT TOURNEY") &self.rom_data[0x7FC0..0x7FC9] == b"VT TOURNEY")
} }
fn assert_rom_length(&self) { fn assert_rom_length(&self) {
assert!( assert!(self.rom_data.len() >= ENEMIZER_FILE_LENGTH, "You need to expand the rom before you can use Enemizer features.");
self.rom_data.len() >= ENEMIZER_FILE_LENGTH,
"You need to expand the rom before you can use Enemizer features."
);
} }
pub fn get_enemizer_seed(&self) -> i32 { pub fn get_enemizer_seed(&self) -> i32 {
@ -177,12 +163,9 @@ impl RomData {
pub fn get_enemizer_version(&self) -> anyhow::Result<&str> { pub fn get_enemizer_version(&self) -> anyhow::Result<&str> {
if self.is_enemizer() { if self.is_enemizer() {
let version_start = let version_start = self.asar_symbols["enemizer_info_table"] + ENEMIZER_INFO_VERSION_OFFSET;
self.asar_symbols["enemizer_info_table"] + ENEMIZER_INFO_VERSION_OFFSET;
let version_end = version_start + ENEMIZER_INFO_VERSION_LENGTH; let version_end = version_start + ENEMIZER_INFO_VERSION_LENGTH;
Ok(std::str::from_utf8( Ok(std::str::from_utf8(&self.rom_data[version_start..version_end])?)
&self.rom_data[version_start..version_end],
)?)
} else { } else {
bail!("Not Enemizer Rom") bail!("Not Enemizer Rom")
} }
@ -200,7 +183,7 @@ impl RomData {
self.set_patch_bytes(version_start..version_end) self.set_patch_bytes(version_start..version_end)
} }
pub fn set_info_flags(&mut self, flags: OptionFlags) -> anyhow::Result<()> { pub fn set_info_flags(&mut self, flags: OptionFlags) -> anyhow::Result<()>{
let bytes = flags.into_bytes(); let bytes = flags.into_bytes();
if bytes.len() > 0x100 - ENEMIZER_INFO_FLAGS_OFFSET { if bytes.len() > 0x100 - ENEMIZER_INFO_FLAGS_OFFSET {
bail!("Option flags is too long to fit in the space allocated. Need to move data/code in asm file."); bail!("Option flags is too long to fit in the space allocated. Need to move data/code in asm file.");
@ -259,11 +242,10 @@ impl RomData {
pub fn move_room_headers(&mut self) { pub fn move_room_headers(&mut self) {
let table_base = DUNGEON_HEADER_POINTER_TABLE; let table_base = DUNGEON_HEADER_POINTER_TABLE;
let header_base = self.asar_symbols["room_header_table"]; let header_base = self.asar_symbols["rom_header_table"];
// Change room header bank (at 0xB5E7) to 0x04. // Change room header bank (at 0xB5E7) to 0x04.
let new_room_bank = let new_room_bank = self.rom_data[self.asar_symbols["moved_room_header_bank_value_address"]];
self.rom_data[self.asar_symbols["moved_room_header_bank_value_address"]];
self.rom_data[ROOM_HEADER_BANK_LOCATION] = new_room_bank; self.rom_data[ROOM_HEADER_BANK_LOCATION] = new_room_bank;
// Copy header table. // Copy header table.
@ -274,15 +256,14 @@ impl RomData {
self.rom_data[table_base + (i * 2)], self.rom_data[table_base + (i * 2)],
self.rom_data[table_base + (i * 2) + 1], self.rom_data[table_base + (i * 2) + 1],
4, 4,
0, 0
]; ];
let snes_address = u32::from_le_bytes(room_pointer); let snes_address = u32::from_le_bytes(room_pointer);
let pc_address = snes_to_pc_address(snes_address); let pc_address = snes_to_pc_address(snes_address);
// Copy i'th room's headers to new room_header_table. // Copy i'th room's headers to new room_header_table.
let header_start = header_base + (i * 14); let header_start = header_base + (i * 14);
self.rom_data self.rom_data.copy_within(pc_address..(pc_address + 14), header_start);
.copy_within(pc_address..(pc_address + 14), header_start);
} }
// Repoint the pointer table to the new header table. // Repoint the pointer table to the new header table.
@ -291,8 +272,7 @@ impl RomData {
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."); 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)] self.rom_data[(table_base + (i * 2))..(table_base + (i * 2) + 1)].copy_from_slice(&snes[0..1]);
.copy_from_slice(&snes[0..1]);
} }
} }
} }

View file

@ -1,8 +0,0 @@
#!/bin/sh
if [[ ! -s base_patch.json || ! -s asar_symbols.txt ]]; then
cargo run -p bin_comp -- assembly/src/main.asm base_patch.json asar_symbols.txt
fi
if [[ ! -s enemizer_base_patch.json ]]; then
cargo run -p base_patch_generator -- "$1" base_patch.json asar_symbols.txt enemizer_base_patch.json
fi