From 129bd69d233b8a4645f5886fcfcc57ae2dba3a66 Mon Sep 17 00:00:00 2001 From: serenagrace Date: Mon, 6 Oct 2025 11:26:09 -0500 Subject: [PATCH 01/39] SOS slot changes --- reader_core/src/gen7/frame.rs | 257 +++++++++--------- reader_core/src/gen7/reader.rs | 473 +++++++++++++++++---------------- 2 files changed, 368 insertions(+), 362 deletions(-) diff --git a/reader_core/src/gen7/frame.rs b/reader_core/src/gen7/frame.rs index 6d10578..33fcd50 100644 --- a/reader_core/src/gen7/frame.rs +++ b/reader_core/src/gen7/frame.rs @@ -1,126 +1,131 @@ -use super::{ - draw::{draw_citra_info, draw_daycare, draw_header, draw_pkx, draw_rng, draw_sos}, - reader::Gen7Reader, -}; -use crate::{ - pnp, - rng::{RngWrapper, Sfmt}, - utils::{ - menu::{Menu, MenuOption, MenuOptionValue}, - sub_menu::SubMenu, - ShowView, - }, -}; -use once_cell::unsync::Lazy; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum Gen7View { - MainMenu, - Rng, - Daycare, - WildPokemon, - Sos, - Party, - Box, - Pelago, - Citra, -} - -impl MenuOptionValue for Gen7View { - fn get_label(view: Self) -> &'static str { - match view { - Self::MainMenu => "Main Menu", - Self::Rng => "RNG", - Self::Daycare => "Daycare", - Self::WildPokemon => "Wild", - Self::Sos => "SOS", - Self::Party => "Party", - Self::Box => "Box", - Self::Pelago => "Pelago", - Self::Citra => "Citra", - } - } -} - -struct PersistedState { - sfmt: RngWrapper, - show_view: ShowView, - view: Gen7View, - main_menu: Menu<8, Gen7View>, - party_menu: SubMenu<1, 6>, - pelago_menu: SubMenu<1, 3>, -} - -unsafe fn get_state() -> &'static mut PersistedState { - static mut STATE: Lazy = Lazy::new(|| PersistedState { - sfmt: RngWrapper::default(), - show_view: ShowView::default(), - view: Gen7View::MainMenu, - party_menu: SubMenu::default(), - pelago_menu: SubMenu::default(), - main_menu: Menu::new([ - MenuOption::new(Gen7View::Rng), - MenuOption::new(Gen7View::Daycare), - MenuOption::new(Gen7View::WildPokemon), - MenuOption::new(Gen7View::Sos), - MenuOption::new(Gen7View::Party), - MenuOption::new(Gen7View::Box), - MenuOption::new(Gen7View::Pelago), - MenuOption::new(Gen7View::Citra), - ]), - }); - Lazy::force_mut(&mut STATE) -} - -fn run_frame(reader: Gen7Reader) { - pnp::set_print_max_len(22); - - let init_seed: u32 = reader.init_seed(); - let sfmt_state: u64 = reader.sfmt_state(); - - // This is safe as long as this is guaranteed to run single threaded. - // A lock hinders performance too much on a 3ds. - let state = unsafe { get_state() }; - - state.sfmt.reinit_if_needed(init_seed); - state.sfmt.update_advances(sfmt_state); - - if !state.show_view.check() { - return; - } - - let is_locked = state.main_menu.update_lock(); - state.view = state.main_menu.next_view(Gen7View::MainMenu, state.view); - draw_header(Gen7View::MainMenu, state.view, is_locked); - - match state.view { - Gen7View::Rng => draw_rng(&reader, &state.sfmt), - Gen7View::Daycare => draw_daycare(&reader), - Gen7View::WildPokemon => draw_pkx(&reader.wild_pkm()), - Gen7View::Sos => draw_sos(&reader), - Gen7View::Box => draw_pkx(&reader.box_pkm()), - Gen7View::Citra => draw_citra_info(&reader), - Gen7View::Party => { - let slot = state.party_menu.update_and_draw(is_locked); - draw_pkx(&reader.party_pkm((slot - 1) as u32)); - } - Gen7View::Pelago => { - let slot = state.pelago_menu.update_and_draw(is_locked); - draw_pkx(&reader.pelago_pkm((slot - 1) as u32)) - } - Gen7View::MainMenu => { - state.main_menu.update_view(); - state.main_menu.draw(); - } - } -} - -pub fn run_sm_frame() { - let reader = Gen7Reader::sm(); - run_frame(reader) -} - -pub fn run_usum_frame() { - let reader = Gen7Reader::usum(); - run_frame(reader) -} +use super::{ + draw::{draw_citra_info, draw_daycare, draw_header, draw_pkx, draw_rng, draw_sos}, + reader::Gen7Reader, +}; +use crate::{ + pnp, + rng::{RngWrapper, Sfmt}, + utils::{ + menu::{Menu, MenuOption, MenuOptionValue}, + sub_menu::SubMenu, + ShowView, + }, +}; +use once_cell::unsync::Lazy; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum Gen7View { + MainMenu, + Rng, + Daycare, + WildPokemon, + Sos, + Party, + Box, + Pelago, + Citra, +} + +impl MenuOptionValue for Gen7View { + fn get_label(view: Self) -> &'static str { + match view { + Self::MainMenu => "Main Menu", + Self::Rng => "RNG", + Self::Daycare => "Daycare", + Self::WildPokemon => "Wild", + Self::Sos => "SOS", + Self::Party => "Party", + Self::Box => "Box", + Self::Pelago => "Pelago", + Self::Citra => "Citra", + } + } +} + +struct PersistedState { + sfmt: RngWrapper, + show_view: ShowView, + view: Gen7View, + main_menu: Menu<8, Gen7View>, + wild_menu: SubMenu<1, 6>, + party_menu: SubMenu<1, 6>, + pelago_menu: SubMenu<1, 3>, +} + +unsafe fn get_state() -> &'static mut PersistedState { + static mut STATE: Lazy = Lazy::new(|| PersistedState { + sfmt: RngWrapper::default(), + show_view: ShowView::default(), + view: Gen7View::MainMenu, + party_menu: SubMenu::default(), + pelago_menu: SubMenu::default(), + wild_menu: SubMenu::default(), + main_menu: Menu::new([ + MenuOption::new(Gen7View::Rng), + MenuOption::new(Gen7View::Daycare), + MenuOption::new(Gen7View::WildPokemon), + MenuOption::new(Gen7View::Sos), + MenuOption::new(Gen7View::Party), + MenuOption::new(Gen7View::Box), + MenuOption::new(Gen7View::Pelago), + MenuOption::new(Gen7View::Citra), + ]), + }); + Lazy::force_mut(&mut STATE) +} + +fn run_frame(reader: Gen7Reader) { + pnp::set_print_max_len(22); + + let init_seed: u32 = reader.init_seed(); + let sfmt_state: u64 = reader.sfmt_state(); + + // This is safe as long as this is guaranteed to run single threaded. + // A lock hinders performance too much on a 3ds. + let state = unsafe { get_state() }; + + state.sfmt.reinit_if_needed(init_seed); + state.sfmt.update_advances(sfmt_state); + + if !state.show_view.check() { + return; + } + + let is_locked = state.main_menu.update_lock(); + state.view = state.main_menu.next_view(Gen7View::MainMenu, state.view); + draw_header(Gen7View::MainMenu, state.view, is_locked); + + match state.view { + Gen7View::Rng => draw_rng(&reader, &state.sfmt), + Gen7View::Daycare => draw_daycare(&reader), + Gen7View::WildPokemon => { + let slot = state.wild_menu.update_and_draw(is_locked); + draw_pkx(&reader.wild_pkm((slot - 1) as u32)); + } + Gen7View::Sos => draw_sos(&reader), + Gen7View::Box => draw_pkx(&reader.box_pkm()), + Gen7View::Citra => draw_citra_info(&reader), + Gen7View::Party => { + let slot = state.party_menu.update_and_draw(is_locked); + draw_pkx(&reader.party_pkm((slot - 1) as u32)); + } + Gen7View::Pelago => { + let slot = state.pelago_menu.update_and_draw(is_locked); + draw_pkx(&reader.pelago_pkm((slot - 1) as u32)) + } + Gen7View::MainMenu => { + state.main_menu.update_view(); + state.main_menu.draw(); + } + } +} + +pub fn run_sm_frame() { + let reader = Gen7Reader::sm(); + run_frame(reader) +} + +pub fn run_usum_frame() { + let reader = Gen7Reader::usum(); + run_frame(reader) +} diff --git a/reader_core/src/gen7/reader.rs b/reader_core/src/gen7/reader.rs index 11d418f..3b0e41f 100644 --- a/reader_core/src/gen7/reader.rs +++ b/reader_core/src/gen7/reader.rs @@ -1,236 +1,237 @@ -use super::{game_lib, hook}; -use crate::pnp; -use core::num::{NonZeroU32, NonZeroU8}; -use pkm_rs::{Pk7, PokeCrypto}; - -struct Gen7Addresses { - initial_seed: u32, - sfmt_state_index: u32, - sfmt_state: u32, - party: u32, - wild: u32, - sos: u32, - sos_chain_length: u32, - pelago: u32, - egg_ready: u32, - egg: u32, - parent1: u32, - parent2: u32, - is_parent1_occupied: u32, - is_parent2_occupied: u32, - shiny_charm: u32, - id: u32, - box_cursor: u32, - npc_list: u32, - npc_head_blinking_offset: u32, -} - -const SM_ADDRESSES: Gen7Addresses = Gen7Addresses { - initial_seed: 0x325a3878, - sfmt_state_index: 0x33196548, - sfmt_state: 0x33195b88, - party: 0x34195e10, - wild: 0x3002f7b8, - sos: 0x3002f7b8, - sos_chain_length: 0x3003960d, - pelago: 0x331110ca, - egg_ready: 0x3313edd8, - egg: 0x3313eddc, - parent1: 0x3313ec01, - parent2: 0x3313ecea, - is_parent1_occupied: 0x3313ec00, - is_parent2_occupied: 0x3313ece9, - shiny_charm: 0x330d5930, - id: 0x330d67d0, - box_cursor: 0x30000298, - npc_list: 0x341977c4, - npc_head_blinking_offset: 0x2f4, -}; - -const USUM_ADDRESSES: Gen7Addresses = Gen7Addresses { - initial_seed: 0x32663bf0, - sfmt_state_index: 0x330d3f98, - sfmt_state: 0x330d35d8, - party: 0x33f7fa44, - wild: 0x3002f9a0, - sos: 0x3002f9a0, - sos_chain_length: 0x300397f9, - pelago: 0x3304d16a, - egg_ready: 0x3307b1e8, - egg: 0x3307b1ec, - parent1: 0x3307b011, - parent2: 0x3307b0fa, - is_parent1_occupied: 0x3307b010, - is_parent2_occupied: 0x3307b0f9, - shiny_charm: 0x33011930, - id: 0x33012818, - box_cursor: 0x30000298, - npc_list: 0x33f81438, - npc_head_blinking_offset: 0x2fc, -}; - -pub struct Gen7Reader { - is_usum: bool, - addrs: &'static Gen7Addresses, -} - -impl Gen7Reader { - pub fn sm() -> Self { - Self { - is_usum: false, - addrs: &SM_ADDRESSES, - } - } - - pub fn usum() -> Self { - Self { - is_usum: true, - addrs: &USUM_ADDRESSES, - } - } - - pub fn g7tid(&self) -> u32 { - let sidtid = pnp::read::(self.addrs.id); - - sidtid % 1000000 - } - - fn tid(&self) -> u16 { - pnp::read::(self.addrs.id) - } - - fn sid(&self) -> u16 { - pnp::read::(self.addrs.id + 2) - } - - pub fn tsv(&self) -> u16 { - (self.tid() ^ self.sid()) >> 4 - } - - pub fn trv(&self) -> u16 { - (self.tid() ^ self.sid()) & 0xf - } - - pub fn init_seed(&self) -> u32 { - pnp::read(self.addrs.initial_seed) - } - - fn sfmt_state_index(&self) -> u32 { - pnp::read(self.addrs.sfmt_state_index) - } - - pub fn sfmt_state(&self) -> u64 { - let index = self.sfmt_state_index(); - pnp::read(self.addrs.sfmt_state + if index != 624 { index * 4 } else { 0 }) - } - - pub fn egg_seed(&self) -> [u32; 4] { - [ - pnp::read(self.addrs.egg), - pnp::read(self.addrs.egg + 0x4), - pnp::read(self.addrs.egg + 0x8), - pnp::read(self.addrs.egg + 0xc), - ] - } - - pub fn sos_seed(&self) -> u32 { - hook::sos_seed() - } - - pub fn sos_chain(&self) -> u8 { - pnp::read(self.addrs.sos_chain_length) - } - - fn read_pk7(&self, offset: u32) -> Pk7 { - let bytes = pnp::read_array::<{ Pk7::STORED_SIZE }>(offset); - Pk7::new_valid(bytes) - } - - pub fn party_pkm(&self, slot: u32) -> Pk7 { - let offset = (slot * 484) + self.addrs.party; - self.read_pk7(offset) - } - - fn egg_parent(&self, is_present: u32, pkm: u32) -> Option { - let is_parent_present = pnp::read::(is_present) != 0; - - if !is_parent_present { - return None; - } - - let parent = self.read_pk7(pkm); - Some(parent) - } - - pub fn egg_parent_1(&self) -> Option { - self.egg_parent(self.addrs.is_parent1_occupied, self.addrs.parent1) - } - - pub fn egg_parent_2(&self) -> Option { - self.egg_parent(self.addrs.is_parent2_occupied, self.addrs.parent2) - } - - pub fn wild_pkm(&self) -> Pk7 { - self.read_pk7(self.addrs.wild) - } - - pub fn box_pkm(&self) -> Pk7 { - self.read_pk7(self.addrs.box_cursor) - } - - pub fn pelago_pkm(&self, slot: u32) -> Pk7 { - self.read_pk7((slot * 236) + self.addrs.pelago) - } - - pub fn sos_pkm(&self) -> Pk7 { - self.read_pk7(self.addrs.sos) - } - - pub fn is_egg_ready(&self) -> bool { - pnp::read::(self.addrs.egg_ready) != 0 - } - - fn has_item(&self, offset: u32, item_id: u32, count: u32) -> bool { - if self.is_usum { - game_lib::usum_has_item(offset, item_id, count) - } else { - game_lib::sm_has_item(offset, item_id, count) - } - } - - pub fn has_shiny_charm(&self) -> bool { - self.has_item(self.addrs.shiny_charm, 632, 1) - } - - pub fn npc_count(&self) -> u8 { - let mut npc_count: u8 = 0; - for index in 0..35 { - let npc = pnp::read::(self.addrs.npc_list + (index * 4)); - let is_present = pnp::read::(npc + 0xbc) != 0 && pnp::read::(npc + 0xc0) != 0; - let can_blink = pnp::read::(npc + 0xe8) == 0; - - if is_present && can_blink { - let blink_type = - NonZeroU32::new(pnp::read::(npc + self.addrs.npc_head_blinking_offset)) - .and_then(|struct_ptr| { - NonZeroU32::new(pnp::read::(struct_ptr.get() + 0x114)) - }) - .and_then(|struct_ptr| { - NonZeroU8::new(pnp::read::(struct_ptr.get() + 0xde)) - }) - .map(|blink_setting| blink_setting.get()) - .unwrap_or_default(); - let is_blinking = blink_type == 1 || blink_type == 2; - if is_blinking { - npc_count += 1; - } - } - } - - npc_count.saturating_sub(1) - } - - pub fn main_rng_seed_context(&self) -> hook::RngSeedContext { - hook::main_rng_seed_context() - } -} +use super::{game_lib, hook}; +use crate::pnp; +use core::num::{NonZeroU32, NonZeroU8}; +use pkm_rs::{Pk7, PokeCrypto}; + +struct Gen7Addresses { + initial_seed: u32, + sfmt_state_index: u32, + sfmt_state: u32, + party: u32, + wild: u32, + sos: u32, + sos_chain_length: u32, + pelago: u32, + egg_ready: u32, + egg: u32, + parent1: u32, + parent2: u32, + is_parent1_occupied: u32, + is_parent2_occupied: u32, + shiny_charm: u32, + id: u32, + box_cursor: u32, + npc_list: u32, + npc_head_blinking_offset: u32, +} + +const SM_ADDRESSES: Gen7Addresses = Gen7Addresses { + initial_seed: 0x325a3878, + sfmt_state_index: 0x33196548, + sfmt_state: 0x33195b88, + party: 0x34195e10, + wild: 0x3002f7b8, + sos: 0x3002f7b8, + sos_chain_length: 0x3003960d, + pelago: 0x331110ca, + egg_ready: 0x3313edd8, + egg: 0x3313eddc, + parent1: 0x3313ec01, + parent2: 0x3313ecea, + is_parent1_occupied: 0x3313ec00, + is_parent2_occupied: 0x3313ece9, + shiny_charm: 0x330d5930, + id: 0x330d67d0, + box_cursor: 0x30000298, + npc_list: 0x341977c4, + npc_head_blinking_offset: 0x2f4, +}; + +const USUM_ADDRESSES: Gen7Addresses = Gen7Addresses { + initial_seed: 0x32663bf0, + sfmt_state_index: 0x330d3f98, + sfmt_state: 0x330d35d8, + party: 0x33f7fa44, + wild: 0x3002f9a0, + sos: 0x3002f9a0, + sos_chain_length: 0x300397f9, + pelago: 0x3304d16a, + egg_ready: 0x3307b1e8, + egg: 0x3307b1ec, + parent1: 0x3307b011, + parent2: 0x3307b0fa, + is_parent1_occupied: 0x3307b010, + is_parent2_occupied: 0x3307b0f9, + shiny_charm: 0x33011930, + id: 0x33012818, + box_cursor: 0x30000298, + npc_list: 0x33f81438, + npc_head_blinking_offset: 0x2fc, +}; + +pub struct Gen7Reader { + is_usum: bool, + addrs: &'static Gen7Addresses, +} + +impl Gen7Reader { + pub fn sm() -> Self { + Self { + is_usum: false, + addrs: &SM_ADDRESSES, + } + } + + pub fn usum() -> Self { + Self { + is_usum: true, + addrs: &USUM_ADDRESSES, + } + } + + pub fn g7tid(&self) -> u32 { + let sidtid = pnp::read::(self.addrs.id); + + sidtid % 1000000 + } + + fn tid(&self) -> u16 { + pnp::read::(self.addrs.id) + } + + fn sid(&self) -> u16 { + pnp::read::(self.addrs.id + 2) + } + + pub fn tsv(&self) -> u16 { + (self.tid() ^ self.sid()) >> 4 + } + + pub fn trv(&self) -> u16 { + (self.tid() ^ self.sid()) & 0xf + } + + pub fn init_seed(&self) -> u32 { + pnp::read(self.addrs.initial_seed) + } + + fn sfmt_state_index(&self) -> u32 { + pnp::read(self.addrs.sfmt_state_index) + } + + pub fn sfmt_state(&self) -> u64 { + let index = self.sfmt_state_index(); + pnp::read(self.addrs.sfmt_state + if index != 624 { index * 4 } else { 0 }) + } + + pub fn egg_seed(&self) -> [u32; 4] { + [ + pnp::read(self.addrs.egg), + pnp::read(self.addrs.egg + 0x4), + pnp::read(self.addrs.egg + 0x8), + pnp::read(self.addrs.egg + 0xc), + ] + } + + pub fn sos_seed(&self) -> u32 { + hook::sos_seed() + } + + pub fn sos_chain(&self) -> u8 { + pnp::read(self.addrs.sos_chain_length) + } + + fn read_pk7(&self, offset: u32) -> Pk7 { + let bytes = pnp::read_array::<{ Pk7::STORED_SIZE }>(offset); + Pk7::new_valid(bytes) + } + + pub fn party_pkm(&self, slot: u32) -> Pk7 { + let offset = (slot * 484) + self.addrs.party; + self.read_pk7(offset) + } + + fn egg_parent(&self, is_present: u32, pkm: u32) -> Option { + let is_parent_present = pnp::read::(is_present) != 0; + + if !is_parent_present { + return None; + } + + let parent = self.read_pk7(pkm); + Some(parent) + } + + pub fn egg_parent_1(&self) -> Option { + self.egg_parent(self.addrs.is_parent1_occupied, self.addrs.parent1) + } + + pub fn egg_parent_2(&self) -> Option { + self.egg_parent(self.addrs.is_parent2_occupied, self.addrs.parent2) + } + + pub fn wild_pkm(&self, slot: u32) -> Pk7 { + let offset = (slot * 484) + self.addrs.wild; + self.read_pk7(offset) + } + + pub fn box_pkm(&self) -> Pk7 { + self.read_pk7(self.addrs.box_cursor) + } + + pub fn pelago_pkm(&self, slot: u32) -> Pk7 { + self.read_pk7((slot * 236) + self.addrs.pelago) + } + + pub fn sos_pkm(&self) -> Pk7 { + self.read_pk7(self.addrs.sos) + } + + pub fn is_egg_ready(&self) -> bool { + pnp::read::(self.addrs.egg_ready) != 0 + } + + fn has_item(&self, offset: u32, item_id: u32, count: u32) -> bool { + if self.is_usum { + game_lib::usum_has_item(offset, item_id, count) + } else { + game_lib::sm_has_item(offset, item_id, count) + } + } + + pub fn has_shiny_charm(&self) -> bool { + self.has_item(self.addrs.shiny_charm, 632, 1) + } + + pub fn npc_count(&self) -> u8 { + let mut npc_count: u8 = 0; + for index in 0..35 { + let npc = pnp::read::(self.addrs.npc_list + (index * 4)); + let is_present = pnp::read::(npc + 0xbc) != 0 && pnp::read::(npc + 0xc0) != 0; + let can_blink = pnp::read::(npc + 0xe8) == 0; + + if is_present && can_blink { + let blink_type = + NonZeroU32::new(pnp::read::(npc + self.addrs.npc_head_blinking_offset)) + .and_then(|struct_ptr| { + NonZeroU32::new(pnp::read::(struct_ptr.get() + 0x114)) + }) + .and_then(|struct_ptr| { + NonZeroU8::new(pnp::read::(struct_ptr.get() + 0xde)) + }) + .map(|blink_setting| blink_setting.get()) + .unwrap_or_default(); + let is_blinking = blink_type == 1 || blink_type == 2; + if is_blinking { + npc_count += 1; + } + } + } + + npc_count.saturating_sub(1) + } + + pub fn main_rng_seed_context(&self) -> hook::RngSeedContext { + hook::main_rng_seed_context() + } +} From 3c273d1dce3e4976aa9b055bcd19c59f32cb2dae Mon Sep 17 00:00:00 2001 From: serenagrace Date: Mon, 6 Oct 2025 11:34:53 -0500 Subject: [PATCH 02/39] Fixed line endings --- reader_core/src/gen7/frame.rs | 262 +++++++++--------- reader_core/src/gen7/reader.rs | 474 ++++++++++++++++----------------- 2 files changed, 368 insertions(+), 368 deletions(-) diff --git a/reader_core/src/gen7/frame.rs b/reader_core/src/gen7/frame.rs index 33fcd50..307d69c 100644 --- a/reader_core/src/gen7/frame.rs +++ b/reader_core/src/gen7/frame.rs @@ -1,131 +1,131 @@ -use super::{ - draw::{draw_citra_info, draw_daycare, draw_header, draw_pkx, draw_rng, draw_sos}, - reader::Gen7Reader, -}; -use crate::{ - pnp, - rng::{RngWrapper, Sfmt}, - utils::{ - menu::{Menu, MenuOption, MenuOptionValue}, - sub_menu::SubMenu, - ShowView, - }, -}; -use once_cell::unsync::Lazy; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum Gen7View { - MainMenu, - Rng, - Daycare, - WildPokemon, - Sos, - Party, - Box, - Pelago, - Citra, -} - -impl MenuOptionValue for Gen7View { - fn get_label(view: Self) -> &'static str { - match view { - Self::MainMenu => "Main Menu", - Self::Rng => "RNG", - Self::Daycare => "Daycare", - Self::WildPokemon => "Wild", - Self::Sos => "SOS", - Self::Party => "Party", - Self::Box => "Box", - Self::Pelago => "Pelago", - Self::Citra => "Citra", - } - } -} - -struct PersistedState { - sfmt: RngWrapper, - show_view: ShowView, - view: Gen7View, - main_menu: Menu<8, Gen7View>, - wild_menu: SubMenu<1, 6>, - party_menu: SubMenu<1, 6>, - pelago_menu: SubMenu<1, 3>, -} - -unsafe fn get_state() -> &'static mut PersistedState { - static mut STATE: Lazy = Lazy::new(|| PersistedState { - sfmt: RngWrapper::default(), - show_view: ShowView::default(), - view: Gen7View::MainMenu, - party_menu: SubMenu::default(), - pelago_menu: SubMenu::default(), - wild_menu: SubMenu::default(), - main_menu: Menu::new([ - MenuOption::new(Gen7View::Rng), - MenuOption::new(Gen7View::Daycare), - MenuOption::new(Gen7View::WildPokemon), - MenuOption::new(Gen7View::Sos), - MenuOption::new(Gen7View::Party), - MenuOption::new(Gen7View::Box), - MenuOption::new(Gen7View::Pelago), - MenuOption::new(Gen7View::Citra), - ]), - }); - Lazy::force_mut(&mut STATE) -} - -fn run_frame(reader: Gen7Reader) { - pnp::set_print_max_len(22); - - let init_seed: u32 = reader.init_seed(); - let sfmt_state: u64 = reader.sfmt_state(); - - // This is safe as long as this is guaranteed to run single threaded. - // A lock hinders performance too much on a 3ds. - let state = unsafe { get_state() }; - - state.sfmt.reinit_if_needed(init_seed); - state.sfmt.update_advances(sfmt_state); - - if !state.show_view.check() { - return; - } - - let is_locked = state.main_menu.update_lock(); - state.view = state.main_menu.next_view(Gen7View::MainMenu, state.view); - draw_header(Gen7View::MainMenu, state.view, is_locked); - - match state.view { - Gen7View::Rng => draw_rng(&reader, &state.sfmt), - Gen7View::Daycare => draw_daycare(&reader), - Gen7View::WildPokemon => { - let slot = state.wild_menu.update_and_draw(is_locked); - draw_pkx(&reader.wild_pkm((slot - 1) as u32)); - } - Gen7View::Sos => draw_sos(&reader), - Gen7View::Box => draw_pkx(&reader.box_pkm()), - Gen7View::Citra => draw_citra_info(&reader), - Gen7View::Party => { - let slot = state.party_menu.update_and_draw(is_locked); - draw_pkx(&reader.party_pkm((slot - 1) as u32)); - } - Gen7View::Pelago => { - let slot = state.pelago_menu.update_and_draw(is_locked); - draw_pkx(&reader.pelago_pkm((slot - 1) as u32)) - } - Gen7View::MainMenu => { - state.main_menu.update_view(); - state.main_menu.draw(); - } - } -} - -pub fn run_sm_frame() { - let reader = Gen7Reader::sm(); - run_frame(reader) -} - -pub fn run_usum_frame() { - let reader = Gen7Reader::usum(); - run_frame(reader) -} +use super::{ + draw::{draw_citra_info, draw_daycare, draw_header, draw_pkx, draw_rng, draw_sos}, + reader::Gen7Reader, +}; +use crate::{ + pnp, + rng::{RngWrapper, Sfmt}, + utils::{ + menu::{Menu, MenuOption, MenuOptionValue}, + sub_menu::SubMenu, + ShowView, + }, +}; +use once_cell::unsync::Lazy; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum Gen7View { + MainMenu, + Rng, + Daycare, + WildPokemon, + Sos, + Party, + Box, + Pelago, + Citra, +} + +impl MenuOptionValue for Gen7View { + fn get_label(view: Self) -> &'static str { + match view { + Self::MainMenu => "Main Menu", + Self::Rng => "RNG", + Self::Daycare => "Daycare", + Self::WildPokemon => "Wild", + Self::Sos => "SOS", + Self::Party => "Party", + Self::Box => "Box", + Self::Pelago => "Pelago", + Self::Citra => "Citra", + } + } +} + +struct PersistedState { + sfmt: RngWrapper, + show_view: ShowView, + view: Gen7View, + main_menu: Menu<8, Gen7View>, + wild_menu: SubMenu<1, 6>, + party_menu: SubMenu<1, 6>, + pelago_menu: SubMenu<1, 3>, +} + +unsafe fn get_state() -> &'static mut PersistedState { + static mut STATE: Lazy = Lazy::new(|| PersistedState { + sfmt: RngWrapper::default(), + show_view: ShowView::default(), + view: Gen7View::MainMenu, + party_menu: SubMenu::default(), + pelago_menu: SubMenu::default(), + wild_menu: SubMenu::default(), + main_menu: Menu::new([ + MenuOption::new(Gen7View::Rng), + MenuOption::new(Gen7View::Daycare), + MenuOption::new(Gen7View::WildPokemon), + MenuOption::new(Gen7View::Sos), + MenuOption::new(Gen7View::Party), + MenuOption::new(Gen7View::Box), + MenuOption::new(Gen7View::Pelago), + MenuOption::new(Gen7View::Citra), + ]), + }); + Lazy::force_mut(&mut STATE) +} + +fn run_frame(reader: Gen7Reader) { + pnp::set_print_max_len(22); + + let init_seed: u32 = reader.init_seed(); + let sfmt_state: u64 = reader.sfmt_state(); + + // This is safe as long as this is guaranteed to run single threaded. + // A lock hinders performance too much on a 3ds. + let state = unsafe { get_state() }; + + state.sfmt.reinit_if_needed(init_seed); + state.sfmt.update_advances(sfmt_state); + + if !state.show_view.check() { + return; + } + + let is_locked = state.main_menu.update_lock(); + state.view = state.main_menu.next_view(Gen7View::MainMenu, state.view); + draw_header(Gen7View::MainMenu, state.view, is_locked); + + match state.view { + Gen7View::Rng => draw_rng(&reader, &state.sfmt), + Gen7View::Daycare => draw_daycare(&reader), + Gen7View::WildPokemon => { + let slot = state.wild_menu.update_and_draw(is_locked); + draw_pkx(&reader.wild_pkm((slot - 1) as u32)); + } + Gen7View::Sos => draw_sos(&reader), + Gen7View::Box => draw_pkx(&reader.box_pkm()), + Gen7View::Citra => draw_citra_info(&reader), + Gen7View::Party => { + let slot = state.party_menu.update_and_draw(is_locked); + draw_pkx(&reader.party_pkm((slot - 1) as u32)); + } + Gen7View::Pelago => { + let slot = state.pelago_menu.update_and_draw(is_locked); + draw_pkx(&reader.pelago_pkm((slot - 1) as u32)) + } + Gen7View::MainMenu => { + state.main_menu.update_view(); + state.main_menu.draw(); + } + } +} + +pub fn run_sm_frame() { + let reader = Gen7Reader::sm(); + run_frame(reader) +} + +pub fn run_usum_frame() { + let reader = Gen7Reader::usum(); + run_frame(reader) +} diff --git a/reader_core/src/gen7/reader.rs b/reader_core/src/gen7/reader.rs index 3b0e41f..06ca60e 100644 --- a/reader_core/src/gen7/reader.rs +++ b/reader_core/src/gen7/reader.rs @@ -1,237 +1,237 @@ -use super::{game_lib, hook}; -use crate::pnp; -use core::num::{NonZeroU32, NonZeroU8}; -use pkm_rs::{Pk7, PokeCrypto}; - -struct Gen7Addresses { - initial_seed: u32, - sfmt_state_index: u32, - sfmt_state: u32, - party: u32, - wild: u32, - sos: u32, - sos_chain_length: u32, - pelago: u32, - egg_ready: u32, - egg: u32, - parent1: u32, - parent2: u32, - is_parent1_occupied: u32, - is_parent2_occupied: u32, - shiny_charm: u32, - id: u32, - box_cursor: u32, - npc_list: u32, - npc_head_blinking_offset: u32, -} - -const SM_ADDRESSES: Gen7Addresses = Gen7Addresses { - initial_seed: 0x325a3878, - sfmt_state_index: 0x33196548, - sfmt_state: 0x33195b88, - party: 0x34195e10, - wild: 0x3002f7b8, - sos: 0x3002f7b8, - sos_chain_length: 0x3003960d, - pelago: 0x331110ca, - egg_ready: 0x3313edd8, - egg: 0x3313eddc, - parent1: 0x3313ec01, - parent2: 0x3313ecea, - is_parent1_occupied: 0x3313ec00, - is_parent2_occupied: 0x3313ece9, - shiny_charm: 0x330d5930, - id: 0x330d67d0, - box_cursor: 0x30000298, - npc_list: 0x341977c4, - npc_head_blinking_offset: 0x2f4, -}; - -const USUM_ADDRESSES: Gen7Addresses = Gen7Addresses { - initial_seed: 0x32663bf0, - sfmt_state_index: 0x330d3f98, - sfmt_state: 0x330d35d8, - party: 0x33f7fa44, - wild: 0x3002f9a0, - sos: 0x3002f9a0, - sos_chain_length: 0x300397f9, - pelago: 0x3304d16a, - egg_ready: 0x3307b1e8, - egg: 0x3307b1ec, - parent1: 0x3307b011, - parent2: 0x3307b0fa, - is_parent1_occupied: 0x3307b010, - is_parent2_occupied: 0x3307b0f9, - shiny_charm: 0x33011930, - id: 0x33012818, - box_cursor: 0x30000298, - npc_list: 0x33f81438, - npc_head_blinking_offset: 0x2fc, -}; - -pub struct Gen7Reader { - is_usum: bool, - addrs: &'static Gen7Addresses, -} - -impl Gen7Reader { - pub fn sm() -> Self { - Self { - is_usum: false, - addrs: &SM_ADDRESSES, - } - } - - pub fn usum() -> Self { - Self { - is_usum: true, - addrs: &USUM_ADDRESSES, - } - } - - pub fn g7tid(&self) -> u32 { - let sidtid = pnp::read::(self.addrs.id); - - sidtid % 1000000 - } - - fn tid(&self) -> u16 { - pnp::read::(self.addrs.id) - } - - fn sid(&self) -> u16 { - pnp::read::(self.addrs.id + 2) - } - - pub fn tsv(&self) -> u16 { - (self.tid() ^ self.sid()) >> 4 - } - - pub fn trv(&self) -> u16 { - (self.tid() ^ self.sid()) & 0xf - } - - pub fn init_seed(&self) -> u32 { - pnp::read(self.addrs.initial_seed) - } - - fn sfmt_state_index(&self) -> u32 { - pnp::read(self.addrs.sfmt_state_index) - } - - pub fn sfmt_state(&self) -> u64 { - let index = self.sfmt_state_index(); - pnp::read(self.addrs.sfmt_state + if index != 624 { index * 4 } else { 0 }) - } - - pub fn egg_seed(&self) -> [u32; 4] { - [ - pnp::read(self.addrs.egg), - pnp::read(self.addrs.egg + 0x4), - pnp::read(self.addrs.egg + 0x8), - pnp::read(self.addrs.egg + 0xc), - ] - } - - pub fn sos_seed(&self) -> u32 { - hook::sos_seed() - } - - pub fn sos_chain(&self) -> u8 { - pnp::read(self.addrs.sos_chain_length) - } - - fn read_pk7(&self, offset: u32) -> Pk7 { - let bytes = pnp::read_array::<{ Pk7::STORED_SIZE }>(offset); - Pk7::new_valid(bytes) - } - - pub fn party_pkm(&self, slot: u32) -> Pk7 { - let offset = (slot * 484) + self.addrs.party; - self.read_pk7(offset) - } - - fn egg_parent(&self, is_present: u32, pkm: u32) -> Option { - let is_parent_present = pnp::read::(is_present) != 0; - - if !is_parent_present { - return None; - } - - let parent = self.read_pk7(pkm); - Some(parent) - } - - pub fn egg_parent_1(&self) -> Option { - self.egg_parent(self.addrs.is_parent1_occupied, self.addrs.parent1) - } - - pub fn egg_parent_2(&self) -> Option { - self.egg_parent(self.addrs.is_parent2_occupied, self.addrs.parent2) - } - - pub fn wild_pkm(&self, slot: u32) -> Pk7 { - let offset = (slot * 484) + self.addrs.wild; - self.read_pk7(offset) - } - - pub fn box_pkm(&self) -> Pk7 { - self.read_pk7(self.addrs.box_cursor) - } - - pub fn pelago_pkm(&self, slot: u32) -> Pk7 { - self.read_pk7((slot * 236) + self.addrs.pelago) - } - - pub fn sos_pkm(&self) -> Pk7 { - self.read_pk7(self.addrs.sos) - } - - pub fn is_egg_ready(&self) -> bool { - pnp::read::(self.addrs.egg_ready) != 0 - } - - fn has_item(&self, offset: u32, item_id: u32, count: u32) -> bool { - if self.is_usum { - game_lib::usum_has_item(offset, item_id, count) - } else { - game_lib::sm_has_item(offset, item_id, count) - } - } - - pub fn has_shiny_charm(&self) -> bool { - self.has_item(self.addrs.shiny_charm, 632, 1) - } - - pub fn npc_count(&self) -> u8 { - let mut npc_count: u8 = 0; - for index in 0..35 { - let npc = pnp::read::(self.addrs.npc_list + (index * 4)); - let is_present = pnp::read::(npc + 0xbc) != 0 && pnp::read::(npc + 0xc0) != 0; - let can_blink = pnp::read::(npc + 0xe8) == 0; - - if is_present && can_blink { - let blink_type = - NonZeroU32::new(pnp::read::(npc + self.addrs.npc_head_blinking_offset)) - .and_then(|struct_ptr| { - NonZeroU32::new(pnp::read::(struct_ptr.get() + 0x114)) - }) - .and_then(|struct_ptr| { - NonZeroU8::new(pnp::read::(struct_ptr.get() + 0xde)) - }) - .map(|blink_setting| blink_setting.get()) - .unwrap_or_default(); - let is_blinking = blink_type == 1 || blink_type == 2; - if is_blinking { - npc_count += 1; - } - } - } - - npc_count.saturating_sub(1) - } - - pub fn main_rng_seed_context(&self) -> hook::RngSeedContext { - hook::main_rng_seed_context() - } -} +use super::{game_lib, hook}; +use crate::pnp; +use core::num::{NonZeroU32, NonZeroU8}; +use pkm_rs::{Pk7, PokeCrypto}; + +struct Gen7Addresses { + initial_seed: u32, + sfmt_state_index: u32, + sfmt_state: u32, + party: u32, + wild: u32, + sos: u32, + sos_chain_length: u32, + pelago: u32, + egg_ready: u32, + egg: u32, + parent1: u32, + parent2: u32, + is_parent1_occupied: u32, + is_parent2_occupied: u32, + shiny_charm: u32, + id: u32, + box_cursor: u32, + npc_list: u32, + npc_head_blinking_offset: u32, +} + +const SM_ADDRESSES: Gen7Addresses = Gen7Addresses { + initial_seed: 0x325a3878, + sfmt_state_index: 0x33196548, + sfmt_state: 0x33195b88, + party: 0x34195e10, + wild: 0x3002f7b8, + sos: 0x3002f7b8, + sos_chain_length: 0x3003960d, + pelago: 0x331110ca, + egg_ready: 0x3313edd8, + egg: 0x3313eddc, + parent1: 0x3313ec01, + parent2: 0x3313ecea, + is_parent1_occupied: 0x3313ec00, + is_parent2_occupied: 0x3313ece9, + shiny_charm: 0x330d5930, + id: 0x330d67d0, + box_cursor: 0x30000298, + npc_list: 0x341977c4, + npc_head_blinking_offset: 0x2f4, +}; + +const USUM_ADDRESSES: Gen7Addresses = Gen7Addresses { + initial_seed: 0x32663bf0, + sfmt_state_index: 0x330d3f98, + sfmt_state: 0x330d35d8, + party: 0x33f7fa44, + wild: 0x3002f9a0, + sos: 0x3002f9a0, + sos_chain_length: 0x300397f9, + pelago: 0x3304d16a, + egg_ready: 0x3307b1e8, + egg: 0x3307b1ec, + parent1: 0x3307b011, + parent2: 0x3307b0fa, + is_parent1_occupied: 0x3307b010, + is_parent2_occupied: 0x3307b0f9, + shiny_charm: 0x33011930, + id: 0x33012818, + box_cursor: 0x30000298, + npc_list: 0x33f81438, + npc_head_blinking_offset: 0x2fc, +}; + +pub struct Gen7Reader { + is_usum: bool, + addrs: &'static Gen7Addresses, +} + +impl Gen7Reader { + pub fn sm() -> Self { + Self { + is_usum: false, + addrs: &SM_ADDRESSES, + } + } + + pub fn usum() -> Self { + Self { + is_usum: true, + addrs: &USUM_ADDRESSES, + } + } + + pub fn g7tid(&self) -> u32 { + let sidtid = pnp::read::(self.addrs.id); + + sidtid % 1000000 + } + + fn tid(&self) -> u16 { + pnp::read::(self.addrs.id) + } + + fn sid(&self) -> u16 { + pnp::read::(self.addrs.id + 2) + } + + pub fn tsv(&self) -> u16 { + (self.tid() ^ self.sid()) >> 4 + } + + pub fn trv(&self) -> u16 { + (self.tid() ^ self.sid()) & 0xf + } + + pub fn init_seed(&self) -> u32 { + pnp::read(self.addrs.initial_seed) + } + + fn sfmt_state_index(&self) -> u32 { + pnp::read(self.addrs.sfmt_state_index) + } + + pub fn sfmt_state(&self) -> u64 { + let index = self.sfmt_state_index(); + pnp::read(self.addrs.sfmt_state + if index != 624 { index * 4 } else { 0 }) + } + + pub fn egg_seed(&self) -> [u32; 4] { + [ + pnp::read(self.addrs.egg), + pnp::read(self.addrs.egg + 0x4), + pnp::read(self.addrs.egg + 0x8), + pnp::read(self.addrs.egg + 0xc), + ] + } + + pub fn sos_seed(&self) -> u32 { + hook::sos_seed() + } + + pub fn sos_chain(&self) -> u8 { + pnp::read(self.addrs.sos_chain_length) + } + + fn read_pk7(&self, offset: u32) -> Pk7 { + let bytes = pnp::read_array::<{ Pk7::STORED_SIZE }>(offset); + Pk7::new_valid(bytes) + } + + pub fn party_pkm(&self, slot: u32) -> Pk7 { + let offset = (slot * 484) + self.addrs.party; + self.read_pk7(offset) + } + + fn egg_parent(&self, is_present: u32, pkm: u32) -> Option { + let is_parent_present = pnp::read::(is_present) != 0; + + if !is_parent_present { + return None; + } + + let parent = self.read_pk7(pkm); + Some(parent) + } + + pub fn egg_parent_1(&self) -> Option { + self.egg_parent(self.addrs.is_parent1_occupied, self.addrs.parent1) + } + + pub fn egg_parent_2(&self) -> Option { + self.egg_parent(self.addrs.is_parent2_occupied, self.addrs.parent2) + } + + pub fn wild_pkm(&self, slot: u32) -> Pk7 { + let offset = (slot * 484) + self.addrs.wild; + self.read_pk7(offset) + } + + pub fn box_pkm(&self) -> Pk7 { + self.read_pk7(self.addrs.box_cursor) + } + + pub fn pelago_pkm(&self, slot: u32) -> Pk7 { + self.read_pk7((slot * 236) + self.addrs.pelago) + } + + pub fn sos_pkm(&self) -> Pk7 { + self.read_pk7(self.addrs.sos) + } + + pub fn is_egg_ready(&self) -> bool { + pnp::read::(self.addrs.egg_ready) != 0 + } + + fn has_item(&self, offset: u32, item_id: u32, count: u32) -> bool { + if self.is_usum { + game_lib::usum_has_item(offset, item_id, count) + } else { + game_lib::sm_has_item(offset, item_id, count) + } + } + + pub fn has_shiny_charm(&self) -> bool { + self.has_item(self.addrs.shiny_charm, 632, 1) + } + + pub fn npc_count(&self) -> u8 { + let mut npc_count: u8 = 0; + for index in 0..35 { + let npc = pnp::read::(self.addrs.npc_list + (index * 4)); + let is_present = pnp::read::(npc + 0xbc) != 0 && pnp::read::(npc + 0xc0) != 0; + let can_blink = pnp::read::(npc + 0xe8) == 0; + + if is_present && can_blink { + let blink_type = + NonZeroU32::new(pnp::read::(npc + self.addrs.npc_head_blinking_offset)) + .and_then(|struct_ptr| { + NonZeroU32::new(pnp::read::(struct_ptr.get() + 0x114)) + }) + .and_then(|struct_ptr| { + NonZeroU8::new(pnp::read::(struct_ptr.get() + 0xde)) + }) + .map(|blink_setting| blink_setting.get()) + .unwrap_or_default(); + let is_blinking = blink_type == 1 || blink_type == 2; + if is_blinking { + npc_count += 1; + } + } + } + + npc_count.saturating_sub(1) + } + + pub fn main_rng_seed_context(&self) -> hook::RngSeedContext { + hook::main_rng_seed_context() + } +} From 7dab31a4c33944a7215c179ca441dd3b11c7cf4a Mon Sep 17 00:00:00 2001 From: serenagrace Date: Mon, 6 Oct 2025 15:26:51 -0500 Subject: [PATCH 03/39] 0.7.5 Push --- 3gx/PokeReader.plgInfo | 4 ++-- reader_core/Cargo.lock | 2 +- reader_core/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/3gx/PokeReader.plgInfo b/3gx/PokeReader.plgInfo index 4e765d4..56ebc95 100644 --- a/3gx/PokeReader.plgInfo +++ b/3gx/PokeReader.plgInfo @@ -2,8 +2,8 @@ Author: Zaksabeast Version: # Plugin version Major: 1 - Minor: 0 - Revision: 0 + Minor: 7 + Revision: 5 Targets: # Low TitleId of games which are compatibles with this plugin (empty for all) 0x00055D00 diff --git a/reader_core/Cargo.lock b/reader_core/Cargo.lock index 4e445ff..2ee75fe 100644 --- a/reader_core/Cargo.lock +++ b/reader_core/Cargo.lock @@ -133,7 +133,7 @@ dependencies = [ [[package]] name = "pokereader" -version = "0.7.4" +version = "0.7.5" dependencies = [ "binrw 0.14.0", "chrono", diff --git a/reader_core/Cargo.toml b/reader_core/Cargo.toml index 65f2206..2e8de17 100644 --- a/reader_core/Cargo.toml +++ b/reader_core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pokereader" -version = "0.7.4" +version = "0.7.5" edition = "2021" [dependencies] From 7f6ec0857cecde54f2eefc264c0bdbce796b538b Mon Sep 17 00:00:00 2001 From: serenagrace Date: Mon, 6 Oct 2025 21:22:11 -0500 Subject: [PATCH 04/39] Move to v0.8.0, improved Gen7 SOS Functionality - Wild View now shows 4 slots, can be manually scrolled through to see SOS data - Improved SOS Support. Select "Caller Slot", then "Ally Slot" will be dynamically determined. - Display Caller PP remaining to avoid struggle! - Display whether Adrenaline Orb effect is active. - Supports both SM/USUM. - Tested on UM hardware + retail cartridge. --- reader_core/Cargo.lock | 2 +- reader_core/Cargo.toml | 2 +- reader_core/src/draw.rs | 30 +++++++++++++++++++++++++++++- reader_core/src/gen7/draw.rs | 24 +++++++++++++++++++++--- reader_core/src/gen7/frame.rs | 11 ++++++++--- reader_core/src/gen7/reader.rs | 30 +++++++++++++++++++++++++++--- reader_core/src/utils/sub_menu.rs | 4 ++++ 7 files changed, 91 insertions(+), 12 deletions(-) diff --git a/reader_core/Cargo.lock b/reader_core/Cargo.lock index 2ee75fe..cac726b 100644 --- a/reader_core/Cargo.lock +++ b/reader_core/Cargo.lock @@ -133,7 +133,7 @@ dependencies = [ [[package]] name = "pokereader" -version = "0.7.5" +version = "0.8.0" dependencies = [ "binrw 0.14.0", "chrono", diff --git a/reader_core/Cargo.toml b/reader_core/Cargo.toml index 2e8de17..c254d7c 100644 --- a/reader_core/Cargo.toml +++ b/reader_core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pokereader" -version = "0.7.5" +version = "0.8.0" edition = "2021" [dependencies] diff --git a/reader_core/src/draw.rs b/reader_core/src/draw.rs index 6121277..0eb4f16 100644 --- a/reader_core/src/draw.rs +++ b/reader_core/src/draw.rs @@ -101,6 +101,34 @@ macro_rules! print_stat { }; } +pub fn draw_pkx_brief(pkx: &impl Pkx) { + let species = pkx.species_t().to_string(); + let ability = pkx.ability_t().to_string(); + + let shiny_type = match pkx.shiny_type() { + Some(Shiny::Star) => "Star", + Some(Shiny::Square) => "Square", + None => "Not Shiny", + }; + let shiny_color = get_shiny_color(pkx.is_shiny()); + let iv_hp = pkx.iv_hp(); + let iv_atk = pkx.iv_atk(); + let iv_def = pkx.iv_def(); + let iv_spa = pkx.iv_spa(); + let iv_spd = pkx.iv_spd(); + let iv_spe = pkx.iv_spe(); + + let nature = pkx.nature_t(); + + pnp::println!("{} {}", nature, species); + pnp::println!("Ability: ({}) {}", pkx.ability_number_t(), ability); + pnp::println!("PID: {:08X}", pkx.pid()); + pnp::println!(color = shiny_color, "PSV: {:04}, {}", pkx.psv(), shiny_type); + pnp::println!(""); + pnp::println!("HPower: {}", pkx.hidden_power_t()); + pnp::println!("{} {} {} {} {} {}", iv_hp, iv_atk, iv_def, iv_spa, iv_spd, iv_spe); +} + pub fn draw_pkx(pkx: &impl Pkx) { let species = pkx.species_t().to_string(); let ability = pkx.ability_t().to_string(); @@ -132,9 +160,9 @@ pub fn draw_pkx(pkx: &impl Pkx) { pnp::println!("Ability: ({}) {}", pkx.ability_number_t(), ability); pnp::println!("PID: {:08X}", pkx.pid()); pnp::println!(color = shiny_color, "PSV: {:04}, {}", pkx.psv(), shiny_type); - pnp::println!("Friendship: {}", pkx.ht_friendship()); pnp::println!(""); pnp::println!("HPower: {}", pkx.hidden_power_t()); + pnp::println!("PP Remaining: {}", (pkx.move1_pp() + pkx.move2_pp() + pkx.move3_pp() + pkx.move4_pp())); print_stat!(iv_hp, ev_hp, Hp, &nature_stat, "HP "); print_stat!(iv_atk, ev_atk, Atk, &nature_stat, "Atk "); print_stat!(iv_def, ev_def, Def, &nature_stat, "Def "); diff --git a/reader_core/src/gen7/draw.rs b/reader_core/src/gen7/draw.rs index 78f5233..6f56c0f 100644 --- a/reader_core/src/gen7/draw.rs +++ b/reader_core/src/gen7/draw.rs @@ -5,7 +5,11 @@ use crate::{ utils::{format_egg_parent, is_daycare_masuda_method}, }; -pub use crate::draw::{draw_header, draw_pkx}; +const WHITE: u32 = 0xffffff; +const GREEN: u32 = 0x00cc00; +const RED: u32 = 0xff0000; + +pub use crate::draw::{draw_header, draw_pkx, draw_pkx_brief}; pub fn draw_rng(reader: &Gen7Reader, rng: &RngWrapper) { let sfmt_state = rng.current_state(); @@ -30,11 +34,25 @@ pub fn draw_citra_info(reader: &Gen7Reader) { pnp::println!("Time offset: {}", main_rng_seed_context.time_offset_ms); } -pub fn draw_sos(reader: &Gen7Reader) { +pub fn draw_sos(reader: &Gen7Reader, slot: u32) { pnp::println!("SOS Seed: {:08X}", reader.sos_seed()); + if reader.orb_active() { + pnp::println!(color = GREEN, "Orb Active") + } else { + pnp::println!(color = RED, "Orb Not Active"); + + } pnp::println!("SOS Chain Length: {}", reader.sos_chain()); + pnp::println!("Caller Slot: {}", slot); + let caller_pp = reader.get_pp(&reader.sos_caller_pkm(slot)); + if caller_pp > 1 { + pnp::println!(color= WHITE, "Caller PP: {}", caller_pp); + } else { + pnp::println!(color=RED, "Caller PP: {} !", caller_pp); + } pnp::println!(""); - draw_pkx(&reader.sos_pkm()); + pnp::println!("Ally Data (Slot {}):", reader.ally_slot(slot) + 1); + draw_pkx_brief(&reader.sos_ally_pkm(slot)); } pub fn draw_daycare(reader: &Gen7Reader) { diff --git a/reader_core/src/gen7/frame.rs b/reader_core/src/gen7/frame.rs index 307d69c..d8cfe2b 100644 --- a/reader_core/src/gen7/frame.rs +++ b/reader_core/src/gen7/frame.rs @@ -47,8 +47,9 @@ struct PersistedState { show_view: ShowView, view: Gen7View, main_menu: Menu<8, Gen7View>, - wild_menu: SubMenu<1, 6>, + wild_menu: SubMenu<1, 4>, party_menu: SubMenu<1, 6>, + sos_menu: SubMenu<1, 4>, pelago_menu: SubMenu<1, 3>, } @@ -59,7 +60,8 @@ unsafe fn get_state() -> &'static mut PersistedState { view: Gen7View::MainMenu, party_menu: SubMenu::default(), pelago_menu: SubMenu::default(), - wild_menu: SubMenu::default(), + wild_menu: SubMenu::default(), + sos_menu: SubMenu::default(), main_menu: Menu::new([ MenuOption::new(Gen7View::Rng), MenuOption::new(Gen7View::Daycare), @@ -102,7 +104,10 @@ fn run_frame(reader: Gen7Reader) { let slot = state.wild_menu.update_and_draw(is_locked); draw_pkx(&reader.wild_pkm((slot - 1) as u32)); } - Gen7View::Sos => draw_sos(&reader), + Gen7View::Sos => { + let caller_slot = state.sos_menu.update_headless(is_locked); + draw_sos(&reader, caller_slot as u32); + } Gen7View::Box => draw_pkx(&reader.box_pkm()), Gen7View::Citra => draw_citra_info(&reader), Gen7View::Party => { diff --git a/reader_core/src/gen7/reader.rs b/reader_core/src/gen7/reader.rs index 06ca60e..411b955 100644 --- a/reader_core/src/gen7/reader.rs +++ b/reader_core/src/gen7/reader.rs @@ -1,7 +1,7 @@ use super::{game_lib, hook}; use crate::pnp; use core::num::{NonZeroU32, NonZeroU8}; -use pkm_rs::{Pk7, PokeCrypto}; +use pkm_rs::{Pk7, PokeCrypto, Pkx}; struct Gen7Addresses { initial_seed: u32, @@ -10,7 +10,11 @@ struct Gen7Addresses { party: u32, wild: u32, sos: u32, + sos_index: u32, + orb_active: u32, sos_chain_length: u32, + ally_id: u32, + prev_call_succeed: u32, pelago: u32, egg_ready: u32, egg: u32, @@ -32,7 +36,11 @@ const SM_ADDRESSES: Gen7Addresses = Gen7Addresses { party: 0x34195e10, wild: 0x3002f7b8, sos: 0x3002f7b8, + sos_index: 0x30039614, + orb_active: 0x3003961c, sos_chain_length: 0x3003960d, + ally_id: 0x3003961e, + prev_call_succeed: 0x3003961f, pelago: 0x331110ca, egg_ready: 0x3313edd8, egg: 0x3313eddc, @@ -54,7 +62,11 @@ const USUM_ADDRESSES: Gen7Addresses = Gen7Addresses { party: 0x33f7fa44, wild: 0x3002f9a0, sos: 0x3002f9a0, + sos_index: 0x300397F0, + orb_active: 0x300397f8, sos_chain_length: 0x300397f9, + ally_id: 0x300397fA, + prev_call_succeed: 0x300397fb, pelago: 0x3304d16a, egg_ready: 0x3307b1e8, egg: 0x3307b1ec, @@ -140,6 +152,12 @@ impl Gen7Reader { pub fn sos_chain(&self) -> u8 { pnp::read(self.addrs.sos_chain_length) } + pub fn orb_active(&self) -> bool { + ((pnp::read::(self.addrs.orb_active) & 0x1) > 0) as bool + } + pub fn ally_slot(&self, caller_slot: u32) -> u32 { + (caller_slot + (self.sos_chain() as u32 % 3)) % 4 + } fn read_pk7(&self, offset: u32) -> Pk7 { let bytes = pnp::read_array::<{ Pk7::STORED_SIZE }>(offset); @@ -183,8 +201,14 @@ impl Gen7Reader { self.read_pk7((slot * 236) + self.addrs.pelago) } - pub fn sos_pkm(&self) -> Pk7 { - self.read_pk7(self.addrs.sos) + pub fn sos_caller_pkm(&self, caller_slot: u32) -> Pk7 { + self.read_pk7(((caller_slot - 1) * 484) + self.addrs.sos) + } + pub fn sos_ally_pkm(&self, caller_slot: u32) -> Pk7 { + self.read_pk7((self.ally_slot(caller_slot) * 484) + self.addrs.sos) + } + pub fn get_pp(&self, pkx: &impl Pkx) -> u32 { + pkx.move1_pp() as u32 + pkx.move2_pp() as u32 + pkx.move3_pp() as u32 + pkx.move4_pp() as u32 } pub fn is_egg_ready(&self) -> bool { diff --git a/reader_core/src/utils/sub_menu.rs b/reader_core/src/utils/sub_menu.rs index abb7974..4448fbb 100644 --- a/reader_core/src/utils/sub_menu.rs +++ b/reader_core/src/utils/sub_menu.rs @@ -30,4 +30,8 @@ impl SubMenu { self.draw_header(); self.counter.value() } + pub fn update_headless(&mut self, is_locked: bool) -> usize { + self.update_counter(is_locked); + self.counter.value() + } } From 46a6465dbe2b64ee16e4ecdb787c691fda3eb3ee Mon Sep 17 00:00:00 2001 From: serenagrace Date: Mon, 6 Oct 2025 21:35:51 -0500 Subject: [PATCH 05/39] v0.8.1 Cleaned up some output ordering --- reader_core/Cargo.lock | 2 +- reader_core/Cargo.toml | 2 +- reader_core/src/draw.rs | 1 - reader_core/src/gen7/draw.rs | 3 +-- 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/reader_core/Cargo.lock b/reader_core/Cargo.lock index cac726b..75b4a89 100644 --- a/reader_core/Cargo.lock +++ b/reader_core/Cargo.lock @@ -133,7 +133,7 @@ dependencies = [ [[package]] name = "pokereader" -version = "0.8.0" +version = "0.8.1" dependencies = [ "binrw 0.14.0", "chrono", diff --git a/reader_core/Cargo.toml b/reader_core/Cargo.toml index c254d7c..5b03dc2 100644 --- a/reader_core/Cargo.toml +++ b/reader_core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pokereader" -version = "0.8.0" +version = "0.8.1" edition = "2021" [dependencies] diff --git a/reader_core/src/draw.rs b/reader_core/src/draw.rs index 0eb4f16..c385396 100644 --- a/reader_core/src/draw.rs +++ b/reader_core/src/draw.rs @@ -124,7 +124,6 @@ pub fn draw_pkx_brief(pkx: &impl Pkx) { pnp::println!("Ability: ({}) {}", pkx.ability_number_t(), ability); pnp::println!("PID: {:08X}", pkx.pid()); pnp::println!(color = shiny_color, "PSV: {:04}, {}", pkx.psv(), shiny_type); - pnp::println!(""); pnp::println!("HPower: {}", pkx.hidden_power_t()); pnp::println!("{} {} {} {} {} {}", iv_hp, iv_atk, iv_def, iv_spa, iv_spd, iv_spe); } diff --git a/reader_core/src/gen7/draw.rs b/reader_core/src/gen7/draw.rs index 6f56c0f..d4e7a23 100644 --- a/reader_core/src/gen7/draw.rs +++ b/reader_core/src/gen7/draw.rs @@ -36,14 +36,13 @@ pub fn draw_citra_info(reader: &Gen7Reader) { pub fn draw_sos(reader: &Gen7Reader, slot: u32) { pnp::println!("SOS Seed: {:08X}", reader.sos_seed()); + pnp::println!("SOS Chain Length: {}", reader.sos_chain()); if reader.orb_active() { pnp::println!(color = GREEN, "Orb Active") } else { pnp::println!(color = RED, "Orb Not Active"); } - pnp::println!("SOS Chain Length: {}", reader.sos_chain()); - pnp::println!("Caller Slot: {}", slot); let caller_pp = reader.get_pp(&reader.sos_caller_pkm(slot)); if caller_pp > 1 { pnp::println!(color= WHITE, "Caller PP: {}", caller_pp); From b6128c4d8d9862b2b0ea5987b5173fd78e73f00c Mon Sep 17 00:00:00 2001 From: serenagrace Date: Mon, 6 Oct 2025 22:40:49 -0500 Subject: [PATCH 06/39] 0.8.2 Added annotation to Caller Slot on SOS menu --- reader_core/Cargo.lock | 2 +- reader_core/Cargo.toml | 2 +- reader_core/src/gen7/draw.rs | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/reader_core/Cargo.lock b/reader_core/Cargo.lock index 75b4a89..a8b2bdd 100644 --- a/reader_core/Cargo.lock +++ b/reader_core/Cargo.lock @@ -133,7 +133,7 @@ dependencies = [ [[package]] name = "pokereader" -version = "0.8.1" +version = "0.8.2" dependencies = [ "binrw 0.14.0", "chrono", diff --git a/reader_core/Cargo.toml b/reader_core/Cargo.toml index 5b03dc2..fcf5cfb 100644 --- a/reader_core/Cargo.toml +++ b/reader_core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pokereader" -version = "0.8.1" +version = "0.8.2" edition = "2021" [dependencies] diff --git a/reader_core/src/gen7/draw.rs b/reader_core/src/gen7/draw.rs index d4e7a23..f7555fb 100644 --- a/reader_core/src/gen7/draw.rs +++ b/reader_core/src/gen7/draw.rs @@ -43,6 +43,7 @@ pub fn draw_sos(reader: &Gen7Reader, slot: u32) { pnp::println!(color = RED, "Orb Not Active"); } + pnp::println!("Caller Slot: {}", slot); let caller_pp = reader.get_pp(&reader.sos_caller_pkm(slot)); if caller_pp > 1 { pnp::println!(color= WHITE, "Caller PP: {}", caller_pp); From 4580e8f4d9919db7c4d1e430fe7a330b3791af14 Mon Sep 17 00:00:00 2001 From: Serena Belveal <57582123+serenagrace@users.noreply.github.com> Date: Tue, 7 Oct 2025 11:55:40 -0500 Subject: [PATCH 07/39] Update reader.rs Fix off-by-one in SOS ally slot --- reader_core/src/gen7/reader.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reader_core/src/gen7/reader.rs b/reader_core/src/gen7/reader.rs index 411b955..6b46cc2 100644 --- a/reader_core/src/gen7/reader.rs +++ b/reader_core/src/gen7/reader.rs @@ -156,7 +156,7 @@ impl Gen7Reader { ((pnp::read::(self.addrs.orb_active) & 0x1) > 0) as bool } pub fn ally_slot(&self, caller_slot: u32) -> u32 { - (caller_slot + (self.sos_chain() as u32 % 3)) % 4 + ((caller_slot - 1) + (self.sos_chain() as u32 % 3)) % 4 } fn read_pk7(&self, offset: u32) -> Pk7 { From 112bdb09e0d06ef734d0c59a33ef1a148827fdd2 Mon Sep 17 00:00:00 2001 From: serenagrace Date: Tue, 7 Oct 2025 13:46:08 -0500 Subject: [PATCH 08/39] v0.8.3 - Refactored pp calls, updated brief IV drawing --- 3gx/PokeReader.plgInfo | 4 ++-- reader_core/Cargo.lock | 2 +- reader_core/Cargo.toml | 2 +- reader_core/src/draw.rs | 17 +++++++++++++++-- reader_core/src/gen7/draw.rs | 6 +----- reader_core/src/gen7/reader.rs | 6 +++--- 6 files changed, 23 insertions(+), 14 deletions(-) diff --git a/3gx/PokeReader.plgInfo b/3gx/PokeReader.plgInfo index 56ebc95..b9e0e00 100644 --- a/3gx/PokeReader.plgInfo +++ b/3gx/PokeReader.plgInfo @@ -2,8 +2,8 @@ Author: Zaksabeast Version: # Plugin version Major: 1 - Minor: 7 - Revision: 5 + Minor: 8 + Revision: 3 Targets: # Low TitleId of games which are compatibles with this plugin (empty for all) 0x00055D00 diff --git a/reader_core/Cargo.lock b/reader_core/Cargo.lock index a8b2bdd..793d526 100644 --- a/reader_core/Cargo.lock +++ b/reader_core/Cargo.lock @@ -133,7 +133,7 @@ dependencies = [ [[package]] name = "pokereader" -version = "0.8.2" +version = "0.8.3" dependencies = [ "binrw 0.14.0", "chrono", diff --git a/reader_core/Cargo.toml b/reader_core/Cargo.toml index fcf5cfb..8689718 100644 --- a/reader_core/Cargo.toml +++ b/reader_core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pokereader" -version = "0.8.2" +version = "0.8.3" edition = "2021" [dependencies] diff --git a/reader_core/src/draw.rs b/reader_core/src/draw.rs index c385396..a78d509 100644 --- a/reader_core/src/draw.rs +++ b/reader_core/src/draw.rs @@ -88,6 +88,10 @@ fn nature_stat_str(nature_stat: &NatureStat, stat: Stat) -> &'static str { " " } +fn get_pp(pkx: &impl Pkx) -> u32 { + pkx.move1_pp() as u32 + pkx.move2_pp() as u32 + pkx.move3_pp() as u32 + pkx.move4_pp() as u32 +} + macro_rules! print_stat { ($iv:expr, $ev:expr, $stat:expr, $nature_stat:expr, $name:expr) => { pnp::println!( @@ -101,6 +105,15 @@ macro_rules! print_stat { }; } +macro_rules! print_pp { + ($pp:expr) => { + pnp::println!( + color = if $pp > 1 { WHITE } else { RED }, + "PP Remaining: {}", $pp + ); + } +} + pub fn draw_pkx_brief(pkx: &impl Pkx) { let species = pkx.species_t().to_string(); let ability = pkx.ability_t().to_string(); @@ -125,7 +138,7 @@ pub fn draw_pkx_brief(pkx: &impl Pkx) { pnp::println!("PID: {:08X}", pkx.pid()); pnp::println!(color = shiny_color, "PSV: {:04}, {}", pkx.psv(), shiny_type); pnp::println!("HPower: {}", pkx.hidden_power_t()); - pnp::println!("{} {} {} {} {} {}", iv_hp, iv_atk, iv_def, iv_spa, iv_spd, iv_spe); + pnp::println!("IVs: {}/{}/{}/{}/{}/{}", iv_hp, iv_atk, iv_def, iv_spa, iv_spd, iv_spe); } pub fn draw_pkx(pkx: &impl Pkx) { @@ -161,7 +174,7 @@ pub fn draw_pkx(pkx: &impl Pkx) { pnp::println!(color = shiny_color, "PSV: {:04}, {}", pkx.psv(), shiny_type); pnp::println!(""); pnp::println!("HPower: {}", pkx.hidden_power_t()); - pnp::println!("PP Remaining: {}", (pkx.move1_pp() + pkx.move2_pp() + pkx.move3_pp() + pkx.move4_pp())); + print_pp!(get_pp(pkx)); print_stat!(iv_hp, ev_hp, Hp, &nature_stat, "HP "); print_stat!(iv_atk, ev_atk, Atk, &nature_stat, "Atk "); print_stat!(iv_def, ev_def, Def, &nature_stat, "Def "); diff --git a/reader_core/src/gen7/draw.rs b/reader_core/src/gen7/draw.rs index f7555fb..ad8fd7f 100644 --- a/reader_core/src/gen7/draw.rs +++ b/reader_core/src/gen7/draw.rs @@ -45,11 +45,7 @@ pub fn draw_sos(reader: &Gen7Reader, slot: u32) { } pnp::println!("Caller Slot: {}", slot); let caller_pp = reader.get_pp(&reader.sos_caller_pkm(slot)); - if caller_pp > 1 { - pnp::println!(color= WHITE, "Caller PP: {}", caller_pp); - } else { - pnp::println!(color=RED, "Caller PP: {} !", caller_pp); - } + pnp::println!(color= if caller_pp > 1 { WHITE } else { RED }, "Caller PP: {}", caller_pp); pnp::println!(""); pnp::println!("Ally Data (Slot {}):", reader.ally_slot(slot) + 1); draw_pkx_brief(&reader.sos_ally_pkm(slot)); diff --git a/reader_core/src/gen7/reader.rs b/reader_core/src/gen7/reader.rs index 6b46cc2..c63c70c 100644 --- a/reader_core/src/gen7/reader.rs +++ b/reader_core/src/gen7/reader.rs @@ -1,7 +1,7 @@ use super::{game_lib, hook}; use crate::pnp; use core::num::{NonZeroU32, NonZeroU8}; -use pkm_rs::{Pk7, PokeCrypto, Pkx}; +use pkm_rs::{Pk7, Pkx, PokeCrypto}; struct Gen7Addresses { initial_seed: u32, @@ -207,8 +207,8 @@ impl Gen7Reader { pub fn sos_ally_pkm(&self, caller_slot: u32) -> Pk7 { self.read_pk7((self.ally_slot(caller_slot) * 484) + self.addrs.sos) } - pub fn get_pp(&self, pkx: &impl Pkx) -> u32 { - pkx.move1_pp() as u32 + pkx.move2_pp() as u32 + pkx.move3_pp() as u32 + pkx.move4_pp() as u32 + pub fn get_pp(&self, pkm: &Pk7) -> u32 { + pkm.move1_pp() as u32 + pkm.move2_pp() as u32 + pkm.move3_pp() as u32 + pkm.move4_pp() as u32 } pub fn is_egg_ready(&self) -> bool { From e5bf4b80b106f05f82c8c9c743d2b1ce1a4bf58e Mon Sep 17 00:00:00 2001 From: serenagrace Date: Tue, 7 Oct 2025 16:02:49 -0500 Subject: [PATCH 09/39] v0.8.4 - Added Submenu with Capture for tracking correction value for SOS ally slot - Hold X and press Right on the dPad to set the caller slot to the current ally slot - Hold X and press Up/Down on the dPad to increment/decrement caller slot manually - When a new Caller slot is set, the current chain length is saved as state in order to determine future ally slots (correction value) - Updated README with new controls - Added coloration to Egg Ready, Masuda, and Charm text --- 3gx/PokeReader.plgInfo | 2 +- README.md | 3 ++ reader_core/Cargo.lock | 2 +- reader_core/Cargo.toml | 2 +- reader_core/src/gen7/draw.rs | 12 +++--- reader_core/src/gen7/frame.rs | 16 ++++++-- reader_core/src/gen7/reader.rs | 10 +++-- reader_core/src/utils/circular_counter.rs | 4 ++ reader_core/src/utils/mod.rs | 1 + reader_core/src/utils/sub_menu_capture.rs | 50 +++++++++++++++++++++++ 10 files changed, 85 insertions(+), 17 deletions(-) create mode 100644 reader_core/src/utils/sub_menu_capture.rs diff --git a/3gx/PokeReader.plgInfo b/3gx/PokeReader.plgInfo index b9e0e00..5b1ab74 100644 --- a/3gx/PokeReader.plgInfo +++ b/3gx/PokeReader.plgInfo @@ -3,7 +3,7 @@ Author: Zaksabeast Version: # Plugin version Major: 1 Minor: 8 - Revision: 3 + Revision: 4 Targets: # Low TitleId of games which are compatibles with this plugin (empty for all) 0x00055D00 diff --git a/README.md b/README.md index ac92e35..3ec69c6 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,9 @@ This information can be used to RNG shiny and high IV Pokemon, similar to lua sc - Start + Select: Pause game and enable manual frame advancing - Select: Advance one frame while paused - Start or A: Unpause game +- SOS Menu Commands: + - X + Right (D-Pad): Set SOS Caller slot to current Ally slot + - X + Up/Down: Manually increment/decrement Caller slot ## Installing diff --git a/reader_core/Cargo.lock b/reader_core/Cargo.lock index 793d526..4022b9c 100644 --- a/reader_core/Cargo.lock +++ b/reader_core/Cargo.lock @@ -133,7 +133,7 @@ dependencies = [ [[package]] name = "pokereader" -version = "0.8.3" +version = "0.8.4" dependencies = [ "binrw 0.14.0", "chrono", diff --git a/reader_core/Cargo.toml b/reader_core/Cargo.toml index 8689718..3bc9b9a 100644 --- a/reader_core/Cargo.toml +++ b/reader_core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pokereader" -version = "0.8.3" +version = "0.8.4" edition = "2021" [dependencies] diff --git a/reader_core/src/gen7/draw.rs b/reader_core/src/gen7/draw.rs index ad8fd7f..f9b1c0d 100644 --- a/reader_core/src/gen7/draw.rs +++ b/reader_core/src/gen7/draw.rs @@ -34,7 +34,7 @@ pub fn draw_citra_info(reader: &Gen7Reader) { pnp::println!("Time offset: {}", main_rng_seed_context.time_offset_ms); } -pub fn draw_sos(reader: &Gen7Reader, slot: u32) { +pub fn draw_sos(reader: &Gen7Reader, slot: u32, correction: u32, is_locked: bool) { pnp::println!("SOS Seed: {:08X}", reader.sos_seed()); pnp::println!("SOS Chain Length: {}", reader.sos_chain()); if reader.orb_active() { @@ -47,8 +47,8 @@ pub fn draw_sos(reader: &Gen7Reader, slot: u32) { let caller_pp = reader.get_pp(&reader.sos_caller_pkm(slot)); pnp::println!(color= if caller_pp > 1 { WHITE } else { RED }, "Caller PP: {}", caller_pp); pnp::println!(""); - pnp::println!("Ally Data (Slot {}):", reader.ally_slot(slot) + 1); - draw_pkx_brief(&reader.sos_ally_pkm(slot)); + pnp::println!("Ally Data (Slot {}):", reader.ally_slot(slot, correction) + 1); + draw_pkx_brief(&reader.sos_ally_pkm(slot, correction)); } pub fn draw_daycare(reader: &Gen7Reader) { @@ -59,7 +59,7 @@ pub fn draw_daycare(reader: &Gen7Reader) { let has_shiny_charm = reader.has_shiny_charm(); let is_masuda_method = is_daycare_masuda_method(&parent1, &parent2); - pnp::println!("Egg Ready: {}", is_egg_ready); + pnp::println!(color= if is_egg_ready {GREEN} else {WHITE}, "Egg Ready: {}", is_egg_ready); pnp::println!("{}", format_egg_parent(1, &parent1)); pnp::println!("{}", format_egg_parent(2, &parent2)); pnp::println!(""); @@ -68,6 +68,6 @@ pub fn draw_daycare(reader: &Gen7Reader) { pnp::println!("Egg[1]: {:08X}", egg_seed[1]); pnp::println!("Egg[0]: {:08X}", egg_seed[0]); pnp::println!(""); - pnp::println!("Shiny Charm: {}", has_shiny_charm); - pnp::println!("Masuda Method: {}", is_masuda_method); + pnp::println!(color= if has_shiny_charm {GREEN} else {WHITE}, "Shiny Charm: {}", has_shiny_charm); + pnp::println!(color= if is_masuda_method {GREEN} else {WHITE}, "Masuda Method: {}", is_masuda_method); } diff --git a/reader_core/src/gen7/frame.rs b/reader_core/src/gen7/frame.rs index d8cfe2b..47be337 100644 --- a/reader_core/src/gen7/frame.rs +++ b/reader_core/src/gen7/frame.rs @@ -8,6 +8,7 @@ use crate::{ utils::{ menu::{Menu, MenuOption, MenuOptionValue}, sub_menu::SubMenu, + sub_menu_capture::SubMenuCapture, ShowView, }, }; @@ -49,7 +50,7 @@ struct PersistedState { main_menu: Menu<8, Gen7View>, wild_menu: SubMenu<1, 4>, party_menu: SubMenu<1, 6>, - sos_menu: SubMenu<1, 4>, + sos_menu: SubMenuCapture<1, 4>, pelago_menu: SubMenu<1, 3>, } @@ -61,7 +62,7 @@ unsafe fn get_state() -> &'static mut PersistedState { party_menu: SubMenu::default(), pelago_menu: SubMenu::default(), wild_menu: SubMenu::default(), - sos_menu: SubMenu::default(), + sos_menu: SubMenuCapture::default(), main_menu: Menu::new([ MenuOption::new(Gen7View::Rng), MenuOption::new(Gen7View::Daycare), @@ -105,8 +106,15 @@ fn run_frame(reader: Gen7Reader) { draw_pkx(&reader.wild_pkm((slot - 1) as u32)); } Gen7View::Sos => { - let caller_slot = state.sos_menu.update_headless(is_locked); - draw_sos(&reader, caller_slot as u32); + let prev_caller_slot = state.sos_menu.counter_value(); + let prev_correction_value = state.sos_menu.captured_value(); + let caller_slot = state.sos_menu.update_headless( + is_locked, + reader.sos_chain() as u32, + reader.ally_slot(prev_caller_slot as u32, prev_correction_value) as usize + 1 + ); + let correction_value = state.sos_menu.captured_value(); + draw_sos(&reader, caller_slot as u32, correction_value, is_locked); } Gen7View::Box => draw_pkx(&reader.box_pkm()), Gen7View::Citra => draw_citra_info(&reader), diff --git a/reader_core/src/gen7/reader.rs b/reader_core/src/gen7/reader.rs index c63c70c..353eac1 100644 --- a/reader_core/src/gen7/reader.rs +++ b/reader_core/src/gen7/reader.rs @@ -155,8 +155,10 @@ impl Gen7Reader { pub fn orb_active(&self) -> bool { ((pnp::read::(self.addrs.orb_active) & 0x1) > 0) as bool } - pub fn ally_slot(&self, caller_slot: u32) -> u32 { - ((caller_slot - 1) + (self.sos_chain() as u32 % 3)) % 4 + pub fn ally_slot(&self, caller_slot: u32, correction: u32) -> u32 { + if self.sos_chain() == 0 { 0 } else { + ((caller_slot - 1) + ((self.sos_chain() as i32 - (correction as i32 + 1)) % 3) as u32 + 1) % 4 + } } fn read_pk7(&self, offset: u32) -> Pk7 { @@ -204,8 +206,8 @@ impl Gen7Reader { pub fn sos_caller_pkm(&self, caller_slot: u32) -> Pk7 { self.read_pk7(((caller_slot - 1) * 484) + self.addrs.sos) } - pub fn sos_ally_pkm(&self, caller_slot: u32) -> Pk7 { - self.read_pk7((self.ally_slot(caller_slot) * 484) + self.addrs.sos) + pub fn sos_ally_pkm(&self, caller_slot: u32, correction: u32) -> Pk7 { + self.read_pk7((self.ally_slot(caller_slot, correction) * 484) + self.addrs.sos) } pub fn get_pp(&self, pkm: &Pk7) -> u32 { pkm.move1_pp() as u32 + pkm.move2_pp() as u32 + pkm.move3_pp() as u32 + pkm.move4_pp() as u32 diff --git a/reader_core/src/utils/circular_counter.rs b/reader_core/src/utils/circular_counter.rs index 5b7dcb7..34635e6 100644 --- a/reader_core/src/utils/circular_counter.rs +++ b/reader_core/src/utils/circular_counter.rs @@ -27,6 +27,10 @@ impl CircularCounter { self.value } + pub fn set(&mut self, value: usize) -> usize { + self.value = if value < MIN {MIN} else { if value > MAX {MAX} else {value} }; + self.value + } } impl Default for CircularCounter { diff --git a/reader_core/src/utils/mod.rs b/reader_core/src/utils/mod.rs index 0987ca3..9838b81 100644 --- a/reader_core/src/utils/mod.rs +++ b/reader_core/src/utils/mod.rs @@ -8,6 +8,7 @@ mod hook_gen6_seed; pub mod menu; mod show_view; pub mod sub_menu; +pub mod sub_menu_capture; pub use circular_counter::*; pub use daycare::*; diff --git a/reader_core/src/utils/sub_menu_capture.rs b/reader_core/src/utils/sub_menu_capture.rs new file mode 100644 index 0000000..265e730 --- /dev/null +++ b/reader_core/src/utils/sub_menu_capture.rs @@ -0,0 +1,50 @@ +use super::CircularCounter; +use crate::pnp; + +#[derive(Default)] +pub struct SubMenuCapture { + counter: CircularCounter, + value: u32 +} + +impl SubMenuCapture { + fn draw_header(&self) { + pnp::println!("Slot {}", self.counter.value()); + pnp::println!("[v] Next | Prev [^]"); + pnp::println!(""); + } + + fn update_counter(&mut self, is_locked: bool, capture_value: u32, set_value: usize) { + if is_locked { + return; + } + + if pnp::is_just_pressed(pnp::Button::Ddown | pnp::Button::X) { + self.counter.increment(); + self.value = capture_value; + } else if pnp::is_just_pressed(pnp::Button::Dup | pnp::Button::X) { + self.counter.decrement(); + self.value = capture_value; + } else if pnp::is_just_pressed(pnp::Button::Dright | pnp::Button::X) { + self.counter.set(set_value); + self.value = capture_value; + } + } + + pub fn update_and_draw(&mut self, is_locked: bool, capture_value: u32, set_value: usize) -> usize { + self.update_counter(is_locked, capture_value, set_value); + self.draw_header(); + self.counter.value() + } + pub fn update_headless(&mut self, is_locked: bool, capture_value: u32, set_value: usize) -> usize { + self.update_counter(is_locked, capture_value, set_value); + self.counter.value() + } + + pub fn captured_value(&mut self) -> u32 { + self.value + } + pub fn counter_value(&self) -> usize { + return self.counter.value(); + } +} From 597918ce972e8f792cd49990d746b04bdaf9f05d Mon Sep 17 00:00:00 2001 From: serenagrace Date: Wed, 8 Oct 2025 08:23:55 -0500 Subject: [PATCH 10/39] Implemented Code Review changes --- 3gx/PokeReader.plgInfo | 4 +-- reader_core/Cargo.lock | 2 +- reader_core/Cargo.toml | 2 +- reader_core/src/draw.rs | 41 ++++++++++++----------- reader_core/src/gen7/draw.rs | 8 ++--- reader_core/src/gen7/frame.rs | 2 +- reader_core/src/utils/circular_counter.rs | 2 +- reader_core/src/utils/sub_menu.rs | 4 --- 8 files changed, 29 insertions(+), 36 deletions(-) diff --git a/3gx/PokeReader.plgInfo b/3gx/PokeReader.plgInfo index 5b1ab74..4e765d4 100644 --- a/3gx/PokeReader.plgInfo +++ b/3gx/PokeReader.plgInfo @@ -2,8 +2,8 @@ Author: Zaksabeast Version: # Plugin version Major: 1 - Minor: 8 - Revision: 4 + Minor: 0 + Revision: 0 Targets: # Low TitleId of games which are compatibles with this plugin (empty for all) 0x00055D00 diff --git a/reader_core/Cargo.lock b/reader_core/Cargo.lock index 4022b9c..cac726b 100644 --- a/reader_core/Cargo.lock +++ b/reader_core/Cargo.lock @@ -133,7 +133,7 @@ dependencies = [ [[package]] name = "pokereader" -version = "0.8.4" +version = "0.8.0" dependencies = [ "binrw 0.14.0", "chrono", diff --git a/reader_core/Cargo.toml b/reader_core/Cargo.toml index 3bc9b9a..c254d7c 100644 --- a/reader_core/Cargo.toml +++ b/reader_core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pokereader" -version = "0.8.4" +version = "0.8.0" edition = "2021" [dependencies] diff --git a/reader_core/src/draw.rs b/reader_core/src/draw.rs index a78d509..7535193 100644 --- a/reader_core/src/draw.rs +++ b/reader_core/src/draw.rs @@ -2,9 +2,9 @@ use crate::alloc::string::ToString; use crate::{pnp, utils::menu::MenuOptionValue}; use pkm_rs::{Nature, Pkx, Shiny}; -const WHITE: u32 = 0xffffff; -const GREEN: u32 = 0x00cc00; -const RED: u32 = 0xff0000; +pub const WHITE: u32 = 0xffffff; +pub const GREEN: u32 = 0x00cc00; +pub const RED: u32 = 0xff0000; fn get_shiny_color(is_shiny: bool) -> u32 { match is_shiny { @@ -105,24 +105,28 @@ macro_rules! print_stat { }; } -macro_rules! print_pp { - ($pp:expr) => { - pnp::println!( - color = if $pp > 1 { WHITE } else { RED }, - "PP Remaining: {}", $pp - ); +pub fn print_pp(pp: u32) { + pnp::println!(color = if pp > 1 { WHITE } else { RED }, + "PP Remaining: {}", pp + ); +} + +pub fn shiny_type(pkx: &impl Pkx) -> &str { + match pkx.shiny_type() { + Some(Shiny::Star) => "Star", + Some(Shiny::Square) => "Square", + None => "Not Shiny", } } + + + pub fn draw_pkx_brief(pkx: &impl Pkx) { let species = pkx.species_t().to_string(); let ability = pkx.ability_t().to_string(); - let shiny_type = match pkx.shiny_type() { - Some(Shiny::Star) => "Star", - Some(Shiny::Square) => "Square", - None => "Not Shiny", - }; + let shiny_type = shiny_type(pkx); let shiny_color = get_shiny_color(pkx.is_shiny()); let iv_hp = pkx.iv_hp(); let iv_atk = pkx.iv_atk(); @@ -145,11 +149,7 @@ pub fn draw_pkx(pkx: &impl Pkx) { let species = pkx.species_t().to_string(); let ability = pkx.ability_t().to_string(); - let shiny_type = match pkx.shiny_type() { - Some(Shiny::Star) => "Star", - Some(Shiny::Square) => "Square", - None => "Not Shiny", - }; + let shiny_type = shiny_type(pkx); let shiny_color = get_shiny_color(pkx.is_shiny()); let iv_hp = pkx.iv_hp(); let iv_atk = pkx.iv_atk(); @@ -172,9 +172,10 @@ pub fn draw_pkx(pkx: &impl Pkx) { pnp::println!("Ability: ({}) {}", pkx.ability_number_t(), ability); pnp::println!("PID: {:08X}", pkx.pid()); pnp::println!(color = shiny_color, "PSV: {:04}, {}", pkx.psv(), shiny_type); + pnp::println!("Friendship: {}", pkx.ht_friendship()); pnp::println!(""); pnp::println!("HPower: {}", pkx.hidden_power_t()); - print_pp!(get_pp(pkx)); + print_pp(get_pp(pkx)); print_stat!(iv_hp, ev_hp, Hp, &nature_stat, "HP "); print_stat!(iv_atk, ev_atk, Atk, &nature_stat, "Atk "); print_stat!(iv_def, ev_def, Def, &nature_stat, "Def "); diff --git a/reader_core/src/gen7/draw.rs b/reader_core/src/gen7/draw.rs index f9b1c0d..0dfb2c9 100644 --- a/reader_core/src/gen7/draw.rs +++ b/reader_core/src/gen7/draw.rs @@ -5,11 +5,7 @@ use crate::{ utils::{format_egg_parent, is_daycare_masuda_method}, }; -const WHITE: u32 = 0xffffff; -const GREEN: u32 = 0x00cc00; -const RED: u32 = 0xff0000; - -pub use crate::draw::{draw_header, draw_pkx, draw_pkx_brief}; +pub use crate::draw::{draw_header, draw_pkx, draw_pkx_brief, GREEN,RED,WHITE}; pub fn draw_rng(reader: &Gen7Reader, rng: &RngWrapper) { let sfmt_state = rng.current_state(); @@ -34,7 +30,7 @@ pub fn draw_citra_info(reader: &Gen7Reader) { pnp::println!("Time offset: {}", main_rng_seed_context.time_offset_ms); } -pub fn draw_sos(reader: &Gen7Reader, slot: u32, correction: u32, is_locked: bool) { +pub fn draw_sos(reader: &Gen7Reader, slot: u32, correction: u32) { pnp::println!("SOS Seed: {:08X}", reader.sos_seed()); pnp::println!("SOS Chain Length: {}", reader.sos_chain()); if reader.orb_active() { diff --git a/reader_core/src/gen7/frame.rs b/reader_core/src/gen7/frame.rs index 47be337..e5786ed 100644 --- a/reader_core/src/gen7/frame.rs +++ b/reader_core/src/gen7/frame.rs @@ -114,7 +114,7 @@ fn run_frame(reader: Gen7Reader) { reader.ally_slot(prev_caller_slot as u32, prev_correction_value) as usize + 1 ); let correction_value = state.sos_menu.captured_value(); - draw_sos(&reader, caller_slot as u32, correction_value, is_locked); + draw_sos(&reader, caller_slot as u32, correction_value); } Gen7View::Box => draw_pkx(&reader.box_pkm()), Gen7View::Citra => draw_citra_info(&reader), diff --git a/reader_core/src/utils/circular_counter.rs b/reader_core/src/utils/circular_counter.rs index 34635e6..3d70b96 100644 --- a/reader_core/src/utils/circular_counter.rs +++ b/reader_core/src/utils/circular_counter.rs @@ -28,7 +28,7 @@ impl CircularCounter { self.value } pub fn set(&mut self, value: usize) -> usize { - self.value = if value < MIN {MIN} else { if value > MAX {MAX} else {value} }; + self.value = value.clamp(MIN, MAX); self.value } } diff --git a/reader_core/src/utils/sub_menu.rs b/reader_core/src/utils/sub_menu.rs index 4448fbb..abb7974 100644 --- a/reader_core/src/utils/sub_menu.rs +++ b/reader_core/src/utils/sub_menu.rs @@ -30,8 +30,4 @@ impl SubMenu { self.draw_header(); self.counter.value() } - pub fn update_headless(&mut self, is_locked: bool) -> usize { - self.update_counter(is_locked); - self.counter.value() - } } From 3fa9736ade0e719c14836586a27ca5a0c015d895 Mon Sep 17 00:00:00 2001 From: serenagrace Date: Wed, 8 Oct 2025 12:27:17 -0500 Subject: [PATCH 11/39] Added Help Menu with more control info Added is-wild switch to draw_pkx --- reader_core/src/crystal/frame.rs | 9 +++- reader_core/src/draw.rs | 69 ++++++++++++++++++++++++++-- reader_core/src/gen6/oras_frame.rs | 13 ++++-- reader_core/src/gen6/xy_frame.rs | 13 ++++-- reader_core/src/gen7/frame.rs | 30 ++++++++++-- reader_core/src/lib.rs | 4 ++ reader_core/src/transporter/frame.rs | 11 ++++- reader_core/src/utils/help_menu.rs | 64 ++++++++++++++++++++++++++ reader_core/src/utils/menu.rs | 6 +-- reader_core/src/utils/mod.rs | 1 + reader_core/src/utils/sub_menu.rs | 6 +++ 11 files changed, 204 insertions(+), 22 deletions(-) create mode 100644 reader_core/src/utils/help_menu.rs diff --git a/reader_core/src/crystal/frame.rs b/reader_core/src/crystal/frame.rs index 5d822ee..3d1fb48 100644 --- a/reader_core/src/crystal/frame.rs +++ b/reader_core/src/crystal/frame.rs @@ -8,6 +8,7 @@ use crate::{ utils::{ menu::{Menu, MenuOption, MenuOptionValue}, sub_menu::SubMenu, + help_menu::HelpMenu, ShowView, }, }; @@ -20,6 +21,7 @@ enum CrystalView { Party, Wild, NonCfw, + HelpMenu } impl MenuOptionValue for CrystalView { @@ -30,6 +32,7 @@ impl MenuOptionValue for CrystalView { Self::Party => "Party", Self::Wild => "Wild", Self::NonCfw => "Non-CFW", + Self::HelpMenu => "Help" } } } @@ -38,8 +41,9 @@ struct PersistedState { frame: usize, show_view: ShowView, view: CrystalView, - main_menu: Menu<4, CrystalView>, + main_menu: Menu<5, CrystalView>, party_menu: SubMenu<1, 6>, + help_menu: HelpMenu } unsafe fn get_state() -> &'static mut PersistedState { @@ -48,11 +52,13 @@ unsafe fn get_state() -> &'static mut PersistedState { show_view: ShowView::default(), view: CrystalView::MainMenu, party_menu: SubMenu::default(), + help_menu: HelpMenu::default(), main_menu: Menu::new([ MenuOption::new(CrystalView::Rng), MenuOption::new(CrystalView::Party), MenuOption::new(CrystalView::Wild), MenuOption::new(CrystalView::NonCfw), + MenuOption::new(CrystalView::HelpMenu) ]), }); Lazy::force_mut(&mut STATE) @@ -91,6 +97,7 @@ pub fn run_frame() { draw_pkx(&reader.party((slot - 1) as u8)); } CrystalView::NonCfw => draw_non_cfw(&reader, state.frame), + CrystalView::HelpMenu => state.help_menu.update_and_draw(is_locked), CrystalView::MainMenu => { state.main_menu.update_view(); state.main_menu.draw(); diff --git a/reader_core/src/draw.rs b/reader_core/src/draw.rs index 7535193..24fb8ca 100644 --- a/reader_core/src/draw.rs +++ b/reader_core/src/draw.rs @@ -1,10 +1,13 @@ use crate::alloc::string::ToString; use crate::{pnp, utils::menu::MenuOptionValue}; use pkm_rs::{Nature, Pkx, Shiny}; +use crate::{VERSION, GIT_HASH}; +use super::title::{loaded_title, LoadedTitle}; pub const WHITE: u32 = 0xffffff; pub const GREEN: u32 = 0x00cc00; pub const RED: u32 = 0xff0000; +pub const MUTED_CYAN: u32 = 0x00cccc; fn get_shiny_color(is_shiny: bool) -> u32 { match is_shiny { @@ -111,7 +114,31 @@ pub fn print_pp(pp: u32) { ); } -pub fn shiny_type(pkx: &impl Pkx) -> &str { +pub fn print_title() { + match loaded_title() { + Ok(title) => { + match title { + LoadedTitle::S => { pnp::println!(color = 0xd75f00, "Pokemon Sun")}, + LoadedTitle::M => { pnp::println!(color = 0xaf5fff, "Pokemon Moon")}, + LoadedTitle::Us => { pnp::println!(color = 0xff5f1f, "Pokemon Ultra Sun")}, + LoadedTitle::Um => { pnp::println!(color = 0xaf00ff,"Pokemon Ultra Moon")}, + LoadedTitle::X => { pnp::println!(color = 0x00ffff, "Pokemon X")}, + LoadedTitle::Y => { pnp::println!(color = 0xd7005f, "Pokemon Y")}, + LoadedTitle::Or => { pnp::println!(color = 0xFF4433,"Pokemon Omega Ruby")}, + LoadedTitle::As => { pnp::println!(color = 0x0000ff, "Pokemon Alpha Sapphire")}, + LoadedTitle::Transporter => { pnp::println!(color = 0xd7ff00, "Pokemon Transporter")}, + LoadedTitle::CrystalEn + | LoadedTitle::CrystalDe + | LoadedTitle::CrystalFr + | LoadedTitle::CrystalEs + | LoadedTitle::CrystalIt => { pnp::println!(color= 0xaf00d7, "Pokemon Crystal")}, + } + }, + Err(_error) => { pnp::println!(color = RED, "???") } + } +} + +pub fn shiny_type(pkx: &impl Pkx) -> &'static str { match pkx.shiny_type() { Some(Shiny::Star) => "Star", Some(Shiny::Square) => "Square", @@ -145,7 +172,7 @@ pub fn draw_pkx_brief(pkx: &impl Pkx) { pnp::println!("IVs: {}/{}/{}/{}/{}/{}", iv_hp, iv_atk, iv_def, iv_spa, iv_spd, iv_spe); } -pub fn draw_pkx(pkx: &impl Pkx) { +pub fn draw_pkx(pkx: &impl Pkx, wild: bool) { let species = pkx.species_t().to_string(); let ability = pkx.ability_t().to_string(); @@ -172,10 +199,14 @@ pub fn draw_pkx(pkx: &impl Pkx) { pnp::println!("Ability: ({}) {}", pkx.ability_number_t(), ability); pnp::println!("PID: {:08X}", pkx.pid()); pnp::println!(color = shiny_color, "PSV: {:04}, {}", pkx.psv(), shiny_type); - pnp::println!("Friendship: {}", pkx.ht_friendship()); + if !wild { // Friendship will always be zero for wild pokemon and does not fit + pnp::println!("Friendship: {}", pkx.ht_friendship()); + } pnp::println!(""); pnp::println!("HPower: {}", pkx.hidden_power_t()); - print_pp(get_pp(pkx)); + if wild { // PP does not matter for Party/Box view as you can just summary + print_pp(get_pp(pkx)); + } print_stat!(iv_hp, ev_hp, Hp, &nature_stat, "HP "); print_stat!(iv_atk, ev_atk, Atk, &nature_stat, "Atk "); print_stat!(iv_def, ev_def, Def, &nature_stat, "Def "); @@ -184,6 +215,36 @@ pub fn draw_pkx(pkx: &impl Pkx) { print_stat!(iv_spe, ev_spe, Spe, &nature_stat, "Spe "); } +pub fn draw_controls_help() { + pnp::println!("[Start] + [Select]:"); + pnp::println!(" - Pause Game"); + pnp::println!(""); + pnp::println!("[Start]/[A]:"); + pnp::println!(" - Unpause Game"); + pnp::println!(""); + pnp::println!("[Select]:"); + pnp::println!(" - Frame Advance"); +} + +pub fn draw_specific_help(draw_func: fn() -> ()) { + draw_func(); +} + +pub fn draw_misc_help() { + pnp::println!("PokeReader"); + draw_version(); + pnp::println!(""); + pnp::println!("Current Title:"); + print_title(); + pnp::println!(""); + pnp::println!("PokemonRNG Discord:"); + pnp::println!(color=MUTED_CYAN, "discord.gg/d8JuAvg"); +} + +pub fn draw_version() { + pnp::println!("Ver {} {}", VERSION, GIT_HASH); +} + pub fn draw_header(main_menu: T, current_view: T, is_locked: bool) { if is_locked { pnp::println!("Unlock X+Y"); diff --git a/reader_core/src/gen6/oras_frame.rs b/reader_core/src/gen6/oras_frame.rs index 6ba097b..634a4d0 100644 --- a/reader_core/src/gen6/oras_frame.rs +++ b/reader_core/src/gen6/oras_frame.rs @@ -11,6 +11,7 @@ use crate::{ utils::{ menu::{Menu, MenuOption, MenuOptionValue}, sub_menu::SubMenu, + help_menu::HelpMenu, ShowView, }, }; @@ -27,6 +28,7 @@ enum OrasView { Party, MirageSpot, SeedRng, + HelpMenu } impl MenuOptionValue for OrasView { @@ -41,6 +43,7 @@ impl MenuOptionValue for OrasView { Self::Party => "Party", Self::MirageSpot => "Mirage Spot", Self::SeedRng => "Seed RNG", + Self::HelpMenu => "Help" } } } @@ -49,9 +52,10 @@ struct PersistedState { rng: Gen6Rng, show_view: ShowView, view: OrasView, - main_menu: Menu<8, OrasView>, + main_menu: Menu<9, OrasView>, party_menu: SubMenu<1, 6>, wild_menu: SubMenu<1, 5>, + help_menu: HelpMenu } unsafe fn get_state() -> &'static mut PersistedState { @@ -61,6 +65,7 @@ unsafe fn get_state() -> &'static mut PersistedState { view: OrasView::MainMenu, party_menu: SubMenu::default(), wild_menu: SubMenu::default(), + help_menu: HelpMenu::default(), main_menu: Menu::new([ MenuOption::new(OrasView::Rng), MenuOption::new(OrasView::Daycare1), @@ -70,6 +75,7 @@ unsafe fn get_state() -> &'static mut PersistedState { MenuOption::new(OrasView::Party), MenuOption::new(OrasView::MirageSpot), MenuOption::new(OrasView::SeedRng), + MenuOption::new(OrasView::HelpMenu) ]), }); Lazy::force_mut(&mut STATE) @@ -100,15 +106,16 @@ pub fn run_oras_frame() { OrasView::Daycare2 => draw_daycare(&reader.daycare2()), OrasView::Wild => { let slot = state.wild_menu.update_and_draw(is_locked); - draw_pkx(&reader.wild_pkm((slot - 1) as u32)); + draw_pkx(&reader.wild_pkm((slot - 1) as u32), true); } OrasView::DexNav => draw_dex_nav(&reader, &state.rng), OrasView::Party => { let slot = state.party_menu.update_and_draw(is_locked); - draw_pkx(&reader.party_pkm((slot - 1) as u32)); + draw_pkx(&reader.party_pkm((slot - 1) as u32), false); } OrasView::SeedRng => draw_seed_rng(&reader, &state.rng), OrasView::MirageSpot => draw_mirage_spot(&reader), + OrasView::HelpMenu => state.help_menu.update_and_draw(is_locked), OrasView::MainMenu => { state.main_menu.update_view(); state.main_menu.draw(); diff --git a/reader_core/src/gen6/xy_frame.rs b/reader_core/src/gen6/xy_frame.rs index 4b1c4ee..2a22cd0 100644 --- a/reader_core/src/gen6/xy_frame.rs +++ b/reader_core/src/gen6/xy_frame.rs @@ -8,6 +8,7 @@ use crate::{ utils::{ menu::{Menu, MenuOption, MenuOptionValue}, sub_menu::SubMenu, + help_menu::HelpMenu, ShowView, }, }; @@ -22,6 +23,7 @@ enum XyView { Radar, Party, SeedRng, + HelpMenu } impl MenuOptionValue for XyView { @@ -34,6 +36,7 @@ impl MenuOptionValue for XyView { Self::Radar => "Radar", Self::Party => "Party", Self::SeedRng => "Seed RNG", + Self::HelpMenu => "Help" } } } @@ -42,9 +45,10 @@ struct PersistedState { rng: Gen6Rng, show_view: ShowView, view: XyView, - main_menu: Menu<6, XyView>, + main_menu: Menu<7, XyView>, party_menu: SubMenu<1, 6>, wild_menu: SubMenu<1, 5>, + help_menu: HelpMenu } unsafe fn get_state() -> &'static mut PersistedState { @@ -54,6 +58,7 @@ unsafe fn get_state() -> &'static mut PersistedState { view: XyView::MainMenu, party_menu: SubMenu::default(), wild_menu: SubMenu::default(), + help_menu: HelpMenu::default(), main_menu: Menu::new([ MenuOption::new(XyView::Rng), MenuOption::new(XyView::Daycare), @@ -61,6 +66,7 @@ unsafe fn get_state() -> &'static mut PersistedState { MenuOption::new(XyView::Radar), MenuOption::new(XyView::Party), MenuOption::new(XyView::SeedRng), + MenuOption::new(XyView::HelpMenu) ]), }); Lazy::force_mut(&mut STATE) @@ -90,14 +96,15 @@ pub fn run_xy_frame() { XyView::Daycare => draw_daycare(&reader.daycare1()), XyView::Wild => { let slot = state.wild_menu.update_and_draw(is_locked); - draw_pkx(&reader.wild_pkm((slot - 1) as u32)); + draw_pkx(&reader.wild_pkm((slot - 1) as u32), true); } XyView::Radar => draw_radar(&reader, &state.rng), XyView::Party => { let slot = state.party_menu.update_and_draw(is_locked); - draw_pkx(&reader.party_pkm((slot - 1) as u32)); + draw_pkx(&reader.party_pkm((slot - 1) as u32), false); } XyView::SeedRng => draw_seed_rng(&reader, &state.rng), + XyView::HelpMenu => state.help_menu.update_and_draw(is_locked), XyView::MainMenu => { state.main_menu.update_view(); state.main_menu.draw(); diff --git a/reader_core/src/gen7/frame.rs b/reader_core/src/gen7/frame.rs index e5786ed..23887aa 100644 --- a/reader_core/src/gen7/frame.rs +++ b/reader_core/src/gen7/frame.rs @@ -8,6 +8,7 @@ use crate::{ utils::{ menu::{Menu, MenuOption, MenuOptionValue}, sub_menu::SubMenu, + help_menu::HelpMenu, sub_menu_capture::SubMenuCapture, ShowView, }, @@ -25,6 +26,7 @@ enum Gen7View { Box, Pelago, Citra, + HelpMenu, } impl MenuOptionValue for Gen7View { @@ -39,6 +41,7 @@ impl MenuOptionValue for Gen7View { Self::Box => "Box", Self::Pelago => "Pelago", Self::Citra => "Citra", + Self::HelpMenu => "Help", } } } @@ -47,7 +50,8 @@ struct PersistedState { sfmt: RngWrapper, show_view: ShowView, view: Gen7View, - main_menu: Menu<8, Gen7View>, + main_menu: Menu<9, Gen7View>, + help_menu: HelpMenu, wild_menu: SubMenu<1, 4>, party_menu: SubMenu<1, 6>, sos_menu: SubMenuCapture<1, 4>, @@ -63,6 +67,20 @@ unsafe fn get_state() -> &'static mut PersistedState { pelago_menu: SubMenu::default(), wild_menu: SubMenu::default(), sos_menu: SubMenuCapture::default(), + help_menu: HelpMenu::new(|| { + pnp::println!("SOS Controls:"); + pnp::println!("[X] + [Right]:"); + pnp::println!(" Set Caller slot to"); + pnp::println!(" the current ally."); + pnp::println!(" Use this when you"); + pnp::println!(" faint the caller."); + pnp::println!(""); + pnp::println!("[X] + [Up]/[Down]:"); + pnp::println!(" Manually change"); + pnp::println!(" the caller slot."); + pnp::println!(" (Not recommended)"); + pnp::println!(""); + }), main_menu: Menu::new([ MenuOption::new(Gen7View::Rng), MenuOption::new(Gen7View::Daycare), @@ -72,6 +90,7 @@ unsafe fn get_state() -> &'static mut PersistedState { MenuOption::new(Gen7View::Box), MenuOption::new(Gen7View::Pelago), MenuOption::new(Gen7View::Citra), + MenuOption::new(Gen7View::HelpMenu), ]), }); Lazy::force_mut(&mut STATE) @@ -103,7 +122,7 @@ fn run_frame(reader: Gen7Reader) { Gen7View::Daycare => draw_daycare(&reader), Gen7View::WildPokemon => { let slot = state.wild_menu.update_and_draw(is_locked); - draw_pkx(&reader.wild_pkm((slot - 1) as u32)); + draw_pkx(&reader.wild_pkm((slot - 1) as u32), true); } Gen7View::Sos => { let prev_caller_slot = state.sos_menu.counter_value(); @@ -116,16 +135,17 @@ fn run_frame(reader: Gen7Reader) { let correction_value = state.sos_menu.captured_value(); draw_sos(&reader, caller_slot as u32, correction_value); } - Gen7View::Box => draw_pkx(&reader.box_pkm()), + Gen7View::Box => draw_pkx(&reader.box_pkm(), false), Gen7View::Citra => draw_citra_info(&reader), Gen7View::Party => { let slot = state.party_menu.update_and_draw(is_locked); - draw_pkx(&reader.party_pkm((slot - 1) as u32)); + draw_pkx(&reader.party_pkm((slot - 1) as u32), false); } Gen7View::Pelago => { let slot = state.pelago_menu.update_and_draw(is_locked); - draw_pkx(&reader.pelago_pkm((slot - 1) as u32)) + draw_pkx(&reader.pelago_pkm((slot - 1) as u32), true) } + Gen7View::HelpMenu => state.help_menu.update_and_draw(is_locked), Gen7View::MainMenu => { state.main_menu.update_view(); state.main_menu.draw(); diff --git a/reader_core/src/lib.rs b/reader_core/src/lib.rs index 8fa65a6..658c808 100644 --- a/reader_core/src/lib.rs +++ b/reader_core/src/lib.rs @@ -17,8 +17,12 @@ mod title; mod transporter; mod utils; +pub const VERSION: &str = env!("CARGO_PKG_VERSION"); +pub const GIT_HASH: &str = env!("GIT_HASH"); + use title::{loaded_title, LoadedTitle, TitleError}; + #[cfg(target_os = "horizon")] #[panic_handler] fn my_panic(info: &core::panic::PanicInfo) -> ! { diff --git a/reader_core/src/transporter/frame.rs b/reader_core/src/transporter/frame.rs index a7d7ad4..8fd51a3 100644 --- a/reader_core/src/transporter/frame.rs +++ b/reader_core/src/transporter/frame.rs @@ -8,6 +8,7 @@ use crate::{ utils::{ menu::{Menu, MenuOption, MenuOptionValue}, sub_menu::SubMenu, + help_menu::HelpMenu, ShowView, }, }; @@ -18,6 +19,7 @@ enum TransporterView { MainMenu, Pokemon, Rng, + HelpMenu } impl MenuOptionValue for TransporterView { @@ -26,6 +28,7 @@ impl MenuOptionValue for TransporterView { Self::MainMenu => "Main Menu", Self::Pokemon => "Pokemon", Self::Rng => "RNG", + Self::HelpMenu => "Help", } } } @@ -34,7 +37,8 @@ struct PersistedState { rng: TransporterRng, show_view: ShowView, view: TransporterView, - main_menu: Menu<2, TransporterView>, + main_menu: Menu<3, TransporterView>, + help_menu: HelpMenu, pokemon_menu: SubMenu<1, 30>, } @@ -44,9 +48,11 @@ unsafe fn get_state() -> &'static mut PersistedState { show_view: ShowView::default(), view: TransporterView::MainMenu, pokemon_menu: SubMenu::default(), + help_menu: HelpMenu::default(), main_menu: Menu::new([ MenuOption::new(TransporterView::Rng), MenuOption::new(TransporterView::Pokemon), + MenuOption::new(TransporterView::HelpMenu) ]), }); Lazy::force_mut(&mut STATE) @@ -77,8 +83,9 @@ pub fn run_frame() { TransporterView::Rng => draw_rng(&state.rng), TransporterView::Pokemon => { let slot = state.pokemon_menu.update_and_draw(is_locked); - draw_pkx(&reader.transported_pkm((slot - 1) as u32)); + draw_pkx(&reader.transported_pkm((slot - 1) as u32), false); } + TransporterView::HelpMenu => state.help_menu.update_and_draw(is_locked), TransporterView::MainMenu => { state.main_menu.update_view(); state.main_menu.draw(); diff --git a/reader_core/src/utils/help_menu.rs b/reader_core/src/utils/help_menu.rs new file mode 100644 index 0000000..7c5a9d9 --- /dev/null +++ b/reader_core/src/utils/help_menu.rs @@ -0,0 +1,64 @@ +use crate::pnp; +use super::sub_menu::SubMenu; +use crate::draw::{draw_controls_help, draw_specific_help, draw_misc_help}; + + +enum HelpView { + Controls, + SpecificControls, + Misc +} + + +pub struct HelpMenu { + specific_help: fn () -> (), + sub_menu: SubMenu<1,3> +} + +impl Default for HelpMenu { + fn default() -> Self { + HelpMenu { + specific_help: || { pnp::println!("No Game-Specific controls.") }, + sub_menu: SubMenu::default() + } + } +} + +fn view(slot: usize) -> HelpView { + match slot { + 1 => HelpView::Controls, + 2 => HelpView::SpecificControls, + 3 => HelpView::Misc, + _ => HelpView::Misc + } +} + +fn print_view(help_view: &HelpView) { + match help_view { + HelpView::Controls => pnp::println!("Controls"), + HelpView::SpecificControls => pnp::println!("Game-Specific Controls"), + HelpView::Misc => pnp::println!("Additional Info") + } +} + +impl HelpMenu { + pub fn new(specific_help: fn() -> ()) -> Self { + Self { + specific_help: specific_help, + sub_menu: SubMenu::default() + } + } + pub fn update_and_draw(&mut self, is_locked: bool) { + let help_view = view(self.sub_menu.update_headless(is_locked)); + print_view(&help_view); + pnp::println!("[v] Next | Prev [^]"); + pnp::println!(""); + + match help_view { + HelpView::Controls => { draw_controls_help() }, + HelpView::SpecificControls => { draw_specific_help(self.specific_help) }, + HelpView::Misc => { draw_misc_help() } + } + + } +} diff --git a/reader_core/src/utils/menu.rs b/reader_core/src/utils/menu.rs index 2ac0e6e..876be0b 100644 --- a/reader_core/src/utils/menu.rs +++ b/reader_core/src/utils/menu.rs @@ -1,7 +1,5 @@ -use crate::{pnp, pnp::Button, utils::CircularCounter}; +use crate::{pnp, pnp::Button, utils::CircularCounter, draw::draw_version}; -const VERSION: &str = env!("CARGO_PKG_VERSION"); -const GIT_HASH: &str = env!("GIT_HASH"); pub trait MenuOptionValue: Copy { fn get_label(option: Self) -> &'static str; @@ -62,7 +60,7 @@ impl Menu { pnp::println!("{} {}", self.cursor_str(index + 1), option.label); } pnp::println!(""); - pnp::println!("Ver {} {}", VERSION, GIT_HASH); + draw_version(); } pub fn update_view(&mut self) { diff --git a/reader_core/src/utils/mod.rs b/reader_core/src/utils/mod.rs index 9838b81..d0226b9 100644 --- a/reader_core/src/utils/mod.rs +++ b/reader_core/src/utils/mod.rs @@ -8,6 +8,7 @@ mod hook_gen6_seed; pub mod menu; mod show_view; pub mod sub_menu; +pub mod help_menu; pub mod sub_menu_capture; pub use circular_counter::*; diff --git a/reader_core/src/utils/sub_menu.rs b/reader_core/src/utils/sub_menu.rs index abb7974..f9f0fce 100644 --- a/reader_core/src/utils/sub_menu.rs +++ b/reader_core/src/utils/sub_menu.rs @@ -30,4 +30,10 @@ impl SubMenu { self.draw_header(); self.counter.value() } + + // For Updating when we want a custom header + pub fn update_headless(&mut self, is_locked: bool) -> usize { + self.update_counter(is_locked); + self.counter.value() + } } From f99f49bcda1e9aeccfbb4c0e2f0cf8edbfe2c151 Mon Sep 17 00:00:00 2001 From: serenagrace Date: Wed, 8 Oct 2025 12:42:54 -0500 Subject: [PATCH 12/39] Fixed coloration for crystal and overflow in specific help --- reader_core/src/crystal/draw.rs | 1 + reader_core/src/crystal/mod.rs | 1 + reader_core/src/draw.rs | 11 ++++++++++- reader_core/src/utils/help_menu.rs | 2 +- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/reader_core/src/crystal/draw.rs b/reader_core/src/crystal/draw.rs index 8d4e07e..96dd483 100644 --- a/reader_core/src/crystal/draw.rs +++ b/reader_core/src/crystal/draw.rs @@ -7,6 +7,7 @@ use crate::pnp::{self, Button}; const WHITE: u32 = 0xffffff; const GREEN: u32 = 0x003c00; const RED: u32 = 0x1f0000; +pub const CRYSTAL_CYAN: u32 = 0x003c3c; fn get_iv_color(iv: u8) -> u32 { match iv { diff --git a/reader_core/src/crystal/mod.rs b/reader_core/src/crystal/mod.rs index 48ff2fa..fa3bf98 100644 --- a/reader_core/src/crystal/mod.rs +++ b/reader_core/src/crystal/mod.rs @@ -7,3 +7,4 @@ mod reader; pub use frame::run_frame; pub use hook::init_crystal; +pub use draw::CRYSTAL_CYAN; diff --git a/reader_core/src/draw.rs b/reader_core/src/draw.rs index 24fb8ca..2857387 100644 --- a/reader_core/src/draw.rs +++ b/reader_core/src/draw.rs @@ -3,6 +3,7 @@ use crate::{pnp, utils::menu::MenuOptionValue}; use pkm_rs::{Nature, Pkx, Shiny}; use crate::{VERSION, GIT_HASH}; use super::title::{loaded_title, LoadedTitle}; +use crate::crystal::CRYSTAL_CYAN; pub const WHITE: u32 = 0xffffff; pub const GREEN: u32 = 0x00cc00; @@ -238,7 +239,15 @@ pub fn draw_misc_help() { print_title(); pnp::println!(""); pnp::println!("PokemonRNG Discord:"); - pnp::println!(color=MUTED_CYAN, "discord.gg/d8JuAvg"); + match loaded_title() { + Ok(LoadedTitle::CrystalEn) + | Ok(LoadedTitle::CrystalEs) + | Ok(LoadedTitle::CrystalDe) + | Ok(LoadedTitle::CrystalFr) + | Ok(LoadedTitle::CrystalIt) => + pnp::println!(color = CRYSTAL_CYAN, "discord.gg/d8JuAvg"), + _ => pnp::println!(color = MUTED_CYAN, "discord.gg/d8JuAvg"), + } } pub fn draw_version() { diff --git a/reader_core/src/utils/help_menu.rs b/reader_core/src/utils/help_menu.rs index 7c5a9d9..af0c232 100644 --- a/reader_core/src/utils/help_menu.rs +++ b/reader_core/src/utils/help_menu.rs @@ -18,7 +18,7 @@ pub struct HelpMenu { impl Default for HelpMenu { fn default() -> Self { HelpMenu { - specific_help: || { pnp::println!("No Game-Specific controls.") }, + specific_help: || { pnp::println!("No Game-Specific info.") }, sub_menu: SubMenu::default() } } From 751687bee1f19c76a2daa2af88bf5e004684796b Mon Sep 17 00:00:00 2001 From: serenagrace Date: Wed, 8 Oct 2025 13:28:32 -0500 Subject: [PATCH 13/39] updated resource urls --- reader_core/src/draw.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/reader_core/src/draw.rs b/reader_core/src/draw.rs index 2857387..587cd6d 100644 --- a/reader_core/src/draw.rs +++ b/reader_core/src/draw.rs @@ -238,15 +238,16 @@ pub fn draw_misc_help() { pnp::println!("Current Title:"); print_title(); pnp::println!(""); - pnp::println!("PokemonRNG Discord:"); + pnp::println!("PokemonRNG Resources:"); + pnp::println!(color=0xd7005f, " pokemonRNG.com"); match loaded_title() { Ok(LoadedTitle::CrystalEn) | Ok(LoadedTitle::CrystalEs) | Ok(LoadedTitle::CrystalDe) | Ok(LoadedTitle::CrystalFr) | Ok(LoadedTitle::CrystalIt) => - pnp::println!(color = CRYSTAL_CYAN, "discord.gg/d8JuAvg"), - _ => pnp::println!(color = MUTED_CYAN, "discord.gg/d8JuAvg"), + pnp::println!(color = CRYSTAL_CYAN, " discord.gg/d8JuAvg"), + _ => pnp::println!(color = MUTED_CYAN, " discord.gg/d8JuAvg"), } } From d77d6c040f4ed4a7d69ee6240b2200626570aa26 Mon Sep 17 00:00:00 2001 From: serenagrace Date: Wed, 8 Oct 2025 21:21:29 -0500 Subject: [PATCH 14/39] Cleanup and corrected friendship --- reader_core/src/draw.rs | 44 ++++++++++++++++------------ reader_core/src/gen6/draw.rs | 2 +- reader_core/src/gen6/oras_frame.rs | 6 ++-- reader_core/src/gen6/xy_frame.rs | 6 ++-- reader_core/src/gen7/draw.rs | 5 ++-- reader_core/src/gen7/frame.rs | 10 +++---- reader_core/src/gen7/reader.rs | 5 +--- reader_core/src/transporter/draw.rs | 2 +- reader_core/src/transporter/frame.rs | 4 +-- 9 files changed, 43 insertions(+), 41 deletions(-) diff --git a/reader_core/src/draw.rs b/reader_core/src/draw.rs index 587cd6d..e61d48d 100644 --- a/reader_core/src/draw.rs +++ b/reader_core/src/draw.rs @@ -36,6 +36,12 @@ enum Stat { } use Stat::*; +#[derive(PartialEq, Eq)] +pub enum PkxType { + Wild, + Tame +} + struct NatureStat { increase: Stat, decrease: Stat, @@ -92,7 +98,7 @@ fn nature_stat_str(nature_stat: &NatureStat, stat: Stat) -> &'static str { " " } -fn get_pp(pkx: &impl Pkx) -> u32 { +pub fn get_pp(pkx: &impl Pkx) -> u32 { pkx.move1_pp() as u32 + pkx.move2_pp() as u32 + pkx.move3_pp() as u32 + pkx.move4_pp() as u32 } @@ -119,20 +125,20 @@ pub fn print_title() { match loaded_title() { Ok(title) => { match title { - LoadedTitle::S => { pnp::println!(color = 0xd75f00, "Pokemon Sun")}, - LoadedTitle::M => { pnp::println!(color = 0xaf5fff, "Pokemon Moon")}, - LoadedTitle::Us => { pnp::println!(color = 0xff5f1f, "Pokemon Ultra Sun")}, - LoadedTitle::Um => { pnp::println!(color = 0xaf00ff,"Pokemon Ultra Moon")}, - LoadedTitle::X => { pnp::println!(color = 0x00ffff, "Pokemon X")}, - LoadedTitle::Y => { pnp::println!(color = 0xd7005f, "Pokemon Y")}, - LoadedTitle::Or => { pnp::println!(color = 0xFF4433,"Pokemon Omega Ruby")}, - LoadedTitle::As => { pnp::println!(color = 0x0000ff, "Pokemon Alpha Sapphire")}, - LoadedTitle::Transporter => { pnp::println!(color = 0xd7ff00, "Pokemon Transporter")}, + LoadedTitle::S => { pnp::println!(color = 0xd75f00, " Pokemon Sun")}, + LoadedTitle::M => { pnp::println!(color = 0xaf5fff, " Pokemon Moon")}, + LoadedTitle::Us => { pnp::println!(color = 0xff5f1f, " Pokemon Ultra Sun")}, + LoadedTitle::Um => { pnp::println!(color = 0xaf00ff," Pokemon Ultra Moon")}, + LoadedTitle::X => { pnp::println!(color = 0x00ffff, " Pokemon X")}, + LoadedTitle::Y => { pnp::println!(color = 0xd7005f, " Pokemon Y")}, + LoadedTitle::Or => { pnp::println!(color = 0xFF4433," Pokemon Omega Ruby")}, + LoadedTitle::As => { pnp::println!(color = 0x0000ff, " Pokemon Alpha Sapphire")}, + LoadedTitle::Transporter => { pnp::println!(color = 0xd7ff00, " Pokemon Transporter")}, LoadedTitle::CrystalEn | LoadedTitle::CrystalDe | LoadedTitle::CrystalFr | LoadedTitle::CrystalEs - | LoadedTitle::CrystalIt => { pnp::println!(color= 0xaf00d7, "Pokemon Crystal")}, + | LoadedTitle::CrystalIt => { pnp::println!(color= 0xaf00d7, " Pokemon Crystal")}, } }, Err(_error) => { pnp::println!(color = RED, "???") } @@ -173,7 +179,7 @@ pub fn draw_pkx_brief(pkx: &impl Pkx) { pnp::println!("IVs: {}/{}/{}/{}/{}/{}", iv_hp, iv_atk, iv_def, iv_spa, iv_spd, iv_spe); } -pub fn draw_pkx(pkx: &impl Pkx, wild: bool) { +pub fn draw_pkx(pkx: &impl Pkx, pkx_type: PkxType) { let species = pkx.species_t().to_string(); let ability = pkx.ability_t().to_string(); @@ -200,12 +206,12 @@ pub fn draw_pkx(pkx: &impl Pkx, wild: bool) { pnp::println!("Ability: ({}) {}", pkx.ability_number_t(), ability); pnp::println!("PID: {:08X}", pkx.pid()); pnp::println!(color = shiny_color, "PSV: {:04}, {}", pkx.psv(), shiny_type); - if !wild { // Friendship will always be zero for wild pokemon and does not fit - pnp::println!("Friendship: {}", pkx.ht_friendship()); + if pkx_type == PkxType::Tame { // Friendship will always be zero for wild pokemon and does not fit + pnp::println!("Friendship: {}", pkx.current_friendship()); } pnp::println!(""); pnp::println!("HPower: {}", pkx.hidden_power_t()); - if wild { // PP does not matter for Party/Box view as you can just summary + if pkx_type == PkxType::Wild { // PP does not matter for Party/Box view as you can just summary print_pp(get_pp(pkx)); } print_stat!(iv_hp, ev_hp, Hp, &nature_stat, "HP "); @@ -239,20 +245,20 @@ pub fn draw_misc_help() { print_title(); pnp::println!(""); pnp::println!("PokemonRNG Resources:"); - pnp::println!(color=0xd7005f, " pokemonRNG.com"); + pnp::println!(color=MUTED_CYAN, " PokemonRNG.com"); match loaded_title() { Ok(LoadedTitle::CrystalEn) | Ok(LoadedTitle::CrystalEs) | Ok(LoadedTitle::CrystalDe) | Ok(LoadedTitle::CrystalFr) | Ok(LoadedTitle::CrystalIt) => - pnp::println!(color = CRYSTAL_CYAN, " discord.gg/d8JuAvg"), - _ => pnp::println!(color = MUTED_CYAN, " discord.gg/d8JuAvg"), + pnp::println!(color = CRYSTAL_CYAN, " discord.gg/d8JuAvg"), + _ => pnp::println!(color = MUTED_CYAN, " discord.gg/d8JuAvg"), } } pub fn draw_version() { - pnp::println!("Ver {} {}", VERSION, GIT_HASH); + pnp::println!(" Ver {} {}", VERSION, GIT_HASH); } pub fn draw_header(main_menu: T, current_view: T, is_locked: bool) { diff --git a/reader_core/src/gen6/draw.rs b/reader_core/src/gen6/draw.rs index 1b44c5a..b782aa3 100644 --- a/reader_core/src/gen6/draw.rs +++ b/reader_core/src/gen6/draw.rs @@ -8,7 +8,7 @@ use crate::{ utils::{format_egg_parent, is_daycare_masuda_method}, }; -pub use crate::draw::{draw_header, draw_pkx}; +pub use crate::draw::{draw_header, draw_pkx, PkxType}; pub fn draw_tinymt(reader: &Gen6Reader, rng: &Gen6Rng) { let tinymt = rng.tinymt(); diff --git a/reader_core/src/gen6/oras_frame.rs b/reader_core/src/gen6/oras_frame.rs index 634a4d0..d446a79 100644 --- a/reader_core/src/gen6/oras_frame.rs +++ b/reader_core/src/gen6/oras_frame.rs @@ -1,7 +1,7 @@ use super::{ draw::{ draw_daycare, draw_dex_nav, draw_header, draw_mirage_spot, draw_pkx, draw_rng, - draw_seed_rng, + draw_seed_rng, PkxType }, reader::Gen6Reader, rng::Gen6Rng, @@ -106,12 +106,12 @@ pub fn run_oras_frame() { OrasView::Daycare2 => draw_daycare(&reader.daycare2()), OrasView::Wild => { let slot = state.wild_menu.update_and_draw(is_locked); - draw_pkx(&reader.wild_pkm((slot - 1) as u32), true); + draw_pkx(&reader.wild_pkm((slot - 1) as u32), PkxType::Wild); } OrasView::DexNav => draw_dex_nav(&reader, &state.rng), OrasView::Party => { let slot = state.party_menu.update_and_draw(is_locked); - draw_pkx(&reader.party_pkm((slot - 1) as u32), false); + draw_pkx(&reader.party_pkm((slot - 1) as u32), PkxType::Tame); } OrasView::SeedRng => draw_seed_rng(&reader, &state.rng), OrasView::MirageSpot => draw_mirage_spot(&reader), diff --git a/reader_core/src/gen6/xy_frame.rs b/reader_core/src/gen6/xy_frame.rs index 2a22cd0..9d2936f 100644 --- a/reader_core/src/gen6/xy_frame.rs +++ b/reader_core/src/gen6/xy_frame.rs @@ -1,5 +1,5 @@ use super::{ - draw::{draw_daycare, draw_header, draw_pkx, draw_radar, draw_rng, draw_seed_rng}, + draw::{draw_daycare, draw_header, draw_pkx, draw_radar, draw_rng, draw_seed_rng, PkxType}, reader::Gen6Reader, rng::Gen6Rng, }; @@ -96,12 +96,12 @@ pub fn run_xy_frame() { XyView::Daycare => draw_daycare(&reader.daycare1()), XyView::Wild => { let slot = state.wild_menu.update_and_draw(is_locked); - draw_pkx(&reader.wild_pkm((slot - 1) as u32), true); + draw_pkx(&reader.wild_pkm((slot - 1) as u32), PkxType::Wild); } XyView::Radar => draw_radar(&reader, &state.rng), XyView::Party => { let slot = state.party_menu.update_and_draw(is_locked); - draw_pkx(&reader.party_pkm((slot - 1) as u32), false); + draw_pkx(&reader.party_pkm((slot - 1) as u32), PkxType::Tame); } XyView::SeedRng => draw_seed_rng(&reader, &state.rng), XyView::HelpMenu => state.help_menu.update_and_draw(is_locked), diff --git a/reader_core/src/gen7/draw.rs b/reader_core/src/gen7/draw.rs index 0dfb2c9..06389a3 100644 --- a/reader_core/src/gen7/draw.rs +++ b/reader_core/src/gen7/draw.rs @@ -5,7 +5,7 @@ use crate::{ utils::{format_egg_parent, is_daycare_masuda_method}, }; -pub use crate::draw::{draw_header, draw_pkx, draw_pkx_brief, GREEN,RED,WHITE}; +pub use crate::draw::{draw_header, draw_pkx, draw_pkx_brief, print_pp, get_pp, PkxType, GREEN, RED, WHITE}; pub fn draw_rng(reader: &Gen7Reader, rng: &RngWrapper) { let sfmt_state = rng.current_state(); @@ -40,8 +40,7 @@ pub fn draw_sos(reader: &Gen7Reader, slot: u32, correction: u32) { } pnp::println!("Caller Slot: {}", slot); - let caller_pp = reader.get_pp(&reader.sos_caller_pkm(slot)); - pnp::println!(color= if caller_pp > 1 { WHITE } else { RED }, "Caller PP: {}", caller_pp); + print_pp(get_pp(&reader.sos_caller_pkm(slot))); pnp::println!(""); pnp::println!("Ally Data (Slot {}):", reader.ally_slot(slot, correction) + 1); draw_pkx_brief(&reader.sos_ally_pkm(slot, correction)); diff --git a/reader_core/src/gen7/frame.rs b/reader_core/src/gen7/frame.rs index 23887aa..9314fb3 100644 --- a/reader_core/src/gen7/frame.rs +++ b/reader_core/src/gen7/frame.rs @@ -1,5 +1,5 @@ use super::{ - draw::{draw_citra_info, draw_daycare, draw_header, draw_pkx, draw_rng, draw_sos}, + draw::{draw_citra_info, draw_daycare, draw_header, draw_pkx, draw_rng, draw_sos, PkxType}, reader::Gen7Reader, }; use crate::{ @@ -122,7 +122,7 @@ fn run_frame(reader: Gen7Reader) { Gen7View::Daycare => draw_daycare(&reader), Gen7View::WildPokemon => { let slot = state.wild_menu.update_and_draw(is_locked); - draw_pkx(&reader.wild_pkm((slot - 1) as u32), true); + draw_pkx(&reader.wild_pkm((slot - 1) as u32), PkxType::Wild); } Gen7View::Sos => { let prev_caller_slot = state.sos_menu.counter_value(); @@ -135,15 +135,15 @@ fn run_frame(reader: Gen7Reader) { let correction_value = state.sos_menu.captured_value(); draw_sos(&reader, caller_slot as u32, correction_value); } - Gen7View::Box => draw_pkx(&reader.box_pkm(), false), + Gen7View::Box => draw_pkx(&reader.box_pkm(), PkxType::Tame), Gen7View::Citra => draw_citra_info(&reader), Gen7View::Party => { let slot = state.party_menu.update_and_draw(is_locked); - draw_pkx(&reader.party_pkm((slot - 1) as u32), false); + draw_pkx(&reader.party_pkm((slot - 1) as u32), PkxType::Tame); } Gen7View::Pelago => { let slot = state.pelago_menu.update_and_draw(is_locked); - draw_pkx(&reader.pelago_pkm((slot - 1) as u32), true) + draw_pkx(&reader.pelago_pkm((slot - 1) as u32), PkxType::Wild) } Gen7View::HelpMenu => state.help_menu.update_and_draw(is_locked), Gen7View::MainMenu => { diff --git a/reader_core/src/gen7/reader.rs b/reader_core/src/gen7/reader.rs index 353eac1..7c3e873 100644 --- a/reader_core/src/gen7/reader.rs +++ b/reader_core/src/gen7/reader.rs @@ -1,7 +1,7 @@ use super::{game_lib, hook}; use crate::pnp; use core::num::{NonZeroU32, NonZeroU8}; -use pkm_rs::{Pk7, Pkx, PokeCrypto}; +use pkm_rs::{Pk7, PokeCrypto}; struct Gen7Addresses { initial_seed: u32, @@ -209,9 +209,6 @@ impl Gen7Reader { pub fn sos_ally_pkm(&self, caller_slot: u32, correction: u32) -> Pk7 { self.read_pk7((self.ally_slot(caller_slot, correction) * 484) + self.addrs.sos) } - pub fn get_pp(&self, pkm: &Pk7) -> u32 { - pkm.move1_pp() as u32 + pkm.move2_pp() as u32 + pkm.move3_pp() as u32 + pkm.move4_pp() as u32 - } pub fn is_egg_ready(&self) -> bool { pnp::read::(self.addrs.egg_ready) != 0 diff --git a/reader_core/src/transporter/draw.rs b/reader_core/src/transporter/draw.rs index b2a0897..fb93262 100644 --- a/reader_core/src/transporter/draw.rs +++ b/reader_core/src/transporter/draw.rs @@ -1,5 +1,5 @@ use super::rng::TransporterRng; -pub use crate::draw::{draw_header, draw_pkx}; +pub use crate::draw::{draw_header, draw_pkx, PkxType}; use crate::pnp; pub fn draw_rng(rng: &TransporterRng) { diff --git a/reader_core/src/transporter/frame.rs b/reader_core/src/transporter/frame.rs index 8fd51a3..aa8c12d 100644 --- a/reader_core/src/transporter/frame.rs +++ b/reader_core/src/transporter/frame.rs @@ -1,5 +1,5 @@ use super::{ - draw::{draw_header, draw_pkx, draw_rng}, + draw::{draw_header, draw_pkx, draw_rng, PkxType}, reader::TransporterReader, rng::TransporterRng, }; @@ -83,7 +83,7 @@ pub fn run_frame() { TransporterView::Rng => draw_rng(&state.rng), TransporterView::Pokemon => { let slot = state.pokemon_menu.update_and_draw(is_locked); - draw_pkx(&reader.transported_pkm((slot - 1) as u32), false); + draw_pkx(&reader.transported_pkm((slot - 1) as u32), PkxType::Tame); } TransporterView::HelpMenu => state.help_menu.update_and_draw(is_locked), TransporterView::MainMenu => { From 06cbcaef308f41e2ef4f49a1fde289e95701477a Mon Sep 17 00:00:00 2001 From: serenagrace Date: Wed, 8 Oct 2025 21:21:29 -0500 Subject: [PATCH 15/39] Cleanup and corrected friendship --- reader_core/src/draw.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/reader_core/src/draw.rs b/reader_core/src/draw.rs index e61d48d..8e14e10 100644 --- a/reader_core/src/draw.rs +++ b/reader_core/src/draw.rs @@ -153,9 +153,6 @@ pub fn shiny_type(pkx: &impl Pkx) -> &'static str { } } - - - pub fn draw_pkx_brief(pkx: &impl Pkx) { let species = pkx.species_t().to_string(); let ability = pkx.ability_t().to_string(); From 8c5e49b4f0f9a7d3857337d88c1899621d6b8669 Mon Sep 17 00:00:00 2001 From: serenagrace Date: Fri, 10 Oct 2025 08:06:12 -0500 Subject: [PATCH 16/39] Cargo format and review round 3 --- reader_core/src/crystal/frame.rs | 10 +-- reader_core/src/crystal/mod.rs | 2 +- reader_core/src/crystal/pk2.rs | 5 +- reader_core/src/draw.rs | 95 +++++++++++++++-------- reader_core/src/gen6/oras_frame.rs | 12 +-- reader_core/src/gen6/xy_frame.rs | 10 +-- reader_core/src/gen7/draw.rs | 28 +++++-- reader_core/src/gen7/frame.rs | 6 +- reader_core/src/gen7/reader.rs | 29 ++++--- reader_core/src/lib.rs | 1 - reader_core/src/transporter/frame.rs | 6 +- reader_core/src/utils/help_menu.rs | 35 ++++----- reader_core/src/utils/menu.rs | 3 +- reader_core/src/utils/mod.rs | 2 +- reader_core/src/utils/sub_menu_capture.rs | 22 +++++- 15 files changed, 163 insertions(+), 103 deletions(-) diff --git a/reader_core/src/crystal/frame.rs b/reader_core/src/crystal/frame.rs index 3d1fb48..edaa62a 100644 --- a/reader_core/src/crystal/frame.rs +++ b/reader_core/src/crystal/frame.rs @@ -6,9 +6,9 @@ use super::{ use crate::{ pnp, utils::{ + help_menu::HelpMenu, menu::{Menu, MenuOption, MenuOptionValue}, sub_menu::SubMenu, - help_menu::HelpMenu, ShowView, }, }; @@ -21,7 +21,7 @@ enum CrystalView { Party, Wild, NonCfw, - HelpMenu + HelpMenu, } impl MenuOptionValue for CrystalView { @@ -32,7 +32,7 @@ impl MenuOptionValue for CrystalView { Self::Party => "Party", Self::Wild => "Wild", Self::NonCfw => "Non-CFW", - Self::HelpMenu => "Help" + Self::HelpMenu => "Help", } } } @@ -43,7 +43,7 @@ struct PersistedState { view: CrystalView, main_menu: Menu<5, CrystalView>, party_menu: SubMenu<1, 6>, - help_menu: HelpMenu + help_menu: HelpMenu, } unsafe fn get_state() -> &'static mut PersistedState { @@ -58,7 +58,7 @@ unsafe fn get_state() -> &'static mut PersistedState { MenuOption::new(CrystalView::Party), MenuOption::new(CrystalView::Wild), MenuOption::new(CrystalView::NonCfw), - MenuOption::new(CrystalView::HelpMenu) + MenuOption::new(CrystalView::HelpMenu), ]), }); Lazy::force_mut(&mut STATE) diff --git a/reader_core/src/crystal/mod.rs b/reader_core/src/crystal/mod.rs index fa3bf98..cd4a2a6 100644 --- a/reader_core/src/crystal/mod.rs +++ b/reader_core/src/crystal/mod.rs @@ -5,6 +5,6 @@ mod hook; mod pk2; mod reader; +pub use draw::CRYSTAL_CYAN; pub use frame::run_frame; pub use hook::init_crystal; -pub use draw::CRYSTAL_CYAN; diff --git a/reader_core/src/crystal/pk2.rs b/reader_core/src/crystal/pk2.rs index 01b77e1..4f28ced 100644 --- a/reader_core/src/crystal/pk2.rs +++ b/reader_core/src/crystal/pk2.rs @@ -313,10 +313,7 @@ impl Pk2 { .get(((atk & 3) << 2 | def & 3) as usize) .unwrap_or(&"Unknown"), hidden_power_base: 31 - + (5 * ((atk >> 3) << 3 - | (def >> 3) << 2 - | (spe >> 3) << 1 - | (spc >> 3)) + + (5 * ((atk >> 3) << 3 | (def >> 3) << 2 | (spe >> 3) << 1 | (spc >> 3)) + (spc & 3)) / 2, } diff --git a/reader_core/src/draw.rs b/reader_core/src/draw.rs index 8e14e10..c9411cf 100644 --- a/reader_core/src/draw.rs +++ b/reader_core/src/draw.rs @@ -1,9 +1,9 @@ +use super::title::{loaded_title, LoadedTitle}; use crate::alloc::string::ToString; +use crate::crystal::CRYSTAL_CYAN; use crate::{pnp, utils::menu::MenuOptionValue}; +use crate::{GIT_HASH, VERSION}; use pkm_rs::{Nature, Pkx, Shiny}; -use crate::{VERSION, GIT_HASH}; -use super::title::{loaded_title, LoadedTitle}; -use crate::crystal::CRYSTAL_CYAN; pub const WHITE: u32 = 0xffffff; pub const GREEN: u32 = 0x00cc00; @@ -39,7 +39,7 @@ use Stat::*; #[derive(PartialEq, Eq)] pub enum PkxType { Wild, - Tame + Tame, } struct NatureStat { @@ -116,32 +116,54 @@ macro_rules! print_stat { } pub fn print_pp(pp: u32) { - pnp::println!(color = if pp > 1 { WHITE } else { RED }, - "PP Remaining: {}", pp + pnp::println!( + color = if pp > 1 { WHITE } else { RED }, + "PP Remaining: {}", + pp ); } pub fn print_title() { match loaded_title() { - Ok(title) => { - match title { - LoadedTitle::S => { pnp::println!(color = 0xd75f00, " Pokemon Sun")}, - LoadedTitle::M => { pnp::println!(color = 0xaf5fff, " Pokemon Moon")}, - LoadedTitle::Us => { pnp::println!(color = 0xff5f1f, " Pokemon Ultra Sun")}, - LoadedTitle::Um => { pnp::println!(color = 0xaf00ff," Pokemon Ultra Moon")}, - LoadedTitle::X => { pnp::println!(color = 0x00ffff, " Pokemon X")}, - LoadedTitle::Y => { pnp::println!(color = 0xd7005f, " Pokemon Y")}, - LoadedTitle::Or => { pnp::println!(color = 0xFF4433," Pokemon Omega Ruby")}, - LoadedTitle::As => { pnp::println!(color = 0x0000ff, " Pokemon Alpha Sapphire")}, - LoadedTitle::Transporter => { pnp::println!(color = 0xd7ff00, " Pokemon Transporter")}, - LoadedTitle::CrystalEn - | LoadedTitle::CrystalDe - | LoadedTitle::CrystalFr - | LoadedTitle::CrystalEs - | LoadedTitle::CrystalIt => { pnp::println!(color= 0xaf00d7, " Pokemon Crystal")}, + Ok(title) => match title { + LoadedTitle::S => { + pnp::println!(color = 0xd75f00, " Pokemon Sun") + } + LoadedTitle::M => { + pnp::println!(color = 0xaf5fff, " Pokemon Moon") + } + LoadedTitle::Us => { + pnp::println!(color = 0xff5f1f, " Pokemon Ultra Sun") + } + LoadedTitle::Um => { + pnp::println!(color = 0xaf00ff, " Pokemon Ultra Moon") + } + LoadedTitle::X => { + pnp::println!(color = 0x00ffff, " Pokemon X") + } + LoadedTitle::Y => { + pnp::println!(color = 0xd7005f, " Pokemon Y") + } + LoadedTitle::Or => { + pnp::println!(color = 0xFF4433, " Pokemon Omega Ruby") + } + LoadedTitle::As => { + pnp::println!(color = 0x0000ff, " Pokemon Alpha Sapphire") + } + LoadedTitle::Transporter => { + pnp::println!(color = 0xd7ff00, " Pokemon Transporter") + } + LoadedTitle::CrystalEn + | LoadedTitle::CrystalDe + | LoadedTitle::CrystalFr + | LoadedTitle::CrystalEs + | LoadedTitle::CrystalIt => { + pnp::println!(color = 0xaf00d7, " Pokemon Crystal") } }, - Err(_error) => { pnp::println!(color = RED, "???") } + Err(_error) => { + pnp::println!(color = RED, "???") + } } } @@ -173,7 +195,15 @@ pub fn draw_pkx_brief(pkx: &impl Pkx) { pnp::println!("PID: {:08X}", pkx.pid()); pnp::println!(color = shiny_color, "PSV: {:04}, {}", pkx.psv(), shiny_type); pnp::println!("HPower: {}", pkx.hidden_power_t()); - pnp::println!("IVs: {}/{}/{}/{}/{}/{}", iv_hp, iv_atk, iv_def, iv_spa, iv_spd, iv_spe); + pnp::println!( + "IVs: {}/{}/{}/{}/{}/{}", + iv_hp, + iv_atk, + iv_def, + iv_spa, + iv_spd, + iv_spe + ); } pub fn draw_pkx(pkx: &impl Pkx, pkx_type: PkxType) { @@ -203,12 +233,14 @@ pub fn draw_pkx(pkx: &impl Pkx, pkx_type: PkxType) { pnp::println!("Ability: ({}) {}", pkx.ability_number_t(), ability); pnp::println!("PID: {:08X}", pkx.pid()); pnp::println!(color = shiny_color, "PSV: {:04}, {}", pkx.psv(), shiny_type); - if pkx_type == PkxType::Tame { // Friendship will always be zero for wild pokemon and does not fit + if pkx_type == PkxType::Tame { + // Friendship will always be zero for wild pokemon and does not fit pnp::println!("Friendship: {}", pkx.current_friendship()); } pnp::println!(""); pnp::println!("HPower: {}", pkx.hidden_power_t()); - if pkx_type == PkxType::Wild { // PP does not matter for Party/Box view as you can just summary + if pkx_type == PkxType::Wild { + // PP does not matter for Party/Box view as you can just summary print_pp(get_pp(pkx)); } print_stat!(iv_hp, ev_hp, Hp, &nature_stat, "HP "); @@ -242,14 +274,13 @@ pub fn draw_misc_help() { print_title(); pnp::println!(""); pnp::println!("PokemonRNG Resources:"); - pnp::println!(color=MUTED_CYAN, " PokemonRNG.com"); + pnp::println!(color = MUTED_CYAN, " PokemonRNG.com"); match loaded_title() { Ok(LoadedTitle::CrystalEn) - | Ok(LoadedTitle::CrystalEs) - | Ok(LoadedTitle::CrystalDe) - | Ok(LoadedTitle::CrystalFr) - | Ok(LoadedTitle::CrystalIt) => - pnp::println!(color = CRYSTAL_CYAN, " discord.gg/d8JuAvg"), + | Ok(LoadedTitle::CrystalEs) + | Ok(LoadedTitle::CrystalDe) + | Ok(LoadedTitle::CrystalFr) + | Ok(LoadedTitle::CrystalIt) => pnp::println!(color = CRYSTAL_CYAN, " discord.gg/d8JuAvg"), _ => pnp::println!(color = MUTED_CYAN, " discord.gg/d8JuAvg"), } } diff --git a/reader_core/src/gen6/oras_frame.rs b/reader_core/src/gen6/oras_frame.rs index d446a79..ccd73b9 100644 --- a/reader_core/src/gen6/oras_frame.rs +++ b/reader_core/src/gen6/oras_frame.rs @@ -1,7 +1,7 @@ use super::{ draw::{ draw_daycare, draw_dex_nav, draw_header, draw_mirage_spot, draw_pkx, draw_rng, - draw_seed_rng, PkxType + draw_seed_rng, PkxType, }, reader::Gen6Reader, rng::Gen6Rng, @@ -9,9 +9,9 @@ use super::{ use crate::{ pnp, utils::{ + help_menu::HelpMenu, menu::{Menu, MenuOption, MenuOptionValue}, sub_menu::SubMenu, - help_menu::HelpMenu, ShowView, }, }; @@ -28,7 +28,7 @@ enum OrasView { Party, MirageSpot, SeedRng, - HelpMenu + HelpMenu, } impl MenuOptionValue for OrasView { @@ -43,7 +43,7 @@ impl MenuOptionValue for OrasView { Self::Party => "Party", Self::MirageSpot => "Mirage Spot", Self::SeedRng => "Seed RNG", - Self::HelpMenu => "Help" + Self::HelpMenu => "Help", } } } @@ -55,7 +55,7 @@ struct PersistedState { main_menu: Menu<9, OrasView>, party_menu: SubMenu<1, 6>, wild_menu: SubMenu<1, 5>, - help_menu: HelpMenu + help_menu: HelpMenu, } unsafe fn get_state() -> &'static mut PersistedState { @@ -75,7 +75,7 @@ unsafe fn get_state() -> &'static mut PersistedState { MenuOption::new(OrasView::Party), MenuOption::new(OrasView::MirageSpot), MenuOption::new(OrasView::SeedRng), - MenuOption::new(OrasView::HelpMenu) + MenuOption::new(OrasView::HelpMenu), ]), }); Lazy::force_mut(&mut STATE) diff --git a/reader_core/src/gen6/xy_frame.rs b/reader_core/src/gen6/xy_frame.rs index 9d2936f..322cf27 100644 --- a/reader_core/src/gen6/xy_frame.rs +++ b/reader_core/src/gen6/xy_frame.rs @@ -6,9 +6,9 @@ use super::{ use crate::{ pnp, utils::{ + help_menu::HelpMenu, menu::{Menu, MenuOption, MenuOptionValue}, sub_menu::SubMenu, - help_menu::HelpMenu, ShowView, }, }; @@ -23,7 +23,7 @@ enum XyView { Radar, Party, SeedRng, - HelpMenu + HelpMenu, } impl MenuOptionValue for XyView { @@ -36,7 +36,7 @@ impl MenuOptionValue for XyView { Self::Radar => "Radar", Self::Party => "Party", Self::SeedRng => "Seed RNG", - Self::HelpMenu => "Help" + Self::HelpMenu => "Help", } } } @@ -48,7 +48,7 @@ struct PersistedState { main_menu: Menu<7, XyView>, party_menu: SubMenu<1, 6>, wild_menu: SubMenu<1, 5>, - help_menu: HelpMenu + help_menu: HelpMenu, } unsafe fn get_state() -> &'static mut PersistedState { @@ -66,7 +66,7 @@ unsafe fn get_state() -> &'static mut PersistedState { MenuOption::new(XyView::Radar), MenuOption::new(XyView::Party), MenuOption::new(XyView::SeedRng), - MenuOption::new(XyView::HelpMenu) + MenuOption::new(XyView::HelpMenu), ]), }); Lazy::force_mut(&mut STATE) diff --git a/reader_core/src/gen7/draw.rs b/reader_core/src/gen7/draw.rs index 06389a3..2d33066 100644 --- a/reader_core/src/gen7/draw.rs +++ b/reader_core/src/gen7/draw.rs @@ -5,7 +5,9 @@ use crate::{ utils::{format_egg_parent, is_daycare_masuda_method}, }; -pub use crate::draw::{draw_header, draw_pkx, draw_pkx_brief, print_pp, get_pp, PkxType, GREEN, RED, WHITE}; +pub use crate::draw::{ + draw_header, draw_pkx, draw_pkx_brief, get_pp, print_pp, PkxType, GREEN, RED, WHITE, +}; pub fn draw_rng(reader: &Gen7Reader, rng: &RngWrapper) { let sfmt_state = rng.current_state(); @@ -37,12 +39,14 @@ pub fn draw_sos(reader: &Gen7Reader, slot: u32, correction: u32) { pnp::println!(color = GREEN, "Orb Active") } else { pnp::println!(color = RED, "Orb Not Active"); - } pnp::println!("Caller Slot: {}", slot); print_pp(get_pp(&reader.sos_caller_pkm(slot))); pnp::println!(""); - pnp::println!("Ally Data (Slot {}):", reader.ally_slot(slot, correction) + 1); + pnp::println!( + "Ally Data (Slot {}):", + reader.ally_slot(slot, correction) + 1 + ); draw_pkx_brief(&reader.sos_ally_pkm(slot, correction)); } @@ -54,7 +58,11 @@ pub fn draw_daycare(reader: &Gen7Reader) { let has_shiny_charm = reader.has_shiny_charm(); let is_masuda_method = is_daycare_masuda_method(&parent1, &parent2); - pnp::println!(color= if is_egg_ready {GREEN} else {WHITE}, "Egg Ready: {}", is_egg_ready); + pnp::println!( + color = if is_egg_ready { GREEN } else { WHITE }, + "Egg Ready: {}", + is_egg_ready + ); pnp::println!("{}", format_egg_parent(1, &parent1)); pnp::println!("{}", format_egg_parent(2, &parent2)); pnp::println!(""); @@ -63,6 +71,14 @@ pub fn draw_daycare(reader: &Gen7Reader) { pnp::println!("Egg[1]: {:08X}", egg_seed[1]); pnp::println!("Egg[0]: {:08X}", egg_seed[0]); pnp::println!(""); - pnp::println!(color= if has_shiny_charm {GREEN} else {WHITE}, "Shiny Charm: {}", has_shiny_charm); - pnp::println!(color= if is_masuda_method {GREEN} else {WHITE}, "Masuda Method: {}", is_masuda_method); + pnp::println!( + color = if has_shiny_charm { GREEN } else { WHITE }, + "Shiny Charm: {}", + has_shiny_charm + ); + pnp::println!( + color = if is_masuda_method { GREEN } else { WHITE }, + "Masuda Method: {}", + is_masuda_method + ); } diff --git a/reader_core/src/gen7/frame.rs b/reader_core/src/gen7/frame.rs index 9314fb3..2663663 100644 --- a/reader_core/src/gen7/frame.rs +++ b/reader_core/src/gen7/frame.rs @@ -6,9 +6,9 @@ use crate::{ pnp, rng::{RngWrapper, Sfmt}, utils::{ + help_menu::HelpMenu, menu::{Menu, MenuOption, MenuOptionValue}, sub_menu::SubMenu, - help_menu::HelpMenu, sub_menu_capture::SubMenuCapture, ShowView, }, @@ -130,8 +130,8 @@ fn run_frame(reader: Gen7Reader) { let caller_slot = state.sos_menu.update_headless( is_locked, reader.sos_chain() as u32, - reader.ally_slot(prev_caller_slot as u32, prev_correction_value) as usize + 1 - ); + reader.ally_slot(prev_caller_slot as u32, prev_correction_value) as usize + 1, + ); let correction_value = state.sos_menu.captured_value(); draw_sos(&reader, caller_slot as u32, correction_value); } diff --git a/reader_core/src/gen7/reader.rs b/reader_core/src/gen7/reader.rs index 7c3e873..290f1a9 100644 --- a/reader_core/src/gen7/reader.rs +++ b/reader_core/src/gen7/reader.rs @@ -10,11 +10,13 @@ struct Gen7Addresses { party: u32, wild: u32, sos: u32, - sos_index: u32, orb_active: u32, sos_chain_length: u32, - ally_id: u32, - prev_call_succeed: u32, + // To be used in the future vvv + _sos_index: u32, + _ally_id: u32, + _prev_call_succeed: u32, + // pelago: u32, egg_ready: u32, egg: u32, @@ -36,11 +38,11 @@ const SM_ADDRESSES: Gen7Addresses = Gen7Addresses { party: 0x34195e10, wild: 0x3002f7b8, sos: 0x3002f7b8, - sos_index: 0x30039614, + _sos_index: 0x30039614, orb_active: 0x3003961c, sos_chain_length: 0x3003960d, - ally_id: 0x3003961e, - prev_call_succeed: 0x3003961f, + _ally_id: 0x3003961e, + _prev_call_succeed: 0x3003961f, pelago: 0x331110ca, egg_ready: 0x3313edd8, egg: 0x3313eddc, @@ -62,11 +64,11 @@ const USUM_ADDRESSES: Gen7Addresses = Gen7Addresses { party: 0x33f7fa44, wild: 0x3002f9a0, sos: 0x3002f9a0, - sos_index: 0x300397F0, + _sos_index: 0x300397F0, orb_active: 0x300397f8, sos_chain_length: 0x300397f9, - ally_id: 0x300397fA, - prev_call_succeed: 0x300397fb, + _ally_id: 0x300397fA, + _prev_call_succeed: 0x300397fb, pelago: 0x3304d16a, egg_ready: 0x3307b1e8, egg: 0x3307b1ec, @@ -156,8 +158,13 @@ impl Gen7Reader { ((pnp::read::(self.addrs.orb_active) & 0x1) > 0) as bool } pub fn ally_slot(&self, caller_slot: u32, correction: u32) -> u32 { - if self.sos_chain() == 0 { 0 } else { - ((caller_slot - 1) + ((self.sos_chain() as i32 - (correction as i32 + 1)) % 3) as u32 + 1) % 4 + if self.sos_chain() == 0 { + 0 + } else { + ((caller_slot - 1) + + ((self.sos_chain() as i32 - (correction as i32 + 1)) % 3) as u32 + + 1) + % 4 } } diff --git a/reader_core/src/lib.rs b/reader_core/src/lib.rs index 658c808..f9e07ca 100644 --- a/reader_core/src/lib.rs +++ b/reader_core/src/lib.rs @@ -22,7 +22,6 @@ pub const GIT_HASH: &str = env!("GIT_HASH"); use title::{loaded_title, LoadedTitle, TitleError}; - #[cfg(target_os = "horizon")] #[panic_handler] fn my_panic(info: &core::panic::PanicInfo) -> ! { diff --git a/reader_core/src/transporter/frame.rs b/reader_core/src/transporter/frame.rs index aa8c12d..daed7fc 100644 --- a/reader_core/src/transporter/frame.rs +++ b/reader_core/src/transporter/frame.rs @@ -6,9 +6,9 @@ use super::{ use crate::{ pnp, utils::{ + help_menu::HelpMenu, menu::{Menu, MenuOption, MenuOptionValue}, sub_menu::SubMenu, - help_menu::HelpMenu, ShowView, }, }; @@ -19,7 +19,7 @@ enum TransporterView { MainMenu, Pokemon, Rng, - HelpMenu + HelpMenu, } impl MenuOptionValue for TransporterView { @@ -52,7 +52,7 @@ unsafe fn get_state() -> &'static mut PersistedState { main_menu: Menu::new([ MenuOption::new(TransporterView::Rng), MenuOption::new(TransporterView::Pokemon), - MenuOption::new(TransporterView::HelpMenu) + MenuOption::new(TransporterView::HelpMenu), ]), }); Lazy::force_mut(&mut STATE) diff --git a/reader_core/src/utils/help_menu.rs b/reader_core/src/utils/help_menu.rs index af0c232..da7dae8 100644 --- a/reader_core/src/utils/help_menu.rs +++ b/reader_core/src/utils/help_menu.rs @@ -1,25 +1,23 @@ -use crate::pnp; use super::sub_menu::SubMenu; -use crate::draw::{draw_controls_help, draw_specific_help, draw_misc_help}; - +use crate::draw::{draw_controls_help, draw_misc_help, draw_specific_help}; +use crate::pnp; enum HelpView { Controls, SpecificControls, - Misc + Misc, } - pub struct HelpMenu { - specific_help: fn () -> (), - sub_menu: SubMenu<1,3> + specific_help: fn() -> (), + sub_menu: SubMenu<1, 3>, } impl Default for HelpMenu { fn default() -> Self { HelpMenu { - specific_help: || { pnp::println!("No Game-Specific info.") }, - sub_menu: SubMenu::default() + specific_help: || pnp::println!("No Game-Specific info."), + sub_menu: SubMenu::default(), } } } @@ -29,7 +27,7 @@ fn view(slot: usize) -> HelpView { 1 => HelpView::Controls, 2 => HelpView::SpecificControls, 3 => HelpView::Misc, - _ => HelpView::Misc + _ => HelpView::Misc, } } @@ -37,16 +35,16 @@ fn print_view(help_view: &HelpView) { match help_view { HelpView::Controls => pnp::println!("Controls"), HelpView::SpecificControls => pnp::println!("Game-Specific Controls"), - HelpView::Misc => pnp::println!("Additional Info") + HelpView::Misc => pnp::println!("Additional Info"), } } impl HelpMenu { pub fn new(specific_help: fn() -> ()) -> Self { - Self { - specific_help: specific_help, - sub_menu: SubMenu::default() - } + Self { + specific_help: specific_help, + sub_menu: SubMenu::default(), + } } pub fn update_and_draw(&mut self, is_locked: bool) { let help_view = view(self.sub_menu.update_headless(is_locked)); @@ -55,10 +53,9 @@ impl HelpMenu { pnp::println!(""); match help_view { - HelpView::Controls => { draw_controls_help() }, - HelpView::SpecificControls => { draw_specific_help(self.specific_help) }, - HelpView::Misc => { draw_misc_help() } + HelpView::Controls => draw_controls_help(), + HelpView::SpecificControls => draw_specific_help(self.specific_help), + HelpView::Misc => draw_misc_help(), } - } } diff --git a/reader_core/src/utils/menu.rs b/reader_core/src/utils/menu.rs index 876be0b..5c4d7fa 100644 --- a/reader_core/src/utils/menu.rs +++ b/reader_core/src/utils/menu.rs @@ -1,5 +1,4 @@ -use crate::{pnp, pnp::Button, utils::CircularCounter, draw::draw_version}; - +use crate::{draw::draw_version, pnp, pnp::Button, utils::CircularCounter}; pub trait MenuOptionValue: Copy { fn get_label(option: Self) -> &'static str; diff --git a/reader_core/src/utils/mod.rs b/reader_core/src/utils/mod.rs index d0226b9..31bd68a 100644 --- a/reader_core/src/utils/mod.rs +++ b/reader_core/src/utils/mod.rs @@ -3,12 +3,12 @@ mod circular_counter; mod daycare; mod game_fn; +pub mod help_menu; mod hook_game_branch; mod hook_gen6_seed; pub mod menu; mod show_view; pub mod sub_menu; -pub mod help_menu; pub mod sub_menu_capture; pub use circular_counter::*; diff --git a/reader_core/src/utils/sub_menu_capture.rs b/reader_core/src/utils/sub_menu_capture.rs index 265e730..22c7fe0 100644 --- a/reader_core/src/utils/sub_menu_capture.rs +++ b/reader_core/src/utils/sub_menu_capture.rs @@ -4,15 +4,17 @@ use crate::pnp; #[derive(Default)] pub struct SubMenuCapture { counter: CircularCounter, - value: u32 + value: u32, } impl SubMenuCapture { + /* Unused fn draw_header(&self) { pnp::println!("Slot {}", self.counter.value()); pnp::println!("[v] Next | Prev [^]"); pnp::println!(""); } + */ fn update_counter(&mut self, is_locked: bool, capture_value: u32, set_value: usize) { if is_locked { @@ -22,7 +24,7 @@ impl SubMenuCapture { if pnp::is_just_pressed(pnp::Button::Ddown | pnp::Button::X) { self.counter.increment(); self.value = capture_value; - } else if pnp::is_just_pressed(pnp::Button::Dup | pnp::Button::X) { + } else if pnp::is_just_pressed(pnp::Button::Dup | pnp::Button::X) { self.counter.decrement(); self.value = capture_value; } else if pnp::is_just_pressed(pnp::Button::Dright | pnp::Button::X) { @@ -31,12 +33,24 @@ impl SubMenuCapture { } } - pub fn update_and_draw(&mut self, is_locked: bool, capture_value: u32, set_value: usize) -> usize { + /* Unused + pub fn update_and_draw( + &mut self, + is_locked: bool, + capture_value: u32, + set_value: usize, + ) -> usize { self.update_counter(is_locked, capture_value, set_value); self.draw_header(); self.counter.value() } - pub fn update_headless(&mut self, is_locked: bool, capture_value: u32, set_value: usize) -> usize { + */ + pub fn update_headless( + &mut self, + is_locked: bool, + capture_value: u32, + set_value: usize, + ) -> usize { self.update_counter(is_locked, capture_value, set_value); self.counter.value() } From 821bae78eb78c2340c399a3d652b2ec4befc8ee5 Mon Sep 17 00:00:00 2001 From: serenagrace Date: Fri, 10 Oct 2025 08:15:33 -0500 Subject: [PATCH 17/39] Remove dead code --- reader_core/src/utils/help_menu.rs | 1 + reader_core/src/utils/sub_menu_capture.rs | 21 +-------------------- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/reader_core/src/utils/help_menu.rs b/reader_core/src/utils/help_menu.rs index da7dae8..9d96fb9 100644 --- a/reader_core/src/utils/help_menu.rs +++ b/reader_core/src/utils/help_menu.rs @@ -46,6 +46,7 @@ impl HelpMenu { sub_menu: SubMenu::default(), } } + pub fn update_and_draw(&mut self, is_locked: bool) { let help_view = view(self.sub_menu.update_headless(is_locked)); print_view(&help_view); diff --git a/reader_core/src/utils/sub_menu_capture.rs b/reader_core/src/utils/sub_menu_capture.rs index 22c7fe0..2da19ce 100644 --- a/reader_core/src/utils/sub_menu_capture.rs +++ b/reader_core/src/utils/sub_menu_capture.rs @@ -8,14 +8,6 @@ pub struct SubMenuCapture { } impl SubMenuCapture { - /* Unused - fn draw_header(&self) { - pnp::println!("Slot {}", self.counter.value()); - pnp::println!("[v] Next | Prev [^]"); - pnp::println!(""); - } - */ - fn update_counter(&mut self, is_locked: bool, capture_value: u32, set_value: usize) { if is_locked { return; @@ -33,18 +25,6 @@ impl SubMenuCapture { } } - /* Unused - pub fn update_and_draw( - &mut self, - is_locked: bool, - capture_value: u32, - set_value: usize, - ) -> usize { - self.update_counter(is_locked, capture_value, set_value); - self.draw_header(); - self.counter.value() - } - */ pub fn update_headless( &mut self, is_locked: bool, @@ -58,6 +38,7 @@ impl SubMenuCapture { pub fn captured_value(&mut self) -> u32 { self.value } + pub fn counter_value(&self) -> usize { return self.counter.value(); } From fe8c619265969dbbe517593cc3596b0ce832b994 Mon Sep 17 00:00:00 2001 From: serenagrace Date: Fri, 10 Oct 2025 09:21:55 -0500 Subject: [PATCH 18/39] Updated format config --- reader_core/rustfmt.toml | 2 ++ reader_core/src/crystal/pk2.rs | 2 ++ reader_core/src/lib.rs | 1 + 3 files changed, 5 insertions(+) create mode 100644 reader_core/rustfmt.toml diff --git a/reader_core/rustfmt.toml b/reader_core/rustfmt.toml new file mode 100644 index 0000000..49ad328 --- /dev/null +++ b/reader_core/rustfmt.toml @@ -0,0 +1,2 @@ +style_edition = "2024" +max_width = 110 diff --git a/reader_core/src/crystal/pk2.rs b/reader_core/src/crystal/pk2.rs index 4f28ced..fd74bcc 100644 --- a/reader_core/src/crystal/pk2.rs +++ b/reader_core/src/crystal/pk2.rs @@ -253,12 +253,14 @@ const SPECIES_LOOKUP: [&str; 252] = [ "Celebi", ]; +#[rustfmt::skip] const NATURE_LOOKUP: [&str; 25] = [ "Hardy", "Lonely", "Brave", "Adamant", "Naughty", "Bold", "Docile", "Relaxed", "Impish", "Lax", "Timid", "Hasty", "Serious", "Jolly", "Naive", "Modest", "Mild", "Quiet", "Bashful", "Rash", "Calm", "Gentle", "Sassy", "Careful", "Quirky", ]; +#[rustfmt::skip] const HIDDEN_POWER_LOOKUP: [&str; 16] = [ "Fighting", "Flying", "Poison", "Ground", "Rock", "Bug", "Ghost", "Steel", "Fire", "Water", "Grass", "Electric", "Psychic", "Ice", "Dragon", "Dark", diff --git a/reader_core/src/lib.rs b/reader_core/src/lib.rs index f9e07ca..5bccfd1 100644 --- a/reader_core/src/lib.rs +++ b/reader_core/src/lib.rs @@ -1,6 +1,7 @@ #![no_std] #![allow(static_mut_refs)] #![feature(naked_functions)] +#![rustfmt::skip::macros(println)] extern crate alloc; From 72c6739cc8f9f990cf8512e63b4127a8eb622ce7 Mon Sep 17 00:00:00 2001 From: serenagrace Date: Fri, 10 Oct 2025 09:22:07 -0500 Subject: [PATCH 19/39] Added formatting target --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index 73f15fe..ee72b57 100644 --- a/Makefile +++ b/Makefile @@ -21,6 +21,9 @@ clean: make clean -C 3gx rm -rf out +format: + cargo +nightly fmt --all --manifest-path reader_core/Cargo.toml + lint: cargo +nightly-2024-03-21 clippy --release -Z build-std=core,alloc --target armv6k-nintendo-3ds --manifest-path reader_core/Cargo.toml From c62f1bde0ccefb55bfe97bdde600e98e266ba3fc Mon Sep 17 00:00:00 2001 From: serenagrace Date: Fri, 10 Oct 2025 09:22:29 -0500 Subject: [PATCH 20/39] Enforced formatting --- reader_core/build.rs | 12 +---- reader_core/src/crystal/draw.rs | 6 +-- reader_core/src/crystal/frame.rs | 2 +- reader_core/src/crystal/pk2.rs | 54 ++++++++++++++++++----- reader_core/src/draw.rs | 46 +++++-------------- reader_core/src/gen6/draw.rs | 14 ++---- reader_core/src/gen6/game_lib.rs | 2 +- reader_core/src/gen6/oras_frame.rs | 5 +-- reader_core/src/gen6/reader.rs | 4 +- reader_core/src/gen6/rng.rs | 2 +- reader_core/src/gen6/xy_frame.rs | 4 +- reader_core/src/gen7/draw.rs | 9 +--- reader_core/src/gen7/frame.rs | 4 +- reader_core/src/gen7/reader.rs | 22 +++------ reader_core/src/lib.rs | 2 +- reader_core/src/pnp/memory.rs | 2 +- reader_core/src/rng/mt.rs | 4 +- reader_core/src/rng/rng_wrapper.rs | 2 +- reader_core/src/rng/sfmt.rs | 4 +- reader_core/src/transporter/draw.rs | 2 +- reader_core/src/transporter/frame.rs | 8 ++-- reader_core/src/transporter/rng.rs | 2 +- reader_core/src/utils/hook_game_branch.rs | 3 +- reader_core/src/utils/menu.rs | 6 +-- reader_core/src/utils/show_view.rs | 2 +- reader_core/src/utils/sub_menu_capture.rs | 9 +--- 26 files changed, 95 insertions(+), 137 deletions(-) diff --git a/reader_core/build.rs b/reader_core/build.rs index c36eda1..ab5e1aa 100644 --- a/reader_core/build.rs +++ b/reader_core/build.rs @@ -8,11 +8,7 @@ fn get_tree_state() -> &'static str { .unwrap() .stdout .is_empty(); - if is_clean { - "" - } else { - "dirty-" - } + if is_clean { "" } else { "dirty-" } } fn get_hash() -> String { @@ -30,9 +26,5 @@ fn get_hash() -> String { } fn main() { - println!( - "cargo:rustc-env=GIT_HASH={}{}", - get_tree_state(), - get_hash() - ); + println!("cargo:rustc-env=GIT_HASH={}{}", get_tree_state(), get_hash()); } diff --git a/reader_core/src/crystal/draw.rs b/reader_core/src/crystal/draw.rs index 96dd483..c464c1c 100644 --- a/reader_core/src/crystal/draw.rs +++ b/reader_core/src/crystal/draw.rs @@ -43,11 +43,7 @@ pub fn draw_rng(reader: &Gen2Reader) { pub fn draw_pkx(pkx: &Pk2) { pnp::println!("Species: {}", pkx.species); pnp::println!(color = get_shiny_color(pkx.shiny), "Shiny: {}", pkx.shiny); - pnp::println!( - "HPower: {} {}", - pkx.hidden_power_type, - pkx.hidden_power_base - ); + pnp::println!("HPower: {} {}", pkx.hidden_power_type, pkx.hidden_power_base); pnp::println!(color = get_iv_color(pkx.hp), "HP DV: {}", pkx.hp); pnp::println!(color = get_iv_color(pkx.atk), "Atk DV: {}", pkx.atk); pnp::println!(color = get_iv_color(pkx.def), "Def DV: {}", pkx.def); diff --git a/reader_core/src/crystal/frame.rs b/reader_core/src/crystal/frame.rs index edaa62a..1a16899 100644 --- a/reader_core/src/crystal/frame.rs +++ b/reader_core/src/crystal/frame.rs @@ -6,10 +6,10 @@ use super::{ use crate::{ pnp, utils::{ + ShowView, help_menu::HelpMenu, menu::{Menu, MenuOption, MenuOptionValue}, sub_menu::SubMenu, - ShowView, }, }; use once_cell::unsync::Lazy; diff --git a/reader_core/src/crystal/pk2.rs b/reader_core/src/crystal/pk2.rs index fd74bcc..51b3d1c 100644 --- a/reader_core/src/crystal/pk2.rs +++ b/reader_core/src/crystal/pk2.rs @@ -255,15 +255,51 @@ const SPECIES_LOOKUP: [&str; 252] = [ #[rustfmt::skip] const NATURE_LOOKUP: [&str; 25] = [ - "Hardy", "Lonely", "Brave", "Adamant", "Naughty", "Bold", "Docile", "Relaxed", "Impish", "Lax", - "Timid", "Hasty", "Serious", "Jolly", "Naive", "Modest", "Mild", "Quiet", "Bashful", "Rash", - "Calm", "Gentle", "Sassy", "Careful", "Quirky", + "Hardy", + "Lonely", + "Brave", + "Adamant", + "Naughty", + "Bold", + "Docile", + "Relaxed", + "Impish", + "Lax", + "Timid", + "Hasty", + "Serious", + "Jolly", + "Naive", + "Modest", + "Mild", + "Quiet", + "Bashful", + "Rash", + "Calm", + "Gentle", + "Sassy", + "Careful", + "Quirky", ]; #[rustfmt::skip] const HIDDEN_POWER_LOOKUP: [&str; 16] = [ - "Fighting", "Flying", "Poison", "Ground", "Rock", "Bug", "Ghost", "Steel", "Fire", "Water", - "Grass", "Electric", "Psychic", "Ice", "Dragon", "Dark", + "Fighting", + "Flying", + "Poison", + "Ground", + "Rock", + "Bug", + "Ghost", + "Steel", + "Fire", + "Water", + "Grass", + "Electric", + "Psychic", + "Ice", + "Dragon", + "Dark", ]; pub struct Pk2 { @@ -301,9 +337,7 @@ impl Pk2 { Pk2 { spec_index, species: SPECIES_LOOKUP.get(spec_index as usize).unwrap_or(&"None"), - nature: NATURE_LOOKUP - .get(experience as usize % 25) - .unwrap_or(&"Unknown"), + nature: NATURE_LOOKUP.get(experience as usize % 25).unwrap_or(&"Unknown"), experience, atk, def, @@ -315,9 +349,7 @@ impl Pk2 { .get(((atk & 3) << 2 | def & 3) as usize) .unwrap_or(&"Unknown"), hidden_power_base: 31 - + (5 * ((atk >> 3) << 3 | (def >> 3) << 2 | (spe >> 3) << 1 | (spc >> 3)) - + (spc & 3)) - / 2, + + (5 * ((atk >> 3) << 3 | (def >> 3) << 2 | (spe >> 3) << 1 | (spc >> 3)) + (spc & 3)) / 2, } } } diff --git a/reader_core/src/draw.rs b/reader_core/src/draw.rs index c9411cf..383cbf7 100644 --- a/reader_core/src/draw.rs +++ b/reader_core/src/draw.rs @@ -1,8 +1,8 @@ -use super::title::{loaded_title, LoadedTitle}; +use super::title::{LoadedTitle, loaded_title}; use crate::alloc::string::ToString; use crate::crystal::CRYSTAL_CYAN; -use crate::{pnp, utils::menu::MenuOptionValue}; use crate::{GIT_HASH, VERSION}; +use crate::{pnp, utils::menu::MenuOptionValue}; use pkm_rs::{Nature, Pkx, Shiny}; pub const WHITE: u32 = 0xffffff; @@ -116,43 +116,21 @@ macro_rules! print_stat { } pub fn print_pp(pp: u32) { - pnp::println!( - color = if pp > 1 { WHITE } else { RED }, - "PP Remaining: {}", - pp - ); + pnp::println!(color = if pp > 1 { WHITE } else { RED }, "PP Remaining: {}", pp); } pub fn print_title() { match loaded_title() { Ok(title) => match title { - LoadedTitle::S => { - pnp::println!(color = 0xd75f00, " Pokemon Sun") - } - LoadedTitle::M => { - pnp::println!(color = 0xaf5fff, " Pokemon Moon") - } - LoadedTitle::Us => { - pnp::println!(color = 0xff5f1f, " Pokemon Ultra Sun") - } - LoadedTitle::Um => { - pnp::println!(color = 0xaf00ff, " Pokemon Ultra Moon") - } - LoadedTitle::X => { - pnp::println!(color = 0x00ffff, " Pokemon X") - } - LoadedTitle::Y => { - pnp::println!(color = 0xd7005f, " Pokemon Y") - } - LoadedTitle::Or => { - pnp::println!(color = 0xFF4433, " Pokemon Omega Ruby") - } - LoadedTitle::As => { - pnp::println!(color = 0x0000ff, " Pokemon Alpha Sapphire") - } - LoadedTitle::Transporter => { - pnp::println!(color = 0xd7ff00, " Pokemon Transporter") - } + LoadedTitle::S => pnp::println!(color = 0xd75f00, " Pokemon Sun"), + LoadedTitle::M => pnp::println!(color = 0xaf5fff, " Pokemon Moon"), + LoadedTitle::Us => pnp::println!(color = 0xff5f1f, " Pokemon Ultra Sun"), + LoadedTitle::Um => pnp::println!(color = 0xaf00ff, " Pokemon Ultra Moon"), + LoadedTitle::X => pnp::println!(color = 0x00ffff, " Pokemon X"), + LoadedTitle::Y => pnp::println!(color = 0xd7005f, " Pokemon Y"), + LoadedTitle::Or => pnp::println!(color = 0xFF4433, " Pokemon Omega Ruby"), + LoadedTitle::As => pnp::println!(color = 0x0000ff, " Pokemon Alpha Sapphire"), + LoadedTitle::Transporter => pnp::println!(color = 0xd7ff00, " Pokemon Transporter"), LoadedTitle::CrystalEn | LoadedTitle::CrystalDe | LoadedTitle::CrystalFr diff --git a/reader_core/src/gen6/draw.rs b/reader_core/src/gen6/draw.rs index b782aa3..79f4af4 100644 --- a/reader_core/src/gen6/draw.rs +++ b/reader_core/src/gen6/draw.rs @@ -8,7 +8,7 @@ use crate::{ utils::{format_egg_parent, is_daycare_masuda_method}, }; -pub use crate::draw::{draw_header, draw_pkx, PkxType}; +pub use crate::draw::{PkxType, draw_header, draw_pkx}; pub fn draw_tinymt(reader: &Gen6Reader, rng: &Gen6Rng) { let tinymt = rng.tinymt(); @@ -20,16 +20,8 @@ pub fn draw_tinymt(reader: &Gen6Reader, rng: &Gen6Rng) { pnp::println!("Advances: {}", tinymt.advances()); pnp::println!(""); pnp::println!("TinyMT seed:"); - pnp::println!( - "[3]{:08X} [2]{:08X}", - tinymt_init_state[3], - tinymt_init_state[2] - ); - pnp::println!( - "[1]{:08X} [0]{:08X}", - tinymt_init_state[1], - tinymt_init_state[0] - ); + pnp::println!("[3]{:08X} [2]{:08X}", tinymt_init_state[3], tinymt_init_state[2]); + pnp::println!("[1]{:08X} [0]{:08X}", tinymt_init_state[1], tinymt_init_state[0]); pnp::println!("TinyMT state:"); pnp::println!("[3]{:08X} [2]{:08X}", tinymt_state[3], tinymt_state[2]); pnp::println!("[1]{:08X} [0]{:08X}", tinymt_state[1], tinymt_state[0]); diff --git a/reader_core/src/gen6/game_lib.rs b/reader_core/src/gen6/game_lib.rs index b99dabd..2e69c07 100644 --- a/reader_core/src/gen6/game_lib.rs +++ b/reader_core/src/gen6/game_lib.rs @@ -1,4 +1,4 @@ -use crate::title::{loaded_title, LoadedTitle}; +use crate::title::{LoadedTitle, loaded_title}; use crate::utils::game_fn; game_fn!(xy_get_seed_hash() -> u64 = 0x10cad8); diff --git a/reader_core/src/gen6/oras_frame.rs b/reader_core/src/gen6/oras_frame.rs index ccd73b9..0792e6e 100644 --- a/reader_core/src/gen6/oras_frame.rs +++ b/reader_core/src/gen6/oras_frame.rs @@ -1,7 +1,6 @@ use super::{ draw::{ - draw_daycare, draw_dex_nav, draw_header, draw_mirage_spot, draw_pkx, draw_rng, - draw_seed_rng, PkxType, + PkxType, draw_daycare, draw_dex_nav, draw_header, draw_mirage_spot, draw_pkx, draw_rng, draw_seed_rng, }, reader::Gen6Reader, rng::Gen6Rng, @@ -9,10 +8,10 @@ use super::{ use crate::{ pnp, utils::{ + ShowView, help_menu::HelpMenu, menu::{Menu, MenuOption, MenuOptionValue}, sub_menu::SubMenu, - ShowView, }, }; use once_cell::unsync::Lazy; diff --git a/reader_core/src/gen6/reader.rs b/reader_core/src/gen6/reader.rs index a22c45c..b3d809f 100644 --- a/reader_core/src/gen6/reader.rs +++ b/reader_core/src/gen6/reader.rs @@ -103,9 +103,7 @@ pub struct Gen6Reader { impl Gen6Reader { pub fn xy() -> Self { - Self { - addrs: &XY_ADDRESSES, - } + Self { addrs: &XY_ADDRESSES } } pub fn oras() -> Self { diff --git a/reader_core/src/gen6/rng.rs b/reader_core/src/gen6/rng.rs index 4a33cdd..e378d7c 100644 --- a/reader_core/src/gen6/rng.rs +++ b/reader_core/src/gen6/rng.rs @@ -1,5 +1,5 @@ use super::reader::Gen6Reader; -use crate::rng::{RngWrapper, TinyMT, MT}; +use crate::rng::{MT, RngWrapper, TinyMT}; #[derive(Default)] pub struct Gen6Rng { diff --git a/reader_core/src/gen6/xy_frame.rs b/reader_core/src/gen6/xy_frame.rs index 322cf27..066ca45 100644 --- a/reader_core/src/gen6/xy_frame.rs +++ b/reader_core/src/gen6/xy_frame.rs @@ -1,15 +1,15 @@ use super::{ - draw::{draw_daycare, draw_header, draw_pkx, draw_radar, draw_rng, draw_seed_rng, PkxType}, + draw::{PkxType, draw_daycare, draw_header, draw_pkx, draw_radar, draw_rng, draw_seed_rng}, reader::Gen6Reader, rng::Gen6Rng, }; use crate::{ pnp, utils::{ + ShowView, help_menu::HelpMenu, menu::{Menu, MenuOption, MenuOptionValue}, sub_menu::SubMenu, - ShowView, }, }; use once_cell::unsync::Lazy; diff --git a/reader_core/src/gen7/draw.rs b/reader_core/src/gen7/draw.rs index 2d33066..b0534a4 100644 --- a/reader_core/src/gen7/draw.rs +++ b/reader_core/src/gen7/draw.rs @@ -5,9 +5,7 @@ use crate::{ utils::{format_egg_parent, is_daycare_masuda_method}, }; -pub use crate::draw::{ - draw_header, draw_pkx, draw_pkx_brief, get_pp, print_pp, PkxType, GREEN, RED, WHITE, -}; +pub use crate::draw::{GREEN, PkxType, RED, WHITE, draw_header, draw_pkx, draw_pkx_brief, get_pp, print_pp}; pub fn draw_rng(reader: &Gen7Reader, rng: &RngWrapper) { let sfmt_state = rng.current_state(); @@ -43,10 +41,7 @@ pub fn draw_sos(reader: &Gen7Reader, slot: u32, correction: u32) { pnp::println!("Caller Slot: {}", slot); print_pp(get_pp(&reader.sos_caller_pkm(slot))); pnp::println!(""); - pnp::println!( - "Ally Data (Slot {}):", - reader.ally_slot(slot, correction) + 1 - ); + pnp::println!("Ally Data (Slot {}):", reader.ally_slot(slot, correction) + 1); draw_pkx_brief(&reader.sos_ally_pkm(slot, correction)); } diff --git a/reader_core/src/gen7/frame.rs b/reader_core/src/gen7/frame.rs index 2663663..0b38554 100644 --- a/reader_core/src/gen7/frame.rs +++ b/reader_core/src/gen7/frame.rs @@ -1,16 +1,16 @@ use super::{ - draw::{draw_citra_info, draw_daycare, draw_header, draw_pkx, draw_rng, draw_sos, PkxType}, + draw::{PkxType, draw_citra_info, draw_daycare, draw_header, draw_pkx, draw_rng, draw_sos}, reader::Gen7Reader, }; use crate::{ pnp, rng::{RngWrapper, Sfmt}, utils::{ + ShowView, help_menu::HelpMenu, menu::{Menu, MenuOption, MenuOptionValue}, sub_menu::SubMenu, sub_menu_capture::SubMenuCapture, - ShowView, }, }; use once_cell::unsync::Lazy; diff --git a/reader_core/src/gen7/reader.rs b/reader_core/src/gen7/reader.rs index 290f1a9..ad47ec6 100644 --- a/reader_core/src/gen7/reader.rs +++ b/reader_core/src/gen7/reader.rs @@ -1,6 +1,6 @@ use super::{game_lib, hook}; use crate::pnp; -use core::num::{NonZeroU32, NonZeroU8}; +use core::num::{NonZeroU8, NonZeroU32}; use pkm_rs::{Pk7, PokeCrypto}; struct Gen7Addresses { @@ -161,10 +161,7 @@ impl Gen7Reader { if self.sos_chain() == 0 { 0 } else { - ((caller_slot - 1) - + ((self.sos_chain() as i32 - (correction as i32 + 1)) % 3) as u32 - + 1) - % 4 + ((caller_slot - 1) + ((self.sos_chain() as i32 - (correction as i32 + 1)) % 3) as u32 + 1) % 4 } } @@ -241,16 +238,11 @@ impl Gen7Reader { let can_blink = pnp::read::(npc + 0xe8) == 0; if is_present && can_blink { - let blink_type = - NonZeroU32::new(pnp::read::(npc + self.addrs.npc_head_blinking_offset)) - .and_then(|struct_ptr| { - NonZeroU32::new(pnp::read::(struct_ptr.get() + 0x114)) - }) - .and_then(|struct_ptr| { - NonZeroU8::new(pnp::read::(struct_ptr.get() + 0xde)) - }) - .map(|blink_setting| blink_setting.get()) - .unwrap_or_default(); + let blink_type = NonZeroU32::new(pnp::read::(npc + self.addrs.npc_head_blinking_offset)) + .and_then(|struct_ptr| NonZeroU32::new(pnp::read::(struct_ptr.get() + 0x114))) + .and_then(|struct_ptr| NonZeroU8::new(pnp::read::(struct_ptr.get() + 0xde))) + .map(|blink_setting| blink_setting.get()) + .unwrap_or_default(); let is_blinking = blink_type == 1 || blink_type == 2; if is_blinking { npc_count += 1; diff --git a/reader_core/src/lib.rs b/reader_core/src/lib.rs index 5bccfd1..aad8f3e 100644 --- a/reader_core/src/lib.rs +++ b/reader_core/src/lib.rs @@ -21,7 +21,7 @@ mod utils; pub const VERSION: &str = env!("CARGO_PKG_VERSION"); pub const GIT_HASH: &str = env!("GIT_HASH"); -use title::{loaded_title, LoadedTitle, TitleError}; +use title::{LoadedTitle, TitleError, loaded_title}; #[cfg(target_os = "horizon")] #[panic_handler] diff --git a/reader_core/src/pnp/memory.rs b/reader_core/src/pnp/memory.rs index b2b8d09..62e1afa 100644 --- a/reader_core/src/pnp/memory.rs +++ b/reader_core/src/pnp/memory.rs @@ -1,6 +1,6 @@ use super::bindings; use alloc::{vec, vec::Vec}; -use binrw::{io::Cursor, BinRead, BinWrite, BinWriterExt}; +use binrw::{BinRead, BinWrite, BinWriterExt, io::Cursor}; use core::mem; pub fn pa_from_va_ptr(ptr: u32) -> u32 { diff --git a/reader_core/src/rng/mt.rs b/reader_core/src/rng/mt.rs index 9134d1b..a316de7 100644 --- a/reader_core/src/rng/mt.rs +++ b/reader_core/src/rng/mt.rs @@ -26,9 +26,7 @@ impl MT { let mut seed = seed; for i in 1..624 { - seed = (seed ^ (seed >> 30)) - .wrapping_mul(0x6c078965) - .wrapping_add(i); + seed = (seed ^ (seed >> 30)).wrapping_mul(0x6c078965).wrapping_add(i); self.mt[i as usize] = seed; } } diff --git a/reader_core/src/rng/rng_wrapper.rs b/reader_core/src/rng/rng_wrapper.rs index 6d3aba7..7085c90 100644 --- a/reader_core/src/rng/rng_wrapper.rs +++ b/reader_core/src/rng/rng_wrapper.rs @@ -64,7 +64,7 @@ impl RngWrapper { #[cfg(test)] mod test { use super::*; - use crate::rng::{Rng, Sfmt, TinyMT, MT}; + use crate::rng::{MT, Rng, Sfmt, TinyMT}; #[test] fn should_track_sfmt_advances() { diff --git a/reader_core/src/rng/sfmt.rs b/reader_core/src/rng/sfmt.rs index bb1b598..e6968be 100644 --- a/reader_core/src/rng/sfmt.rs +++ b/reader_core/src/rng/sfmt.rs @@ -23,9 +23,7 @@ impl Sfmt { let mut seed = seed; for i in 1..624 { - seed = (seed ^ (seed >> 30)) - .wrapping_mul(0x6c078965) - .wrapping_add(i); + seed = (seed ^ (seed >> 30)).wrapping_mul(0x6c078965).wrapping_add(i); self.sfmt[i as usize] = seed; } diff --git a/reader_core/src/transporter/draw.rs b/reader_core/src/transporter/draw.rs index fb93262..8e5ede2 100644 --- a/reader_core/src/transporter/draw.rs +++ b/reader_core/src/transporter/draw.rs @@ -1,5 +1,5 @@ use super::rng::TransporterRng; -pub use crate::draw::{draw_header, draw_pkx, PkxType}; +pub use crate::draw::{PkxType, draw_header, draw_pkx}; use crate::pnp; pub fn draw_rng(rng: &TransporterRng) { diff --git a/reader_core/src/transporter/frame.rs b/reader_core/src/transporter/frame.rs index daed7fc..dbfad4e 100644 --- a/reader_core/src/transporter/frame.rs +++ b/reader_core/src/transporter/frame.rs @@ -1,15 +1,15 @@ use super::{ - draw::{draw_header, draw_pkx, draw_rng, PkxType}, + draw::{PkxType, draw_header, draw_pkx, draw_rng}, reader::TransporterReader, rng::TransporterRng, }; use crate::{ pnp, utils::{ + ShowView, help_menu::HelpMenu, menu::{Menu, MenuOption, MenuOptionValue}, sub_menu::SubMenu, - ShowView, }, }; use once_cell::unsync::Lazy; @@ -74,9 +74,7 @@ pub fn run_frame() { } let is_locked = state.main_menu.update_lock(); - state.view = state - .main_menu - .next_view(TransporterView::MainMenu, state.view); + state.view = state.main_menu.next_view(TransporterView::MainMenu, state.view); draw_header(TransporterView::MainMenu, state.view, is_locked); match state.view { diff --git a/reader_core/src/transporter/rng.rs b/reader_core/src/transporter/rng.rs index bb3f4bd..ef0a8f2 100644 --- a/reader_core/src/transporter/rng.rs +++ b/reader_core/src/transporter/rng.rs @@ -1,5 +1,5 @@ use super::reader::TransporterReader; -use crate::rng::{RngWrapper, MT}; +use crate::rng::{MT, RngWrapper}; #[derive(Default)] pub struct TransporterRng { diff --git a/reader_core/src/utils/hook_game_branch.rs b/reader_core/src/utils/hook_game_branch.rs index e10933a..845b2ef 100644 --- a/reader_core/src/utils/hook_game_branch.rs +++ b/reader_core/src/utils/hook_game_branch.rs @@ -20,8 +20,7 @@ fn replace_arm_branch( }; } - let new_offset = - (((new_jump_address as i32 - instruction_address as i32 - 8) >> 2) & 0x00FFFFFF) as u32; + let new_offset = (((new_jump_address as i32 - instruction_address as i32 - 8) >> 2) & 0x00FFFFFF) as u32; let new_branch_instruction = (branch_instruction & 0xFF000000) | new_offset; ReplacedBranch { diff --git a/reader_core/src/utils/menu.rs b/reader_core/src/utils/menu.rs index 5c4d7fa..d5aab2f 100644 --- a/reader_core/src/utils/menu.rs +++ b/reader_core/src/utils/menu.rs @@ -47,11 +47,7 @@ impl Menu { } fn cursor_str(&self, index: usize) -> &str { - if self.counter.value() == index { - ">" - } else { - " " - } + if self.counter.value() == index { ">" } else { " " } } pub fn draw(&self) { diff --git a/reader_core/src/utils/show_view.rs b/reader_core/src/utils/show_view.rs index a0abc66..f94cade 100644 --- a/reader_core/src/utils/show_view.rs +++ b/reader_core/src/utils/show_view.rs @@ -1,4 +1,4 @@ -use crate::pnp::{is_just_pressed, Button}; +use crate::pnp::{Button, is_just_pressed}; // This is abstracted away for consistency. // Some logic needs to run per frame, regardless of a screen showing. diff --git a/reader_core/src/utils/sub_menu_capture.rs b/reader_core/src/utils/sub_menu_capture.rs index 2da19ce..23713c7 100644 --- a/reader_core/src/utils/sub_menu_capture.rs +++ b/reader_core/src/utils/sub_menu_capture.rs @@ -25,12 +25,7 @@ impl SubMenuCapture { } } - pub fn update_headless( - &mut self, - is_locked: bool, - capture_value: u32, - set_value: usize, - ) -> usize { + pub fn update_headless(&mut self, is_locked: bool, capture_value: u32, set_value: usize) -> usize { self.update_counter(is_locked, capture_value, set_value); self.counter.value() } @@ -40,6 +35,6 @@ impl SubMenuCapture { } pub fn counter_value(&self) -> usize { - return self.counter.value(); + self.counter.value() } } From 9bd354d4c988248ceac76346e33d9a02de72aa24 Mon Sep 17 00:00:00 2001 From: serenagrace Date: Fri, 10 Oct 2025 09:25:42 -0500 Subject: [PATCH 21/39] Stabilize formatting --- reader_core/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/reader_core/src/lib.rs b/reader_core/src/lib.rs index aad8f3e..dd61133 100644 --- a/reader_core/src/lib.rs +++ b/reader_core/src/lib.rs @@ -1,7 +1,6 @@ #![no_std] #![allow(static_mut_refs)] #![feature(naked_functions)] -#![rustfmt::skip::macros(println)] extern crate alloc; From 2db4b87eaf230bda8bbf31babf7f234251c5344c Mon Sep 17 00:00:00 2001 From: serenagrace Date: Fri, 10 Oct 2025 18:19:28 -0500 Subject: [PATCH 22/39] Added SOS Index, Caller Slot Call Rate --- reader_core/Cargo.lock | 2 +- reader_core/Cargo.toml | 2 +- reader_core/src/gen7/call_rates.rs | 262 +++++++++++++++++++++++++++++ reader_core/src/gen7/draw.rs | 13 +- reader_core/src/gen7/mod.rs | 2 + reader_core/src/gen7/reader.rs | 54 ++++-- reader_core/src/pnp/memory.rs | 4 + 7 files changed, 323 insertions(+), 16 deletions(-) create mode 100644 reader_core/src/gen7/call_rates.rs diff --git a/reader_core/Cargo.lock b/reader_core/Cargo.lock index cac726b..75b4a89 100644 --- a/reader_core/Cargo.lock +++ b/reader_core/Cargo.lock @@ -133,7 +133,7 @@ dependencies = [ [[package]] name = "pokereader" -version = "0.8.0" +version = "0.8.1" dependencies = [ "binrw 0.14.0", "chrono", diff --git a/reader_core/Cargo.toml b/reader_core/Cargo.toml index c254d7c..5b03dc2 100644 --- a/reader_core/Cargo.toml +++ b/reader_core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pokereader" -version = "0.8.0" +version = "0.8.1" edition = "2021" [dependencies] diff --git a/reader_core/src/gen7/call_rates.rs b/reader_core/src/gen7/call_rates.rs new file mode 100644 index 0000000..4f9fc28 --- /dev/null +++ b/reader_core/src/gen7/call_rates.rs @@ -0,0 +1,262 @@ +use crate::alloc::string::ToString; +use pkm_rs::Pkx; +pub fn lookup_call_rate(pkx: &impl Pkx, is_usum: bool) -> u32 { + match pkx.species_t().to_string().as_str() { + "Slowbro" + | "Dhelmise" + | "Drampa" + | "Turtonator" + | "Lurantis" + | "Lycanroc" + | "Relicanth" + | "Glalie" + | "Absol" + | "Sharpedo" + | "Miltank" + | "Lapras" + | "Gyarados" + | "Tauros" + | "Pinsir" + | "Scyther" + | "Kangaskhan" + | "Marowak" => 3, + "Raticate" + | "Hakamo-o" + | "Bruxish" + | "Pyukumuku" + | "Palossand" + | "Steenee" + | "Bewear" + | "Shiinotic" + | "Araquanid" + | "Mudsdale" + | "Ribombee" + | "Oricorio" + | "Gumshoos" + | "Klefki" + | "Fletchinder" + | "Mandibuzz" + | "Braviary" + | "Alomomola" + | "Garbodor" + | "Krokorok" + | "Boldore" + | "Herdier" + | "Lumineon" + | "Munchlax" + | "Drifblim" + | "Gastrodon" + | "Metang" + | "Shelgon" + | "Luvdisc" + | "Whiscash" + | "Vibrava" + | "Spinda" + | "Torkoal" + | "Wailord" + | "Hariyama" + | "Masquerain" + | "Pelipper" + | "Skarmory" + | "Granbull" + | "Lanturn" + | "Ariados" + | "Ledian" + | "Dragonair" + | "Magmar" + | "Electabuzz" + | "Seaking" + | "Hypno" + | "Haunter" + | "Muk" + | "Magneton" + | "Graveler" + | "Tentacruel" + | "Machoke" + | "Kadabra" + | "Poliwhirl" + | "Primeape" + | "Golduck" + | "Persian" + | "Dugtrio" + | "Parasect" + | "Jigglypuff" + | "Clefairy" + | "Pikachu" + | "Fearow" => 6, + "Rattata" + | "Jangmo-o" + | "Mimikyu" + | "Togedemaru" + | "Sandygast" + | "Comfey" + | "Bounsweet" + | "Stufful" + | "Salandit" + | "Morelull" + | "Fomantis" + | "Dewpider" + | "Mudbray" + | "Wishiwashi" + | "Rockruff" + | "Cutifly" + | "Crabrawler" + | "Grubbin" + | "Yungoos" + | "Trumbeak" + | "Phantump" + | "Carbink" + | "Pancham" + | "Fletchling" + | "Vullaby" + | "Rufflet" + | "Emolga" + | "Trubbish" + | "Sandile" + | "Petilil" + | "Cottonee" + | "Roggenrola" + | "Lillipup" + | "Finneon" + | "Drifloon" + | "Shellos" + | "Beldum" + | "Bagon" + | "Snorunt" + | "Feebas" + | "Barboach" + | "Trapinch" + | "Wailmer" + | "Carvanha" + | "Nosepass" + | "Makuhita" + | "Surskit" + | "Wingull" + | "Smeargle" + | "Delibird" + | "Corsola" + | "Sneasel" + | "Snubbull" + | "Misdreavus" + | "Murkrow" + | "Chinchou" + | "Spinarak" + | "Ledyba" + | "Dratini" + | "Eevee" + | "Ditto" + | "Magikarp" + | "Staryu" + | "Goldeen" + | "Drowzee" + | "Gastly" + | "Shellder" + | "Grimer" + | "Magnemite" + | "Slowpoke" + | "Geodude" + | "Machop" + | "Abra" + | "Poliwag" + | "Growlithe" + | "Mankey" + | "Meowth" + | "Diglett" + | "Paras" + | "Golbat" + | "Vulpix" + | "Sandshrew" + | "Spearow" => 9, + "Caterpie" + | "Passimian" + | "Oranguru" + | "Salazzle" + | "Charjabug" + | "Pikipek" + | "Riolu" + | "Bonsly" + | "Magby" + | "Elekid" + | "Igglybuff" + | "Cleffa" + | "Pichu" + | "Cubone" + | "Exeggcute" + | "Tentacool" + | "Psyduck" + | "Zubat" + | "Metapod" => 15, + "Lickitung" + | "Hawlucha" + | "Larvesta" + | "Druddigon" + | "Mienshao" + | "Tropius" + | "Remoraid" + | "Heracross" + | "Dunsparce" => if is_usum { 3 } else { 0 }, + "Arbok" + | "Noivern" + | "Clawitzer" + | "Dragalage" + | "Malamar" + | "Furfrou" + | "Pyroar" + | "Mienfoo" + | "Jellicent" + | "Zoroark" + | "Scrafty" + | "Lopunny" + | "Banette" + | "Crawdaunt" + | "Manectric" + | "Mawile" + | "Houndoom" + | "Forretress" + | "Flaaffy" + | "Xatu" + | "Noctowl" + | "Dewgong" => if is_usum { 6 } else { 0 }, + "Chansey" + | "Noibat" + | "Dedenne" + | "Clauncher" + | "Skrelp" + | "Inkay" + | "Floette" // Warn: Apparently Only red Floette can call SOS + | "Litleo" + | "Frillish" + | "Minccino" + | "Zorua" + | "Scraggy" + | "Basculin" + | "Buneary" + | "Shuppet" + | "Keckleon" + | "Corphish" + | "Electrike" + | "Pupitar" + | "Larvitar" + | "Houndour" + | "Pineco" + | "Aipom" + | "Mareep" + | "Natu" + | "Hoothoot" + | "Seel" + | "Ekans" => if is_usum { 9 } else { 0 }, + "Smoochum" + | "Flabebe" + | "Bisharp" + | "Golurk" + | "Golett" + | "Beheeyem" + | "Elgyem" + | "Mantyke" + | "Mime Jr." + | "Clamperl" + | "Claydol" + | "Baltoy" => if is_usum { 15 } else { 0 }, + _ => 0, + } +} diff --git a/reader_core/src/gen7/draw.rs b/reader_core/src/gen7/draw.rs index b0534a4..9df9c56 100644 --- a/reader_core/src/gen7/draw.rs +++ b/reader_core/src/gen7/draw.rs @@ -1,4 +1,4 @@ -use super::reader::Gen7Reader; +use super::{lookup_call_rate, reader::Gen7Reader}; use crate::{ pnp, rng::{RngWrapper, Sfmt}, @@ -32,13 +32,24 @@ pub fn draw_citra_info(reader: &Gen7Reader) { pub fn draw_sos(reader: &Gen7Reader, slot: u32, correction: u32) { pnp::println!("SOS Seed: {:08X}", reader.sos_seed()); + + let sos_index = reader.sos_index(); + pnp::println!("SOS Index: {}", sos_index); pnp::println!("SOS Chain Length: {}", reader.sos_chain()); if reader.orb_active() { pnp::println!(color = GREEN, "Orb Active") } else { pnp::println!(color = RED, "Orb Not Active"); } + pnp::println!(""); pnp::println!("Caller Slot: {}", slot); + let species = &reader.sos_caller_pkm(slot); + let call_rate = lookup_call_rate(species, reader.is_usum()); + pnp::println!( + color = if call_rate == 0 { RED } else { WHITE }, + "Call Rate: {}", + call_rate + ); print_pp(get_pp(&reader.sos_caller_pkm(slot))); pnp::println!(""); pnp::println!("Ally Data (Slot {}):", reader.ally_slot(slot, correction) + 1); diff --git a/reader_core/src/gen7/mod.rs b/reader_core/src/gen7/mod.rs index ed5650d..1752f7e 100644 --- a/reader_core/src/gen7/mod.rs +++ b/reader_core/src/gen7/mod.rs @@ -1,8 +1,10 @@ +mod call_rates; mod draw; mod frame; mod game_lib; mod hook; mod reader; +use call_rates::lookup_call_rate; pub use frame::*; pub use hook::{init_sm, init_um, init_us}; diff --git a/reader_core/src/gen7/reader.rs b/reader_core/src/gen7/reader.rs index ad47ec6..f4b575e 100644 --- a/reader_core/src/gen7/reader.rs +++ b/reader_core/src/gen7/reader.rs @@ -3,19 +3,21 @@ use crate::pnp; use core::num::{NonZeroU8, NonZeroU32}; use pkm_rs::{Pk7, PokeCrypto}; -struct Gen7Addresses { +pub struct Gen7Addresses { initial_seed: u32, sfmt_state_index: u32, sfmt_state: u32, + _sos_base_addr: u32, + _sos_sfmt_state: u32, party: u32, wild: u32, sos: u32, - orb_active: u32, + sos_index: u32, sos_chain_length: u32, + _prev_call_succeed: u32, + orb_active: u32, // To be used in the future vvv - _sos_index: u32, _ally_id: u32, - _prev_call_succeed: u32, // pelago: u32, egg_ready: u32, @@ -35,14 +37,16 @@ const SM_ADDRESSES: Gen7Addresses = Gen7Addresses { initial_seed: 0x325a3878, sfmt_state_index: 0x33196548, sfmt_state: 0x33195b88, + _sos_base_addr: 0x30038C44, + _sos_sfmt_state: 0x30038C54, party: 0x34195e10, wild: 0x3002f7b8, sos: 0x3002f7b8, - _sos_index: 0x30039614, - orb_active: 0x3003961c, + sos_index: 0x30039614, sos_chain_length: 0x3003960d, - _ally_id: 0x3003961e, _prev_call_succeed: 0x3003961f, + orb_active: 0x3003961c, + _ally_id: 0x3003961e, pelago: 0x331110ca, egg_ready: 0x3313edd8, egg: 0x3313eddc, @@ -61,14 +65,16 @@ const USUM_ADDRESSES: Gen7Addresses = Gen7Addresses { initial_seed: 0x32663bf0, sfmt_state_index: 0x330d3f98, sfmt_state: 0x330d35d8, + _sos_base_addr: 0x30038E20, + _sos_sfmt_state: 0x30038E30, party: 0x33f7fa44, wild: 0x3002f9a0, sos: 0x3002f9a0, - _sos_index: 0x300397F0, - orb_active: 0x300397f8, + sos_index: 0x300397F0, sos_chain_length: 0x300397f9, - _ally_id: 0x300397fA, _prev_call_succeed: 0x300397fb, + orb_active: 0x300397f8, + _ally_id: 0x300397fA, pelago: 0x3304d16a, egg_ready: 0x3307b1e8, egg: 0x3307b1ec, @@ -103,6 +109,10 @@ impl Gen7Reader { } } + pub fn is_usum(&self) -> bool { + self.is_usum + } + pub fn g7tid(&self) -> u32 { let sidtid = pnp::read::(self.addrs.id); @@ -151,11 +161,29 @@ impl Gen7Reader { hook::sos_seed() } + pub fn sos_index(&self) -> u16 { + let index = pnp::read(self.addrs.sos_index); + if index != 624 { index } else { 0 } + } + + // Unused (not displayed) for now but proven to work + pub fn _sos_state(&self) -> u32 { + pnp::read(self.addrs._sos_sfmt_state + (self.sos_index() as u32 * 4)) + } + + /* Note: Not very useful... + * Value does not update until after last + * input, which makes it rather misleading. */ + pub fn _sos_prevcall(&self) -> bool { + pnp::read_bool(self.addrs._prev_call_succeed) + } + pub fn sos_chain(&self) -> u8 { pnp::read(self.addrs.sos_chain_length) } + pub fn orb_active(&self) -> bool { - ((pnp::read::(self.addrs.orb_active) & 0x1) > 0) as bool + pnp::read_bool(self.addrs.orb_active) } pub fn ally_slot(&self, caller_slot: u32, correction: u32) -> u32 { if self.sos_chain() == 0 { @@ -176,7 +204,7 @@ impl Gen7Reader { } fn egg_parent(&self, is_present: u32, pkm: u32) -> Option { - let is_parent_present = pnp::read::(is_present) != 0; + let is_parent_present = pnp::read_bool(is_present); if !is_parent_present { return None; @@ -215,7 +243,7 @@ impl Gen7Reader { } pub fn is_egg_ready(&self) -> bool { - pnp::read::(self.addrs.egg_ready) != 0 + pnp::read_bool(self.addrs.egg_ready) } fn has_item(&self, offset: u32, item_id: u32, count: u32) -> bool { diff --git a/reader_core/src/pnp/memory.rs b/reader_core/src/pnp/memory.rs index 62e1afa..68e78a8 100644 --- a/reader_core/src/pnp/memory.rs +++ b/reader_core/src/pnp/memory.rs @@ -31,6 +31,10 @@ where T::read_le(&mut reader).unwrap_or_default() } +pub fn read_bool(addr: u32) -> bool { + read::(addr) != 0 +} + pub fn write_slice(addr: u32, buf: &[u8]) { unsafe { bindings::host_write_mem(addr, buf.len() as u32, buf.as_ptr() as u32); From b8f72e56b06d908a6c64ea7aa896797e955d2bb9 Mon Sep 17 00:00:00 2001 From: serenagrace Date: Sat, 11 Oct 2025 11:50:45 -0500 Subject: [PATCH 23/39] Fixed call rates to use species enum --- reader_core/src/gen7/call_rates.rs | 516 ++++++++++++++--------------- 1 file changed, 258 insertions(+), 258 deletions(-) diff --git a/reader_core/src/gen7/call_rates.rs b/reader_core/src/gen7/call_rates.rs index 4f9fc28..2580872 100644 --- a/reader_core/src/gen7/call_rates.rs +++ b/reader_core/src/gen7/call_rates.rs @@ -1,262 +1,262 @@ -use crate::alloc::string::ToString; -use pkm_rs::Pkx; +use pkm_rs::{Pkx, Species::*}; + pub fn lookup_call_rate(pkx: &impl Pkx, is_usum: bool) -> u32 { - match pkx.species_t().to_string().as_str() { - "Slowbro" - | "Dhelmise" - | "Drampa" - | "Turtonator" - | "Lurantis" - | "Lycanroc" - | "Relicanth" - | "Glalie" - | "Absol" - | "Sharpedo" - | "Miltank" - | "Lapras" - | "Gyarados" - | "Tauros" - | "Pinsir" - | "Scyther" - | "Kangaskhan" - | "Marowak" => 3, - "Raticate" - | "Hakamo-o" - | "Bruxish" - | "Pyukumuku" - | "Palossand" - | "Steenee" - | "Bewear" - | "Shiinotic" - | "Araquanid" - | "Mudsdale" - | "Ribombee" - | "Oricorio" - | "Gumshoos" - | "Klefki" - | "Fletchinder" - | "Mandibuzz" - | "Braviary" - | "Alomomola" - | "Garbodor" - | "Krokorok" - | "Boldore" - | "Herdier" - | "Lumineon" - | "Munchlax" - | "Drifblim" - | "Gastrodon" - | "Metang" - | "Shelgon" - | "Luvdisc" - | "Whiscash" - | "Vibrava" - | "Spinda" - | "Torkoal" - | "Wailord" - | "Hariyama" - | "Masquerain" - | "Pelipper" - | "Skarmory" - | "Granbull" - | "Lanturn" - | "Ariados" - | "Ledian" - | "Dragonair" - | "Magmar" - | "Electabuzz" - | "Seaking" - | "Hypno" - | "Haunter" - | "Muk" - | "Magneton" - | "Graveler" - | "Tentacruel" - | "Machoke" - | "Kadabra" - | "Poliwhirl" - | "Primeape" - | "Golduck" - | "Persian" - | "Dugtrio" - | "Parasect" - | "Jigglypuff" - | "Clefairy" - | "Pikachu" - | "Fearow" => 6, - "Rattata" - | "Jangmo-o" - | "Mimikyu" - | "Togedemaru" - | "Sandygast" - | "Comfey" - | "Bounsweet" - | "Stufful" - | "Salandit" - | "Morelull" - | "Fomantis" - | "Dewpider" - | "Mudbray" - | "Wishiwashi" - | "Rockruff" - | "Cutifly" - | "Crabrawler" - | "Grubbin" - | "Yungoos" - | "Trumbeak" - | "Phantump" - | "Carbink" - | "Pancham" - | "Fletchling" - | "Vullaby" - | "Rufflet" - | "Emolga" - | "Trubbish" - | "Sandile" - | "Petilil" - | "Cottonee" - | "Roggenrola" - | "Lillipup" - | "Finneon" - | "Drifloon" - | "Shellos" - | "Beldum" - | "Bagon" - | "Snorunt" - | "Feebas" - | "Barboach" - | "Trapinch" - | "Wailmer" - | "Carvanha" - | "Nosepass" - | "Makuhita" - | "Surskit" - | "Wingull" - | "Smeargle" - | "Delibird" - | "Corsola" - | "Sneasel" - | "Snubbull" - | "Misdreavus" - | "Murkrow" - | "Chinchou" - | "Spinarak" - | "Ledyba" - | "Dratini" - | "Eevee" - | "Ditto" - | "Magikarp" - | "Staryu" - | "Goldeen" - | "Drowzee" - | "Gastly" - | "Shellder" - | "Grimer" - | "Magnemite" - | "Slowpoke" - | "Geodude" - | "Machop" - | "Abra" - | "Poliwag" - | "Growlithe" - | "Mankey" - | "Meowth" - | "Diglett" - | "Paras" - | "Golbat" - | "Vulpix" - | "Sandshrew" - | "Spearow" => 9, - "Caterpie" - | "Passimian" - | "Oranguru" - | "Salazzle" - | "Charjabug" - | "Pikipek" - | "Riolu" - | "Bonsly" - | "Magby" - | "Elekid" - | "Igglybuff" - | "Cleffa" - | "Pichu" - | "Cubone" - | "Exeggcute" - | "Tentacool" - | "Psyduck" - | "Zubat" - | "Metapod" => 15, - "Lickitung" - | "Hawlucha" - | "Larvesta" - | "Druddigon" - | "Mienshao" - | "Tropius" - | "Remoraid" - | "Heracross" - | "Dunsparce" => if is_usum { 3 } else { 0 }, - "Arbok" - | "Noivern" - | "Clawitzer" - | "Dragalage" - | "Malamar" - | "Furfrou" - | "Pyroar" - | "Mienfoo" - | "Jellicent" - | "Zoroark" - | "Scrafty" - | "Lopunny" - | "Banette" - | "Crawdaunt" - | "Manectric" - | "Mawile" - | "Houndoom" - | "Forretress" - | "Flaaffy" - | "Xatu" - | "Noctowl" - | "Dewgong" => if is_usum { 6 } else { 0 }, - "Chansey" - | "Noibat" - | "Dedenne" - | "Clauncher" - | "Skrelp" - | "Inkay" - | "Floette" // Warn: Apparently Only red Floette can call SOS - | "Litleo" - | "Frillish" - | "Minccino" - | "Zorua" - | "Scraggy" - | "Basculin" - | "Buneary" - | "Shuppet" - | "Keckleon" - | "Corphish" - | "Electrike" - | "Pupitar" - | "Larvitar" - | "Houndour" - | "Pineco" - | "Aipom" - | "Mareep" - | "Natu" - | "Hoothoot" - | "Seel" - | "Ekans" => if is_usum { 9 } else { 0 }, - "Smoochum" - | "Flabebe" - | "Bisharp" - | "Golurk" - | "Golett" - | "Beheeyem" - | "Elgyem" - | "Mantyke" - | "Mime Jr." - | "Clamperl" - | "Claydol" - | "Baltoy" => if is_usum { 15 } else { 0 }, + match pkx.species_t() { + Slowbro + | Dhelmise + | Drampa + | Turtonator + | Lurantis + | Lycanroc + | Relicanth + | Glalie + | Absol + | Sharpedo + | Miltank + | Lapras + | Gyarados + | Tauros + | Pinsir + | Scyther + | Kangaskhan + | Marowak => 3, + Raticate + | HakamoO + | Bruxish + | Pyukumuku + | Palossand + | Steenee + | Bewear + | Shiinotic + | Araquanid + | Mudsdale + | Ribombee + | Oricorio + | Gumshoos + | Klefki + | Fletchinder + | Mandibuzz + | Braviary + | Alomomola + | Garbodor + | Krokorok + | Boldore + | Herdier + | Lumineon + | Munchlax + | Drifblim + | Gastrodon + | Metang + | Shelgon + | Luvdisc + | Whiscash + | Vibrava + | Spinda + | Torkoal + | Wailord + | Hariyama + | Masquerain + | Pelipper + | Skarmory + | Granbull + | Lanturn + | Ariados + | Ledian + | Dragonair + | Magmar + | Electabuzz + | Seaking + | Hypno + | Haunter + | Muk + | Magneton + | Graveler + | Tentacruel + | Machoke + | Kadabra + | Poliwhirl + | Primeape + | Golduck + | Persian + | Dugtrio + | Parasect + | Jigglypuff + | Clefairy + | Pikachu + | Fearow => 6, + Rattata + | JangmoO + | Mimikyu + | Togedemaru + | Sandygast + | Comfey + | Bounsweet + | Stufful + | Salandit + | Morelull + | Fomantis + | Dewpider + | Mudbray + | Wishiwashi + | Rockruff + | Cutiefly + | Crabrawler + | Grubbin + | Yungoos + | Trumbeak + | Phantump + | Carbink + | Pancham + | Fletchling + | Vullaby + | Rufflet + | Emolga + | Trubbish + | Sandile + | Petilil + | Cottonee + | Roggenrola + | Lillipup + | Finneon + | Drifloon + | Shellos + | Beldum + | Bagon + | Snorunt + | Feebas + | Barboach + | Trapinch + | Wailmer + | Carvanha + | Nosepass + | Makuhita + | Surskit + | Wingull + | Smeargle + | Delibird + | Corsola + | Sneasel + | Snubbull + | Misdreavus + | Murkrow + | Chinchou + | Spinarak + | Ledyba + | Dratini + | Eevee + | Ditto + | Magikarp + | Staryu + | Goldeen + | Drowzee + | Gastly + | Shellder + | Grimer + | Magnemite + | Slowpoke + | Geodude + | Machop + | Abra + | Poliwag + | Growlithe + | Mankey + | Meowth + | Diglett + | Paras + | Golbat + | Vulpix + | Sandshrew + | Spearow => 9, + Caterpie + | Passimian + | Oranguru + | Salazzle + | Charjabug + | Pikipek + | Riolu + | Bonsly + | Magby + | Elekid + | Igglybuff + | Cleffa + | Pichu + | Cubone + | Exeggcute + | Tentacool + | Psyduck + | Zubat + | Metapod => 15, + Lickitung + | Hawlucha + | Larvesta + | Druddigon + | Mienshao + | Tropius + | Remoraid + | Heracross + | Dunsparce => if is_usum { 3 } else { 0 }, + Arbok + | Noivern + | Clawitzer + | Dragalge + | Malamar + | Furfrou + | Pyroar + | Mienfoo + | Jellicent + | Zoroark + | Scrafty + | Lopunny + | Banette + | Crawdaunt + | Manectric + | Mawile + | Houndoom + | Forretress + | Flaaffy + | Xatu + | Noctowl + | Dewgong => if is_usum { 6 } else { 0 }, + Chansey + | Noibat + | Dedenne + | Clauncher + | Skrelp + | Inkay + | Floette // Warn: Apparently Only red Floette can call SOS + | Litleo + | Frillish + | Minccino + | Zorua + | Scraggy + | Basculin + | Buneary + | Shuppet + | Kecleon + | Corphish + | Electrike + | Pupitar + | Larvitar + | Houndour + | Pineco + | Aipom + | Mareep + | Natu + | Hoothoot + | Seel + | Ekans => if is_usum { 9 } else { 0 }, + Smoochum + | Flabebe + | Bisharp + | Golurk + | Golett + | Beheeyem + | Elgyem + | Mantyke + | MimeJr + | Clamperl + | Claydol + | Baltoy => if is_usum { 15 } else { 0 }, _ => 0, } } From 483041a7dedf1c9f922692bd02956bfe56d80631 Mon Sep 17 00:00:00 2001 From: serenagrace Date: Sat, 11 Oct 2025 11:51:13 -0500 Subject: [PATCH 24/39] Split SFMT -> 32/64bit impls --- reader_core/src/gen7/draw.rs | 4 +- reader_core/src/gen7/frame.rs | 4 +- reader_core/src/gen7/reader.rs | 11 +---- reader_core/src/rng/sfmt.rs | 75 +++++++++++++++++++++++++++++----- 4 files changed, 69 insertions(+), 25 deletions(-) diff --git a/reader_core/src/gen7/draw.rs b/reader_core/src/gen7/draw.rs index 9df9c56..3c19acd 100644 --- a/reader_core/src/gen7/draw.rs +++ b/reader_core/src/gen7/draw.rs @@ -1,13 +1,13 @@ use super::{lookup_call_rate, reader::Gen7Reader}; use crate::{ pnp, - rng::{RngWrapper, Sfmt}, + rng::{RngWrapper, Sfmt32, Sfmt64}, utils::{format_egg_parent, is_daycare_masuda_method}, }; pub use crate::draw::{GREEN, PkxType, RED, WHITE, draw_header, draw_pkx, draw_pkx_brief, get_pp, print_pp}; -pub fn draw_rng(reader: &Gen7Reader, rng: &RngWrapper) { +pub fn draw_rng(reader: &Gen7Reader, rng: &RngWrapper) { let sfmt_state = rng.current_state(); pnp::println!("Seed: {:08X}", rng.init_seed()); diff --git a/reader_core/src/gen7/frame.rs b/reader_core/src/gen7/frame.rs index 0b38554..69199c6 100644 --- a/reader_core/src/gen7/frame.rs +++ b/reader_core/src/gen7/frame.rs @@ -4,7 +4,7 @@ use super::{ }; use crate::{ pnp, - rng::{RngWrapper, Sfmt}, + rng::{RngWrapper, Sfmt32, Sfmt64}, utils::{ ShowView, help_menu::HelpMenu, @@ -47,7 +47,7 @@ impl MenuOptionValue for Gen7View { } struct PersistedState { - sfmt: RngWrapper, + sfmt: RngWrapper, show_view: ShowView, view: Gen7View, main_menu: Menu<9, Gen7View>, diff --git a/reader_core/src/gen7/reader.rs b/reader_core/src/gen7/reader.rs index 838ce99..560d430 100644 --- a/reader_core/src/gen7/reader.rs +++ b/reader_core/src/gen7/reader.rs @@ -181,20 +181,11 @@ impl Gen7Reader { pub fn sos_chain(&self) -> u8 { pnp::read(self.addrs.sos_chain_length) } - pub fn orb_active(&self) -> bool { - ((pnp::read::(self.addrs.orb_active) & 0x1) > 0) as bool - } - pub fn ally_slot(&self, caller_slot: u32, correction: u32) -> u32 { - if self.sos_chain() == 0 { - 0 - } else { - ((caller_slot - 1) + ((self.sos_chain() as i32 - (correction as i32 + 1)) % 3) as u32 + 1) % 4 - } - } pub fn orb_active(&self) -> bool { pnp::read_bool(self.addrs.orb_active) } + pub fn ally_slot(&self, caller_slot: u32, correction: u32) -> u32 { if self.sos_chain() == 0 { 0 diff --git a/reader_core/src/rng/sfmt.rs b/reader_core/src/rng/sfmt.rs index e6968be..7c4c057 100644 --- a/reader_core/src/rng/sfmt.rs +++ b/reader_core/src/rng/sfmt.rs @@ -1,12 +1,12 @@ use crate::rng::Rng; #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct Sfmt { +pub struct Sfmt32 { index: usize, sfmt: [u32; 624], } -impl Sfmt { +impl Sfmt32 { pub fn new(seed: u32) -> Self { let mut rng = Self { sfmt: [0; 624], @@ -36,20 +36,22 @@ impl Sfmt { self.sfmt[0] ^= !inner & 1; } - fn get_current_state(&self) -> u64 { + fn get_current_state(&self) -> u32 { let index = if self.index != 624 { self.index } else { 0 }; - let low = self.sfmt[index] as u64; - let high = self.sfmt[index + 1] as u64; + self.sfmt[index] + } - low | (high << 32) + fn get_next_state(&self) -> u32 { + let index = if self.index != 624 { self.index } else { 0 }; + self.sfmt[index + 1] } - pub fn next(&mut self) -> u64 { + pub fn next(&mut self) -> u32 { if self.index == 624 { self.shuffle(); } - self.index += 2; + self.index += 1; self.get_current_state() } @@ -95,7 +97,7 @@ impl Sfmt { } } -impl Default for Sfmt { +impl Default for Sfmt32 { fn default() -> Self { Self { index: 0, @@ -104,12 +106,63 @@ impl Default for Sfmt { } } -impl Rng for Sfmt { +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Sfmt64 { + sfmt: Sfmt32, +} + +impl Sfmt64 { + pub fn new(seed: u32) -> Self { + Self { + sfmt: Sfmt32::new(seed), + } + } + + fn get_current_state(&self) -> u64 { + let lo = self.sfmt.get_current_state() as u64; + let hi = self.sfmt.get_next_state() as u64; + lo | (hi << 32) + } + + pub fn next(&mut self) -> u64 { + self.sfmt.next(); + let lo = self.sfmt.next() as u64; + let hi = self.sfmt.get_next_state() as u64; + lo | (hi << 32) + } +} + +impl Default for Sfmt64 { + fn default() -> Self { + Self { + sfmt: Sfmt32::default(), + } + } +} + +impl Rng for Sfmt32 { + type Seed = u32; + type CurrentState = u32; + + fn new(seed: Self::Seed) -> Self { + Sfmt32::new(seed) + } + + fn next_state(&mut self) -> Self::CurrentState { + self.next() + } + + fn current_state(&mut self) -> Self::CurrentState { + self.get_current_state() + } +} + +impl Rng for Sfmt64 { type Seed = u32; type CurrentState = u64; fn new(seed: Self::Seed) -> Self { - Sfmt::new(seed) + Sfmt64::new(seed) } fn next_state(&mut self) -> Self::CurrentState { From eca50523467c6c7d57a18d714ce94381ae325d30 Mon Sep 17 00:00:00 2001 From: serenagrace Date: Sat, 11 Oct 2025 11:59:53 -0500 Subject: [PATCH 25/39] Implemented RNG wrapper for SOS Sfmt32 --- reader_core/src/gen7/draw.rs | 5 +++-- reader_core/src/gen7/frame.rs | 9 ++++++++- reader_core/src/gen7/reader.rs | 19 +++++++++---------- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/reader_core/src/gen7/draw.rs b/reader_core/src/gen7/draw.rs index 3c19acd..8164736 100644 --- a/reader_core/src/gen7/draw.rs +++ b/reader_core/src/gen7/draw.rs @@ -30,11 +30,12 @@ pub fn draw_citra_info(reader: &Gen7Reader) { pnp::println!("Time offset: {}", main_rng_seed_context.time_offset_ms); } -pub fn draw_sos(reader: &Gen7Reader, slot: u32, correction: u32) { - pnp::println!("SOS Seed: {:08X}", reader.sos_seed()); +pub fn draw_sos(reader: &Gen7Reader, rng: &RngWrapper, slot: u32, correction: u32) { + pnp::println!("SOS Seed: {:08X}", rng.init_seed()); let sos_index = reader.sos_index(); pnp::println!("SOS Index: {}", sos_index); + pnp::println!("SOS Index: {}", rng.advances()); pnp::println!("SOS Chain Length: {}", reader.sos_chain()); if reader.orb_active() { pnp::println!(color = GREEN, "Orb Active") diff --git a/reader_core/src/gen7/frame.rs b/reader_core/src/gen7/frame.rs index 69199c6..7e116bf 100644 --- a/reader_core/src/gen7/frame.rs +++ b/reader_core/src/gen7/frame.rs @@ -48,6 +48,7 @@ impl MenuOptionValue for Gen7View { struct PersistedState { sfmt: RngWrapper, + sos_sfmt: RngWrapper, show_view: ShowView, view: Gen7View, main_menu: Menu<9, Gen7View>, @@ -61,6 +62,7 @@ struct PersistedState { unsafe fn get_state() -> &'static mut PersistedState { static mut STATE: Lazy = Lazy::new(|| PersistedState { sfmt: RngWrapper::default(), + sos_sfmt: RngWrapper::default(), show_view: ShowView::default(), view: Gen7View::MainMenu, party_menu: SubMenu::default(), @@ -102,12 +104,17 @@ fn run_frame(reader: Gen7Reader) { let init_seed: u32 = reader.init_seed(); let sfmt_state: u64 = reader.sfmt_state(); + let sos_seed: u32 = reader.sos_seed(); + let sos_state: u32 = reader.sos_state(); + // This is safe as long as this is guaranteed to run single threaded. // A lock hinders performance too much on a 3ds. let state = unsafe { get_state() }; state.sfmt.reinit_if_needed(init_seed); state.sfmt.update_advances(sfmt_state); + state.sos_sfmt.reinit_if_needed(sos_seed); + state.sos_sfmt.update_advances(sos_state); if !state.show_view.check() { return; @@ -133,7 +140,7 @@ fn run_frame(reader: Gen7Reader) { reader.ally_slot(prev_caller_slot as u32, prev_correction_value) as usize + 1, ); let correction_value = state.sos_menu.captured_value(); - draw_sos(&reader, caller_slot as u32, correction_value); + draw_sos(&reader, &state.sos_sfmt, caller_slot as u32, correction_value); } Gen7View::Box => draw_pkx(&reader.box_pkm(), PkxType::Tame), Gen7View::Citra => draw_citra_info(&reader), diff --git a/reader_core/src/gen7/reader.rs b/reader_core/src/gen7/reader.rs index 560d430..9d45f12 100644 --- a/reader_core/src/gen7/reader.rs +++ b/reader_core/src/gen7/reader.rs @@ -3,12 +3,12 @@ use crate::pnp; use core::num::{NonZeroU8, NonZeroU32}; use pkm_rs::{Pk7, PokeCrypto}; -pub struct Gen7Addresses { +struct Gen7Addresses { initial_seed: u32, sfmt_state_index: u32, sfmt_state: u32, _sos_base_addr: u32, - _sos_sfmt_state: u32, + sos_sfmt_state: u32, party: u32, wild: u32, sos: u32, @@ -38,7 +38,7 @@ const SM_ADDRESSES: Gen7Addresses = Gen7Addresses { sfmt_state_index: 0x33196548, sfmt_state: 0x33195b88, _sos_base_addr: 0x30038C44, - _sos_sfmt_state: 0x30038C54, + sos_sfmt_state: 0x30038C54, party: 0x34195e10, wild: 0x3002f7b8, sos: 0x3002f7b8, @@ -66,7 +66,7 @@ const USUM_ADDRESSES: Gen7Addresses = Gen7Addresses { sfmt_state_index: 0x330d3f98, sfmt_state: 0x330d35d8, _sos_base_addr: 0x30038E20, - _sos_sfmt_state: 0x30038E30, + sos_sfmt_state: 0x30038E30, party: 0x33f7fa44, wild: 0x3002f9a0, sos: 0x3002f9a0, @@ -140,12 +140,12 @@ impl Gen7Reader { } fn sfmt_state_index(&self) -> u32 { - pnp::read(self.addrs.sfmt_state_index) + let index = pnp::read(self.addrs.sfmt_state_index); + if index != 624 { index } else { 0 } } pub fn sfmt_state(&self) -> u64 { - let index = self.sfmt_state_index(); - pnp::read(self.addrs.sfmt_state + if index != 624 { index * 4 } else { 0 }) + pnp::read(self.addrs.sfmt_state + self.sfmt_state_index() * 4) } pub fn egg_seed(&self) -> [u32; 4] { @@ -166,9 +166,8 @@ impl Gen7Reader { if index != 624 { index } else { 0 } } - // Unused (not displayed) for now but proven to work - pub fn _sos_state(&self) -> u32 { - pnp::read(self.addrs._sos_sfmt_state + (self.sos_index() as u32 * 4)) + pub fn sos_state(&self) -> u32 { + pnp::read(self.addrs.sos_sfmt_state + (self.sos_index() as u32 * 4)) } /* Note: Not very useful... From 7bc56fc789d4be19791d616289ccf8375727b663 Mon Sep 17 00:00:00 2001 From: serenagrace Date: Sun, 12 Oct 2025 19:04:28 -0500 Subject: [PATCH 26/39] PP Coloration and Color Constants --- reader_core/src/draw.rs | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/reader_core/src/draw.rs b/reader_core/src/draw.rs index 383cbf7..9c94b12 100644 --- a/reader_core/src/draw.rs +++ b/reader_core/src/draw.rs @@ -6,9 +6,18 @@ use crate::{pnp, utils::menu::MenuOptionValue}; use pkm_rs::{Nature, Pkx, Shiny}; pub const WHITE: u32 = 0xffffff; -pub const GREEN: u32 = 0x00cc00; pub const RED: u32 = 0xff0000; +pub const MAGMA_RED: u32 = 0xFF4433; +pub const ORANGE: u32 = 0xd75f00; +pub const ULTRA_ORANGE: u32 = 0xff5f1f; +pub const YELLOW: u32 = 0xd7ff00; +pub const GREEN: u32 = 0x00cc00; +pub const CYAN: u32 = 0x00ffff; pub const MUTED_CYAN: u32 = 0x00cccc; +pub const BLUE: u32 = 0x0000ff; +pub const PURPLE: u32 = 0xaf5fff; +pub const ULTRA_PURPLE: u32 = 0xaf00ff; +pub const HOT_PINK: u32 = 0xd7005f; fn get_shiny_color(is_shiny: bool) -> u32 { match is_shiny { @@ -116,21 +125,29 @@ macro_rules! print_stat { } pub fn print_pp(pp: u32) { - pnp::println!(color = if pp > 1 { WHITE } else { RED }, "PP Remaining: {}", pp); + let color = match pp << 1 { + 1 => RED, + 2 => MAGMA_RED, + 3 => ORANGE, + 4 => ULTRA_ORANGE, + 5 => YELLOW, + _ => WHITE, + }; + pnp::println!(color = color, "PP Remaining: {}", pp); } pub fn print_title() { match loaded_title() { Ok(title) => match title { - LoadedTitle::S => pnp::println!(color = 0xd75f00, " Pokemon Sun"), - LoadedTitle::M => pnp::println!(color = 0xaf5fff, " Pokemon Moon"), - LoadedTitle::Us => pnp::println!(color = 0xff5f1f, " Pokemon Ultra Sun"), - LoadedTitle::Um => pnp::println!(color = 0xaf00ff, " Pokemon Ultra Moon"), - LoadedTitle::X => pnp::println!(color = 0x00ffff, " Pokemon X"), - LoadedTitle::Y => pnp::println!(color = 0xd7005f, " Pokemon Y"), - LoadedTitle::Or => pnp::println!(color = 0xFF4433, " Pokemon Omega Ruby"), - LoadedTitle::As => pnp::println!(color = 0x0000ff, " Pokemon Alpha Sapphire"), - LoadedTitle::Transporter => pnp::println!(color = 0xd7ff00, " Pokemon Transporter"), + LoadedTitle::S => pnp::println!(color = ORANGE, " Pokemon Sun"), + LoadedTitle::M => pnp::println!(color = PURPLE, " Pokemon Moon"), + LoadedTitle::Us => pnp::println!(color = ULTRA_ORANGE, " Pokemon Ultra Sun"), + LoadedTitle::Um => pnp::println!(color = ULTRA_PURPLE, " Pokemon Ultra Moon"), + LoadedTitle::X => pnp::println!(color = CYAN, " Pokemon X"), + LoadedTitle::Y => pnp::println!(color = HOT_PINK, " Pokemon Y"), + LoadedTitle::Or => pnp::println!(color = MAGMA_RED, " Pokemon Omega Ruby"), + LoadedTitle::As => pnp::println!(color = BLUE, " Pokemon Alpha Sapphire"), + LoadedTitle::Transporter => pnp::println!(color = YELLOW, " Pokemon Transporter"), LoadedTitle::CrystalEn | LoadedTitle::CrystalDe | LoadedTitle::CrystalFr From 9f337c265a218574d53f6497cc0a326843a55d59 Mon Sep 17 00:00:00 2001 From: serenagrace Date: Sun, 12 Oct 2025 19:09:47 -0500 Subject: [PATCH 27/39] Added failbacks to drawpkx functions --- reader_core/src/draw.rs | 19 +++++++++++++++++-- reader_core/src/gen7/frame.rs | 5 +++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/reader_core/src/draw.rs b/reader_core/src/draw.rs index 9c94b12..aa73d99 100644 --- a/reader_core/src/draw.rs +++ b/reader_core/src/draw.rs @@ -170,7 +170,10 @@ pub fn shiny_type(pkx: &impl Pkx) -> &'static str { } } -pub fn draw_pkx_brief(pkx: &impl Pkx) { +pub fn draw_pkx_brief(pkx: &impl Pkx) -> bool { + if !pkx.is_valid() { + return draw_invalid_pkx(); + } let species = pkx.species_t().to_string(); let ability = pkx.ability_t().to_string(); @@ -199,9 +202,14 @@ pub fn draw_pkx_brief(pkx: &impl Pkx) { iv_spd, iv_spe ); + + return false; } -pub fn draw_pkx(pkx: &impl Pkx, pkx_type: PkxType) { +pub fn draw_pkx(pkx: &impl Pkx, pkx_type: PkxType) -> bool { + if !pkx.is_valid() { + return draw_invalid_pkx(); + } let species = pkx.species_t().to_string(); let ability = pkx.ability_t().to_string(); @@ -244,6 +252,13 @@ pub fn draw_pkx(pkx: &impl Pkx, pkx_type: PkxType) { print_stat!(iv_spa, ev_spa, SpA, &nature_stat, "SpA "); print_stat!(iv_spd, ev_spd, SpD, &nature_stat, "SpD "); print_stat!(iv_spe, ev_spe, Spe, &nature_stat, "Spe "); + + return false; +} + +pub fn draw_invalid_pkx() -> bool { + pnp::println!("No Data."); + return true; } pub fn draw_controls_help() { diff --git a/reader_core/src/gen7/frame.rs b/reader_core/src/gen7/frame.rs index 7e116bf..897fe8d 100644 --- a/reader_core/src/gen7/frame.rs +++ b/reader_core/src/gen7/frame.rs @@ -141,8 +141,9 @@ fn run_frame(reader: Gen7Reader) { ); let correction_value = state.sos_menu.captured_value(); draw_sos(&reader, &state.sos_sfmt, caller_slot as u32, correction_value); + Gen7View::Box => { + draw_pkx(&reader.box_pkm(), PkxType::Tame); } - Gen7View::Box => draw_pkx(&reader.box_pkm(), PkxType::Tame), Gen7View::Citra => draw_citra_info(&reader), Gen7View::Party => { let slot = state.party_menu.update_and_draw(is_locked); @@ -150,7 +151,7 @@ fn run_frame(reader: Gen7Reader) { } Gen7View::Pelago => { let slot = state.pelago_menu.update_and_draw(is_locked); - draw_pkx(&reader.pelago_pkm((slot - 1) as u32), PkxType::Wild) + draw_pkx(&reader.pelago_pkm((slot - 1) as u32), PkxType::Wild); } Gen7View::HelpMenu => state.help_menu.update_and_draw(is_locked), Gen7View::MainMenu => { From a29c0a97cbce447df67e1c24c2ed944546abd1ac Mon Sep 17 00:00:00 2001 From: serenagrace Date: Sun, 12 Oct 2025 19:12:36 -0500 Subject: [PATCH 28/39] Gen7 Reader Slot/Side Refactor + SOS Track --- reader_core/src/gen7/draw.rs | 81 ++++++++++--- reader_core/src/gen7/frame.rs | 56 ++++----- reader_core/src/gen7/reader.rs | 137 ++++++++++++++++++---- reader_core/src/utils/circular_counter.rs | 5 +- reader_core/src/utils/mod.rs | 1 - reader_core/src/utils/sub_menu.rs | 11 ++ reader_core/src/utils/sub_menu_capture.rs | 40 ------- 7 files changed, 214 insertions(+), 117 deletions(-) delete mode 100644 reader_core/src/utils/sub_menu_capture.rs diff --git a/reader_core/src/gen7/draw.rs b/reader_core/src/gen7/draw.rs index 8164736..278e56d 100644 --- a/reader_core/src/gen7/draw.rs +++ b/reader_core/src/gen7/draw.rs @@ -1,11 +1,17 @@ -use super::{lookup_call_rate, reader::Gen7Reader}; +use super::{ + lookup_call_rate, + reader::{Gen7Reader, Gen7WildSide}, +}; use crate::{ pnp, rng::{RngWrapper, Sfmt32, Sfmt64}, utils::{format_egg_parent, is_daycare_masuda_method}, }; +use pkm_rs::Pkx; -pub use crate::draw::{GREEN, PkxType, RED, WHITE, draw_header, draw_pkx, draw_pkx_brief, get_pp, print_pp}; +pub use crate::draw::{ + GREEN, PkxType, RED, WHITE, draw_header, draw_invalid_pkx, draw_pkx, draw_pkx_brief, get_pp, print_pp, +}; pub fn draw_rng(reader: &Gen7Reader, rng: &RngWrapper) { let sfmt_state = rng.current_state(); @@ -30,31 +36,70 @@ pub fn draw_citra_info(reader: &Gen7Reader) { pnp::println!("Time offset: {}", main_rng_seed_context.time_offset_ms); } -pub fn draw_sos(reader: &Gen7Reader, rng: &RngWrapper, slot: u32, correction: u32) { - pnp::println!("SOS Seed: {:08X}", rng.init_seed()); +pub fn draw_sos(reader: &Gen7Reader, rng: &mut RngWrapper, menu_val: usize) -> bool { + let sos_seed: u32 = reader.sos_seed(); + let sos_state: u32 = reader.sos_state(); + let sos_chain: u16 = reader.sos_chain() as u16; + let sos_index: u16 = reader.sos_index(); + + rng.reinit_if_needed(sos_seed); + if sos_index | sos_chain > 0 { + rng.update_advances(sos_state); + } - let sos_index = reader.sos_index(); - pnp::println!("SOS Index: {}", sos_index); + let caller_side = Gen7WildSide::new(menu_val); + let ally_side = caller_side.other(); + let caller_pkm = &reader.read_wild_side(caller_side); + let ally_pkm = &reader.read_wild_side(ally_side); + + if !caller_pkm.is_valid() { + return draw_invalid_pkx(); + } + + pnp::println!("SOS Seed: {:08X}", rng.init_seed()); pnp::println!("SOS Index: {}", rng.advances()); - pnp::println!("SOS Chain Length: {}", reader.sos_chain()); + pnp::println!("SOS Chain Length: {}", sos_chain); + if reader.orb_active() { pnp::println!(color = GREEN, "Orb Active") } else { pnp::println!(color = RED, "Orb Not Active"); } + pnp::println!(""); - pnp::println!("Caller Slot: {}", slot); - let species = &reader.sos_caller_pkm(slot); - let call_rate = lookup_call_rate(species, reader.is_usum()); - pnp::println!( - color = if call_rate == 0 { RED } else { WHITE }, - "Call Rate: {}", - call_rate - ); - print_pp(get_pp(&reader.sos_caller_pkm(slot))); + if caller_pkm.is_valid() { + pnp::println!( + "{} {} ({}):", + caller_pkm.species_t(), + &reader.wild_slot_lookup(caller_side).label(), + caller_side.label() + ); + let call_rate = lookup_call_rate(caller_pkm, reader.is_usum()); + pnp::println!( + color = if call_rate == 0 { RED } else { WHITE }, + "Call Rate: {}", + call_rate + ); + print_pp(get_pp(caller_pkm)); + } else { + return true; + } + pnp::println!(""); - pnp::println!("Ally Data (Slot {}):", reader.ally_slot(slot, correction) + 1); - draw_pkx_brief(&reader.sos_ally_pkm(slot, correction)); + if reader.sos_chain() > 0 { + pnp::println!( + "{} {} ({}):", + ally_pkm.species_t(), + reader.wild_slot_lookup(ally_side).label(), + ally_side.label() + ); + if ally_pkm.is_valid() { + draw_pkx_brief(ally_pkm); + return false; + } + } + pnp::println!("No Ally to display."); + return true; } pub fn draw_daycare(reader: &Gen7Reader) { diff --git a/reader_core/src/gen7/frame.rs b/reader_core/src/gen7/frame.rs index 897fe8d..54cece1 100644 --- a/reader_core/src/gen7/frame.rs +++ b/reader_core/src/gen7/frame.rs @@ -1,6 +1,6 @@ use super::{ draw::{PkxType, draw_citra_info, draw_daycare, draw_header, draw_pkx, draw_rng, draw_sos}, - reader::Gen7Reader, + reader::{Gen7PkmSlot, Gen7Reader}, }; use crate::{ pnp, @@ -10,7 +10,6 @@ use crate::{ help_menu::HelpMenu, menu::{Menu, MenuOption, MenuOptionValue}, sub_menu::SubMenu, - sub_menu_capture::SubMenuCapture, }, }; use once_cell::unsync::Lazy; @@ -53,9 +52,9 @@ struct PersistedState { view: Gen7View, main_menu: Menu<9, Gen7View>, help_menu: HelpMenu, - wild_menu: SubMenu<1, 4>, + wild_menu: SubMenu<1, 5>, party_menu: SubMenu<1, 6>, - sos_menu: SubMenuCapture<1, 4>, + sos_menu: SubMenu<1, 2>, pelago_menu: SubMenu<1, 3>, } @@ -68,20 +67,12 @@ unsafe fn get_state() -> &'static mut PersistedState { party_menu: SubMenu::default(), pelago_menu: SubMenu::default(), wild_menu: SubMenu::default(), - sos_menu: SubMenuCapture::default(), + sos_menu: SubMenu::default(), help_menu: HelpMenu::new(|| { pnp::println!("SOS Controls:"); - pnp::println!("[X] + [Right]:"); - pnp::println!(" Set Caller slot to"); - pnp::println!(" the current ally."); - pnp::println!(" Use this when you"); - pnp::println!(" faint the caller."); - pnp::println!(""); - pnp::println!("[X] + [Up]/[Down]:"); - pnp::println!(" Manually change"); - pnp::println!(" the caller slot."); - pnp::println!(" (Not recommended)"); - pnp::println!(""); + pnp::println!("[X]/[Up]/[Down]:"); + pnp::println!(" - Swap Caller"); + pnp::println!(" Left/Right") }), main_menu: Menu::new([ MenuOption::new(Gen7View::Rng), @@ -104,18 +95,12 @@ fn run_frame(reader: Gen7Reader) { let init_seed: u32 = reader.init_seed(); let sfmt_state: u64 = reader.sfmt_state(); - let sos_seed: u32 = reader.sos_seed(); - let sos_state: u32 = reader.sos_state(); - // This is safe as long as this is guaranteed to run single threaded. // A lock hinders performance too much on a 3ds. let state = unsafe { get_state() }; state.sfmt.reinit_if_needed(init_seed); state.sfmt.update_advances(sfmt_state); - state.sos_sfmt.reinit_if_needed(sos_seed); - state.sos_sfmt.update_advances(sos_state); - if !state.show_view.check() { return; } @@ -128,26 +113,29 @@ fn run_frame(reader: Gen7Reader) { Gen7View::Rng => draw_rng(&reader, &state.sfmt), Gen7View::Daycare => draw_daycare(&reader), Gen7View::WildPokemon => { - let slot = state.wild_menu.update_and_draw(is_locked); - draw_pkx(&reader.wild_pkm((slot - 1) as u32), PkxType::Wild); + let slot = Gen7PkmSlot::new(state.wild_menu.update_headless(is_locked)); + pnp::println!("Slot {}", slot.label()); + pnp::println!("[v] Next | Prev [^]"); + pnp::println!(""); + draw_pkx(&reader.read_wild_slot(slot), PkxType::Wild); } Gen7View::Sos => { - let prev_caller_slot = state.sos_menu.counter_value(); - let prev_correction_value = state.sos_menu.captured_value(); - let caller_slot = state.sos_menu.update_headless( - is_locked, - reader.sos_chain() as u32, - reader.ally_slot(prev_caller_slot as u32, prev_correction_value) as usize + 1, - ); - let correction_value = state.sos_menu.captured_value(); - draw_sos(&reader, &state.sos_sfmt, caller_slot as u32, correction_value); + let caller_side = if pnp::is_just_pressed(pnp::Button::X) { + state.sos_menu.increment() + } else { + state.sos_menu.update_headless(is_locked) + }; + if draw_sos(&reader, &mut state.sos_sfmt, caller_side) { + state.sos_menu.reset(); // Default to right-side caller + } + } Gen7View::Box => { draw_pkx(&reader.box_pkm(), PkxType::Tame); } Gen7View::Citra => draw_citra_info(&reader), Gen7View::Party => { let slot = state.party_menu.update_and_draw(is_locked); - draw_pkx(&reader.party_pkm((slot - 1) as u32), PkxType::Tame); + draw_pkx(&reader.party_pkm(Gen7PkmSlot::new(slot)), PkxType::Tame); } Gen7View::Pelago => { let slot = state.pelago_menu.update_and_draw(is_locked); diff --git a/reader_core/src/gen7/reader.rs b/reader_core/src/gen7/reader.rs index 9d45f12..474bc49 100644 --- a/reader_core/src/gen7/reader.rs +++ b/reader_core/src/gen7/reader.rs @@ -11,9 +11,9 @@ struct Gen7Addresses { sos_sfmt_state: u32, party: u32, wild: u32, - sos: u32, sos_index: u32, sos_chain_length: u32, + sos_battle_table: u32, _prev_call_succeed: u32, orb_active: u32, // To be used in the future vvv @@ -39,9 +39,9 @@ const SM_ADDRESSES: Gen7Addresses = Gen7Addresses { sfmt_state: 0x33195b88, _sos_base_addr: 0x30038C44, sos_sfmt_state: 0x30038C54, + sos_battle_table: 0x30000420, party: 0x34195e10, wild: 0x3002f7b8, - sos: 0x3002f7b8, sos_index: 0x30039614, sos_chain_length: 0x3003960d, _prev_call_succeed: 0x3003961f, @@ -67,9 +67,9 @@ const USUM_ADDRESSES: Gen7Addresses = Gen7Addresses { sfmt_state: 0x330d35d8, _sos_base_addr: 0x30038E20, sos_sfmt_state: 0x30038E30, + sos_battle_table: 0x30000420, party: 0x33f7fa44, wild: 0x3002f9a0, - sos: 0x3002f9a0, sos_index: 0x300397F0, sos_chain_length: 0x300397f9, _prev_call_succeed: 0x300397fb, @@ -94,6 +94,89 @@ pub struct Gen7Reader { addrs: &'static Gen7Addresses, } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Gen7WildSide { + Left, + Right, + Invalid, +} + +impl Gen7WildSide { + pub fn new(value: usize) -> Self { + match value { + 1 => Gen7WildSide::Right, + 2 => Gen7WildSide::Left, + _ => Gen7WildSide::Invalid, + } + } + pub fn other(&self) -> Self { + match self { + Gen7WildSide::Left => Gen7WildSide::Right, + Gen7WildSide::Right => Gen7WildSide::Left, + Gen7WildSide::Invalid => Gen7WildSide::Invalid, + } + } + + pub fn offset(&self) -> Option { + match self { + Gen7WildSide::Left => Some(0x4), + Gen7WildSide::Right => Some(0x0), + Gen7WildSide::Invalid => None, + } + } + + pub fn label(&self) -> &'static str { + match self { + Gen7WildSide::Left => "Left", + Gen7WildSide::Right => "Right", + Gen7WildSide::Invalid => "Invalid", + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Gen7PkmSlot { + A, + B, + C, + D, + E, + Invalid, +} + +impl Gen7PkmSlot { + pub fn new(value: usize) -> Self { + match value { + 1 => Gen7PkmSlot::A, + 2 => Gen7PkmSlot::B, + 3 => Gen7PkmSlot::C, + 4 => Gen7PkmSlot::D, + 5 => Gen7PkmSlot::E, + _ => Gen7PkmSlot::Invalid, + } + } + pub fn offset(&self) -> Option { + match self { + Gen7PkmSlot::A => Some(0x0), + Gen7PkmSlot::B => Some(0x1E4), + Gen7PkmSlot::C => Some(0x3c8), + Gen7PkmSlot::D => Some(0x5ac), + Gen7PkmSlot::E => Some(0x790), + Gen7PkmSlot::Invalid => None, + } + } + pub fn label(&self) -> &'static str { + match self { + Gen7PkmSlot::A => "A", + Gen7PkmSlot::B => "B", + Gen7PkmSlot::C => "C", + Gen7PkmSlot::D => "D", + Gen7PkmSlot::E => "E", + Gen7PkmSlot::Invalid => "Invalid", + } + } +} + impl Gen7Reader { pub fn sm() -> Self { Self { @@ -185,22 +268,42 @@ impl Gen7Reader { pnp::read_bool(self.addrs.orb_active) } - pub fn ally_slot(&self, caller_slot: u32, correction: u32) -> u32 { - if self.sos_chain() == 0 { - 0 - } else { - ((caller_slot - 1) + ((self.sos_chain() as i32 - (correction as i32 + 1)) % 3) as u32 + 1) % 4 + pub fn wild_slot_lookup(&self, side: Gen7WildSide) -> Gen7PkmSlot { + match side.offset() { + Some(offset) => { + let battle_table = self.addrs.sos_battle_table + offset; + let pkx_container_ptr = + pnp::read::(battle_table).clamp(0x30004DA8, 0x30004DA8 + (0x330 * 6)); + Gen7PkmSlot::new( + (((pnp::read::(pkx_container_ptr) + 0x40 - self.addrs.wild) / 484) + 1).clamp(1, 6) + as usize, + ) + } + None => Gen7PkmSlot::Invalid, + } + } + + pub fn read_wild_slot(&self, slot: Gen7PkmSlot) -> Pk7 { + match slot.offset() { + Some(offset) => self.read_pk7(self.addrs.wild + offset), + None => Pk7::default(), } } + pub fn read_wild_side(&self, side: Gen7WildSide) -> Pk7 { + self.read_wild_slot(self.wild_slot_lookup(side)) + } + fn read_pk7(&self, offset: u32) -> Pk7 { let bytes = pnp::read_array::<{ Pk7::STORED_SIZE }>(offset); Pk7::new_valid(bytes) } - pub fn party_pkm(&self, slot: u32) -> Pk7 { - let offset = (slot * 484) + self.addrs.party; - self.read_pk7(offset) + pub fn party_pkm(&self, slot: Gen7PkmSlot) -> Pk7 { + match slot.offset() { + Some(offset) => self.read_pk7(self.addrs.party + offset), + None => Pk7::default(), + } } fn egg_parent(&self, is_present: u32, pkm: u32) -> Option { @@ -222,11 +325,6 @@ impl Gen7Reader { self.egg_parent(self.addrs.is_parent2_occupied, self.addrs.parent2) } - pub fn wild_pkm(&self, slot: u32) -> Pk7 { - let offset = (slot * 484) + self.addrs.wild; - self.read_pk7(offset) - } - pub fn box_pkm(&self) -> Pk7 { self.read_pk7(self.addrs.box_cursor) } @@ -235,13 +333,6 @@ impl Gen7Reader { self.read_pk7((slot * 236) + self.addrs.pelago) } - pub fn sos_caller_pkm(&self, caller_slot: u32) -> Pk7 { - self.read_pk7(((caller_slot - 1) * 484) + self.addrs.sos) - } - pub fn sos_ally_pkm(&self, caller_slot: u32, correction: u32) -> Pk7 { - self.read_pk7((self.ally_slot(caller_slot, correction) * 484) + self.addrs.sos) - } - pub fn is_egg_ready(&self) -> bool { pnp::read_bool(self.addrs.egg_ready) } diff --git a/reader_core/src/utils/circular_counter.rs b/reader_core/src/utils/circular_counter.rs index 3d70b96..82064f8 100644 --- a/reader_core/src/utils/circular_counter.rs +++ b/reader_core/src/utils/circular_counter.rs @@ -14,7 +14,6 @@ impl CircularCounter { } else { self.value += 1; } - self.value } @@ -31,6 +30,10 @@ impl CircularCounter { self.value = value.clamp(MIN, MAX); self.value } + pub fn reset(&mut self) -> usize { + self.value = MIN; + MIN + } } impl Default for CircularCounter { diff --git a/reader_core/src/utils/mod.rs b/reader_core/src/utils/mod.rs index 31bd68a..87d0abd 100644 --- a/reader_core/src/utils/mod.rs +++ b/reader_core/src/utils/mod.rs @@ -9,7 +9,6 @@ mod hook_gen6_seed; pub mod menu; mod show_view; pub mod sub_menu; -pub mod sub_menu_capture; pub use circular_counter::*; pub use daycare::*; diff --git a/reader_core/src/utils/sub_menu.rs b/reader_core/src/utils/sub_menu.rs index f9f0fce..3ab1ee3 100644 --- a/reader_core/src/utils/sub_menu.rs +++ b/reader_core/src/utils/sub_menu.rs @@ -36,4 +36,15 @@ impl SubMenu { self.update_counter(is_locked); self.counter.value() } + + pub fn _set(&mut self, value: usize) -> usize { + self.counter.set(value) + } + + pub fn reset(&mut self) -> usize { + self.counter.reset() + } + pub fn increment(&mut self) -> usize { + self.counter.increment() + } } diff --git a/reader_core/src/utils/sub_menu_capture.rs b/reader_core/src/utils/sub_menu_capture.rs deleted file mode 100644 index 23713c7..0000000 --- a/reader_core/src/utils/sub_menu_capture.rs +++ /dev/null @@ -1,40 +0,0 @@ -use super::CircularCounter; -use crate::pnp; - -#[derive(Default)] -pub struct SubMenuCapture { - counter: CircularCounter, - value: u32, -} - -impl SubMenuCapture { - fn update_counter(&mut self, is_locked: bool, capture_value: u32, set_value: usize) { - if is_locked { - return; - } - - if pnp::is_just_pressed(pnp::Button::Ddown | pnp::Button::X) { - self.counter.increment(); - self.value = capture_value; - } else if pnp::is_just_pressed(pnp::Button::Dup | pnp::Button::X) { - self.counter.decrement(); - self.value = capture_value; - } else if pnp::is_just_pressed(pnp::Button::Dright | pnp::Button::X) { - self.counter.set(set_value); - self.value = capture_value; - } - } - - pub fn update_headless(&mut self, is_locked: bool, capture_value: u32, set_value: usize) -> usize { - self.update_counter(is_locked, capture_value, set_value); - self.counter.value() - } - - pub fn captured_value(&mut self) -> u32 { - self.value - } - - pub fn counter_value(&self) -> usize { - self.counter.value() - } -} From e7055c6e06c16956ffa43d9784800c5931cd84d5 Mon Sep 17 00:00:00 2001 From: serenagrace Date: Sun, 12 Oct 2025 19:04:28 -0500 Subject: [PATCH 29/39] PP Coloration and Color Constants --- reader_core/src/draw.rs | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/reader_core/src/draw.rs b/reader_core/src/draw.rs index 383cbf7..2b2bf7b 100644 --- a/reader_core/src/draw.rs +++ b/reader_core/src/draw.rs @@ -6,9 +6,18 @@ use crate::{pnp, utils::menu::MenuOptionValue}; use pkm_rs::{Nature, Pkx, Shiny}; pub const WHITE: u32 = 0xffffff; -pub const GREEN: u32 = 0x00cc00; pub const RED: u32 = 0xff0000; +pub const MAGMA_RED: u32 = 0xFF4433; +pub const ORANGE: u32 = 0xd75f00; +pub const ULTRA_ORANGE: u32 = 0xff5f1f; +pub const YELLOW: u32 = 0xd7ff00; +pub const GREEN: u32 = 0x00cc00; +pub const CYAN: u32 = 0x00ffff; pub const MUTED_CYAN: u32 = 0x00cccc; +pub const BLUE: u32 = 0x0000ff; +pub const PURPLE: u32 = 0xaf5fff; +pub const ULTRA_PURPLE: u32 = 0xaf00ff; +pub const HOT_PINK: u32 = 0xd7005f; fn get_shiny_color(is_shiny: bool) -> u32 { match is_shiny { @@ -116,21 +125,29 @@ macro_rules! print_stat { } pub fn print_pp(pp: u32) { - pnp::println!(color = if pp > 1 { WHITE } else { RED }, "PP Remaining: {}", pp); + let color = match pp >> 1 { + 1 => RED, + 2 => MAGMA_RED, + 3 => ORANGE, + 4 => ULTRA_ORANGE, + 5 => YELLOW, + _ => WHITE, + }; + pnp::println!(color = color, "PP Remaining: {}", pp); } pub fn print_title() { match loaded_title() { Ok(title) => match title { - LoadedTitle::S => pnp::println!(color = 0xd75f00, " Pokemon Sun"), - LoadedTitle::M => pnp::println!(color = 0xaf5fff, " Pokemon Moon"), - LoadedTitle::Us => pnp::println!(color = 0xff5f1f, " Pokemon Ultra Sun"), - LoadedTitle::Um => pnp::println!(color = 0xaf00ff, " Pokemon Ultra Moon"), - LoadedTitle::X => pnp::println!(color = 0x00ffff, " Pokemon X"), - LoadedTitle::Y => pnp::println!(color = 0xd7005f, " Pokemon Y"), - LoadedTitle::Or => pnp::println!(color = 0xFF4433, " Pokemon Omega Ruby"), - LoadedTitle::As => pnp::println!(color = 0x0000ff, " Pokemon Alpha Sapphire"), - LoadedTitle::Transporter => pnp::println!(color = 0xd7ff00, " Pokemon Transporter"), + LoadedTitle::S => pnp::println!(color = ORANGE, " Pokemon Sun"), + LoadedTitle::M => pnp::println!(color = PURPLE, " Pokemon Moon"), + LoadedTitle::Us => pnp::println!(color = ULTRA_ORANGE, " Pokemon Ultra Sun"), + LoadedTitle::Um => pnp::println!(color = ULTRA_PURPLE, " Pokemon Ultra Moon"), + LoadedTitle::X => pnp::println!(color = CYAN, " Pokemon X"), + LoadedTitle::Y => pnp::println!(color = HOT_PINK, " Pokemon Y"), + LoadedTitle::Or => pnp::println!(color = MAGMA_RED, " Pokemon Omega Ruby"), + LoadedTitle::As => pnp::println!(color = BLUE, " Pokemon Alpha Sapphire"), + LoadedTitle::Transporter => pnp::println!(color = YELLOW, " Pokemon Transporter"), LoadedTitle::CrystalEn | LoadedTitle::CrystalDe | LoadedTitle::CrystalFr From a2c0a5438ee5996c31a8e40809e186b95be5e899 Mon Sep 17 00:00:00 2001 From: serenagrace Date: Sun, 12 Oct 2025 20:14:15 -0500 Subject: [PATCH 30/39] v0.8.2 Tested and Formatted --- reader_core/Cargo.lock | 2 +- reader_core/Cargo.toml | 2 +- reader_core/src/rng/rng_wrapper.rs | 1 - reader_core/src/utils/circular_counter.rs | 4 +++- reader_core/src/utils/sub_menu.rs | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/reader_core/Cargo.lock b/reader_core/Cargo.lock index 75b4a89..a8b2bdd 100644 --- a/reader_core/Cargo.lock +++ b/reader_core/Cargo.lock @@ -133,7 +133,7 @@ dependencies = [ [[package]] name = "pokereader" -version = "0.8.1" +version = "0.8.2" dependencies = [ "binrw 0.14.0", "chrono", diff --git a/reader_core/Cargo.toml b/reader_core/Cargo.toml index 5b03dc2..fcf5cfb 100644 --- a/reader_core/Cargo.toml +++ b/reader_core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pokereader" -version = "0.8.1" +version = "0.8.2" edition = "2021" [dependencies] diff --git a/reader_core/src/rng/rng_wrapper.rs b/reader_core/src/rng/rng_wrapper.rs index 7085c90..dbf1b60 100644 --- a/reader_core/src/rng/rng_wrapper.rs +++ b/reader_core/src/rng/rng_wrapper.rs @@ -37,7 +37,6 @@ impl RngWrapper { self.reinit(seed); return true; } - false } diff --git a/reader_core/src/utils/circular_counter.rs b/reader_core/src/utils/circular_counter.rs index 82064f8..a845f43 100644 --- a/reader_core/src/utils/circular_counter.rs +++ b/reader_core/src/utils/circular_counter.rs @@ -26,10 +26,12 @@ impl CircularCounter { self.value } - pub fn set(&mut self, value: usize) -> usize { + + pub fn _set(&mut self, value: usize) -> usize { self.value = value.clamp(MIN, MAX); self.value } + pub fn reset(&mut self) -> usize { self.value = MIN; MIN diff --git a/reader_core/src/utils/sub_menu.rs b/reader_core/src/utils/sub_menu.rs index 3ab1ee3..897bf82 100644 --- a/reader_core/src/utils/sub_menu.rs +++ b/reader_core/src/utils/sub_menu.rs @@ -38,7 +38,7 @@ impl SubMenu { } pub fn _set(&mut self, value: usize) -> usize { - self.counter.set(value) + self.counter._set(value) } pub fn reset(&mut self) -> usize { From 5742799f3e32e7addfc431fc5ecda799b768977c Mon Sep 17 00:00:00 2001 From: serenagrace Date: Sun, 12 Oct 2025 21:29:19 -0500 Subject: [PATCH 31/39] More strict about hiding SOS Menu --- reader_core/src/gen7/draw.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/reader_core/src/gen7/draw.rs b/reader_core/src/gen7/draw.rs index 278e56d..e29a5d3 100644 --- a/reader_core/src/gen7/draw.rs +++ b/reader_core/src/gen7/draw.rs @@ -43,8 +43,10 @@ pub fn draw_sos(reader: &Gen7Reader, rng: &mut RngWrapper, menu_val: usi let sos_index: u16 = reader.sos_index(); rng.reinit_if_needed(sos_seed); - if sos_index | sos_chain > 0 { - rng.update_advances(sos_state); + if sos_seed > 0 { + if sos_index | sos_chain > 0 { + rng.update_advances(sos_state); + } } let caller_side = Gen7WildSide::new(menu_val); From 8cdb86b969f946e275cf3d2af00d697ff2e8272a Mon Sep 17 00:00:00 2001 From: serenagrace Date: Sun, 12 Oct 2025 21:29:51 -0500 Subject: [PATCH 32/39] Fix slot F & Cleanup constants --- reader_core/src/gen7/reader.rs | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/reader_core/src/gen7/reader.rs b/reader_core/src/gen7/reader.rs index 474bc49..53c9a0d 100644 --- a/reader_core/src/gen7/reader.rs +++ b/reader_core/src/gen7/reader.rs @@ -14,6 +14,7 @@ struct Gen7Addresses { sos_index: u32, sos_chain_length: u32, sos_battle_table: u32, + pkm_container_base: u32, _prev_call_succeed: u32, orb_active: u32, // To be used in the future vvv @@ -31,6 +32,7 @@ struct Gen7Addresses { box_cursor: u32, npc_list: u32, npc_head_blinking_offset: u32, + pk7_data_size: u32, } const SM_ADDRESSES: Gen7Addresses = Gen7Addresses { @@ -40,6 +42,7 @@ const SM_ADDRESSES: Gen7Addresses = Gen7Addresses { _sos_base_addr: 0x30038C44, sos_sfmt_state: 0x30038C54, sos_battle_table: 0x30000420, + pkm_container_base: 0x30004DA8, party: 0x34195e10, wild: 0x3002f7b8, sos_index: 0x30039614, @@ -59,6 +62,7 @@ const SM_ADDRESSES: Gen7Addresses = Gen7Addresses { box_cursor: 0x30000298, npc_list: 0x341977c4, npc_head_blinking_offset: 0x2f4, + pk7_data_size: 0x330, }; const USUM_ADDRESSES: Gen7Addresses = Gen7Addresses { @@ -68,6 +72,7 @@ const USUM_ADDRESSES: Gen7Addresses = Gen7Addresses { _sos_base_addr: 0x30038E20, sos_sfmt_state: 0x30038E30, sos_battle_table: 0x30000420, + pkm_container_base: 0x30004DA8, party: 0x33f7fa44, wild: 0x3002f9a0, sos_index: 0x300397F0, @@ -87,6 +92,7 @@ const USUM_ADDRESSES: Gen7Addresses = Gen7Addresses { box_cursor: 0x30000298, npc_list: 0x33f81438, npc_head_blinking_offset: 0x2fc, + pk7_data_size: 0x330, }; pub struct Gen7Reader { @@ -141,6 +147,7 @@ pub enum Gen7PkmSlot { C, D, E, + F, Invalid, } @@ -152,6 +159,7 @@ impl Gen7PkmSlot { 3 => Gen7PkmSlot::C, 4 => Gen7PkmSlot::D, 5 => Gen7PkmSlot::E, + 6 => Gen7PkmSlot::F, _ => Gen7PkmSlot::Invalid, } } @@ -162,6 +170,7 @@ impl Gen7PkmSlot { Gen7PkmSlot::C => Some(0x3c8), Gen7PkmSlot::D => Some(0x5ac), Gen7PkmSlot::E => Some(0x790), + Gen7PkmSlot::F => Some(0x974), Gen7PkmSlot::Invalid => None, } } @@ -172,6 +181,7 @@ impl Gen7PkmSlot { Gen7PkmSlot::C => "C", Gen7PkmSlot::D => "D", Gen7PkmSlot::E => "E", + Gen7PkmSlot::F => "F", Gen7PkmSlot::Invalid => "Invalid", } } @@ -244,6 +254,7 @@ impl Gen7Reader { hook::sos_seed() } + // We still use this naive check to hint to the RNG wrapper when it can rest. pub fn sos_index(&self) -> u16 { let index = pnp::read(self.addrs.sos_index); if index != 624 { index } else { 0 } @@ -272,11 +283,15 @@ impl Gen7Reader { match side.offset() { Some(offset) => { let battle_table = self.addrs.sos_battle_table + offset; - let pkx_container_ptr = - pnp::read::(battle_table).clamp(0x30004DA8, 0x30004DA8 + (0x330 * 6)); + let pkx_container_ptr = pnp::read::(battle_table).clamp( + self.addrs.pkm_container_base, + self.addrs.pkm_container_base + (self.addrs.pk7_data_size * 6), + ); Gen7PkmSlot::new( - (((pnp::read::(pkx_container_ptr) + 0x40 - self.addrs.wild) / 484) + 1).clamp(1, 6) - as usize, + (((pnp::read::(pkx_container_ptr) + 0x40 - self.addrs.wild) + / self.addrs.pk7_data_size) + + 1) + .clamp(1, 6) as usize, ) } None => Gen7PkmSlot::Invalid, From 51e87a89ae265e56bb0951b9dbe015feeccce1ae Mon Sep 17 00:00:00 2001 From: Serena Belveal <57582123+serenagrace@users.noreply.github.com> Date: Mon, 13 Oct 2025 10:27:08 -0500 Subject: [PATCH 33/39] Fixed SOS RNG Hook for SM --- reader_core/src/gen7/hook.rs | 15 +++++++++++---- reader_core/src/gen7/reader.rs | 4 ++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/reader_core/src/gen7/hook.rs b/reader_core/src/gen7/hook.rs index 4a3049e..d849a40 100644 --- a/reader_core/src/gen7/hook.rs +++ b/reader_core/src/gen7/hook.rs @@ -1,5 +1,6 @@ use crate::{pnp, utils}; use chrono::NaiveDateTime; +use super::reader::{SM_ADDRESSES, USUM_ADDRESSES}; static mut MAIN_RNG_SEED_TICKS: u32 = 0; static mut MAIN_RNG_TIME_OFFSET_MS: u64 = 0; static mut GAME_START_DATE_TIME: NaiveDateTime = NaiveDateTime::MIN; @@ -9,8 +10,14 @@ pub fn sos_seed() -> u32 { unsafe { SOS_SEED } } -fn init_sfmt_hook(regs: &[u32], _stack_pointer: *mut u32) { - if regs[0] == 0x30038e30 { +fn init_sm_sfmt_hook(regs: &[u32], _stack_pointer: *mut u32) { + if regs[0] == SM_ADDRESSES.sos_sfmt_state { + unsafe { SOS_SEED = regs[1] }; + } +} + +fn init_ussm_sfmt_hook(regs: &[u32], _stack_pointer: *mut u32) { + if regs[0] == USSM_ADDRESSES.sos_sfmt_state { unsafe { SOS_SEED = regs[1] }; } } @@ -62,7 +69,7 @@ pub fn init_um() { pub fn init_us() { utils::hook_game_branch! { game_name = us, - init_sfmt_hook = 0x361e60, + init_usum_sfmt_hook = 0x361e60, init_main_rng_hook = 0x3fcbbc, } } @@ -70,7 +77,7 @@ pub fn init_us() { pub fn init_sm() { utils::hook_game_branch! { game_name = sm, - init_sfmt_hook = 0x359784, + init_sm_fmt_hook = 0x359784, init_main_rng_hook = 0x3eab60, } } diff --git a/reader_core/src/gen7/reader.rs b/reader_core/src/gen7/reader.rs index 53c9a0d..d9d0adf 100644 --- a/reader_core/src/gen7/reader.rs +++ b/reader_core/src/gen7/reader.rs @@ -35,7 +35,7 @@ struct Gen7Addresses { pk7_data_size: u32, } -const SM_ADDRESSES: Gen7Addresses = Gen7Addresses { +pub const SM_ADDRESSES: Gen7Addresses = Gen7Addresses { initial_seed: 0x325a3878, sfmt_state_index: 0x33196548, sfmt_state: 0x33195b88, @@ -65,7 +65,7 @@ const SM_ADDRESSES: Gen7Addresses = Gen7Addresses { pk7_data_size: 0x330, }; -const USUM_ADDRESSES: Gen7Addresses = Gen7Addresses { +pub const USUM_ADDRESSES: Gen7Addresses = Gen7Addresses { initial_seed: 0x32663bf0, sfmt_state_index: 0x330d3f98, sfmt_state: 0x330d35d8, From 7e321b0899d05743e29f6e7af0b5a35ade244e8c Mon Sep 17 00:00:00 2001 From: serenagrace Date: Mon, 13 Oct 2025 18:25:32 -0500 Subject: [PATCH 34/39] Make draw_brief more brief - (hidden power and species are still in wild view) --- reader_core/src/draw.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/reader_core/src/draw.rs b/reader_core/src/draw.rs index 02c2440..f597426 100644 --- a/reader_core/src/draw.rs +++ b/reader_core/src/draw.rs @@ -174,7 +174,6 @@ pub fn draw_pkx_brief(pkx: &impl Pkx) -> bool { if !pkx.is_valid() { return draw_invalid_pkx(); } - let species = pkx.species_t().to_string(); let ability = pkx.ability_t().to_string(); let shiny_type = shiny_type(pkx); @@ -188,11 +187,10 @@ pub fn draw_pkx_brief(pkx: &impl Pkx) -> bool { let nature = pkx.nature_t(); - pnp::println!("{} {}", nature, species); pnp::println!("Ability: ({}) {}", pkx.ability_number_t(), ability); pnp::println!("PID: {:08X}", pkx.pid()); pnp::println!(color = shiny_color, "PSV: {:04}, {}", pkx.psv(), shiny_type); - pnp::println!("HPower: {}", pkx.hidden_power_t()); + pnp::println!("Nature: {}", nature); pnp::println!( "IVs: {}/{}/{}/{}/{}/{}", iv_hp, From 0a2ba6d7a0ed602892bd61c324689ccc0f440c4f Mon Sep 17 00:00:00 2001 From: serenagrace Date: Mon, 13 Oct 2025 18:26:29 -0500 Subject: [PATCH 35/39] Add main rng advances to SOS --- reader_core/src/gen7/draw.rs | 21 ++++++++++++++------- reader_core/src/gen7/frame.rs | 2 +- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/reader_core/src/gen7/draw.rs b/reader_core/src/gen7/draw.rs index e29a5d3..b7dcc1c 100644 --- a/reader_core/src/gen7/draw.rs +++ b/reader_core/src/gen7/draw.rs @@ -36,16 +36,21 @@ pub fn draw_citra_info(reader: &Gen7Reader) { pnp::println!("Time offset: {}", main_rng_seed_context.time_offset_ms); } -pub fn draw_sos(reader: &Gen7Reader, rng: &mut RngWrapper, menu_val: usize) -> bool { +pub fn draw_sos( + reader: &Gen7Reader, + main_rng: &mut RngWrapper, + sos_rng: &mut RngWrapper, + menu_val: usize, +) -> bool { let sos_seed: u32 = reader.sos_seed(); let sos_state: u32 = reader.sos_state(); let sos_chain: u16 = reader.sos_chain() as u16; let sos_index: u16 = reader.sos_index(); - rng.reinit_if_needed(sos_seed); + sos_rng.reinit_if_needed(sos_seed); if sos_seed > 0 { if sos_index | sos_chain > 0 { - rng.update_advances(sos_state); + sos_rng.update_advances(sos_state); } } @@ -58,16 +63,18 @@ pub fn draw_sos(reader: &Gen7Reader, rng: &mut RngWrapper, menu_val: usi return draw_invalid_pkx(); } - pnp::println!("SOS Seed: {:08X}", rng.init_seed()); - pnp::println!("SOS Index: {}", rng.advances()); + pnp::println!("SOS Seed: {:08X}", sos_rng.init_seed()); + pnp::println!("SOS Index: {}", sos_rng.advances()); pnp::println!("SOS Chain Length: {}", sos_chain); if reader.orb_active() { - pnp::println!(color = GREEN, "Orb Active") + pnp::println!(color = GREEN, "Orb Active"); } else { - pnp::println!(color = RED, "Orb Not Active"); + pnp::println!(color = RED, "Orb Not Active!"); } + pnp::println!("RNG Frame: {}", main_rng.advances()); + pnp::println!(""); if caller_pkm.is_valid() { pnp::println!( diff --git a/reader_core/src/gen7/frame.rs b/reader_core/src/gen7/frame.rs index 54cece1..59cde7d 100644 --- a/reader_core/src/gen7/frame.rs +++ b/reader_core/src/gen7/frame.rs @@ -125,7 +125,7 @@ fn run_frame(reader: Gen7Reader) { } else { state.sos_menu.update_headless(is_locked) }; - if draw_sos(&reader, &mut state.sos_sfmt, caller_side) { + if draw_sos(&reader, &mut state.sfmt, &mut state.sos_sfmt, caller_side) { state.sos_menu.reset(); // Default to right-side caller } } From 8343276199e30f837c12fcdfa2fb7ab3b43886b6 Mon Sep 17 00:00:00 2001 From: serenagrace Date: Mon, 13 Oct 2025 18:28:12 -0500 Subject: [PATCH 36/39] Cleanup constants and fix hooks --- reader_core/src/gen7/hook.rs | 12 +++---- reader_core/src/gen7/reader.rs | 58 ++++++++++++++++++---------------- 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/reader_core/src/gen7/hook.rs b/reader_core/src/gen7/hook.rs index d849a40..8f90937 100644 --- a/reader_core/src/gen7/hook.rs +++ b/reader_core/src/gen7/hook.rs @@ -1,6 +1,6 @@ +use super::reader::{SM_SOS_SFMT_ADDR, USUM_SOS_SFMT_ADDR}; use crate::{pnp, utils}; use chrono::NaiveDateTime; -use super::reader::{SM_ADDRESSES, USUM_ADDRESSES}; static mut MAIN_RNG_SEED_TICKS: u32 = 0; static mut MAIN_RNG_TIME_OFFSET_MS: u64 = 0; static mut GAME_START_DATE_TIME: NaiveDateTime = NaiveDateTime::MIN; @@ -11,13 +11,13 @@ pub fn sos_seed() -> u32 { } fn init_sm_sfmt_hook(regs: &[u32], _stack_pointer: *mut u32) { - if regs[0] == SM_ADDRESSES.sos_sfmt_state { + if regs[0] == SM_SOS_SFMT_ADDR { unsafe { SOS_SEED = regs[1] }; } } -fn init_ussm_sfmt_hook(regs: &[u32], _stack_pointer: *mut u32) { - if regs[0] == USSM_ADDRESSES.sos_sfmt_state { +fn init_usum_sfmt_hook(regs: &[u32], _stack_pointer: *mut u32) { + if regs[0] == USUM_SOS_SFMT_ADDR { unsafe { SOS_SEED = regs[1] }; } } @@ -61,7 +61,7 @@ fn init_main_rng_hook(_regs: &[u32], stack_pointer: *mut u32) { pub fn init_um() { utils::hook_game_branch! { game_name = um, - init_sfmt_hook = 0x361e60, + init_usum_sfmt_hook = 0x361e60, init_main_rng_hook = 0x3fcbc0, } } @@ -77,7 +77,7 @@ pub fn init_us() { pub fn init_sm() { utils::hook_game_branch! { game_name = sm, - init_sm_fmt_hook = 0x359784, + init_sm_sfmt_hook = 0x359784, init_main_rng_hook = 0x3eab60, } } diff --git a/reader_core/src/gen7/reader.rs b/reader_core/src/gen7/reader.rs index d9d0adf..6163354 100644 --- a/reader_core/src/gen7/reader.rs +++ b/reader_core/src/gen7/reader.rs @@ -3,6 +3,13 @@ use crate::pnp; use core::num::{NonZeroU8, NonZeroU32}; use pkm_rs::{Pk7, PokeCrypto}; +pub const SM_SOS_BASE_ADDR: u32 = 0x30038c34; +pub const USUM_SOS_BASE_ADDR: u32 = 0x30038e20; +pub const SM_SOS_SFMT_ADDR: u32 = SM_SOS_BASE_ADDR + 0x10; +pub const USUM_SOS_SFMT_ADDR: u32 = USUM_SOS_BASE_ADDR + 0x10; +pub const PKM_CONT_SIZE: u32 = 0x330; +pub const PK7_DATA_SIZE: u32 = 0x1E4; + struct Gen7Addresses { initial_seed: u32, sfmt_state_index: u32, @@ -12,13 +19,13 @@ struct Gen7Addresses { party: u32, wild: u32, sos_index: u32, - sos_chain_length: u32, + sos_chain_len: u32, sos_battle_table: u32, pkm_container_base: u32, - _prev_call_succeed: u32, + _sos_call_succeed: u32, orb_active: u32, // To be used in the future vvv - _ally_id: u32, + _sos_ally_id: u32, // pelago: u32, egg_ready: u32, @@ -32,24 +39,23 @@ struct Gen7Addresses { box_cursor: u32, npc_list: u32, npc_head_blinking_offset: u32, - pk7_data_size: u32, } -pub const SM_ADDRESSES: Gen7Addresses = Gen7Addresses { +const SM_ADDRESSES: Gen7Addresses = Gen7Addresses { initial_seed: 0x325a3878, sfmt_state_index: 0x33196548, sfmt_state: 0x33195b88, - _sos_base_addr: 0x30038C44, - sos_sfmt_state: 0x30038C54, + _sos_base_addr: 0x30038C34, + sos_sfmt_state: SM_SOS_SFMT_ADDR, sos_battle_table: 0x30000420, pkm_container_base: 0x30004DA8, party: 0x34195e10, wild: 0x3002f7b8, - sos_index: 0x30039614, - sos_chain_length: 0x3003960d, - _prev_call_succeed: 0x3003961f, - orb_active: 0x3003961c, - _ally_id: 0x3003961e, + sos_index: SM_SOS_BASE_ADDR + 0x9d0, + orb_active: SM_SOS_BASE_ADDR + 0x9d8, + sos_chain_len: SM_SOS_BASE_ADDR + 0x9d9, + _sos_ally_id: SM_SOS_BASE_ADDR + 0x9da, + _sos_call_succeed: SM_SOS_BASE_ADDR + 0x9db, pelago: 0x331110ca, egg_ready: 0x3313edd8, egg: 0x3313eddc, @@ -62,24 +68,23 @@ pub const SM_ADDRESSES: Gen7Addresses = Gen7Addresses { box_cursor: 0x30000298, npc_list: 0x341977c4, npc_head_blinking_offset: 0x2f4, - pk7_data_size: 0x330, }; -pub const USUM_ADDRESSES: Gen7Addresses = Gen7Addresses { +const USUM_ADDRESSES: Gen7Addresses = Gen7Addresses { initial_seed: 0x32663bf0, sfmt_state_index: 0x330d3f98, sfmt_state: 0x330d35d8, _sos_base_addr: 0x30038E20, - sos_sfmt_state: 0x30038E30, + sos_sfmt_state: USUM_SOS_SFMT_ADDR, sos_battle_table: 0x30000420, pkm_container_base: 0x30004DA8, party: 0x33f7fa44, wild: 0x3002f9a0, - sos_index: 0x300397F0, - sos_chain_length: 0x300397f9, - _prev_call_succeed: 0x300397fb, - orb_active: 0x300397f8, - _ally_id: 0x300397fA, + sos_index: USUM_SOS_BASE_ADDR + 0x9d0, + orb_active: USUM_SOS_BASE_ADDR + 0x9d8, + sos_chain_len: USUM_SOS_BASE_ADDR + 0x9d9, + _sos_ally_id: USUM_SOS_BASE_ADDR + 0x9da, + _sos_call_succeed: USUM_SOS_BASE_ADDR + 0x9db, pelago: 0x3304d16a, egg_ready: 0x3307b1e8, egg: 0x3307b1ec, @@ -92,7 +97,6 @@ pub const USUM_ADDRESSES: Gen7Addresses = Gen7Addresses { box_cursor: 0x30000298, npc_list: 0x33f81438, npc_head_blinking_offset: 0x2fc, - pk7_data_size: 0x330, }; pub struct Gen7Reader { @@ -268,11 +272,11 @@ impl Gen7Reader { * Value does not update until after last * input, which makes it rather misleading. */ pub fn _sos_prevcall(&self) -> bool { - pnp::read_bool(self.addrs._prev_call_succeed) + pnp::read_bool(self.addrs._sos_call_succeed) } pub fn sos_chain(&self) -> u8 { - pnp::read(self.addrs.sos_chain_length) + pnp::read(self.addrs.sos_chain_len) } pub fn orb_active(&self) -> bool { @@ -285,13 +289,11 @@ impl Gen7Reader { let battle_table = self.addrs.sos_battle_table + offset; let pkx_container_ptr = pnp::read::(battle_table).clamp( self.addrs.pkm_container_base, - self.addrs.pkm_container_base + (self.addrs.pk7_data_size * 6), + self.addrs.pkm_container_base + (PKM_CONT_SIZE * 6), ); Gen7PkmSlot::new( - (((pnp::read::(pkx_container_ptr) + 0x40 - self.addrs.wild) - / self.addrs.pk7_data_size) - + 1) - .clamp(1, 6) as usize, + (((pnp::read::(pkx_container_ptr) + 0x40 - self.addrs.wild) / PK7_DATA_SIZE) + 1) + .clamp(1, 6) as usize, ) } None => Gen7PkmSlot::Invalid, From cffaa3ecf08788270d0279dab7021c88e6e65bc7 Mon Sep 17 00:00:00 2001 From: serenagrace Date: Mon, 13 Oct 2025 18:29:16 -0500 Subject: [PATCH 37/39] correct rng test suite and sfmt64 index bug --- reader_core/src/rng/rng_wrapper.rs | 6 +++--- reader_core/src/rng/sfmt.rs | 11 +++++------ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/reader_core/src/rng/rng_wrapper.rs b/reader_core/src/rng/rng_wrapper.rs index dbf1b60..5cd833e 100644 --- a/reader_core/src/rng/rng_wrapper.rs +++ b/reader_core/src/rng/rng_wrapper.rs @@ -63,19 +63,19 @@ impl RngWrapper { #[cfg(test)] mod test { use super::*; - use crate::rng::{MT, Rng, Sfmt, TinyMT}; + use crate::rng::{MT, Rng, Sfmt32, Sfmt64, TinyMT}; #[test] fn should_track_sfmt_advances() { let seed = 0x92845c35; - let mut rng = Sfmt::new(seed); + let mut rng = Sfmt64::new(seed); for _ in 0..478 { rng.next_state(); } assert_eq!(rng.current_state(), 0x5a1ef513d10eccfb); - let mut wrapper = RngWrapper::::default(); + let mut wrapper = RngWrapper::::default(); wrapper.reinit(seed); wrapper.update_advances(rng.current_state()); assert_eq!(wrapper.advances(), 478); diff --git a/reader_core/src/rng/sfmt.rs b/reader_core/src/rng/sfmt.rs index 7c4c057..3b60154 100644 --- a/reader_core/src/rng/sfmt.rs +++ b/reader_core/src/rng/sfmt.rs @@ -37,13 +37,13 @@ impl Sfmt32 { } fn get_current_state(&self) -> u32 { - let index = if self.index != 624 { self.index } else { 0 }; + let index = (self.index) % 624; self.sfmt[index] } fn get_next_state(&self) -> u32 { - let index = if self.index != 624 { self.index } else { 0 }; - self.sfmt[index + 1] + let index = (self.index + 1) % 624; + self.sfmt[index] } pub fn next(&mut self) -> u32 { @@ -52,7 +52,6 @@ impl Sfmt32 { } self.index += 1; - self.get_current_state() } @@ -180,7 +179,7 @@ mod test { #[test] fn test_shuffle() { - let mut rng = Sfmt::new(0x7725e5e1); + let mut rng = Sfmt64::new(0x7725e5e1); for _ in 0..1000 { rng.next(); } @@ -191,7 +190,7 @@ mod test { #[test] fn test_next_should_return_state_before_shuffle() { - let mut rng = Sfmt::new(0xc91cc389); + let mut rng = Sfmt64::new(0xc91cc389); for _ in 0..624 { rng.next(); } From d801ed1a9a238ba45a151dd34c06b78c423b8b09 Mon Sep 17 00:00:00 2001 From: serenagrace Date: Mon, 13 Oct 2025 18:57:30 -0500 Subject: [PATCH 38/39] SFMT Panic semantics --- reader_core/src/rng/sfmt.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/reader_core/src/rng/sfmt.rs b/reader_core/src/rng/sfmt.rs index 3b60154..d705fcc 100644 --- a/reader_core/src/rng/sfmt.rs +++ b/reader_core/src/rng/sfmt.rs @@ -37,11 +37,15 @@ impl Sfmt32 { } fn get_current_state(&self) -> u32 { - let index = (self.index) % 624; + // sgrace: I think it's better to panic if this overflows, + // As index > 624 should never naturally occur. + let index = if self.index == 624 { 0 } else { self.index }; self.sfmt[index] } fn get_next_state(&self) -> u32 { + // sgrace: This one, however, can naturally overflow + // in Sfmt64 at index = 0, so handle that. let index = (self.index + 1) % 624; self.sfmt[index] } From 5efec80844c9626217823505128a59c6a67af720 Mon Sep 17 00:00:00 2001 From: serenagrace Date: Mon, 13 Oct 2025 19:16:55 -0500 Subject: [PATCH 39/39] PP indicator correction --- reader_core/src/draw.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/reader_core/src/draw.rs b/reader_core/src/draw.rs index f597426..97db45a 100644 --- a/reader_core/src/draw.rs +++ b/reader_core/src/draw.rs @@ -126,11 +126,11 @@ macro_rules! print_stat { pub fn print_pp(pp: u32) { let color = match pp >> 1 { - 1 => RED, - 2 => MAGMA_RED, - 3 => ORANGE, - 4 => ULTRA_ORANGE, - 5 => YELLOW, + 0 => RED, + 1 => MAGMA_RED, + 2 => ORANGE, + 3 => ULTRA_ORANGE, + 4 => YELLOW, _ => WHITE, }; pnp::println!(color = color, "PP Remaining: {}", pp);