mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2024-10-31 19:44:20 +00:00
commit stuff from last 2 months idfk what I've exactly changed
This commit is contained in:
parent
2cb9335453
commit
e018b53b04
|
@ -69,13 +69,13 @@ lua-ffi = { git = "https://github.com/doukutsu-rs/lua-ffi.git", rev = "e0b2ff596
|
|||
num-derive = "0.3.2"
|
||||
num-traits = "0.2.12"
|
||||
paste = "1.0.0"
|
||||
pretty_env_logger = "0.4.0"
|
||||
sdl2 = { version = "=0.34.2", optional = true, features = ["unsafe_textures", "bundled", "static-link"] }
|
||||
sdl2-sys = { version = "=0.34.2", optional = true, features = ["bundled", "static-link"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_derive = "1"
|
||||
serde_json = "1.0"
|
||||
serde_yaml = "0.8"
|
||||
simple_logger = { version = "1.13" }
|
||||
strum = "0.20"
|
||||
strum_macros = "0.20"
|
||||
# remove and replace when drain_filter is in stable
|
||||
|
|
|
@ -90,6 +90,21 @@ impl BMFontRenderer {
|
|||
self.draw_colored_text(iter, x, y, (255, 255, 255, 255), constants, texture_set, ctx)
|
||||
}
|
||||
|
||||
pub fn draw_colored_text_with_shadow_scaled<I: Iterator<Item = char> + Clone>(
|
||||
&self,
|
||||
iter: I,
|
||||
x: f32,
|
||||
y: f32,
|
||||
scale: f32,
|
||||
color: (u8, u8, u8, u8),
|
||||
constants: &EngineConstants,
|
||||
texture_set: &mut TextureSet,
|
||||
ctx: &mut Context,
|
||||
) -> GameResult {
|
||||
self.draw_colored_text_scaled(iter.clone(), x + scale, y + scale, scale, (0, 0, 0, 150), constants, texture_set, ctx)?;
|
||||
self.draw_colored_text_scaled(iter, x, y, scale, color, constants, texture_set, ctx)
|
||||
}
|
||||
|
||||
pub fn draw_colored_text_scaled<I: Iterator<Item = char>>(
|
||||
&self,
|
||||
iter: I,
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 8.5 KiB |
Binary file not shown.
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 789 B |
|
@ -120,7 +120,6 @@ impl BuiltinFS {
|
|||
]),
|
||||
FSNode::Directory("lightmap", vec![
|
||||
FSNode::File("spot.png", include_bytes!("builtin/lightmap/spot.png")),
|
||||
FSNode::File("direct.png", include_bytes!("builtin/lightmap/direct.png")),
|
||||
]),
|
||||
])
|
||||
],
|
||||
|
|
|
@ -9,9 +9,10 @@ use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
|
|||
use crate::bitfield;
|
||||
use crate::texture_set::G_MAG;
|
||||
|
||||
/// Multiply cave story degrees (0-255, which corresponds to 0°-360°) with this to get
|
||||
/// Multiply cave story degrees (0-255, which corresponds to 0°-360°) with this constant to get
|
||||
/// respective value in radians.
|
||||
pub const CDEG_RAD: f64 = std::f64::consts::PI / 128.0;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref VERSION_BANNER: String = {
|
||||
let version = option_env!("DRS_BUILD_VERSION_OVERRIDE").unwrap_or(env!("CARGO_PKG_VERSION"));
|
||||
|
@ -57,6 +58,10 @@ bitfield! {
|
|||
}
|
||||
|
||||
impl Flag {
|
||||
pub fn any_flag(&self) -> bool {
|
||||
self.0 != 0
|
||||
}
|
||||
|
||||
pub fn hit_anything(&self) -> bool {
|
||||
(self.0 & 0x2ff) != 0
|
||||
}
|
||||
|
@ -121,7 +126,6 @@ bitfield! {
|
|||
|
||||
// engine specific flags
|
||||
pub friendly_fire, set_friendly_fire: 14;
|
||||
pub wind, set_wind: 15;
|
||||
}
|
||||
|
||||
bitfield! {
|
||||
|
|
|
@ -585,8 +585,8 @@ pub struct NPCConsts {
|
|||
#[serde(default = "default_n195_background_grate")]
|
||||
pub n195_background_grate: Rect<u16>,
|
||||
|
||||
#[serde(default = "default_n196_ironhead_motion_wall")]
|
||||
pub n196_ironhead_motion_wall: [Rect<u16>; 2],
|
||||
#[serde(default = "default_n196_ironhead_wall")]
|
||||
pub n196_ironhead_wall: [Rect<u16>; 2],
|
||||
|
||||
#[serde(default = "default_n197_porcupine_fish")]
|
||||
pub n197_porcupine_fish: [Rect<u16>; 4],
|
||||
|
@ -627,8 +627,8 @@ pub struct NPCConsts {
|
|||
#[serde(default = "default_n209_basu_projectile_destroyed_egg_corridor")]
|
||||
pub n209_basu_projectile_destroyed_egg_corridor: [Rect<u16>; 4],
|
||||
|
||||
#[serde(default = "default_n210_destroyed_egg_corridor")]
|
||||
pub n210_destroyed_egg_corridor: [Rect<u16>; 4],
|
||||
#[serde(default = "default_n210_beetle_destroyed_egg_corridor")]
|
||||
pub n210_beetle_destroyed_egg_corridor: [Rect<u16>; 4],
|
||||
|
||||
#[serde(default = "default_n211_small_spikes")]
|
||||
pub n211_small_spikes: [Rect<u16>; 4],
|
||||
|
@ -1074,6 +1074,9 @@ pub struct NPCConsts {
|
|||
|
||||
#[serde(default = "default_b03_monster_x")]
|
||||
pub b03_monster_x: [Rect<u16>; 29],
|
||||
|
||||
#[serde(default = "default_b04_core")]
|
||||
pub b04_core: [Rect<u16>; 10],
|
||||
}
|
||||
|
||||
fn default_n001_experience() -> [Rect<u16>; 6] {
|
||||
|
@ -3211,7 +3214,7 @@ fn default_n195_background_grate() -> Rect<u16> {
|
|||
Rect { left: 112, top: 64, right: 128, bottom: 80 }
|
||||
}
|
||||
|
||||
fn default_n196_ironhead_motion_wall() -> [Rect<u16>; 2] {
|
||||
fn default_n196_ironhead_wall() -> [Rect<u16>; 2] {
|
||||
[
|
||||
Rect { left: 112, top: 64, right: 144, bottom: 80 },
|
||||
Rect { left: 112, top: 80, right: 144, bottom: 96 },
|
||||
|
@ -3340,7 +3343,7 @@ fn default_n209_basu_projectile_destroyed_egg_corridor() -> [Rect<u16>; 4] {
|
|||
]
|
||||
}
|
||||
|
||||
fn default_n210_destroyed_egg_corridor() -> [Rect<u16>; 4] {
|
||||
fn default_n210_beetle_destroyed_egg_corridor() -> [Rect<u16>; 4] {
|
||||
[
|
||||
Rect { left: 0, top: 112, right: 16, bottom: 128 },
|
||||
Rect { left: 16, top: 112, right: 32, bottom: 128 },
|
||||
|
@ -4850,3 +4853,20 @@ fn default_b03_monster_x() -> [Rect<u16>; 29] {
|
|||
Rect { left: 48, top: 208, right: 64, bottom: 224 },
|
||||
]
|
||||
}
|
||||
|
||||
fn default_b04_core() -> [Rect<u16>; 10] {
|
||||
[
|
||||
Rect { left: 0, top: 0, right: 72, bottom: 112 }, // face
|
||||
Rect { left: 0, top: 112, right: 72, bottom: 224 },
|
||||
Rect { left: 160, top: 0, right: 232, bottom: 112 },
|
||||
Rect { left: 0, top: 0, right: 0, bottom: 0 },
|
||||
|
||||
Rect { left: 72, top: 0, right: 160, bottom: 112 }, // tail
|
||||
Rect { left: 72, top: 112, right: 160, bottom: 224 },
|
||||
Rect { left: 0, top: 0, right: 0, bottom: 0 },
|
||||
|
||||
Rect { left: 256, top: 0, right: 320, bottom: 40 }, // small head
|
||||
Rect { left: 256, top: 40, right: 320, bottom: 80 },
|
||||
Rect { left: 256, top: 80, right: 320, bottom: 120 },
|
||||
]
|
||||
}
|
||||
|
|
|
@ -155,7 +155,6 @@ impl BackendEventLoop for GlutinEventLoop {
|
|||
state_ref.shutdown();
|
||||
}
|
||||
Event::Resumed => {
|
||||
println!("resumed!");
|
||||
{
|
||||
let mut mutex = GAME_SUSPENDED.lock().unwrap();
|
||||
*mutex = false;
|
||||
|
@ -171,7 +170,6 @@ impl BackendEventLoop for GlutinEventLoop {
|
|||
}
|
||||
}
|
||||
Event::Suspended => {
|
||||
println!("suspended!");
|
||||
{
|
||||
let mut mutex = GAME_SUSPENDED.lock().unwrap();
|
||||
*mutex = true;
|
||||
|
|
|
@ -15,7 +15,6 @@ use std::time::Instant;
|
|||
|
||||
use directories::ProjectDirs;
|
||||
use lazy_static::lazy_static;
|
||||
use pretty_env_logger::env_logger::Env;
|
||||
|
||||
use crate::builtin_fs::BuiltinFS;
|
||||
use crate::framework::context::Context;
|
||||
|
@ -188,9 +187,7 @@ impl Game {
|
|||
}
|
||||
|
||||
pub fn init() -> GameResult {
|
||||
pretty_env_logger::env_logger::from_env(Env::default().default_filter_or("info"))
|
||||
//.filter(Some("ndk_glue"), LevelFilter::Trace)
|
||||
.init();
|
||||
let _ = simple_logger::init_with_level(log::Level::Info);
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
let resource_dir = if let Ok(data_dir) = env::var("CAVESTORY_DATA_DIR") {
|
||||
|
|
|
@ -62,7 +62,7 @@ impl NPC {
|
|||
self.anim_counter = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y = clamp(self.vel_y, -0x5ff, 0x5ff);
|
||||
|
@ -162,7 +162,7 @@ impl NPC {
|
|||
self.action_counter = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y += 0x20;
|
||||
|
@ -501,13 +501,12 @@ impl NPC {
|
|||
}
|
||||
}
|
||||
|
||||
println!("y: {}", self.y as f64 / 512.0);
|
||||
if self.y < -32 * 0x200 {
|
||||
self.npc_type = 0;
|
||||
state.quake_counter = 30;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.target_x != 0 && self.rng.range(0..10) == 0 {
|
||||
|
@ -603,7 +602,7 @@ impl NPC {
|
|||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y = clamp(self.vel_y, -0x5ff, 0x5ff);
|
||||
|
@ -793,7 +792,7 @@ impl NPC {
|
|||
self.action_counter = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.action_num != 5 {
|
||||
|
@ -977,7 +976,7 @@ impl NPC {
|
|||
self.action_num = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_x = clamp(self.vel_x, -0x400, 0x400);
|
||||
|
@ -1196,7 +1195,7 @@ impl NPC {
|
|||
self.action_num = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y += 0x20;
|
||||
|
|
|
@ -76,7 +76,7 @@ impl NPC {
|
|||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y += 0x40;
|
||||
|
|
|
@ -58,7 +58,7 @@ impl NPC {
|
|||
state.create_caret(self.x, self.y, CaretType::Zzz, Direction::Left);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let dir_offset = if self.direction == Direction::Left { 0 } else { 7 };
|
||||
|
|
|
@ -58,7 +58,7 @@ impl NPC {
|
|||
self.x += self.direction.vector_x() * 0x200;
|
||||
}
|
||||
5 => self.anim_num = 5,
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y += 0x20;
|
||||
|
@ -225,7 +225,7 @@ impl NPC {
|
|||
self.action_counter2 = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.action_num < 30 || self.action_num >= 40 {
|
||||
|
@ -302,7 +302,7 @@ impl NPC {
|
|||
self.anim_rect = state.constants.npc.n062_kazuma_computer[self.anim_num as usize];
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -342,7 +342,7 @@ impl NPC {
|
|||
|
||||
self.vel_x = self.direction.vector_x() * 0x200;
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y += 0x40;
|
||||
|
@ -412,7 +412,7 @@ impl NPC {
|
|||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let dir_offset = if self.direction == Direction::Left { 0 } else { 2 };
|
||||
|
@ -467,11 +467,103 @@ impl NPC {
|
|||
self.cond.set_alive(false);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n167_booster_falling[self.anim_num as usize];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n217_itoh(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
match self.action_num {
|
||||
0 | 1 => {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
self.anim_num = 0;
|
||||
self.anim_counter = 0;
|
||||
self.vel_x = 0;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
10 => {
|
||||
self.anim_num = 2;
|
||||
self.vel_x = 0;
|
||||
}
|
||||
20 => {
|
||||
self.action_num = 21;
|
||||
self.anim_num = 2;
|
||||
self.vel_x += 0x200;
|
||||
self.vel_y -= 0x400;
|
||||
}
|
||||
21 => {
|
||||
if self.flags.hit_bottom_wall() {
|
||||
self.anim_num = 3;
|
||||
self.action_num = 30;
|
||||
self.action_counter = 0;
|
||||
self.vel_x = 0;
|
||||
self.target_x = self.x;
|
||||
}
|
||||
}
|
||||
30 => {
|
||||
self.anim_num = 3;
|
||||
self.action_counter += 1;
|
||||
self.x = if ((self.action_counter / 2) & 1) != 0 { self.target_x + 512 } else { self.target_x }
|
||||
}
|
||||
|
||||
40 | 41 => {
|
||||
if self.action_num == 40 {
|
||||
self.action_num = 41;
|
||||
self.vel_y = -512;
|
||||
self.anim_num = 2;
|
||||
}
|
||||
if self.flags.hit_bottom_wall() {
|
||||
self.action_num = 42;
|
||||
self.anim_num = 4;
|
||||
}
|
||||
}
|
||||
42 => {
|
||||
self.vel_x = 0;
|
||||
self.anim_num = 4;
|
||||
}
|
||||
|
||||
50 | 51 => {
|
||||
if self.action_num == 50 {
|
||||
self.action_num = 51;
|
||||
self.action_counter = 0;
|
||||
}
|
||||
self.action_counter += 1;
|
||||
if self.action_counter > 32 {
|
||||
self.action_num = 42;
|
||||
}
|
||||
self.vel_x = 512;
|
||||
|
||||
self.animate(3, 4, 7);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y += 0x40;
|
||||
if self.vel_y > 0x5ff {
|
||||
self.vel_y = 0x5ff;
|
||||
}
|
||||
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
|
||||
self.anim_rect = state.constants.npc.n217_itoh[self.anim_num as usize];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use num_traits::{abs, clamp};
|
||||
|
||||
use crate::caret::CaretType;
|
||||
use crate::common::Direction;
|
||||
use crate::common::{Direction, Rect};
|
||||
use crate::framework::error::GameResult;
|
||||
use crate::npc::list::NPCList;
|
||||
use crate::npc::NPC;
|
||||
use crate::player::Player;
|
||||
use crate::player::{Player, TargetPlayer};
|
||||
use crate::rng::RNG;
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
use crate::weapon::bullet::BulletManager;
|
||||
|
@ -111,7 +111,7 @@ impl NPC {
|
|||
self.animate(8, 1, 4);
|
||||
self.x += self.direction.vector_x() * 0x100;
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.vel_y > 0x5ff {
|
||||
|
@ -244,7 +244,7 @@ impl NPC {
|
|||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.action_num > 10 && self.action_num < 30 && bullet_manager.count_bullets_type_idx_all(6) > 0 {
|
||||
|
@ -349,11 +349,440 @@ impl NPC {
|
|||
0
|
||||
};
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n165_curly_collapsed[self.anim_num as usize];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n180_curly_ai(
|
||||
&mut self,
|
||||
state: &mut SharedGameState,
|
||||
players: [&mut Player; 2],
|
||||
npc_list: &NPCList,
|
||||
) -> GameResult {
|
||||
let player = self.get_closest_player_ref(&players);
|
||||
|
||||
if self.y >= player.y - 0x14000 {
|
||||
if state.npc_curly_counter > 0 {
|
||||
self.target_x = state.npc_curly_target.0;
|
||||
self.target_y = state.npc_curly_target.1;
|
||||
} else {
|
||||
self.target_x = player.x;
|
||||
self.target_y = player.y;
|
||||
}
|
||||
} else {
|
||||
self.target_x = if self.y > 0x1FFFF { 0 } else { 0x280000 };
|
||||
self.target_y = self.y;
|
||||
}
|
||||
|
||||
if (self.vel_x < 0 && self.flags.hit_left_wall()) || (self.vel_x > 0 && self.flags.hit_right_wall()) {
|
||||
self.vel_x = 0;
|
||||
}
|
||||
|
||||
match self.action_num {
|
||||
20 => {
|
||||
self.action_num = 100;
|
||||
self.anim_num = 0;
|
||||
self.x = player.x;
|
||||
self.y = player.y;
|
||||
|
||||
let mut npc = NPC::create(183, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
npc.parent_id = self.id;
|
||||
let _ = npc_list.spawn(0x100, npc);
|
||||
|
||||
if !state.get_flag(563) {
|
||||
let mut npc = NPC::create(181, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
npc.parent_id = self.id;
|
||||
let _ = npc_list.spawn(0x100, npc);
|
||||
} else {
|
||||
let mut npc = NPC::create(182, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
npc.parent_id = self.id;
|
||||
let _ = npc_list.spawn(0x100, npc);
|
||||
}
|
||||
}
|
||||
40 | 41 => {
|
||||
if self.action_num == 40 {
|
||||
self.action_num = 41;
|
||||
self.action_counter = 0;
|
||||
self.anim_num = 10;
|
||||
}
|
||||
|
||||
self.action_counter += 1;
|
||||
if self.action_counter == 750 {
|
||||
self.npc_flags.set_interactable(false);
|
||||
self.anim_num = 0;
|
||||
}
|
||||
if self.action_counter > 1000 {
|
||||
self.action_num = 100;
|
||||
self.anim_num = 0;
|
||||
|
||||
let mut npc = NPC::create(183, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
npc.parent_id = self.id;
|
||||
let _ = npc_list.spawn(0x100, npc);
|
||||
|
||||
if !state.get_flag(563) {
|
||||
let mut npc = NPC::create(181, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
npc.parent_id = self.id;
|
||||
let _ = npc_list.spawn(0x100, npc);
|
||||
} else {
|
||||
let mut npc = NPC::create(182, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
npc.parent_id = self.id;
|
||||
let _ = npc_list.spawn(0x100, npc);
|
||||
}
|
||||
}
|
||||
}
|
||||
100 => {
|
||||
self.anim_num = 0;
|
||||
self.vel_x = 7 * self.vel_x / 8;
|
||||
self.action_counter3 = 0;
|
||||
|
||||
if self.x <= self.target_x + 0x2000 {
|
||||
if self.x < self.target_x - 0x2000 {
|
||||
self.action_num = 300;
|
||||
self.anim_num = 1;
|
||||
self.direction = Direction::Right;
|
||||
self.action_counter = self.rng.range(20..60) as u16;
|
||||
}
|
||||
} else {
|
||||
self.action_num = 200;
|
||||
self.anim_num = 1;
|
||||
self.direction = Direction::Left;
|
||||
self.action_counter = self.rng.range(20..60) as u16;
|
||||
}
|
||||
}
|
||||
200 => {
|
||||
self.vel_x -= 0x20;
|
||||
self.direction = Direction::Left;
|
||||
if self.flags.hit_left_wall() {
|
||||
self.action_counter3 += 1;
|
||||
} else {
|
||||
self.action_counter3 = 0;
|
||||
}
|
||||
}
|
||||
210 => {
|
||||
self.vel_x -= 0x20;
|
||||
self.direction = Direction::Left;
|
||||
if self.flags.hit_bottom_wall() {
|
||||
self.action_num = 100;
|
||||
}
|
||||
}
|
||||
300 => {
|
||||
self.vel_x += 0x20;
|
||||
self.direction = Direction::Right;
|
||||
if self.flags.hit_right_wall() {
|
||||
self.action_counter3 += 1;
|
||||
} else {
|
||||
self.action_counter3 = 0;
|
||||
}
|
||||
}
|
||||
310 => {
|
||||
self.vel_x += 0x20;
|
||||
self.direction = Direction::Right;
|
||||
if self.flags.hit_bottom_wall() {
|
||||
self.action_num = 100;
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if state.npc_curly_counter > 0 {
|
||||
state.npc_curly_counter -= 1;
|
||||
}
|
||||
|
||||
if state.npc_curly_counter == 70 {
|
||||
self.action_counter2 = 10;
|
||||
} else if state.npc_curly_counter == 60 && self.flags.hit_bottom_wall() && self.rng.range(0..2) != 0 {
|
||||
self.action_num = if self.x <= self.target_x { 310 } else { 210 };
|
||||
self.anim_num = 1;
|
||||
self.action_counter3 = 0;
|
||||
self.vel_y = -0x600;
|
||||
state.sound_manager.play_sfx(15);
|
||||
}
|
||||
|
||||
let mut delx = self.x - self.target_x;
|
||||
let dely = self.y - self.target_y;
|
||||
if delx < 0 {
|
||||
delx = -delx;
|
||||
}
|
||||
|
||||
if self.action_num == 100 {
|
||||
self.anim_num = if delx + 0x400 >= dely { 0 } else { 5 }
|
||||
}
|
||||
|
||||
if self.action_num == 210 || self.action_num == 310 {
|
||||
self.anim_num = if delx + 0x400 >= dely { 1 } else { 6 }
|
||||
}
|
||||
|
||||
if self.action_num == 200 || self.action_num == 300 {
|
||||
self.anim_counter += 1;
|
||||
self.anim_num = (self.anim_counter / 4 % 4) + if delx + 0x400 >= dely { 1 } else { 6 };
|
||||
|
||||
if self.action_counter > 0 {
|
||||
self.action_counter -= 1;
|
||||
if self.flags.any_flag() && self.action_counter3 > 10 {
|
||||
self.action_num += 10;
|
||||
self.anim_num = 1;
|
||||
self.action_counter3 = 0;
|
||||
self.vel_y = -0x600;
|
||||
state.sound_manager.play_sfx(15);
|
||||
}
|
||||
} else {
|
||||
self.action_num = 100;
|
||||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if self.action_num >= 100 && self.action_num < 500 {
|
||||
if self.x >= player.x - 0xA000 && self.x <= player.x + 0xA000 {
|
||||
self.vel_y += 0x33;
|
||||
} else {
|
||||
self.vel_y += if self.flags.any_flag() { 0x10 } else { 0x33 };
|
||||
}
|
||||
}
|
||||
|
||||
self.vel_x = self.vel_x.clamp(-0x300, 0x300);
|
||||
|
||||
if self.vel_y > 0x5FF {
|
||||
self.vel_y = 0x5FF;
|
||||
}
|
||||
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
|
||||
if self.action_num >= 100 && !self.flags.hit_bottom_wall() && self.anim_num != 1000 {
|
||||
if delx + 0x400 >= dely {
|
||||
self.anim_num = 1;
|
||||
} else {
|
||||
self.anim_num = 6;
|
||||
}
|
||||
}
|
||||
|
||||
let dir_offset = if self.direction == Direction::Left { 0 } else { 11 };
|
||||
|
||||
self.anim_rect = state.constants.npc.n180_curly_ai[self.anim_num as usize + dir_offset];
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n181_curly_ai_machine_gun(
|
||||
&mut self,
|
||||
state: &mut SharedGameState,
|
||||
npc_list: &NPCList,
|
||||
bullet_manager: &mut BulletManager,
|
||||
) -> GameResult {
|
||||
if let Some(parent) = self.get_parent_ref_mut(npc_list) {
|
||||
if parent.anim_num > 4 {
|
||||
self.direction = parent.direction;
|
||||
self.x = parent.x;
|
||||
self.y = parent.y - 0x1400;
|
||||
self.anim_num = 1;
|
||||
} else {
|
||||
self.x = parent.x
|
||||
+ if parent.direction == Direction::Left {
|
||||
self.direction = Direction::Left;
|
||||
-0x1000
|
||||
} else {
|
||||
self.direction = Direction::Right;
|
||||
0x1000
|
||||
};
|
||||
self.y = parent.y;
|
||||
self.anim_num = 0;
|
||||
}
|
||||
|
||||
if parent.anim_num == 1 || parent.anim_num == 3 || parent.anim_num == 6 || parent.anim_num == 8 {
|
||||
self.y -= 0x200;
|
||||
}
|
||||
|
||||
if self.action_num == 0 {
|
||||
if parent.action_counter2 == 10 {
|
||||
parent.action_counter2 = 0;
|
||||
self.action_num = 10;
|
||||
self.action_counter = 0;
|
||||
}
|
||||
} else if self.action_num == 10 {
|
||||
self.action_counter += 1;
|
||||
if self.action_counter % 6 == 1 {
|
||||
if self.anim_num != 0 {
|
||||
if self.direction != Direction::Left {
|
||||
bullet_manager.create_bullet(
|
||||
self.x + 0x400,
|
||||
self.y - 0x800,
|
||||
12,
|
||||
TargetPlayer::Player1,
|
||||
Direction::Up,
|
||||
&state.constants,
|
||||
);
|
||||
state.create_caret(self.x + 0x400, self.y - 0x800, CaretType::Shoot, Direction::Left);
|
||||
} else {
|
||||
bullet_manager.create_bullet(
|
||||
self.x - 0x400,
|
||||
self.y - 0x800,
|
||||
12,
|
||||
TargetPlayer::Player1,
|
||||
Direction::Up,
|
||||
&state.constants,
|
||||
);
|
||||
state.create_caret(self.x - 0x400, self.y - 0x800, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
} else if self.direction != Direction::Left {
|
||||
bullet_manager.create_bullet(
|
||||
self.x + 0x800,
|
||||
self.y + 0x600,
|
||||
12,
|
||||
TargetPlayer::Player1,
|
||||
Direction::Right,
|
||||
&state.constants,
|
||||
);
|
||||
state.create_caret(self.x + 0x800, self.y + 0x600, CaretType::Shoot, Direction::Left);
|
||||
} else {
|
||||
bullet_manager.create_bullet(
|
||||
self.x - 0x800,
|
||||
self.y + 0x600,
|
||||
12,
|
||||
TargetPlayer::Player1,
|
||||
Direction::Left,
|
||||
&state.constants,
|
||||
);
|
||||
state.create_caret(self.x - 0x800, self.y + 0x600, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
}
|
||||
if self.action_counter == 60 {
|
||||
self.action_num = 0;
|
||||
}
|
||||
}
|
||||
|
||||
let dir_offset = if self.direction == Direction::Left { 0 } else { 2 };
|
||||
|
||||
self.anim_rect = state.constants.npc.n181_curly_ai_machine_gun[self.anim_num as usize + dir_offset];
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n182_curly_ai_polar_star(
|
||||
&mut self,
|
||||
state: &mut SharedGameState,
|
||||
npc_list: &NPCList,
|
||||
bullet_manager: &mut BulletManager,
|
||||
) -> GameResult {
|
||||
if let Some(parent) = self.get_parent_ref_mut(npc_list) {
|
||||
if parent.anim_num > 4 {
|
||||
self.direction = parent.direction;
|
||||
self.x = parent.x;
|
||||
self.y = parent.y - 0x1400;
|
||||
self.anim_num = 1;
|
||||
} else {
|
||||
self.x = parent.x
|
||||
+ if parent.direction == Direction::Left {
|
||||
self.direction = Direction::Left;
|
||||
-0x1000
|
||||
} else {
|
||||
self.direction = Direction::Right;
|
||||
0x1000
|
||||
};
|
||||
self.y = parent.y;
|
||||
self.anim_num = 0;
|
||||
}
|
||||
if parent.anim_num == 1 || parent.anim_num == 3 || parent.anim_num == 6 || parent.anim_num == 8 {
|
||||
self.y -= 0x200;
|
||||
}
|
||||
|
||||
if self.action_num == 0 {
|
||||
if parent.action_counter2 == 10 {
|
||||
parent.action_counter2 = 0;
|
||||
self.action_num = 10;
|
||||
self.action_counter = 0;
|
||||
}
|
||||
} else if self.action_num == 10 {
|
||||
self.action_counter += 1;
|
||||
if self.action_counter % 6 == 1 {
|
||||
if self.anim_num != 0 {
|
||||
if self.direction != Direction::Left {
|
||||
bullet_manager.create_bullet(
|
||||
self.x + 0x400,
|
||||
self.y - 0x800,
|
||||
12,
|
||||
TargetPlayer::Player1,
|
||||
Direction::Up,
|
||||
&state.constants,
|
||||
);
|
||||
state.create_caret(self.x + 0x400, self.y - 0x800, CaretType::Shoot, Direction::Left);
|
||||
} else {
|
||||
bullet_manager.create_bullet(
|
||||
self.x - 0x400,
|
||||
self.y - 0x800,
|
||||
12,
|
||||
TargetPlayer::Player1,
|
||||
Direction::Up,
|
||||
&state.constants,
|
||||
);
|
||||
state.create_caret(self.x - 0x400, self.y - 0x800, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
} else if self.direction != Direction::Left {
|
||||
bullet_manager.create_bullet(
|
||||
self.x + 0x800,
|
||||
self.y + 0x600,
|
||||
12,
|
||||
TargetPlayer::Player1,
|
||||
Direction::Right,
|
||||
&state.constants,
|
||||
);
|
||||
state.create_caret(self.x + 0x800, self.y + 0x600, CaretType::Shoot, Direction::Left);
|
||||
} else {
|
||||
bullet_manager.create_bullet(
|
||||
self.x - 0x800,
|
||||
self.y + 0x600,
|
||||
12,
|
||||
TargetPlayer::Player1,
|
||||
Direction::Left,
|
||||
&state.constants,
|
||||
);
|
||||
state.create_caret(self.x - 0x800, self.y + 0x600, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
}
|
||||
if self.action_counter == 60 {
|
||||
self.action_num = 0;
|
||||
}
|
||||
}
|
||||
|
||||
let dir_offset = if self.direction == Direction::Left { 0 } else { 2 };
|
||||
|
||||
self.anim_rect = state.constants.npc.n182_curly_ai_polar_star[self.anim_num as usize + dir_offset];
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n183_curly_air_tank_bubble(
|
||||
&mut self,
|
||||
state: &mut SharedGameState,
|
||||
npc_list: &NPCList,
|
||||
) -> GameResult {
|
||||
if let Some(parent) = self.get_parent_ref_mut(npc_list) {
|
||||
if self.action_num == 0 {
|
||||
self.x = parent.x;
|
||||
self.y = parent.y;
|
||||
self.action_num = 1;
|
||||
}
|
||||
|
||||
self.x += (parent.x - self.x) / 2;
|
||||
self.y += (parent.y - self.y) / 2;
|
||||
|
||||
self.animate(1, 0, 1);
|
||||
|
||||
self.anim_rect = if parent.flags.in_water() {
|
||||
state.constants.npc.n183_curly_air_tank_bubble[self.anim_num as usize]
|
||||
} else {
|
||||
Rect::new(0, 0, 0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,7 +92,7 @@ impl NPC {
|
|||
self.action_num = 0x14;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.x += self.vel_x;
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
use crate::framework::error::GameResult;
|
||||
use num_traits::{abs, clamp};
|
||||
|
||||
use crate::caret::CaretType;
|
||||
use crate::common::{CDEG_RAD, Direction, Rect};
|
||||
use crate::common::{Direction, Rect, CDEG_RAD};
|
||||
use crate::framework::error::GameResult;
|
||||
use crate::npc::list::NPCList;
|
||||
use crate::npc::NPC;
|
||||
use crate::player::Player;
|
||||
use crate::player::{Player, TargetPlayer};
|
||||
use crate::rng::RNG;
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
use crate::weapon::bullet::BulletManager;
|
||||
|
||||
impl NPC {
|
||||
pub(crate) fn tick_n002_behemoth(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
|
@ -20,23 +21,25 @@ impl NPC {
|
|||
match self.action_num {
|
||||
0 => {
|
||||
self.vel_x = match self.direction {
|
||||
Direction::Left => { -0x100 }
|
||||
Direction::Right => { 0x100 }
|
||||
_ => { 0 }
|
||||
Direction::Left => -0x100,
|
||||
Direction::Right => 0x100,
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
self.anim_counter += 1;
|
||||
if self.anim_counter > 8 {
|
||||
self.anim_counter = 0;
|
||||
self.anim_num = (self.anim_num + 1) % 3;
|
||||
self.anim_rect = state.constants.npc.n002_behemoth[self.anim_num as usize + if self.direction == Direction::Right { 7 } else { 0 }];
|
||||
self.anim_rect = state.constants.npc.n002_behemoth
|
||||
[self.anim_num as usize + if self.direction == Direction::Right { 7 } else { 0 }];
|
||||
}
|
||||
|
||||
if self.shock > 0 {
|
||||
self.action_counter = 0;
|
||||
self.action_num = 1;
|
||||
self.anim_num = 4;
|
||||
self.anim_rect = state.constants.npc.n002_behemoth[self.anim_num as usize + if self.direction == Direction::Right { 7 } else { 0 }];
|
||||
self.anim_rect = state.constants.npc.n002_behemoth
|
||||
[self.anim_num as usize + if self.direction == Direction::Right { 7 } else { 0 }];
|
||||
}
|
||||
}
|
||||
1 => {
|
||||
|
@ -50,7 +53,8 @@ impl NPC {
|
|||
self.anim_num = 6;
|
||||
self.anim_counter = 0;
|
||||
self.damage = 5;
|
||||
self.anim_rect = state.constants.npc.n002_behemoth[self.anim_num as usize + if self.direction == Direction::Right { 7 } else { 0 }];
|
||||
self.anim_rect = state.constants.npc.n002_behemoth
|
||||
[self.anim_num as usize + if self.direction == Direction::Right { 7 } else { 0 }];
|
||||
} else {
|
||||
self.action_num = 0;
|
||||
self.anim_counter = 0;
|
||||
|
@ -59,9 +63,9 @@ impl NPC {
|
|||
}
|
||||
2 => {
|
||||
self.vel_x = match self.direction {
|
||||
Direction::Left => { -0x400 }
|
||||
Direction::Right => { 0x400 }
|
||||
_ => { 0 }
|
||||
Direction::Left => -0x400,
|
||||
Direction::Right => 0x400,
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
self.action_counter += 1;
|
||||
|
@ -80,10 +84,11 @@ impl NPC {
|
|||
state.quake_counter = 8;
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n002_behemoth[self.anim_num as usize + if self.direction == Direction::Right { 7 } else { 0 }];
|
||||
self.anim_rect = state.constants.npc.n002_behemoth
|
||||
[self.anim_num as usize + if self.direction == Direction::Right { 7 } else { 0 }];
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y += 0x40;
|
||||
|
@ -97,14 +102,19 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n005_green_critter(&mut self, state: &mut SharedGameState, players: [&mut Player; 2]) -> GameResult {
|
||||
pub(crate) fn tick_n005_green_critter(
|
||||
&mut self,
|
||||
state: &mut SharedGameState,
|
||||
players: [&mut Player; 2],
|
||||
) -> GameResult {
|
||||
match self.action_num {
|
||||
0 | 1 => {
|
||||
if self.action_num == 0 {
|
||||
self.y += 0x600;
|
||||
self.action_num = 1;
|
||||
self.anim_num = 0;
|
||||
self.anim_rect = state.constants.npc.n005_green_critter[self.anim_num as usize + if self.direction == Direction::Right { 3 } else { 0 }];
|
||||
self.anim_rect = state.constants.npc.n005_green_critter
|
||||
[self.anim_num as usize + if self.direction == Direction::Right { 3 } else { 0 }];
|
||||
}
|
||||
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
@ -120,13 +130,15 @@ impl NPC {
|
|||
}
|
||||
|
||||
if self.action_counter >= 8
|
||||
&& self.x - (112 * 0x200) < player.x
|
||||
&& self.x + (112 * 0x200) > player.x
|
||||
&& self.y - (80 * 0x200) < player.y
|
||||
&& self.y + (80 * 0x200) > player.y {
|
||||
&& self.x - 0xe000 < player.x
|
||||
&& self.x + 0xe000 > player.x
|
||||
&& self.y - 0xa000 < player.y
|
||||
&& self.y + 0xa000 > player.y
|
||||
{
|
||||
if self.anim_num != 1 {
|
||||
self.anim_num = 1;
|
||||
self.anim_rect = state.constants.npc.n005_green_critter[self.anim_num as usize + if self.direction == Direction::Right { 3 } else { 0 }];
|
||||
self.anim_rect = state.constants.npc.n005_green_critter
|
||||
[self.anim_num as usize + if self.direction == Direction::Right { 3 } else { 0 }];
|
||||
}
|
||||
} else {
|
||||
if self.action_counter < 8 {
|
||||
|
@ -135,7 +147,8 @@ impl NPC {
|
|||
|
||||
if self.anim_num != 0 {
|
||||
self.anim_num = 0;
|
||||
self.anim_rect = state.constants.npc.n005_green_critter[self.anim_num as usize + if self.direction == Direction::Right { 3 } else { 0 }];
|
||||
self.anim_rect = state.constants.npc.n005_green_critter
|
||||
[self.anim_num as usize + if self.direction == Direction::Right { 3 } else { 0 }];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -145,22 +158,25 @@ impl NPC {
|
|||
|
||||
if self.anim_num != 0 {
|
||||
self.anim_num = 0;
|
||||
self.anim_rect = state.constants.npc.n005_green_critter[self.anim_num as usize + if self.direction == Direction::Right { 3 } else { 0 }];
|
||||
self.anim_rect = state.constants.npc.n005_green_critter
|
||||
[self.anim_num as usize + if self.direction == Direction::Right { 3 } else { 0 }];
|
||||
}
|
||||
}
|
||||
|
||||
if self.action_counter >= 8
|
||||
&& self.target_x >= 100
|
||||
&& self.x - (64 * 0x200) < player.x
|
||||
&& self.x + (64 * 0x200) > player.x
|
||||
&& self.y - (80 * 0x200) < player.y
|
||||
&& self.y + (80 * 0x200) > player.y {
|
||||
&& self.x - 0x8000 < player.x
|
||||
&& self.x + 0x8000 > player.x
|
||||
&& self.y - 0xa000 < player.y
|
||||
&& self.y + 0xa000 > player.y
|
||||
{
|
||||
self.action_num = 2;
|
||||
self.action_counter = 0;
|
||||
|
||||
if self.anim_num != 0 {
|
||||
self.anim_num = 0;
|
||||
self.anim_rect = state.constants.npc.n005_green_critter[self.anim_num as usize + if self.direction == Direction::Right { 3 } else { 0 }];
|
||||
self.anim_rect = state.constants.npc.n005_green_critter
|
||||
[self.anim_num as usize + if self.direction == Direction::Right { 3 } else { 0 }];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -171,7 +187,8 @@ impl NPC {
|
|||
|
||||
if self.anim_num != 2 {
|
||||
self.anim_num = 2;
|
||||
self.anim_rect = state.constants.npc.n005_green_critter[self.anim_num as usize + if self.direction == Direction::Right { 3 } else { 0 }];
|
||||
self.anim_rect = state.constants.npc.n005_green_critter
|
||||
[self.anim_num as usize + if self.direction == Direction::Right { 3 } else { 0 }];
|
||||
}
|
||||
|
||||
self.vel_y = -0x5ff;
|
||||
|
@ -194,11 +211,12 @@ impl NPC {
|
|||
|
||||
if self.anim_num != 0 {
|
||||
self.anim_num = 0;
|
||||
self.anim_rect = state.constants.npc.n005_green_critter[self.anim_num as usize + if self.direction == Direction::Right { 3 } else { 0 }];
|
||||
self.anim_rect = state.constants.npc.n005_green_critter
|
||||
[self.anim_num as usize + if self.direction == Direction::Right { 3 } else { 0 }];
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y += 0x40;
|
||||
|
@ -218,9 +236,13 @@ impl NPC {
|
|||
self.action_num = 1;
|
||||
|
||||
match self.direction {
|
||||
Direction::Left => { self.action_num = 1; }
|
||||
Direction::Right => { self.action_num = 3; }
|
||||
_ => {}
|
||||
Direction::Left => {
|
||||
self.action_num = 1;
|
||||
}
|
||||
Direction::Right => {
|
||||
self.action_num = 3;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
1 => {
|
||||
|
@ -301,10 +323,11 @@ impl NPC {
|
|||
self.anim_num = 1;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n006_green_beetle[self.anim_num as usize + if self.direction == Direction::Right { 5 } else { 0 }];
|
||||
self.anim_rect = state.constants.npc.n006_green_beetle
|
||||
[self.anim_num as usize + if self.direction == Direction::Right { 5 } else { 0 }];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -347,7 +370,7 @@ impl NPC {
|
|||
self.action_num = 1;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.vel_x < 0 {
|
||||
|
@ -367,13 +390,18 @@ impl NPC {
|
|||
}
|
||||
|
||||
if self.anim_counter == 1 {
|
||||
self.anim_rect = state.constants.npc.n007_basil[self.anim_num as usize + if self.direction == Direction::Right { 3 } else { 0 }];
|
||||
self.anim_rect = state.constants.npc.n007_basil
|
||||
[self.anim_num as usize + if self.direction == Direction::Right { 3 } else { 0 }];
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n008_blue_beetle(&mut self, state: &mut SharedGameState, players: [&mut Player; 2]) -> GameResult {
|
||||
pub(crate) fn tick_n008_blue_beetle(
|
||||
&mut self,
|
||||
state: &mut SharedGameState,
|
||||
players: [&mut Player; 2],
|
||||
) -> GameResult {
|
||||
match self.action_num {
|
||||
0 => {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
@ -394,7 +422,7 @@ impl NPC {
|
|||
self.x = player.x - 256 * 0x200;
|
||||
self.vel_x = 0x2ff;
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
} else {
|
||||
self.npc_flags.set_shootable(false);
|
||||
|
@ -431,7 +459,7 @@ impl NPC {
|
|||
self.y += self.vel_y;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.anim_counter += 1;
|
||||
|
@ -445,7 +473,8 @@ impl NPC {
|
|||
}
|
||||
|
||||
if self.anim_counter == 1 {
|
||||
self.anim_rect = state.constants.npc.n008_blue_beetle[self.anim_num as usize + if self.direction == Direction::Right { 2 } else { 0 }];
|
||||
self.anim_rect = state.constants.npc.n008_blue_beetle
|
||||
[self.anim_num as usize + if self.direction == Direction::Right { 2 } else { 0 }];
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -528,7 +557,7 @@ impl NPC {
|
|||
}
|
||||
self.animate(1, 0, 1);
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n025_lift[self.anim_num as usize];
|
||||
|
@ -536,7 +565,12 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n058_basu(&mut self, state: &mut SharedGameState, players: [&mut Player; 2], npc_list: &NPCList) -> GameResult {
|
||||
pub(crate) fn tick_n058_basu(
|
||||
&mut self,
|
||||
state: &mut SharedGameState,
|
||||
players: [&mut Player; 2],
|
||||
npc_list: &NPCList,
|
||||
) -> GameResult {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
match self.action_num {
|
||||
|
@ -599,13 +633,12 @@ impl NPC {
|
|||
self.vel_x = 0;
|
||||
self.x = self.target_x;
|
||||
self.damage = 0;
|
||||
self.direction = Direction::from_int_facing(self.tsc_direction as usize)
|
||||
.unwrap_or(Direction::Left);
|
||||
self.direction = Direction::from_int_facing(self.tsc_direction as usize).unwrap_or(Direction::Left);
|
||||
self.anim_rect = Rect::new(0, 0, 0, 0);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.action_counter < 150 {
|
||||
|
@ -677,6 +710,490 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n200_zombie_dragon(
|
||||
&mut self,
|
||||
state: &mut SharedGameState,
|
||||
players: [&mut Player; 2],
|
||||
npc_list: &NPCList,
|
||||
) -> GameResult {
|
||||
if self.action_num < 100 && self.life < 950 {
|
||||
self.action_num = 100;
|
||||
self.npc_flags.set_shootable(false);
|
||||
self.damage = 0;
|
||||
|
||||
state.sound_manager.play_sfx(72);
|
||||
npc_list.create_death_smoke(self.x, self.y, self.display_bounds.right as usize, 8, state, &self.rng);
|
||||
self.create_xp_drop(state, npc_list);
|
||||
}
|
||||
|
||||
match self.action_num {
|
||||
0 | 10 => {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 10;
|
||||
self.action_counter3 = 0;
|
||||
}
|
||||
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
self.animate(30, 0, 1);
|
||||
|
||||
if self.action_counter3 != 0 {
|
||||
self.action_counter3 -= 1;
|
||||
}
|
||||
|
||||
if self.action_counter3 == 0 && player.x > self.x - 0xE000 && player.x < self.x + 0xE000 {
|
||||
self.action_num = 20;
|
||||
}
|
||||
}
|
||||
20 | 21 => {
|
||||
if self.action_num == 20 {
|
||||
self.action_num = 21;
|
||||
self.action_counter = 0;
|
||||
}
|
||||
|
||||
self.action_counter += 1;
|
||||
if (self.action_counter & 1) != 0 {
|
||||
self.anim_num = 2;
|
||||
} else {
|
||||
self.anim_num = 3;
|
||||
}
|
||||
if self.action_counter > 30 {
|
||||
self.action_num = 30;
|
||||
}
|
||||
|
||||
let player = self.get_closest_player_mut(players);
|
||||
self.direction = if player.x >= self.x { Direction::Right } else { Direction::Left };
|
||||
}
|
||||
30 | 31 => {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
if self.action_num == 30 {
|
||||
self.action_num = 31;
|
||||
self.action_counter = 0;
|
||||
self.anim_num = 4;
|
||||
self.target_x = player.x;
|
||||
self.target_y = player.y;
|
||||
}
|
||||
|
||||
self.action_counter += 1;
|
||||
if self.action_counter <= 39 && self.action_counter % 8 == 1 {
|
||||
let px = self.x + (self.direction.vector_x() * 0x1c00) - self.target_x;
|
||||
let py = self.y - self.target_y;
|
||||
|
||||
let deg = f64::atan2(py as f64, px as f64) + self.rng.range(-6..6) as f64 * CDEG_RAD;
|
||||
|
||||
let mut npc = NPC::create(202, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
npc.x = self.x + self.direction.vector_x() * 0x1c00;
|
||||
npc.y = self.y;
|
||||
npc.vel_x = (deg.cos() * -1536.0) as i32;
|
||||
npc.vel_y = (deg.sin() * -1536.0) as i32;
|
||||
|
||||
let _ = npc_list.spawn(0x100, npc);
|
||||
|
||||
if !player.cond.hidden() {
|
||||
state.sound_manager.play_sfx(33);
|
||||
}
|
||||
}
|
||||
if self.action_counter > 60 {
|
||||
self.action_num = 10;
|
||||
self.action_counter3 = self.rng.range(100..200) as u16;
|
||||
self.anim_counter = 0;
|
||||
}
|
||||
}
|
||||
100 => {
|
||||
self.anim_num = 5;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let dir_offset = if self.direction == Direction::Left { 0 } else { 6 };
|
||||
|
||||
self.anim_rect = state.constants.npc.n200_zombie_dragon[self.anim_num as usize + dir_offset];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n201_zombie_dragon_dead(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
let dir_offset = if self.direction == Direction::Left { 0 } else { 1 };
|
||||
|
||||
self.anim_rect = state.constants.npc.n201_zombie_dragon_dead[dir_offset];
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n202_zombie_dragon_projectile(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
self.y += self.vel_y;
|
||||
self.x += self.vel_x;
|
||||
|
||||
self.animate(1, 0, 2);
|
||||
|
||||
self.anim_rect = state.constants.npc.n202_zombie_dragon_projectile[self.anim_num as usize];
|
||||
self.action_counter3 += 1;
|
||||
if self.flags.hit_anything() || 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_n203_critter_destroyed_egg_corridor(
|
||||
&mut self,
|
||||
state: &mut SharedGameState,
|
||||
players: [&mut Player; 2],
|
||||
) -> GameResult {
|
||||
match self.action_num {
|
||||
0 | 1 => {
|
||||
if self.action_num == 0 {
|
||||
self.y += 0x600;
|
||||
self.action_num = 1;
|
||||
self.anim_num = 0;
|
||||
}
|
||||
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
if self.x > player.x {
|
||||
self.direction = Direction::Left;
|
||||
} else {
|
||||
self.direction = Direction::Right;
|
||||
}
|
||||
|
||||
if self.target_x < 100 {
|
||||
self.target_x += 1;
|
||||
}
|
||||
|
||||
if self.action_counter >= 8
|
||||
&& self.x - 0xe000 < player.x
|
||||
&& self.x + 0xe000 > player.x
|
||||
&& self.y - 0xa000 < player.y
|
||||
&& self.y + 0xa000 > player.y
|
||||
{
|
||||
self.anim_num = 1;
|
||||
} else {
|
||||
if self.action_counter < 8 {
|
||||
self.action_counter += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if self.shock > 0 {
|
||||
self.action_num = 2;
|
||||
self.action_counter = 0;
|
||||
self.anim_num = 0;
|
||||
}
|
||||
|
||||
if self.action_counter >= 8
|
||||
&& self.target_x >= 100
|
||||
&& self.x - 0x6000 < player.x
|
||||
&& self.x + 0x6000 > player.x
|
||||
&& self.y - 0xa000 < player.y
|
||||
&& self.y + 0xa000 > player.y
|
||||
{
|
||||
self.action_num = 2;
|
||||
self.action_counter = 0;
|
||||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
self.action_counter += 1;
|
||||
if self.action_counter > 8 {
|
||||
self.action_num = 3;
|
||||
self.anim_num = 2;
|
||||
|
||||
self.vel_y = -0x5ff;
|
||||
state.sound_manager.play_sfx(30);
|
||||
|
||||
if self.direction == Direction::Left {
|
||||
self.vel_x = -0x100;
|
||||
} else {
|
||||
self.vel_x = 0x100;
|
||||
}
|
||||
}
|
||||
}
|
||||
3 => {
|
||||
if self.flags.hit_bottom_wall() {
|
||||
self.vel_x = 0;
|
||||
self.action_counter = 0;
|
||||
self.action_num = 1;
|
||||
self.anim_num = 0;
|
||||
|
||||
state.sound_manager.play_sfx(23);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let dir_offset = if self.direction == Direction::Right { 3 } else { 0 };
|
||||
self.anim_rect = state.constants.npc.n203_critter_destroyed_egg_corridor[self.anim_num as usize + dir_offset];
|
||||
|
||||
self.vel_y += 0x40;
|
||||
if self.vel_y > 0x5ff {
|
||||
self.vel_y = 0x5ff;
|
||||
}
|
||||
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n204_small_falling_spike(
|
||||
&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.target_x = self.x;
|
||||
}
|
||||
|
||||
let player = self.get_closest_player_ref(&players);
|
||||
|
||||
if player.x > self.x - 0x1800 && player.x < self.x + 0x1800 && player.y > self.y {
|
||||
self.action_num = 2;
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
self.action_counter += 1;
|
||||
self.x = if ((self.action_counter / 6) & 1) != 0 { self.target_x - 0x200 } else { self.target_x };
|
||||
|
||||
if self.action_counter > 30 {
|
||||
self.action_num = 3;
|
||||
self.anim_num = 1;
|
||||
}
|
||||
}
|
||||
3 => {
|
||||
self.vel_y += 0x20;
|
||||
|
||||
if self.flags.hit_anything() {
|
||||
let player = self.get_closest_player_ref(&players);
|
||||
if !player.cond.hidden() {
|
||||
state.sound_manager.play_sfx(12);
|
||||
}
|
||||
|
||||
npc_list.create_death_smoke(
|
||||
self.x,
|
||||
self.y,
|
||||
self.display_bounds.right as usize,
|
||||
4,
|
||||
state,
|
||||
&self.rng,
|
||||
);
|
||||
self.cond.set_alive(false);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.vel_y > 3072 {
|
||||
self.vel_y = 3072;
|
||||
}
|
||||
|
||||
self.y += self.vel_y;
|
||||
self.anim_rect = state.constants.npc.n204_small_falling_spike[self.anim_num as usize];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n205_large_falling_spike(
|
||||
&mut self,
|
||||
state: &mut SharedGameState,
|
||||
players: [&mut Player; 2],
|
||||
npc_list: &NPCList,
|
||||
bullet_manager: &mut BulletManager,
|
||||
) -> GameResult {
|
||||
match self.action_num {
|
||||
0 | 1 => {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
self.target_x = self.x;
|
||||
self.y += 0x800;
|
||||
}
|
||||
|
||||
let player = self.get_closest_player_ref(&players);
|
||||
if player.x > self.x - 0x1800 && player.x < self.x + 0x1800 && player.y > self.y {
|
||||
self.action_num = 2;
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
self.action_counter += 1;
|
||||
|
||||
if ((self.action_counter / 6) & 1) != 0 {
|
||||
self.x = self.target_x - 0x200;
|
||||
} else {
|
||||
self.x = self.target_x;
|
||||
}
|
||||
|
||||
if self.action_counter > 30 {
|
||||
self.action_num = 3;
|
||||
self.anim_num = 1;
|
||||
self.action_counter = 0;
|
||||
}
|
||||
}
|
||||
3 => {
|
||||
let player = self.get_closest_player_ref(&players);
|
||||
|
||||
if player.y <= self.y {
|
||||
self.npc_flags.set_solid_hard(true);
|
||||
self.damage = 0;
|
||||
} else {
|
||||
self.npc_flags.set_solid_hard(false);
|
||||
self.damage = 127;
|
||||
}
|
||||
|
||||
self.vel_y += 0x20;
|
||||
self.action_counter += 1;
|
||||
|
||||
if self.action_counter > 8 && self.flags.any_flag() {
|
||||
self.action_num = 4;
|
||||
self.action_counter = 0;
|
||||
self.damage = 0;
|
||||
self.vel_y = 0;
|
||||
self.npc_flags.set_solid_hard(true);
|
||||
|
||||
state.sound_manager.play_sfx(12);
|
||||
npc_list.create_death_smoke(
|
||||
self.x,
|
||||
self.y,
|
||||
self.display_bounds.right as usize,
|
||||
4,
|
||||
state,
|
||||
&self.rng,
|
||||
);
|
||||
bullet_manager.create_bullet(
|
||||
self.x,
|
||||
self.y,
|
||||
24,
|
||||
TargetPlayer::Player1,
|
||||
Direction::Left,
|
||||
&state.constants,
|
||||
);
|
||||
}
|
||||
}
|
||||
4 => {
|
||||
self.action_counter += 1;
|
||||
if self.action_counter > 4 {
|
||||
self.action_num = 5;
|
||||
self.npc_flags.set_shootable(true);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.vel_y > 0xC00 {
|
||||
self.vel_y = 0xC00;
|
||||
}
|
||||
|
||||
self.y += self.vel_y;
|
||||
|
||||
self.anim_rect = state.constants.npc.n205_large_falling_spike[self.anim_num as usize];
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n206_counter_bomb(
|
||||
&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.target_x = self.x;
|
||||
self.target_y = self.y;
|
||||
self.action_counter3 = 120;
|
||||
self.action_counter = self.rng.range(0..50) as u16;
|
||||
}
|
||||
self.action_counter += 1;
|
||||
if self.action_counter >= 50 {
|
||||
self.action_counter = 0;
|
||||
self.action_num = 2;
|
||||
self.vel_y = 0x300;
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
let player = self.get_closest_player_ref(&players);
|
||||
if player.x > self.x - 0xA000 && player.x < self.x + 0xA000 {
|
||||
self.action_counter = 0;
|
||||
self.action_num = 3;
|
||||
}
|
||||
|
||||
if self.shock > 0 {
|
||||
self.action_counter = 0;
|
||||
self.action_num = 3;
|
||||
}
|
||||
}
|
||||
3 => {
|
||||
let mut npc = NPC::create(207, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
npc.x = self.x + 0x2000;
|
||||
npc.y = self.y + 0x800;
|
||||
|
||||
match self.action_counter {
|
||||
0 => {
|
||||
npc.tsc_direction = 0;
|
||||
let _ = npc_list.spawn(0x100, npc);
|
||||
}
|
||||
60 => {
|
||||
npc.tsc_direction = 1;
|
||||
let _ = npc_list.spawn(0x100, npc);
|
||||
}
|
||||
120 => {
|
||||
npc.tsc_direction = 2;
|
||||
let _ = npc_list.spawn(0x100, npc);
|
||||
}
|
||||
180 => {
|
||||
npc.tsc_direction = 3;
|
||||
let _ = npc_list.spawn(0x100, npc);
|
||||
}
|
||||
240 => {
|
||||
npc.tsc_direction = 4;
|
||||
let _ = npc_list.spawn(0x100, npc);
|
||||
}
|
||||
300 => {
|
||||
self.hit_bounds.right = 0x10000;
|
||||
self.hit_bounds.left = 0x10000;
|
||||
self.hit_bounds.top = 0xC800;
|
||||
self.hit_bounds.bottom = 0xC800;
|
||||
self.damage = 30;
|
||||
self.cond.set_explode_die(true);
|
||||
|
||||
state.quake_counter = 20;
|
||||
state.sound_manager.play_sfx(35);
|
||||
npc_list.create_death_smoke(self.x, self.y, 0x10000, 100 as usize, state, &self.rng);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.action_counter += 1;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.action_num > 1 {
|
||||
if self.target_y < self.y {
|
||||
self.vel_y -= 0x10;
|
||||
}
|
||||
|
||||
if self.target_y > self.y {
|
||||
self.vel_y += 0x10;
|
||||
}
|
||||
|
||||
self.vel_y = self.vel_y.clamp(-0x100, 0x100);
|
||||
}
|
||||
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
|
||||
self.animate(4, 0, 2);
|
||||
|
||||
self.anim_rect = state.constants.npc.n206_counter_bomb[self.anim_num as usize];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n207_counter_bomb_countdown(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
match self.action_num {
|
||||
0 | 1 => {
|
||||
|
@ -700,7 +1217,7 @@ impl NPC {
|
|||
self.cond.set_alive(false);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n207_counter_bomb_countdown[self.anim_num as usize % 5];
|
||||
|
@ -708,7 +1225,12 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n208_basu_destroyed_egg_corridor(&mut self, state: &mut SharedGameState, players: [&mut Player; 2], npc_list: &NPCList) -> GameResult {
|
||||
pub(crate) fn tick_n208_basu_destroyed_egg_corridor(
|
||||
&mut self,
|
||||
state: &mut SharedGameState,
|
||||
players: [&mut Player; 2],
|
||||
npc_list: &NPCList,
|
||||
) -> GameResult {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
match self.action_num {
|
||||
|
@ -771,13 +1293,12 @@ impl NPC {
|
|||
self.vel_x = 0;
|
||||
self.x = self.target_x;
|
||||
self.damage = 0;
|
||||
self.direction = Direction::from_int_facing(self.tsc_direction as usize)
|
||||
.unwrap_or(Direction::Left);
|
||||
self.direction = Direction::from_int_facing(self.tsc_direction as usize).unwrap_or(Direction::Left);
|
||||
self.anim_rect = Rect::new(0, 0, 0, 0);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.action_counter < 150 {
|
||||
|
@ -824,7 +1345,10 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n209_basu_projectile_destroyed_egg_corridor(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
pub(crate) fn tick_n209_basu_projectile_destroyed_egg_corridor(
|
||||
&mut self,
|
||||
state: &mut SharedGameState,
|
||||
) -> GameResult {
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
|
||||
|
@ -848,4 +1372,87 @@ impl NPC {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n210_beetle_destroyed_egg_corridor(
|
||||
&mut self,
|
||||
state: &mut SharedGameState,
|
||||
players: [&mut Player; 2],
|
||||
) -> GameResult {
|
||||
match self.action_num {
|
||||
0 => {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
if player.x < self.x + 0x2000 && player.x > self.x - 0x2000 {
|
||||
self.npc_flags.set_shootable(true);
|
||||
self.vel_y = -0x200;
|
||||
self.target_y = self.y;
|
||||
self.action_num = 1;
|
||||
self.damage = 2;
|
||||
|
||||
match self.direction {
|
||||
Direction::Left => {
|
||||
self.x = player.x + 0x20000;
|
||||
self.vel_x = -0x2ff;
|
||||
}
|
||||
Direction::Right => {
|
||||
self.x = player.x - 0x20000;
|
||||
self.vel_x = 0x2ff;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
} else {
|
||||
self.npc_flags.set_shootable(false);
|
||||
self.anim_rect.left = 0;
|
||||
self.anim_rect.right = 0;
|
||||
self.damage = 0;
|
||||
self.vel_x = 0;
|
||||
self.vel_y = 0;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
1 => {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
if self.x > player.x {
|
||||
self.direction = Direction::Left;
|
||||
self.vel_x -= 0x10;
|
||||
} else {
|
||||
self.direction = Direction::Right;
|
||||
self.vel_x += 0x10;
|
||||
}
|
||||
|
||||
self.vel_y += if self.y < self.target_y { 8 } else { -8 };
|
||||
|
||||
self.vel_x = clamp(self.vel_x, -0x2ff, 0x2ff);
|
||||
self.vel_y = clamp(self.vel_y, -0x200, 0x200);
|
||||
|
||||
if self.shock > 0 {
|
||||
self.x += self.vel_x / 2;
|
||||
self.y += self.vel_y / 2;
|
||||
} else {
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.anim_counter += 1;
|
||||
if self.anim_counter > 1 {
|
||||
self.anim_counter = 0;
|
||||
self.anim_num += 1;
|
||||
|
||||
if self.anim_num > 1 {
|
||||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if self.anim_counter == 1 {
|
||||
self.anim_rect = state.constants.npc.n210_beetle_destroyed_egg_corridor
|
||||
[self.anim_num as usize + if self.direction == Direction::Right { 2 } else { 0 }];
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ impl NPC {
|
|||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.shock > 0 {
|
||||
|
@ -167,7 +167,7 @@ impl NPC {
|
|||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y += 0x40;
|
||||
|
@ -215,7 +215,7 @@ impl NPC {
|
|||
|
||||
self.vel_y = clamp(self.vel_y, -0x300, 0x300);
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.x += self.vel_x;
|
||||
|
|
|
@ -120,7 +120,7 @@ impl NPC {
|
|||
state.quake_counter = 30;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.action_num != 4 {
|
||||
|
@ -198,7 +198,7 @@ impl NPC {
|
|||
self.npc_flags.set_ignore_solidity(true);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.x += self.vel_x;
|
||||
|
@ -329,7 +329,7 @@ impl NPC {
|
|||
state.sound_manager.play_sfx(23);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.action_num != 4 {
|
||||
|
@ -429,7 +429,7 @@ impl NPC {
|
|||
self.vel_y = 0x200;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.x += self.vel_x;
|
||||
|
@ -549,7 +549,7 @@ impl NPC {
|
|||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.shock > 0 {
|
||||
|
@ -656,7 +656,7 @@ impl NPC {
|
|||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.direction = if self.x <= self.target_x { Direction::Right } else { Direction::Left };
|
||||
|
@ -835,7 +835,7 @@ impl NPC {
|
|||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.action_num <= 9
|
||||
|
@ -1021,7 +1021,7 @@ impl NPC {
|
|||
npc_list.create_death_smoke(self.x, self.y, 0x2000, 16, state, &self.rng);
|
||||
self.cond.set_alive(false);
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n107_malco_broken[self.anim_num as usize];
|
||||
|
@ -1085,7 +1085,7 @@ impl NPC {
|
|||
let _ = npc_list.spawn(0x100, npc.clone());
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y += 0x40;
|
||||
|
@ -1183,7 +1183,7 @@ impl NPC {
|
|||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.action_num <= 9
|
||||
|
@ -1333,7 +1333,7 @@ impl NPC {
|
|||
state.sound_manager.play_sfx(23);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y += if self.action_num <= 50 { 0x40 } else { 0x20 };
|
||||
|
@ -1423,7 +1423,7 @@ impl NPC {
|
|||
self.cond.set_alive(false);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.action_counter % 4 == 0 && self.action_num >= 20 {
|
||||
|
|
|
@ -71,7 +71,7 @@ impl NPC {
|
|||
7 => {
|
||||
self.action_num = 1;
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y += 0x40;
|
||||
|
@ -258,7 +258,7 @@ impl NPC {
|
|||
self.vel_x2 = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y += 0x40;
|
||||
|
@ -373,7 +373,7 @@ impl NPC {
|
|||
self.anim_rect = state.constants.npc.n089_igor_dead[self.anim_num as usize + dir_offset];
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -75,7 +75,7 @@ impl NPC {
|
|||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n298_intro_doctor[self.anim_num as usize];
|
||||
|
@ -97,7 +97,7 @@ impl NPC {
|
|||
self.anim_num = 0;
|
||||
self.action_counter = 0;
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@ impl NPC {
|
|||
state.sound_manager.play_sfx(23);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y += 0x55;
|
||||
|
|
|
@ -136,7 +136,7 @@ impl NPC {
|
|||
state.sound_manager.play_sfx(23);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.action_num == 4 {
|
||||
|
@ -314,7 +314,7 @@ impl NPC {
|
|||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y += 0x40;
|
||||
|
@ -349,7 +349,7 @@ impl NPC {
|
|||
match self.direction {
|
||||
Direction::Left => self.vel_x = 0x100,
|
||||
Direction::Right => self.vel_x = -0x100,
|
||||
_ => {}
|
||||
_ => (),
|
||||
};
|
||||
state.sound_manager.play_sfx(53);
|
||||
}
|
||||
|
@ -368,7 +368,7 @@ impl NPC {
|
|||
self.cond.set_explode_die(true);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y += 0x20;
|
||||
|
@ -458,7 +458,7 @@ impl NPC {
|
|||
self.anim_counter = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
if player.x >= self.x {
|
||||
self.direction = Direction::Right;
|
||||
|
@ -626,7 +626,7 @@ impl NPC {
|
|||
self.action_num = 1;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
self.y += self.vel_y;
|
||||
|
||||
|
@ -692,7 +692,7 @@ impl NPC {
|
|||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n166_chaba[self.anim_num as usize];
|
||||
|
@ -786,7 +786,7 @@ impl NPC {
|
|||
self.cond.set_alive(false);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
state.npc_super_pos = (self.x, -512000);
|
||||
|
@ -818,7 +818,7 @@ impl NPC {
|
|||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let dir_offset = if self.direction == Direction::Left { 0 } else { 2 };
|
||||
|
@ -850,7 +850,7 @@ impl NPC {
|
|||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let dir_offset = if self.direction == Direction::Left { 0 } else { 2 };
|
||||
|
@ -901,7 +901,7 @@ impl NPC {
|
|||
self.action_counter += 1;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n168_boulder;
|
||||
|
@ -1118,7 +1118,7 @@ impl NPC {
|
|||
self.action_counter = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y += 0x33;
|
||||
|
@ -1358,7 +1358,7 @@ impl NPC {
|
|||
|
||||
self.target_x += if self.direction != Direction::Left { 0x200 } else { -0x200 };
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_x = self.vel_x.clamp(-0x400, 0x400);
|
||||
|
@ -1419,7 +1419,7 @@ impl NPC {
|
|||
|
||||
self.action_num = 1;
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.animate(10, 0, 3);
|
||||
|
@ -1454,7 +1454,7 @@ impl NPC {
|
|||
self.y -= 0x3000;
|
||||
self.action_num = 1;
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -1480,7 +1480,7 @@ impl NPC {
|
|||
_ => (),
|
||||
};
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.animate(10, 0, 3);
|
||||
|
|
|
@ -91,7 +91,7 @@ impl NPC {
|
|||
self.action_num = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.shock > 0 && [1, 2, 4].contains(&self.action_num) {
|
||||
|
@ -199,7 +199,7 @@ impl NPC {
|
|||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.direction == Direction::Left {
|
||||
|
@ -243,7 +243,7 @@ impl NPC {
|
|||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
|
||||
|
@ -341,7 +341,7 @@ impl NPC {
|
|||
|
||||
self.anim_num = 6;
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if (self.vel_x < 0 && self.flags.hit_left_wall())
|
||||
|
@ -424,7 +424,7 @@ impl NPC {
|
|||
self.action_num = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.shock > 0 && [1, 2, 4].contains(&self.action_num) {
|
||||
|
|
|
@ -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;
|
||||
|
@ -84,7 +84,7 @@ impl NPC {
|
|||
Direction::Up => {
|
||||
self.anim_rect = state.constants.npc.n004_smoke[self.anim_num as usize + 8];
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -171,7 +171,7 @@ impl NPC {
|
|||
self.action_num = 1;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y += 0x40;
|
||||
|
@ -271,7 +271,7 @@ impl NPC {
|
|||
self.action_num = 1;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y += 0x40;
|
||||
|
@ -289,7 +289,7 @@ impl NPC {
|
|||
0 => match self.direction {
|
||||
Direction::Left => self.anim_rect = state.constants.npc.n018_door[0],
|
||||
Direction::Right => self.anim_rect = state.constants.npc.n018_door[1],
|
||||
_ => {}
|
||||
_ => (),
|
||||
},
|
||||
1 => {
|
||||
let mut npc = NPC::create(4, &state.npc_table);
|
||||
|
@ -307,7 +307,7 @@ impl NPC {
|
|||
self.action_num = 0;
|
||||
self.anim_rect = state.constants.npc.n018_door[0]
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -324,7 +324,7 @@ impl NPC {
|
|||
self.anim_num = self.anim_counter / 4;
|
||||
self.anim_rect = state.constants.npc.n020_computer[1 + self.anim_num as usize];
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -352,7 +352,7 @@ impl NPC {
|
|||
1 => {
|
||||
self.anim_num = (self.anim_num + 1) & 1;
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n022_teleporter[self.anim_num as usize];
|
||||
|
@ -408,7 +408,7 @@ impl NPC {
|
|||
self.anim_rect = state.constants.npc.n030_hermit_gunsmith[0];
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
} else {
|
||||
if self.action_num == 0 {
|
||||
|
@ -442,7 +442,7 @@ impl NPC {
|
|||
match self.direction {
|
||||
Direction::Left => self.anim_rect = state.constants.npc.n034_bed[0],
|
||||
Direction::Right => self.anim_rect = state.constants.npc.n034_bed[1],
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -472,7 +472,7 @@ impl NPC {
|
|||
self.anim_rect.left = 0;
|
||||
self.anim_rect.right = 0;
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -485,7 +485,7 @@ impl NPC {
|
|||
match self.direction {
|
||||
Direction::Left => self.anim_rect = state.constants.npc.n039_save_sign[0],
|
||||
Direction::Right => self.anim_rect = state.constants.npc.n039_save_sign[1],
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -511,7 +511,7 @@ impl NPC {
|
|||
match self.direction {
|
||||
Direction::Left => self.anim_rect = state.constants.npc.n043_chalkboard[0],
|
||||
Direction::Right => self.anim_rect = state.constants.npc.n043_chalkboard[1],
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -555,7 +555,6 @@ impl NPC {
|
|||
if self.direction == Direction::Left {
|
||||
self.anim_counter = (self.anim_counter + 1) % 4;
|
||||
self.anim_num = self.anim_counter / 2;
|
||||
self.anim_rect = state.constants.npc.n072_sprinkler[self.anim_num as usize];
|
||||
|
||||
let player = self.get_closest_player_mut(players);
|
||||
if self.anim_num % 2 == 0 && (player.x - self.x).abs() < 480 * 0x200 {
|
||||
|
@ -578,6 +577,8 @@ impl NPC {
|
|||
}
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n072_sprinkler[self.anim_num as usize];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -637,7 +638,7 @@ impl NPC {
|
|||
match self.direction {
|
||||
Direction::Left => self.anim_rect = state.constants.npc.n078_pot[0],
|
||||
Direction::Right => self.anim_rect = state.constants.npc.n078_pot[1],
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -650,8 +651,7 @@ impl NPC {
|
|||
self.anim_num = 0;
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
if abs(player.x - self.x) < 0x1000 && player.y < self.y + 0x1000 && player.y > self.y - 0x2000
|
||||
{
|
||||
if abs(player.x - self.x) < 0x1000 && player.y < self.y + 0x1000 && player.y > self.y - 0x2000 {
|
||||
state.sound_manager.play_sfx(43);
|
||||
self.action_num = 1;
|
||||
}
|
||||
|
@ -662,7 +662,7 @@ impl NPC {
|
|||
self.anim_num = 1;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let dir_offset = if self.direction == Direction::Left { 0 } else { 3 };
|
||||
|
@ -730,7 +730,7 @@ impl NPC {
|
|||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.anim_counter == 0 {
|
||||
|
@ -789,7 +789,7 @@ impl NPC {
|
|||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.anim_counter == 0 {
|
||||
|
@ -845,7 +845,7 @@ impl NPC {
|
|||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.anim_counter == 0 {
|
||||
|
@ -900,7 +900,7 @@ impl NPC {
|
|||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.anim_counter == 0 {
|
||||
|
@ -1002,7 +1002,7 @@ impl NPC {
|
|||
self.npc_flags.set_solid_hard(true);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y += 0x20;
|
||||
|
@ -1061,14 +1061,14 @@ impl NPC {
|
|||
npc.direction = Direction::Right;
|
||||
let _ = npc_list.spawn(0, npc);
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
match self.direction {
|
||||
Direction::Left => self.anim_rect = state.constants.npc.n125_hidden_item[0],
|
||||
Direction::Right => self.anim_rect = state.constants.npc.n125_hidden_item[1],
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -1119,7 +1119,7 @@ impl NPC {
|
|||
return Ok(());
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n146_lighting[self.anim_num as usize];
|
||||
|
@ -1243,7 +1243,7 @@ impl NPC {
|
|||
self.vel_x += 0x20;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_x = clamp(self.vel_x, -0x200, 0x200);
|
||||
|
@ -1387,7 +1387,7 @@ impl NPC {
|
|||
self.vel_y += 0x20;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y = clamp(self.vel_y, -0x200, 0x200);
|
||||
|
@ -1401,6 +1401,134 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n189_homing_flame(
|
||||
&mut self,
|
||||
state: &mut SharedGameState,
|
||||
players: [&mut Player; 2],
|
||||
) -> 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.vel_x = -0x40;
|
||||
}
|
||||
|
||||
self.y += self.vel_y;
|
||||
self.action_counter += 1;
|
||||
if self.action_counter > 256 {
|
||||
self.action_num = 10;
|
||||
}
|
||||
}
|
||||
10 => {
|
||||
self.vel_x += if player.x >= self.x { 8 } else { -8 };
|
||||
self.vel_y += if player.y >= self.y { 8 } else { -8 };
|
||||
|
||||
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;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if player.x >= self.x {
|
||||
self.direction = Direction::Right;
|
||||
} else {
|
||||
self.direction = Direction::Left;
|
||||
}
|
||||
|
||||
self.animate(2, 0, 2);
|
||||
|
||||
self.anim_rect = state.constants.npc.n189_homing_flame[self.anim_num as usize];
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n190_broken_robot(&mut self, state: &mut SharedGameState, npc_list: &NPCList) -> GameResult {
|
||||
match self.action_num {
|
||||
0 => self.anim_num = 0,
|
||||
10 => {
|
||||
let mut npc = NPC::create(4, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
npc.x = self.x;
|
||||
|
||||
for _ in 0..8 {
|
||||
npc.y = self.y + self.rng.range(-8..8) * 0x200;
|
||||
npc.vel_x = self.rng.range(-8..-2) * 0x200;
|
||||
npc.vel_y = self.rng.range(-3..3) * 0x200;
|
||||
|
||||
npc_list.spawn(0x100, npc.clone());
|
||||
}
|
||||
|
||||
state.sound_manager.play_sfx(72);
|
||||
self.cond.set_alive(false);
|
||||
}
|
||||
20 => self.animate(10, 0, 1),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n190_broken_robot[self.anim_num as usize];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n191_water_level(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
match self.action_num {
|
||||
0 | 10 => {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 10;
|
||||
self.target_y = self.y;
|
||||
self.vel_y = 0x200;
|
||||
}
|
||||
|
||||
self.vel_y += if self.y >= self.target_y { -4 } else { 4 };
|
||||
self.vel_y = self.vel_y.clamp(-0x100, 0x100);
|
||||
|
||||
self.y += self.vel_y;
|
||||
}
|
||||
20 | 21 => {
|
||||
if self.action_num == 20 {
|
||||
self.action_num = 21;
|
||||
self.action_counter = 0;
|
||||
}
|
||||
|
||||
self.vel_y += if self.y >= self.target_y { -4 } else { 4 };
|
||||
self.vel_y = self.vel_y.clamp(-0x200, 0x200);
|
||||
|
||||
self.y += self.vel_y;
|
||||
|
||||
self.action_counter += 1;
|
||||
if self.action_counter > 1000 {
|
||||
self.action_num = 22;
|
||||
}
|
||||
}
|
||||
22 => {
|
||||
self.vel_y += if self.y >= 0 { -4 } else { 4 };
|
||||
self.vel_y = self.vel_y.clamp(-0x200, 0x200);
|
||||
|
||||
self.y += self.vel_y;
|
||||
|
||||
if self.y <= 0x7FFF || state.npc_super_pos.1 > 0 {
|
||||
self.action_num = 21;
|
||||
self.action_counter = 0;
|
||||
}
|
||||
}
|
||||
30 => {
|
||||
self.vel_y += if self.y >= 0 { -4 } else { 4 };
|
||||
self.vel_y = self.vel_y.clamp(-0x200, 0x100);
|
||||
|
||||
self.y += self.vel_y;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
state.water_level = self.y;
|
||||
self.anim_rect = Rect::new(0, 0, 0, 0);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n194_broken_blue_robot(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
|
@ -1468,6 +1596,27 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n219_smoke_generator(&mut self, state: &mut SharedGameState, npc_list: &NPCList) -> GameResult {
|
||||
if self.direction != Direction::Left {
|
||||
let mut npc = NPC::create(199, &state.npc_table);
|
||||
npc.x = self.x + self.rng.range(-160..160) * 0x200;
|
||||
npc.y = self.y + self.rng.range(-128..128) * 0x200;
|
||||
npc.direction = Direction::Right;
|
||||
|
||||
let _ = npc_list.spawn(0x100, npc);
|
||||
} else if self.rng.range(0..40) == 1 {
|
||||
let mut npc = NPC::create(4, &state.npc_table);
|
||||
npc.x = self.x + self.rng.range(-20..20) * 0x200;
|
||||
npc.y = self.y;
|
||||
|
||||
let _ = npc_list.spawn(0x100, npc);
|
||||
}
|
||||
|
||||
self.anim_rect = Rect::new(0, 0, 0, 0);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n222_prison_bars(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
self.y -= 0x1000;
|
||||
|
@ -1594,7 +1743,7 @@ impl NPC {
|
|||
Direction::Up => self.y -= 0x400,
|
||||
Direction::Right => self.x += 0x400,
|
||||
Direction::Bottom => self.y += 0x400,
|
||||
_ => {}
|
||||
_ => (),
|
||||
},
|
||||
30 => {
|
||||
self.x = player.x;
|
||||
|
@ -1625,7 +1774,7 @@ impl NPC {
|
|||
self.y = (player.y + npc.y) / 2;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -1696,7 +1845,7 @@ impl NPC {
|
|||
self.anim_num += 4;
|
||||
self.action_num = 1;
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n351_statue_shootable[self.anim_num as usize % 9];
|
||||
|
@ -1801,7 +1950,7 @@ impl NPC {
|
|||
self.y = npc.y - 0x2600;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ impl NPC {
|
|||
|
||||
self.animate(3, 2, 3);
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.x += self.vel_x;
|
||||
|
@ -183,7 +183,7 @@ impl NPC {
|
|||
self.action_num = 14;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.x += self.vel_x;
|
||||
|
@ -350,7 +350,7 @@ impl NPC {
|
|||
50 => {
|
||||
self.anim_num = 8;
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.x += self.vel_x;
|
||||
|
|
|
@ -1,24 +1,25 @@
|
|||
pub mod balrog;
|
||||
pub mod booster;
|
||||
pub mod chaco;
|
||||
pub mod characters;
|
||||
pub mod curly;
|
||||
pub mod doctor;
|
||||
pub mod egg_corridor;
|
||||
pub mod first_cave;
|
||||
pub mod grasstown;
|
||||
pub mod igor;
|
||||
pub mod intro;
|
||||
pub mod last_cave;
|
||||
pub mod maze;
|
||||
pub mod mimiga_village;
|
||||
pub mod misc;
|
||||
pub mod misery;
|
||||
pub mod outer_wall;
|
||||
pub mod pickups;
|
||||
pub mod quote;
|
||||
pub mod sand_zone;
|
||||
pub mod santa;
|
||||
pub mod sue;
|
||||
pub mod toroko;
|
||||
pub mod weapon_trail;
|
||||
pub(in super) mod balrog;
|
||||
pub(in super) mod booster;
|
||||
pub(in super) mod chaco;
|
||||
pub(in super) mod characters;
|
||||
pub(in super) mod curly;
|
||||
pub(in super) mod doctor;
|
||||
pub(in super) mod egg_corridor;
|
||||
pub(in super) mod first_cave;
|
||||
pub(in super) mod grasstown;
|
||||
pub(in super) mod igor;
|
||||
pub(in super) mod intro;
|
||||
pub(in super) mod last_cave;
|
||||
pub(in super) mod maze;
|
||||
pub(in super) mod mimiga_village;
|
||||
pub(in super) mod misc;
|
||||
pub(in super) mod misery;
|
||||
pub(in super) mod outer_wall;
|
||||
pub(in super) mod pickups;
|
||||
pub(in super) mod plantation;
|
||||
pub(in super) mod quote;
|
||||
pub(in super) mod sand_zone;
|
||||
pub(in super) mod santa;
|
||||
pub(in super) mod sue;
|
||||
pub(in super) mod toroko;
|
||||
pub(in super) mod weapon_trail;
|
||||
|
|
|
@ -1,12 +1,226 @@
|
|||
use num_traits::abs;
|
||||
|
||||
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;
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
|
||||
impl NPC {
|
||||
pub(crate) fn tick_n215_sandcroc_outer_wall(&mut self, state: &mut SharedGameState, players: [&mut Player; 2]) -> GameResult {
|
||||
pub(crate) fn tick_n212_sky_dragon(
|
||||
&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 -= 0x800;
|
||||
}
|
||||
self.animate(30, 0, 1);
|
||||
}
|
||||
10 | 11 => {
|
||||
if self.action_num == 10 {
|
||||
self.action_num = 11;
|
||||
self.anim_num = 2;
|
||||
self.anim_counter = 0;
|
||||
self.target_y = self.y - 0x2000;
|
||||
self.target_x = self.x - 0xc00;
|
||||
self.vel_y = 0;
|
||||
self.npc_flags.set_ignore_solidity(true);
|
||||
}
|
||||
|
||||
self.vel_x += if self.x >= self.target_x { -8 } else { 8 };
|
||||
self.vel_y += if self.y >= self.target_y { -8 } else { 8 };
|
||||
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
|
||||
self.animate(5, 2, 3);
|
||||
}
|
||||
20 | 21 => {
|
||||
if self.action_num == 20 {
|
||||
self.action_num = 21;
|
||||
self.npc_flags.set_ignore_solidity(true);
|
||||
}
|
||||
self.vel_y += if self.y >= self.target_y { -0x10 } else { 0x10 };
|
||||
|
||||
self.vel_x += 0x20;
|
||||
self.vel_x = self.vel_x.clamp(-0x600, 0x600);
|
||||
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
|
||||
self.animate(2, 2, 3);
|
||||
}
|
||||
30 => {
|
||||
self.action_num = 31;
|
||||
|
||||
let mut npc = NPC::create(297, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
let _ = npc_list.spawn(0x100, npc);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n212_sky_dragon[self.anim_num as usize];
|
||||
|
||||
if players[0].equip.has_mimiga_mask() && self.anim_num > 1 {
|
||||
self.anim_rect.top += 40;
|
||||
self.anim_rect.bottom += 40;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n213_night_spirit(
|
||||
&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.anim_num = 0;
|
||||
self.target_x = self.x;
|
||||
self.target_y = self.y;
|
||||
}
|
||||
if player.y > self.y - 0x1000 && player.y < self.y + 0x1000 {
|
||||
self.y += if self.direction != Direction::Left { 0x1E000 } else { -0x1E000 };
|
||||
self.action_num = 10;
|
||||
self.action_counter = 0;
|
||||
self.anim_num = 1;
|
||||
self.vel_y = 0;
|
||||
self.npc_flags.set_shootable(true);
|
||||
}
|
||||
}
|
||||
10 => {
|
||||
self.animate(2, 1, 3);
|
||||
|
||||
self.action_counter += 1;
|
||||
if self.action_counter > 200 {
|
||||
self.action_num = 20;
|
||||
self.action_counter = 0;
|
||||
self.anim_num = 4;
|
||||
}
|
||||
}
|
||||
20 => {
|
||||
self.animate(2, 4, 6);
|
||||
|
||||
self.action_counter += 1;
|
||||
if self.action_counter > 50 {
|
||||
self.action_num = 30;
|
||||
self.action_counter = 0;
|
||||
self.anim_num = 7;
|
||||
}
|
||||
}
|
||||
30 => {
|
||||
self.animate(2, 7, 9);
|
||||
|
||||
self.action_counter += 1;
|
||||
if self.action_counter % 5 == 1 {
|
||||
let mut npc = NPC::create(214, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
npc.x = self.x;
|
||||
npc.y = self.y;
|
||||
|
||||
npc.vel_y = self.rng.range(-0x200..0x200);
|
||||
npc.vel_x = self.rng.range(2..12) * 0x80;
|
||||
let _ = npc_list.spawn(0x100, npc);
|
||||
|
||||
state.sound_manager.play_sfx(21);
|
||||
}
|
||||
|
||||
if self.action_counter > 50 {
|
||||
self.action_num = 10;
|
||||
self.action_counter = 0;
|
||||
self.anim_num = 1;
|
||||
}
|
||||
}
|
||||
40 => {
|
||||
self.vel_y += if self.y >= self.target_y { -0x40 } else { 0x40 };
|
||||
self.vel_y = self.vel_y.clamp(-0x400, 0x400);
|
||||
self.y += if self.shock > 0 { self.vel_y / 2 } else { self.vel_y };
|
||||
|
||||
self.animate(2, 4, 6);
|
||||
|
||||
if player.y < self.target_y + 0x1E000 && player.y > self.target_y - 0x1E000 {
|
||||
self.action_num = 20;
|
||||
self.action_counter = 0;
|
||||
self.anim_num = 4;
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.action_num > 9 && self.action_num <= 30 {
|
||||
self.vel_y += if self.y >= player.y { -0x19 } else { 0x19 };
|
||||
|
||||
self.vel_y = self.vel_y.clamp(-0x400, 0x400);
|
||||
|
||||
if self.flags.hit_top_wall() {
|
||||
self.vel_y = 0x200;
|
||||
}
|
||||
if self.flags.hit_bottom_wall() {
|
||||
self.vel_y = -0x200;
|
||||
}
|
||||
self.y += if self.shock > 0 { self.vel_y / 2 } else { self.vel_y };
|
||||
|
||||
if player.y > self.target_y + 0x1E000 || player.y < self.target_y - 0x1E000 {
|
||||
self.action_num = 40;
|
||||
}
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n213_night_spirit[self.anim_num as usize];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n214_night_spirit_projectile(
|
||||
&mut self,
|
||||
state: &mut SharedGameState,
|
||||
npc_list: &NPCList,
|
||||
) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
self.npc_flags.set_ignore_solidity(true);
|
||||
}
|
||||
|
||||
if self.action_num == 1 {
|
||||
self.animate(2, 0, 2);
|
||||
|
||||
self.vel_x -= 0x19;
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
|
||||
if self.vel_x < 0 {
|
||||
self.npc_flags.set_ignore_solidity(false);
|
||||
}
|
||||
|
||||
if self.flags.hit_anything() {
|
||||
npc_list.create_death_smoke(self.x, self.y, self.display_bounds.right as usize, 4, state, &self.rng);
|
||||
state.sound_manager.play_sfx(28);
|
||||
self.cond.set_alive(false);
|
||||
}
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n214_night_spirit_projectile[self.anim_num as usize];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n215_sandcroc_outer_wall(
|
||||
&mut self,
|
||||
state: &mut SharedGameState,
|
||||
players: [&mut Player; 2],
|
||||
) -> GameResult {
|
||||
match self.action_num {
|
||||
0 | 1 => {
|
||||
if self.action_num == 0 {
|
||||
|
@ -47,7 +261,7 @@ impl NPC {
|
|||
self.action_counter = 0;
|
||||
self.npc_flags.set_shootable(true);
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
30 => {
|
||||
|
@ -80,7 +294,7 @@ impl NPC {
|
|||
self.action_counter += 1;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n215_sandcroc_outer_wall[self.anim_num as usize];
|
||||
|
|
|
@ -187,7 +187,7 @@ impl NPC {
|
|||
3 => {
|
||||
self.anim_rect = state.constants.npc.n086_missile_pickup[2 + self.anim_num as usize];
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.action_counter2 > 550 {
|
||||
|
@ -255,7 +255,7 @@ impl NPC {
|
|||
6 => {
|
||||
self.anim_rect = state.constants.npc.n087_heart_pickup[2 + self.anim_num as usize];
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.action_counter2 > 550 {
|
||||
|
|
289
src/npc/ai/plantation.rs
Normal file
289
src/npc/ai/plantation.rs
Normal file
|
@ -0,0 +1,289 @@
|
|||
use crate::common::Direction;
|
||||
use crate::framework::error::GameResult;
|
||||
use crate::npc::NPC;
|
||||
use crate::player::Player;
|
||||
use crate::rng::RNG;
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
|
||||
impl NPC {
|
||||
pub(crate) fn tick_n220_shovel_brigade(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
match self.action_num {
|
||||
0 | 1 => {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
self.anim_num = 0;
|
||||
self.anim_counter = 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let dir_offset = if self.direction == Direction::Left { 0 } else { 2 };
|
||||
|
||||
self.anim_rect = state.constants.npc.n220_shovel_brigade[self.anim_num as usize + dir_offset];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n221_shovel_brigade_walking(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
match self.action_num {
|
||||
0 | 1 => {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
self.anim_num = 0;
|
||||
self.anim_counter = 0;
|
||||
self.vel_x = 0;
|
||||
}
|
||||
|
||||
if self.rng.range(0..60) == 1 {
|
||||
self.action_num = 2;
|
||||
self.action_counter = 0;
|
||||
self.anim_num = 1;
|
||||
}
|
||||
if self.rng.range(0..60) == 1 {
|
||||
self.action_num = 10;
|
||||
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;
|
||||
}
|
||||
}
|
||||
10 | 11 => {
|
||||
if self.action_num == 10 {
|
||||
self.action_num = 11;
|
||||
self.action_counter = self.rng.range(0..16) as u16;
|
||||
self.anim_num = 2;
|
||||
self.anim_counter = 0;
|
||||
|
||||
if (self.rng.range(0..9) & 1) != 0 {
|
||||
self.direction = Direction::Left;
|
||||
} else {
|
||||
self.direction = Direction::Right;
|
||||
}
|
||||
}
|
||||
|
||||
if self.direction != Direction::Left || !self.flags.hit_left_wall() {
|
||||
if self.direction == Direction::Right && self.flags.hit_right_wall() {
|
||||
self.direction = Direction::Left;
|
||||
}
|
||||
} else {
|
||||
self.direction = Direction::Right;
|
||||
}
|
||||
|
||||
if self.direction != Direction::Left {
|
||||
self.vel_x = 0x200;
|
||||
} else {
|
||||
self.vel_x = -0x200;
|
||||
}
|
||||
|
||||
self.animate(4, 2, 5);
|
||||
|
||||
self.action_counter += 1;
|
||||
if self.action_counter > 32 {
|
||||
self.action_num = 0;
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
self.vel_y += 0x20;
|
||||
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 { 6 };
|
||||
|
||||
self.anim_rect = state.constants.npc.n221_shovel_brigade_walking[self.anim_num as usize + dir_offset];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n223_momorin(&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.anim_num = 0;
|
||||
self.anim_counter = 0;
|
||||
}
|
||||
|
||||
if self.rng.range(0..160) == 1 {
|
||||
self.action_num = 2;
|
||||
self.action_counter = 0;
|
||||
self.anim_num = 1;
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
self.action_counter += 1;
|
||||
if self.action_counter > 12 {
|
||||
self.action_num = 1;
|
||||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
3 => {
|
||||
self.anim_num = 2;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let player = self.get_closest_player_ref(&players);
|
||||
|
||||
if self.action_num <= 1 && player.y < self.y + 0x2000 && player.y > self.y - 0x2000 {
|
||||
if player.x >= self.x {
|
||||
self.direction = Direction::Right;
|
||||
} else {
|
||||
self.direction = Direction::Left;
|
||||
}
|
||||
}
|
||||
|
||||
let dir_offset = if self.direction == Direction::Left { 0 } else { 3 };
|
||||
|
||||
self.anim_rect = state.constants.npc.n223_momorin[self.anim_num as usize + dir_offset];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n224_chie(&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.anim_num = 0;
|
||||
self.anim_counter = 0;
|
||||
}
|
||||
|
||||
if self.rng.range(0..160) == 1 {
|
||||
self.action_num = 2;
|
||||
self.action_counter = 0;
|
||||
self.anim_num = 1;
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
self.action_counter += 1;
|
||||
if self.action_counter > 12 {
|
||||
self.action_num = 1;
|
||||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
let player = self.get_closest_player_ref(&players);
|
||||
|
||||
if self.action_num <= 1 && player.y < self.y + 0x2000 && player.y > self.y - 0x2000 {
|
||||
if player.x >= self.x {
|
||||
self.direction = Direction::Right;
|
||||
} else {
|
||||
self.direction = Direction::Left;
|
||||
}
|
||||
}
|
||||
|
||||
let dir_offset = if self.direction == Direction::Left { 0 } else { 2 };
|
||||
|
||||
self.anim_rect = state.constants.npc.n224_chie[self.anim_num as usize + dir_offset];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n225_megane(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
self.anim_num = 0;
|
||||
self.anim_counter = 0;
|
||||
}
|
||||
|
||||
if self.action_num == 1 {
|
||||
if self.rng.range(0..160) == 1 {
|
||||
self.action_num = 2;
|
||||
self.action_counter = 0;
|
||||
self.anim_num = 1;
|
||||
}
|
||||
} else if self.action_num == 2 {
|
||||
self.action_counter += 1;
|
||||
|
||||
if self.action_counter > 12 {
|
||||
self.action_num = 1;
|
||||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
|
||||
let dir_offset = if self.direction == Direction::Left { 0 } else { 2 };
|
||||
|
||||
self.anim_rect = state.constants.npc.n225_megane[self.anim_num as usize + dir_offset];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n226_kanpachi_plantation(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
match self.action_num {
|
||||
0 | 1 => {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
self.anim_num = 0;
|
||||
self.anim_counter = 0;
|
||||
self.vel_x = 0;
|
||||
}
|
||||
if self.rng.range(0..60) == 1 {
|
||||
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;
|
||||
}
|
||||
}
|
||||
10 | 11 => {
|
||||
if self.action_num == 10 {
|
||||
self.action_num = 11;
|
||||
self.anim_num = 2;
|
||||
self.anim_counter = 0;
|
||||
}
|
||||
|
||||
self.vel_x = 0x200;
|
||||
|
||||
self.animate(4, 2, 5);
|
||||
self.action_counter += 1;
|
||||
}
|
||||
20 => {
|
||||
self.vel_x = 0;
|
||||
self.anim_num = 6;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y += 0x20;
|
||||
|
||||
if self.vel_y > 0x5FF {
|
||||
self.vel_y = 0x5FF;
|
||||
}
|
||||
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
|
||||
self.anim_rect = state.constants.npc.n226_kanpachi_plantation[self.anim_num as usize];
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -52,7 +52,7 @@ impl NPC {
|
|||
self.cond.set_alive(false);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y += 0x40;
|
||||
|
@ -109,7 +109,7 @@ impl NPC {
|
|||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y += 0x40;
|
||||
|
@ -270,7 +270,7 @@ impl NPC {
|
|||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let dir_offset = if self.direction == Direction::Left { 0 } else { 9 };
|
||||
|
|
|
@ -109,7 +109,7 @@ impl NPC {
|
|||
self.action_num = 6;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.life <= 100 {
|
||||
|
@ -175,7 +175,7 @@ impl NPC {
|
|||
self.anim_num = 1;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.vel_x2 < 0 && self.flags.hit_left_wall() {
|
||||
|
@ -247,7 +247,7 @@ impl NPC {
|
|||
self.action_counter = 0;
|
||||
self.npc_flags.set_shootable(true);
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
3 => {
|
||||
|
@ -280,7 +280,7 @@ impl NPC {
|
|||
self.action_counter += 1;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n047_sandcroc[self.anim_num as usize];
|
||||
|
@ -382,7 +382,7 @@ impl NPC {
|
|||
self.anim_num = 1;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.action_num > 9 {
|
||||
|
@ -458,7 +458,7 @@ impl NPC {
|
|||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y = clamp(self.vel_y, -0x5ff, 0x5ff);
|
||||
|
@ -527,7 +527,7 @@ impl NPC {
|
|||
self.vel_y += 0x20;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.vel_x < 0 && self.flags.hit_left_wall() {
|
||||
|
@ -678,7 +678,7 @@ impl NPC {
|
|||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y += 0x80;
|
||||
|
@ -756,7 +756,7 @@ impl NPC {
|
|||
self.anim_counter = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let dir_offset = if self.direction == Direction::Left { 0 } else { 3 };
|
||||
|
@ -836,7 +836,7 @@ impl NPC {
|
|||
self.vel_x = clamp(self.vel_x, -0x5ff, 0x5ff);
|
||||
self.vel_y = clamp(self.vel_y, -0x5ff, 0x5ff);
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.x += self.vel_x;
|
||||
|
@ -897,7 +897,7 @@ impl NPC {
|
|||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n121_colon_b[self.anim_num as usize];
|
||||
|
@ -1020,7 +1020,7 @@ impl NPC {
|
|||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
if self.action_num > 10 && self.action_num < 20 && self.life != 1000 {
|
||||
self.action_num = 20;
|
||||
|
@ -1079,7 +1079,7 @@ impl NPC {
|
|||
state.sound_manager.play_sfx(26);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n124_sunstone[self.anim_num as usize];
|
||||
|
@ -1159,7 +1159,7 @@ impl NPC {
|
|||
self.vel_x = -0x400;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
// why
|
||||
|
@ -1234,7 +1234,7 @@ impl NPC {
|
|||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.action_counter += 1;
|
||||
|
@ -1350,7 +1350,7 @@ impl NPC {
|
|||
state.sound_manager.play_sfx(105);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y += 0x40;
|
||||
|
@ -1390,7 +1390,7 @@ impl NPC {
|
|||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let dir_offset = if self.direction == Direction::Left { 0 } else { 2 };
|
||||
|
@ -1428,7 +1428,7 @@ impl NPC {
|
|||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
// todo dog stacking?
|
||||
|
@ -1511,7 +1511,7 @@ impl NPC {
|
|||
self.npc_flags.set_invulnerable(false);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
self.vel_y += 0x40;
|
||||
if self.vel_y > 0x5FF {
|
||||
|
@ -1604,7 +1604,7 @@ impl NPC {
|
|||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.action_num > 9 {
|
||||
|
|
|
@ -62,7 +62,7 @@ impl NPC {
|
|||
5 => {
|
||||
self.anim_num = 6;
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let dir_offset = if self.direction == Direction::Left { 0 } else { 7 };
|
||||
|
|
|
@ -205,7 +205,7 @@ impl NPC {
|
|||
self.anim_num = 9;
|
||||
self.vel_y = -0x400;
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.action_num != 14 {
|
||||
|
@ -275,7 +275,7 @@ impl NPC {
|
|||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n092_sue_at_pc[self.anim_num as usize];
|
||||
|
|
|
@ -148,7 +148,7 @@ impl NPC {
|
|||
12 => {
|
||||
self.vel_x = 0;
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y += 0x40;
|
||||
|
@ -252,7 +252,7 @@ impl NPC {
|
|||
self.vel_x = 0;
|
||||
self.anim_num = 5;
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.vel_y += 0x40;
|
||||
|
@ -560,7 +560,7 @@ impl NPC {
|
|||
self.cond.set_alive(false);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.action_num > 100 && self.action_num <= 104 && (self.action_counter % 9) == 0 {
|
||||
|
@ -744,7 +744,7 @@ impl NPC {
|
|||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
self.vel_y += 64;
|
||||
self.vel_y = self.vel_y.clamp(-0x5ff, 0x5ff);
|
||||
|
@ -807,7 +807,7 @@ impl NPC {
|
|||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.action_num > 1 {
|
||||
|
|
|
@ -24,7 +24,7 @@ impl NPC {
|
|||
Direction::Up | Direction::Bottom => {
|
||||
self.anim_rect = state.constants.npc.n127_machine_gun_trail_l2[self.anim_num as usize + 3];
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -54,7 +54,7 @@ impl NPC {
|
|||
self.display_bounds.left = 0x1000;
|
||||
self.display_bounds.top = 0x800;
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,7 @@ impl NPC {
|
|||
Direction::Bottom => {
|
||||
self.anim_rect = state.constants.npc.n128_machine_gun_trail_l3[self.anim_num as usize + 15];
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -1,12 +1,96 @@
|
|||
use crate::caret::CaretType;
|
||||
use crate::common::{Direction, CDEG_RAD};
|
||||
use crate::framework::error::GameResult;
|
||||
use crate::npc::boss::BossNPC;
|
||||
use crate::npc::list::NPCList;
|
||||
use crate::npc::NPC;
|
||||
use crate::player::Player;
|
||||
use crate::rng::RNG;
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
use crate::stage::Stage;
|
||||
|
||||
impl NPC {
|
||||
pub(crate) fn tick_n178_core_blade_projectile(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.flags.hit_anything() {
|
||||
state.create_caret(self.x, self.y, CaretType::ProjectileDissipation, Direction::Left);
|
||||
self.cond.set_alive(false);
|
||||
}
|
||||
|
||||
if self.flags.in_water() {
|
||||
self.x += self.vel_x / 2;
|
||||
self.y += self.vel_y / 2;
|
||||
} else {
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
}
|
||||
|
||||
self.animate(1, 0, 2);
|
||||
|
||||
self.action_counter3 += 1;
|
||||
if self.action_counter3 > 150 {
|
||||
self.vanish(state);
|
||||
state.create_caret(self.x, self.y, CaretType::ProjectileDissipation, Direction::Left);
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n178_core_blade_projectile[self.anim_num as usize];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n179_core_wisp_projectile(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.flags.hit_anything() {
|
||||
state.create_caret(self.x, self.y, CaretType::ProjectileDissipation, Direction::Left);
|
||||
self.cond.set_alive(false);
|
||||
}
|
||||
|
||||
self.vel_x -= 0x20;
|
||||
self.vel_y = 0;
|
||||
|
||||
if self.vel_x < -0x400 {
|
||||
self.vel_x = -0x400;
|
||||
}
|
||||
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
|
||||
self.animate(1, 0, 2);
|
||||
|
||||
self.action_counter3 += 1;
|
||||
if self.action_counter3 > 300 {
|
||||
self.vanish(state);
|
||||
state.create_caret(self.x, self.y, CaretType::ProjectileDissipation, Direction::Left);
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n179_core_wisp_projectile[self.anim_num as usize];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n218_core_giant_ball(&mut self, state: &mut SharedGameState) -> GameResult
|
||||
{
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
|
||||
self.action_counter += 1;
|
||||
if self.action_counter > 200 {
|
||||
self.cond.set_alive(false);
|
||||
}
|
||||
|
||||
self.animate(2, 0, 1);
|
||||
self.anim_rect = state.constants.npc.n218_core_giant_ball[self.anim_num as usize];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl BossNPC {
|
||||
pub(crate) fn tick_b04_core(&mut self, state: &mut SharedGameState, players: [&mut Player; 2], npc_list: &NPCList) {
|
||||
pub(crate) fn tick_b04_core(
|
||||
&mut self,
|
||||
state: &mut SharedGameState,
|
||||
mut players: [&mut Player; 2],
|
||||
npc_list: &NPCList,
|
||||
stage: &mut Stage,
|
||||
) {
|
||||
let mut flag = false;
|
||||
// i will refactor that one day
|
||||
#[allow(mutable_transmutes)]
|
||||
|
@ -83,21 +167,27 @@ impl BossNPC {
|
|||
|
||||
self.parts[2] = self.parts[1].clone();
|
||||
self.parts[2].x = self.parts[0].x + 0x2000;
|
||||
self.parts[2].x = self.parts[0].y;
|
||||
self.parts[2].y = self.parts[0].y;
|
||||
|
||||
self.parts[3] = self.parts[1].clone();
|
||||
self.parts[3].x = self.parts[0].x - 0x1000;
|
||||
self.parts[3].x = self.parts[0].y + 0x8000;
|
||||
self.parts[3].y = self.parts[0].y + 0x8000;
|
||||
|
||||
self.parts[6] = self.parts[1].clone();
|
||||
self.parts[6].x = self.parts[0].x - 0x6000;
|
||||
self.parts[6].x = self.parts[0].y - 0x4000;
|
||||
self.parts[6].y = self.parts[0].y - 0x4000;
|
||||
|
||||
self.parts[7] = self.parts[1].clone();
|
||||
self.parts[7].x = self.parts[0].x - 0x6000;
|
||||
self.parts[7].x = self.parts[0].y + 0x4000;
|
||||
self.parts[7].y = self.parts[0].y + 0x4000;
|
||||
|
||||
for part in self.parts.iter_mut() {
|
||||
part.prev_x = part.x;
|
||||
part.prev_y = part.y;
|
||||
}
|
||||
200 => {
|
||||
}
|
||||
200 | 201 => {
|
||||
if self.parts[0].action_num == 200 {
|
||||
self.parts[0].action_num = 201;
|
||||
self.parts[0].action_counter = 0;
|
||||
self.parts[11].npc_flags.set_shootable(false);
|
||||
|
@ -107,13 +197,14 @@ impl BossNPC {
|
|||
state.sound_manager.stop_sfx(41);
|
||||
state.sound_manager.stop_sfx(58);
|
||||
}
|
||||
201 => {
|
||||
self.parts[0].target_x = self.parts[0].x;
|
||||
self.parts[0].target_y = self.parts[0].y;
|
||||
|
||||
let idx = self.parts[0].get_closest_player_idx_mut(&players);
|
||||
self.parts[0].target_x = players[idx].x;
|
||||
self.parts[0].target_y = players[idx].y;
|
||||
|
||||
self.parts[0].action_counter += 1;
|
||||
if self.parts[0].action_counter > 400 {
|
||||
self.parts[0].action_counter2 += 2;
|
||||
self.parts[0].action_counter2 += 1;
|
||||
|
||||
state.sound_manager.play_sfx(115);
|
||||
|
||||
|
@ -123,24 +214,24 @@ impl BossNPC {
|
|||
self.parts[0].action_counter2 = 0;
|
||||
self.parts[0].action_num = 220;
|
||||
}
|
||||
}
|
||||
|
||||
self.parts[4].anim_num = 0;
|
||||
self.parts[5].anim_num = 0;
|
||||
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
210 | 211 => {
|
||||
if self.parts[0].action_num == 210 {
|
||||
self.parts[0].action_num = 211;
|
||||
self.parts[0].action_counter = 0;
|
||||
self.parts[0].action_counter2 = self.parts[0].life;
|
||||
self.parts[0].action_counter3 = self.parts[0].life;
|
||||
self.parts[11].npc_flags.set_shootable(true);
|
||||
}
|
||||
|
||||
let player = self.parts[0].get_closest_player_mut(players);
|
||||
self.parts[0].target_x = player.x;
|
||||
self.parts[0].target_y = player.y;
|
||||
let idx = self.parts[0].get_closest_player_idx_mut(&players);
|
||||
self.parts[0].target_x = players[idx].x;
|
||||
self.parts[0].target_y = players[idx].y;
|
||||
|
||||
if self.parts[0].shock > 0 {
|
||||
*flash_counter += 1;
|
||||
|
@ -171,7 +262,7 @@ impl BossNPC {
|
|||
}
|
||||
|
||||
if self.parts[0].action_counter > 400
|
||||
|| (self.parts[0].life as i32) < self.parts[0].action_counter2 as i32 - 200
|
||||
|| (self.parts[0].life as i32) < self.parts[0].action_counter3 as i32 - 200
|
||||
{
|
||||
self.parts[0].action_num = 200;
|
||||
self.parts[4].anim_num = 2;
|
||||
|
@ -200,7 +291,7 @@ impl BossNPC {
|
|||
npc.y = players[idx].y + self.parts[0].rng.range(-160..160) * 0x200;
|
||||
let _ = npc_list.spawn(0x100, npc);
|
||||
|
||||
for player in players {
|
||||
for player in players.iter_mut() {
|
||||
player.vel_x -= 0x20;
|
||||
player.cond.set_increase_acceleration(true);
|
||||
}
|
||||
|
@ -238,6 +329,53 @@ impl BossNPC {
|
|||
flag = true;
|
||||
}
|
||||
}
|
||||
500 | 501 => {
|
||||
if self.parts[0].action_num == 500 {
|
||||
self.parts[0].action_num = 501;
|
||||
self.parts[0].action_counter = 0;
|
||||
self.parts[0].vel_x = 0;
|
||||
self.parts[0].vel_y = 0;
|
||||
self.parts[4].anim_num = 2;
|
||||
self.parts[5].anim_num = 0;
|
||||
self.parts[1].action_num = 200;
|
||||
self.parts[2].action_num = 200;
|
||||
self.parts[3].action_num = 200;
|
||||
self.parts[6].action_num = 200;
|
||||
self.parts[7].action_num = 200;
|
||||
|
||||
state.quake_counter = 20;
|
||||
|
||||
let mut npc = NPC::create(4, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
for _ in 0..32 {
|
||||
npc.x = self.parts[0].x + self.parts[0].rng.range(-0x80..0x80) * 0x200;
|
||||
npc.y = self.parts[0].y + self.parts[0].rng.range(-0x40..0x40) * 0x200;
|
||||
|
||||
npc.vel_x = self.parts[0].rng.range(-0x80..0x80) * 0x200;
|
||||
npc.vel_y = self.parts[0].rng.range(-0x80..0x80) * 0x200;
|
||||
|
||||
let _ = npc_list.spawn(0x100, npc.clone());
|
||||
}
|
||||
|
||||
for i in 0..12 {
|
||||
self.parts[i].npc_flags.set_invulnerable(false);
|
||||
self.parts[i].npc_flags.set_shootable(false);
|
||||
}
|
||||
}
|
||||
|
||||
self.parts[0].action_counter += 1;
|
||||
if (self.parts[0].action_counter & 0x0f) != 0 {
|
||||
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(-0x40..0x40) * 0x200;
|
||||
npc.y = self.parts[0].y + self.parts[0].rng.range(-0x20..0x20) * 0x200;
|
||||
|
||||
npc.vel_x = self.parts[0].rng.range(-0x80..0x80) * 0x200;
|
||||
npc.vel_y = self.parts[0].rng.range(-0x80..0x80) * 0x200;
|
||||
|
||||
let _ = npc_list.spawn(0x100, npc);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
@ -258,21 +396,21 @@ impl BossNPC {
|
|||
npc.x = self.parts[4].x + self.parts[0].rng.range(-32..16) * 0x200;
|
||||
npc.vel_x = self.parts[0].rng.range(-0x200..0x200);
|
||||
npc.vel_y = self.parts[0].rng.range(-0x100..0x100);
|
||||
npc_list.spawn(0x100, npc.clone());
|
||||
let _ = npc_list.spawn(0x100, npc.clone());
|
||||
}
|
||||
}
|
||||
|
||||
if self.parts[0].action_num >= 200 && self.parts[0].action_num < 300 {
|
||||
if self.parts[0].action_counter == 140 {
|
||||
if self.parts[0].action_counter == 80 {
|
||||
self.parts[1].action_num = 120;
|
||||
} else if self.parts[0].action_counter == 110 {
|
||||
self.parts[2].action_num = 120;
|
||||
} else if self.parts[0].action_counter == 140 {
|
||||
self.parts[3].action_num = 120;
|
||||
} else if self.parts[0].action_counter == 170 {
|
||||
self.parts[6].action_num = 120;
|
||||
} else if self.parts[0].action_counter == 200 {
|
||||
self.parts[7].action_num = 120;
|
||||
} else if self.parts[0].action_counter == 80 {
|
||||
self.parts[1].action_num = 120;
|
||||
} else if self.parts[0].action_counter == 110 {
|
||||
self.parts[2].action_num = 120;
|
||||
}
|
||||
|
||||
if self.parts[0].x < self.parts[0].target_x + 0x14000 {
|
||||
|
@ -292,9 +430,251 @@ impl BossNPC {
|
|||
}
|
||||
}
|
||||
|
||||
self.parts[0].vel_x = self.parts[0].vel_x.clamp(-0x100, 0x100);
|
||||
self.parts[0].vel_y = self.parts[0].vel_y.clamp(-0x100, 0x100);
|
||||
self.parts[0].vel_x = self.parts[0].vel_x.clamp(-0x80, 0x80);
|
||||
self.parts[0].vel_y = self.parts[0].vel_y.clamp(-0x80, 0x80);
|
||||
self.parts[0].x += self.parts[0].vel_x;
|
||||
self.parts[0].y += self.parts[0].vel_y;
|
||||
|
||||
self.tick_b04_core_face(4, state);
|
||||
self.tick_b04_core_tail(5, state);
|
||||
self.tick_b04_core_small_head(1, state, &players, npc_list, stage);
|
||||
self.tick_b04_core_small_head(2, state, &players, npc_list, stage);
|
||||
self.tick_b04_core_small_head(3, state, &players, npc_list, stage);
|
||||
self.tick_b04_core_small_head(6, state, &players, npc_list, stage);
|
||||
self.tick_b04_core_small_head(7, state, &players, npc_list, stage);
|
||||
self.tick_b04_core_hitbox(8, state);
|
||||
self.tick_b04_core_hitbox(9, state);
|
||||
self.tick_b04_core_hitbox(10, state);
|
||||
self.tick_b04_core_hitbox(11, state);
|
||||
}
|
||||
|
||||
fn tick_b04_core_face(&mut self, i: usize, state: &mut SharedGameState) {
|
||||
let (head, tail) = self.parts.split_at_mut(i);
|
||||
let base = &mut head[0];
|
||||
let part = &mut tail[0];
|
||||
|
||||
match part.action_num {
|
||||
10 | 11 => {
|
||||
if part.action_num == 10 {
|
||||
part.action_num = 11;
|
||||
part.anim_num = 2;
|
||||
part.npc_flags.set_ignore_solidity(true);
|
||||
part.display_bounds.left = 0x4800;
|
||||
part.display_bounds.top = 0x7000;
|
||||
}
|
||||
part.x = base.x - 0x4800;
|
||||
part.y = base.y;
|
||||
}
|
||||
50 | 51 => {
|
||||
if part.action_num == 50 {
|
||||
part.action_num = 51;
|
||||
part.action_counter = 112;
|
||||
}
|
||||
part.action_counter -= 1;
|
||||
|
||||
if part.action_counter == 0 {
|
||||
part.action_num = 100;
|
||||
part.anim_num = 3;
|
||||
}
|
||||
part.x = base.x - 0x4800;
|
||||
part.y = base.y;
|
||||
}
|
||||
100 => {
|
||||
part.anim_num = 3;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if part.action_num == 51 {
|
||||
part.anim_rect.bottom = part.action_counter + part.anim_rect.top;
|
||||
}
|
||||
|
||||
part.anim_rect = state.constants.npc.b04_core[part.anim_num as usize];
|
||||
}
|
||||
|
||||
fn tick_b04_core_tail(&mut self, i: usize, state: &mut SharedGameState) {
|
||||
let (head, tail) = self.parts.split_at_mut(i);
|
||||
let base = &mut head[0];
|
||||
let part = &mut tail[0];
|
||||
|
||||
match part.action_num {
|
||||
10 | 11 => {
|
||||
if part.action_num == 10 {
|
||||
part.action_num = 11;
|
||||
part.anim_num = 0;
|
||||
part.npc_flags.set_ignore_solidity(true);
|
||||
part.display_bounds.left = 0x5800;
|
||||
part.display_bounds.top = 0x7000;
|
||||
}
|
||||
part.x = base.x + 0x5800;
|
||||
part.y = base.y;
|
||||
}
|
||||
50 | 51 => {
|
||||
if part.action_num == 50 {
|
||||
part.action_num = 51;
|
||||
part.action_counter = 112;
|
||||
}
|
||||
part.action_counter -= 1;
|
||||
|
||||
if part.action_counter == 0 {
|
||||
part.action_num = 100;
|
||||
part.anim_num = 2;
|
||||
}
|
||||
part.x = base.x + 0x5800;
|
||||
part.y = base.y;
|
||||
}
|
||||
100 => {
|
||||
part.anim_num = 2;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if part.action_num == 51 {
|
||||
part.anim_rect.bottom = part.action_counter + part.anim_rect.top;
|
||||
}
|
||||
|
||||
part.anim_rect = state.constants.npc.b04_core[4 + part.anim_num as usize];
|
||||
}
|
||||
|
||||
fn tick_b04_core_small_head(
|
||||
&mut self,
|
||||
i: usize,
|
||||
state: &mut SharedGameState,
|
||||
players: &[&mut Player; 2],
|
||||
npc_list: &NPCList,
|
||||
stage: &Stage,
|
||||
) {
|
||||
let (head, tail) = self.parts.split_at_mut(i);
|
||||
let base = &mut head[0];
|
||||
let part = &mut tail[0];
|
||||
|
||||
part.life = 1000;
|
||||
match part.action_num {
|
||||
10 => {
|
||||
part.anim_num = 2;
|
||||
part.npc_flags.set_shootable(false);
|
||||
}
|
||||
100 | 101 => {
|
||||
if part.action_num == 100 {
|
||||
part.action_num = 101;
|
||||
part.anim_num = 2;
|
||||
part.action_counter = 0;
|
||||
part.target_x = base.x + (base.rng.range(-128..32) * 0x200);
|
||||
part.target_y = base.y + (base.rng.range(-64..64) * 0x200);
|
||||
part.npc_flags.set_shootable(true);
|
||||
}
|
||||
part.x += (part.target_x - part.x) / 16;
|
||||
part.y += (part.target_y - part.y) / 16;
|
||||
|
||||
part.action_counter += 1;
|
||||
if part.action_counter > 50 {
|
||||
part.anim_num = 0;
|
||||
}
|
||||
}
|
||||
120 | 121 => {
|
||||
if part.action_num == 120 {
|
||||
part.action_num = 121;
|
||||
part.action_counter = 0;
|
||||
}
|
||||
|
||||
part.action_counter += 1;
|
||||
if ((part.action_counter / 2) & 1) != 0 {
|
||||
part.anim_num = 0;
|
||||
} else {
|
||||
part.anim_num = 1;
|
||||
}
|
||||
|
||||
if part.action_counter > 20 {
|
||||
part.action_num = 130;
|
||||
}
|
||||
}
|
||||
130 | 131 => {
|
||||
if part.action_num == 130 {
|
||||
part.action_num = 131;
|
||||
part.anim_num = 2;
|
||||
part.action_counter = 0;
|
||||
part.target_x = part.x + (part.rng.range(24..48) * 0x200);
|
||||
part.target_y = part.y + (part.rng.range(-4..4) * 0x200);
|
||||
}
|
||||
|
||||
part.x += (part.target_x - part.x) / 16;
|
||||
part.y += (part.target_y - part.y) / 16;
|
||||
|
||||
part.action_counter += 1;
|
||||
if part.action_counter > 50 {
|
||||
part.action_num = 140;
|
||||
part.anim_num = 0;
|
||||
}
|
||||
|
||||
if part.action_counter == 1 || part.action_counter == 3 {
|
||||
let player_idx = part.get_closest_player_idx_mut(players);
|
||||
let px = part.x - players[player_idx].x;
|
||||
let py = part.y - players[player_idx].y;
|
||||
|
||||
let deg = f64::atan2(py as f64, px as f64) + part.rng.range(-2..2) as f64 * CDEG_RAD;
|
||||
|
||||
let mut npc = NPC::create(178, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
npc.x = part.x;
|
||||
npc.y = part.y;
|
||||
npc.vel_x = (deg.cos() * -1024.0) as i32;
|
||||
npc.vel_y = (deg.sin() * -1024.0) as i32;
|
||||
|
||||
let _ = npc_list.spawn(0x100, npc);
|
||||
|
||||
state.sound_manager.play_sfx(39);
|
||||
}
|
||||
}
|
||||
140 => {
|
||||
part.x += (part.target_x - part.x) / 16;
|
||||
part.y += (part.target_y - part.y) / 16;
|
||||
}
|
||||
200 | 201 => {
|
||||
if part.action_num == 200 {
|
||||
part.action_num = 201;
|
||||
part.anim_num = 2;
|
||||
part.vel_x = 0;
|
||||
part.vel_y = 0;
|
||||
}
|
||||
part.vel_x += 32;
|
||||
part.x += part.vel_x;
|
||||
|
||||
if part.x > (stage.map.width as i32 * 0x2000) + 0x4000 {
|
||||
part.cond.set_alive(false);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
if part.shock > 0 {
|
||||
part.target_x += 1024;
|
||||
}
|
||||
|
||||
part.anim_rect = state.constants.npc.b04_core[7 + part.anim_num as usize];
|
||||
}
|
||||
|
||||
fn tick_b04_core_hitbox(&mut self, i: usize, state: &mut SharedGameState) {
|
||||
let (head, tail) = self.parts.split_at_mut(i);
|
||||
let base = &mut head[0];
|
||||
let part = &mut tail[0];
|
||||
|
||||
match part.action_counter2 {
|
||||
0 => {
|
||||
part.x = base.x;
|
||||
part.y = base.y - 0x4000;
|
||||
}
|
||||
1 => {
|
||||
part.x = base.x + 0x3800;
|
||||
part.y = base.y;
|
||||
}
|
||||
2 => {
|
||||
part.x = base.x + 0x800;
|
||||
part.y = base.y + 0x4000;
|
||||
}
|
||||
3 => {
|
||||
part.x = base.x - 0x3800;
|
||||
part.y = base.y + 0x800;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,100 @@
|
|||
use crate::common::Direction;
|
||||
use crate::framework::error::GameResult;
|
||||
use crate::npc::boss::BossNPC;
|
||||
use crate::npc::NPC;
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
use crate::rng::RNG;
|
||||
|
||||
impl NPC {
|
||||
pub(crate) fn tick_n196_ironhead_wall(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
self.x -= 0xC00;
|
||||
if self.x <= 0x26000 {
|
||||
self.x += 0x2C000;
|
||||
}
|
||||
|
||||
let dir_offset = if self.direction == Direction::Left { 0 } else { 1 };
|
||||
|
||||
self.anim_rect = state.constants.npc.n196_ironhead_wall[dir_offset];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n197_porcupine_fish(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
match self.action_num {
|
||||
0 | 10 => {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 10;
|
||||
self.anim_counter = 0;
|
||||
self.vel_y = self.rng.range(-0x200..0x200);
|
||||
self.vel_x = 0x800;
|
||||
}
|
||||
|
||||
self.animate(2, 0, 1);
|
||||
|
||||
if self.vel_x < 0 {
|
||||
self.damage = 3;
|
||||
self.action_num = 20;
|
||||
}
|
||||
}
|
||||
20 => {
|
||||
self.damage = 3;
|
||||
self.animate(0, 2, 3);
|
||||
|
||||
if self.x <= 0x5FFF {
|
||||
// npc->destroy_voice = 0; // todo
|
||||
self.cond.set_explode_die(true);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.flags.hit_top_wall() {
|
||||
self.vel_y = 0x200;
|
||||
}
|
||||
if self.flags.hit_bottom_wall() {
|
||||
self.vel_y = -0x200;
|
||||
}
|
||||
|
||||
self.vel_x -= 0xC;
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
self.anim_rect = state.constants.npc.n197_porcupine_fish[self.anim_num as usize];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n198_ironhead_projectile(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
self.action_counter += 1;
|
||||
if self.action_counter > 20 {
|
||||
self.action_num = 1;
|
||||
self.vel_x = 0;
|
||||
self.vel_y = 0;
|
||||
self.action_counter3 = 0;
|
||||
}
|
||||
} else if self.action_num == 1 {
|
||||
self.vel_x += 0x20;
|
||||
}
|
||||
|
||||
self.animate(0, 0, 2);
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
|
||||
self.anim_rect = state.constants.npc.n198_ironhead_projectile[self.anim_num as usize];
|
||||
|
||||
self.action_counter3 += 1;
|
||||
if self.action_counter3 > 100 {
|
||||
self.cond.set_alive(false);
|
||||
}
|
||||
|
||||
if self.action_counter3 % 4 == 1 {
|
||||
state.sound_manager.play_sfx(46);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl BossNPC {
|
||||
pub(crate) fn tick_b05_ironhead(&mut self) {
|
||||
|
||||
}
|
||||
pub(crate) fn tick_b05_ironhead(&mut self) {}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ impl GameEntity<([&mut Player; 2], &NPCList, &mut Stage, &BulletManager, &mut Fl
|
|||
fn tick(
|
||||
&mut self,
|
||||
state: &mut SharedGameState,
|
||||
(players, npc_list, _stage, bullet_manager, flash): (
|
||||
(players, npc_list, stage, bullet_manager, flash): (
|
||||
[&mut Player; 2],
|
||||
&NPCList,
|
||||
&mut Stage,
|
||||
|
@ -81,7 +81,7 @@ impl GameEntity<([&mut Player; 2], &NPCList, &mut Stage, &BulletManager, &mut Fl
|
|||
1 => self.tick_b01_omega(state, players, npc_list, bullet_manager, flash),
|
||||
2 => self.tick_b02_balfrog(state, players, npc_list),
|
||||
3 => self.tick_b03_monster_x(state, players, npc_list, flash),
|
||||
4 => self.tick_b04_core(state, players, npc_list),
|
||||
4 => self.tick_b04_core(state, players, npc_list, stage),
|
||||
5 => self.tick_b05_ironhead(),
|
||||
6 => self.tick_b06_twins(),
|
||||
7 => self.tick_b07_undead_core(),
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
use std::io;
|
||||
use std::io::Cursor;
|
||||
|
||||
use byteorder::{LE, ReadBytesExt};
|
||||
use byteorder::{ReadBytesExt, LE};
|
||||
use num_traits::abs;
|
||||
|
||||
use crate::bitfield;
|
||||
use crate::common::{Condition, interpolate_fix9_scale, Rect};
|
||||
use crate::common::Direction;
|
||||
use crate::common::Flag;
|
||||
use crate::common::{interpolate_fix9_scale, Condition, Rect};
|
||||
use crate::components::flash::Flash;
|
||||
use crate::components::number_popup::NumberPopup;
|
||||
use crate::entity::GameEntity;
|
||||
|
@ -185,7 +185,7 @@ impl NPC {
|
|||
}
|
||||
}
|
||||
|
||||
impl GameEntity<([&mut Player; 2], &NPCList, &mut Stage, &BulletManager, &mut Flash)> for NPC {
|
||||
impl GameEntity<([&mut Player; 2], &NPCList, &mut Stage, &mut BulletManager, &mut Flash)> for NPC {
|
||||
fn tick(
|
||||
&mut self,
|
||||
state: &mut SharedGameState,
|
||||
|
@ -193,7 +193,7 @@ impl GameEntity<([&mut Player; 2], &NPCList, &mut Stage, &BulletManager, &mut Fl
|
|||
[&mut Player; 2],
|
||||
&NPCList,
|
||||
&mut Stage,
|
||||
&BulletManager,
|
||||
&mut BulletManager,
|
||||
&mut Flash,
|
||||
),
|
||||
) -> GameResult {
|
||||
|
@ -383,23 +383,55 @@ impl GameEntity<([&mut Player; 2], &NPCList, &mut Stage, &BulletManager, &mut Fl
|
|||
175 => self.tick_n175_gaudi_egg(state),
|
||||
176 => self.tick_n176_buyo_buyo_base(state, players, npc_list),
|
||||
177 => self.tick_n177_buyo_buyo(state, players),
|
||||
178 => self.tick_n178_core_blade_projectile(state),
|
||||
179 => self.tick_n179_core_wisp_projectile(state),
|
||||
180 => self.tick_n180_curly_ai(state, players, npc_list),
|
||||
181 => self.tick_n181_curly_ai_machine_gun(state, npc_list, bullet_manager),
|
||||
182 => self.tick_n182_curly_ai_polar_star(state, npc_list, bullet_manager),
|
||||
183 => self.tick_n183_curly_air_tank_bubble(state, npc_list),
|
||||
184 => self.tick_n184_shutter(state, npc_list),
|
||||
185 => self.tick_n185_small_shutter(state),
|
||||
186 => self.tick_n186_lift_block(state),
|
||||
187 => self.tick_n187_fuzz_core(state, players, npc_list),
|
||||
188 => self.tick_n188_fuzz(state, players, npc_list),
|
||||
189 => self.tick_n189_homing_flame(state, players),
|
||||
190 => self.tick_n190_broken_robot(state, npc_list),
|
||||
191 => self.tick_n191_water_level(state),
|
||||
192 => self.tick_n192_scooter(state),
|
||||
193 => self.tick_n193_broken_scooter(state),
|
||||
194 => self.tick_n194_broken_blue_robot(state),
|
||||
195 => self.tick_n195_background_grate(state),
|
||||
196 => self.tick_n196_ironhead_wall(state),
|
||||
197 => self.tick_n197_porcupine_fish(state),
|
||||
198 => self.tick_n198_ironhead_projectile(state),
|
||||
199 => self.tick_n199_wind_particles(state),
|
||||
200 => self.tick_n200_zombie_dragon(state, players, npc_list),
|
||||
201 => self.tick_n201_zombie_dragon_dead(state),
|
||||
202 => self.tick_n202_zombie_dragon_projectile(state),
|
||||
203 => self.tick_n203_critter_destroyed_egg_corridor(state, players),
|
||||
204 => self.tick_n204_small_falling_spike(state, players, npc_list),
|
||||
205 => self.tick_n205_large_falling_spike(state, players, npc_list, bullet_manager),
|
||||
206 => self.tick_n206_counter_bomb(state, players, npc_list),
|
||||
207 => self.tick_n207_counter_bomb_countdown(state),
|
||||
208 => self.tick_n208_basu_destroyed_egg_corridor(state, players, npc_list),
|
||||
209 => self.tick_n209_basu_projectile_destroyed_egg_corridor(state),
|
||||
210 => self.tick_n210_beetle_destroyed_egg_corridor(state, players),
|
||||
211 => self.tick_n211_small_spikes(state),
|
||||
212 => self.tick_n212_sky_dragon(state, players, npc_list),
|
||||
213 => self.tick_n213_night_spirit(state, players, npc_list),
|
||||
214 => self.tick_n214_night_spirit_projectile(state, npc_list),
|
||||
215 => self.tick_n215_sandcroc_outer_wall(state, players),
|
||||
216 => self.tick_n216_debug_cat(state),
|
||||
217 => self.tick_n217_itoh(state),
|
||||
218 => self.tick_n218_core_giant_ball(state),
|
||||
219 => self.tick_n219_smoke_generator(state, npc_list),
|
||||
220 => self.tick_n220_shovel_brigade(state),
|
||||
221 => self.tick_n221_shovel_brigade_walking(state),
|
||||
222 => self.tick_n222_prison_bars(state),
|
||||
223 => self.tick_n223_momorin(state, players),
|
||||
224 => self.tick_n224_chie(state, players),
|
||||
225 => self.tick_n225_megane(state),
|
||||
226 => self.tick_n226_kanpachi_plantation(state),
|
||||
227 => self.tick_n227_bucket(state),
|
||||
229 => self.tick_n229_red_flowers_sprouts(state),
|
||||
230 => self.tick_n230_red_flowers_blooming(state),
|
||||
|
|
|
@ -125,10 +125,10 @@ pub trait PhysicalEntity {
|
|||
let bounds_bottom = if self.is_player() { 0x800 } else { 0x600 };
|
||||
let half_tile_size = state.tile_size.as_int() * 0x100;
|
||||
|
||||
// left wall
|
||||
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)
|
||||
&& (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 + 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
|
||||
{
|
||||
self.set_x(((x * 2 + 1) * half_tile_size) + self.hit_bounds().right as i32);
|
||||
|
@ -147,9 +147,7 @@ pub trait PhysicalEntity {
|
|||
}
|
||||
|
||||
// right wall
|
||||
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)
|
||||
&& (self.x() + self.hit_bounds().right as i32) > (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) * half_tile_size
|
||||
{
|
||||
self.set_x(((x * 2 - 1) * half_tile_size) - self.hit_bounds().right as i32);
|
||||
|
@ -166,11 +164,12 @@ pub trait PhysicalEntity {
|
|||
|
||||
self.flags().set_hit_right_wall(true);
|
||||
}
|
||||
}
|
||||
|
||||
// ceiling
|
||||
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)
|
||||
&& (self.y() - self.hit_bounds().top as i32) < (y * 2 + 1) * half_tile_size
|
||||
&& ((self.x() + self.hit_bounds().right as i32) > (x * 2 - 1) * half_tile_size + 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
|
||||
{
|
||||
self.set_y(((y * 2 + 1) * half_tile_size) + self.hit_bounds().top as i32);
|
||||
|
@ -203,9 +202,7 @@ pub trait PhysicalEntity {
|
|||
}
|
||||
|
||||
// floor
|
||||
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)
|
||||
&& ((self.y() + self.hit_bounds().bottom as i32) > ((y * 2 - 1) * half_tile_size))
|
||||
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)
|
||||
{
|
||||
self.set_y(((y * 2 - 1) * half_tile_size) - self.hit_bounds().bottom as i32);
|
||||
|
@ -225,6 +222,7 @@ pub trait PhysicalEntity {
|
|||
self.flags().set_hit_bottom_wall(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn test_platform_hit(&mut self, state: &mut SharedGameState, x: i32, y: i32) {
|
||||
let half_tile_size = state.tile_size.as_int() * 0x100;
|
||||
|
@ -897,5 +895,9 @@ pub trait PhysicalEntity {
|
|||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if self.is_player() && (self.y() - 0x800) > state.water_level {
|
||||
self.flags().set_in_water(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1289,6 +1289,45 @@ impl GameScene {
|
|||
|
||||
batch.draw(ctx)?;
|
||||
|
||||
if layer == TileLayer::Foreground && self.stage.data.background_type == BackgroundType::Water {
|
||||
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, &self.tex_background_name)?;
|
||||
let rect_top = Rect {
|
||||
left: 0,
|
||||
top: 0,
|
||||
right: 32,
|
||||
bottom: 16
|
||||
};
|
||||
let rect_middle = Rect {
|
||||
left: 0,
|
||||
top: 16,
|
||||
right: 32,
|
||||
bottom: 48
|
||||
};
|
||||
|
||||
let tile_start_x = frame_x as i32 / 32;
|
||||
let tile_end_x = (frame_x + 16.0 + state.canvas_size.0) as i32 / 32 + 1;
|
||||
let water_y = state.water_level as f32 / 512.0;
|
||||
let tile_count_y = (frame_y + 16.0 + state.canvas_size.1 - water_y) as i32 / 32 + 1;
|
||||
|
||||
for x in tile_start_x..tile_end_x {
|
||||
batch.add_rect(
|
||||
(x as f32 * 32.0) - frame_x,
|
||||
water_y - frame_y,
|
||||
&rect_top,
|
||||
);
|
||||
|
||||
for y in 0..tile_count_y {
|
||||
batch.add_rect(
|
||||
(x as f32 * 32.0) - frame_x,
|
||||
(y as f32 * 32.0) + water_y - frame_y,
|
||||
&rect_middle,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
batch.draw(ctx)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -1518,7 +1557,7 @@ impl GameScene {
|
|||
[&mut self.player1, &mut self.player2],
|
||||
&self.npc_list,
|
||||
&mut self.stage,
|
||||
&self.bullet_manager,
|
||||
&mut self.bullet_manager,
|
||||
&mut self.flash,
|
||||
),
|
||||
)?;
|
||||
|
@ -1698,12 +1737,12 @@ impl GameScene {
|
|||
self.draw_debug_object(npc, state, ctx)?;
|
||||
|
||||
let text = format!("{}:{}:{}", npc.id, npc.npc_type, npc.action_num);
|
||||
state.font.draw_colored_text_scaled(
|
||||
state.font.draw_colored_text_with_shadow_scaled(
|
||||
text.chars(),
|
||||
((npc.x - self.frame.x) / 0x200) as f32,
|
||||
((npc.y - self.frame.y) / 0x200) as f32,
|
||||
0.5,
|
||||
((npc.id & 0xf0) as u8, (npc.cond.0 >> 8) as u8, (npc.id & 0x0f << 4) as u8, 255),
|
||||
(255, 255, 0, 255),
|
||||
&state.constants,
|
||||
&mut state.texture_set,
|
||||
ctx,
|
||||
|
@ -1789,12 +1828,16 @@ impl Scene for GameScene {
|
|||
self.frame.target_y = self.player1.y;
|
||||
self.frame.immediate_update(state, &self.stage);
|
||||
|
||||
// I'd personally set it to something higher but left it as is for accuracy.
|
||||
state.water_level = 0x1e0000;
|
||||
|
||||
self.lighting_mode = match () {
|
||||
_ if self.intro_mode => LightingMode::None,
|
||||
_ if !state.constants.is_switch && (self.stage.data.background_type == BackgroundType::Black
|
||||
|| self.stage.data.background.name() == "bkBlack") => LightingMode::Ambient,
|
||||
_ if state.constants.is_switch && (self.stage.data.background_type == BackgroundType::Black
|
||||
|| self.stage.data.background.name() == "bkBlack") => LightingMode::None,
|
||||
_ if self.stage.data.background.name() == "bkFall" => LightingMode::None,
|
||||
_ if self.stage.data.background_type != BackgroundType::Black
|
||||
&& self.stage.data.background_type != BackgroundType::Outside
|
||||
&& self.stage.data.background_type != BackgroundType::OutsideWind
|
||||
|
@ -1857,6 +1900,8 @@ impl Scene for GameScene {
|
|||
}
|
||||
|
||||
for _ in 0..ticks {
|
||||
TextScriptVM::run(state, self, ctx)?;
|
||||
|
||||
match state.textscript_vm.mode {
|
||||
ScriptMode::Map if state.control_flags.tick_world() => self.tick_world(state)?,
|
||||
ScriptMode::StageSelect => self.stage_select.tick(state, (ctx, &self.player1, &self.player2))?,
|
||||
|
@ -1883,12 +1928,11 @@ impl Scene for GameScene {
|
|||
}
|
||||
|
||||
self.flash.tick(state, ())?;
|
||||
TextScriptVM::run(state, self, ctx)?;
|
||||
|
||||
#[cfg(feature = "scripting")]
|
||||
state.lua.scene_tick();
|
||||
|
||||
if state.control_flags.control_enabled() {
|
||||
if state.control_flags.tick_world() {
|
||||
self.tick = self.tick.wrapping_add(1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,6 @@ impl LoadingScene {
|
|||
|
||||
impl Scene for LoadingScene {
|
||||
fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||
println!("**TICK**");
|
||||
// deferred to let the loading image draw
|
||||
if self.tick == 1 {
|
||||
if let Err(err) = self.load_stuff(state, ctx) {
|
||||
|
|
|
@ -362,6 +362,19 @@ setmetatable(doukutsu.rs, {
|
|||
end,
|
||||
})
|
||||
|
||||
setmetatable(doukutsu, {
|
||||
__index = function(self, property)
|
||||
if property == "currentStage" then
|
||||
local v = __doukutsu_rs:stageCommand(0x03)
|
||||
if v == nil then
|
||||
v = -1
|
||||
end
|
||||
|
||||
return v
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
doukutsu.player = __doukutsu_rs_runtime_dont_touch._playerRef0
|
||||
|
||||
function doukutsu.playSfx(id)
|
||||
|
|
5
src/scripting/doukutsu.d.ts
vendored
5
src/scripting/doukutsu.d.ts
vendored
|
@ -208,6 +208,11 @@ declare namespace doukutsu {
|
|||
*/
|
||||
const rs: DoukutsuRSApi;
|
||||
|
||||
/**
|
||||
* The number of current stage, read-only. Set to -1 if in menu.
|
||||
*/
|
||||
const currentStage: number;
|
||||
|
||||
/**
|
||||
* Plays a sound effect with specified ID.
|
||||
*/
|
||||
|
|
|
@ -440,8 +440,9 @@ impl Doukutsu {
|
|||
LightingMode::Ambient => "ambient",
|
||||
}),
|
||||
0x02 => state.push(game_state.settings.shader_effects),
|
||||
0x03 => state.push(game_scene.stage_id as u32),
|
||||
0x101 => {
|
||||
if let Some(v) = state.to_str(4) {
|
||||
if let Some(v) = state.to_str(3) {
|
||||
game_scene.lighting_mode = match v {
|
||||
"none" => LightingMode::None,
|
||||
"backgroundOnly" => LightingMode::BackgroundOnly,
|
||||
|
|
|
@ -129,6 +129,7 @@ pub struct SharedGameState {
|
|||
pub npc_super_pos: (i32, i32),
|
||||
pub npc_curly_target: (i32, i32),
|
||||
pub npc_curly_counter: u16,
|
||||
pub water_level: i32,
|
||||
pub stages: Vec<StageData>,
|
||||
pub frame_time: f64,
|
||||
pub debugger: bool,
|
||||
|
@ -207,8 +208,6 @@ impl SharedGameState {
|
|||
}
|
||||
}
|
||||
|
||||
println!("lookup path: {:#?}", texture_set.paths);
|
||||
|
||||
#[cfg(feature = "hooks")]
|
||||
init_hooks();
|
||||
|
||||
|
@ -231,6 +230,7 @@ impl SharedGameState {
|
|||
npc_super_pos: (0, 0),
|
||||
npc_curly_target: (0, 0),
|
||||
npc_curly_counter: 0,
|
||||
water_level: 0,
|
||||
stages: Vec::with_capacity(96),
|
||||
frame_time: 0.0,
|
||||
debugger: false,
|
||||
|
|
|
@ -165,7 +165,6 @@ impl OrgPlaybackEngine {
|
|||
for track in 0..8 {
|
||||
if let Some(note) = self.song.tracks[track].notes.iter().find(|x| x.pos == self.play_pos) {
|
||||
// New note
|
||||
//eprintln!("{:?}", &self.keys);
|
||||
if note.key != 255 {
|
||||
if self.keys[track] == 255 {
|
||||
// New
|
||||
|
|
|
@ -1259,6 +1259,7 @@ impl TextScriptVM {
|
|||
|
||||
let skip = state.textscript_vm.flags.cutscene_skip();
|
||||
state.control_flags.set_tick_world(true);
|
||||
state.control_flags.set_interactions_disabled(true);
|
||||
state.textscript_vm.flags.0 = 0;
|
||||
state.textscript_vm.flags.set_cutscene_skip(skip);
|
||||
state.textscript_vm.face = 0;
|
||||
|
@ -1542,7 +1543,7 @@ impl TextScriptVM {
|
|||
[&mut game_scene.player1, &mut game_scene.player2],
|
||||
&game_scene.npc_list,
|
||||
&mut game_scene.stage,
|
||||
&game_scene.bullet_manager,
|
||||
&mut game_scene.bullet_manager,
|
||||
&mut game_scene.flash,
|
||||
),
|
||||
)?;
|
||||
|
|
|
@ -257,7 +257,6 @@ impl TextureSet {
|
|||
.iter()
|
||||
.find_map(|s| {
|
||||
FILE_TYPES.iter().map(|ext| [s, name, ext].join("")).find(|path| {
|
||||
println!("{}", path);
|
||||
filesystem::exists(ctx, path)
|
||||
})
|
||||
})
|
||||
|
@ -268,7 +267,6 @@ impl TextureSet {
|
|||
.iter()
|
||||
.find_map(|s| {
|
||||
FILE_TYPES.iter().map(|ext| [s, name, ".glow", ext].join("")).find(|path| {
|
||||
println!("{}", path);
|
||||
filesystem::exists(ctx, path)
|
||||
})
|
||||
}).is_some();
|
||||
|
|
|
@ -1010,6 +1010,15 @@ impl Bullet {
|
|||
self.anim_rect = state.constants.weapon.bullet_rects.b023_blade_slash[self.anim_num as usize + dir_offset];
|
||||
}
|
||||
|
||||
fn tick_spike(&mut self) {
|
||||
self.action_counter += 1;
|
||||
if self.action_counter > 2 {
|
||||
self.cond.set_alive(false);
|
||||
}
|
||||
|
||||
self.anim_rect = Rect::new(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
fn tick_blade_1(&mut self, state: &mut SharedGameState) {
|
||||
self.action_counter += 1;
|
||||
if self.action_counter > self.lifetime {
|
||||
|
@ -1597,6 +1606,7 @@ impl Bullet {
|
|||
21 => self.tick_bubble_3(state, players, new_bullets),
|
||||
22 => self.tick_bubble_spines(state),
|
||||
23 => self.tick_blade_slash(state),
|
||||
24 => self.tick_spike(),
|
||||
25 => self.tick_blade_1(state),
|
||||
26 => self.tick_blade_2(state),
|
||||
27 => self.tick_blade_3(state, new_bullets),
|
||||
|
|
Loading…
Reference in a new issue