RNG Tweaks

This commit is contained in:
dawnDus 2022-04-20 08:07:27 -04:00
parent b94b20bf76
commit 28a3f160c3
No known key found for this signature in database
GPG Key ID: 972AABDE81848F21
8 changed files with 51 additions and 61 deletions

View File

@ -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(())
}

View File

@ -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);

View File

@ -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] }
}
}

View File

@ -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 {

View File

@ -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<UnsafeCell<[NPC; NPC_LIST_MAX_CAP]>>,
max_npc: Cell<u16>,
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 }
}
}

View File

@ -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)

View File

@ -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(())
}

View File

@ -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();