diff --git a/src/builtin/lightmap/spot.png b/src/builtin/lightmap/spot.png index 640e30f..593a525 100644 Binary files a/src/builtin/lightmap/spot.png and b/src/builtin/lightmap/spot.png differ diff --git a/src/common.rs b/src/common.rs index 28ce1d1..c2963b6 100644 --- a/src/common.rs +++ b/src/common.rs @@ -15,7 +15,7 @@ pub const CDEG_RAD: f64 = std::f64::consts::PI / 128.0; lazy_static! { pub static ref VERSION_BANNER: String = { let version = option_env!("DRS_BUILD_VERSION_OVERRIDE").unwrap_or(env!("CARGO_PKG_VERSION")); - format!("doukutsu-rs {}", version) + format!("NXEngine-RS {}", version) }; } diff --git a/src/engine_constants/mod.rs b/src/engine_constants/mod.rs index afe3ca8..78d4324 100644 --- a/src/engine_constants/mod.rs +++ b/src/engine_constants/mod.rs @@ -277,7 +277,7 @@ impl EngineConstants { supports_og_textures: false, my_char: MyCharConsts { display_bounds: Rect { left: 8 * 0x200, top: 8 * 0x200, right: 8 * 0x200, bottom: 8 * 0x200 }, - hit_bounds: Rect { left: 5 * 0x200, top: 8 * 0x200, right: 5 * 0x200, bottom: 8 * 0x200 }, + hit_bounds: Rect { left: 8 * 0x200, top: 8 * 0x200, right: 8 * 0x200, bottom: 8 * 0x200 }, life: 3, max_life: 3, control_mode: ControlMode::Normal, diff --git a/src/framework/backend_sdl2.rs b/src/framework/backend_sdl2.rs index 93f82ab..d3fae01 100644 --- a/src/framework/backend_sdl2.rs +++ b/src/framework/backend_sdl2.rs @@ -61,7 +61,7 @@ impl SDL2EventLoop { let event_pump = sdl.event_pump().map_err(|e| GameError::WindowError(e))?; let video = sdl.video().map_err(|e| GameError::WindowError(e))?; let window = - video.window("Cave Story (doukutsu-rs)", 640, 480).position_centered().resizable().build().map_err(|e| GameError::WindowError(e.to_string()))?; + video.window("NXEngine-RS", 640, 480).position_centered().resizable().build().map_err(|e| GameError::WindowError(e.to_string()))?; let canvas = window.into_canvas().accelerated().present_vsync().build().map_err(|e| GameError::RenderError(e.to_string()))?; @@ -365,6 +365,7 @@ impl BackendRenderer for SDL2Renderer { let (r, g, b, a) = color.to_rgba(); refs.canvas.set_draw_color(pixels::Color::RGBA(r, g, b, a)); + refs.canvas.set_blend_mode(sdl2::render::BlendMode::Blend); refs.canvas .fill_rect(sdl2::rect::Rect::new(rect.left as i32, rect.top as i32, rect.width() as u32, rect.height() as u32)) .map_err(|e| GameError::RenderError(e.to_string()))?; @@ -378,6 +379,7 @@ impl BackendRenderer for SDL2Renderer { let (r, g, b, a) = color.to_rgba(); refs.canvas.set_draw_color(pixels::Color::RGBA(r, g, b, a)); + refs.canvas.set_blend_mode(sdl2::render::BlendMode::Blend); match line_width { 0 => {} // no-op diff --git a/src/main.rs b/src/main.rs index b548c45..103d7fc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,7 +17,7 @@ fn main() { if let Err(e) = result { let title: LPCWSTR = OsStr::new("Error!") .encode_wide().chain(Some(0)).collect::>().as_ptr(); - let message: LPCWSTR = OsStr::new(format!("Whoops, doukutsu-rs crashed: {}", e).as_str()) + let message: LPCWSTR = OsStr::new(format!("Whoops, nxengine-rs crashed: {}", e).as_str()) .encode_wide().chain(Some(0)).collect::>().as_ptr(); MessageBoxW(null_mut(), message, diff --git a/src/npc/ai/sand_zone.rs b/src/npc/ai/sand_zone.rs index 2b68d21..cfe1fb0 100644 --- a/src/npc/ai/sand_zone.rs +++ b/src/npc/ai/sand_zone.rs @@ -1,7 +1,7 @@ use num_traits::{abs, clamp}; use crate::caret::CaretType; -use crate::common::{Direction, CDEG_RAD}; +use crate::common::{CDEG_RAD, Direction}; use crate::framework::error::GameResult; use crate::npc::list::NPCList; use crate::npc::NPC; @@ -667,7 +667,14 @@ impl NPC { if self.action_counter > 50 { state.sound_manager.play_sfx(25); self.vanish(state); - npc_list.create_death_smoke(self.x, self.y, self.display_bounds.right as usize, 8, state, &self.rng); + npc_list.create_death_smoke( + self.x, + self.y, + self.display_bounds.right as usize, + 8, + state, + &self.rng, + ); } } _ => {} @@ -897,6 +904,68 @@ impl NPC { Ok(()) } + pub(crate) fn tick_n122_colon_enraged( + &mut self, + state: &mut SharedGameState, + players: [&mut Player; 2], + ) -> GameResult { + match self.action_num { + 0 | 1 => { + if self.action_num == 0 { + self.action_num = 1; + self.anim_num = 0; + self.anim_counter = 0; + } + + if self.rng.range(0..120) == 10 { + self.action_num = 2; + self.action_counter = 0; + self.anim_num = 1; + } + + let player = self.get_closest_player_mut(players); + if (self.x - player.x).abs() < 0x4000 && self.y - 0x4000 < player.y && self.y + 0x2000 > player.y { + if self.x <= player.x { + Direction::Right + } else { + Direction::Left + }; + } + } + 2 => { + self.action_counter += 1; + if self.action_counter > 8 { + self.action_num = 1; + self.anim_num = 0; + } + } + 10 | 11 => { + if self.action_num == 10 { + self.action_num = 11; + self.action_counter = self.rng.range(0..50) as u16; + self.anim_num = 0; + self.life = 1000; + self.damage = 0; + } + + if self.action_counter > 0 { + self.action_counter -= 1; + } else { + self.action_num = 13; + } + } + 13 | 14 => { + if self.action_num == 13 { + self.action_num = 14; + self.action_counter = self.rng.range(0..50) as u16; + } + } + _ => {} + } + + Ok(()) + } + pub(crate) fn tick_n124_sunstone(&mut self, state: &mut SharedGameState) -> GameResult { match self.action_num { 0 | 1 => { @@ -987,7 +1056,7 @@ impl NPC { self.animate(2, 4, 5); } else { self.anim_num = 5; - self.anim_counter =0; + self.anim_counter = 0; } if self.vel_x < 0 && self.flags.hit_left_wall() { @@ -1030,7 +1099,6 @@ impl NPC { self.x += self.vel_x; self.y += self.vel_y; - let dir_offset = if self.direction == Direction::Left { 0 } else { 6 }; self.anim_rect = state.constants.npc.n126_puppy_running[self.anim_num as usize + dir_offset]; diff --git a/src/scene/game_scene.rs b/src/scene/game_scene.rs index bd57f19..17aaae9 100644 --- a/src/scene/game_scene.rs +++ b/src/scene/game_scene.rs @@ -591,17 +591,19 @@ impl GameScene { } fn draw_light_map(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { - let canvas = state.lightmap_canvas.as_mut(); - if let None = canvas { - return Ok(()); - } + //let canvas = state.lightmap_canvas.as_mut(); + // if let None = canvas { + // return Ok(()); + // } - let canvas = canvas.unwrap(); + // let canvas = canvas.unwrap(); - graphics::set_render_target(ctx, Some(canvas))?; - graphics::set_blend_mode(ctx, BlendMode::Add)?; + //graphics::set_render_target(ctx, Some(canvas))?; + //graphics::set_blend_mode(ctx, BlendMode::Add)?; + + //graphics::clear(ctx, Color::from_rgb(100, 100, 110)); + graphics::draw_rect(ctx, Rect::new(0, 0, state.screen_size.0 as isize + 1, state.screen_size.1 as isize + 1), Color::from_rgba(0, 0, 0, 150))?; - graphics::clear(ctx, Color::from_rgb(100, 100, 110)); { let scale = state.scale; let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "builtin/lightmap/spot")?; @@ -802,15 +804,15 @@ impl GameScene { batch.draw_filtered(FilterMode::Linear, ctx)?; } - graphics::set_blend_mode(ctx, BlendMode::Multiply)?; - graphics::set_render_target(ctx, None)?; + //graphics::set_blend_mode(ctx, BlendMode::Multiply)?; + //graphics::set_render_target(ctx, None)?; - let rect = Rect { left: 0.0, top: 0.0, right: state.screen_size.0, bottom: state.screen_size.1 }; + /*let rect = Rect { left: 0.0, top: 0.0, right: state.screen_size.0, bottom: state.screen_size.1 }; canvas.clear(); canvas.add(SpriteBatchCommand::DrawRect(rect, rect)); canvas.draw()?; - graphics::set_blend_mode(ctx, BlendMode::Alpha)?; + graphics::set_blend_mode(ctx, BlendMode::Alpha)?;*/ Ok(()) } @@ -1439,12 +1441,7 @@ impl Scene for GameScene { //graphics::set_canvas(ctx, Some(&state.game_canvas)); self.draw_background(state, ctx)?; self.draw_tiles(state, ctx, TileLayer::Background)?; - if state.settings.shader_effects - && self.stage.data.background_type != BackgroundType::Black - && self.stage.data.background_type != BackgroundType::Outside - && self.stage.data.background_type != BackgroundType::OutsideWind - && self.stage.data.background.name() != "bkBlack" - { + if state.settings.shader_effects { self.draw_light_map(state, ctx)?; } @@ -1469,19 +1466,11 @@ impl Scene for GameScene { self.draw_bullets(state, ctx)?; self.player2.draw(state, ctx, &self.frame)?; self.player1.draw(state, ctx, &self.frame)?; - /*if state.settings.shader_effects && self.water_visible { - self.draw_water(state, ctx)?; - }*/ self.draw_tiles(state, ctx, TileLayer::Foreground)?; self.draw_tiles(state, ctx, TileLayer::Snack)?; self.draw_carets(state, ctx)?; - if state.settings.shader_effects - && (self.stage.data.background_type == BackgroundType::Black - || self.stage.data.background.name() == "bkBlack") - { - self.draw_light_map(state, ctx)?; - } + self.flash.draw(state, ctx, &self.frame)?; /*graphics::set_canvas(ctx, None); @@ -1586,7 +1575,7 @@ impl Scene for GameScene { ctx: &mut Context, ui: &mut imgui::Ui, ) -> GameResult { - components.live_debugger.run_ingame(self, state, ctx, ui)?; + //components.live_debugger.run_ingame(self, state, ctx, ui)?; Ok(()) } } diff --git a/src/sound/org_playback.rs b/src/sound/org_playback.rs index 918ce20..aa4c335 100644 --- a/src/sound/org_playback.rs +++ b/src/sound/org_playback.rs @@ -4,6 +4,7 @@ use crate::sound::organya::{Song as Organya, Version}; use crate::sound::stuff::*; use crate::sound::wav::*; use crate::sound::wave_bank::SoundBank; +use num_traits::Pow; pub(crate) struct OrgPlaybackEngine { song: Organya, @@ -117,11 +118,9 @@ impl OrgPlaybackEngine { .zip(self.track_buffers[128..].iter_mut()) .enumerate() { - if self.song.version == Version::Extended { - *buf = RenderBuffer::new(samples.samples[track.inst.inst as usize].clone()); - } else { - *buf = RenderBuffer::new(samples.samples[idx].clone()); - } + static MAP: [usize; 12] = [0, 0, 1, 0, 4, 2, 3, 0, 5, 0, 0, 0]; + + *buf = RenderBuffer::new(samples.samples[MAP[track.inst.inst as usize]].clone()); } self.song = song; @@ -171,12 +170,14 @@ impl OrgPlaybackEngine { let key = note.key % 12; let p_oct = k % 8; - let freq = org_key_to_freq(key + p_oct * 12, self.song.tracks[track].inst.freq as i16); + //let freq = org_key_to_freq(key + p_oct * 12, self.song.tracks[track].inst.freq as i16); + let freq = 2.0f32.pow((note.key as f32 + self.song.tracks[track].inst.freq as f32 / 1000.0 + 155.376) / 12.0); let l = p_oct as usize * 8 + track + swap; self.track_buffers[l].set_frequency(freq as u32); - self.track_buffers[l] - .organya_select_octave(p_oct as usize, self.song.tracks[track].inst.pipi != 0); + self.track_buffers[l].organya_select_octave(0, self.song.tracks[track].inst.pipi != 0); + //self.track_buffers[l] + // .organya_select_octave(p_oct as usize, self.song.tracks[track].inst.pipi != 0); } self.track_buffers[j].looping = true; self.track_buffers[j].playing = true; @@ -190,11 +191,12 @@ impl OrgPlaybackEngine { if self.song.tracks[track].inst.pipi == 0 { self.track_buffers[j].looping = false; } - self.swaps[track] += 64; - self.swaps[track] %= 128; + //self.swaps[track] += 64; + //self.swaps[track] %= 128; let j = octave as usize + track + self.swaps[track]; - self.track_buffers[j] - .organya_select_octave(note.key as usize / 12, self.song.tracks[track].inst.pipi != 0); + self.track_buffers[j].organya_select_octave(0, self.song.tracks[track].inst.pipi != 0); + //self.track_buffers[j] + // .organya_select_octave(note.key as usize / 12, self.song.tracks[track].inst.pipi != 0); self.track_buffers[j].looping = true; self.track_buffers[j].playing = true; } else { @@ -204,8 +206,8 @@ impl OrgPlaybackEngine { if self.song.tracks[track].inst.pipi == 0 { self.track_buffers[j].looping = false; } - self.swaps[track] += 64; - self.swaps[track] %= 128; + //self.swaps[track] += 64; + //self.swaps[track] %= 128; let octave = (note.key / 12) * 8; let j = octave as usize + track + self.swaps[track]; for k in 0..16 { @@ -213,11 +215,13 @@ impl OrgPlaybackEngine { let key = note.key % 12; let p_oct = k % 8; - let freq = org_key_to_freq(key + p_oct * 12, self.song.tracks[track].inst.freq as i16); + //let freq = org_key_to_freq(key + p_oct * 12, self.song.tracks[track].inst.freq as i16); + let freq = 2.0f32.pow((note.key as f32 + self.song.tracks[track].inst.freq as f32 / 1000.0 + 155.376) / 12.0); let l = p_oct as usize * 8 + track + swap; self.track_buffers[l].set_frequency(freq as u32); - self.track_buffers[l] - .organya_select_octave(p_oct as usize, self.song.tracks[track].inst.pipi != 0); + self.track_buffers[l].organya_select_octave(0, self.song.tracks[track].inst.pipi != 0); + //self.track_buffers[l] + // .organya_select_octave(p_oct as usize, self.song.tracks[track].inst.pipi != 0); } self.track_buffers[j].looping = true; self.track_buffers[j].playing = true; @@ -267,7 +271,8 @@ impl OrgPlaybackEngine { if let Some(note) = notes.iter().find(|x| x.pos == self.play_pos) { // FIXME: Add constants for dummy values if note.key != 255 { - let freq = org_key_to_drum_freq(note.key); + //let freq = org_key_to_drum_freq(note.key); + let freq = note.key as f32 * (22050.0 / 32.5); self.track_buffers[j].set_frequency(freq as u32); self.track_buffers[j].set_position(0); self.track_buffers[j].playing = true; @@ -358,9 +363,9 @@ pub fn mix(dst: &mut [u16], dst_fmt: WavFormat, srcs: &mut [RenderBuffer]) { let r2 = (1.0 - f32::cos(r1 * PI)) / 2.0; //let s = s1; // No interp - //let s = s1 + (s2 - s1) * r1; // Linear interp + let s = s1 + (s2 - s1) * r1; // Linear interp //let s = s1 * (1.0 - r2) + s2 * r2; // Cosine interp - let s = cubic_interp(s1, s2, s4, s3, r1); // Cubic interp + //let s = cubic_interp(s1, s2, s4, s3, r1); // Cubic interp // Ideally we want sinc/lanczos interpolation, since that's what DirectSound appears to use. // -128..128