mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2024-11-22 13:42:47 +00:00
fix npc leaks, new mimiga village npcs
This commit is contained in:
parent
49461d66fa
commit
ed94343da3
|
@ -183,6 +183,8 @@ pub struct NPCConsts {
|
|||
pub n065_first_cave_bat: [Rect<usize>; 8],
|
||||
pub n066_misery_bubble: [Rect<usize>; 4],
|
||||
pub n067_misery_floating: [Rect<usize>; 16],
|
||||
pub n068_balrog: [Rect<usize>; 18],
|
||||
pub n069_pignon: [Rect<usize>; 12],
|
||||
pub n070_sparkle: [Rect<usize>; 4],
|
||||
pub n071_chinfish: [Rect<usize>; 6],
|
||||
pub n072_sprinkler: [Rect<usize>; 2],
|
||||
|
@ -222,7 +224,7 @@ pub struct TitleConsts {
|
|||
pub menu_bottom: Rect<usize>,
|
||||
pub menu_middle: Rect<usize>,
|
||||
pub menu_left: Rect<usize>,
|
||||
pub menu_right: Rect<usize>
|
||||
pub menu_right: Rect<usize>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -791,8 +793,6 @@ impl EngineConstants {
|
|||
Rect { left: 160, top: 0, right: 176, bottom: 16 },
|
||||
Rect { left: 176, top: 0, right: 192, bottom: 16 },
|
||||
Rect { left: 144, top: 0, right: 160, bottom: 16 },
|
||||
|
||||
|
||||
Rect { left: 80, top: 16, right: 96, bottom: 32 }, // right
|
||||
Rect { left: 96, top: 16, right: 112, bottom: 32 },
|
||||
Rect { left: 112, top: 16, right: 128, bottom: 32 },
|
||||
|
@ -802,6 +802,40 @@ impl EngineConstants {
|
|||
Rect { left: 176, top: 16, right: 192, bottom: 32 },
|
||||
Rect { left: 144, top: 16, right: 160, bottom: 32 },
|
||||
],
|
||||
n068_balrog: [
|
||||
Rect { left: 0, top: 0, right: 40, bottom: 24 }, // left
|
||||
Rect { left: 0, top: 48, right: 40, bottom: 72 },
|
||||
Rect { left: 0, top: 0, right: 40, bottom: 24 },
|
||||
Rect { left: 40, top: 48, right: 80, bottom: 72 },
|
||||
Rect { left: 0, top: 0, right: 40, bottom: 24 },
|
||||
Rect { left: 80, top: 48, right: 120, bottom: 72 },
|
||||
Rect { left: 120, top: 48, right: 160, bottom: 72 },
|
||||
Rect { left: 120, top: 0, right: 160, bottom: 24 },
|
||||
Rect { left: 80, top: 0, right: 120, bottom: 24 },
|
||||
Rect { left: 0, top: 24, right: 40, bottom: 48 }, // right
|
||||
Rect { left: 0, top: 72, right: 40, bottom: 96 },
|
||||
Rect { left: 0, top: 24, right: 40, bottom: 48 },
|
||||
Rect { left: 40, top: 72, right: 80, bottom: 96 },
|
||||
Rect { left: 0, top: 24, right: 40, bottom: 48 },
|
||||
Rect { left: 80, top: 72, right: 120, bottom: 96 },
|
||||
Rect { left: 120, top: 72, right: 160, bottom: 96 },
|
||||
Rect { left: 120, top: 24, right: 160, bottom: 48 },
|
||||
Rect { left: 80, top: 24, right: 120, bottom: 48 },
|
||||
],
|
||||
n069_pignon: [
|
||||
Rect { left: 48, top: 0, right: 64, bottom: 16 }, // left
|
||||
Rect { left: 64, top: 0, right: 80, bottom: 16 },
|
||||
Rect { left: 80, top: 0, right: 96, bottom: 16 },
|
||||
Rect { left: 96, top: 0, right: 112, bottom: 16 },
|
||||
Rect { left: 48, top: 0, right: 64, bottom: 16 },
|
||||
Rect { left: 112, top: 0, right: 128, bottom: 16 },
|
||||
Rect { left: 48, top: 16, right: 64, bottom: 32 }, // right
|
||||
Rect { left: 64, top: 16, right: 80, bottom: 32 },
|
||||
Rect { left: 80, top: 16, right: 96, bottom: 32 },
|
||||
Rect { left: 96, top: 16, right: 112, bottom: 32 },
|
||||
Rect { left: 48, top: 16, right: 64, bottom: 32 },
|
||||
Rect { left: 112, top: 16, right: 128, bottom: 32 },
|
||||
],
|
||||
n070_sparkle: [
|
||||
Rect { left: 96, top: 48, right: 112, bottom: 64 },
|
||||
Rect { left: 112, top: 48, right: 128, bottom: 64 },
|
||||
|
@ -1093,8 +1127,6 @@ impl EngineConstants {
|
|||
"Resource/BITMAP/Credit17" => (160, 240), // cse2
|
||||
"Resource/BITMAP/Credit18" => (160, 240), // cse2
|
||||
"Resource/BITMAP/pixel" => (160, 16), // cse2
|
||||
"Resource/CURSOR/CURSOR_IKA" => (32, 32), // cse2
|
||||
"Resource/CURSOR/CURSOR_NORMAL" => (32, 32), // cse2
|
||||
"StageImage" => (256, 16),
|
||||
"Stage/Prt0" => (32, 32),
|
||||
"Stage/PrtAlmond" => (256, 96),
|
||||
|
@ -1164,7 +1196,7 @@ impl EngineConstants {
|
|||
self.tex_sizes.insert(str!("Caret"), (320, 320));
|
||||
self.tex_sizes.insert(str!("MyChar"), (200, 384));
|
||||
self.tex_sizes.insert(str!("Npc/NpcRegu"), (320, 410));
|
||||
self.title.logo_rect = Rect { left: 0, top: 0, right: 214, bottom: 50};
|
||||
self.title.logo_rect = Rect { left: 0, top: 0, right: 214, bottom: 50 };
|
||||
self.font_path = str!("csfont.fnt");
|
||||
self.font_scale = 0.5;
|
||||
self.font_space_offset = 2.0;
|
||||
|
|
|
@ -132,7 +132,7 @@ impl Inventory {
|
|||
if let Some(weapon) = self.get_current_weapon_mut() {
|
||||
let lvl_table = state.constants.weapon.level_table[weapon.wtype as usize];
|
||||
let mut tmp_exp = weapon.experience as isize - exp as isize;
|
||||
|
||||
|
||||
if tmp_exp >= 0 {
|
||||
weapon.experience = tmp_exp as u16;
|
||||
} else {
|
||||
|
@ -141,8 +141,8 @@ impl Inventory {
|
|||
weapon.experience = 0;
|
||||
tmp_exp = 0;
|
||||
} else if weapon.experience < exp {
|
||||
let max_level = lvl_table[weapon.level as usize - 1] as isize;
|
||||
weapon.level = weapon.level.prev();
|
||||
let max_level = lvl_table[weapon.level as usize - 1] as isize;
|
||||
weapon.experience = (max_level + tmp_exp.max(-max_level)) as u16;
|
||||
tmp_exp += max_level;
|
||||
|
||||
|
|
|
@ -59,6 +59,12 @@ impl LiveDebugger {
|
|||
game_scene.player.vel_y as f32 / 512.0,
|
||||
));
|
||||
|
||||
ui.text(format!(
|
||||
"NPC Count: {}/{}",
|
||||
game_scene.npc_map.npcs.len(),
|
||||
game_scene.npc_map.npc_ids.len(),
|
||||
));
|
||||
|
||||
ui.text(format!(
|
||||
"Booster fuel: ({})", game_scene.player.booster_fuel
|
||||
));
|
||||
|
|
|
@ -9,6 +9,113 @@ use crate::player::Player;
|
|||
use crate::shared_game_state::SharedGameState;
|
||||
|
||||
impl NPC {
|
||||
pub(crate) fn tick_n069_pignon(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
let dir_offset = if self.direction == Direction::Left { 0 } else { 6 };
|
||||
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;
|
||||
|
||||
self.anim_rect = state.constants.npc.n069_pignon[self.anim_num as usize + dir_offset];
|
||||
}
|
||||
|
||||
if state.game_rng.range(0..100) == 1 {
|
||||
self.action_num = 2;
|
||||
self.action_counter = 0;
|
||||
self.anim_num = 1;
|
||||
|
||||
self.anim_rect = state.constants.npc.n069_pignon[self.anim_num as usize + dir_offset];
|
||||
}
|
||||
|
||||
|
||||
if state.game_rng.range(0..150) == 1 {
|
||||
self.action_num = 3;
|
||||
self.action_counter = 50;
|
||||
self.anim_num = 0;
|
||||
|
||||
self.anim_rect = state.constants.npc.n069_pignon[self.anim_num as usize + dir_offset];
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
self.action_counter += 1;
|
||||
if self.action_counter > 8 {
|
||||
self.action_num = 1;
|
||||
self.anim_num = 0;
|
||||
|
||||
self.anim_rect = state.constants.npc.n069_pignon[self.anim_num as usize + dir_offset];
|
||||
}
|
||||
}
|
||||
3 | 4 => {
|
||||
if self.action_num == 3 {
|
||||
self.action_num = 4;
|
||||
self.anim_num = 2;
|
||||
self.anim_counter = 0;
|
||||
|
||||
self.anim_rect = state.constants.npc.n069_pignon[self.anim_num as usize + dir_offset];
|
||||
}
|
||||
|
||||
if self.action_counter > 0 {
|
||||
self.action_counter -= 1;
|
||||
} else {
|
||||
self.action_num = 0;
|
||||
}
|
||||
|
||||
self.anim_counter += 1;
|
||||
if self.anim_counter > 2 {
|
||||
self.anim_counter = 0;
|
||||
self.anim_num += 1;
|
||||
if self.anim_num > 4 {
|
||||
self.anim_num = 2;
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n069_pignon[self.anim_num as usize + dir_offset];
|
||||
}
|
||||
|
||||
if self.flags.hit_left_wall() {
|
||||
self.direction = Direction::Right;
|
||||
}
|
||||
|
||||
if self.flags.hit_right_wall() {
|
||||
self.direction = Direction::Left;
|
||||
}
|
||||
|
||||
self.vel_x = match self.direction {
|
||||
Direction::Left => { -0x100 } // -0.5fix9
|
||||
Direction::Right => { 0x100 } // 0.5fix9
|
||||
_ => { 0 }
|
||||
};
|
||||
}
|
||||
5 => {
|
||||
if self.flags.hit_bottom_wall() {
|
||||
self.action_num = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if self.shock > 0 && [1,2,4].contains(&self.action_num) {
|
||||
self.vel_y = -0x200;
|
||||
self.anim_num = 5;
|
||||
self.action_num = 5;
|
||||
|
||||
self.anim_rect = state.constants.npc.n069_pignon[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_n071_chinfish(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
|
|
|
@ -4,6 +4,8 @@ use crate::ggez::GameResult;
|
|||
use crate::npc::{NPC, NPCMap};
|
||||
use crate::player::Player;
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
use crate::stage::Stage;
|
||||
use num_traits::real::Real;
|
||||
|
||||
impl NPC {
|
||||
pub(crate) fn tick_n000_null(&mut self) -> GameResult {
|
||||
|
@ -475,13 +477,75 @@ impl NPC {
|
|||
}
|
||||
|
||||
|
||||
pub(crate) fn tick_n072_sprinkler(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
pub(crate) fn tick_n072_sprinkler(&mut self, state: &mut SharedGameState, player: &Player) -> GameResult {
|
||||
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];
|
||||
|
||||
// todo: spawn water droplets
|
||||
if self.anim_num % 2 == 0 && (player.x - self.x).abs() < 480 * 0x200 {
|
||||
self.action_counter = self.action_counter.wrapping_add(1);
|
||||
|
||||
let mut droplet = NPCMap::create_npc(73, &state.npc_table);
|
||||
droplet.cond.set_alive(true);
|
||||
droplet.direction = Direction::Left;
|
||||
droplet.x = self.x;
|
||||
droplet.y = self.y;
|
||||
droplet.vel_x = 2 * state.game_rng.range(-0x200..0x200) as isize;
|
||||
droplet.vel_y = 3 * state.game_rng.range(-0x200..0x80) as isize;
|
||||
state.new_npcs.push(droplet);
|
||||
|
||||
if self.action_counter % 2 == 0 {
|
||||
droplet.vel_x = 2 * state.game_rng.range(-0x200..0x200) as isize;
|
||||
droplet.vel_y = 3 * state.game_rng.range(-0x200..0x80) as isize;
|
||||
state.new_npcs.push(droplet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n073_water_droplet(&mut self, state: &mut SharedGameState, stage: &Stage) -> GameResult {
|
||||
self.vel_y += 0x20;
|
||||
|
||||
self.anim_rect = state.constants.npc.n073_water_droplet[state.game_rng.range(0..4) as usize];
|
||||
|
||||
if self.vel_y > 0x5ff {
|
||||
self.vel_y = 0x5ff;
|
||||
}
|
||||
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
|
||||
if self.direction == Direction::Right {
|
||||
self.anim_rect.top += 2;
|
||||
self.anim_rect.bottom += 2;
|
||||
}
|
||||
|
||||
self.action_counter += 1;
|
||||
if self.action_counter > 10 && (self.flags.hit_left_wall() || self.flags.hit_right_wall()
|
||||
|| self.flags.hit_bottom_wall() || self.flags.in_water()) {
|
||||
// hit something
|
||||
self.cond.set_alive(false);
|
||||
}
|
||||
|
||||
if self.y > stage.map.height as isize * 16 * 0x200 {
|
||||
// out of map
|
||||
self.cond.set_alive(false);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n076_flowers(&mut self) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
|
||||
self.anim_rect.left = self.event_num as usize * 16;
|
||||
self.anim_rect.top = 0;
|
||||
self.anim_rect.right = self.anim_rect.left + 16;
|
||||
self.anim_rect.bottom = self.anim_rect.top + 16;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -19,6 +19,7 @@ use crate::map::NPCData;
|
|||
use crate::physics::PhysicalEntity;
|
||||
use crate::player::Player;
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
use crate::stage::Stage;
|
||||
use crate::str;
|
||||
|
||||
pub mod characters;
|
||||
|
@ -84,9 +85,11 @@ pub struct NPC {
|
|||
pub anim_rect: Rect<usize>,
|
||||
}
|
||||
|
||||
static PARTICLE_NPCS: [u16; 3] = [1, 4, 73];
|
||||
|
||||
impl NPC {
|
||||
pub fn get_start_index(&self) -> u16 {
|
||||
if self.npc_type == 1 || self.npc_type == 4 {
|
||||
if PARTICLE_NPCS.contains(&self.npc_type) {
|
||||
0x100
|
||||
} else {
|
||||
0
|
||||
|
@ -94,8 +97,8 @@ impl NPC {
|
|||
}
|
||||
}
|
||||
|
||||
impl GameEntity<(&mut Player, &HashMap<u16, RefCell<NPC>>)> for NPC {
|
||||
fn tick(&mut self, state: &mut SharedGameState, (player, map): (&mut Player, &HashMap<u16, RefCell<NPC>>)) -> GameResult {
|
||||
impl GameEntity<(&mut Player, &HashMap<u16, RefCell<NPC>>, &Stage)> for NPC {
|
||||
fn tick(&mut self, state: &mut SharedGameState, (player, map, stage): (&mut Player, &HashMap<u16, RefCell<NPC>>, &Stage)) -> GameResult {
|
||||
match self.npc_type {
|
||||
0 => { self.tick_n000_null() }
|
||||
1 => { self.tick_n001_experience(state) }
|
||||
|
@ -134,11 +137,14 @@ impl GameEntity<(&mut Player, &HashMap<u16, RefCell<NPC>>)> for NPC {
|
|||
65 => { self.tick_n065_first_cave_bat(state, player) }
|
||||
66 => { self.tick_n066_misery_bubble(state, map) }
|
||||
67 => { self.tick_n067_misery_floating(state) }
|
||||
69 => { self.tick_n069_pignon(state) }
|
||||
70 => { self.tick_n070_sparkle(state) }
|
||||
71 => { self.tick_n071_chinfish(state) }
|
||||
72 => { self.tick_n072_sprinkler(state) }
|
||||
72 => { self.tick_n072_sprinkler(state, player) }
|
||||
73 => { self.tick_n073_water_droplet(state, stage) }
|
||||
74 => { self.tick_n074_jack(state) }
|
||||
75 => { self.tick_n075_kanpachi(state, player) }
|
||||
76 => { self.tick_n076_flowers() }
|
||||
77 => { self.tick_n077_yamashita(state) }
|
||||
78 => { self.tick_n078_pot(state) }
|
||||
79 => { self.tick_n079_mahin(state, player) }
|
||||
|
@ -368,6 +374,10 @@ impl NPCMap {
|
|||
}
|
||||
}).collect_vec();
|
||||
|
||||
if !dead_npcs.is_empty() {
|
||||
println!("deleting npcs: {:?}", dead_npcs);
|
||||
}
|
||||
|
||||
for npc_id in dead_npcs.iter() {
|
||||
self.npc_ids.remove(npc_id);
|
||||
self.npcs.remove(npc_id);
|
||||
|
@ -526,6 +536,7 @@ pub struct NPCTableEntry {
|
|||
|
||||
pub struct NPCTable {
|
||||
entries: Vec<NPCTableEntry>,
|
||||
pub tileset_name: String,
|
||||
pub tex_npc1_name: String,
|
||||
pub tex_npc2_name: String,
|
||||
}
|
||||
|
@ -535,6 +546,7 @@ impl NPCTable {
|
|||
pub fn new() -> NPCTable {
|
||||
NPCTable {
|
||||
entries: Vec::new(),
|
||||
tileset_name: str!("Stage/Prt0"),
|
||||
tex_npc1_name: str!("Npc/Npc0"),
|
||||
tex_npc2_name: str!("Npc/Npc0"),
|
||||
}
|
||||
|
@ -646,9 +658,12 @@ 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,
|
||||
17 => "Bullet",
|
||||
19 => "Caret",
|
||||
20 => "Npc/NpcSym",
|
||||
21 => self.tex_npc1_name.as_str(),
|
||||
22 => self.tex_npc2_name.as_str(),
|
||||
21 => &self.tex_npc1_name,
|
||||
22 => &self.tex_npc2_name,
|
||||
23 => "Npc/NpcRegu",
|
||||
_ => "Npc/Npc0"
|
||||
}
|
||||
|
|
|
@ -689,6 +689,7 @@ impl Scene for GameScene {
|
|||
}
|
||||
}
|
||||
|
||||
state.npc_table.tileset_name = self.tex_tileset_name.to_owned();
|
||||
state.npc_table.tex_npc1_name = ["Npc/", &self.stage.data.npc1.filename()].join("");
|
||||
state.npc_table.tex_npc2_name = ["Npc/", &self.stage.data.npc2.filename()].join("");
|
||||
|
||||
|
@ -732,12 +733,12 @@ impl Scene for GameScene {
|
|||
let mut npc = npc_cell.borrow_mut();
|
||||
|
||||
if npc.cond.alive() {
|
||||
npc.tick(state, (&mut self.player, &self.npc_map.npcs))?;
|
||||
npc.tick(state, (&mut self.player, &self.npc_map.npcs, &self.stage))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.npc_map.process_npc_changes(state);
|
||||
self.npc_map.process_npc_changes(state);
|
||||
self.npc_map.garbage_collect();
|
||||
|
||||
self.player.flags.0 = 0;
|
||||
|
||||
|
@ -755,6 +756,7 @@ impl Scene for GameScene {
|
|||
}
|
||||
}
|
||||
self.npc_map.process_npc_changes(state);
|
||||
self.npc_map.garbage_collect();
|
||||
self.tick_npc_bullet_collissions(state);
|
||||
|
||||
state.tick_carets();
|
||||
|
|
|
@ -12,7 +12,6 @@ use itertools::Itertools;
|
|||
use num_derive::FromPrimitive;
|
||||
use num_traits::{clamp, FromPrimitive};
|
||||
|
||||
use crate::str;
|
||||
use crate::bitfield;
|
||||
use crate::common::{Direction, FadeDirection, FadeState};
|
||||
use crate::encoding::{read_cur_shift_jis, read_cur_wtf8};
|
||||
|
@ -23,6 +22,7 @@ use crate::player::ControlMode;
|
|||
use crate::scene::game_scene::GameScene;
|
||||
use crate::scene::title_scene::TitleScene;
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
use crate::str;
|
||||
use crate::weapon::WeaponType;
|
||||
|
||||
/// Engine's text script VM operation codes.
|
||||
|
@ -1112,7 +1112,7 @@ impl TextScriptVM {
|
|||
|
||||
if tick_npc != 0 {
|
||||
if let Some(npc) = game_scene.npc_map.npcs.get(&tick_npc) {
|
||||
npc.borrow_mut().tick(state, (&mut game_scene.player, &game_scene.npc_map.npcs))?;
|
||||
npc.borrow_mut().tick(state, (&mut game_scene.player, &game_scene.npc_map.npcs, &game_scene.stage))?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue