diff --git a/src/frame.rs b/src/frame.rs index 47eaed2..96b9bc9 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -3,11 +3,22 @@ use crate::shared_game_state::SharedGameState; use crate::stage::Stage; use crate::common::interpolate_fix9_scale; +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u8)] +pub enum UpdateTarget { + Player, + NPC(u16), + Boss(u16), +} + pub struct Frame { pub x: isize, pub y: isize, pub prev_x: isize, pub prev_y: isize, + pub update_target: UpdateTarget, + pub target_x: isize, + pub target_y: isize, pub wait: isize, } @@ -19,11 +30,11 @@ impl Frame { (x, y) } - pub fn immediate_update(&mut self, state: &mut SharedGameState, player: &Player, stage: &Stage) { + pub fn immediate_update(&mut self, state: &mut SharedGameState, stage: &Stage) { if (stage.map.width - 1) * 16 < state.canvas_size.0 as usize { self.x = -(((state.canvas_size.0 as isize - ((stage.map.width - 1) * 16) as isize) * 0x200) / 2); } else { - self.x = player.target_x - (state.canvas_size.0 as isize * 0x200 / 2); + self.x = self.target_x - (state.canvas_size.0 as isize * 0x200 / 2); if self.x < 0 { self.x = 0; @@ -38,7 +49,7 @@ impl Frame { if (stage.map.height - 1) * 16 < state.canvas_size.1 as usize { self.y = -(((state.canvas_size.1 as isize - ((stage.map.height - 1) * 16) as isize) * 0x200) / 2); } else { - self.y = player.target_y - (state.canvas_size.1 as isize * 0x200 / 2); + self.y = self.target_y - (state.canvas_size.1 as isize * 0x200 / 2); if self.y < 0 { self.y = 0; @@ -54,11 +65,11 @@ impl Frame { self.prev_y = self.y; } - pub fn update(&mut self, state: &mut SharedGameState, player: &Player, stage: &Stage) { + pub fn update(&mut self, state: &mut SharedGameState, stage: &Stage) { if (stage.map.width - 1) * 16 < state.canvas_size.0 as usize { self.x = -(((state.canvas_size.0 as isize - ((stage.map.width - 1) * 16) as isize) * 0x200) / 2); } else { - self.x += (player.target_x - (state.canvas_size.0 as isize * 0x200 / 2) - self.x) / self.wait; + self.x += (self.target_x - (state.canvas_size.0 as isize * 0x200 / 2) - self.x) / self.wait; if self.x < 0 { self.x = 0; @@ -73,7 +84,7 @@ impl Frame { if (stage.map.height - 1) * 16 < state.canvas_size.1 as usize { self.y = -(((state.canvas_size.1 as isize - ((stage.map.height - 1) * 16) as isize) * 0x200) / 2); } else { - self.y += (player.target_y - (state.canvas_size.1 as isize * 0x200 / 2) - self.y) / self.wait; + self.y += (self.target_y - (state.canvas_size.1 as isize * 0x200 / 2) - self.y) / self.wait; if self.y < 0 { self.y = 0; diff --git a/src/npc/egg_corridor.rs b/src/npc/egg_corridor.rs index 47e8cfc..4a6cec2 100644 --- a/src/npc/egg_corridor.rs +++ b/src/npc/egg_corridor.rs @@ -608,7 +608,7 @@ impl NPC { } else { self.action_counter2 += 1; if (self.action_counter2 % 8) == 0 && abs(self.x - player.x) < 160 * 0x200 { - let angle = ((player.y - self.y) as f64 / (player.x - self.x) as f64).atan(); + let angle = ((player.y - self.y) as f64 / (player.x - self.x) as f64).atan() + (state.game_rng.range(-6..6) as u8) as f64 * CDEG_RAD; let mut npc = NPCMap::create_npc(84, &state.npc_table); diff --git a/src/player.rs b/src/player.rs index d9d5794..7cd48d6 100644 --- a/src/player.rs +++ b/src/player.rs @@ -44,7 +44,6 @@ pub struct Player { pub down: bool, pub shock_counter: u8, pub current_weapon: u8, - pub update_target: bool, pub stars: u8, pub damage: u16, pub air_counter: u16, @@ -90,7 +89,6 @@ impl Player { index_x: 0, index_y: 0, splash: false, - update_target: true, up: false, down: false, current_weapon: 0, @@ -448,10 +446,8 @@ impl Player { } } - if self.update_target { - self.target_x = self.x + self.index_x; - self.target_y = self.y + self.index_y; - } + self.target_x = self.x + self.index_x; + self.target_y = self.y + self.index_y; if self.vel_x > physics.resist || self.vel_x < -physics.resist { self.x += self.vel_x; diff --git a/src/scene/game_scene.rs b/src/scene/game_scene.rs index c6c1571..0fed6c2 100644 --- a/src/scene/game_scene.rs +++ b/src/scene/game_scene.rs @@ -5,7 +5,7 @@ use crate::bullet::BulletManager; use crate::caret::CaretType; use crate::common::{Direction, FadeDirection, FadeState, fix9_scale, Rect}; use crate::entity::GameEntity; -use crate::frame::Frame; +use crate::frame::{Frame, UpdateTarget}; use crate::ggez::{Context, GameResult, graphics, timer}; use crate::ggez::graphics::{BlendMode, Color, Drawable, DrawParam, FilterMode, Vector2}; use crate::ggez::nalgebra::clamp; @@ -79,6 +79,9 @@ impl GameScene { y: 0, prev_x: 0, prev_y: 0, + update_target: UpdateTarget::Player, + target_x: 0, + target_y: 0, wait: 16, }, stage_id: id, @@ -918,7 +921,7 @@ impl GameScene { self.player.tick_npc_collisions(state, &mut self.npc_map, &mut self.inventory); for npc_id in self.npc_map.npc_ids.iter() { - if let Some(npc_cell) = self.npc_map.npcs.get_mut(npc_id) { + if let Some(npc_cell) = self.npc_map.npcs.get(npc_id) { let mut npc = npc_cell.borrow_mut(); if npc.cond.alive() && !npc.npc_flags.ignore_solidity() { @@ -935,7 +938,31 @@ impl GameScene { self.bullet_manager.tick_bullets(state, &self.player, &mut self.stage); state.tick_carets(); - self.frame.update(state, &self.player, &self.stage); + match self.frame.update_target { + UpdateTarget::Player => { + self.frame.target_x = self.player.target_x; + self.frame.target_y = self.player.target_y; + } + UpdateTarget::NPC(npc_id) => { + if let Some(npc_cell) = self.npc_map.npcs.get(&npc_id) { + let mut npc = npc_cell.borrow(); + + if npc.cond.alive() { + self.frame.target_x = npc.x; + self.frame.target_y = npc.y; + } + } + } + UpdateTarget::Boss(boss_id) => { + if let Some(boss) = self.npc_map.boss_map.parts.get(boss_id as usize) { + if boss.cond.alive() { + self.frame.target_x = boss.x; + self.frame.target_y = boss.y; + } + } + } + } + self.frame.update(state, &self.stage); if state.control_flags.control_enabled() { if let Some(weapon) = self.inventory.get_current_weapon_mut() { @@ -1162,9 +1189,9 @@ impl Scene for GameScene { state.npc_table.tex_npc1_name = ["Npc/", &self.stage.data.npc1.filename()].join(""); state.npc_table.tex_npc2_name = ["Npc/", &self.stage.data.npc2.filename()].join(""); - self.player.target_x = self.player.x; - self.player.target_y = self.player.y; - self.frame.immediate_update(state, &self.player, &self.stage); + self.frame.target_x = self.player.x; + self.frame.target_y = self.player.y; + self.frame.immediate_update(state, &self.stage); Ok(()) } diff --git a/src/text_script.rs b/src/text_script.rs index 8ac3662..180386c 100644 --- a/src/text_script.rs +++ b/src/text_script.rs @@ -28,6 +28,7 @@ use crate::scene::title_scene::TitleScene; use crate::shared_game_state::SharedGameState; use crate::str; use crate::weapon::WeaponType; +use crate::frame::UpdateTarget; /// Engine's text script VM operation codes. #[derive(EnumString, Debug, FromPrimitive, PartialEq)] @@ -49,11 +50,11 @@ pub enum OpCode { /// { + state.start_intro(ctx)?; + break; + } } } @@ -689,7 +695,7 @@ impl TextScriptVM { state.textscript_vm.stack.clear(); game_scene.player.cond.set_interacted(false); - game_scene.player.update_target = true; + game_scene.frame.update_target = UpdateTarget::Player; exec_state = TextScriptExecutionState::Ended; } @@ -894,7 +900,7 @@ impl TextScriptVM { OpCode::SMP => { let pos_x = read_cur_varint(&mut cursor)? as usize; let pos_y = read_cur_varint(&mut cursor)? as usize; - + let tile_type = game_scene.stage.tile_at(pos_x, pos_y); game_scene.stage.change_tile(pos_x, pos_y, tile_type.wrapping_sub(1)); @@ -1100,10 +1106,19 @@ impl TextScriptVM { exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32); } + OpCode::FOB => { + let part_id = read_cur_varint(&mut cursor)? as u16; + let ticks = read_cur_varint(&mut cursor)? as isize; + + game_scene.frame.wait = ticks; + game_scene.frame.update_target = UpdateTarget::Boss(part_id); + + exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32); + } OpCode::FOM => { let ticks = read_cur_varint(&mut cursor)? as isize; game_scene.frame.wait = ticks; - game_scene.player.update_target = true; + game_scene.frame.update_target = UpdateTarget::Player; exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32); } @@ -1111,15 +1126,13 @@ impl TextScriptVM { let event_num = read_cur_varint(&mut cursor)? as u16; let ticks = read_cur_varint(&mut cursor)? as isize; game_scene.frame.wait = ticks; - game_scene.player.update_target = false; for npc_id in game_scene.npc_map.npc_ids.iter() { if let Some(npc_cell) = game_scene.npc_map.npcs.get(npc_id) { let npc = npc_cell.borrow(); if event_num == npc.event_num { - game_scene.player.target_x = npc.x; - game_scene.player.target_y = npc.y; + game_scene.frame.update_target = UpdateTarget::NPC(npc.id); break; } } @@ -1355,8 +1368,10 @@ impl TextScriptVM { exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32); } - // todo: INI starts intro - OpCode::INI | OpCode::ESC => { + OpCode::INI => { + exec_state = TextScriptExecutionState::Reset; + } + OpCode::ESC => { state.next_scene = Some(Box::new(TitleScene::new())); state.control_flags.set_tick_world(false); state.control_flags.set_control_enabled(false);