mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2024-11-21 21:22:44 +00:00
Accuracy fixes for Sand Zone and Labyrinth (#215)
* Accuracy fixes for Sand Zone and Labyrinth And a couple of smaller things as well * Remove NPCList::remove_by_type (kill_npcs_by_type does the same thing) Also rename remove_by_event to kill_npcs_by_event for consistency
This commit is contained in:
parent
b294f65656
commit
f6caffd624
|
@ -452,9 +452,8 @@ impl NPC {
|
|||
self.vel_y = -0x800;
|
||||
self.npc_flags.set_ignore_solidity(true);
|
||||
|
||||
for npc in npc_list.iter_alive().filter(|npc| npc.npc_type == 117 || npc.npc_type == 150) {
|
||||
npc.cond.set_alive(false)
|
||||
}
|
||||
npc_list.kill_npcs_by_type(150, false, state);
|
||||
npc_list.kill_npcs_by_type(117, false, state);
|
||||
|
||||
let mut npc = NPC::create(355, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
|
|
|
@ -1160,7 +1160,7 @@ impl NPC {
|
|||
self.action_counter += 1;
|
||||
if self.action_counter > 250 {
|
||||
self.action_num = 22;
|
||||
npc_list.remove_by_type(270, state);
|
||||
npc_list.kill_npcs_by_type(270, false, state);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
|
|
|
@ -399,12 +399,12 @@ impl NPC {
|
|||
0 | 1 => {
|
||||
if self.action_num == 0 {
|
||||
let deg = self.rng.range(0..255) as f64 * CDEG_RAD;
|
||||
self.vel_y = (deg.cos() * -512.0) as i32;
|
||||
self.target_x = self.x + 8 * ((deg + 64.0 * CDEG_RAD).cos() * -512.0) as i32;
|
||||
self.vel_x = (deg.cos() * 512.0) as i32;
|
||||
self.target_x = self.x + 8 * ((deg + 64.0 * CDEG_RAD).cos() * 512.0) as i32;
|
||||
|
||||
let deg = self.rng.range(0..255) as f64 * CDEG_RAD;
|
||||
self.vel_y = (deg.sin() * -512.0) as i32;
|
||||
self.target_y = self.y + 8 * ((deg + 64.0 * CDEG_RAD).sin() * -512.0) as i32;
|
||||
self.vel_y = (deg.sin() * 512.0) as i32;
|
||||
self.target_y = self.y + 8 * ((deg + 64.0 * CDEG_RAD).sin() * 512.0) as i32;
|
||||
|
||||
self.action_num = 1;
|
||||
self.action_counter3 = 120;
|
||||
|
@ -886,9 +886,9 @@ impl NPC {
|
|||
state.sound_manager.play_sfx(25);
|
||||
}
|
||||
|
||||
self.vel_y += 0x10;
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
self.vel_y += 0x10;
|
||||
|
||||
if self.action_counter != 0 && self.flags.hit_bottom_wall() {
|
||||
state.sound_manager.play_sfx(35);
|
||||
|
@ -915,6 +915,9 @@ impl NPC {
|
|||
players: [&mut Player; 2],
|
||||
npc_list: &NPCList,
|
||||
) -> GameResult {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
self.face_player(player);
|
||||
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
self.action_counter = self.rng.range(0..50) as u16;
|
||||
|
@ -937,14 +940,6 @@ impl NPC {
|
|||
self.vel_y = self.vel_y.clamp(-0x200, 0x200);
|
||||
self.y += self.vel_y;
|
||||
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
if self.x <= player.x {
|
||||
self.direction = Direction::Right;
|
||||
} else {
|
||||
self.direction = Direction::Left;
|
||||
}
|
||||
|
||||
if self.direction != Direction::Left {
|
||||
if player.y < self.y + 0xA000
|
||||
&& player.y > self.y - 0xA000
|
||||
|
@ -1048,12 +1043,12 @@ impl NPC {
|
|||
self.action_num = 25;
|
||||
self.action_counter = 0;
|
||||
self.anim_num = 2;
|
||||
self.vel_y = -0x5ff;
|
||||
self.vel_y = -0x600;
|
||||
|
||||
if self.x >= self.target_x {
|
||||
self.vel_x = -0x100;
|
||||
self.vel_x = -0x80;
|
||||
} else {
|
||||
self.vel_x = 0x100;
|
||||
self.vel_x = 0x80;
|
||||
}
|
||||
} else {
|
||||
state.sound_manager.play_sfx(30);
|
||||
|
@ -1151,6 +1146,10 @@ impl NPC {
|
|||
self.action_num = 2;
|
||||
}
|
||||
|
||||
// So we're going to move *before* checking collisions, huh?
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
|
||||
let mut hit = false;
|
||||
|
||||
if self.flags.hit_left_wall() {
|
||||
|
@ -1178,6 +1177,8 @@ impl NPC {
|
|||
}
|
||||
2 => {
|
||||
self.vel_y += 0x40;
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
|
||||
if self.flags.hit_bottom_wall() {
|
||||
self.action_counter2 += 1;
|
||||
|
@ -1190,9 +1191,6 @@ impl NPC {
|
|||
_ => (),
|
||||
}
|
||||
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
|
||||
self.vel_y = self.vel_y.clamp(-0x5ff, 0x5ff);
|
||||
|
||||
self.anim_num += 1;
|
||||
|
@ -1277,9 +1275,7 @@ impl NPC {
|
|||
self.action_num = 2;
|
||||
self.action_counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if self.action_num == 2 {
|
||||
} else if self.action_num == 2 {
|
||||
self.animate(3, 0, 1);
|
||||
|
||||
self.action_counter += 1;
|
||||
|
@ -1415,7 +1411,7 @@ impl NPC {
|
|||
|
||||
for _ in 0..4 {
|
||||
npc.x = self.x + self.rng.range(-12..12) as i32 * 0x200;
|
||||
npc.y = self.y + 0x2000 + self.rng.range(-12..12) as i32 * 0x200;
|
||||
npc.y = self.y + 0x2000;
|
||||
npc.vel_x = self.rng.range(-0x155..0x155) as i32;
|
||||
npc.vel_y = self.rng.range(-0x600..0) as i32;
|
||||
|
||||
|
@ -1524,9 +1520,7 @@ impl NPC {
|
|||
self.action_num = 2;
|
||||
self.vel_y = 0x300;
|
||||
}
|
||||
}
|
||||
|
||||
if self.action_num == 2 {
|
||||
} else if self.action_num == 2 {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
self.action_counter3 += 4;
|
||||
|
@ -1559,24 +1553,22 @@ impl NPC {
|
|||
self.action_counter3 = self.tsc_direction;
|
||||
}
|
||||
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
if self.action_num == 1 {
|
||||
if let Some(parent) = self.get_parent_ref_mut(npc_list) {
|
||||
if parent.npc_type == 187 && parent.cond.alive() {
|
||||
let deg = (self.action_counter3.wrapping_add(parent.action_counter3) & 0xff) as f64 * CDEG_RAD;
|
||||
|
||||
self.x = parent.x + 20 * (deg.sin() * -512.0) as i32;
|
||||
self.y = parent.y + 32 * (deg.cos() * -512.0) as i32;
|
||||
self.x = parent.x + 20 * (deg.sin() * 512.0) as i32;
|
||||
self.y = parent.y + 32 * (deg.cos() * 512.0) as i32;
|
||||
} else {
|
||||
self.vel_x = self.rng.range(-512..512);
|
||||
self.vel_y = self.rng.range(-512..512);
|
||||
self.action_num = 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
if self.action_num == 10 {
|
||||
} else if self.action_num == 10 {
|
||||
self.vel_x += if player.x >= self.x { 0x20 } else { -0x20 };
|
||||
|
||||
self.vel_y += if player.y >= self.y { 0x20 } else { -0x20 };
|
||||
|
|
|
@ -92,11 +92,8 @@ impl NPC {
|
|||
}
|
||||
|
||||
pub(crate) fn tick_n013_forcefield(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
self.anim_counter = (self.anim_counter + 1) % 2;
|
||||
if self.anim_counter == 1 {
|
||||
self.anim_num = (self.anim_num + 1) % 4;
|
||||
self.anim_rect = state.constants.npc.n013_forcefield[self.anim_num as usize];
|
||||
}
|
||||
self.anim_num = (self.anim_num + 1) % 4;
|
||||
self.anim_rect = state.constants.npc.n013_forcefield[self.anim_num as usize];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -662,7 +662,7 @@ impl NPC {
|
|||
self.vel_x = 0;
|
||||
self.vel_y = 0;
|
||||
|
||||
npc_list.remove_by_type(252, state);
|
||||
npc_list.kill_npcs_by_type(252, true, state);
|
||||
|
||||
let mut npc = NPC::create(4, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
|
|
|
@ -13,15 +13,15 @@ use crate::util::rng::RNG;
|
|||
impl NPC {
|
||||
pub(crate) fn tick_n044_polish(&mut self, state: &mut SharedGameState, npc_list: &NPCList) -> GameResult {
|
||||
match self.action_num {
|
||||
0 | 1 => {
|
||||
self.anim_num = 0;
|
||||
self.action_num = match self.direction {
|
||||
Direction::Left => 8,
|
||||
Direction::Right => 2,
|
||||
_ => 8,
|
||||
};
|
||||
}
|
||||
2 => {
|
||||
0 | 1 | 2 => {
|
||||
if self.action_num <= 1 {
|
||||
self.anim_num = 0;
|
||||
self.action_num = match self.direction {
|
||||
Direction::Left => 8,
|
||||
Direction::Right => 2,
|
||||
_ => 8,
|
||||
};
|
||||
}
|
||||
self.vel_y += 0x20;
|
||||
if self.vel_y > 0 && self.flags.hit_bottom_wall() {
|
||||
self.vel_y = -0x100;
|
||||
|
@ -575,7 +575,7 @@ impl NPC {
|
|||
|
||||
let parent = parent.unwrap();
|
||||
|
||||
let angle = self.vel_x + parent.vel_y2;
|
||||
let angle = (self.vel_x + parent.vel_y2) & 0xFF;
|
||||
|
||||
if self.action_num < 2 {
|
||||
if self.action_num == 0 {
|
||||
|
@ -773,22 +773,25 @@ impl NPC {
|
|||
self.anim_counter = self.rng.range(0..4) as u16;
|
||||
self.action_counter2 = 120;
|
||||
|
||||
let mut angle = self.rng.range(0..255);
|
||||
let angle = self.rng.range(0..255);
|
||||
|
||||
self.vel_x = ((angle as f64 * CDEG_RAD).cos() * -512.0) as i32;
|
||||
angle += 0x40;
|
||||
self.target_x = self.x + 8 * ((angle as f64 * CDEG_RAD).cos() * -512.0) as i32;
|
||||
self.vel_y = ((angle as f64 * CDEG_RAD).sin() * -512.0) as i32;
|
||||
angle += 0x40;
|
||||
self.target_y = self.y + 8 * ((angle as f64 * CDEG_RAD).sin() * -512.0) as i32;
|
||||
self.vel_x = ((angle as f64 * CDEG_RAD).cos() * 512.0) as i32;
|
||||
self.target_x = self.x + 8 * (((angle + 0x40) as f64 * CDEG_RAD).cos() * 512.0) as i32;
|
||||
|
||||
let angle = self.rng.range(0..255);
|
||||
self.vel_y = ((angle as f64 * CDEG_RAD).sin() * 512.0) as i32;
|
||||
self.target_y = self.y + 8 * (((angle + 0x40) as f64 * CDEG_RAD).sin() * 512.0) as i32;
|
||||
}
|
||||
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
self.direction = if self.x > player.x { Direction::Left } else { Direction::Right };
|
||||
|
||||
self.vel_x += ((self.target_x - self.x).signum() * 0x10).clamp(-0x200, 0x200);
|
||||
self.vel_y += ((self.target_y - self.y).signum() * 0x10).clamp(-0x200, 0x200);
|
||||
self.vel_x += (self.target_x - self.x).signum() * 0x10;
|
||||
self.vel_y += (self.target_y - self.y).signum() * 0x10;
|
||||
|
||||
self.vel_x = clamp(self.vel_x, -0x200, 0x200);
|
||||
self.vel_y = clamp(self.vel_y, -0x200, 0x200);
|
||||
|
||||
if self.shock != 0 {
|
||||
self.action_num = 2;
|
||||
|
@ -802,7 +805,7 @@ impl NPC {
|
|||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
self.direction = if self.x > player.x { Direction::Left } else { Direction::Right };
|
||||
self.vel_x += if self.y <= player.y + 0x4000 {
|
||||
self.vel_x += if self.y <= player.y + 0x6000 {
|
||||
(player.x - self.x).signum() * 0x10
|
||||
} else {
|
||||
(self.x - player.x).signum() * 0x10
|
||||
|
@ -1020,7 +1023,7 @@ impl NPC {
|
|||
}
|
||||
self.vel_y += 32;
|
||||
|
||||
self.vel_x = self.vel_x.clamp(-0x200, 0x200);
|
||||
self.vel_x = self.vel_x.clamp(-0x1FF, 0x1FF);
|
||||
|
||||
self.clamp_fall_speed();
|
||||
self.y += self.vel_y;
|
||||
|
@ -1223,23 +1226,24 @@ impl NPC {
|
|||
}
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
self.action_counter += 1;
|
||||
if self.action_counter > 8 {
|
||||
self.action_num = 1;
|
||||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.action_counter += 1;
|
||||
if self.action_counter > 8 {
|
||||
self.action_num = 1;
|
||||
self.anim_num = 0;
|
||||
}
|
||||
|
||||
self.vel_y += 0x40;
|
||||
self.clamp_fall_speed();
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
|
||||
let anim = if self.direction == Direction::Left { 0 } else { 4 };
|
||||
let dir_offset = if self.direction == Direction::Left { 0 } else { 4 };
|
||||
|
||||
self.anim_rect = state.constants.npc.n130_puppy_sitting[anim];
|
||||
self.anim_rect = state.constants.npc.n130_puppy_sitting[self.anim_num as usize + dir_offset];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1263,6 +1267,7 @@ impl NPC {
|
|||
state: &mut SharedGameState,
|
||||
players: [&mut Player; 2],
|
||||
) -> GameResult {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
match self.action_num {
|
||||
0 | 1 => {
|
||||
if self.action_num == 0 {
|
||||
|
@ -1277,13 +1282,16 @@ impl NPC {
|
|||
self.anim_num = 1;
|
||||
}
|
||||
|
||||
let player = self.get_closest_player_mut(players);
|
||||
if (self.x - player.x).abs() < 0x8000 && (self.y - player.y).abs() < 0x2000 {
|
||||
self.animate(4, 2, 4);
|
||||
|
||||
if self.anim_num == 4 && self.anim_counter == 0 {
|
||||
state.sound_manager.play_sfx(105);
|
||||
}
|
||||
} else {
|
||||
if self.anim_num == 4 {
|
||||
self.anim_num = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
|
@ -1343,6 +1351,10 @@ impl NPC {
|
|||
_ => (),
|
||||
}
|
||||
|
||||
if self.action_num < 100 {
|
||||
self.face_player(player);
|
||||
}
|
||||
|
||||
self.vel_y += 0x40;
|
||||
self.clamp_fall_speed();
|
||||
|
||||
|
|
|
@ -590,88 +590,89 @@ impl NPC {
|
|||
players: [&mut Player; 2],
|
||||
npc_list: &NPCList,
|
||||
) -> GameResult {
|
||||
if self.action_num != 1 {
|
||||
if 1 < self.action_num {
|
||||
if self.action_num == 10 {
|
||||
if (self.flags.0 & 0xf) == 0 {
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
match self.action_num {
|
||||
0 | 1 => {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
self.action_counter = 0;
|
||||
}
|
||||
let parent = self.get_parent_ref_mut(npc_list);
|
||||
if let Some(parent) = parent {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
if parent.direction == Direction::Left {
|
||||
self.x = parent.x + 0x1400;
|
||||
} else {
|
||||
self.action_num = 0x14;
|
||||
self.action_counter = 0;
|
||||
|
||||
state.create_caret(self.x, self.y, CaretType::ProjectileDissipation, Direction::Left);
|
||||
state.sound_manager.play_sfx(0xc);
|
||||
|
||||
let mut npc = NPC::create(4, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
for _ in 0..4 {
|
||||
npc.x = self.x;
|
||||
npc.y = self.y;
|
||||
npc.vel_x = self.rng.range(-0x200..0x200);
|
||||
npc.vel_y = self.rng.range(-0x200..0x200);
|
||||
|
||||
let _ = npc_list.spawn(0x100, npc.clone());
|
||||
}
|
||||
self.x = parent.x + -0x1400;
|
||||
}
|
||||
} else if self.action_num == 0x14 {
|
||||
|
||||
self.y = parent.y + -0x1000;
|
||||
if (parent.action_num == 0x18) || (parent.action_num == 0x34) {
|
||||
self.action_num = 10;
|
||||
if parent.direction == Direction::Left {
|
||||
self.x = parent.x + -0x2000;
|
||||
} else {
|
||||
self.x = parent.x + 0x2000;
|
||||
}
|
||||
self.y = parent.y;
|
||||
|
||||
let angle = f64::atan2((self.y - player.y) as f64, (self.x - player.x) as f64);
|
||||
|
||||
self.vel_x = (angle.cos() * -2048.0) as i32;
|
||||
self.vel_y = (angle.sin() * -2048.0) as i32;
|
||||
state.sound_manager.play_sfx(0x27);
|
||||
}
|
||||
}
|
||||
}
|
||||
10 => {
|
||||
if (self.flags.0 & 0xf) == 0 {
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
self.action_counter += 1;
|
||||
if 4 < self.action_counter {
|
||||
let mut npc = NPC::create(4, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
for _ in 0..4 {
|
||||
npc.x = self.x;
|
||||
npc.y = self.y;
|
||||
npc.vel_x = self.rng.range(-0x200..0x200);
|
||||
npc.vel_y = self.rng.range(-0x200..0x200);
|
||||
|
||||
let _ = npc_list.spawn(0x100, npc.clone());
|
||||
}
|
||||
|
||||
self.npc_type = 0x8e;
|
||||
self.anim_num = 0;
|
||||
self.action_num = 0x14;
|
||||
self.vel_x = 0;
|
||||
self.npc_flags.set_invulnerable(false);
|
||||
self.npc_flags.set_shootable(true);
|
||||
self.damage = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
self.action_counter = 0;
|
||||
}
|
||||
} else {
|
||||
let parent = self.get_parent_ref_mut(npc_list);
|
||||
if let Some(parent) = parent {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
if parent.direction == Direction::Left {
|
||||
self.x = parent.x + 0x1400;
|
||||
} else {
|
||||
self.x = parent.x + -0x1400;
|
||||
}
|
||||
self.action_num = 0x14;
|
||||
self.action_counter = 0;
|
||||
|
||||
self.y = parent.y + -0x1000;
|
||||
if (parent.action_num == 0x18) || (parent.action_num == 0x34) {
|
||||
self.action_num = 10;
|
||||
if parent.direction == Direction::Left {
|
||||
self.x = parent.x + -0x2000;
|
||||
} else {
|
||||
self.x = parent.x + 0x2000;
|
||||
state.create_caret(self.x, self.y, CaretType::ProjectileDissipation, Direction::Left);
|
||||
state.sound_manager.play_sfx(0xc);
|
||||
|
||||
let mut npc = NPC::create(4, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
for _ in 0..4 {
|
||||
npc.x = self.x;
|
||||
npc.y = self.y;
|
||||
npc.vel_x = self.rng.range(-0x200..0x200);
|
||||
npc.vel_y = self.rng.range(-0x200..0x200);
|
||||
|
||||
let _ = npc_list.spawn(0x100, npc.clone());
|
||||
}
|
||||
self.y = parent.y;
|
||||
|
||||
let angle = f64::atan2((self.y - player.y) as f64, (self.x - player.x) as f64);
|
||||
|
||||
self.vel_x = (angle.cos() * -2048.0) as i32;
|
||||
self.vel_y = (angle.sin() * -2048.0) as i32;
|
||||
state.sound_manager.play_sfx(0x27);
|
||||
}
|
||||
}
|
||||
20 => {
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
self.action_counter += 1;
|
||||
if 4 < self.action_counter {
|
||||
let mut npc = NPC::create(4, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
for _ in 0..4 {
|
||||
npc.x = self.x;
|
||||
npc.y = self.y;
|
||||
npc.vel_x = self.rng.range(-0x200..0x200);
|
||||
npc.vel_y = self.rng.range(-0x200..0x200);
|
||||
|
||||
let _ = npc_list.spawn(0x100, npc.clone());
|
||||
}
|
||||
|
||||
self.npc_type = 0x8e;
|
||||
self.anim_num = 0;
|
||||
self.action_num = 0x14;
|
||||
self.vel_x = 0;
|
||||
self.npc_flags.set_invulnerable(false);
|
||||
self.npc_flags.set_shootable(true);
|
||||
self.damage = 1;
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.anim_num += 1;
|
||||
|
|
|
@ -1754,7 +1754,7 @@ impl BossNPC {
|
|||
self.parts[0].action_counter = 0;
|
||||
self.parts[0].vel_x = 0;
|
||||
self.parts[0].vel_y = 0;
|
||||
npc_list.kill_npcs_by_type(339, true, state);
|
||||
npc_list.kill_npcs_by_type(339, false, state);
|
||||
}
|
||||
|
||||
self.parts[0].y += (0x13E00 - self.parts[0].y) / 8;
|
||||
|
|
|
@ -180,6 +180,10 @@ impl BossNPC {
|
|||
self.parts[7].x = self.parts[0].x - 0x6000;
|
||||
self.parts[7].y = self.parts[0].y + 0x4000;
|
||||
|
||||
for i in [2,3,6,7] {
|
||||
self.hurt_sound[i] = 54;
|
||||
}
|
||||
|
||||
for part in &mut self.parts {
|
||||
part.prev_x = part.x;
|
||||
part.prev_y = part.y;
|
||||
|
|
|
@ -81,6 +81,8 @@ impl GameEntity<([&mut Player; 2], &NPCList, &mut Stage, &BulletManager, &mut Fl
|
|||
),
|
||||
) -> GameResult {
|
||||
if !self.parts[0].cond.alive() {
|
||||
// Kind of hacky but fixes Monster X's damage popup being stuck on screen
|
||||
self.parts[0].popup.tick(state, ())?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
|
|
@ -180,11 +180,9 @@ impl BossNPC {
|
|||
self.parts[3].hit_bounds =
|
||||
Rect { left: 5 * 0x200, top: 5 * 0x200, right: 5 * 0x200, bottom: 5 * 0x200 };
|
||||
self.parts[3].npc_flags.set_ignore_solidity(true);
|
||||
self.hurt_sound[3] = 54;
|
||||
self.death_sound[3] = 71;
|
||||
|
||||
self.parts[4] = self.parts[3].clone();
|
||||
self.parts[3].target_x = 1;
|
||||
self.parts[4].target_x = 1;
|
||||
|
||||
self.parts[5] = self.parts[3].clone();
|
||||
self.parts[6] = self.parts[3].clone();
|
||||
|
@ -193,6 +191,11 @@ impl BossNPC {
|
|||
self.parts[5].life = 100;
|
||||
self.parts[6].life = 100;
|
||||
|
||||
for i in 3..7 {
|
||||
self.hurt_sound[i] = 54;
|
||||
self.death_sound[i] = 71;
|
||||
}
|
||||
|
||||
self.parts[7].cond.set_alive(true);
|
||||
self.parts[7].x = self.parts[0].x;
|
||||
self.parts[7].y = self.parts[0].y;
|
||||
|
@ -202,6 +205,7 @@ impl BossNPC {
|
|||
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].npc_flags.set_ignore_solidity(true);
|
||||
self.hurt_sound[7] = 52;
|
||||
|
||||
self.parts[9].cond.set_alive(true);
|
||||
self.parts[9].x = self.parts[0].x - 64 * 0x200;
|
||||
|
@ -264,8 +268,6 @@ impl BossNPC {
|
|||
self.parts[0].action_num = 11;
|
||||
self.parts[0].action_counter = 0;
|
||||
self.parts[0].action_counter2 = 0;
|
||||
|
||||
self.parts[7].action_num = 2;
|
||||
}
|
||||
|
||||
self.parts[0].action_counter += 1;
|
||||
|
@ -466,11 +468,9 @@ impl BossNPC {
|
|||
state.sound_manager.play_sfx(52);
|
||||
}
|
||||
|
||||
let mut npc = NPC::create(4, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
npc.x = self.parts[0].x + self.parts[0].rng.range(-72..72) as i32 * 0x200;
|
||||
npc.y = self.parts[0].y + self.parts[0].rng.range(-64..64) as i32 * 0x200;
|
||||
let _ = npc_list.spawn(0x100, npc);
|
||||
let x = self.parts[0].x + self.parts[0].rng.range(-72..72) as i32 * 0x200;
|
||||
let y = self.parts[0].y + self.parts[0].rng.range(-64..64) as i32 * 0x200;
|
||||
npc_list.create_death_smoke(x, y, 1, 1, state, &self.parts[0].rng);
|
||||
|
||||
if self.parts[0].action_counter > 100 {
|
||||
self.parts[0].action_num = 1001;
|
||||
|
@ -489,16 +489,12 @@ impl BossNPC {
|
|||
part.cond.set_alive(false);
|
||||
}
|
||||
|
||||
for npc in npc_list.iter_alive() {
|
||||
if npc.npc_type == 158 {
|
||||
npc.cond.set_alive(false);
|
||||
}
|
||||
}
|
||||
npc_list.kill_npcs_by_type(158, true, state);
|
||||
|
||||
let mut npc = NPC::create(159, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
npc.x = self.parts[0].x;
|
||||
npc.y = self.parts[1].y - 24 * 0x200;
|
||||
npc.y = self.parts[0].y - 24 * 0x200;
|
||||
|
||||
let _ = npc_list.spawn(0, npc);
|
||||
}
|
||||
|
@ -552,9 +548,6 @@ impl BossNPC {
|
|||
match self.parts[i].action_num {
|
||||
0 => {
|
||||
self.parts[0].npc_flags.set_shootable(false);
|
||||
self.parts[i].anim_num = 2;
|
||||
}
|
||||
2 => {
|
||||
self.parts[i].anim_num = 0;
|
||||
}
|
||||
10 | 11 => {
|
||||
|
@ -565,7 +558,7 @@ impl BossNPC {
|
|||
}
|
||||
|
||||
if self.parts[0].shock > 0 {
|
||||
self.parts[i].action_counter2 += 1;
|
||||
self.parts[i].action_counter2 = self.parts[i].action_counter2.wrapping_add(1);
|
||||
if self.parts[i].action_counter2 / 2 % 2 != 0 {
|
||||
self.parts[i].anim_num = 1;
|
||||
} else {
|
||||
|
@ -575,16 +568,16 @@ impl BossNPC {
|
|||
self.parts[i].anim_num = 0;
|
||||
}
|
||||
}
|
||||
40 => {
|
||||
self.parts[0].npc_flags.set_shootable(false);
|
||||
self.parts[i].anim_num = 0;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.parts[i].x = self.parts[0].x;
|
||||
self.parts[i].y = self.parts[0].y;
|
||||
|
||||
if self.parts[0].action_num <= 10 {
|
||||
self.parts[i].anim_num = 2;
|
||||
}
|
||||
|
||||
self.parts[i].anim_rect = state.constants.npc.b03_monster_x[self.parts[i].anim_num as usize];
|
||||
}
|
||||
|
||||
|
@ -812,7 +805,7 @@ impl BossNPC {
|
|||
if self.parts[i].target_x < 0 {
|
||||
self.parts[i].target_x = 0;
|
||||
self.parts[i].action_num = 0;
|
||||
self.parts[7].action_num = 40;
|
||||
self.parts[7].action_num = 0;
|
||||
self.parts[13].action_num = 0;
|
||||
self.parts[14].action_num = 0;
|
||||
self.parts[15].action_num = 0;
|
||||
|
|
|
@ -75,6 +75,7 @@ impl BossNPC {
|
|||
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.hurt_sound[0] = 52;
|
||||
|
||||
self.parts[1].cond.set_alive(true);
|
||||
self.parts[1].display_bounds =
|
||||
|
@ -100,6 +101,7 @@ impl BossNPC {
|
|||
self.parts[4].display_bounds = self.parts[3].display_bounds;
|
||||
self.parts[4].hit_bounds = self.parts[3].hit_bounds;
|
||||
self.parts[4].npc_flags = self.parts[3].npc_flags;
|
||||
self.parts[4].x = self.parts[0].x - 0x2000;
|
||||
self.parts[4].y = self.parts[3].y;
|
||||
self.parts[4].direction = Direction::Right;
|
||||
self.hurt_sound[4] = 52;
|
||||
|
@ -166,7 +168,7 @@ impl BossNPC {
|
|||
}
|
||||
60 => {
|
||||
self.parts[0].action_counter += 1;
|
||||
if self.parts[0].action_counter % 3 == 0 && (20..80).contains(&self.parts[0].action_counter) {
|
||||
if self.parts[0].action_counter % 3 == 0 && (21..80).contains(&self.parts[0].action_counter) {
|
||||
let mut npc = NPC::create(48, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
npc.x = self.parts[0].x;
|
||||
|
@ -195,6 +197,8 @@ impl BossNPC {
|
|||
match self.parts[0].anim_num {
|
||||
1 => self.parts[0].damage = 20,
|
||||
0 => {
|
||||
state.sound_manager.stop_sfx(102);
|
||||
state.sound_manager.play_sfx(12);
|
||||
self.parts[0].action_num = 80;
|
||||
self.parts[0].action_counter = 0;
|
||||
self.parts[0].npc_flags.set_shootable(false);
|
||||
|
@ -297,7 +301,7 @@ impl BossNPC {
|
|||
|
||||
state.sound_manager.play_sfx(12);
|
||||
state.sound_manager.play_sfx(25);
|
||||
state.sound_manager.play_sfx(102);
|
||||
state.sound_manager.stop_sfx(102);
|
||||
}
|
||||
1 => {
|
||||
self.parts[0].damage = 20;
|
||||
|
@ -427,13 +431,9 @@ impl BossNPC {
|
|||
self.parts[0].action_num = 150;
|
||||
self.parts[0].action_counter = 0;
|
||||
self.parts[0].damage = 0;
|
||||
self.parts[5].damage = 5;
|
||||
self.parts[5].damage = 0;
|
||||
|
||||
for npc in npc_list.iter_alive() {
|
||||
if npc.npc_type == 48 {
|
||||
npc.cond.set_alive(false);
|
||||
}
|
||||
}
|
||||
npc_list.kill_npcs_by_type(48, true, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -225,7 +225,7 @@ impl BossNPC {
|
|||
1020 => {
|
||||
self.parts[0].action_counter += 1;
|
||||
if self.parts[0].action_counter > 50 {
|
||||
npc_list.remove_by_type(211, state);
|
||||
npc_list.kill_npcs_by_type(211, true, state);
|
||||
|
||||
self.parts[0].cond.set_alive(false);
|
||||
self.parts[1].cond.set_alive(false);
|
||||
|
|
|
@ -266,13 +266,13 @@ impl NPCList {
|
|||
|
||||
match npc.size {
|
||||
1 => {
|
||||
self.create_death_smoke(npc.x, npc.y, npc.display_bounds.right as usize, 3, state, &npc.rng);
|
||||
self.create_death_smoke(npc.x, npc.y, npc.display_bounds.right as usize, 4, state, &npc.rng);
|
||||
}
|
||||
2 => {
|
||||
self.create_death_smoke(npc.x, npc.y, npc.display_bounds.right as usize, 7, state, &npc.rng);
|
||||
self.create_death_smoke(npc.x, npc.y, npc.display_bounds.right as usize, 8, state, &npc.rng);
|
||||
}
|
||||
3 => {
|
||||
self.create_death_smoke(npc.x, npc.y, npc.display_bounds.right as usize, 12, state, &npc.rng);
|
||||
self.create_death_smoke(npc.x, npc.y, npc.display_bounds.right as usize, 16, state, &npc.rng);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
@ -348,7 +348,7 @@ impl NPCList {
|
|||
}
|
||||
|
||||
/// Removes NPCs whose event number matches the provided one.
|
||||
pub fn remove_by_event(&self, event_num: u16, state: &mut SharedGameState) {
|
||||
pub fn kill_npcs_by_event(&self, event_num: u16, state: &mut SharedGameState) {
|
||||
for npc in self.iter_alive() {
|
||||
if npc.event_num == event_num {
|
||||
npc.cond.set_alive(false);
|
||||
|
@ -357,23 +357,6 @@ impl NPCList {
|
|||
}
|
||||
}
|
||||
|
||||
/// Removes NPCs (and creates a smoke effect) whose type IDs match the provided one.
|
||||
pub fn remove_by_type(&self, npc_type: u16, state: &mut SharedGameState) {
|
||||
for npc in self.iter_alive() {
|
||||
if npc.npc_type == npc_type {
|
||||
npc.cond.set_alive(false);
|
||||
state.set_flag(npc.flag_num as usize, true);
|
||||
|
||||
match npc.size {
|
||||
1 => self.create_death_smoke(npc.x, npc.y, npc.display_bounds.right as usize, 4, state, &npc.rng),
|
||||
2 => self.create_death_smoke(npc.x, npc.y, npc.display_bounds.right as usize, 8, state, &npc.rng),
|
||||
3 => self.create_death_smoke(npc.x, npc.y, npc.display_bounds.right as usize, 16, state, &npc.rng),
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates NPC death smoke diffusing in random directions.
|
||||
#[inline]
|
||||
pub fn create_death_smoke(
|
||||
|
|
|
@ -262,19 +262,20 @@ impl Player {
|
|||
}
|
||||
|
||||
if state.control_flags.control_enabled() {
|
||||
let trigger_only_down = self.controller.trigger_down()
|
||||
&& !self.controller.trigger_up()
|
||||
&& !self.controller.trigger_left()
|
||||
&& !self.controller.trigger_right()
|
||||
&& !self.controller.trigger_shoot();
|
||||
|
||||
let only_down = self.controller.move_down()
|
||||
&& !self.controller.move_up()
|
||||
&& !self.controller.move_left()
|
||||
&& !self.controller.move_right()
|
||||
&& !self.controller.shoot();
|
||||
&& !self.controller.shoot()
|
||||
&& !self.controller.jump()
|
||||
&& !self.controller.prev_weapon()
|
||||
&& !self.controller.next_weapon()
|
||||
&& !self.controller.map()
|
||||
&& !self.controller.inventory()
|
||||
&& !self.controller.strafe();
|
||||
// Leaving the skip button unchecked as a "feature" :)
|
||||
|
||||
if trigger_only_down
|
||||
if self.controller.trigger_down()
|
||||
&& only_down
|
||||
&& !self.cond.interacted()
|
||||
&& !state.control_flags.interactions_disabled()
|
||||
|
|
|
@ -1369,14 +1369,14 @@ impl TextScriptVM {
|
|||
TSCOpCode::DNP => {
|
||||
let event_num = read_cur_varint(&mut cursor)? as u16;
|
||||
|
||||
game_scene.npc_list.remove_by_event(event_num, state);
|
||||
game_scene.npc_list.kill_npcs_by_event(event_num, state);
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
TSCOpCode::DNA => {
|
||||
let npc_remove_type = read_cur_varint(&mut cursor)? as u16;
|
||||
|
||||
game_scene.npc_list.remove_by_type(npc_remove_type, state);
|
||||
game_scene.npc_list.kill_npcs_by_type(npc_remove_type, true, state);
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
|
|
|
@ -1953,8 +1953,8 @@ impl PhysicalEntity for Bullet {
|
|||
let mut npc = NPC::create(4, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
npc.direction = Direction::Left;
|
||||
npc.x = (x * 16 + 8) * 0x200;
|
||||
npc.y = (y * 16 + 8) * 0x200;
|
||||
npc.x = (x + ox) * tile_size;
|
||||
npc.y = (y + oy) * tile_size;
|
||||
|
||||
for _ in 0..4 {
|
||||
npc.vel_x = npc.rng.range(-0x200..0x200) as i32;
|
||||
|
|
Loading…
Reference in a new issue