mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2025-12-08 13:08:30 +00:00
Use HitExtents instead of Rect for hitboxes
This commit is contained in:
parent
f4602687eb
commit
2335cf0064
|
|
@ -279,10 +279,20 @@ impl<T: Num + PartialOrd + Copy> Rect<T> {
|
|||
Rect { left: x, top: y, right: x.add(width), bottom: y.add(height) }
|
||||
}
|
||||
|
||||
pub fn has_point(&self, x: T, y: T) -> bool {
|
||||
/**
|
||||
* Returns true if the point (x, y) is inside the rectangle (inclusive).
|
||||
*/
|
||||
pub fn has_point_incl(&self, x: T, y: T) -> bool {
|
||||
self.left.ge(&x) && self.right.le(&x) && self.top.ge(&y) && self.bottom.le(&y)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the point (x, y) is inside the rectangle (exclusive).
|
||||
*/
|
||||
pub fn has_point_excl(&self, x: T, y: T) -> bool {
|
||||
self.left.le(&x) && self.right.gt(&x) && self.top.le(&y) && self.bottom.gt(&y)
|
||||
}
|
||||
|
||||
pub fn width(&self) -> T {
|
||||
if self.left.gt(&self.right) {
|
||||
self.left.sub(self.right)
|
||||
|
|
|
|||
|
|
@ -4,9 +4,10 @@ use crate::common::{Direction, Rect};
|
|||
use crate::components::flash::Flash;
|
||||
use crate::framework::error::GameResult;
|
||||
use crate::game::caret::CaretType;
|
||||
use crate::game::npc::{NPC, NPCLayer};
|
||||
use crate::game::npc::boss::BossNPC;
|
||||
use crate::game::npc::list::NPCList;
|
||||
use crate::game::npc::{NPCLayer, NPC};
|
||||
use crate::game::physics::HitExtents;
|
||||
use crate::game::player::Player;
|
||||
use crate::game::shared_game_state::{GameDifficulty, SharedGameState};
|
||||
use crate::game::stage::Stage;
|
||||
|
|
@ -196,11 +197,11 @@ impl NPC {
|
|||
if self.action_num == 0 {
|
||||
self.npc_flags.set_interactable(true);
|
||||
self.action_num = 1;
|
||||
|
||||
|
||||
if self.direction == Direction::Right {
|
||||
self.npc_flags.set_interactable(false);
|
||||
self.vel_y = -0x200;
|
||||
|
||||
|
||||
//Creates smoke
|
||||
let mut npc = NPC::create(4, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
|
|
@ -235,7 +236,7 @@ impl NPC {
|
|||
pub(crate) fn tick_n017_health_refill(&mut self, state: &mut SharedGameState, npc_list: &NPCList) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
|
||||
|
||||
//Creates smoke when spawned in a shelter
|
||||
if self.direction == Direction::Right {
|
||||
self.vel_y = -0x200;
|
||||
|
|
@ -659,9 +660,9 @@ impl NPC {
|
|||
self.action_counter += 1;
|
||||
if self.action_counter > 10
|
||||
&& (self.flags.hit_left_wall()
|
||||
|| self.flags.hit_right_wall()
|
||||
|| self.flags.hit_bottom_wall()
|
||||
|| self.flags.in_water())
|
||||
|| self.flags.hit_right_wall()
|
||||
|| self.flags.hit_bottom_wall()
|
||||
|| self.flags.in_water())
|
||||
{
|
||||
// hit something
|
||||
self.cond.set_alive(false);
|
||||
|
|
@ -1996,7 +1997,7 @@ impl NPC {
|
|||
// Big Block
|
||||
self.anim_rect = Rect::new(0, 64, 32, 96);
|
||||
self.display_bounds = Rect::new(0x2000, 0x2000, 0x2000, 0x2000);
|
||||
self.hit_bounds = Rect::new(0x1800, 0x1800, 0x1800, 0x1800);
|
||||
self.hit_bounds = HitExtents { left: 0x1800, top: 0x1800, right: 0x1800, bottom: 0x1800 };
|
||||
} else {
|
||||
// Small Blocks
|
||||
let scale = state.tile_size.as_int() as u16;
|
||||
|
|
@ -2080,7 +2081,7 @@ impl NPC {
|
|||
self.npc_flags.set_invulnerable(true);
|
||||
self.anim_num = 1;
|
||||
self.display_bounds = Rect::new(0x1000, 0x1000, 0x1000, 0x1000);
|
||||
self.hit_bounds = Rect::new(0x1000, 0x1000, 0x1000, 0x1000);
|
||||
self.hit_bounds = HitExtents { left: 0x1000, top: 0x1000, right: 0x1000, bottom: 0x1000 };
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
|
@ -2091,7 +2092,7 @@ impl NPC {
|
|||
self.action_num = 11;
|
||||
self.action_counter = 16;
|
||||
}
|
||||
|
||||
|
||||
self.action_counter = self.action_counter.saturating_sub(2);
|
||||
if self.action_counter == 0 {
|
||||
self.action_num = 100;
|
||||
|
|
@ -2204,11 +2205,11 @@ impl NPC {
|
|||
npc.cond.set_alive(true);
|
||||
npc.x = self.x
|
||||
+ if player.equip.has_booster_2_0() {
|
||||
self.rng.range(-14..14)
|
||||
} else {
|
||||
self.rng.range(-11..11)
|
||||
} * state.tile_size.as_int()
|
||||
* 0x200;
|
||||
self.rng.range(-14..14)
|
||||
} else {
|
||||
self.rng.range(-11..11)
|
||||
} * state.tile_size.as_int()
|
||||
* 0x200;
|
||||
npc.y = player.y - 0x1C000;
|
||||
npc.direction = if self.rng.range(0..10) & 1 != 0 { Direction::Left } else { Direction::Right };
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use crate::game::caret::CaretType;
|
|||
use crate::game::npc::boss::BossNPC;
|
||||
use crate::game::npc::list::NPCList;
|
||||
use crate::game::npc::NPC;
|
||||
use crate::game::physics::HitExtents;
|
||||
use crate::game::player::Player;
|
||||
use crate::game::shared_game_state::SharedGameState;
|
||||
use crate::util::rng::RNG;
|
||||
|
|
@ -42,7 +43,7 @@ impl BossNPC {
|
|||
self.parts[0].direction = Direction::Right;
|
||||
self.parts[0].display_bounds =
|
||||
Rect { left: 48 * 0x200, top: 48 * 0x200, right: 32 * 0x200, bottom: 0x2000 };
|
||||
self.parts[0].hit_bounds = Rect { left: 24 * 0x200, top: 0x2000, right: 24 * 0x200, bottom: 0x2000 };
|
||||
self.parts[0].hit_bounds = HitExtents { left: 24 * 0x200, top: 0x2000, right: 24 * 0x200, bottom: 0x2000 };
|
||||
self.parts[0].size = 3;
|
||||
self.parts[0].exp = 1;
|
||||
self.parts[0].event_num = 1000;
|
||||
|
|
@ -478,12 +479,12 @@ impl BossNPC {
|
|||
self.hurt_sound[1] = 52;
|
||||
self.parts[1].size = 3;
|
||||
self.parts[1].npc_flags.set_invulnerable(true);
|
||||
self.parts[1].hit_bounds = Rect { left: 0x2000, top: 0x2000, right: 0x2000, bottom: 0x2000 };
|
||||
self.parts[1].hit_bounds = HitExtents { left: 0x2000, top: 0x2000, right: 0x2000, bottom: 0x2000 };
|
||||
|
||||
self.hurt_sound[2] = 52;
|
||||
self.parts[2].size = 3;
|
||||
self.parts[2].npc_flags.set_invulnerable(true);
|
||||
self.parts[2].hit_bounds = Rect { left: 24 * 0x200, top: 0x2000, right: 24 * 0x200, bottom: 0x2000 };
|
||||
self.parts[2].hit_bounds = HitExtents { left: 24 * 0x200, top: 0x2000, right: 24 * 0x200, bottom: 0x2000 };
|
||||
}
|
||||
1 => {
|
||||
self.parts[1].x = self.parts[0].x + self.parts[0].direction.vector_x() * 24 * 0x200;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
use crate::common::{CDEG_RAD, Direction, Rect};
|
||||
use crate::common::{Direction, Rect, CDEG_RAD};
|
||||
use crate::components::flash::Flash;
|
||||
use crate::framework::error::GameResult;
|
||||
use crate::game::caret::CaretType;
|
||||
use crate::game::npc::boss::BossNPC;
|
||||
use crate::game::npc::list::NPCList;
|
||||
use crate::game::npc::NPC;
|
||||
use crate::game::physics::HitExtents;
|
||||
use crate::game::player::Player;
|
||||
use crate::game::shared_game_state::SharedGameState;
|
||||
use crate::game::stage::Stage;
|
||||
|
|
@ -1430,7 +1431,7 @@ impl BossNPC {
|
|||
self.parts[0].x = 0x28000;
|
||||
self.parts[0].y = -0x8000;
|
||||
self.hurt_sound[0] = 54;
|
||||
self.parts[0].hit_bounds = Rect { left: 0x4000, top: 0x6000, right: 0x4000, bottom: 0x6000 };
|
||||
self.parts[0].hit_bounds = HitExtents { left: 0x4000, top: 0x6000, right: 0x4000, bottom: 0x6000 };
|
||||
self.parts[0].npc_flags.set_ignore_solidity(true);
|
||||
self.parts[0].npc_flags.set_solid_hard(true);
|
||||
self.parts[0].npc_flags.set_event_when_killed(true);
|
||||
|
|
@ -1445,7 +1446,7 @@ impl BossNPC {
|
|||
self.parts[1].direction = Direction::Left;
|
||||
self.parts[1].npc_flags.set_ignore_solidity(true);
|
||||
self.parts[1].display_bounds = Rect { left: 0x1800, top: 0, right: 0x1800, bottom: 0x2000 };
|
||||
self.parts[1].hit_bounds = Rect { left: 0x1800, top: 0, right: 0x1800, bottom: 0x2000 };
|
||||
self.parts[1].hit_bounds = HitExtents { left: 0x1800, top: 0, right: 0x1800, bottom: 0x2000 };
|
||||
|
||||
self.parts[2] = self.parts[1].clone();
|
||||
self.parts[2].direction = Direction::Right;
|
||||
|
|
@ -1456,21 +1457,21 @@ impl BossNPC {
|
|||
self.parts[3].npc_flags.set_invulnerable(true);
|
||||
self.parts[3].npc_flags.set_ignore_solidity(true);
|
||||
self.parts[3].display_bounds = Rect { left: 0x7800, top: 0x7800, right: 0x7800, bottom: 0x7800 };
|
||||
self.parts[3].hit_bounds = Rect { left: 0x6000, top: 0x3000, right: 0x6000, bottom: 0x4000 };
|
||||
self.parts[3].hit_bounds = HitExtents { left: 0x6000, top: 0x3000, right: 0x6000, bottom: 0x4000 };
|
||||
|
||||
self.parts[4].cond.set_alive(true);
|
||||
self.parts[4].cond.set_damage_boss(true);
|
||||
self.parts[4].npc_flags.set_solid_soft(true);
|
||||
self.parts[4].npc_flags.set_invulnerable(true);
|
||||
self.parts[4].npc_flags.set_ignore_solidity(true);
|
||||
self.parts[4].hit_bounds = Rect { left: 0x4000, top: 0x1000, right: 0x4000, bottom: 0x1000 };
|
||||
self.parts[4].hit_bounds = HitExtents { left: 0x4000, top: 0x1000, right: 0x4000, bottom: 0x1000 };
|
||||
|
||||
self.parts[5].cond.set_alive(true);
|
||||
self.parts[5].cond.set_damage_boss(true);
|
||||
self.parts[5].npc_flags.set_solid_hard(true);
|
||||
self.parts[5].npc_flags.set_invulnerable(true);
|
||||
self.parts[5].npc_flags.set_ignore_solidity(true);
|
||||
self.parts[5].hit_bounds = Rect { left: 0x4000, top: 0, right: 0x4000, bottom: 0x6000 };
|
||||
self.parts[5].hit_bounds = HitExtents { left: 0x4000, top: 0, right: 0x4000, bottom: 0x6000 };
|
||||
}
|
||||
100 | 101 => {
|
||||
if self.parts[0].action_num == 100 {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use crate::framework::error::GameResult;
|
|||
use crate::game::npc::boss::BossNPC;
|
||||
use crate::game::npc::list::NPCList;
|
||||
use crate::game::npc::NPC;
|
||||
use crate::game::physics::HitExtents;
|
||||
use crate::game::shared_game_state::SharedGameState;
|
||||
use crate::game::stage::Stage;
|
||||
use crate::util::rng::RNG;
|
||||
|
|
@ -62,7 +63,7 @@ impl BossNPC {
|
|||
self.parts[0].x = 0;
|
||||
self.parts[0].y = 0;
|
||||
self.parts[0].display_bounds = Rect { left: 0x5000, top: 0x7800, right: 0x5000, bottom: 0x7800 };
|
||||
self.parts[0].hit_bounds = Rect { left: 0x6200, top: 0x7800, right: 0x5000, bottom: 0x6000 };
|
||||
self.parts[0].hit_bounds = HitExtents { left: 0x6200, top: 0x7800, right: 0x5000, bottom: 0x6000 };
|
||||
self.hurt_sound[0] = 54;
|
||||
self.parts[0].npc_flags.set_ignore_solidity(true);
|
||||
self.parts[0].npc_flags.set_solid_hard(true);
|
||||
|
|
@ -139,14 +140,14 @@ impl BossNPC {
|
|||
self.parts[1].cond.set_alive(true);
|
||||
self.parts[1].npc_flags.set_invulnerable(true);
|
||||
self.parts[1].npc_flags.set_ignore_solidity(true);
|
||||
self.parts[1].hit_bounds = Rect { left: 0x1C00, top: 0x1000, right: 0x1C00, bottom: 0x1000 };
|
||||
self.parts[1].hit_bounds = HitExtents { left: 0x1C00, top: 0x1000, right: 0x1C00, bottom: 0x1000 };
|
||||
|
||||
self.parts[2] = self.parts[1].clone();
|
||||
|
||||
self.parts[3].cond.set_alive(true);
|
||||
self.parts[3].cond.set_damage_boss(true);
|
||||
self.parts[3].npc_flags.set_shootable(true);
|
||||
self.parts[3].hit_bounds = Rect { left: 0xC00, top: 0x1000, right: 0xC00, bottom: 0x1000 };
|
||||
self.parts[3].hit_bounds = HitExtents { left: 0xC00, top: 0x1000, right: 0xC00, bottom: 0x1000 };
|
||||
|
||||
let mut npc = NPC::create(325, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
|
|
@ -162,7 +163,8 @@ impl BossNPC {
|
|||
// This relies heavily on the map not being changed
|
||||
// Need to calculate offset from the default starting location
|
||||
for i in 0..5 {
|
||||
let extra_smoke = if stage.change_tile(i + 8, self.parts[0].action_counter3 as usize, 0) { 3 } else { 0 };
|
||||
let extra_smoke =
|
||||
if stage.change_tile(i + 8, self.parts[0].action_counter3 as usize, 0) { 3 } else { 0 };
|
||||
npc_list.create_death_smoke(
|
||||
(i as i32 + 8) * 0x2000,
|
||||
self.parts[0].action_counter3 as i32 * 0x2000,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use crate::framework::error::GameResult;
|
|||
use crate::game::npc::boss::BossNPC;
|
||||
use crate::game::npc::list::NPCList;
|
||||
use crate::game::npc::NPC;
|
||||
use crate::game::physics::HitExtents;
|
||||
use crate::game::player::Player;
|
||||
use crate::game::shared_game_state::SharedGameState;
|
||||
use crate::util::rng::RNG;
|
||||
|
|
@ -198,7 +199,7 @@ impl BossNPC {
|
|||
self.parts[0].event_num = 1000;
|
||||
self.parts[0].life = 400;
|
||||
self.parts[0].display_bounds = Rect::new(0x5000, 0x1800, 0x3000, 0x1800);
|
||||
self.parts[0].hit_bounds = Rect::new(0x2000, 0x1400, 0x2000, 0x1400);
|
||||
self.parts[0].hit_bounds = HitExtents { left: 0x2000, top: 0x1400, right: 0x2000, bottom: 0x1400 };
|
||||
}
|
||||
100 | 101 => {
|
||||
if self.parts[0].action_num == 100 {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
use num_traits::{abs, clamp};
|
||||
|
||||
use crate::common::{CDEG_RAD, Direction, Rect};
|
||||
use crate::common::{Direction, Rect, CDEG_RAD};
|
||||
use crate::components::flash::Flash;
|
||||
use crate::framework::error::GameResult;
|
||||
use crate::game::caret::CaretType;
|
||||
use crate::game::npc::boss::BossNPC;
|
||||
use crate::game::npc::list::NPCList;
|
||||
use crate::game::npc::NPC;
|
||||
use crate::game::physics::HitExtents;
|
||||
use crate::game::player::Player;
|
||||
use crate::game::shared_game_state::SharedGameState;
|
||||
use crate::util::rng::RNG;
|
||||
|
|
@ -39,7 +40,8 @@ impl NPC {
|
|||
|
||||
let player = self.get_closest_player_mut(players);
|
||||
// Get angle between 0 and 2*PI
|
||||
let direction = f64::atan2((self.y - player.y) as f64, (self.x - player.x) as f64) + std::f64::consts::PI;
|
||||
let direction =
|
||||
f64::atan2((self.y - player.y) as f64, (self.x - player.x) as f64) + std::f64::consts::PI;
|
||||
|
||||
if direction < radians {
|
||||
if radians - direction < std::f64::consts::PI {
|
||||
|
|
@ -156,7 +158,7 @@ impl BossNPC {
|
|||
self.parts[0].size = 3;
|
||||
self.parts[0].event_num = 1000;
|
||||
self.parts[0].hit_bounds =
|
||||
Rect { left: 24 * 0x200, top: 24 * 0x200, right: 24 * 0x200, bottom: 24 * 0x200 };
|
||||
HitExtents { left: 24 * 0x200, top: 24 * 0x200, right: 24 * 0x200, bottom: 24 * 0x200 };
|
||||
self.parts[0].npc_flags.set_ignore_solidity(true);
|
||||
self.parts[0].npc_flags.set_event_when_killed(true);
|
||||
self.parts[0].npc_flags.set_show_damage(true);
|
||||
|
|
@ -178,7 +180,7 @@ impl BossNPC {
|
|||
self.parts[3].target_x = 0;
|
||||
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 };
|
||||
HitExtents { left: 5 * 0x200, top: 5 * 0x200, right: 5 * 0x200, bottom: 5 * 0x200 };
|
||||
self.parts[3].npc_flags.set_ignore_solidity(true);
|
||||
|
||||
self.parts[4] = self.parts[3].clone();
|
||||
|
|
@ -203,7 +205,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 = HitExtents { left: 0x1000, top: 24 * 0x200, right: 0x1000, bottom: 0x2000 };
|
||||
self.parts[7].npc_flags.set_ignore_solidity(true);
|
||||
self.hurt_sound[7] = 52;
|
||||
|
||||
|
|
@ -215,7 +217,8 @@ 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 =
|
||||
HitExtents { 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);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use crate::game::caret::CaretType;
|
|||
use crate::game::npc::boss::BossNPC;
|
||||
use crate::game::npc::list::NPCList;
|
||||
use crate::game::npc::NPC;
|
||||
use crate::game::physics::HitExtents;
|
||||
use crate::game::player::Player;
|
||||
use crate::game::shared_game_state::SharedGameState;
|
||||
use crate::game::weapon::bullet::BulletManager;
|
||||
|
|
@ -74,7 +75,7 @@ impl BossNPC {
|
|||
self.parts[0].target_y = self.parts[0].y;
|
||||
self.parts[0].display_bounds =
|
||||
Rect { left: 40 * 0x200, top: 40 * 0x200, right: 40 * 0x200, bottom: 0x2000 };
|
||||
self.parts[0].hit_bounds = Rect { left: 0x1000, top: 24 * 0x200, right: 0x1000, bottom: 0x2000 };
|
||||
self.parts[0].hit_bounds = HitExtents { left: 0x1000, top: 24 * 0x200, right: 0x1000, bottom: 0x2000 };
|
||||
self.hurt_sound[0] = 52;
|
||||
|
||||
self.parts[1].cond.set_alive(true);
|
||||
|
|
@ -94,7 +95,7 @@ impl BossNPC {
|
|||
self.parts[3].x = self.parts[0].x + 0x2000;
|
||||
self.parts[3].y = self.parts[0].y;
|
||||
self.parts[3].display_bounds = Rect { left: 24 * 0x200, top: 0x2000, right: 0x2000, bottom: 0x2000 };
|
||||
self.parts[3].hit_bounds = Rect { left: 0x1000, top: 0x1000, right: 0x1000, bottom: 0x1000 };
|
||||
self.parts[3].hit_bounds = HitExtents { left: 0x1000, top: 0x1000, right: 0x1000, bottom: 0x1000 };
|
||||
self.hurt_sound[3] = 52;
|
||||
|
||||
self.parts[4].cond.set_alive(true);
|
||||
|
|
@ -421,7 +422,8 @@ impl BossNPC {
|
|||
self.parts[5].action_num = 1;
|
||||
self.parts[5].npc_flags.set_solid_soft(true);
|
||||
self.parts[5].npc_flags.set_ignore_solidity(true);
|
||||
self.parts[5].hit_bounds = Rect { left: 20 * 0x200, top: 36 * 0x200, right: 20 * 0x200, bottom: 0x2000 };
|
||||
self.parts[5].hit_bounds =
|
||||
HitExtents { left: 20 * 0x200, top: 36 * 0x200, right: 20 * 0x200, bottom: 0x2000 };
|
||||
}
|
||||
|
||||
self.parts[5].x = self.parts[0].x;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
use crate::common::{CDEG_RAD, Direction, Rect, SliceExt};
|
||||
use crate::common::{Direction, Rect, SliceExt, CDEG_RAD};
|
||||
use crate::components::flash::Flash;
|
||||
use crate::game::npc::boss::BossNPC;
|
||||
use crate::game::npc::list::NPCList;
|
||||
use crate::game::npc::NPC;
|
||||
use crate::game::physics::HitExtents;
|
||||
use crate::game::player::Player;
|
||||
use crate::game::shared_game_state::SharedGameState;
|
||||
use crate::util::rng::RNG;
|
||||
|
|
@ -24,7 +25,7 @@ impl BossNPC {
|
|||
self.parts[0].x = 0x14000 + (state.constants.game.tile_offset_x * 0x2000);
|
||||
self.parts[0].y = 0x10000;
|
||||
self.parts[0].display_bounds = Rect::new(0x1000, 0x1000, 0x10000, 0x1000);
|
||||
self.parts[0].hit_bounds = Rect::new(0x1000, 0x1000, 0x1000, 0x1000);
|
||||
self.parts[0].hit_bounds = HitExtents { left: 0x1000, top: 0x1000, right: 0x1000, bottom: 0x1000 };
|
||||
self.hurt_sound[0] = 54;
|
||||
self.parts[0].npc_flags.set_ignore_solidity(true);
|
||||
self.parts[0].npc_flags.set_event_when_killed(true);
|
||||
|
|
@ -37,7 +38,7 @@ impl BossNPC {
|
|||
self.parts[0].target_y = 0x3D;
|
||||
|
||||
self.parts[2].display_bounds = Rect::new(0x2800, 0x2000, 0x2800, 0x2000);
|
||||
self.parts[2].hit_bounds = Rect::new(0x1800, 0x1400, 0x1800, 0x1400);
|
||||
self.parts[2].hit_bounds = HitExtents { left: 0x1800, top: 0x1400, right: 0x1800, bottom: 0x1400 };
|
||||
self.parts[2].npc_flags.set_ignore_solidity(true);
|
||||
self.parts[2].npc_flags.set_invulnerable(true);
|
||||
self.parts[2].parent_id = 3;
|
||||
|
|
@ -47,7 +48,7 @@ impl BossNPC {
|
|||
|
||||
self.parts[3].cond.set_alive(true);
|
||||
self.parts[3].display_bounds = Rect::new(0x2800, 0x2800, 0x2800, 0x2800);
|
||||
self.parts[3].hit_bounds = Rect::new(0x1800, 0x400, 0x1800, 0x2000);
|
||||
self.parts[3].hit_bounds = HitExtents { left: 0x1800, top: 0x400, right: 0x1800, bottom: 0x2000 };
|
||||
self.parts[3].npc_flags.set_ignore_solidity(true);
|
||||
self.parts[3].parent_id = 0;
|
||||
self.parts[3].damage = 10;
|
||||
|
|
@ -261,7 +262,7 @@ impl BossNPC {
|
|||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
match part.action_num {
|
||||
0 => {
|
||||
part.action_num = 1;
|
||||
|
|
@ -316,14 +317,14 @@ impl BossNPC {
|
|||
part.hit_bounds.left = 0x2000;
|
||||
|
||||
state.sound_manager.play_sfx(51);
|
||||
|
||||
|
||||
npc_list.create_death_smoke(
|
||||
part.x,
|
||||
part.y,
|
||||
part.display_bounds.right as usize,
|
||||
4,
|
||||
state,
|
||||
&part.rng
|
||||
&part.rng,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ use crate::game::stage::{Stage, StageTexturePaths};
|
|||
use crate::game::weapon::bullet::BulletManager;
|
||||
use crate::util::rng::Xoroshiro32PlusPlus;
|
||||
|
||||
use super::physics::HitExtents;
|
||||
|
||||
pub mod ai;
|
||||
pub mod boss;
|
||||
pub mod list;
|
||||
|
|
@ -123,7 +125,7 @@ pub struct NPC {
|
|||
pub anim_counter: u16,
|
||||
pub anim_rect: Rect<u16>,
|
||||
pub display_bounds: Rect<u32>,
|
||||
pub hit_bounds: Rect<u32>,
|
||||
pub hit_bounds: HitExtents,
|
||||
pub rng: Xoroshiro32PlusPlus,
|
||||
pub popup: NumberPopup,
|
||||
pub splash: bool,
|
||||
|
|
@ -157,7 +159,7 @@ impl NPC {
|
|||
direction: Direction::Left,
|
||||
tsc_direction: 0,
|
||||
display_bounds: Rect { left: 0, top: 0, right: 0, bottom: 0 },
|
||||
hit_bounds: Rect { left: 0, top: 0, right: 0, bottom: 0 },
|
||||
hit_bounds: HitExtents { left: 0, top: 0, right: 0, bottom: 0 },
|
||||
parent_id: 0,
|
||||
action_num: 0,
|
||||
anim_num: 0,
|
||||
|
|
@ -740,7 +742,7 @@ impl PhysicalEntity for NPC {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn hit_bounds(&self) -> &Rect<u32> {
|
||||
fn hit_bounds(&self) -> &HitExtents {
|
||||
&self.hit_bounds
|
||||
}
|
||||
|
||||
|
|
@ -909,16 +911,16 @@ impl NPCTable {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_hit_bounds(&self, npc_type: u16) -> Rect<u32> {
|
||||
pub fn get_hit_bounds(&self, npc_type: u16) -> HitExtents {
|
||||
if let Some(npc) = self.entries.get(npc_type as usize) {
|
||||
Rect {
|
||||
HitExtents {
|
||||
left: npc.hit_bounds.left as u32 * 0x200,
|
||||
top: npc.hit_bounds.top as u32 * 0x200,
|
||||
right: npc.hit_bounds.right as u32 * 0x200,
|
||||
bottom: npc.hit_bounds.bottom as u32 * 0x200,
|
||||
}
|
||||
} else {
|
||||
Rect { left: 0, top: 0, right: 0, bottom: 0 }
|
||||
HitExtents { left: 0, top: 0, right: 0, bottom: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -82,6 +82,33 @@ pub const OFFSETS: [(i32, i32); 64] = [
|
|||
(4, 4),
|
||||
];
|
||||
|
||||
/**
|
||||
* Represents hitbox extents, with each value being the distance from the center of the entity.
|
||||
*/
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct HitExtents {
|
||||
pub left: u32,
|
||||
pub right: u32,
|
||||
pub top: u32,
|
||||
pub bottom: u32,
|
||||
}
|
||||
|
||||
impl HitExtents {
|
||||
/**
|
||||
* Check if a point is within the hitbox extents of an entity on X axis (exclusively).
|
||||
*/
|
||||
pub const fn point_in_entity_x(&self, entity_x: i32, point_x: i32) -> bool {
|
||||
point_x > entity_x - self.left as i32 && point_x < entity_x + self.right as i32
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a point is within the hitbox extents of an entity on Y axis (exclusively).
|
||||
*/
|
||||
pub const fn point_in_entity_y(&self, entity_y: i32, point_y: i32) -> bool {
|
||||
point_y > entity_y - self.top as i32 && point_y < entity_y + self.bottom as i32
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PhysicalEntity {
|
||||
fn x(&self) -> i32;
|
||||
fn y(&self) -> i32;
|
||||
|
|
@ -96,7 +123,7 @@ pub trait PhysicalEntity {
|
|||
0
|
||||
}
|
||||
|
||||
fn hit_bounds(&self) -> &Rect<u32>;
|
||||
fn hit_bounds(&self) -> &HitExtents;
|
||||
fn display_bounds(&self) -> &Rect<u32>;
|
||||
|
||||
fn set_x(&mut self, x: i32);
|
||||
|
|
@ -125,14 +152,23 @@ pub trait PhysicalEntity {
|
|||
let bounds_bottom = if self.is_player() { 0x800 } else { 0x600 };
|
||||
let half_tile_size = state.tile_size.as_int() * 0x100;
|
||||
|
||||
if (self.y() - self.hit_bounds().top as i32) < ((y * 2 + 1) * half_tile_size - bounds_top)
|
||||
&& (self.y() + self.hit_bounds().bottom as i32) > ((y * 2 - 1) * half_tile_size + bounds_bottom)
|
||||
let hit_bounds = *self.hit_bounds();
|
||||
|
||||
let block_center_x = (x * 2) * half_tile_size;
|
||||
let block_center_y = (y * 2) * half_tile_size;
|
||||
let block_top = (y * 2 - 1) * half_tile_size;
|
||||
let block_bottom = (y * 2 + 1) * half_tile_size;
|
||||
let block_left = (x * 2 - 1) * half_tile_size;
|
||||
let block_right = (x * 2 + 1) * half_tile_size;
|
||||
|
||||
if (self.y() - hit_bounds.top as i32) < (block_bottom - bounds_top)
|
||||
&& (self.y() + hit_bounds.bottom as i32) > (block_top + bounds_bottom)
|
||||
{
|
||||
// left wall
|
||||
if (self.x() - self.hit_bounds().right as i32) < (x * 2 + 1) * half_tile_size
|
||||
&& (self.x() - self.hit_bounds().right as i32) > (x * 2) * half_tile_size
|
||||
if (self.x() - hit_bounds.right as i32) < block_right
|
||||
&& (self.x() - hit_bounds.right as i32) > block_center_x
|
||||
{
|
||||
self.set_x(((x * 2 + 1) * half_tile_size) + self.hit_bounds().right as i32);
|
||||
self.set_x(block_right + hit_bounds.right as i32);
|
||||
|
||||
if self.is_player() {
|
||||
if self.vel_x() < -0x180 {
|
||||
|
|
@ -148,10 +184,10 @@ pub trait PhysicalEntity {
|
|||
}
|
||||
|
||||
// right wall
|
||||
if (self.x() + self.hit_bounds().right as i32) > (x * 2 - 1) * half_tile_size
|
||||
&& (self.x() + self.hit_bounds().right as i32) < (x * 2) * half_tile_size
|
||||
if (self.x() + hit_bounds.right as i32) > block_left
|
||||
&& (self.x() + hit_bounds.right as i32) < block_center_x
|
||||
{
|
||||
self.set_x(((x * 2 - 1) * half_tile_size) - self.hit_bounds().right as i32);
|
||||
self.set_x(block_left - hit_bounds.right as i32);
|
||||
|
||||
if self.is_player() {
|
||||
if self.vel_x() > 0x180 {
|
||||
|
|
@ -167,27 +203,26 @@ pub trait PhysicalEntity {
|
|||
}
|
||||
}
|
||||
|
||||
if ((self.x() - self.hit_bounds().right as i32) < (x * 2 + 1) * half_tile_size - bounds_x)
|
||||
&& ((self.x() + self.hit_bounds().right as i32) > (x * 2 - 1) * half_tile_size + bounds_x)
|
||||
if ((self.x() - hit_bounds.right as i32) < block_right - bounds_x)
|
||||
&& ((self.x() + hit_bounds.right as i32) > block_left + bounds_x)
|
||||
{
|
||||
// ceiling
|
||||
if (self.y() - self.hit_bounds().top as i32) < (y * 2 + 1) * half_tile_size
|
||||
&& (self.y() - self.hit_bounds().top as i32) > (y * 2) * half_tile_size
|
||||
if (self.y() - hit_bounds.top as i32) < block_bottom && (self.y() - hit_bounds.top as i32) > block_center_y
|
||||
{
|
||||
self.set_y(((y * 2 + 1) * half_tile_size) + self.hit_bounds().top as i32);
|
||||
self.set_y(block_bottom + hit_bounds.top as i32);
|
||||
|
||||
if self.is_player() {
|
||||
if !self.cond().hidden() && self.vel_y() < -0x200 {
|
||||
state.sound_manager.play_sfx(3);
|
||||
state.create_caret(
|
||||
self.x(),
|
||||
self.y() - self.hit_bounds().top as i32,
|
||||
self.y() - hit_bounds.top as i32,
|
||||
CaretType::LittleParticles,
|
||||
Direction::Left,
|
||||
);
|
||||
state.create_caret(
|
||||
self.x(),
|
||||
self.y() - self.hit_bounds().top as i32,
|
||||
self.y() - hit_bounds.top as i32,
|
||||
CaretType::LittleParticles,
|
||||
Direction::Left,
|
||||
);
|
||||
|
|
@ -204,10 +239,10 @@ pub trait PhysicalEntity {
|
|||
}
|
||||
|
||||
// floor
|
||||
if ((self.y() + self.hit_bounds().bottom as i32) > ((y * 2 - 1) * half_tile_size))
|
||||
&& ((self.y() + self.hit_bounds().bottom as i32) < (y * 2) * half_tile_size)
|
||||
if ((self.y() + hit_bounds.bottom as i32) > block_top)
|
||||
&& ((self.y() + hit_bounds.bottom as i32) < block_center_y)
|
||||
{
|
||||
self.set_y(((y * 2 - 1) * half_tile_size) - self.hit_bounds().bottom as i32);
|
||||
self.set_y(block_top - hit_bounds.bottom as i32);
|
||||
|
||||
if self.is_player() {
|
||||
if self.vel_y() > 0x400 {
|
||||
|
|
@ -228,13 +263,16 @@ pub trait PhysicalEntity {
|
|||
|
||||
fn test_platform_hit(&mut self, state: &mut SharedGameState, x: i32, y: i32) {
|
||||
let half_tile_size = state.tile_size.as_int() * 0x100;
|
||||
let block_top = (y * 2 - 1) * half_tile_size;
|
||||
let block_left = (x * 2 - 1) * half_tile_size;
|
||||
let block_right = (x * 2 + 1) * half_tile_size;
|
||||
|
||||
if ((self.x() - self.hit_bounds().right as i32) < (x * 2 + 1) * half_tile_size)
|
||||
&& ((self.x() + self.hit_bounds().right as i32) > (x * 2 - 1) * half_tile_size)
|
||||
&& ((self.y() + self.hit_bounds().bottom as i32) > ((y * 2 - 1) * half_tile_size))
|
||||
&& ((self.y() + self.hit_bounds().bottom as i32) < (y * 2 - 1) * half_tile_size + 0x400)
|
||||
if ((self.x() - self.hit_bounds().right as i32) < block_right)
|
||||
&& ((self.x() + self.hit_bounds().right as i32) > block_left)
|
||||
&& ((self.y() + self.hit_bounds().bottom as i32) > block_top)
|
||||
&& ((self.y() + self.hit_bounds().bottom as i32) < block_top + 0x400)
|
||||
{
|
||||
self.set_y(((y * 2 - 1) * half_tile_size) - self.hit_bounds().bottom as i32);
|
||||
self.set_y(block_top - self.hit_bounds().bottom as i32);
|
||||
|
||||
if self.is_player() {
|
||||
if self.vel_y() > 0x400 {
|
||||
|
|
@ -257,12 +295,15 @@ pub trait PhysicalEntity {
|
|||
let tile_size = state.tile_size.as_int() * 0x200;
|
||||
let half_tile_size = tile_size / 2;
|
||||
let quarter_tile_size = half_tile_size / 2;
|
||||
let block_top = (y * 2 - 1) * half_tile_size;
|
||||
let block_left = (x * 2 - 1) * half_tile_size;
|
||||
let block_right = (x * 2 + 1) * half_tile_size;
|
||||
|
||||
if self.x() < (x * 2 + 1) * half_tile_size
|
||||
&& self.x() > (x * 2 - 1) * half_tile_size
|
||||
if self.x() < block_right
|
||||
&& self.x() > block_left
|
||||
&& (self.y() - self.hit_bounds().top as i32)
|
||||
< (y * tile_size) - (self.x() - x * tile_size) / 2 + quarter_tile_size
|
||||
&& (self.y() + self.hit_bounds().bottom as i32) > (y * 2 - 1) * half_tile_size
|
||||
< (y * tile_size) - (self.x() - x * tile_size) / 2 + quarter_tile_size
|
||||
&& (self.y() + self.hit_bounds().bottom as i32) > block_top
|
||||
{
|
||||
self.set_y(
|
||||
(y * tile_size) - ((self.x() - x * tile_size) / 2) + quarter_tile_size + self.hit_bounds().top as i32,
|
||||
|
|
@ -298,12 +339,15 @@ pub trait PhysicalEntity {
|
|||
let tile_size = state.tile_size.as_int() * 0x200;
|
||||
let half_tile_size = tile_size / 2;
|
||||
let quarter_tile_size = half_tile_size / 2;
|
||||
let block_top = (y * 2 - 1) * half_tile_size;
|
||||
let block_left = (x * 2 - 1) * half_tile_size;
|
||||
let block_right = (x * 2 + 1) * half_tile_size;
|
||||
|
||||
if self.x() < (x * 2 + 1) * half_tile_size
|
||||
&& self.x() > (x * 2 - 1) * half_tile_size
|
||||
if self.x() < block_right
|
||||
&& self.x() > block_left
|
||||
&& (self.y() - self.hit_bounds().top as i32)
|
||||
< (y * tile_size) - (self.x() - x * tile_size) / 2 - quarter_tile_size
|
||||
&& (self.y() + self.hit_bounds().bottom as i32) > (y * 2 - 1) * half_tile_size
|
||||
< (y * tile_size) - (self.x() - x * tile_size) / 2 - quarter_tile_size
|
||||
&& (self.y() + self.hit_bounds().bottom as i32) > block_top
|
||||
{
|
||||
self.set_y(
|
||||
(y * tile_size) - ((self.x() - x * tile_size) / 2) - quarter_tile_size + self.hit_bounds().top as i32,
|
||||
|
|
@ -339,12 +383,15 @@ pub trait PhysicalEntity {
|
|||
let tile_size = state.tile_size.as_int() * 0x200;
|
||||
let half_tile_size = tile_size / 2;
|
||||
let quarter_tile_size = half_tile_size / 2;
|
||||
let block_top = (y * 2 - 1) * half_tile_size;
|
||||
let block_left = (x * 2 - 1) * half_tile_size;
|
||||
let block_right = (x * 2 + 1) * half_tile_size;
|
||||
|
||||
if self.x() < (x * 2 + 1) * half_tile_size
|
||||
&& self.x() > (x * 2 - 1) * half_tile_size
|
||||
if self.x() < block_right
|
||||
&& self.x() > block_left
|
||||
&& (self.y() - self.hit_bounds().top as i32)
|
||||
< (y * tile_size) + (self.x() - x * tile_size) / 2 - quarter_tile_size
|
||||
&& (self.y() + self.hit_bounds().bottom as i32) > (y * 2 - 1) * half_tile_size
|
||||
< (y * tile_size) + (self.x() - x * tile_size) / 2 - quarter_tile_size
|
||||
&& (self.y() + self.hit_bounds().bottom as i32) > block_top
|
||||
{
|
||||
self.set_y(
|
||||
(y * tile_size) + ((self.x() - x * tile_size) / 2) - quarter_tile_size + self.hit_bounds().top as i32,
|
||||
|
|
@ -380,12 +427,15 @@ pub trait PhysicalEntity {
|
|||
let tile_size = state.tile_size.as_int() * 0x200;
|
||||
let half_tile_size = tile_size / 2;
|
||||
let quarter_tile_size = half_tile_size / 2;
|
||||
let block_top = (y * 2 - 1) * half_tile_size;
|
||||
let block_left = (x * 2 - 1) * half_tile_size;
|
||||
let block_right = (x * 2 + 1) * half_tile_size;
|
||||
|
||||
if self.x() < (x * 2 + 1) * half_tile_size
|
||||
&& self.x() > (x * 2 - 1) * half_tile_size
|
||||
if self.x() < block_right
|
||||
&& self.x() > block_left
|
||||
&& (self.y() - self.hit_bounds().top as i32)
|
||||
< (y * tile_size) + (self.x() - x * tile_size) / 2 + quarter_tile_size
|
||||
&& (self.y() + self.hit_bounds().bottom as i32) > (y * 2 - 1) * half_tile_size
|
||||
< (y * tile_size) + (self.x() - x * tile_size) / 2 + quarter_tile_size
|
||||
&& (self.y() + self.hit_bounds().bottom as i32) > block_top
|
||||
{
|
||||
self.set_y(
|
||||
(y * tile_size) + ((self.x() - x * tile_size) / 2) + quarter_tile_size + self.hit_bounds().top as i32,
|
||||
|
|
@ -421,14 +471,17 @@ pub trait PhysicalEntity {
|
|||
let tile_size = state.tile_size.as_int() * 0x200;
|
||||
let half_tile_size = tile_size / 2;
|
||||
let quarter_tile_size = half_tile_size / 2;
|
||||
let block_bottom = (y * 2 + 1) * half_tile_size;
|
||||
let block_left = (x * 2 - 1) * half_tile_size;
|
||||
let block_right = (x * 2 + 1) * half_tile_size;
|
||||
|
||||
self.flags().set_hit_left_higher_half(true);
|
||||
|
||||
if self.x() < (x * 2 + 1) * half_tile_size
|
||||
&& self.x() > (x * 2 - 1) * half_tile_size
|
||||
if self.x() < block_right
|
||||
&& self.x() > block_left
|
||||
&& (self.y() + self.hit_bounds().bottom as i32)
|
||||
> (y * tile_size) + (self.x() - x * tile_size) / 2 - quarter_tile_size
|
||||
&& (self.y() - self.hit_bounds().top as i32) < (y * 2 + 1) * half_tile_size
|
||||
> (y * tile_size) + (self.x() - x * tile_size) / 2 - quarter_tile_size
|
||||
&& (self.y() - self.hit_bounds().top as i32) < block_bottom
|
||||
{
|
||||
self.set_y(
|
||||
(y * tile_size) + ((self.x() - x * tile_size) / 2)
|
||||
|
|
@ -454,14 +507,17 @@ pub trait PhysicalEntity {
|
|||
let tile_size = state.tile_size.as_int() * 0x200;
|
||||
let half_tile_size = tile_size / 2;
|
||||
let quarter_tile_size = half_tile_size / 2;
|
||||
let block_bottom = (y * 2 + 1) * half_tile_size;
|
||||
let block_left = (x * 2 - 1) * half_tile_size;
|
||||
let block_right = (x * 2 + 1) * half_tile_size;
|
||||
|
||||
self.flags().set_hit_left_lower_half(true);
|
||||
|
||||
if (self.x() < (x * 2 + 1) * half_tile_size)
|
||||
&& (self.x() > (x * 2 - 1) * half_tile_size)
|
||||
if (self.x() < block_right)
|
||||
&& (self.x() > block_left)
|
||||
&& (self.y() + self.hit_bounds().bottom as i32)
|
||||
> (y * tile_size) + (self.x() - x * tile_size) / 2 + quarter_tile_size
|
||||
&& (self.y() - self.hit_bounds().top as i32) < (y * 2 + 1) * half_tile_size
|
||||
> (y * tile_size) + (self.x() - x * tile_size) / 2 + quarter_tile_size
|
||||
&& (self.y() - self.hit_bounds().top as i32) < block_bottom
|
||||
{
|
||||
self.set_y(
|
||||
(y * tile_size) + ((self.x() - x * tile_size) / 2) + quarter_tile_size
|
||||
|
|
@ -486,14 +542,17 @@ pub trait PhysicalEntity {
|
|||
let tile_size = state.tile_size.as_int() * 0x200;
|
||||
let half_tile_size = tile_size / 2;
|
||||
let quarter_tile_size = half_tile_size / 2;
|
||||
let block_bottom = (y * 2 + 1) * half_tile_size;
|
||||
let block_left = (x * 2 - 1) * half_tile_size;
|
||||
let block_right = (x * 2 + 1) * half_tile_size;
|
||||
|
||||
self.flags().set_hit_right_lower_half(true);
|
||||
|
||||
if (self.x() < (x * 2 + 1) * half_tile_size)
|
||||
&& (self.x() > (x * 2 - 1) * half_tile_size)
|
||||
if (self.x() < block_right)
|
||||
&& (self.x() > block_left)
|
||||
&& (self.y() + self.hit_bounds().bottom as i32)
|
||||
> (y * tile_size) - (self.x() - x * tile_size) / 2 + quarter_tile_size
|
||||
&& (self.y() - self.hit_bounds().top as i32) < (y * 2 + 1) * half_tile_size
|
||||
> (y * tile_size) - (self.x() - x * tile_size) / 2 + quarter_tile_size
|
||||
&& (self.y() - self.hit_bounds().top as i32) < block_bottom
|
||||
{
|
||||
self.set_y(
|
||||
(y * tile_size) - ((self.x() - x * tile_size) / 2) + quarter_tile_size
|
||||
|
|
@ -518,14 +577,17 @@ pub trait PhysicalEntity {
|
|||
let tile_size = state.tile_size.as_int() * 0x200;
|
||||
let half_tile_size = tile_size / 2;
|
||||
let quarter_tile_size = half_tile_size / 2;
|
||||
let block_bottom = (y * 2 + 1) * half_tile_size;
|
||||
let block_left = (x * 2 - 1) * half_tile_size;
|
||||
let block_right = (x * 2 + 1) * half_tile_size;
|
||||
|
||||
self.flags().set_hit_right_higher_half(true);
|
||||
|
||||
if (self.x() < (x * 2 + 1) * half_tile_size)
|
||||
&& (self.x() > (x * 2 - 1) * half_tile_size)
|
||||
if (self.x() < block_right)
|
||||
&& (self.x() > block_left)
|
||||
&& (self.y() + self.hit_bounds().bottom as i32)
|
||||
> (y * tile_size) - (self.x() - x * tile_size) / 2 - quarter_tile_size
|
||||
&& (self.y() - self.hit_bounds().top as i32) < (y * 2 + 1) * half_tile_size
|
||||
> (y * tile_size) - (self.x() - x * tile_size) / 2 - quarter_tile_size
|
||||
&& (self.y() - self.hit_bounds().top as i32) < block_bottom
|
||||
{
|
||||
self.set_y(
|
||||
(y * tile_size)
|
||||
|
|
@ -551,11 +613,14 @@ pub trait PhysicalEntity {
|
|||
fn test_hit_upper_left_slope(&mut self, state: &mut SharedGameState, x: i32, y: i32) {
|
||||
let tile_size = state.tile_size.as_int() * 0x200;
|
||||
let half_tile_size = tile_size / 2;
|
||||
let block_top = (y * 2 - 1) * half_tile_size;
|
||||
let block_left = (x * 2 - 1) * half_tile_size;
|
||||
let block_right = (x * 2 + 1) * half_tile_size;
|
||||
|
||||
if self.x() < (x * 2 + 1) * half_tile_size
|
||||
&& self.x() > (x * 2 - 1) * half_tile_size
|
||||
if self.x() < block_right
|
||||
&& self.x() > block_left
|
||||
&& (self.y() - self.hit_bounds().top as i32) < (y * tile_size) - (self.x() - x * tile_size)
|
||||
&& (self.y() + self.hit_bounds().bottom as i32) > (y * 2 - 1) * half_tile_size
|
||||
&& (self.y() + self.hit_bounds().bottom as i32) > block_top
|
||||
{
|
||||
self.set_y((y * tile_size) - (self.x() - x * tile_size) + self.hit_bounds().top as i32);
|
||||
|
||||
|
|
@ -587,11 +652,14 @@ pub trait PhysicalEntity {
|
|||
fn test_hit_upper_right_slope(&mut self, state: &mut SharedGameState, x: i32, y: i32) {
|
||||
let tile_size = state.tile_size.as_int() * 0x200;
|
||||
let half_tile_size = tile_size / 2;
|
||||
let block_top = (y * 2 - 1) * half_tile_size;
|
||||
let block_left = (x * 2 - 1) * half_tile_size;
|
||||
let block_right = (x * 2 + 1) * half_tile_size;
|
||||
|
||||
if self.x() < (x * 2 + 1) * half_tile_size
|
||||
&& self.x() > (x * 2 - 1) * half_tile_size
|
||||
if self.x() < block_right
|
||||
&& self.x() > block_left
|
||||
&& (self.y() - self.hit_bounds().top as i32) < (y * tile_size) + (self.x() - x * tile_size)
|
||||
&& (self.y() + self.hit_bounds().bottom as i32) > (y * 2 - 1) * half_tile_size
|
||||
&& (self.y() + self.hit_bounds().bottom as i32) > block_top
|
||||
{
|
||||
self.set_y((y * tile_size) + (self.x() - x * tile_size) + self.hit_bounds().top as i32);
|
||||
|
||||
|
|
@ -624,14 +692,17 @@ pub trait PhysicalEntity {
|
|||
let tile_size = state.tile_size.as_int() * 0x200;
|
||||
let half_tile_size = tile_size / 2;
|
||||
let quarter_tile_size = half_tile_size / 2;
|
||||
let block_bottom = (y * 2 + 1) * half_tile_size;
|
||||
let block_left = (x * 2 - 1) * half_tile_size;
|
||||
let block_right = (x * 2 + 1) * half_tile_size;
|
||||
|
||||
self.flags().set_hit_left_higher_half(true);
|
||||
|
||||
if self.x() < (x * 2 + 1) * half_tile_size
|
||||
&& self.x() > (x * 2 - 1) * half_tile_size
|
||||
if self.x() < block_right
|
||||
&& self.x() > block_left
|
||||
&& (self.y() + self.hit_bounds().bottom as i32)
|
||||
> (y * tile_size) + (self.x() - x * tile_size) - quarter_tile_size
|
||||
&& (self.y() - self.hit_bounds().top as i32) < (y * 2 + 1) * half_tile_size
|
||||
> (y * tile_size) + (self.x() - x * tile_size) - quarter_tile_size
|
||||
&& (self.y() - self.hit_bounds().top as i32) < block_bottom
|
||||
{
|
||||
self.set_y(
|
||||
(y * tile_size) + (self.x() - x * tile_size) - quarter_tile_size - self.hit_bounds().bottom as i32,
|
||||
|
|
@ -655,14 +726,17 @@ pub trait PhysicalEntity {
|
|||
let tile_size = state.tile_size.as_int() * 0x200;
|
||||
let half_tile_size = tile_size / 2;
|
||||
let quarter_tile_size = half_tile_size / 2;
|
||||
let block_bottom = (y * 2 + 1) * half_tile_size;
|
||||
let block_left = (x * 2 - 1) * half_tile_size;
|
||||
let block_right = (x * 2 + 1) * half_tile_size;
|
||||
|
||||
self.flags().set_hit_right_higher_half(true);
|
||||
|
||||
if (self.x() < (x * 2 + 1) * half_tile_size)
|
||||
&& (self.x() > (x * 2 - 1) * half_tile_size)
|
||||
if (self.x() < block_right)
|
||||
&& (self.x() > block_left)
|
||||
&& (self.y() + self.hit_bounds().bottom as i32)
|
||||
> (y * tile_size) - (self.x() - x * tile_size) - quarter_tile_size
|
||||
&& (self.y() - self.hit_bounds().top as i32) < (y * 2 + 1) * half_tile_size
|
||||
> (y * tile_size) - (self.x() - x * tile_size) - quarter_tile_size
|
||||
&& (self.y() - self.hit_bounds().top as i32) < block_bottom
|
||||
{
|
||||
self.set_y(
|
||||
(y * tile_size) - (self.x() - x * tile_size) - quarter_tile_size - self.hit_bounds().bottom as i32,
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ use crate::input::dummy_player_controller::DummyPlayerController;
|
|||
use crate::input::player_controller::PlayerController;
|
||||
use crate::util::rng::RNG;
|
||||
|
||||
use super::physics::HitExtents;
|
||||
|
||||
mod player_hit;
|
||||
pub mod skin;
|
||||
|
||||
|
|
@ -93,7 +95,7 @@ pub struct Player {
|
|||
pub equip: Equipment,
|
||||
pub direction: Direction,
|
||||
pub display_bounds: Rect<u32>,
|
||||
pub hit_bounds: Rect<u32>,
|
||||
pub hit_bounds: HitExtents,
|
||||
pub control_mode: ControlMode,
|
||||
pub question: bool,
|
||||
pub booster_fuel: u32,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use crate::game::inventory::Inventory;
|
|||
use crate::game::npc::boss::BossNPC;
|
||||
use crate::game::npc::list::NPCList;
|
||||
use crate::game::npc::NPC;
|
||||
use crate::game::physics::PhysicalEntity;
|
||||
use crate::game::physics::{HitExtents, PhysicalEntity};
|
||||
use crate::game::player::{ControlMode, Player, TargetPlayer};
|
||||
use crate::game::shared_game_state::SharedGameState;
|
||||
use crate::game::weapon::WeaponType;
|
||||
|
|
@ -43,7 +43,7 @@ impl PhysicalEntity for Player {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn hit_bounds(&self) -> &Rect<u32> {
|
||||
fn hit_bounds(&self) -> &HitExtents {
|
||||
&self.hit_bounds
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use crate::common::{Color, Direction, Rect};
|
|||
use crate::framework::context::Context;
|
||||
use crate::framework::filesystem;
|
||||
use crate::framework::filesystem::File;
|
||||
use crate::game::physics::HitExtents;
|
||||
use crate::game::player::skin::{PlayerAnimationState, PlayerAppearanceState, PlayerSkin};
|
||||
use crate::game::shared_game_state::SharedGameState;
|
||||
|
||||
|
|
@ -227,10 +228,10 @@ impl PlayerSkin for BasicPlayerSkin {
|
|||
""
|
||||
}
|
||||
|
||||
fn get_hit_bounds(&self) -> Rect<u32> {
|
||||
fn get_hit_bounds(&self) -> HitExtents {
|
||||
let ubox = &self.metadata.hit_box;
|
||||
|
||||
Rect {
|
||||
HitExtents {
|
||||
left: ubox.left as u32 * 0x200,
|
||||
top: ubox.top as u32 * 0x200,
|
||||
right: ubox.right as u32 * 0x200,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use crate::bitfield;
|
||||
use crate::common::{Color, Direction, Rect};
|
||||
use crate::game::physics::HitExtents;
|
||||
use crate::game::shared_game_state::SharedGameState;
|
||||
|
||||
pub mod basic;
|
||||
|
|
@ -83,7 +84,7 @@ pub trait PlayerSkin: PlayerSkinClone {
|
|||
fn get_mask_texture_name(&self) -> &str;
|
||||
|
||||
/// Returns hit bounds of skin.
|
||||
fn get_hit_bounds(&self) -> Rect<u32>;
|
||||
fn get_hit_bounds(&self) -> HitExtents;
|
||||
|
||||
/// Returns display bounds of skin.
|
||||
fn get_display_bounds(&self) -> Rect<u32>;
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@ use crate::engine_constants::{BulletData, EngineConstants};
|
|||
use crate::game::caret::CaretType;
|
||||
use crate::game::npc::list::NPCList;
|
||||
use crate::game::npc::NPC;
|
||||
use crate::game::physics::{OFFSETS, PhysicalEntity};
|
||||
use crate::game::physics::{HitExtents, PhysicalEntity, OFFSETS};
|
||||
use crate::game::player::{Player, TargetPlayer};
|
||||
use crate::game::shared_game_state::{SharedGameState, TileSize};
|
||||
use crate::game::stage::Stage;
|
||||
use crate::util::rng::{RNG, Xoroshiro32PlusPlus, XorShift};
|
||||
use crate::util::rng::{XorShift, Xoroshiro32PlusPlus, RNG};
|
||||
|
||||
pub struct BulletManager {
|
||||
pub bullets: Vec<Bullet>,
|
||||
|
|
@ -121,7 +121,7 @@ pub struct Bullet {
|
|||
pub anim_counter: u16,
|
||||
pub action_num: u16,
|
||||
pub action_counter: u16,
|
||||
pub hit_bounds: Rect<u32>,
|
||||
pub hit_bounds: HitExtents,
|
||||
pub display_bounds: Rect<u32>,
|
||||
}
|
||||
|
||||
|
|
@ -180,12 +180,12 @@ impl Bullet {
|
|||
bullet.display_bounds.right as u32 * 0x200,
|
||||
bullet.display_bounds.bottom as u32 * 0x200,
|
||||
),
|
||||
hit_bounds: Rect::new(
|
||||
bullet.block_hit_width as u32 * 0x200,
|
||||
bullet.block_hit_height as u32 * 0x200,
|
||||
bullet.block_hit_width as u32 * 0x200,
|
||||
bullet.block_hit_height as u32 * 0x200,
|
||||
),
|
||||
hit_bounds: HitExtents {
|
||||
left: bullet.block_hit_width as u32 * 0x200,
|
||||
top: bullet.block_hit_height as u32 * 0x200,
|
||||
right: bullet.block_hit_width as u32 * 0x200,
|
||||
bottom: bullet.block_hit_height as u32 * 0x200,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1844,7 +1844,7 @@ impl PhysicalEntity for Bullet {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn hit_bounds(&self) -> &Rect<u32> {
|
||||
fn hit_bounds(&self) -> &HitExtents {
|
||||
&self.hit_bounds
|
||||
}
|
||||
|
||||
|
|
@ -1964,7 +1964,7 @@ impl PhysicalEntity for Bullet {
|
|||
}
|
||||
|
||||
if let Some(tile) =
|
||||
stage.map.tiles.get_mut(stage.map.width as usize * (y + oy) as usize + (x + ox) as usize)
|
||||
stage.map.tiles.get_mut(stage.map.width as usize * (y + oy) as usize + (x + ox) as usize)
|
||||
{
|
||||
*tile = tile.wrapping_sub(1);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue