Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions patches/rom_map/Bank DF.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,7 @@ FEF0 - FEFF: seed name (null-terminated ASCII string)
FF04 - FF04: [FREE]
FF05 - FF06: randomizer settings:
- bitmask $0001: walljump-boots item enabled
- bitmask $0002: split speedbooster item enabled
FF07 - FF08: number of frames of artificial lag to add to the unpause black screen
FF09 - FF0D: randomizer settings: skill/progression/qol/objectives/maplayout (autotracker use)
- stored as single byte ordinal numbers, if a setting has a custom option then byte is set to 0
80 changes: 78 additions & 2 deletions rust/maprando/src/patch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ use crate::{
randomize::{LockedDoor, Randomization, get_starting_items},
settings::{
AreaAssignmentPreset, CrashFixes, CrashFixesPreset, DisableETankSetting, ETankRefill,
EnemyDrops, Fanfares, FixMode, ItemCount, MotherBrainFight, Objective, ObjectiveScreen,
RandomizerSettings, SaveAnimals, SpeedBooster, StartLocationMode, WallJump,
EnemyDrops, Fanfares, FixMode, ItemCount, MapPreset, MotherBrainFight, ObjPreset,
Objective, ObjectiveScreen, ProgressionPreset, QolPreset, RandomizerSettings, SaveAnimals,
SkillPreset, SpeedBooster, StartLocationMode, WallJump,
},
};
use anyhow::{Context, Result, bail, ensure};
Expand Down Expand Up @@ -747,6 +748,7 @@ impl Patcher<'_> {
// For now this is just to indicate if walljump-boots exists as an item,
// and if Speed Booster is split into Blue Booster and Spark Booster.
let mut settings_flag = 0x0000;

if self.settings.other_settings.wall_jump == WallJump::Collectible {
settings_flag |= 0x0001;
}
Expand Down Expand Up @@ -1987,6 +1989,75 @@ impl Patcher<'_> {
Ok(())
}

fn write_autotracker_skill_setting(&mut self) -> Result<()> {
let settings = &self.settings.skill_assumption_settings;

let value: u8 = settings
.preset
.as_deref()
.and_then(SkillPreset::from_preset)
.map(SkillPreset::to_byte)
.unwrap_or(0);

self.rom.write_u8(snes2pc(0xdfff09), value as isize)?;

Ok(())
}

fn write_autotracker_item_progression(&mut self) -> Result<()> {
let settings = &self.settings.item_progression_settings;

let value: u8 = settings
.preset
.as_deref()
.and_then(ProgressionPreset::from_preset)
.map(ProgressionPreset::to_byte)
.unwrap_or(0);

self.rom.write_u8(snes2pc(0xdfff0a), value as isize)?;

Ok(())
}

fn write_autotracker_qol_setting(&mut self) -> Result<()> {
let settings = &self.settings.quality_of_life_settings;

let value: u8 = settings
.preset
.as_deref()
.and_then(QolPreset::from_preset)
.map(QolPreset::to_byte)
.unwrap_or(0);

self.rom.write_u8(snes2pc(0xdfff0b), value as isize)?;

Ok(())
}

fn write_autotracker_objective_setting(&mut self) -> Result<()> {
let settings = &self.settings.objective_settings;

let value: u8 = settings
.preset
.as_deref()
.and_then(ObjPreset::from_preset)
.map(ObjPreset::to_byte)
.unwrap_or(0);

self.rom.write_u8(snes2pc(0xdfff0c), value as isize)?;

Ok(())
}

fn write_autotracker_map_layout(&mut self) -> Result<()> {
let value: u8 = MapPreset::from_preset(&self.settings.map_layout)
.map(MapPreset::to_byte)
.unwrap_or(0);
self.rom.write_u8(snes2pc(0xdfff0d), value as isize)?;

Ok(())
}

