doukutsu-rs/src/game/npc/ai/pickups.rs

277 lines
8.2 KiB
Rust

use crate::common::Direction;
use crate::framework::error::GameResult;
use crate::game::npc::NPC;
use crate::game::shared_game_state::SharedGameState;
use crate::game::stage::{BackgroundType, Stage};
use crate::util::rng::RNG;
impl NPC {
pub(crate) fn tick_n001_experience(&mut self, state: &mut SharedGameState, stage: &mut Stage) -> GameResult {
if stage.data.background_type == BackgroundType::Scrolling || stage.data.background_type == BackgroundType::OutsideWind {
if self.action_num == 0 {
self.action_num = 1;
self.vel_x = self.rng.range(-0x80..0x80) as i32;
self.vel_y = self.rng.range(-0x7f..0x100) as i32;
}
self.vel_x -= 0x8;
if self.x < 0xa000 {
self.cond.set_alive(false);
return Ok(());
}
if self.vel_x < -0x600 {
self.vel_x = -0x600;
}
if self.flags.hit_left_wall() {
self.vel_x = 0x100;
}
if self.flags.hit_top_wall() {
self.vel_y = 0x40;
}
if self.flags.hit_bottom_wall() {
self.vel_y = -0x40;
}
} else {
if self.action_num == 0 {
self.action_num = 1;
self.anim_num = self.rng.range(0..4) as u16;
self.vel_x = self.rng.range(-0x200..0x200) as i32;
self.vel_y = self.rng.range(-0x400..0) as i32;
self.direction = if self.rng.range(0..1) != 0 { Direction::Left } else { Direction::Right };
}
self.vel_y += if self.flags.in_water() { 0x15 } else { 0x2a };
if self.flags.hit_left_wall() && self.vel_x < 0 {
self.vel_x = -self.vel_x;
}
if self.flags.hit_right_wall() && self.vel_x > 0 {
self.vel_x = -self.vel_x;
}
if self.flags.hit_top_wall() && self.vel_y < 0 {
self.vel_y = -self.vel_y;
}
if self.flags.hit_bottom_wall() {
state.sound_manager.play_sfx(45);
self.vel_y = -0x280;
self.vel_x = 2 * self.vel_x / 3;
}
if self.flags.hit_left_wall() || self.flags.hit_right_wall() || self.flags.hit_bottom_wall() {
state.sound_manager.play_sfx(45);
self.action_counter2 += 1;
if self.action_counter2 > 2 {
self.vel_y -= 0x200;
}
} else {
self.action_counter2 = 0;
}
self.vel_x = self.vel_x.clamp(-0x5ff, 0x5ff);
self.vel_y = self.vel_y.clamp(-0x5ff, 0x5ff);
}
self.x += self.vel_x;
self.y += self.vel_y;
self.anim_counter += 1;
if self.direction == Direction::Left {
if self.anim_counter > 2 {
self.anim_counter = 0;
self.anim_num += 1;
if self.anim_num > 5 {
self.anim_num = 0;
}
}
} else if self.anim_counter > 2 {
self.anim_counter = 0;
if self.anim_num > 0 {
self.anim_num -= 1;
} else {
self.anim_num = 5;
}
}
self.anim_rect = state.constants.npc.n001_experience[self.anim_num as usize];
if self.action_num != 0 {
if self.exp >= 20 {
self.anim_rect.top += 32;
self.anim_rect.bottom += 32;
} else if self.exp >= 5 {
self.anim_rect.top += 16;
self.anim_rect.bottom += 16;
}
self.action_num = 1;
}
self.action_counter += 1;
if self.action_counter > 500 && self.anim_num == 5 && self.anim_counter == 2 {
self.cond.set_alive(false);
return Ok(());
}
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;
self.anim_rect.bottom = 0;
}
Ok(())
}
pub(crate) fn tick_n086_missile_pickup(&mut self, state: &mut SharedGameState, stage: &mut Stage) -> GameResult {
if self.direction == Direction::Left {
self.anim_counter += 1;
if self.anim_counter > 2 {
self.anim_counter = 0;
self.anim_num += 1;
if self.anim_num > 1 {
self.anim_num = 0;
}
}
self.action_counter2 += 1;
}
if stage.data.background_type == BackgroundType::Scrolling || stage.data.background_type == BackgroundType::OutsideWind {
if self.action_num == 0 {
self.action_num = 1;
self.vel_x = self.rng.range(0x7f..0x100) as i32;
self.vel_y = self.rng.range(-0x20..0x20) as i32;
}
self.vel_x -= 0x08;
if self.x < 0xa000 {
self.cond.set_alive(false)
}
if self.flags.hit_left_wall() {
self.vel_x = 0x100;
}
if self.flags.hit_top_wall() {
self.vel_y = 0x40;
}
if self.flags.hit_bottom_wall() {
self.vel_y = -0x40;
}
self.x += self.vel_x;
self.y += self.vel_y;
}
match self.exp {
1 => {
self.anim_rect = state.constants.npc.n086_missile_pickup[self.anim_num as usize];
}
3 => {
self.anim_rect = state.constants.npc.n086_missile_pickup[2 + self.anim_num as usize];
}
_ => (),
}
if self.action_counter2 > 550 {
self.cond.set_alive(false);
}
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;
}
if self.action_counter2 > 547 {
self.anim_rect = state.constants.npc.n086_missile_pickup[4];
}
Ok(())
}
pub(crate) fn tick_n087_heart_pickup(&mut self, state: &mut SharedGameState, stage: &mut Stage) -> GameResult {
if self.direction == Direction::Left {
self.anim_counter += 1;
if self.anim_counter > 2 {
self.anim_counter = 0;
self.anim_num += 1;
if self.anim_num > 1 {
self.anim_num = 0;
}
}
self.action_counter2 += 1;
}
if stage.data.background_type == BackgroundType::Scrolling || stage.data.background_type == BackgroundType::OutsideWind {
if self.action_num == 0 {
self.action_num = 1;
self.vel_x = self.rng.range(0x7f..0x100) as i32;
self.vel_y = self.rng.range(-0x20..0x20) as i32;
}
self.vel_x -= 0x08;
if self.x < 0xa000 {
self.cond.set_alive(false)
}
if self.flags.hit_left_wall() {
self.vel_x = 0x100;
}
if self.flags.hit_top_wall() {
self.vel_y = 0x40;
}
if self.flags.hit_bottom_wall() {
self.vel_y = -0x40;
}
self.x += self.vel_x;
self.y += self.vel_y;
}
match self.exp {
2 => {
self.anim_rect = state.constants.npc.n087_heart_pickup[self.anim_num as usize];
}
6 => {
self.anim_rect = state.constants.npc.n087_heart_pickup[2 + self.anim_num as usize];
}
_ => (),
}
if self.action_counter2 > 550 {
self.cond.set_alive(false);
}
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;
}
if self.action_counter2 > 547 {
self.anim_rect = state.constants.npc.n087_heart_pickup[4];
}
Ok(())
}
}