diff --git a/src/common.rs b/src/common.rs index 1c7e70b..86a5201 100644 --- a/src/common.rs +++ b/src/common.rs @@ -8,6 +8,7 @@ use serde::de::{SeqAccess, Visitor}; use serde::ser::SerializeTupleStruct; use crate::bitfield; +use crate::texture_set::G_MAG; /// Multiply cave story degrees (0-255, which corresponds to 0°-360°) with this to get /// respective value in radians. @@ -367,8 +368,11 @@ rect_deserialze!(isize); rect_deserialze!(usize); #[inline(always)] -pub fn fix9_scale(val: i32, scale: f32) -> f32 { - (val as f64 * scale as f64 / 512.0).floor() as f32 / scale +pub fn fix9_scale(val: i32) -> f32 { + unsafe { + let mag = G_MAG as f32; + (val as f32 * mag / 512.0).floor() / mag + } } #[inline(always)] @@ -376,12 +380,21 @@ fn lerp_f64(v1: f64, v2: f64, t: f64) -> f64 { v1 * (1.0 - t) + v2 * t } +#[inline(always)] +fn lerp_f32(v1: f32, v2: f32, t: f32) -> f32 { + v1 * (1.0 - t) + v2 * t +} + pub fn interpolate_fix9_scale(old_val: i32, val: i32, frame_delta: f64) -> f32 { - if abs(old_val - val) > 0x1000 { + if abs(old_val - val) > 0x1800 { return val as f32 / 512.0; } - (lerp_f64(old_val as f64, val as f64, frame_delta) / 512.0) as f32 + unsafe { + let interpolated = lerp_f64(old_val as f64, val as f64, frame_delta) as f32; + let mag = G_MAG as f32; + (interpolated * mag / 512.0).floor() / mag + } } diff --git a/src/components/flash.rs b/src/components/flash.rs index 746051a..363d78c 100644 --- a/src/components/flash.rs +++ b/src/components/flash.rs @@ -65,7 +65,7 @@ impl GameEntity<()> for Flash { FlashState::None => {} FlashState::Cross(x, y, tick) => { let tick = tick as f32 + state.frame_time as f32; - let frame_pos = frame.xy_interpolated(state.frame_time, state.scale); + let frame_pos = frame.xy_interpolated(state.frame_time); let (cen_x, cen_y) = ( (x as f32 / 512.0) - frame_pos.0, diff --git a/src/frame.rs b/src/frame.rs index 001e590..a033665 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -23,9 +23,9 @@ pub struct Frame { } impl Frame { - pub fn xy_interpolated(&self, frame_time: f64, scale: f32) -> (f32, f32) { + pub fn xy_interpolated(&self, frame_time: f64) -> (f32, f32) { if self.prev_x == self.x && self.prev_y == self.y { - return (fix9_scale(self.x, scale), fix9_scale(self.y, scale)); + return (fix9_scale(self.x), fix9_scale(self.y)); } let x = interpolate_fix9_scale(self.prev_x, self.x, frame_time); diff --git a/src/npc/boss/mod.rs b/src/npc/boss/mod.rs index 37d32d0..7df214a 100644 --- a/src/npc/boss/mod.rs +++ b/src/npc/boss/mod.rs @@ -110,16 +110,16 @@ impl GameEntity<([&mut Player; 2], &NPCList, &mut Stage, &BulletManager, &mut Fl let off_x = if npc.direction == Direction::Left { npc.display_bounds.left } else { npc.display_bounds.right } as i32; - let shock = if npc.shock > 0 { (2 * ((npc.shock as i32 / 2) % 2) - 1) as f32 } else { 0.0 }; + let shock = if npc.shock > 0 { (2 * ((npc.shock as i32 / 2) & 1) - 1) as f32 } else { 0.0 }; + let (frame_x, frame_y) = frame.xy_interpolated(state.frame_time); batch.add_rect( - interpolate_fix9_scale(npc.prev_x - off_x - frame.prev_x, npc.x - off_x - frame.x, state.frame_time) - + shock, - interpolate_fix9_scale( - npc.prev_y - npc.display_bounds.top as i32 - frame.prev_y, - npc.y - npc.display_bounds.top as i32 - frame.y, - state.frame_time, - ), + interpolate_fix9_scale(npc.prev_x - off_x, + npc.x - off_x, + state.frame_time) + shock - frame_x, + interpolate_fix9_scale(npc.prev_y - npc.display_bounds.top as i32, + npc.y - npc.display_bounds.top as i32, + state.frame_time) - frame_y, &npc.anim_rect, ); } diff --git a/src/npc/mod.rs b/src/npc/mod.rs index c9bdd70..9677ae4 100644 --- a/src/npc/mod.rs +++ b/src/npc/mod.rs @@ -406,13 +406,15 @@ impl GameEntity<([&mut Player; 2], &NPCList, &mut Stage, &BulletManager, &mut Fl (2 * ((self.shock as i32 / 2) % 2) - 1) as f32 } else { 0.0 }; + let (frame_x, frame_y) = frame.xy_interpolated(state.frame_time); + batch.add_rect( - interpolate_fix9_scale(self.prev_x - off_x - frame.prev_x, - self.x - off_x - frame.x, - state.frame_time) + shock, - interpolate_fix9_scale(self.prev_y - self.display_bounds.top as i32 - frame.prev_y, - self.y - self.display_bounds.top as i32 - frame.y, - state.frame_time), + interpolate_fix9_scale(self.prev_x - off_x, + self.x - off_x, + state.frame_time) + shock - frame_x, + interpolate_fix9_scale(self.prev_y - self.display_bounds.top as i32, + self.y - self.display_bounds.top as i32, + state.frame_time) - frame_y, &self.anim_rect, ); batch.draw(ctx)?; diff --git a/src/player/mod.rs b/src/player/mod.rs index f927434..47f3adc 100644 --- a/src/player/mod.rs +++ b/src/player/mod.rs @@ -740,6 +740,8 @@ impl GameEntity<&NPCList> for Player { return Ok(()); } + let (frame_x, frame_y) = frame.xy_interpolated(state.frame_time); + // hack for stacked dogs if state.constants.is_switch { let dog_amount = (3000..=3005).filter(|id| state.get_flag(*id as usize)).count(); @@ -762,15 +764,15 @@ impl GameEntity<&NPCList> for Player { for i in 1..=(dog_amount as i32) { batch.add_rect( interpolate_fix9_scale( - self.prev_x - frame.prev_x - off_x - vec_x * i, - self.x - frame.x - off_x - vec_x * i, + self.prev_x - off_x - vec_x * i, + self.x - off_x - vec_x * i, state.frame_time, - ), + ) - frame_x, interpolate_fix9_scale( - self.prev_y - frame.prev_y - off_y - vec_y * i, - self.y - frame.y - off_y - vec_y * i, + self.prev_y - off_y - vec_y * i, + self.y - off_y - vec_y * i, state.frame_time, - ), + ) - frame_y, &state.constants.npc.n136_puppy_carried[frame_id], ); } @@ -788,15 +790,17 @@ impl GameEntity<&NPCList> for Player { let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "Arms")?; batch.add_rect( interpolate_fix9_scale( - self.prev_x - self.display_bounds.left as i32 - frame.prev_x, - self.x - self.display_bounds.left as i32 - frame.x, + self.prev_x - self.display_bounds.left as i32, + self.x - self.display_bounds.left as i32, state.frame_time, - ) + if self.direction == Direction::Left { -8.0 } else { 0.0 }, + ) + if self.direction == Direction::Left { -8.0 } else { 0.0 } + - frame_x, interpolate_fix9_scale( - self.prev_y - self.display_bounds.left as i32 - frame.prev_y, - self.y - self.display_bounds.left as i32 - frame.y, + self.prev_y - self.display_bounds.left as i32, + self.y - self.display_bounds.left as i32, state.frame_time, - ) + self.weapon_offset_y as f32, + ) + self.weapon_offset_y as f32 + - frame_y, &self.weapon_rect, ); @@ -808,15 +812,15 @@ impl GameEntity<&NPCList> for Player { state.texture_set.get_or_load_batch(ctx, &state.constants, self.skin.get_skin_texture_name())?; batch.add_rect( interpolate_fix9_scale( - self.prev_x - self.display_bounds.left as i32 - frame.prev_x, - self.x - self.display_bounds.left as i32 - frame.x, + self.prev_x - self.display_bounds.left as i32, + self.x - self.display_bounds.left as i32, state.frame_time, - ), + ) - frame_x, interpolate_fix9_scale( - self.prev_y - self.display_bounds.left as i32 - frame.prev_y, - self.y - self.display_bounds.left as i32 - frame.y, + self.prev_y - self.display_bounds.left as i32, + self.y - self.display_bounds.left as i32, state.frame_time, - ), + ) - frame_y, &self.anim_rect, ); batch.draw(ctx)?; @@ -825,16 +829,8 @@ impl GameEntity<&NPCList> for Player { if (self.equip.has_air_tank() && self.flags.in_water()) || self.control_mode == ControlMode::IronHead { let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "Caret")?; batch.add_rect( - interpolate_fix9_scale( - self.prev_x - frame.prev_x - 12 * 0x200, - self.x - frame.x - 12 * 0x200, - state.frame_time, - ), - interpolate_fix9_scale( - self.prev_y - frame.prev_y - 12 * 0x200, - self.y - frame.y - 12 * 0x200, - state.frame_time, - ), + interpolate_fix9_scale(self.prev_x - 12 * 0x200, self.x - 12 * 0x200, state.frame_time) - frame_x, + interpolate_fix9_scale(self.prev_y - 12 * 0x200, self.y - 12 * 0x200, state.frame_time) - frame_y, &state.constants.player.frames_bubble[(self.tick / 2 % 2) as usize], ); batch.draw(ctx)?; diff --git a/src/scene/game_scene.rs b/src/scene/game_scene.rs index a0a7007..e2c6037 100644 --- a/src/scene/game_scene.rs +++ b/src/scene/game_scene.rs @@ -138,7 +138,7 @@ impl GameScene { fn draw_background(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, &self.tex_background_name)?; let scale = state.scale; - let (frame_x, frame_y) = self.frame.xy_interpolated(state.frame_time, state.scale); + let (frame_x, frame_y) = self.frame.xy_interpolated(state.frame_time); match self.stage.data.background_type { BackgroundType::Stationary => { @@ -761,8 +761,16 @@ impl GameScene { for bullet in self.bullet_manager.bullets.iter() { self.draw_light( - fix9_scale(bullet.x - self.frame.x, scale), - fix9_scale(bullet.y - self.frame.y, scale), + interpolate_fix9_scale( + bullet.prev_x - self.frame.prev_x, + bullet.x - self.frame.x, + state.frame_time, + ), + interpolate_fix9_scale( + bullet.prev_y - self.frame.prev_y, + bullet.y - self.frame.y, + state.frame_time, + ), 0.3, (200, 200, 200), batch, @@ -773,8 +781,16 @@ impl GameScene { match caret.ctype { CaretType::ProjectileDissipation | CaretType::Shoot => { self.draw_light( - fix9_scale(caret.x - self.frame.x, scale), - fix9_scale(caret.y - self.frame.y, scale), + interpolate_fix9_scale( + caret.prev_x - self.frame.prev_x, + caret.x - self.frame.x, + state.frame_time, + ), + interpolate_fix9_scale( + caret.prev_y - self.frame.prev_y, + caret.y - self.frame.y, + state.frame_time, + ), 1.0, (200, 200, 200), batch, @@ -803,38 +819,62 @@ impl GameScene { match npc.npc_type { 1 => { self.draw_light( - fix9_scale(npc.x - self.frame.x, scale), - fix9_scale(npc.y - self.frame.y, scale), + interpolate_fix9_scale( + npc.prev_x - self.frame.prev_x, + npc.x - self.frame.x, + state.frame_time, + ), + interpolate_fix9_scale( + npc.prev_y - self.frame.prev_y, + npc.y - self.frame.y, + state.frame_time, + ), 0.4, (255, 255, 0), batch, ); } 4 if npc.direction == Direction::Up => self.draw_light( - fix9_scale(npc.x - self.frame.x, scale), - fix9_scale(npc.y - self.frame.y, scale), + interpolate_fix9_scale(npc.prev_x - self.frame.prev_x, npc.x - self.frame.x, state.frame_time), + interpolate_fix9_scale(npc.prev_y - self.frame.prev_y, npc.y - self.frame.y, state.frame_time), 1.0, (200, 100, 0), batch, ), 7 => self.draw_light( - fix9_scale(npc.x - self.frame.x, scale), - fix9_scale(npc.y - self.frame.y, scale), + interpolate_fix9_scale(npc.prev_x - self.frame.prev_x, npc.x - self.frame.x, state.frame_time), + interpolate_fix9_scale(npc.prev_y - self.frame.prev_y, npc.y - self.frame.y, state.frame_time), 1.0, (100, 100, 100), batch, ), 17 if npc.anim_num == 0 => { self.draw_light( - fix9_scale(npc.x - self.frame.x, scale), - fix9_scale(npc.y - self.frame.y, scale), + interpolate_fix9_scale( + npc.prev_x - self.frame.prev_x, + npc.x - self.frame.x, + state.frame_time, + ), + interpolate_fix9_scale( + npc.prev_y - self.frame.prev_y, + npc.y - self.frame.y, + state.frame_time, + ), 2.0, (160, 0, 0), batch, ); self.draw_light( - fix9_scale(npc.x - self.frame.x, scale), - fix9_scale(npc.y - self.frame.y, scale), + interpolate_fix9_scale( + npc.prev_x - self.frame.prev_x, + npc.x - self.frame.x, + state.frame_time, + ), + interpolate_fix9_scale( + npc.prev_y - self.frame.prev_y, + npc.y - self.frame.y, + state.frame_time, + ), 0.5, (255, 0, 0), batch, @@ -842,8 +882,16 @@ impl GameScene { } 20 if npc.direction == Direction::Right => { self.draw_light( - fix9_scale(npc.x - self.frame.x, scale), - fix9_scale(npc.y - self.frame.y, scale), + interpolate_fix9_scale( + npc.prev_x - self.frame.prev_x, + npc.x - self.frame.x, + state.frame_time, + ), + interpolate_fix9_scale( + npc.prev_y - self.frame.prev_y, + npc.y - self.frame.y, + state.frame_time, + ), 2.0, (0, 0, 150), batch, @@ -851,8 +899,16 @@ impl GameScene { if npc.anim_num < 2 { self.draw_light( - fix9_scale(npc.x - self.frame.x, scale), - fix9_scale(npc.y - self.frame.y, scale), + interpolate_fix9_scale( + npc.prev_x - self.frame.prev_x, + npc.x - self.frame.x, + state.frame_time, + ), + interpolate_fix9_scale( + npc.prev_y - self.frame.prev_y, + npc.y - self.frame.y, + state.frame_time, + ), 2.1, (0, 0, 30), batch, @@ -860,16 +916,24 @@ impl GameScene { } } 22 if npc.action_num == 1 && npc.anim_num == 1 => self.draw_light( - fix9_scale(npc.x - self.frame.x, scale), - fix9_scale(npc.y - self.frame.y, scale), + interpolate_fix9_scale(npc.prev_x - self.frame.prev_x, npc.x - self.frame.x, state.frame_time), + interpolate_fix9_scale(npc.prev_y - self.frame.prev_y, npc.y - self.frame.y, state.frame_time), 3.0, (0, 0, 255), batch, ), 32 | 87 | 211 => { self.draw_light( - fix9_scale(npc.x - self.frame.x, scale), - fix9_scale(npc.y - self.frame.y, scale), + interpolate_fix9_scale( + npc.prev_x - self.frame.prev_x, + npc.x - self.frame.x, + state.frame_time, + ), + interpolate_fix9_scale( + npc.prev_y - self.frame.prev_y, + npc.y - self.frame.y, + state.frame_time, + ), 2.0, (255, 30, 30), batch, @@ -878,8 +942,16 @@ impl GameScene { 38 => { let flicker = (npc.anim_num ^ 5 & 3) as u8 * 15; self.draw_light( - fix9_scale(npc.x - self.frame.x, scale), - fix9_scale(npc.y - self.frame.y, scale), + interpolate_fix9_scale( + npc.prev_x - self.frame.prev_x, + npc.x - self.frame.x, + state.frame_time, + ), + interpolate_fix9_scale( + npc.prev_y - self.frame.prev_y, + npc.y - self.frame.y, + state.frame_time, + ), 3.5, (130 + flicker, 40 + flicker, 0), batch, @@ -888,16 +960,24 @@ impl GameScene { 70 => { let flicker = 50 + npc.anim_num as u8 * 15; self.draw_light( - fix9_scale(npc.x - self.frame.x, scale), - fix9_scale(npc.y - self.frame.y, scale), + interpolate_fix9_scale( + npc.prev_x - self.frame.prev_x, + npc.x - self.frame.x, + state.frame_time, + ), + interpolate_fix9_scale( + npc.prev_y - self.frame.prev_y, + npc.y - self.frame.y, + state.frame_time, + ), 2.0, (flicker, flicker, flicker), batch, ); } 75 | 77 => self.draw_light( - fix9_scale(npc.x - self.frame.x, scale), - fix9_scale(npc.y - self.frame.y, scale), + interpolate_fix9_scale(npc.prev_x - self.frame.prev_x, npc.x - self.frame.x, state.frame_time), + interpolate_fix9_scale(npc.prev_y - self.frame.prev_y, npc.y - self.frame.y, state.frame_time), 3.0, (255, 100, 0), batch, @@ -910,8 +990,16 @@ impl GameScene { }; self.draw_light( - fix9_scale(npc.x - self.frame.x, scale), - fix9_scale(npc.y - self.frame.y, scale), + interpolate_fix9_scale( + npc.prev_x - self.frame.prev_x, + npc.x - self.frame.x, + state.frame_time, + ), + interpolate_fix9_scale( + npc.prev_y - self.frame.prev_y, + npc.y - self.frame.y, + state.frame_time, + ), 1.5, color, batch, @@ -919,8 +1007,16 @@ impl GameScene { if npc.anim_num < 2 { self.draw_light( - fix9_scale(npc.x - self.frame.x, scale), - fix9_scale(npc.y - self.frame.y, scale) - 8.0, + interpolate_fix9_scale( + npc.prev_x - self.frame.prev_x, + npc.x - self.frame.x, + state.frame_time, + ), + interpolate_fix9_scale( + npc.prev_y - self.frame.prev_y, + npc.y - self.frame.y, + state.frame_time, + ) - 8.0, 2.1, color2, batch, @@ -929,8 +1025,16 @@ impl GameScene { } 299 => { self.draw_light( - fix9_scale(npc.x - self.frame.x, scale), - fix9_scale(npc.y - self.frame.y, scale), + interpolate_fix9_scale( + npc.prev_x - self.frame.prev_x, + npc.x - self.frame.x, + state.frame_time, + ), + interpolate_fix9_scale( + npc.prev_y - self.frame.prev_y, + npc.y - self.frame.y, + state.frame_time, + ), 4.0, (30, 30, 200), batch, @@ -938,8 +1042,16 @@ impl GameScene { } 300 => { self.draw_light( - fix9_scale(npc.x - self.frame.x, scale), - fix9_scale(npc.y - self.frame.y, scale), + interpolate_fix9_scale( + npc.prev_x - self.frame.prev_x, + npc.x - self.frame.x, + state.frame_time, + ), + interpolate_fix9_scale( + npc.prev_y - self.frame.prev_y, + npc.y - self.frame.y, + state.frame_time, + ), 1.5, (200, 10, 10), batch, @@ -972,7 +1084,7 @@ impl GameScene { }; let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, tex)?; let mut rect = Rect::new(0, 0, 16, 16); - let (frame_x, frame_y) = self.frame.xy_interpolated(state.frame_time, state.scale); + let (frame_x, frame_y) = self.frame.xy_interpolated(state.frame_time); let tile_start_x = (frame_x as i32 / 16).clamp(0, self.stage.map.width as i32) as usize; let tile_start_y = (frame_y as i32 / 16).clamp(0, self.stage.map.height as i32) as usize; @@ -1251,7 +1363,13 @@ impl GameScene { for npc in self.npc_list.iter_alive() { npc.tick( state, - ([&mut self.player1, &mut self.player2], &self.npc_list, &mut self.stage, &self.bullet_manager, &mut self.flash), + ( + [&mut self.player1, &mut self.player2], + &self.npc_list, + &mut self.stage, + &self.bullet_manager, + &mut self.flash, + ), )?; } self.boss.tick( @@ -1745,10 +1863,12 @@ impl Scene for GameScene { let pos_y = 0.0; let line_height = state.font.line_height(&state.constants); let w = (self.skip_counter as f32 / CUTSCENE_SKIP_WAIT as f32) * (width + 20.0) / 2.0; - let mut rect = Rect::new_size((pos_x * state.scale) as isize, - (pos_y * state.scale) as isize, - ((20.0 + width) * state.scale) as isize, - ((20.0 + line_height) * state.scale) as isize); + let mut rect = Rect::new_size( + (pos_x * state.scale) as isize, + (pos_y * state.scale) as isize, + ((20.0 + width) * state.scale) as isize, + ((20.0 + line_height) * state.scale) as isize, + ); draw_rect(ctx, rect, Color::from_rgb(0, 0, 32))?; diff --git a/src/texture_set.rs b/src/texture_set.rs index e8943d0..f717a74 100644 --- a/src/texture_set.rs +++ b/src/texture_set.rs @@ -67,10 +67,10 @@ impl SizedBatch { } pub fn add(&mut self, mut x: f32, mut y: f32) { - unsafe { - x = (x * G_MAG).round() / G_MAG; - y = (y * G_MAG).round() / G_MAG; - } + /*unsafe { + x = (x * G_MAG).floor() / G_MAG; + y = (y * G_MAG).floor() / G_MAG; + }*/ let mag = unsafe { I_MAG }; self.batch.add(SpriteBatchCommand::DrawRect( @@ -99,10 +99,10 @@ impl SizedBatch { return; } - unsafe { - x = (x * G_MAG).round() / G_MAG; - y = (y * G_MAG).round() / G_MAG; - } + /*unsafe { + x = (x * G_MAG).floor() / G_MAG; + y = (y * G_MAG).floor() / G_MAG; + }*/ let mag = unsafe { I_MAG }; self.batch.add(SpriteBatchCommand::DrawRectFlip( @@ -132,10 +132,10 @@ impl SizedBatch { return; } - unsafe { - x = (x * G_MAG).round() / G_MAG; - y = (y * G_MAG).round() / G_MAG; - } + /*unsafe { + x = (x * G_MAG).floor() / G_MAG; + y = (y * G_MAG).floor() / G_MAG; + }*/ let mag = unsafe { I_MAG }; self.batch.add(SpriteBatchCommand::DrawRect( @@ -159,10 +159,10 @@ impl SizedBatch { return; } - unsafe { + /*unsafe { x = (x * G_MAG).floor() / G_MAG; y = (y * G_MAG).floor() / G_MAG; - } + }*/ let mag = unsafe { I_MAG }; self.batch.add(SpriteBatchCommand::DrawRectTinted(