1
0
Fork 0
mirror of https://github.com/doukutsu-rs/doukutsu-rs synced 2024-11-26 07:22:45 +00:00

needs more misery

This commit is contained in:
Alula 2021-10-10 01:47:04 +02:00
parent e018b53b04
commit 481f61a705
No known key found for this signature in database
GPG key ID: 3E00485503A1D8BA
18 changed files with 797 additions and 48 deletions

View file

@ -772,8 +772,8 @@ pub struct NPCConsts {
#[serde(default = "default_n258_mimiga_sleeping")]
pub n258_mimiga_sleeping: Rect<u16>,
#[serde(default = "default_n259_curly_unconcious")]
pub n259_curly_unconcious: [Rect<u16>; 2],
#[serde(default = "default_n259_curly_unconscious")]
pub n259_curly_unconscious: [Rect<u16>; 2],
#[serde(default = "default_n260_shovel_brigade_caged")]
pub n260_shovel_brigade_caged: [Rect<u16>; 6],
@ -3794,7 +3794,7 @@ fn default_n258_mimiga_sleeping() -> Rect<u16> {
Rect { left: 48, top: 32, right: 64, bottom: 48 }
}
fn default_n259_curly_unconcious() -> [Rect<u16>; 2] {
fn default_n259_curly_unconscious() -> [Rect<u16>; 2] {
[
Rect { left: 224, top: 96, right: 240, bottom: 112 },
Rect { left: 224, top: 112, right: 240, bottom: 128 },

View file

@ -326,7 +326,7 @@ impl NPC {
}
self.action_counter2 += 1;
self.x += if self.action_counter2 / 2 % 2 != 0 { 0x200 } else { -0x200 };
self.x += if self.action_counter2 & 0x02 != 0 { 0x200 } else { -0x200 };
if self.action_counter > 100 {
self.action_num = 11;
@ -365,7 +365,7 @@ impl NPC {
}
self.anim_counter += 1;
self.anim_num = if self.anim_counter / 2 % 2 != 0 { 5 } else { 6 };
self.anim_num = if self.anim_counter & 0x02 != 0 { 5 } else { 6 };
}
42 | 43 => {
if self.action_num == 42 {
@ -385,7 +385,7 @@ impl NPC {
}
self.anim_counter += 1;
self.anim_num = if self.anim_counter / 2 % 2 != 0 { 7 } else { 6 };
self.anim_num = if self.anim_counter & 0x02 != 0 { 7 } else { 6 };
}
50 => {
self.anim_num = 8;
@ -438,7 +438,7 @@ impl NPC {
}
self.action_counter2 += 1;
self.x += if self.action_counter2 / 2 % 2 != 0 { 0x200 } else { -0x200 };
self.x += if self.action_counter2 & 0x02 != 0 { 0x200 } else { -0x200 };
self.anim_num = 5;
self.vel_x = 0;

View file

@ -88,7 +88,7 @@ impl NPC {
if self.action_num == 31 {
self.anim_rect.bottom = self.action_counter / 4 + self.anim_rect.top;
if self.action_counter / 2 % 2 != 0 {
if self.action_counter & 0x02 != 0 {
self.anim_rect.left += 1;
}
}

View file

@ -785,4 +785,54 @@ impl NPC {
Ok(())
}
pub(crate) fn tick_n259_curly_unconcious(
&mut self,
state: &mut SharedGameState,
players: [&mut Player; 2],
npc_list: &NPCList,
) -> GameResult {
match self.action_num {
0 | 1 => {
if self.action_num == 0 {
self.npc_flags.set_interactable(false);
self.action_num = 1;
}
let player = &players[0];
self.direction = player.direction;
self.x = player.x + 0x600 * self.direction.opposite().vector_x();
self.y = player.y - 0x800;
let dir_offset = if self.direction == Direction::Left { 0 } else { 1 };
self.anim_rect = state.constants.npc.n259_curly_unconscious[dir_offset];
if (player.anim_num & 1) != 0 {
self.anim_rect.top += 1;
}
}
10 => {
self.action_num = 11;
self.vel_x = 0x40;
self.vel_y = -0x20;
self.anim_rect = state.constants.npc.n259_curly_unconscious[0];
}
11 => {
if self.y <= 0x7FFF {
self.vel_y = 0x20;
}
self.x += self.vel_x;
self.y += self.vel_y;
}
20 => {
self.vanish(state);
npc_list.create_death_smoke_up(self.x, self.y, 0x2000, 64, state, &self.rng);
}
_ => (),
}
Ok(())
}
}

View file

@ -111,4 +111,48 @@ impl NPC {
Ok(())
}
pub(crate) fn tick_n257_red_crystal(&mut self, state: &mut SharedGameState) -> GameResult {
if self.action_num == 0 {
self.action_num = 1;
}
if self.action_num == 1 {
if state.npc_super_pos.0 != 0 {
self.action_num = 10;
}
} else if self.action_num == 10 {
if self.x < state.npc_super_pos.0 {
self.vel_x += 0x55;
}
if self.x > state.npc_super_pos.0 {
self.vel_x -= 0x55;
}
if self.y < state.npc_super_pos.1 {
self.vel_y += 0x55;
}
if self.y > state.npc_super_pos.1 {
self.vel_y -= 0x55;
}
self.vel_x = self.vel_x.clamp(-0x400, 0x400);
self.vel_y = self.vel_y.clamp(-0x400, 0x400);
self.x += self.vel_x;
self.y += self.vel_y;
}
self.animate(3, 0, 1);
if self.direction == Direction::Left && self.vel_x > 0 {
self.anim_num = 2;
}
if self.direction == Direction::Right && self.vel_x < 0 {
self.anim_num = 2;
}
self.anim_rect = state.constants.npc.n257_red_crystal[self.anim_num as usize];
Ok(())
}
}

View file

@ -675,7 +675,7 @@ impl NPC {
}
}
if self.action_counter > 120 && self.action_counter / 2 % 2 == 1 && self.anim_num == 1 {
if self.action_counter > 120 && self.action_counter & 0x02 == 1 && self.anim_num == 1 {
self.anim_num = 2;
}
@ -1335,7 +1335,7 @@ impl NPC {
}
}
if self.action_counter > 120 && self.action_counter / 2 % 2 == 1 && self.anim_num == 1 {
if self.action_counter > 120 && self.action_counter & 0x02 == 1 && self.anim_num == 1 {
self.anim_num = 2;
}

View file

@ -928,7 +928,7 @@ impl NPC {
self.action_counter = 0;
}
if self.action_counter / 2 % 2 != 0 {
if self.action_counter & 0x02 != 0 {
self.x += 0x200;
state.sound_manager.play_sfx(11);
} else {

View file

@ -250,7 +250,7 @@ impl NPC {
state.sound_manager.play_sfx(12);
}
self.anim_num = if self.action_counter > 50 && (self.action_counter / 2 % 2) != 0 { 11 } else { 10 };
self.anim_num = if self.action_counter > 50 && (self.action_counter & 0x02) != 0 { 11 } else { 10 };
if self.action_counter > 132 {
self.action_num = 0;
@ -319,13 +319,13 @@ impl NPC {
let dir_offset = if self.direction == Direction::Left { 0 } else { 4 };
self.anim_rect = state.constants.npc.n089_igor_dead[dir_offset];
if (self.action_counter / 2 % 2) != 0 {
if (self.action_counter & 0x02) != 0 {
self.anim_rect.left -= 1;
}
}
2 => {
self.action_counter += 1;
if (self.action_counter / 2 % 2) != 0 && self.action_counter < 100 {
if (self.action_counter & 0x02) != 0 && self.action_counter < 100 {
self.anim_num = 0;
self.display_bounds.left = 20 * 0x200;
self.display_bounds.right = 20 * 0x200;

View file

@ -763,7 +763,7 @@ impl NPC {
self.anim_rect.top += self.action_counter3 / 8;
self.y = ((self.action_counter3 as i32 / 8) * 0x200) + self.target_y;
self.anim_rect.left -= self.action_counter3 / 2 % 2;
self.anim_rect.left -= if (self.action_counter3 & 0x02) != 0 { 1 } else { 0 };
}
if self.action_counter3 % 3 == 2 {
let mut npc = NPC::create(161, &state.npc_table);

View file

@ -4,8 +4,8 @@ use crate::caret::CaretType;
use crate::common::{Direction, Rect};
use crate::components::flash::Flash;
use crate::framework::error::GameResult;
use crate::npc::{NPC, NPCLayer};
use crate::npc::list::NPCList;
use crate::npc::{NPCLayer, NPC};
use crate::player::Player;
use crate::rng::RNG;
use crate::shared_game_state::SharedGameState;
@ -1679,6 +1679,105 @@ impl NPC {
Ok(())
}
pub(crate) fn tick_n238_press_sideways(
&mut self,
state: &mut SharedGameState,
players: [&mut Player; 2],
npc_list: &NPCList,
) -> GameResult {
let player = self.get_closest_player_ref(&players);
match self.action_num {
0 | 1 => {
if self.action_num == 0 {
self.action_num = 1;
self.target_x = self.x;
self.target_y = self.y;
self.display_bounds.left = 0x2000;
self.display_bounds.right = 0x1000;
}
if self.direction == Direction::Left
&& player.x < self.x
&& player.x > self.x - 0x18000
&& player.y > self.y - 0x800
&& player.y < self.y + 0x1000
{
self.action_num = 10;
self.action_counter = 0;
self.anim_num = 2;
}
if self.direction == Direction::Right
&& player.x > self.x
&& player.x < self.x + 0x18000
&& player.y > self.y - 0x800
&& player.y < self.y + 0x1000
{
self.action_num = 10;
self.action_counter = 0;
self.anim_num = 2;
}
}
10 => {
self.damage = 127;
self.x += if self.direction != Direction::Left { 0xC00 } else { -0xC00 };
self.action_counter += 1;
if self.action_counter == 8 {
self.action_num = 20;
self.action_counter = 0;
let mut npc = NPC::create(4, &state.npc_table);
npc.cond.set_alive(true);
for _ in 0..4 {
npc.x = self.x + self.rng.range(-16..16) * 0x200;
npc.y = self.y + self.rng.range(-8..8) * 0x200;
let _ = npc_list.spawn(0x100, npc.clone());
state.sound_manager.play_sfx(12);
}
}
}
20 => {
self.damage = 0;
self.action_counter += 1;
if self.action_counter > 50 {
self.action_counter = 0;
self.action_num = 30;
}
}
30 => {
self.damage = 0;
self.anim_num = 1;
self.action_counter += 1;
if self.action_counter == 12 {
self.action_num = 1;
self.action_counter = 0;
self.anim_num = 0;
}
self.x += if self.direction != Direction::Left { -0x800 } else { 0x800 };
}
_ => (),
}
if self.direction != Direction::Left || player.x >= self.x {
if self.direction == Direction::Right && player.x > self.x {
self.hit_bounds.right = 0x2000;
} else {
self.hit_bounds.right = 0x1000;
}
} else {
self.hit_bounds.right = 0x2000;
}
self.anim_rect = state.constants.npc.n238_press_sideways[self.anim_num as usize];
Ok(())
}
pub(crate) fn tick_n239_cage_bars(&mut self, state: &mut SharedGameState) -> GameResult {
if self.action_num == 0 {
self.action_num = 1;
@ -1699,6 +1798,31 @@ impl NPC {
Ok(())
}
pub(crate) fn tick_n253_experience_capsule(
&mut self,
state: &mut SharedGameState,
npc_list: &NPCList,
) -> GameResult {
if self.action_num == 0 {
self.action_num = 1;
}
self.animate(4, 0, 1);
if self.life <= 100 {
self.cond.set_alive(false);
self.create_xp_drop_custom(self.x, self.y, self.flag_num, state, npc_list);
npc_list.create_death_smoke(self.x, self.y, self.display_bounds.right as usize, 8, state, &self.rng);
state.sound_manager.play_sfx(25);
}
self.anim_rect = state.constants.npc.n253_experience_capsule[self.anim_num as usize];
Ok(())
}
pub(crate) fn tick_n258_mimiga_sleeping(&mut self, state: &mut SharedGameState) -> GameResult {
if self.action_num == 0 {
self.action_num = 1;

View file

@ -1,9 +1,14 @@
use std::hint::unreachable_unchecked;
use num_traits::clamp;
use crate::common::Direction;
use crate::caret::CaretType;
use crate::common::{Direction, CDEG_RAD};
use crate::components::flash::Flash;
use crate::framework::error::GameResult;
use crate::npc::list::NPCList;
use crate::npc::NPC;
use crate::player::Player;
use crate::rng::RNG;
use crate::shared_game_state::SharedGameState;
@ -18,7 +23,7 @@ impl NPC {
self.target_y = npc.y;
let angle = ((self.y - self.target_y) as f64 / (self.x - self.target_x) as f64).atan();
self.vel_x = (angle.cos() * 1024.0) as i32; // 2.0fix9
self.vel_x = (angle.cos() * 1024.0) as i32;
self.vel_y = (angle.sin() * 1024.0) as i32;
}
@ -66,7 +71,12 @@ impl NPC {
Ok(())
}
pub(crate) fn tick_n067_misery_floating(&mut self, state: &mut SharedGameState, npc_list: &NPCList) -> GameResult {
pub(crate) fn tick_n067_misery_floating(
&mut self,
state: &mut SharedGameState,
npc_list: &NPCList,
flash: &mut Flash,
) -> GameResult {
match self.action_num {
0 | 1 => {
if self.action_num == 0 {
@ -172,7 +182,7 @@ impl NPC {
self.action_counter += 1;
if self.action_counter == 30 {
state.sound_manager.play_sfx(101);
// todo flash
flash.set_blink();
self.action_num = 27;
self.anim_num = 7;
}
@ -193,7 +203,7 @@ impl NPC {
let (frame1, frame2) = match self.action_num {
11 => (0, 1),
14 => (2, 3),
_ => unreachable!(),
_ => unsafe { unreachable_unchecked() },
};
if self.anim_counter > 0 {
@ -209,6 +219,7 @@ impl NPC {
}
let dir_offset = if self.direction == Direction::Left { 0 } else { 8 };
self.anim_rect = state.constants.npc.n067_misery_floating[self.anim_num as usize + dir_offset];
if self.action_num == 1 && self.anim_counter < 32 {
@ -219,7 +230,12 @@ impl NPC {
Ok(())
}
pub(crate) fn tick_n082_misery_standing(&mut self, state: &mut SharedGameState, npc_list: &NPCList) -> GameResult {
pub(crate) fn tick_n082_misery_standing(
&mut self,
state: &mut SharedGameState,
npc_list: &NPCList,
flash: &mut Flash,
) -> GameResult {
match self.action_num {
0 | 1 => {
if self.action_num == 0 {
@ -292,10 +308,11 @@ impl NPC {
self.action_counter += 1;
if self.action_counter == 30 {
state.sound_manager.play_sfx(101);
// todo flash
self.action_num = 27;
self.anim_num = 7;
state.sound_manager.play_sfx(101);
flash.set_blink();
}
}
27 => {
@ -356,10 +373,8 @@ impl NPC {
self.x += self.vel_x;
self.y += self.vel_y;
if self.action_num == 11
{
if self.anim_counter != 0
{
if self.action_num == 11 {
if self.anim_counter != 0 {
self.anim_counter -= 1;
self.anim_num = 1;
} else {
@ -371,10 +386,8 @@ impl NPC {
}
}
if self.action_num == 14
{
if self.action_counter != 0
{
if self.action_num == 14 {
if self.action_counter != 0 {
self.action_counter -= 1;
self.anim_num = 3;
} else {
@ -387,11 +400,322 @@ impl NPC {
}
let dir_offset = if self.direction == Direction::Left { 0 } else { 9 };
self.anim_rect = state.constants.npc.n082_misery_standing[self.anim_num as usize + dir_offset];
Ok(())
}
pub(crate) fn tick_n247_misery_boss(
&mut self,
state: &mut SharedGameState,
players: [&mut Player; 2],
npc_list: &NPCList,
) -> GameResult {
match self.action_num {
0 | 1 => {
if self.action_num == 0 {
self.action_num = 1;
self.y += 0xc00;
self.target_y = 0x8000;
}
if self.rng.range(0..120) == 10 {
self.action_num = 2;
self.action_counter = 0;
self.anim_num = 1;
}
}
2 => {
self.action_counter += 1;
if self.action_counter > 8 {
self.action_num = 1;
self.anim_num = 0;
}
}
20 => {
self.vel_x = 0;
self.vel_y += 0x40;
if self.flags.hit_bottom_wall() {
self.action_num = 21;
self.anim_num = 2;
}
}
21 => {
if self.rng.range(0..120) == 10 {
self.action_num = 22;
self.action_counter = 0;
self.anim_num = 3;
}
}
22 => {
self.action_counter += 1;
if self.action_counter > 8 {
self.action_num = 21;
self.anim_num = 2;
}
}
100 | 101 => {
if self.action_num == 100 {
self.action_num = 101;
self.action_counter = 0;
self.anim_num = 0;
self.vel_x = 0;
self.npc_flags.set_shootable(true);
self.action_counter2 = self.life;
}
let player = self.get_closest_player_ref(&players);
if player.x >= self.x {
self.direction = Direction::Right;
} else {
self.direction = Direction::Left;
}
self.vel_y += if self.y >= self.target_y { -0x20 } else { 0x20 };
self.vel_y = self.vel_y.clamp(-0x200, 0x200);
self.action_counter += 1;
if self.action_counter > 200 || (self.life + 80) <= self.action_counter2 {
self.action_counter = 0;
self.action_num = 110;
}
}
110 | 111 => {
if self.action_num == 110 {
self.action_num = 111;
self.action_counter = 0;
self.vel_x = 0;
self.vel_y = 0;
self.npc_flags.set_shootable(false);
}
self.action_counter += 1;
self.anim_num = if (self.action_counter & 1) != 0 { 5 } else { 6 };
if self.action_counter > 30 {
self.action_counter3 += 1;
self.action_num = if self.action_counter3 % 3 == 0 { 113 } else { 112 };
self.action_counter = 0;
self.anim_num = 4;
}
}
112 => {
self.action_counter += 1;
if self.action_counter % 6 == 0 {
let player = self.get_closest_player_ref(&players);
let angle = f64::atan2((self.y - player.y) as f64, (self.x - player.x) as f64)
+ self.rng.range(-4..4) as f64 * CDEG_RAD;
let mut npc = NPC::create(248, &state.npc_table);
npc.cond.set_alive(true);
npc.x = self.x;
npc.y = self.y + 0x800;
npc.vel_x = (angle.cos() * -2048.0) as i32;
npc.vel_y = (angle.sin() * -2048.0) as i32;
let _ = npc_list.spawn(0x100, npc);
state.sound_manager.play_sfx(34);
}
if self.action_counter > 30 {
self.action_num = 150;
self.action_counter = 0;
}
}
113 => {
self.action_counter += 1;
if self.action_counter == 10 {
let player = self.get_closest_player_ref(&players);
let mut npc = NPC::create(279, &state.npc_table);
npc.cond.set_alive(true);
npc.x = player.x;
npc.y = player.y - 0x8000;
npc.direction = Direction::Up;
let _ = npc_list.spawn(0x100, npc);
}
if self.action_counter > 30 {
self.action_num = 150;
self.action_counter = 0;
}
}
150 | 151 => {
if self.action_num == 150 {
self.action_num = 151;
self.action_counter = 0;
self.anim_num = 7;
let mut npc = NPC::create(249, &state.npc_table);
npc.cond.set_alive(true);
npc.x = self.x;
npc.y = self.y;
let _ = npc_list.spawn(0x100, npc.clone());
npc.direction = Direction::Right;
let _ = npc_list.spawn(0x100, npc);
self.target_x = self.rng.range(9..31) * 0x2000;
self.target_y = self.rng.range(5..7) * 0x2000;
state.sound_manager.play_sfx(29);
}
self.action_counter += 1;
if self.action_counter == 42 {
let mut npc = NPC::create(249, &state.npc_table);
npc.cond.set_alive(true);
npc.x = self.target_x + 0x2000;
npc.y = self.target_y;
let _ = npc_list.spawn(0x100, npc.clone());
npc.x = self.x - 0x2000;
npc.direction = Direction::Right;
let _ = npc_list.spawn(0x100, npc);
}
if self.action_counter > 50 {
self.action_counter = 0;
self.vel_y = -0x200;
self.npc_flags.set_shootable(true);
self.x = self.target_x;
self.y = self.target_y;
if self.life < 340 {
let mut npc = NPC::create(252, &state.npc_table);
npc.cond.set_alive(true);
npc.parent_id = self.id;
let _ = npc_list.spawn(0x100, npc.clone());
npc.tsc_direction = 0x80;
let _ = npc_list.spawn(0x100, npc);
}
if self.life < 180 {
let mut npc = NPC::create(252, &state.npc_table);
npc.cond.set_alive(true);
npc.parent_id = self.id;
npc.tsc_direction = 0x40;
let _ = npc_list.spawn(0x100, npc.clone());
npc.tsc_direction = 0xc0;
let _ = npc_list.spawn(0x100, npc);
}
let player = self.get_closest_player_ref(&players);
self.action_num = if player.x > self.x - 0xe000 && player.x <= self.x + 0xe000 { 100 } else { 160 };
}
}
160 | 161 => {
if self.action_num == 160 {
self.action_num = 161;
self.action_counter = 0;
self.anim_num = 4;
let player = self.get_closest_player_ref(&players);
if player.x >= self.x {
self.direction = Direction::Right;
} else {
self.direction = Direction::Left;
}
}
self.vel_y += if self.y >= self.target_y { -0x20 } else { 0x20 };
self.vel_y = self.vel_y.clamp(-0x200, 0x200);
self.action_counter += 1;
if self.action_counter % 24 == 0 {
let mut npc = NPC::create(250, &state.npc_table);
npc.cond.set_alive(true);
npc.x = self.x;
npc.y = self.y + 0x800;
let _ = npc_list.spawn(0x100, npc);
state.sound_manager.play_sfx(34);
}
if self.action_counter > 72 {
self.action_counter = 0;
self.action_num = 100;
}
}
1000 | 1001 => {
if self.action_num == 1000 {
self.npc_flags.set_shootable(false);
self.action_num = 1001;
self.action_counter = 0;
self.anim_num = 4;
self.target_x = self.x;
self.target_y = self.y;
self.vel_x = 0;
self.vel_y = 0;
npc_list.remove_by_type(252, state);
let mut npc = NPC::create(4, &state.npc_table);
npc.cond.set_alive(true);
npc.x = self.x;
npc.y = self.y;
for _ in 0..3 {
let _ = npc_list.spawn(0x100, npc.clone());
}
}
self.action_counter += 1;
self.x = if (self.action_counter & 0x02) != 0 { self.target_x + 0x200 } else { self.target_x };
}
1010 => {
self.vel_y += 0x10;
if self.flags.hit_bottom_wall() {
self.action_num = 1020;
self.anim_num = 8;
}
}
_ => (),
}
self.vel_x = self.vel_x.clamp(-0x200, 0x200);
self.vel_y = self.vel_y.clamp(-0x400, 0x400);
self.x += self.vel_x;
self.y += self.vel_y;
let dir_offset = if self.direction == Direction::Left { 0 } else { 9 };
self.anim_rect = state.constants.npc.n247_misery_boss[self.anim_num as usize + dir_offset];
Ok(())
}
pub(crate) fn tick_n248_misery_boss_vanishing(&mut self, state: &mut SharedGameState) -> GameResult {
if self.flags.any_flag() {
self.cond.set_alive(false);
state.create_caret(self.x, self.y, CaretType::ProjectileDissipation, Direction::Left);
}
self.y += self.vel_y;
self.x += self.vel_x;
self.animate(1, 0, 2);
self.anim_rect = state.constants.npc.n248_misery_boss_vanishing[self.anim_num as usize];
self.action_counter3 += 1;
if self.action_counter3 > 300 {
self.cond.set_alive(false);
state.create_caret(self.x, self.y, CaretType::ProjectileDissipation, Direction::Left);
}
Ok(())
}
pub(crate) fn tick_n249_misery_boss_energy_shot(&mut self, state: &mut SharedGameState) -> GameResult {
self.action_counter2 += 1;
if self.action_counter2 > 8 {
@ -409,4 +733,3 @@ impl NPC {
Ok(())
}
}

View file

@ -128,7 +128,7 @@ impl NPC {
return Ok(());
}
if self.action_counter > 400 && (self.action_counter / 2 % 2) != 0 {
if self.action_counter > 400 && (self.action_counter & 0x02) != 0 {
self.anim_rect.left = 0;
self.anim_rect.top = 0;
self.anim_rect.right = 0;
@ -194,7 +194,7 @@ impl NPC {
self.cond.set_alive(false);
}
if self.action_counter2 > 500 && self.action_counter2 / 2 % 2 != 0 {
if self.action_counter2 > 500 && self.action_counter2 & 0x02 != 0 {
self.anim_rect.right = self.anim_rect.left;
self.anim_rect.bottom = self.anim_rect.top;
}
@ -262,7 +262,7 @@ impl NPC {
self.cond.set_alive(false);
}
if self.action_counter2 > 500 && self.action_counter2 / 2 % 2 != 0 {
if self.action_counter2 > 500 && self.action_counter2 & 0x02 != 0 {
self.anim_rect.right = self.anim_rect.left;
self.anim_rect.bottom = self.anim_rect.top;
}

View file

@ -1,5 +1,7 @@
use crate::caret::CaretType;
use crate::common::Direction;
use crate::framework::error::GameResult;
use crate::npc::list::NPCList;
use crate::npc::NPC;
use crate::player::Player;
use crate::rng::RNG;
@ -28,7 +30,6 @@ impl NPC {
self.anim_num = 0;
}
}
_ => (),
}
@ -284,6 +285,200 @@ impl NPC {
self.y += self.vel_y;
self.anim_rect = state.constants.npc.n226_kanpachi_plantation[self.anim_num as usize];
Ok(())
}
pub(crate) fn tick_n228_droll(&mut self, state: &mut SharedGameState, players: [&mut Player; 2]) -> GameResult {
match self.action_num {
0 | 1 => {
if self.action_num == 0 {
self.action_num = 1;
self.y -= 0x1000;
}
self.vel_x = 0;
self.action_num = 2;
self.anim_num = 0;
}
2 => {
let player = self.get_closest_player_ref(&players);
if self.x <= player.x {
self.direction = Direction::Right;
} else {
self.direction = Direction::Left;
}
self.anim_counter += 1;
if self.anim_counter > 50 {
self.anim_counter = 0;
self.anim_num += 1;
}
if self.anim_num > 1 {
self.anim_num = 0;
}
}
10 | 11 => {
if self.action_num == 10 {
self.action_num = 11;
self.anim_num = 2;
self.action_counter = 0;
}
self.action_counter += 1;
if self.action_counter > 10 {
self.action_num = 12;
self.anim_num = 3;
self.vel_y = -0x600;
if self.direction != Direction::Left {
self.vel_x = 0x200;
} else {
self.vel_x = -0x200;
}
}
}
12 => {
if self.flags.hit_bottom_wall() {
self.anim_num = 2;
self.action_num = 13;
self.action_counter = 0;
}
}
13 => {
self.vel_x /= 2;
self.action_counter += 1;
if self.action_counter > 10 {
self.action_num = 1;
}
}
_ => (),
}
self.vel_y += 0x40;
if self.vel_y > 0x5FF {
self.vel_y = 0x5FF;
}
self.x += self.vel_x;
self.y += self.vel_y;
let dir_offset = if self.direction == Direction::Left { 0 } else { 4 };
self.anim_rect = state.constants.npc.n228_droll[self.anim_num as usize + dir_offset];
Ok(())
}
pub(crate) fn tick_n231_rocket(
&mut self,
state: &mut SharedGameState,
players: [&mut Player; 2],
npc_list: &NPCList,
) -> GameResult {
match self.action_num {
0 | 1 => {
if self.action_num == 0 {
self.action_num = 1;
}
self.anim_num = 0;
}
10 | 11 => {
if self.action_num == 10 {
self.action_num = 11;
self.action_counter = 0;
}
self.action_counter += 1;
self.vel_y += 8;
if self.flags.hit_bottom_wall() {
if self.action_counter > 9 {
self.action_num = 1;
} else {
self.action_num = 12;
}
}
}
12 | 13 => {
if self.action_num == 12 {
self.npc_flags.set_interactable(false);
self.action_num = 13;
self.action_counter = 0;
self.anim_num = 1;
let mut npc = NPC::create(4, &state.npc_table);
npc.cond.set_alive(true);
for _ in 0..10 {
npc.x = self.x + self.rng.range(-16..16) * 0x200;
npc.y = self.y + self.rng.range(-8..8) * 0x200;
let _ = npc_list.spawn(0x100, npc.clone());
state.sound_manager.play_sfx(12);
}
}
self.vel_y -= 8;
self.action_counter += 1;
if (self.action_counter & 1) == 0 {
state.create_caret(self.x - 0x1400, self.y + 0x1000, CaretType::Exhaust, Direction::Bottom);
}
if self.action_counter % 2 == 1 {
state.create_caret(self.x + 0x1400, self.y + 0x1000, CaretType::Exhaust, Direction::Bottom);
}
if self.action_counter % 4 == 1 {
state.sound_manager.play_sfx(34);
}
let player = self.get_closest_player_ref(&players);
if self.flags.hit_top_wall() || player.flags.hit_top_wall() || self.action_counter > 450 {
if self.flags.hit_top_wall() || player.flags.hit_top_wall() {
self.vel_y = 0;
}
self.action_num = 15;
let mut npc = NPC::create(4, &state.npc_table);
npc.cond.set_alive(true);
for _ in 0..6 {
npc.x = self.x + self.rng.range(-16..16) * 0x200;
npc.y = self.y + self.rng.range(-8..8) * 0x200;
let _ = npc_list.spawn(0x100, npc.clone());
state.sound_manager.play_sfx(12);
}
}
}
15 => {
self.vel_y += 8;
self.action_counter += 1;
if self.vel_y < 0 {
if (self.action_counter & 7) == 0 {
state.create_caret(self.x - 0x1400, self.y + 0x1000, CaretType::Exhaust, Direction::Bottom);
}
if self.action_counter % 8 == 4 {
state.create_caret(self.x + 0x1400, self.y + 0x1000, CaretType::Exhaust, Direction::Bottom);
}
if self.action_counter % 16 == 1 {
state.sound_manager.play_sfx(34);
}
}
if self.flags.hit_bottom_wall() {
self.npc_flags.set_interactable(true);
self.action_num = 1;
self.anim_num = 0;
}
}
_ => (),
}
self.vel_y = self.vel_y.clamp(-0x5ff, 0x5ff);
self.y += self.vel_y;
self.anim_rect = state.constants.npc.n231_rocket[self.anim_num as usize];
Ok(())
}
}

View file

@ -68,7 +68,7 @@ impl NPC {
if self.action_num == 4 {
self.anim_rect.bottom = self.anim_rect.top + self.action_counter / 4;
if self.action_counter / 2 % 2 != 0 {
if self.action_counter & 0x02 != 0 {
self.anim_rect.left += 1;
}
}
@ -125,7 +125,7 @@ impl NPC {
if self.action_num == 1 {
self.anim_rect.bottom = self.anim_rect.top + self.action_counter / 4;
if self.action_counter / 2 % 2 != 0 {
if self.action_counter & 0x02 != 0 {
self.anim_rect.left += 1;
}
}

View file

@ -40,7 +40,7 @@ impl NPC {
self.damage = 3;
self.animate(0, 2, 3);
if self.x <= 0x5FFF {
if self.x <= 0x5fff {
// npc->destroy_voice = 0; // todo
self.cond.set_explode_die(true);
}

View file

@ -272,7 +272,7 @@ impl GameEntity<([&mut Player; 2], &NPCList, &mut Stage, &mut BulletManager, &mu
64 => self.tick_n064_first_cave_critter(state, players),
65 => self.tick_n065_first_cave_bat(state, players),
66 => self.tick_n066_misery_bubble(state, npc_list),
67 => self.tick_n067_misery_floating(state, npc_list),
67 => self.tick_n067_misery_floating(state, npc_list, flash),
68 => self.tick_n068_balrog_running(state, players, npc_list),
69 => self.tick_n069_pignon(state),
70 => self.tick_n070_sparkle(state),
@ -287,7 +287,7 @@ impl GameEntity<([&mut Player; 2], &NPCList, &mut Stage, &mut BulletManager, &mu
79 => self.tick_n079_mahin(state, players),
80 => self.tick_n080_gravekeeper(state, players),
81 => self.tick_n081_giant_pignon(state, players),
82 => self.tick_n082_misery_standing(state, npc_list),
82 => self.tick_n082_misery_standing(state, npc_list, flash),
83 => self.tick_n083_igor_cutscene(state),
84 => self.tick_n084_basu_projectile(state),
85 => self.tick_n085_terminal(state, players),
@ -433,13 +433,21 @@ impl GameEntity<([&mut Player; 2], &NPCList, &mut Stage, &mut BulletManager, &mu
225 => self.tick_n225_megane(state),
226 => self.tick_n226_kanpachi_plantation(state),
227 => self.tick_n227_bucket(state),
228 => self.tick_n228_droll(state, players),
229 => self.tick_n229_red_flowers_sprouts(state),
230 => self.tick_n230_red_flowers_blooming(state),
231 => self.tick_n231_rocket(state, players, npc_list),
234 => self.tick_n234_red_flowers_picked(state),
238 => self.tick_n238_press_sideways(state, players, npc_list),
239 => self.tick_n239_cage_bars(state),
241 => self.tick_n241_critter_red(state, players),
247 => self.tick_n247_misery_boss(state, players, npc_list),
248 => self.tick_n248_misery_boss_vanishing(state),
249 => self.tick_n249_misery_boss_energy_shot(state),
253 => self.tick_n253_experience_capsule(state, npc_list),
257 => self.tick_n257_red_crystal(state),
258 => self.tick_n258_mimiga_sleeping(state),
259 => self.tick_n259_curly_unconcious(state, players, npc_list),
292 => self.tick_n292_quake(state),
297 => self.tick_n297_sue_dragon_mouth(state, npc_list),
298 => self.tick_n298_intro_doctor(state),

View file

@ -177,14 +177,20 @@ impl NPC {
}
/// Creates experience drop for this NPC.
#[inline]
pub fn create_xp_drop(&self, state: &SharedGameState, npc_list: &NPCList) {
let mut exp = self.exp;
self.create_xp_drop_custom(self.x, self.y, self.exp, state, npc_list)
}
/// Creates experience drop using specified parameters
pub fn create_xp_drop_custom(&self, x: i32, y: i32, amount: u16, state: &SharedGameState, npc_list: &NPCList) {
let mut exp = amount;
let mut xp_npc = NPC::create(1, &state.npc_table);
xp_npc.cond.set_alive(true);
xp_npc.direction = Direction::Left;
xp_npc.x = self.x;
xp_npc.y = self.y;
xp_npc.x = x;
xp_npc.y = y;
while exp > 0 {
let exp_piece = if exp >= 20 {
@ -310,7 +316,7 @@ impl NPCList {
}
/// Removes NPCs whose event number matches the provided one.
pub fn remove_by_event(&mut self, event_num: u16, state: &mut SharedGameState) {
pub fn remove_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);
@ -320,7 +326,7 @@ impl NPCList {
}
/// Removes NPCs (and creates a smoke effect) whose type IDs match the provided one.
pub fn remove_by_type(&mut self, npc_type: u16, state: &mut SharedGameState) {
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);

View file

@ -728,7 +728,6 @@ impl GameEntity<&NPCList> for Player {
if self.shock_counter != 0 {
self.shock_counter -= 1;
} else if self.damage_taken != 0 {
// todo: damage popup
self.damage_taken = 0;
}