mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2025-03-28 04:49:20 +00:00
add a bunch of simpler npcs
This commit is contained in:
parent
500b8bbeaa
commit
c9c746a6db
14
src/components/inventory.rs
Normal file
14
src/components/inventory.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
|
||||
pub struct Inventory {
|
||||
text_y_pos: usize,
|
||||
tick: usize,
|
||||
}
|
||||
|
||||
impl Inventory {
|
||||
pub fn new() -> Inventory {
|
||||
Inventory {
|
||||
text_y_pos: 24,
|
||||
tick: 0,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
pub mod boss_life_bar;
|
||||
pub mod draw_common;
|
||||
pub mod hud;
|
||||
pub mod inventory;
|
||||
pub mod stage_select;
|
||||
|
|
|
@ -685,6 +685,37 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n207_counter_bomb_countdown(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
match self.action_num {
|
||||
0 | 1 => {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
self.anim_num = self.tsc_direction;
|
||||
state.sound_manager.play_sfx(43);
|
||||
}
|
||||
|
||||
self.x += 0x200;
|
||||
|
||||
self.action_counter += 1;
|
||||
if self.action_counter > 8 {
|
||||
self.action_num = 2;
|
||||
self.action_counter = 0;
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
self.action_counter += 1;
|
||||
if self.action_counter > 30 {
|
||||
self.cond.set_alive(false);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n207_counter_bomb_countdown[self.anim_num as usize % 5];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ use crate::common::Direction;
|
|||
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 {
|
||||
|
@ -22,7 +23,7 @@ impl NPC {
|
|||
match self.direction {
|
||||
Direction::Left => self.vel_x = 0x100,
|
||||
Direction::Right => self.vel_x = -0x100,
|
||||
_ => {},
|
||||
_ => {}
|
||||
};
|
||||
state.sound_manager.play_sfx(53);
|
||||
}
|
||||
|
@ -41,7 +42,7 @@ impl NPC {
|
|||
self.cond.set_explode_die(true);
|
||||
}
|
||||
}
|
||||
_ => {},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.vel_y += 0x20;
|
||||
|
@ -74,6 +75,37 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n166_chaba(&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;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
||||
self.anim_rect = state.constants.npc.n166_chaba[self.anim_num as usize];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n173_gaudi_armored(&mut self, state: &mut SharedGameState, players: [&mut Player; 2]) -> GameResult {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ use ggez::GameResult;
|
|||
use num_traits::{abs, clamp};
|
||||
|
||||
use crate::caret::CaretType;
|
||||
use crate::common::Direction;
|
||||
use crate::common::{Direction, Rect};
|
||||
use crate::npc::list::NPCList;
|
||||
use crate::npc::NPC;
|
||||
use crate::player::Player;
|
||||
|
@ -671,6 +671,15 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n090_background(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
self.anim_rect = state.constants.npc.n090_background;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n096_fan_left(&mut self, state: &mut SharedGameState, mut players: [&mut Player; 2], npc_list: &NPCList) -> GameResult {
|
||||
match self.action_num {
|
||||
0 | 1 => {
|
||||
|
@ -976,6 +985,24 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n116_red_petals(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
self.anim_rect = state.constants.npc.n116_red_petals;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n119_table_chair(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
self.anim_rect = state.constants.npc.n119_table_chair;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n125_hidden_item(&mut self, state: &mut SharedGameState, npc_list: &NPCList) -> GameResult {
|
||||
if self.life < 990 {
|
||||
npc_list.create_death_smoke(self.x, self.y, self.display_bounds.right, 8, state, &self.rng);
|
||||
|
@ -1014,6 +1041,15 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n137_large_door_frame(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
self.anim_rect = state.constants.npc.n137_large_door_frame;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n149_horizontal_moving_block(&mut self, state: &mut SharedGameState, players: [&mut Player; 2], npc_list: &NPCList) -> GameResult {
|
||||
match self.action_num {
|
||||
0 => {
|
||||
|
@ -1133,6 +1169,20 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n152_shutter_stuck(&mut self) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
|
||||
if self.direction == Direction::Right {
|
||||
self.y += 0x2000;
|
||||
}
|
||||
|
||||
self.anim_rect = Rect { left: 0, top: 0, right: 0, bottom: 0 };
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n157_vertical_moving_block(&mut self, state: &mut SharedGameState, players: [&mut Player; 2], npc_list: &NPCList) -> GameResult {
|
||||
match self.action_num {
|
||||
0 => {
|
||||
|
@ -1263,6 +1313,15 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n195_grate(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
self.anim_rect = state.constants.npc.n195_grate;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n199_wind_particles(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
|
@ -1300,6 +1359,62 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n216_debug_cat(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
self.anim_rect = state.constants.npc.n216_debug_cat;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n222_prison_bars(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
self.y -= 0x1000;
|
||||
|
||||
self.action_num = 1;
|
||||
self.anim_rect = state.constants.npc.n222_prison_bars;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n227_bucket(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
self.anim_rect = state.constants.npc.n227_bucket;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n229_red_flowers_sprouts(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
self.y -= 0x2000;
|
||||
|
||||
let anim = if self.direction == Direction::Left { 0 } else { 1 };
|
||||
|
||||
self.anim_rect = state.constants.npc.n229_red_flowers_sprouts[anim];
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n230_red_flowers_blooming(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
self.x -= 0x2000;
|
||||
self.y -= 0x2000;
|
||||
|
||||
let anim = if self.direction == Direction::Left { 0 } else { 1 };
|
||||
|
||||
self.anim_rect = state.constants.npc.n230_red_flowers_blooming[anim];
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n234_red_flowers_picked(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
|
@ -1315,6 +1430,287 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n239_cage_bars(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
if self.direction == Direction::Left {
|
||||
self.x += 0x1000;
|
||||
self.y += 0x2000;
|
||||
} else {
|
||||
self.display_bounds.left = 0x3000;
|
||||
self.display_bounds.top = 0x1000;
|
||||
self.display_bounds.right = 0x3000;
|
||||
}
|
||||
}
|
||||
|
||||
let anim = if self.direction == Direction::Left { 0 } else { 1 };
|
||||
|
||||
self.anim_rect = state.constants.npc.n239_cage_bars[anim];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n258_mimiga_sleeping(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
self.anim_rect = state.constants.npc.n258_mimiga_sleeping;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n292_quake(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
state.quake_counter = 10;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n297_sue_dragon_mouth(&mut self, state: &mut SharedGameState, npc_list: &NPCList) -> GameResult {
|
||||
if let Some(npc) = self.get_parent_ref_mut(npc_list) {
|
||||
self.x = npc.x + 0x2000;
|
||||
self.y = npc.y + 0x1000;
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n297_sue_dragon_mouth;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n302_camera_focus_marker(&mut self, state: &mut SharedGameState, players: [&mut Player; 2], npc_list: &NPCList) -> GameResult {
|
||||
let player = &players[state.textscript_vm.executor_player.index()];
|
||||
|
||||
match self.action_num {
|
||||
10 => {
|
||||
self.x = player.x;
|
||||
self.y = player.y - 0x4000;
|
||||
}
|
||||
20 => {
|
||||
match self.direction {
|
||||
Direction::Left => self.x -= 0x400,
|
||||
Direction::Up => self.y -= 0x400,
|
||||
Direction::Right => self.x += 0x400,
|
||||
Direction::Bottom => self.y += 0x400,
|
||||
_=>{}
|
||||
}
|
||||
}
|
||||
30 => {
|
||||
self.x = player.x;
|
||||
self.y = player.y + 0xa000;
|
||||
}
|
||||
100 | 101 => {
|
||||
if self.action_num == 100 {
|
||||
self.action_num = 101;
|
||||
|
||||
if self.tsc_direction != 0 {
|
||||
for npc in npc_list.iter_alive() {
|
||||
if npc.event_num == self.tsc_direction {
|
||||
self.parent_id = npc.id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if self.parent_id == 0 {
|
||||
self.cond.set_alive(false);
|
||||
}
|
||||
} else {
|
||||
// TODO: handle boss
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(npc) = self.get_parent_ref_mut(npc_list) {
|
||||
self.x = (player.x + npc.x) / 2;
|
||||
self.y = (player.y + npc.y) / 2;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n328_human_transform_machine(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
self.anim_rect = state.constants.npc.n328_human_transform_machine;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n329_laboratory_fan(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
self.anim_counter = self.anim_counter.wrapping_add(1);
|
||||
self.anim_rect = state.constants.npc.n329_laboratory_fan[(self.anim_counter as usize / 2) & 1];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n349_statue(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
|
||||
if self.direction == Direction::Left {
|
||||
self.x += 0x1000;
|
||||
} else if self.direction == Direction::Right {
|
||||
self.y += 0x2000;
|
||||
}
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n349_statue;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
pub(crate) fn tick_n351_statue_shootable(&mut self, state: &mut SharedGameState, npc_list: &NPCList) -> GameResult {
|
||||
match self.action_num {
|
||||
0 => {
|
||||
self.action_num = 1;
|
||||
self.anim_num = self.tsc_direction / 10;
|
||||
self.x += 0x1000;
|
||||
self.y += 0x1800;
|
||||
}
|
||||
10 | 11 => {
|
||||
if self.action_num == 10 {
|
||||
if let Some(true) = state.game_flags.get(self.flag_num as usize) {
|
||||
self.action_num = 20;
|
||||
} else {
|
||||
self.action_num = 11;
|
||||
self.npc_flags.set_shootable(true);
|
||||
}
|
||||
}
|
||||
|
||||
if self.life <= 900 {
|
||||
let mut npc = NPC::create(351, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
npc.x = self.x - 0x1000;
|
||||
npc.y = self.y - 0x1800;
|
||||
npc.tsc_direction = 10 * self.anim_num + 40;
|
||||
|
||||
npc_list.spawn(0, npc);
|
||||
self.cond.set_explode_die(true);
|
||||
}
|
||||
}
|
||||
20 => {
|
||||
self.anim_num += 4;
|
||||
self.action_num = 1;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n351_statue_shootable[self.anim_num as usize % 9];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n352_ending_characters(&mut self, state: &mut SharedGameState, npc_list: &NPCList) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
self.anim_num = 0;
|
||||
self.action_counter2 = self.tsc_direction / 100;
|
||||
self.tsc_direction %= 100;
|
||||
|
||||
if self.action_counter2 <= 13 && ((1 << self.action_counter2) & 0b11001110000000) != 0 {
|
||||
self.spritesheet_id = 21;
|
||||
}
|
||||
|
||||
if self.action_counter2 <= 12 && ((1 << self.action_counter2) & 0b1001000010100) != 0 {
|
||||
self.display_bounds.top = 0x2000;
|
||||
}
|
||||
|
||||
if self.action_counter2 == 9 {
|
||||
self.display_bounds.left = 0x2800;
|
||||
self.display_bounds.right = 0x2800;
|
||||
self.x -= 0x200;
|
||||
}
|
||||
|
||||
if self.action_counter2 == 0 {
|
||||
let mut npc = NPC::create(145, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
npc.direction = Direction::Right;
|
||||
npc.parent_id = self.id;
|
||||
|
||||
npc_list.spawn(0x100, npc);
|
||||
}
|
||||
}
|
||||
|
||||
self.vel_y += 0x40;
|
||||
if self.vel_y > 0x5ff {
|
||||
self.vel_y = 0x5ff;
|
||||
}
|
||||
|
||||
if self.flags.hit_bottom_wall() {
|
||||
self.action_num = 2;
|
||||
self.anim_num = 1;
|
||||
self.vel_y = 0;
|
||||
}
|
||||
|
||||
self.y += self.vel_y;
|
||||
|
||||
self.anim_rect = state.constants.npc.n352_ending_characters[(2 * self.action_counter2 as usize + self.anim_num as usize) % 28];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n355_quote_and_curly_on_balrog(&mut self, state: &mut SharedGameState, npc_list: &NPCList) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
match self.direction {
|
||||
Direction::Left => {
|
||||
self.spritesheet_id = 16;
|
||||
self.anim_num = 0;
|
||||
|
||||
if let Some(npc) = self.get_parent_ref_mut(npc_list) {
|
||||
self.x = npc.x - 0x1c00;
|
||||
self.y = npc.y + 0x1400;
|
||||
}
|
||||
}
|
||||
Direction::Up => {
|
||||
self.spritesheet_id = 23;
|
||||
self.anim_num = 1;
|
||||
|
||||
if let Some(npc) = self.get_parent_ref_mut(npc_list) {
|
||||
self.x = npc.x + 0x1c00;
|
||||
self.y = npc.y + 0x1400;
|
||||
}
|
||||
}
|
||||
Direction::Right => {
|
||||
self.spritesheet_id = 16;
|
||||
self.anim_num = 2;
|
||||
|
||||
if let Some(npc) = self.get_parent_ref_mut(npc_list) {
|
||||
self.x = npc.x - 0xe00;
|
||||
self.y = npc.y - 0x2600;
|
||||
}
|
||||
}
|
||||
Direction::Bottom => {
|
||||
self.spritesheet_id = 23;
|
||||
self.anim_num = 3;
|
||||
|
||||
if let Some(npc) = self.get_parent_ref_mut(npc_list) {
|
||||
self.x = npc.x + 0x800;
|
||||
self.y = npc.y - 0x2600;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n355_quote_and_curly_on_balrog[self.anim_num as usize];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n358_misery_credits(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
self.animate(6, 0, 1);
|
||||
} else if self.action_num == 10 {
|
||||
self.animate(6, 3, 4);
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n358_misery_credits[self.anim_num as usize];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n359_water_droplet_generator(&mut self, state: &mut SharedGameState, players: [&mut Player; 2], npc_list: &NPCList) -> GameResult {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
if abs(player.x - self.x) < 320 * 0x200
|
||||
|
|
|
@ -391,5 +391,22 @@ impl NPC {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n249_misery_boss_energy_shot(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
self.action_counter2 += 1;
|
||||
if self.action_counter2 > 8 {
|
||||
self.cond.set_alive(false);
|
||||
}
|
||||
|
||||
if self.direction == Direction::Left {
|
||||
self.x -= 0x400;
|
||||
self.anim_rect = state.constants.npc.n249_misery_boss_energy_shot[0];
|
||||
} else {
|
||||
self.x += 0x400;
|
||||
self.anim_rect = state.constants.npc.n249_misery_boss_energy_shot[1];
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -558,6 +558,14 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n120_colon_a(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
let anim = if self.direction == Direction::Left { 0 } else { 1 };
|
||||
|
||||
self.anim_rect = state.constants.npc.n120_colon_a[anim];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n124_sunstone(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
match self.action_num {
|
||||
0 | 1 => {
|
||||
|
@ -599,4 +607,26 @@ impl NPC {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n131_puppy_sleeping(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
self.action_counter += 1;
|
||||
if self.action_counter > 100 {
|
||||
self.action_counter = 0;
|
||||
state.create_caret(self.x, self.y, CaretType::Zzz, Direction::Left);
|
||||
}
|
||||
|
||||
let anim = if self.direction == Direction::Left { 0 } else { 1 };
|
||||
|
||||
self.anim_rect = state.constants.npc.n131_puppy_sleeping[anim];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n143_jenka_collapsed(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
let anim = if self.direction == Direction::Left { 0 } else { 1 };
|
||||
|
||||
self.anim_rect = state.constants.npc.n143_jenka_collapsed[anim];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,6 +74,7 @@ pub struct NPC {
|
|||
pub shock: u16,
|
||||
pub life: u16,
|
||||
pub damage: u16,
|
||||
pub spritesheet_id: u16,
|
||||
pub cond: Condition,
|
||||
pub flags: Flag,
|
||||
pub npc_flags: NPCFlag,
|
||||
|
@ -95,17 +96,7 @@ pub struct NPC {
|
|||
pub rng: Xoroshiro32PlusPlus,
|
||||
}
|
||||
|
||||
static PARTICLE_NPCS: [u16; 13] = [1, 4, 11, 45, 48, 73, 84, 86, 87, 108, 129, 199, 355];
|
||||
|
||||
impl NPC {
|
||||
pub fn get_start_index(&self) -> u16 {
|
||||
if PARTICLE_NPCS.contains(&self.npc_type) {
|
||||
0x100
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
pub fn empty() -> NPC {
|
||||
NPC {
|
||||
id: 0,
|
||||
|
@ -125,6 +116,7 @@ impl NPC {
|
|||
shock: 0,
|
||||
life: 0,
|
||||
damage: 0,
|
||||
spritesheet_id: 0,
|
||||
cond: Condition(0),
|
||||
flags: Flag(0),
|
||||
npc_flags: NPCFlag(0),
|
||||
|
@ -235,6 +227,7 @@ impl GameEntity<([&mut Player; 2], &NPCList, &mut Stage, &BulletManager)> for NP
|
|||
87 => self.tick_n087_heart_pickup(state),
|
||||
88 => self.tick_n088_igor_boss(state, players, npc_list),
|
||||
89 => self.tick_n089_igor_dead(state, players, npc_list),
|
||||
90 => self.tick_n090_background(state),
|
||||
91 => self.tick_n091_mimiga_cage(state),
|
||||
92 => self.tick_n092_sue_at_pc(state),
|
||||
93 => self.tick_n093_chaco(state, players),
|
||||
|
@ -259,29 +252,55 @@ impl GameEntity<([&mut Player; 2], &NPCList, &mut Stage, &BulletManager)> for NP
|
|||
112 => self.tick_n112_quote_teleport_in(state, players),
|
||||
113 => self.tick_n113_professor_booster(state),
|
||||
114 => self.tick_n114_press(state, players, npc_list),
|
||||
116 => self.tick_n116_red_petals(state),
|
||||
119 => self.tick_n119_table_chair(state),
|
||||
120 => self.tick_n120_colon_a(state),
|
||||
124 => self.tick_n124_sunstone(state),
|
||||
125 => self.tick_n125_hidden_item(state, npc_list),
|
||||
129 => self.tick_n129_fireball_snake_trail(state),
|
||||
131 => self.tick_n131_puppy_sleeping(state),
|
||||
137 => self.tick_n137_large_door_frame(state),
|
||||
143 => self.tick_n143_jenka_collapsed(state),
|
||||
149 => self.tick_n149_horizontal_moving_block(state, players, npc_list),
|
||||
150 => self.tick_n150_quote(state, players, npc_list),
|
||||
151 => self.tick_n151_blue_robot_standing(state),
|
||||
152 => self.tick_n152_shutter_stuck(),
|
||||
154 => self.tick_n154_gaudi_dead(state),
|
||||
156 => self.tick_n156_gaudi_projectile(state),
|
||||
157 => self.tick_n157_vertical_moving_block(state, players, npc_list),
|
||||
158 => self.tick_n158_fish_missile(state, players),
|
||||
166 => self.tick_n166_chaba(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_grate(state),
|
||||
199 => self.tick_n199_wind_particles(state),
|
||||
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),
|
||||
211 => self.tick_n211_small_spikes(state),
|
||||
215 => self.tick_n215_sandcroc_outer_wall(state, players),
|
||||
216 => self.tick_n216_debug_cat(state),
|
||||
222 => self.tick_n222_prison_bars(state),
|
||||
227 => self.tick_n227_bucket(state),
|
||||
234 => self.tick_n234_red_flowers_picked(state),
|
||||
239 => self.tick_n239_cage_bars(state),
|
||||
241 => self.tick_n241_critter_red(state, players),
|
||||
249 => self.tick_n249_misery_boss_energy_shot(state),
|
||||
258 => self.tick_n258_mimiga_sleeping(state),
|
||||
292 => self.tick_n292_quake(state),
|
||||
297 => self.tick_n297_sue_dragon_mouth(state, npc_list),
|
||||
298 => self.tick_n298_intro_doctor(state),
|
||||
299 => self.tick_n299_intro_balrog_misery(state),
|
||||
300 => self.tick_n300_intro_demon_crown(state),
|
||||
302 => self.tick_n302_camera_focus_marker(state, players, npc_list),
|
||||
328 => self.tick_n328_human_transform_machine(state),
|
||||
329 => self.tick_n329_laboratory_fan(state),
|
||||
349 => self.tick_n349_statue(state),
|
||||
351 => self.tick_n351_statue_shootable(state, npc_list),
|
||||
352 => self.tick_n352_ending_characters(state, npc_list),
|
||||
355 => self.tick_n355_quote_and_curly_on_balrog(state, npc_list),
|
||||
358 => self.tick_n358_misery_credits(state),
|
||||
359 => self.tick_n359_water_droplet_generator(state, players, npc_list),
|
||||
_ => Ok(()),
|
||||
}?;
|
||||
|
@ -306,7 +325,8 @@ impl GameEntity<([&mut Player; 2], &NPCList, &mut Stage, &BulletManager)> for NP
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, state.npc_table.get_texture_name(self.npc_type))?;
|
||||
let texture = state.npc_table.get_texture_name(self.spritesheet_id);
|
||||
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, texture)?;
|
||||
|
||||
let off_x = if self.direction == Direction::Left { self.display_bounds.left } else { self.display_bounds.right } as i32;
|
||||
let shock = if self.shock > 0 {
|
||||
|
@ -541,28 +561,26 @@ impl NPCTable {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_texture_name(&self, npc_type: u16) -> &str {
|
||||
if let Some(npc) = self.entries.get(npc_type as usize) {
|
||||
match npc.spritesheet_id {
|
||||
2 => &self.tileset_name,
|
||||
6 => "Fade",
|
||||
8 => "ItemImage",
|
||||
11 => "Arms",
|
||||
12 => "ArmsImage",
|
||||
14 => "StageImage",
|
||||
15 => "Loading",
|
||||
16 => "MyChar",
|
||||
17 => "Bullet",
|
||||
19 => "Caret",
|
||||
20 => "Npc/NpcSym",
|
||||
21 => &self.tex_npc1_name,
|
||||
22 => &self.tex_npc2_name,
|
||||
23 => "Npc/NpcRegu",
|
||||
26 => "TextBox",
|
||||
_ => "Npc/Npc0"
|
||||
}
|
||||
} else {
|
||||
"Npc/Npc0"
|
||||
pub fn get_texture_name(&self, spritesheet_id: u16) -> &str {
|
||||
match spritesheet_id {
|
||||
0 => "Title",
|
||||
2 => &self.tileset_name,
|
||||
6 => "Fade",
|
||||
8 => "ItemImage",
|
||||
11 => "Arms",
|
||||
12 => "ArmsImage",
|
||||
14 => "StageImage",
|
||||
15 => "Loading",
|
||||
16 => "MyChar",
|
||||
17 => "Bullet",
|
||||
19 => "Caret",
|
||||
20 => "Npc/NpcSym",
|
||||
21 => &self.tex_npc1_name,
|
||||
22 => &self.tex_npc2_name,
|
||||
23 => "Npc/NpcRegu",
|
||||
26 => "TextBox",
|
||||
27 => "Face",
|
||||
_ => "Npc/Npc0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,10 +26,20 @@ impl NPC {
|
|||
pub fn create(npc_type: u16, table: &NPCTable) -> NPC {
|
||||
let display_bounds = table.get_display_bounds(npc_type);
|
||||
let hit_bounds = table.get_hit_bounds(npc_type);
|
||||
let (size, life, damage, flags, exp) = match table.get_entry(npc_type) {
|
||||
Some(entry) => { (entry.size, entry.life, entry.damage as u16, entry.npc_flags, entry.experience as u16) }
|
||||
None => { (2, 0, 0, NPCFlag(0), 0) }
|
||||
};
|
||||
let (size, life, damage, flags, exp, spritesheet_id) =
|
||||
match table.get_entry(npc_type) {
|
||||
Some(entry) => {
|
||||
(
|
||||
entry.size,
|
||||
entry.life,
|
||||
entry.damage as u16,
|
||||
entry.npc_flags,
|
||||
entry.experience as u16,
|
||||
entry.spritesheet_id as u16
|
||||
)
|
||||
}
|
||||
None => { (2, 0, 0, NPCFlag(0), 0, 0) }
|
||||
};
|
||||
let npc_flags = NPCFlag(flags.0);
|
||||
|
||||
NPC {
|
||||
|
@ -54,6 +64,7 @@ impl NPC {
|
|||
size,
|
||||
life,
|
||||
damage,
|
||||
spritesheet_id,
|
||||
cond: Condition(0x00),
|
||||
flags: Flag(0),
|
||||
direction: if npc_flags.spawn_facing_right() { Direction::Right } else { Direction::Left },
|
||||
|
@ -71,50 +82,17 @@ impl NPC {
|
|||
}
|
||||
|
||||
pub fn create_from_data(data: &NPCData, table: &NPCTable) -> NPC {
|
||||
let display_bounds = table.get_display_bounds(data.npc_type);
|
||||
let hit_bounds = table.get_hit_bounds(data.npc_type);
|
||||
let (size, life, damage, flags, exp) = match table.get_entry(data.npc_type) {
|
||||
Some(entry) => { (entry.size, entry.life, entry.damage as u16, entry.npc_flags, entry.experience as u16) }
|
||||
None => { (1, 0, 0, NPCFlag(0), 0) }
|
||||
};
|
||||
let npc_flags = NPCFlag(data.flags | flags.0);
|
||||
let mut npc = NPC::create(data.npc_type, table);
|
||||
|
||||
NPC {
|
||||
id: data.id,
|
||||
npc_type: data.npc_type,
|
||||
x: data.x as i32 * 16 * 0x200,
|
||||
y: data.y as i32 * 16 * 0x200,
|
||||
vel_x: 0,
|
||||
vel_y: 0,
|
||||
vel_x2: 0,
|
||||
vel_y2: 0,
|
||||
target_x: 0,
|
||||
target_y: 0,
|
||||
prev_x: 0,
|
||||
prev_y: 0,
|
||||
action_num: 0,
|
||||
anim_num: 0,
|
||||
flag_num: data.flag_num,
|
||||
event_num: data.event_num,
|
||||
shock: 0,
|
||||
exp,
|
||||
size,
|
||||
life,
|
||||
damage,
|
||||
cond: Condition(0x00),
|
||||
flags: Flag(0),
|
||||
direction: if npc_flags.spawn_facing_right() { Direction::Right } else { Direction::Left },
|
||||
tsc_direction: 0,
|
||||
npc_flags,
|
||||
display_bounds,
|
||||
hit_bounds,
|
||||
parent_id: 0,
|
||||
action_counter: 0,
|
||||
action_counter2: 0,
|
||||
anim_counter: 0,
|
||||
anim_rect: Rect::new(0, 0, 0, 0),
|
||||
rng: Xoroshiro32PlusPlus::new(0),
|
||||
}
|
||||
npc.id = data.id;
|
||||
npc.x = data.x as i32 * 16 * 0x200;
|
||||
npc.y = data.y as i32 * 16 * 0x200;
|
||||
npc.flag_num = data.flag_num;
|
||||
npc.event_num = data.event_num;
|
||||
npc.npc_flags = NPCFlag(data.flags | npc.npc_flags.0);
|
||||
npc.direction = if npc.npc_flags.spawn_facing_right() { Direction::Right } else { Direction::Left };
|
||||
|
||||
npc
|
||||
}
|
||||
|
||||
/// Returns a reference to parent NPC (if present).
|
||||
|
@ -282,7 +260,7 @@ impl NPCList {
|
|||
}
|
||||
|
||||
state.game_flags.set(npc.flag_num as usize, true);
|
||||
|
||||
|
||||
if npc.npc_flags.show_damage() {
|
||||
// todo show damage
|
||||
if vanish {
|
||||
|
|
|
@ -798,7 +798,7 @@ impl GameScene {
|
|||
}
|
||||
|
||||
for bullet in self.bullet_manager.bullets.iter_mut() {
|
||||
if !bullet.cond.alive() || bullet.damage < 1 {
|
||||
if !bullet.cond.alive() || bullet.damage < 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -807,7 +807,7 @@ impl GameScene {
|
|||
}
|
||||
|
||||
if npc.npc_flags.shootable() {
|
||||
npc.life = npc.life.saturating_sub(bullet.damage);
|
||||
npc.life = clamp((npc.life as i32).saturating_sub(bullet.damage as i32), 0, u16::MAX as i32) as u16;
|
||||
|
||||
if npc.life == 0 {
|
||||
if npc.npc_flags.show_damage() {
|
||||
|
@ -870,7 +870,7 @@ impl GameScene {
|
|||
}
|
||||
|
||||
for bullet in self.bullet_manager.bullets.iter_mut() {
|
||||
if !bullet.cond.alive() || bullet.damage < 1 {
|
||||
if !bullet.cond.alive() || bullet.damage < 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -898,7 +898,7 @@ impl GameScene {
|
|||
npc = unsafe { self.boss.parts.get_unchecked_mut(0) };
|
||||
}
|
||||
|
||||
npc.life = npc.life.saturating_sub(bullet.damage);
|
||||
npc.life = clamp((npc.life as i32).saturating_sub(bullet.damage as i32), 0, u16::MAX as i32) as u16;
|
||||
|
||||
if npc.life == 0 {
|
||||
npc.life = npc.id;
|
||||
|
@ -1056,23 +1056,23 @@ impl GameScene {
|
|||
|
||||
if state.control_flags.control_enabled() {
|
||||
#[allow(clippy::cast_ref_to_mut)]
|
||||
let inventory = unsafe { &mut *(&self.inventory_player1 as *const Inventory as *mut Inventory)}; // fuck off
|
||||
let inventory = unsafe { &mut *(&self.inventory_player1 as *const Inventory as *mut Inventory) }; // fuck off
|
||||
if let Some(weapon) = self.inventory_player1.get_current_weapon_mut() {
|
||||
weapon.shoot_bullet(&mut self.player1,
|
||||
TargetPlayer::Player1,
|
||||
inventory,
|
||||
&mut self.bullet_manager,
|
||||
state);
|
||||
weapon.tick(&mut self.player1,
|
||||
TargetPlayer::Player1,
|
||||
inventory,
|
||||
&mut self.bullet_manager,
|
||||
state);
|
||||
}
|
||||
|
||||
#[allow(clippy::cast_ref_to_mut)]
|
||||
let inventory = unsafe { &mut *(&self.inventory_player2 as *const Inventory as *mut Inventory)};
|
||||
let inventory = unsafe { &mut *(&self.inventory_player2 as *const Inventory as *mut Inventory) };
|
||||
if let Some(weapon) = self.inventory_player2.get_current_weapon_mut() {
|
||||
weapon.shoot_bullet(&mut self.player2,
|
||||
TargetPlayer::Player2,
|
||||
inventory,
|
||||
&mut self.bullet_manager,
|
||||
state);
|
||||
weapon.tick(&mut self.player2,
|
||||
TargetPlayer::Player2,
|
||||
inventory,
|
||||
&mut self.bullet_manager,
|
||||
state);
|
||||
}
|
||||
|
||||
self.hud_player1.tick(state, (&self.player1, &mut self.inventory_player1))?;
|
||||
|
|
|
@ -31,7 +31,7 @@ impl Doukutsu {
|
|||
let game_state = &mut (*(*self.ptr).state_ptr);
|
||||
let ctx = &mut (*(*self.ptr).ctx_ptr);
|
||||
|
||||
game_state.sound_manager.play_song(index as usize, &game_state.constants, ctx);
|
||||
let _ = game_state.sound_manager.play_song(index as usize, &game_state.constants, ctx);
|
||||
}
|
||||
|
||||
0
|
||||
|
|
|
@ -1304,6 +1304,7 @@ impl TextScriptVM {
|
|||
npc.size = entry.size;
|
||||
npc.exp = entry.experience as u16;
|
||||
npc.damage = entry.damage as u16;
|
||||
npc.spritesheet_id = entry.spritesheet_id as u16;
|
||||
|
||||
npc.cond.set_alive(true);
|
||||
npc.action_num = 0;
|
||||
|
|
Loading…
Reference in a new issue