diff --git a/src/bullet.rs b/src/bullet.rs index ca21efd..907620b 100644 --- a/src/bullet.rs +++ b/src/bullet.rs @@ -32,7 +32,6 @@ impl BulletManager { } bullet.tick(state, player); - bullet.hit_flags.0 = 0; bullet.tick_map_collisions(state, stage); } @@ -450,9 +449,8 @@ impl PhysicalEntity for Bullet { self.vel_y } - #[inline(always)] - fn size(&self) -> u8 { - 1 + fn hit_rect_size(&self) -> usize { + 2 } #[inline(always)] @@ -515,6 +513,7 @@ impl PhysicalEntity for Bullet { let y = clamp(self.y() / 16 / 0x200, 0, stage.map.height as isize); let mut hit_attribs = [0u8; 4]; + self.flags().0 = 0; if self.flags.hit_right_wall() { // ??? return; } diff --git a/src/engine_constants.rs b/src/engine_constants.rs index 3fc09f1..2b88137 100644 --- a/src/engine_constants.rs +++ b/src/engine_constants.rs @@ -148,7 +148,7 @@ pub struct NPCConsts { pub n008_blue_beetle: [Rect; 4], pub n009_balrog_falling_in: [Rect; 6], pub n010_balrog_shooting: [Rect; 8], - pub n011_balrogs_projectile: [Rect; 3], + pub n011_balrog_energy_shot: [Rect; 3], pub n012_balrog_cutscene: [Rect; 28], pub n013_forcefield: [Rect; 4], pub n014_key: [Rect; 3], @@ -156,7 +156,7 @@ pub struct NPCConsts { pub n016_save_point: [Rect; 8], pub n017_health_refill: [Rect; 2], pub n018_door: [Rect; 2], - pub n019_balrog_burst: [Rect; 8], + pub n019_balrog_bust_in: [Rect; 8], pub n020_computer: [Rect; 4], pub n021_chest_open: Rect, pub n022_teleporter: [Rect; 2], @@ -540,7 +540,7 @@ impl EngineConstants { Rect { left: 80, top: 24, right: 120, bottom: 48 }, Rect { left: 120, top: 24, right: 160, bottom: 48 }, ], - n011_balrogs_projectile: [ + n011_balrog_energy_shot: [ Rect { left: 208, top: 104, right: 224, bottom: 120 }, Rect { left: 224, top: 104, right: 240, bottom: 120 }, Rect { left: 240, top: 104, right: 256, bottom: 120 }, @@ -609,7 +609,7 @@ impl EngineConstants { Rect { left: 224, top: 16, right: 240, bottom: 40 }, Rect { left: 192, top: 112, right: 208, bottom: 136 }, ], - n019_balrog_burst: [ + n019_balrog_bust_in: [ Rect { left: 0, top: 0, right: 40, bottom: 24 }, // left Rect { left: 160, top: 0, right: 200, bottom: 24 }, Rect { left: 80, top: 0, right: 120, bottom: 24 }, diff --git a/src/map.rs b/src/map.rs index cb4f6c1..d545244 100644 --- a/src/map.rs +++ b/src/map.rs @@ -55,6 +55,10 @@ impl Map { } pub fn get_attribute(&self, x: usize, y: usize) -> u8 { + if x >= self.width || y >= self.height { + return 0; + } + self.attrib[*self.tiles.get(self.width * y + x).unwrap_or_else(|| &0u8) as usize] } } diff --git a/src/npc/balrog.rs b/src/npc/balrog.rs index 7140214..3e210c4 100644 --- a/src/npc/balrog.rs +++ b/src/npc/balrog.rs @@ -189,7 +189,7 @@ impl NPC { } } - self.anim_rect = state.constants.npc.n011_balrogs_projectile[self.anim_num as usize]; + self.anim_rect = state.constants.npc.n011_balrog_energy_shot[self.anim_num as usize]; self.action_counter2 += 1; if self.action_counter2 > 150 { @@ -591,7 +591,7 @@ impl NPC { } else { self.action_counter += 1; - if self.flags.hit_left_wall() || self.flags.hit_right_wall() || self.action_counter > 75 { + if (self.flags.hit_left_wall() || self.flags.hit_right_wall()) || self.action_counter > 75 { self.action_num = 9; self.anim_num = 0; } else if self.action_counter2 % 3 == 0 && self.action_counter > 25 { diff --git a/src/npc/misc.rs b/src/npc/misc.rs index ffd53f9..ad6de57 100644 --- a/src/npc/misc.rs +++ b/src/npc/misc.rs @@ -1,3 +1,5 @@ +use num_traits::real::Real; + use crate::caret::CaretType; use crate::common::Direction; use crate::ggez::GameResult; @@ -5,17 +7,22 @@ use crate::npc::{NPC, NPCMap}; use crate::player::Player; use crate::shared_game_state::SharedGameState; use crate::stage::Stage; -use num_traits::real::Real; impl NPC { pub(crate) fn tick_n000_null(&mut self) -> GameResult { - if self.action_num != 0xffff { - self.action_num = 0xffff; - self.anim_rect.left = 0; - self.anim_rect.top = 0; - self.anim_rect.right = 0; - self.anim_rect.bottom = 0; + if self.action_num == 0 { + self.action_num = 1; + + if self.direction == Direction::Right { + self.y += 16 * 0x200; + } } + + self.anim_rect.left = 0; + self.anim_rect.top = 0; + self.anim_rect.right = 16; + self.anim_rect.bottom = 16; + Ok(()) } diff --git a/src/npc/mod.rs b/src/npc/mod.rs index d3f31d2..ad95699 100644 --- a/src/npc/mod.rs +++ b/src/npc/mod.rs @@ -191,29 +191,25 @@ impl GameEntity<(&mut Player, &HashMap>, &mut Stage)> for NPC impl PhysicalEntity for NPC { #[inline(always)] - fn x(&self) -> isize { - self.x - } + fn x(&self) -> isize { self.x } #[inline(always)] - fn y(&self) -> isize { - self.y - } + fn y(&self) -> isize { self.y } #[inline(always)] - fn vel_x(&self) -> isize { - self.vel_x - } + fn vel_x(&self) -> isize { self.vel_x } #[inline(always)] - fn vel_y(&self) -> isize { - self.vel_y - } + fn vel_y(&self) -> isize { self.vel_y } #[inline(always)] - fn size(&self) -> u8 { - self.size - } + fn hit_rect_size(&self) -> usize { if self.size >= 3 { 3 } else { 2 } } + + #[inline(always)] + fn offset_x(&self) -> isize { if self.size >= 3 { -0x1000 } else { 0 } } + + #[inline(always)] + fn offset_y(&self) -> isize { if self.size >= 3 { -0x1000 } else { 0 } } #[inline(always)] fn hit_bounds(&self) -> &Rect { diff --git a/src/physics.rs b/src/physics.rs index 163b0e1..a68e070 100644 --- a/src/physics.rs +++ b/src/physics.rs @@ -5,8 +5,14 @@ use crate::common::{Condition, Direction, Flag, Rect}; use crate::shared_game_state::SharedGameState; use crate::stage::Stage; -pub const OFF_X: [isize; 9] = [0, 1, 0, 1, 2, 2, 2, 0, 1]; -pub const OFF_Y: [isize; 9] = [0, 0, 1, 1, 0, 1, 2, 2, 2]; +// -1 0 1 2 +// +------------ +// -1 | 10 14 15 16 +// 0 | 11 1 2 5 +// 1 | 12 3 4 6 +// 2 | 13 8 9 7 +pub const OFF_X: [isize; 16] = [0, 1, 0, 1, 2, 2, 2, 0, 1, -1, -1, -1, -1, 0, 1, 2]; +pub const OFF_Y: [isize; 16] = [0, 0, 1, 1, 0, 1, 2, 2, 2, -1, 0, 1, 2, -1, -1, -1]; pub trait PhysicalEntity { fn x(&self) -> isize; @@ -14,7 +20,9 @@ pub trait PhysicalEntity { fn vel_x(&self) -> isize; fn vel_y(&self) -> isize; - fn size(&self) -> u8; + fn hit_rect_size(&self) -> usize; + fn offset_x(&self) -> isize { 0 } + fn offset_y(&self) -> isize { 0 } fn hit_bounds(&self) -> &Rect; @@ -31,11 +39,11 @@ pub trait PhysicalEntity { fn ignore_tile_44(&self) -> bool { true } fn judge_hit_block(&mut self, state: &mut SharedGameState, x: isize, y: isize) { - let bounds_x = 5; + let bounds_x = if self.is_player() { 5 } else { 8 }; let bounds_y = if self.is_player() { 4 } else { 5 }; // left wall if (self.y() - self.hit_bounds().top as isize) < (y * 16 + bounds_y) * 0x200 - && self.y() + self.hit_bounds().bottom as isize > (y * 16 - bounds_y) * 0x200 + && (self.y() + self.hit_bounds().bottom as isize) > (y * 16 - bounds_y) * 0x200 && (self.x() - self.hit_bounds().right as isize) < (x * 16 + 8) * 0x200 && (self.x() - self.hit_bounds().right as isize) > x * 16 * 0x200 { self.set_x(((x * 16 + 8) * 0x200) + self.hit_bounds().right as isize); @@ -100,8 +108,8 @@ pub trait PhysicalEntity { // floor if ((self.x() - self.hit_bounds().right as isize) < (x * 16 + bounds_x) * 0x200) && ((self.x() + self.hit_bounds().right as isize) > (x * 16 - bounds_x) * 0x200) - && ((self.y() + self.hit_bounds().bottom as isize) > (y * 16 - 8) * 0x200) - && ((self.y() + self.hit_bounds().bottom as isize) < y * 16 * 0x200) { + && ((self.y() + self.hit_bounds().bottom as isize) > ((y * 16 - 8) * 0x200)) + && ((self.y() + self.hit_bounds().bottom as isize) < (y * 16 * 0x200)) { self.set_y(((y * 16 - 8) * 0x200) - self.hit_bounds().bottom as isize); if self.is_player() { @@ -344,12 +352,15 @@ pub trait PhysicalEntity { } fn tick_map_collisions(&mut self, state: &mut SharedGameState, stage: &mut Stage) { - let big = self.size() >= 3; - let x = clamp((self.x() - if big { 0x1000 } else { 0 }) / 16 / 0x200, 0, stage.map.width as isize); - let y = clamp((self.y() - if big { 0x1000 } else { 0 }) / 16 / 0x200, 0, stage.map.height as isize); + let hit_rect_size = clamp(self.hit_rect_size(), 1, 4); + let hit_rect_size = hit_rect_size * hit_rect_size; + let x = clamp((self.x() + self.offset_x()) / 16 / 0x200, 0, stage.map.width as isize); + let y = clamp((self.y() + self.offset_y()) / 16 / 0x200, 0, stage.map.height as isize); + + self.flags().0 = 0; for (idx, (&ox, &oy)) in OFF_X.iter().zip(OFF_Y.iter()).enumerate() { - if idx == 4 && !big { + if idx == hit_rect_size { break; } @@ -368,12 +379,12 @@ pub trait PhysicalEntity { self.judge_hit_water(x + ox, y + oy); } 0x61 => { - self.judge_hit_water(x + ox, y + oy); self.judge_hit_block(state, x + ox, y + oy); + self.judge_hit_water(x + ox, y + oy); } 0x04 | 0x64 if !self.is_player() => { - self.judge_hit_water(x + ox, y + oy); self.judge_hit_block(state, x + ox, y + oy); + self.judge_hit_water(x + ox, y + oy); } 0x05 | 0x41 | 0x43 | 0x46 if self.is_player() => { self.judge_hit_block(state, x + ox, y + oy); @@ -423,16 +434,16 @@ pub trait PhysicalEntity { // Forces 0x80 | 0xa0 if self.is_player() => { - self.judge_hit_force(x + ox, y + ox, Direction::Left, attrib & 0x20 != 0); + self.judge_hit_force(x + ox, y + oy, Direction::Left, attrib & 0x20 != 0); } 0x81 | 0xa1 if self.is_player() => { - self.judge_hit_force(x + ox, y + ox, Direction::Up, attrib & 0x20 != 0); + self.judge_hit_force(x + ox, y + oy, Direction::Up, attrib & 0x20 != 0); } 0x82 | 0xa2 if self.is_player() => { - self.judge_hit_force(x + ox, y + ox, Direction::Right, attrib & 0x20 != 0); + self.judge_hit_force(x + ox, y + oy, Direction::Right, attrib & 0x20 != 0); } 0x83 | 0xa3 if self.is_player() => { - self.judge_hit_force(x + ox, y + ox, Direction::Bottom, attrib & 0x20 != 0); + self.judge_hit_force(x + ox, y + oy, Direction::Bottom, attrib & 0x20 != 0); } 0x80 | 0xa0 if !self.is_player() => { self.flags().set_force_left(true); diff --git a/src/player_hit.rs b/src/player_hit.rs index 92a7b25..1bdee26 100644 --- a/src/player_hit.rs +++ b/src/player_hit.rs @@ -29,9 +29,8 @@ impl PhysicalEntity for Player { self.vel_y } - #[inline(always)] - fn size(&self) -> u8 { - 1 + fn hit_rect_size(&self) -> usize { + 2 } #[inline(always)] diff --git a/src/scene/game_scene.rs b/src/scene/game_scene.rs index 2407109..3f31cd6 100644 --- a/src/scene/game_scene.rs +++ b/src/scene/game_scene.rs @@ -871,7 +871,6 @@ impl GameScene { self.npc_map.process_npc_changes(state); self.npc_map.garbage_collect(); - self.player.flags.0 = 0; self.player.tick_map_collisions(state, &mut self.stage); self.player.tick_npc_collisions(state, &mut self.npc_map, &mut self.inventory); @@ -880,7 +879,6 @@ impl GameScene { let mut npc = npc_cell.borrow_mut(); if npc.cond.alive() && !npc.npc_flags.ignore_solidity() { - npc.flags.0 = 0; npc.tick_map_collisions(state, &mut self.stage); } } @@ -1022,25 +1020,25 @@ impl GameScene { } // top - state.texture_set.draw_rect(Rect::new_size((npc.x - npc.hit_bounds.left as isize - self.frame.x) / 0x200, + state.texture_set.draw_rect(Rect::new_size((npc.x - npc.hit_bounds.right as isize - self.frame.x) / 0x200, (npc.y - npc.hit_bounds.top as isize - self.frame.y) / 0x200, - (npc.hit_bounds.left + npc.hit_bounds.right) as isize / 0x200, + (npc.hit_bounds.right + npc.hit_bounds.right) as isize / 0x200, 1), [0.0, if npc.flags.hit_top_wall() { 1.0 } else { 0.0 }, 1.0, 1.0], ctx)?; // bottom - state.texture_set.draw_rect(Rect::new_size((npc.x - npc.hit_bounds.left as isize - self.frame.x) / 0x200, - (npc.y + npc.hit_bounds.bottom as isize - self.frame.y) / 0x200, - (npc.hit_bounds.left + npc.hit_bounds.right) as isize / 0x200, + state.texture_set.draw_rect(Rect::new_size((npc.x - npc.hit_bounds.right as isize - self.frame.x) / 0x200, + (npc.y + npc.hit_bounds.bottom as isize - self.frame.y) / 0x200 - 1, + (npc.hit_bounds.right + npc.hit_bounds.right) as isize / 0x200, 1), [0.0, if npc.flags.hit_bottom_wall() { 1.0 } else { 0.0 }, 1.0, 1.0], ctx)?; // left - state.texture_set.draw_rect(Rect::new_size((npc.x - npc.hit_bounds.left as isize - self.frame.x) / 0x200, + state.texture_set.draw_rect(Rect::new_size((npc.x - npc.hit_bounds.right as isize - self.frame.x) / 0x200, (npc.y - npc.hit_bounds.top as isize - self.frame.y) / 0x200, 1, (npc.hit_bounds.top + npc.hit_bounds.bottom) as isize / 0x200), [0.0, if npc.flags.hit_left_wall() { 1.0 } else { 0.0 }, 1.0, 1.0], ctx)?; // right - state.texture_set.draw_rect(Rect::new_size((npc.x + npc.hit_bounds.right as isize - self.frame.x) / 0x200, + state.texture_set.draw_rect(Rect::new_size((npc.x + npc.hit_bounds.right as isize - self.frame.x) / 0x200 - 1, (npc.y - npc.hit_bounds.top as isize - self.frame.y) / 0x200, 1, (npc.hit_bounds.top + npc.hit_bounds.bottom) as isize / 0x200),