1
0
Fork 0
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:
Alula 2021-01-18 20:31:35 +01:00
parent 500b8bbeaa
commit c9c746a6db
No known key found for this signature in database
GPG key ID: 3E00485503A1D8BA
12 changed files with 619 additions and 101 deletions

View 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,
}
}
}

View file

@ -1,4 +1,5 @@
pub mod boss_life_bar;
pub mod draw_common;
pub mod hud;
pub mod inventory;
pub mod stage_select;

View file

@ -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);

View file

@ -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);

View file

@ -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

View file

@ -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(())
}
}

View file

@ -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(())
}
}

View file

@ -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"
}
}
}

View file

@ -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 {

View file

@ -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))?;

View file

@ -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

View file

@ -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;