diff --git a/src/hollow_knight_memory.rs b/src/hollow_knight_memory.rs index 65165c86..3a7c184b 100644 --- a/src/hollow_knight_memory.rs +++ b/src/hollow_knight_memory.rs @@ -201,11 +201,13 @@ struct GameManagerPointers { camera_target_destination: UnityPointer<4>, accepting_input: UnityPointer<3>, tile_map_dirty: UnityPointer<2>, + on_ground: UnityPointer<4>, hero_dead: UnityPointer<4>, hazard_death: UnityPointer<4>, hazard_respawning: UnityPointer<4>, hero_recoiling: UnityPointer<4>, hero_recoil_frozen: UnityPointer<4>, + spell_quake: UnityPointer<4>, hero_transition_state: UnityPointer<3>, focusing: UnityPointer<4>, } @@ -224,11 +226,13 @@ impl GameManagerPointers { camera_target_destination: UnityPointer::new("GameManager", 0, &["_instance", "k__BackingField", "camTarget", "destination"]), accepting_input: UnityPointer::new("GameManager", 0, &["_instance", "k__BackingField", "acceptingInput"]), tile_map_dirty: UnityPointer::new("GameManager", 0, &["_instance", "tilemapDirty"]), + on_ground: UnityPointer::new("GameManager", 0, &["_instance", "k__BackingField", "cState", "onGround"]), hero_dead: UnityPointer::new("GameManager", 0, &["_instance", "k__BackingField", "cState", "dead"]), hazard_death: UnityPointer::new("GameManager", 0, &["_instance", "k__BackingField", "cState", "hazardDeath"]), hazard_respawning: UnityPointer::new("GameManager", 0, &["_instance", "k__BackingField", "cState", "hazardRespawning"]), hero_recoiling: UnityPointer::new("GameManager", 0, &["_instance", "k__BackingField", "cState", "recoiling"]), hero_recoil_frozen: UnityPointer::new("GameManager", 0, &["_instance", "k__BackingField", "cState", "recoilFrozen"]), + spell_quake: UnityPointer::new("GameManager", 0, &["_instance", "k__BackingField", "cState", "spellQuake"]), hero_transition_state: UnityPointer::new("GameManager", 0, &["_instance", "k__BackingField", "transitionState"]), focusing: UnityPointer::new("GameManager", 0, &["_instance", "k__BackingField", "cState", "focusing"]), } @@ -442,6 +446,8 @@ struct PlayerDataPointers { killed_false_knight: UnityPointer<3>, false_knight_dream_defeated: UnityPointer<3>, false_knight_orbs_collected: UnityPointer<3>, + kills_prayer_slug: UnityPointer<3>, + kills_roller: UnityPointer<3>, salubra_blessing: UnityPointer<3>, unchained_hollow_knight: UnityPointer<3>, killed_hollow_knight: UnityPointer<3>, @@ -806,6 +812,8 @@ impl PlayerDataPointers { killed_false_knight: UnityPointer::new("GameManager", 0, &["_instance", "playerData", "killedFalseKnight"]), false_knight_dream_defeated: UnityPointer::new("GameManager", 0, &["_instance", "playerData", "falseKnightDreamDefeated"]), false_knight_orbs_collected: UnityPointer::new("GameManager", 0, &["_instance", "playerData", "falseKnightOrbsCollected"]), + kills_prayer_slug: UnityPointer::new("GameManager", 0, &["_instance", "playerData", "killsPrayerSlug"]), + kills_roller: UnityPointer::new("GameManager", 0, &["_instance", "playerData", "killsRoller"]), salubra_blessing: UnityPointer::new("GameManager", 0, &["_instance", "playerData", "salubraBlessing"]), unchained_hollow_knight: UnityPointer::new("GameManager", 0, &["_instance", "playerData", "unchainedHollowKnight"]), killed_hollow_knight: UnityPointer::new("GameManager", 0, &["_instance", "playerData", "killedHollowKnight"]), @@ -1228,6 +1236,10 @@ impl GameManagerFinder { Some(*self.get_version_vec(process)?.get(VERSION_VEC_MINOR)? >= 3) } + pub fn on_ground(&self, process: &Process) -> Option { + self.pointers.on_ground.deref(process, &self.module, &self.image).ok() + } + pub fn hero_dead(&self, process: &Process) -> Option { self.pointers.hero_dead.deref(process, &self.module, &self.image).ok() } @@ -1256,6 +1268,10 @@ impl GameManagerFinder { Some(maybe_recoil_frozen? || maybe_recoiling?) } + pub fn spell_quake(&self, process: &Process) -> Option { + self.pointers.spell_quake.deref(process, &self.module, &self.image).ok() + } + pub fn get_version_string(&self, process: &Process) -> Option { let s: Address = [&self.pointers.version_number, &self.player_data_pointers.version].into_iter().find_map(|ptr| { self.deref_pointer(process, ptr).ok() @@ -1971,6 +1987,16 @@ impl GameManagerFinder { self.player_data_pointers.false_knight_orbs_collected.deref(process, &self.module, &self.image).ok() } + /// killsPrayerSlug: Kills Maggot + pub fn kills_prayer_slug(&self, process: &Process) -> Option { + self.player_data_pointers.kills_prayer_slug.deref(process, &self.module, &self.image).ok() + } + + /// killsRoller: Kills Little Baldur + pub fn kills_roller(&self, process: &Process) -> Option { + self.player_data_pointers.kills_roller.deref(process, &self.module, &self.image).ok() + } + pub fn salubra_blessing(&self, process: &Process) -> Option { self.player_data_pointers.salubra_blessing.deref(process, &self.module, &self.image).ok() } diff --git a/src/splits.rs b/src/splits.rs index d5f86553..4afce506 100644 --- a/src/splits.rs +++ b/src/splits.rs @@ -1766,10 +1766,18 @@ pub enum Split { /// /// Splits when getting Failed Champion essence FailedChampionEssence, + /// Maggots (Killed) + /// + /// Splits when killing both Maggots + Maggots, /// Ancestral Mound (Transition) /// /// Splits on transition into Ancestral Mound AncestralMound, + /// Little Baldur Hunter's Notes (Killed) + /// + /// Splits when killing all little Baldurs needed for Hunter's Notes journal completion + RollerHuntersNotes, /// Salubra's Blessing (Item) /// /// Splits when obtaining Salubra's Blessing @@ -2341,6 +2349,10 @@ pub enum Split { /// /// Splits on transition to the fourth room in PoP (Final room) PathOfPainTransition3, + /// Path of Pain Room 4 DDark (Event) + /// + /// Splits on landing with Descending Dark in fourth room of PoP + PathOfPainRoom4DDark, /// Path of Pain (Completed) /// /// Splits when completing the Path of Pain in White Palace @@ -3946,6 +3958,8 @@ pub fn continuous_splits(s: &Split, p: &Process, g: &GameManagerFinder, pds: &mu Split::FalseKnight => should_split(g.killed_false_knight(p).is_some_and(|k| k)), Split::FailedKnight => should_split(g.false_knight_dream_defeated(p).is_some_and(|k| k)), Split::FailedChampionEssence => should_split(g.false_knight_orbs_collected(p).is_some_and(|o| o)), + Split::Maggots => should_split(g.kills_prayer_slug(p).is_some_and(|k| k == 0)), + Split::RollerHuntersNotes => should_split(g.kills_roller(p).is_some_and(|k| k == 0)), Split::SalubrasBlessing => should_split(g.salubra_blessing(p).is_some_and(|b| b)), // the award for the most miscellaneous split goes to this one probably Split::PureSnail => should_split(pds.pure_snail(p, g)), @@ -4074,6 +4088,9 @@ pub fn continuous_splits(s: &Split, p: &Process, g: &GameManagerFinder, pds: &mu Split::WhitePalaceOrb1 => should_split(g.white_palace_orb_1(p).is_some_and(|o| o)), Split::WhitePalaceOrb3 => should_split(g.white_palace_orb_3(p).is_some_and(|o| o)), Split::WhitePalaceOrb2 => should_split(g.white_palace_orb_2(p).is_some_and(|o| o)), + Split::PathOfPainRoom4DDark => should_split(g.get_scene_name(p).is_some_and(|s| s.starts_with("White_Palace_20")) + && g.on_ground(p).is_some_and(|b| b) + && g.spell_quake(p).is_some_and(|b| b)), Split::PathOfPain => should_split(g.new_data_binding_seal(p).is_some_and(|n| n)), Split::WhitePalaceSecretRoom => should_split(g.white_palace_secret_room_visited(p).is_some_and(|v| v)), // endregion: White Palace