fn apply_seed_identifiers(&mut self) -> Result<()> {
let cartridge_name = "SUPERMETROID MAPRANDO";
self.rom.write_n(0x7FC0, cartridge_name.as_bytes())?;
Expand Down Expand Up @@ -3642,6 +3713,11 @@ pub fn make_rom(
patcher.apply_mother_brain_fight_patches()?;
patcher.write_custom_item_graphics()?;
patcher.write_objective_data()?;
patcher.write_autotracker_skill_setting()?;
patcher.write_autotracker_item_progression()?;
patcher.write_autotracker_qol_setting()?;
patcher.write_autotracker_objective_setting()?;
patcher.write_autotracker_map_layout()?;
patcher.apply_seed_identifiers()?;
patcher.apply_credits()?;
if randomizer_settings.quality_of_life_settings.hazard_markers {
Expand Down
147 changes: 147 additions & 0 deletions rust/maprando/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,153 @@ pub struct ItemProgressionSettings {
pub filler_items: Vec<FillerItemPrioritySetting>,
}

#[repr(u8)]
#[derive(Serialize, Deserialize, Clone, PartialEq)]
pub enum SkillPreset {
Basic = 1,
Medium = 2,
Hard = 3,
VeryHard = 4,
Expert = 5,
ExpertPlus = 6,
Extreme = 7,
ExtremePlus = 8,
Insane = 9,
InsanePlus = 10,
}

impl SkillPreset {
pub fn from_preset(s: &str) -> Option<Self> {
match s.trim().to_lowercase().as_str() {
"basic" => Some(Self::Basic),
"medium" => Some(Self::Medium),
"hard" => Some(Self::Hard),
"very hard" => Some(Self::VeryHard),
"expert" => Some(Self::Expert),
"expert+" => Some(Self::ExpertPlus),
"extreme" => Some(Self::Extreme),
"extreme+" => Some(Self::ExtremePlus),
"insane" => Some(Self::Insane),
"insane+" => Some(Self::InsanePlus),
_ => None,
}
}

pub fn to_byte(self) -> u8 {
self as u8
}
}

#[repr(u8)]
#[derive(Serialize, Deserialize, Clone, PartialEq)]
pub enum QolPreset {
Off = 1,
Low = 2,
Default = 3,
High = 4,
Max = 5,
}

impl QolPreset {
pub fn from_preset(s: &str) -> Option<Self> {
match s.trim().to_lowercase().as_str() {
"off" => Some(Self::Off),
"low" => Some(Self::Low),
"default" => Some(Self::Default),
"high" => Some(Self::High),
"max" => Some(Self::Max),
_ => None,
}
}

pub fn to_byte(self) -> u8 {
self as u8
}
}

#[repr(u8)]
#[derive(Serialize, Deserialize, Clone, PartialEq)]
pub enum ObjPreset {
None = 1,
Bosses = 2,
MiniBosses = 3,
Chozos = 4,
Pirates = 5,
Metroids = 6,
Random = 7,
}

impl ObjPreset {
pub fn from_preset(s: &str) -> Option<Self> {
match s.trim().to_lowercase().as_str() {
"none" => Some(Self::None),
"bosses" => Some(Self::Bosses),
"minibosses" => Some(Self::MiniBosses),
"chozos" => Some(Self::Chozos),
"pirates" => Some(Self::Pirates),
"metroids" => Some(Self::Metroids),
"random" => Some(Self::Random),
_ => None,
}
}

pub fn to_byte(self) -> u8 {
self as u8
}
}

#[repr(u8)]
#[derive(Serialize, Deserialize, Clone, PartialEq)]
pub enum ProgressionPreset {
Normal = 1,
Tricky = 2,
Technical = 3,
Challenge = 4,
Desolate = 5,
}

impl ProgressionPreset {
pub fn from_preset(s: &str) -> Option<Self> {
match s.trim().to_lowercase().as_str() {
"normal" => Some(Self::Normal),
"tricky" => Some(Self::Tricky),
"technical" => Some(Self::Technical),
"challenge" => Some(Self::Challenge),
"desolate" => Some(Self::Desolate),
_ => None,
}
}

pub fn to_byte(self) -> u8 {
self as u8
}
}

#[repr(u8)]
#[derive(Serialize, Deserialize, Clone, PartialEq)]
pub enum MapPreset {
Vanilla = 1,
Small = 2,
Standard = 3,
Wild = 4,
}

impl MapPreset {
pub fn from_preset(s: &str) -> Option<Self> {
match s.trim().to_lowercase().as_str() {
"vanilla" => Some(Self::Vanilla),
"small" => Some(Self::Small),
"standard" => Some(Self::Standard),
"wild" => Some(Self::Wild),
_ => None,
}
}

pub fn to_byte(self) -> u8 {
self as u8
}
}

#[derive(Serialize, Deserialize, Clone, PartialEq)]
pub struct ItemCount {
pub item: Item,
Expand Down
Loading