diff --git a/Cargo.lock b/Cargo.lock index 9d8f9d7..d5d400f 100755 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,11 +14,22 @@ version = "0.1.0" source = "git+https://github.com/CryZe/asr#4949bad1925169ce2382ff6378e56e6ece02b0c8" dependencies = [ "arrayvec", + "asr-derive", "bytemuck", "itoa", "time", ] +[[package]] +name = "asr-derive" +version = "0.1.0" +source = "git+https://github.com/CryZe/asr#4949bad1925169ce2382ff6378e56e6ece02b0c8" +dependencies = [ + "heck", + "quote", + "syn 2.0.10", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -57,6 +68,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "itoa" version = "1.0.6" diff --git a/Cargo.toml b/Cargo.toml index e9c1bb3..928de7e 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -asr = { git = "https://github.com/CryZe/asr", features = ["integer-vars", "strings"] } +asr = { git = "https://github.com/CryZe/asr", features = ["integer-vars", "strings", "derive"] } bitflags = "1.3.2" bytemuck = "1.12.1" spinning_top = "0.2.3" diff --git a/src/data/mod.rs b/src/data/mod.rs index b59c12c..8b13789 100755 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -1 +1 @@ -pub mod zone; + diff --git a/src/data/zone.rs b/src/data/zone.rs index 1759a3f..1e31cc4 100755 --- a/src/data/zone.rs +++ b/src/data/zone.rs @@ -1,7 +1,9 @@ use phf::phf_map; +use crate::Character; pub struct ZoneDescription { name: &'static str, + character: Character; region: &'static str, ring: u8, } diff --git a/src/lib.rs b/src/lib.rs index e4af0a5..fb939f8 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,15 +2,18 @@ use spinning_top::{const_spinlock, Spinlock}; use std::collections::HashSet; use std::fmt::{Display, Formatter, Result}; -use std::env; +mod data; +mod settings; +mod splits; +use settings::Settings; use bytemuck::Pod; use asr::{ + get_os, timer::{self, TimerState}, watcher::Pair, Address, Process, - get_os }; // mod data; @@ -42,6 +45,8 @@ struct Game { module: u64, splits: HashSet, game_state: Watcher, + agnea_progress: Watcher, + settings: Settings, start: Watcher, } @@ -51,7 +56,9 @@ impl Game { process, module, start: Watcher::new(vec![0x5219628, 0xA8]), + settings: Settings::register(), game_state: Watcher::new(vec![0x4F7AB68, 0x234]), + agnea_progress: Watcher::new(vec![0x4F7AB30, 0x2D8, 0x708, 0x690 + 0xEC]), splits: HashSet::new(), }; Some(game) @@ -61,6 +68,8 @@ impl Game { Some(Vars { start: self.start.update(&self.process, self.module)?, game_state: self.game_state.update(&self.process, self.module)?, + agnea_progress: self.agnea_progress.update(&self.process, self.module)?, + settings: &self.settings, splits: &mut self.splits, }) } @@ -70,7 +79,7 @@ pub struct State { game: Option, } -// This enum maps to the SavePlayerCharacterData +// This enum maps to the SavePlayerCharacterData #[derive(Default, PartialEq)] pub enum Character { #[default] @@ -101,26 +110,37 @@ impl Display for Character { } } -#[derive(Default)] -pub struct Flags { - char_chapter_ending: Character, -} +// #[derive(Default)] +// pub struct Flags { +// char_chapter_ending: Character, +// } #[allow(unused)] -struct Vars<'a> { +pub struct Vars<'a> { start: &'a Pair, game_state: &'a Pair, + agnea_progress: &'a Pair, + settings: &'a Settings, splits: &'a mut HashSet, } impl Vars<'_> { - fn split(&mut self, key: &str) -> Option { + fn split(&mut self, key: &str, settings_field: bool) -> Option { if self.splits.contains(key) { return None; } + self.splits.insert(key.to_string()); - Some(key.to_string()) + // only split if in settings + if settings_field { + return Some(key.to_string()); + } + + None + } + fn clear_splits(&mut self) { + self.splits.clear() } } @@ -134,7 +154,7 @@ pub extern "C" fn update() { let process_for_os = match os.as_str() { "windows" => "Octopath_Traveler2", "linux" => "Octopath_Travel", - _ => "Octopath_Traveler2" + _ => "Octopath_Traveler2", }; match Process::attach(process_for_os) { Some(process) => { @@ -156,38 +176,35 @@ pub extern "C" fn update() { state.game = None; return; } - if let Some(vars) = game.update_vars() { - // timer::set_variable_int("Encounters", *vars.encounters); - // timer::set_variable_int("Deaths", *vars.deaths); + + if let Some(mut vars) = game.update_vars() { match timer::state() { TimerState::NotRunning => { - if vars.game_state.current == 1 && vars.start.old == 0 && vars.start.current == 1 { - // *vars.deaths = 0; - // *vars.encounters = 0; - // *vars.splits = Default::default(); - // *vars.flags = Default::default(); + vars.clear_splits(); + if vars.game_state.current == 1 + && vars.start.old == 0 + && vars.start.current == 1 + { timer::start() } } TimerState::Running => { - // if let Some(reason) = should_split(&mut vars) { - // asr::print_message(&reason); - // timer::split(); - // } - // if vars.game_state.current == 6 && vars.game_state.old == 2 { - // *vars.encounters = *vars.encounters + 1; - // } - // if vars.game_state.current == 7 && vars.game_state.old == 6 { - // *vars.deaths = *vars.deaths + 1; - // } + if let Some(reason) = should_split(&mut vars) { + asr::print_message(&reason); + timer::split(); + } } _ => {} } } - } } fn should_split(vars: &mut Vars) -> Option { + // Agnea + if let Some(split) = splits::agnea::AgneaSplits::chapter_split(vars) { + return Some(split); + } + None } diff --git a/src/settings.rs b/src/settings.rs new file mode 100644 index 0000000..8dd991b --- /dev/null +++ b/src/settings.rs @@ -0,0 +1,234 @@ +#[derive(asr::Settings)] +pub struct Settings { + #[default = false] + /// Agnea 1 - Dreams of Stardom + pub agnea_10: bool, + #[default = false] + /// Agnea 1 - The Village Dancer + pub agnea_20: bool, + #[default = false] + /// Agnea 1 - Seeing Off the Patrons + pub agnea_30: bool, + #[default = false] + /// Agnea 1 - The Tavern After Closing + pub agnea_40: bool, + #[default = false] + /// Agnea 1 - Dancing on Air + pub agnea_50: bool, + #[default = false] + /// Agnea 1 - Telling Papa the News + pub agnea_60: bool, + #[default = false] + /// Agnea 1 - Cuani the Star + pub agnea_70: bool, + #[default = false] + /// Agnea 1 - Memories of Mama + pub agnea_80: bool, + #[default = false] + /// Agnea 1 - Nothing Special + pub agnea_90: bool, + #[default = false] + /// Agnea 1 - Preparing for the Festival + pub agnea_100: bool, + #[default = false] + /// Agnea 1 - Pala's Gone Missing + pub agnea_110: bool, + #[default = false] + /// Agnea 1 - The Raging Duorduor + pub agnea_120: bool, + #[default = false] + /// Agnea 1 - A Dress Ruined + pub agnea_130: bool, + #[default = false] + /// Agnea 1 - I Can Still Dance + pub agnea_140: bool, + #[default = false] + /// Agnea 1 - Mama's Dress + pub agnea_150: bool, + #[default = false] + /// Agnea 1 - Mama's Song + pub agnea_160: bool, + #[default = false] + /// Agnea 1 - The Morning of Departure + pub agnea_170: bool, + #[default = false] + /// Agnea 1 - We Will Meet Again Someday + pub agnea_500: bool, + #[default = false] + /// Agnea 2 - The Metropolis + pub agnea_510: bool, + #[default = false] + /// Agnea 2 - The Theater + pub agnea_520: bool, + #[default = false] + /// Agnea 2 - Into the Theater + pub agnea_550: bool, + #[default = false] + /// Agnea 2 - The Show Begins + pub agnea_560: bool, + #[default = false] + /// Agnea 2 - Greatest Dancer in the Land + pub agnea_570: bool, + #[default = false] + /// Agnea 2 - Gil the Pianist + pub agnea_580: bool, + #[default = false] + /// Agnea 2 - Montraine's Tavern + pub agnea_590: bool, + #[default = false] + /// Agnea 2 - A Show at the Tavern + pub agnea_600: bool, + #[default = false] + /// Agnea 2 - Agnea the House Dancer + pub agnea_610: bool, + #[default = false] + /// Agnea 2 - An Arrogant Man + pub agnea_620: bool, + #[default = false] + /// Agnea 2 - Shattered Hopes + pub agnea_630: bool, + #[default = false] + /// Agnea 2 - Finding the Manager + pub agnea_640: bool, + #[default = false] + /// Agnea 2 - Manager Found + pub agnea_650: bool, + #[default = false] + /// Agnea 2 - For Hope + pub agnea_660: bool, + #[default = false] + /// Agnea 2 - Shining Superstar + pub agnea_670: bool, + #[default = false] + /// Agnea 2 - Hope Protected + pub agnea_680: bool, + #[default = false] + /// Agnea 2 - A Gift From Gil + pub agnea_690: bool, + #[default = false] + /// Agnea 2 - Song of Hope + pub agnea_700: bool, + #[default = false] + /// Agnea 2 - Dolcinaea's Plan + pub agnea_1000: bool, + #[default = false] + /// Agnea 3 - The Traveling Troupe + pub agnea_1010: bool, + #[default = false] + /// Agnea 3 - Giselle's Troupe + pub agnea_1030: bool, + #[default = false] + /// Agnea 3 - The Missing Troupe Leader + pub agnea_1040: bool, + #[default = false] + /// Agnea 3 - The Pressure of the Stage + pub agnea_1050: bool, + #[default = false] + /// Agnea 3 - Even If You Stumble + pub agnea_1060: bool, + #[default = false] + /// Agnea 3 - The Show Goes On + pub agnea_1070: bool, + #[default = false] + /// Agnea 3 - A Celebratory Drink + pub agnea_1080: bool, + #[default = false] + /// Agnea 3 - Promises of Reunion + pub agnea_1500: bool, + #[default = false] + /// Agnea 4 - Where Mama Was + pub agnea_1510: bool, + #[default = false] + /// Agnea 4 - A Mischievous Child + pub agnea_1520: bool, + #[default = false] + /// Agnea 4 - Hope at Risk + pub agnea_1530: bool, + #[default = false] + /// Agnea 4 - Laila Leaves Home + pub agnea_1540: bool, + #[default = false] + /// Agnea 4 - Having Fun + pub agnea_1550: bool, + #[default = false] + /// Agnea 4 - In Step + pub agnea_1580: bool, + #[default = false] + /// Agnea 4 - The Joy of Dancing + pub agnea_1590: bool, + #[default = false] + /// Agnea 4 - Cuani and Dolcinaea + pub agnea_1600: bool, + #[default = false] + /// Agnea 4 - A Town in Trouble + pub agnea_1610: bool, + #[default = false] + /// Agnea 4 - No Mercy + pub agnea_1620: bool, + #[default = false] + /// Agnea 4 - Dolcinaealand + pub agnea_1630: bool, + #[default = false] + /// Agnea 4 - A True Star + pub agnea_1640: bool, + #[default = false] + /// Agnea 4 - Invitation to the Grand Gala + pub agnea_1650: bool, + #[default = false] + /// Agnea 4 - Laila's Dance + pub agnea_1660: bool, + #[default = false] + /// Agnea 4 - Parting from Laila + pub agnea_2000: bool, + #[default = false] + /// Agnea 5 - Center of Attention + pub agnea_2010: bool, + #[default = false] + /// Agnea 5 - To the Grand Gala's Stage + pub agnea_2020: bool, + #[default = false] + /// Agnea 5 - The Mastermind + pub agnea_2030: bool, + #[default = false] + /// Agnea 5 - Reunited with Giselle's Troupe + pub agnea_2040: bool, + #[default = false] + /// Agnea 5 - Rush to the Stage + pub agnea_2050: bool, + #[default = false] + /// Agnea 5 - The Grandeur of the Stage + pub agnea_2060: bool, + #[default = false] + /// Agnea 5 - Gil and Laila's Show + pub agnea_2080: bool, + #[default = false] + /// Agnea 5 - A Bothered Bodyguard, a Star at Ease + pub agnea_2090: bool, + #[default = false] + /// Agnea 5 - The Manager's Resentment + pub agnea_2100: bool, + #[default = false] + /// Agnea 5 - The Festival of Grace + pub agnea_2110: bool, + #[default = false] + /// Agnea 5 - Showtime + pub agnea_2120: bool, + #[default = false] + /// Agnea 5 - Hope Rekindled + pub agnea_2130: bool, + #[default = false] + /// Agnea 5 - At the Dance Battle's End + pub agnea_2140: bool, + #[default = false] + /// Agnea 5 - A Star without Shine + pub agnea_2150: bool, + #[default = false] + /// Agnea 5 - Dolcinaea's Defeat + pub agnea_2160: bool, + #[default = false] + /// Agnea 5 - Encore + pub agnea_2170: bool, + #[default = false] + /// Agnea 5 - Agnea the Star + pub agnea_2500: bool, +} diff --git a/src/splits.rs b/src/splits.rs new file mode 100644 index 0000000..e0c2b77 --- /dev/null +++ b/src/splits.rs @@ -0,0 +1 @@ +pub mod agnea; diff --git a/src/splits/agnea.rs b/src/splits/agnea.rs new file mode 100644 index 0000000..9099a01 --- /dev/null +++ b/src/splits/agnea.rs @@ -0,0 +1,92 @@ +pub struct AgneaSplits; +use crate::Vars; + +impl AgneaSplits { + pub fn chapter_split(vars: &mut Vars) -> Option { + // checks if an old save is lingering, also make sure old zone id isn't 0 later + if vars.agnea_progress.old != vars.agnea_progress.current { + match vars.agnea_progress.current { + p if p == 10 => return vars.split("agnea_10", vars.settings.agnea_10), + p if p == 20 => return vars.split("agnea_20", vars.settings.agnea_20), + p if p == 30 => return vars.split("agnea_30", vars.settings.agnea_30), + p if p == 40 => return vars.split("agnea_40", vars.settings.agnea_40), + p if p == 50 => return vars.split("agnea_50", vars.settings.agnea_50), + p if p == 60 => return vars.split("agnea_60", vars.settings.agnea_60), + p if p == 70 => return vars.split("agnea_70", vars.settings.agnea_70), + p if p == 80 => return vars.split("agnea_80", vars.settings.agnea_80), + p if p == 90 => return vars.split("agnea_90", vars.settings.agnea_90), + p if p == 100 => return vars.split("agnea_100", vars.settings.agnea_100), + p if p == 110 => return vars.split("agnea_110", vars.settings.agnea_110), + p if p == 120 => return vars.split("agnea_120", vars.settings.agnea_120), + p if p == 130 => return vars.split("agnea_130", vars.settings.agnea_130), + p if p == 140 => return vars.split("agnea_140", vars.settings.agnea_140), + p if p == 150 => return vars.split("agnea_150", vars.settings.agnea_150), + p if p == 160 => return vars.split("agnea_160", vars.settings.agnea_160), + p if p == 170 => return vars.split("agnea_170", vars.settings.agnea_170), + p if p == 500 => return vars.split("agnea_500", vars.settings.agnea_500), + p if p == 510 => return vars.split("agnea_510", vars.settings.agnea_510), + p if p == 520 => return vars.split("agnea_520", vars.settings.agnea_520), + p if p == 550 => return vars.split("agnea_550", vars.settings.agnea_550), + p if p == 560 => return vars.split("agnea_560", vars.settings.agnea_560), + p if p == 570 => return vars.split("agnea_570", vars.settings.agnea_570), + p if p == 580 => return vars.split("agnea_580", vars.settings.agnea_580), + p if p == 590 => return vars.split("agnea_590", vars.settings.agnea_590), + p if p == 600 => return vars.split("agnea_600", vars.settings.agnea_600), + p if p == 610 => return vars.split("agnea_610", vars.settings.agnea_610), + p if p == 620 => return vars.split("agnea_620", vars.settings.agnea_620), + p if p == 630 => return vars.split("agnea_630", vars.settings.agnea_630), + p if p == 640 => return vars.split("agnea_640", vars.settings.agnea_640), + p if p == 650 => return vars.split("agnea_650", vars.settings.agnea_650), + p if p == 660 => return vars.split("agnea_660", vars.settings.agnea_660), + p if p == 670 => return vars.split("agnea_670", vars.settings.agnea_670), + p if p == 680 => return vars.split("agnea_680", vars.settings.agnea_680), + p if p == 690 => return vars.split("agnea_690", vars.settings.agnea_690), + p if p == 700 => return vars.split("agnea_700", vars.settings.agnea_700), + p if p == 1000 => return vars.split("agnea_1000", vars.settings.agnea_1000), + p if p == 1010 => return vars.split("agnea_1010", vars.settings.agnea_1010), + p if p == 1030 => return vars.split("agnea_1030", vars.settings.agnea_1030), + p if p == 1040 => return vars.split("agnea_1040", vars.settings.agnea_1040), + p if p == 1050 => return vars.split("agnea_1050", vars.settings.agnea_1050), + p if p == 1060 => return vars.split("agnea_1060", vars.settings.agnea_1060), + p if p == 1070 => return vars.split("agnea_1070", vars.settings.agnea_1070), + p if p == 1080 => return vars.split("agnea_1080", vars.settings.agnea_1080), + p if p == 1500 => return vars.split("agnea_1500", vars.settings.agnea_1500), + p if p == 1510 => return vars.split("agnea_1510", vars.settings.agnea_1510), + p if p == 1520 => return vars.split("agnea_1520", vars.settings.agnea_1520), + p if p == 1530 => return vars.split("agnea_1530", vars.settings.agnea_1530), + p if p == 1540 => return vars.split("agnea_1540", vars.settings.agnea_1540), + p if p == 1550 => return vars.split("agnea_1550", vars.settings.agnea_1550), + p if p == 1580 => return vars.split("agnea_1580", vars.settings.agnea_1580), + p if p == 1590 => return vars.split("agnea_1590", vars.settings.agnea_1590), + p if p == 1600 => return vars.split("agnea_1600", vars.settings.agnea_1600), + p if p == 1610 => return vars.split("agnea_1610", vars.settings.agnea_1610), + p if p == 1620 => return vars.split("agnea_1620", vars.settings.agnea_1620), + p if p == 1630 => return vars.split("agnea_1630", vars.settings.agnea_1630), + p if p == 1640 => return vars.split("agnea_1640", vars.settings.agnea_1640), + p if p == 1650 => return vars.split("agnea_1650", vars.settings.agnea_1650), + p if p == 1660 => return vars.split("agnea_1660", vars.settings.agnea_1660), + p if p == 2000 => return vars.split("agnea_2000", vars.settings.agnea_2000), + p if p == 2010 => return vars.split("agnea_2010", vars.settings.agnea_2010), + p if p == 2020 => return vars.split("agnea_2020", vars.settings.agnea_2020), + p if p == 2030 => return vars.split("agnea_2030", vars.settings.agnea_2030), + p if p == 2040 => return vars.split("agnea_2040", vars.settings.agnea_2040), + p if p == 2050 => return vars.split("agnea_2050", vars.settings.agnea_2050), + p if p == 2060 => return vars.split("agnea_2060", vars.settings.agnea_2060), + p if p == 2080 => return vars.split("agnea_2080", vars.settings.agnea_2080), + p if p == 2090 => return vars.split("agnea_2090", vars.settings.agnea_2090), + p if p == 2100 => return vars.split("agnea_2100", vars.settings.agnea_2100), + p if p == 2110 => return vars.split("agnea_2110", vars.settings.agnea_2110), + p if p == 2120 => return vars.split("agnea_2120", vars.settings.agnea_2120), + p if p == 2130 => return vars.split("agnea_2130", vars.settings.agnea_2130), + p if p == 2140 => return vars.split("agnea_2140", vars.settings.agnea_2140), + p if p == 2150 => return vars.split("agnea_2150", vars.settings.agnea_2150), + p if p == 2160 => return vars.split("agnea_2160", vars.settings.agnea_2160), + p if p == 2170 => return vars.split("agnea_2170", vars.settings.agnea_2170), + p if p == 2500 => return vars.split("agnea_2500", vars.settings.agnea_2500), + _ => return None, + } + } else { + return None; + } + } +}