From 28a3f160c3dc7fe2dca4cf1713a492fb58cc3156 Mon Sep 17 00:00:00 2001 From: dawnDus <96957561+dawndus@users.noreply.github.com> Date: Wed, 20 Apr 2022 08:07:27 -0400 Subject: [PATCH] RNG Tweaks --- src/components/replay.rs | 20 ++++++++++++++------ src/npc/ai/sand_zone.rs | 12 ++---------- src/npc/boss/mod.rs | 10 ++++++---- src/npc/boss/monster_x.rs | 13 +++---------- src/npc/list.rs | 26 ++++++++++++-------------- src/npc/utils.rs | 3 ++- src/scene/game_scene.rs | 24 ++++++++++-------------- src/shared_game_state.rs | 4 ++-- 8 files changed, 51 insertions(+), 61 deletions(-) diff --git a/src/components/replay.rs b/src/components/replay.rs index 4e61235..98a705a 100644 --- a/src/components/replay.rs +++ b/src/components/replay.rs @@ -22,6 +22,7 @@ pub struct Replay { pub controller: ReplayController, tick: usize, resume_tick: usize, + is_active: bool, } impl Replay { @@ -34,11 +35,15 @@ impl Replay { controller: ReplayController::new(), tick: 0, resume_tick: 0, + is_active: false, } } - pub fn start_recording(&mut self, state: &mut SharedGameState) { - self.rng_seed = state.game_rng.dump_state(); + pub fn initialize_recording(&mut self, state: &mut SharedGameState) { + if !self.is_active { + self.rng_seed = state.game_rng.dump_state(); + self.is_active = true; + } } pub fn stop_recording(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { @@ -47,10 +52,13 @@ impl Replay { Ok(()) } - pub fn start_playback(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { - state.replay_state = ReplayState::Playback; - self.read_replay(state, ctx)?; - state.game_rng.load_state(self.rng_seed); + pub fn initialize_playback(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { + if !self.is_active { + state.replay_state = ReplayState::Playback; + self.read_replay(state, ctx)?; + state.game_rng.load_state(self.rng_seed); + self.is_active = true; + } Ok(()) } diff --git a/src/npc/ai/sand_zone.rs b/src/npc/ai/sand_zone.rs index 6fed0a0..3244ce9 100644 --- a/src/npc/ai/sand_zone.rs +++ b/src/npc/ai/sand_zone.rs @@ -927,11 +927,7 @@ impl NPC { && self.y - 0x4000 < player.y && self.y + 0x2000 > player.y { - if self.x <= player.x { - self.direction = Direction::Right; - } else { - self.direction = Direction::Left; - } + self.face_player(player); } } 2 => { @@ -963,11 +959,7 @@ impl NPC { let player = self.get_closest_player_mut(players); - if self.x <= player.x { - self.direction = Direction::Right; - } else { - self.direction = Direction::Left; - } + self.face_player(player); } self.animate(2, 2, 5); diff --git a/src/npc/boss/mod.rs b/src/npc/boss/mod.rs index 4b01aee..612c8eb 100644 --- a/src/npc/boss/mod.rs +++ b/src/npc/boss/mod.rs @@ -46,9 +46,13 @@ impl BossNPC { parts[0].cond.set_alive(true); - for (i, part) in parts.iter_mut().enumerate() { + BossNPC { boss_type: 0, parts, hurt_sound: [0; 20], death_sound: [0; 20] } + } + + pub fn init_rng(&mut self, seed: i32) { + for (i, part) in self.parts.iter_mut().enumerate() { part.rng.load_state( - ((i as u32) + ((seed.abs() as u32 + i as u32) .wrapping_add(3271284409) .rotate_left(5) .wrapping_mul(3815776271) @@ -57,8 +61,6 @@ impl BossNPC { & 0xffffffff) as u32, ); } - - BossNPC { boss_type: 0, parts, hurt_sound: [0; 20], death_sound: [0; 20] } } } diff --git a/src/npc/boss/monster_x.rs b/src/npc/boss/monster_x.rs index be808b1..8512d4e 100644 --- a/src/npc/boss/monster_x.rs +++ b/src/npc/boss/monster_x.rs @@ -175,8 +175,7 @@ impl BossNPC { self.parts[3].life = 60; self.parts[3].size = 2; self.parts[3].target_x = 0; - self.parts[3].display_bounds = - Rect { left: 0x1000, top: 0x1000, right: 0x1000, bottom: 0x1000 }; + self.parts[3].display_bounds = Rect { left: 0x1000, top: 0x1000, right: 0x1000, bottom: 0x1000 }; self.parts[3].hit_bounds = Rect { left: 5 * 0x200, top: 5 * 0x200, right: 5 * 0x200, bottom: 5 * 0x200 }; self.parts[3].npc_flags.set_ignore_solidity(true); @@ -200,8 +199,7 @@ impl BossNPC { self.parts[7].anim_num = 0; self.parts[7].display_bounds = Rect { left: 52 * 0x200, top: 24 * 0x200, right: 52 * 0x200, bottom: 24 * 0x200 }; - self.parts[7].hit_bounds = - Rect { left: 0x1000, top: 24 * 0x200, right: 0x1000, bottom: 0x2000 }; + self.parts[7].hit_bounds = Rect { left: 0x1000, top: 24 * 0x200, right: 0x1000, bottom: 0x2000 }; self.parts[7].npc_flags.set_ignore_solidity(true); self.parts[9].cond.set_alive(true); @@ -212,8 +210,7 @@ impl BossNPC { self.parts[9].direction = Direction::Up; self.parts[9].display_bounds = Rect { left: 36 * 0x200, top: 0x1000, right: 36 * 0x200, bottom: 24 * 0x200 }; - self.parts[9].hit_bounds = - Rect { left: 28 * 0x200, top: 0x1000, right: 28 * 0x200, bottom: 0x2000 }; + self.parts[9].hit_bounds = Rect { left: 28 * 0x200, top: 0x1000, right: 28 * 0x200, bottom: 0x2000 }; self.hurt_sound[9] = 52; self.parts[9].npc_flags.set_rear_and_top_not_hurt(true); self.parts[9].npc_flags.set_ignore_solidity(true); @@ -260,10 +257,6 @@ impl BossNPC { self.parts[16].anim_num = 3; self.parts[16].display_bounds.left = 42 * 0x200; self.parts[16].display_bounds.right = 30 * 0x200; - - for npc in &mut self.parts { - npc.init_rng(); - } } 10 | 11 => { if self.parts[0].action_num == 10 { diff --git a/src/npc/list.rs b/src/npc/list.rs index 68f6d5e..aa8fe69 100644 --- a/src/npc/list.rs +++ b/src/npc/list.rs @@ -1,7 +1,7 @@ use std::cell::{Cell, UnsafeCell}; use std::mem::MaybeUninit; -use crate::framework::error::{GameResult, GameError}; +use crate::framework::error::{GameError, GameResult}; use crate::npc::NPC; @@ -15,6 +15,7 @@ pub struct NPCList { // from theoretically performing some optimizations that might break the code. npcs: Box>, max_npc: Cell, + seed: i32, } #[allow(dead_code)] @@ -31,6 +32,7 @@ impl NPCList { parts_uninit })), max_npc: Cell::new(0), + seed: 0, }; unsafe { @@ -42,6 +44,10 @@ impl NPCList { map } + pub fn set_rng_seed(&mut self, seed: i32) { + self.seed = seed; + } + /// Inserts NPC into list in first available slot after given ID. pub fn spawn(&self, min_id: u16, mut npc: NPC) -> GameResult { let npc_len = unsafe { self.npcs().len() }; @@ -60,7 +66,7 @@ impl NPCList { npc.tsc_direction = npc.direction as u16; } - npc.init_rng(); + npc.init_rng(self.seed); *npc_ref = npc; @@ -89,7 +95,7 @@ impl NPCList { npc.tsc_direction = npc.direction as u16; } - npc.init_rng(); + npc.init_rng(self.seed); unsafe { let npc_ref = self.npcs_mut().get_unchecked_mut(id as usize); @@ -105,9 +111,7 @@ impl NPCList { /// Returns a mutable reference to NPC from this list. pub fn get_npc<'a: 'b, 'b>(&'a self, id: usize) -> Option<&'b mut NPC> { - unsafe { - self.npcs_mut().get_mut(id) - } + unsafe { self.npcs_mut().get_mut(id) } } /// Returns an iterator that iterates over allocated (not up to it's capacity) NPC slots. @@ -156,10 +160,7 @@ pub struct NPCListMutableIterator<'a> { impl<'a> NPCListMutableIterator<'a> { pub fn new(map: &'a NPCList) -> NPCListMutableIterator<'a> { - NPCListMutableIterator { - index: 0, - map, - } + NPCListMutableIterator { index: 0, map } } } @@ -185,10 +186,7 @@ pub struct NPCListMutableAliveIterator<'a> { impl<'a> NPCListMutableAliveIterator<'a> { pub fn new(map: &'a NPCList) -> NPCListMutableAliveIterator<'a> { - NPCListMutableAliveIterator { - index: 0, - map, - } + NPCListMutableAliveIterator { index: 0, map } } } diff --git a/src/npc/utils.rs b/src/npc/utils.rs index f119eb8..2603f87 100644 --- a/src/npc/utils.rs +++ b/src/npc/utils.rs @@ -16,13 +16,14 @@ const MAX_FALL_SPEED: i32 = 0x5FF; impl NPC { /// Initializes the RNG. Called when the [NPC] is being added to an [NPCList]. - pub(crate) fn init_rng(&mut self) { + pub(crate) fn init_rng(&mut self, seed: i32) { self.rng = Xoroshiro32PlusPlus::new( (self.id as u32) .wrapping_sub(self.npc_type as u32) .rotate_right(5) .wrapping_sub(self.flag_num as u32) .rotate_right((self.event_num % 13) as u32) + .wrapping_add(seed.abs() as u32) .wrapping_mul(214013) .rotate_right(13) .wrapping_add(2531011) diff --git a/src/scene/game_scene.rs b/src/scene/game_scene.rs index 3677c44..db43594 100644 --- a/src/scene/game_scene.rs +++ b/src/scene/game_scene.rs @@ -1592,12 +1592,16 @@ impl GameScene { impl Scene for GameScene { fn init(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { - let seed = (self.player1.max_life as i32) - .wrapping_add(self.player1.x as i32) - .wrapping_add(self.player1.y as i32) - .wrapping_add(self.stage_id as i32) - .rotate_right(7); - state.game_rng = XorShift::new(seed); + if state.mod_path.is_some() && state.replay_state == ReplayState::Recording { + self.replay.initialize_recording(state); + } + + if state.mod_path.is_some() && state.replay_state == ReplayState::Playback { + self.replay.initialize_playback(state, ctx)?; + } + + self.npc_list.set_rng_seed(state.game_rng.next()); + self.boss.init_rng(state.game_rng.next()); state.textscript_vm.set_scene_script(self.stage.load_text_script( &state.constants.base_paths, &state.constants, @@ -1677,14 +1681,6 @@ impl Scene for GameScene { self.pause_menu.init(state, ctx)?; self.whimsical_star.init(&self.player1); - if state.mod_path.is_some() && state.replay_state == ReplayState::Recording { - self.replay.start_recording(state); - } - - if state.mod_path.is_some() && state.replay_state == ReplayState::Playback { - self.replay.start_playback(state, ctx)?; - } - Ok(()) } diff --git a/src/shared_game_state.rs b/src/shared_game_state.rs index 8479592..0c3bfe3 100644 --- a/src/shared_game_state.rs +++ b/src/shared_game_state.rs @@ -360,7 +360,7 @@ impl SharedGameState { skip_flags: bitvec::bitvec![0; 64], map_flags: bitvec::bitvec![0; 64], fade_state: FadeState::Hidden, - game_rng: XorShift::new(0), + game_rng: XorShift::new(chrono::Local::now().timestamp() as i32), effect_rng: XorShift::new(123), tile_size: TileSize::Tile16x16, quake_counter: 0, @@ -593,7 +593,7 @@ impl SharedGameState { self.control_flags.0 = 0; self.game_flags = bitvec::bitvec![0; 8000]; self.fade_state = FadeState::Hidden; - self.game_rng = XorShift::new(0); + self.game_rng = XorShift::new(chrono::Local::now().timestamp() as i32); self.teleporter_slots.clear(); self.quake_counter = 0; self.carets.clear();