mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2025-03-24 19:09:22 +00:00
add heart and missile pickups
This commit is contained in:
parent
771516f7e4
commit
f7e7a8563e
|
@ -9,7 +9,7 @@ use itertools::Itertools;
|
|||
|
||||
use crate::bitfield;
|
||||
use crate::caret::CaretType;
|
||||
use crate::common::{Condition, Rect, fix9_scale};
|
||||
use crate::common::{Condition, fix9_scale, Rect};
|
||||
use crate::common::Direction;
|
||||
use crate::common::Flag;
|
||||
use crate::entity::GameEntity;
|
||||
|
@ -95,7 +95,7 @@ pub struct NPC {
|
|||
pub anim_rect: Rect<usize>,
|
||||
}
|
||||
|
||||
static PARTICLE_NPCS: [u16; 6] = [1, 4, 73, 129, 199, 355];
|
||||
static PARTICLE_NPCS: [u16; 8] = [1, 4, 73, 86, 87, 129, 199, 355];
|
||||
|
||||
impl NPC {
|
||||
pub fn get_start_index(&self) -> u16 {
|
||||
|
@ -206,6 +206,8 @@ impl GameEntity<(&mut Player, &HashMap<u16, RefCell<NPC>>, &mut Stage)> for NPC
|
|||
83 => self.tick_n083_igor_cutscene(state),
|
||||
84 => self.tick_n084_basu_projectile(state),
|
||||
85 => self.tick_n085_terminal(state, player),
|
||||
86 => self.tick_n086_missile_pickup(state),
|
||||
87 => self.tick_n087_heart_pickup(state),
|
||||
91 => self.tick_n091_mimiga_cage(state),
|
||||
96 => self.tick_n096_fan_left(state, player),
|
||||
97 => self.tick_n097_fan_up(state, player),
|
||||
|
@ -490,7 +492,7 @@ impl NPCMap {
|
|||
state.create_caret(x, y, CaretType::Explosion, Direction::Left);
|
||||
}
|
||||
|
||||
pub fn process_dead_npcs(&mut self, list: &[u16], state: &mut SharedGameState) {
|
||||
pub fn process_dead_npcs(&mut self, list: &[u16], has_missile: bool, state: &mut SharedGameState) {
|
||||
for id in list {
|
||||
if let Some(npc_cell) = self.npcs.get(id) {
|
||||
let mut npc = npc_cell.borrow_mut();
|
||||
|
@ -507,34 +509,54 @@ impl NPCMap {
|
|||
};
|
||||
|
||||
if npc.exp != 0 {
|
||||
//if state.game_rng.range(0..4) == 0 {
|
||||
// health
|
||||
let rng = state.game_rng.range(0..4);
|
||||
match rng {
|
||||
0 => {
|
||||
let mut heart_pick = NPCMap::create_npc(87, &state.npc_table);
|
||||
heart_pick.cond.set_alive(true);
|
||||
heart_pick.direction = Direction::Left;
|
||||
heart_pick.x = npc.x;
|
||||
heart_pick.y = npc.y;
|
||||
heart_pick.exp = if npc.exp > 6 { 6 } else { 2 };
|
||||
|
||||
//} else {
|
||||
let mut exp = npc.exp;
|
||||
state.new_npcs.push(heart_pick);
|
||||
}
|
||||
1 if has_missile => {
|
||||
let mut missile_pick = NPCMap::create_npc(86, &state.npc_table);
|
||||
missile_pick.cond.set_alive(true);
|
||||
missile_pick.direction = Direction::Left;
|
||||
missile_pick.x = npc.x;
|
||||
missile_pick.y = npc.y;
|
||||
missile_pick.exp = if npc.exp > 6 { 3 } else { 1 };
|
||||
|
||||
while exp > 0 {
|
||||
let exp_piece = if exp >= 20 {
|
||||
exp -= 20;
|
||||
20
|
||||
} else if exp >= 5 {
|
||||
exp -= 5;
|
||||
5
|
||||
} else {
|
||||
exp -= 1;
|
||||
1
|
||||
};
|
||||
state.new_npcs.push(missile_pick);
|
||||
}
|
||||
_ => {
|
||||
let mut exp = npc.exp;
|
||||
|
||||
let mut xp_npc = NPCMap::create_npc(1, &state.npc_table);
|
||||
xp_npc.cond.set_alive(true);
|
||||
xp_npc.direction = Direction::Left;
|
||||
xp_npc.x = npc.x;
|
||||
xp_npc.y = npc.y;
|
||||
xp_npc.exp = exp_piece;
|
||||
while exp > 0 {
|
||||
let exp_piece = if exp >= 20 {
|
||||
exp -= 20;
|
||||
20
|
||||
} else if exp >= 5 {
|
||||
exp -= 5;
|
||||
5
|
||||
} else {
|
||||
exp -= 1;
|
||||
1
|
||||
};
|
||||
|
||||
state.new_npcs.push(xp_npc);
|
||||
let mut xp_npc = NPCMap::create_npc(1, &state.npc_table);
|
||||
xp_npc.cond.set_alive(true);
|
||||
xp_npc.direction = Direction::Left;
|
||||
xp_npc.x = npc.x;
|
||||
xp_npc.y = npc.y;
|
||||
xp_npc.exp = exp_piece;
|
||||
|
||||
state.new_npcs.push(xp_npc);
|
||||
}
|
||||
}
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
||||
state.game_flags.set(npc.flag_num as usize, true);
|
||||
|
|
|
@ -145,6 +145,138 @@ impl NPC {
|
|||
}
|
||||
|
||||
pub(crate) fn tick_n086_missile_pickup(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.direction == Direction::Left {
|
||||
self.anim_counter += 1;
|
||||
if self.anim_counter > 2 {
|
||||
self.anim_counter = 0;
|
||||
self.anim_num += 1;
|
||||
if self.anim_num > 1 {
|
||||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
|
||||
self.action_counter2 += 1;
|
||||
}
|
||||
|
||||
if state.control_flags.wind() {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
self.vel_x = state.game_rng.range(0x7f..0x100) as isize;
|
||||
self.vel_y = state.game_rng.range(-0x20..0x20) as isize;
|
||||
}
|
||||
|
||||
self.vel_x -= 0x08;
|
||||
if self.x < 80 * 0x200 {
|
||||
self.cond.set_alive(false)
|
||||
}
|
||||
|
||||
if self.flags.hit_left_wall() {
|
||||
self.vel_x = 0x100;
|
||||
}
|
||||
|
||||
if self.flags.hit_top_wall() {
|
||||
self.vel_y = 0x40;
|
||||
}
|
||||
|
||||
if self.flags.hit_bottom_wall() {
|
||||
self.vel_y = -0x40;
|
||||
}
|
||||
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
}
|
||||
|
||||
match self.exp {
|
||||
1 => {
|
||||
self.anim_rect = state.constants.npc.n086_missile_pickup[self.anim_num as usize];
|
||||
}
|
||||
3 => {
|
||||
self.anim_rect = state.constants.npc.n086_missile_pickup[2 + self.anim_num as usize];
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if self.action_counter2 > 550 {
|
||||
self.cond.set_alive(false);
|
||||
}
|
||||
|
||||
if self.action_counter2 > 500 && self.action_counter2 / 2 % 2 != 0 {
|
||||
self.anim_rect.right = self.anim_rect.left;
|
||||
self.anim_rect.bottom = self.anim_rect.top;
|
||||
}
|
||||
|
||||
if self.action_counter2 > 547 {
|
||||
self.anim_rect = state.constants.npc.n086_missile_pickup[4];
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n087_heart_pickup(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.direction == Direction::Left {
|
||||
self.anim_counter += 1;
|
||||
if self.anim_counter > 2 {
|
||||
self.anim_counter = 0;
|
||||
self.anim_num += 1;
|
||||
if self.anim_num > 1 {
|
||||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
|
||||
self.action_counter2 += 1;
|
||||
}
|
||||
|
||||
if state.control_flags.wind() {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
self.vel_x = state.game_rng.range(0x7f..0x100) as isize;
|
||||
self.vel_y = state.game_rng.range(-0x20..0x20) as isize;
|
||||
}
|
||||
|
||||
self.vel_x -= 0x08;
|
||||
if self.x < 80 * 0x200 {
|
||||
self.cond.set_alive(false)
|
||||
}
|
||||
|
||||
if self.flags.hit_left_wall() {
|
||||
self.vel_x = 0x100;
|
||||
}
|
||||
|
||||
if self.flags.hit_top_wall() {
|
||||
self.vel_y = 0x40;
|
||||
}
|
||||
|
||||
if self.flags.hit_bottom_wall() {
|
||||
self.vel_y = -0x40;
|
||||
}
|
||||
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
}
|
||||
|
||||
match self.exp {
|
||||
2 => {
|
||||
self.anim_rect = state.constants.npc.n087_heart_pickup[self.anim_num as usize];
|
||||
}
|
||||
6 => {
|
||||
self.anim_rect = state.constants.npc.n087_heart_pickup[2 + self.anim_num as usize];
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if self.action_counter2 > 550 {
|
||||
self.cond.set_alive(false);
|
||||
}
|
||||
|
||||
if self.action_counter2 > 500 && self.action_counter2 / 2 % 2 != 0 {
|
||||
self.anim_rect.right = self.anim_rect.left;
|
||||
self.anim_rect.bottom = self.anim_rect.top;
|
||||
}
|
||||
|
||||
if self.action_counter2 > 547 {
|
||||
self.anim_rect = state.constants.npc.n087_heart_pickup[4];
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -241,22 +241,41 @@ impl Player {
|
|||
flags = self.judge_hit_npc_non_solid(npc.borrow());
|
||||
}
|
||||
|
||||
// xp pickup
|
||||
if flags.0 != 0 && npc.npc_type == 1 {
|
||||
state.sound_manager.play_sfx(14);
|
||||
match inventory.add_xp(npc.exp, state) {
|
||||
AddExperienceResult::None => {}
|
||||
AddExperienceResult::LevelUp => {
|
||||
state.sound_manager.play_sfx(27);
|
||||
state.create_caret(self.x, self.y, CaretType::LevelUp, Direction::Left);
|
||||
}
|
||||
AddExperienceResult::AddStar => {
|
||||
if self.equip.has_whimsical_star() && self.stars < 3 {
|
||||
self.stars += 1;
|
||||
if flags.0 != 0 {
|
||||
match npc.npc_type {
|
||||
// experience pickup
|
||||
1 => {
|
||||
state.sound_manager.play_sfx(14);
|
||||
match inventory.add_xp(npc.exp, state) {
|
||||
AddExperienceResult::None => {}
|
||||
AddExperienceResult::LevelUp => {
|
||||
state.sound_manager.play_sfx(27);
|
||||
state.create_caret(self.x, self.y, CaretType::LevelUp, Direction::Left);
|
||||
}
|
||||
AddExperienceResult::AddStar => {
|
||||
if self.equip.has_whimsical_star() && self.stars < 3 {
|
||||
self.stars += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
npc.cond.set_alive(false);
|
||||
}
|
||||
// missile pickup
|
||||
86 => {
|
||||
// todo add bullets
|
||||
npc.cond.set_alive(false);
|
||||
|
||||
state.sound_manager.play_sfx(42);
|
||||
}
|
||||
// heart pickup
|
||||
87 => {
|
||||
self.life = self.max_life.min(self.life.saturating_add(npc.exp));
|
||||
npc.cond.set_alive(false);
|
||||
|
||||
state.sound_manager.play_sfx(20);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
npc.cond.set_alive(false);
|
||||
}
|
||||
|
||||
if npc.npc_flags.interactable() && !state.control_flags.interactions_disabled() && flags.0 != 0 && self.cond.interacted() {
|
||||
|
|
|
@ -21,6 +21,7 @@ use crate::stage::{BackgroundType, Stage};
|
|||
use crate::text_script::{ConfirmSelection, ScriptMode, TextScriptExecutionState, TextScriptVM};
|
||||
use crate::texture_set::SizedBatch;
|
||||
use crate::ui::Components;
|
||||
use crate::weapon::WeaponType;
|
||||
|
||||
pub struct GameScene {
|
||||
pub tick: usize,
|
||||
|
@ -619,13 +620,10 @@ impl GameScene {
|
|||
self.draw_light(fix9_scale(npc.x - self.frame.x, scale),
|
||||
fix9_scale(npc.y - self.frame.y, scale),
|
||||
3.0, (0, 0, 255), batch),
|
||||
32 | 211 => {
|
||||
32 | 87 | 211 => {
|
||||
self.draw_light(fix9_scale(npc.x - self.frame.x, scale),
|
||||
fix9_scale(npc.y - self.frame.y, scale),
|
||||
3.0, (255, 0, 0), batch);
|
||||
self.draw_light(fix9_scale(npc.x - self.frame.x, scale),
|
||||
fix9_scale(npc.y - self.frame.y, scale),
|
||||
2.0, (255, 0, 0), batch);
|
||||
2.0, (255, 30, 30), batch);
|
||||
}
|
||||
38 => {
|
||||
let flicker = (npc.anim_num ^ 5 & 3) as u8 * 15;
|
||||
|
@ -834,7 +832,9 @@ impl GameScene {
|
|||
}
|
||||
|
||||
if !dead_npcs.is_empty() {
|
||||
self.npc_map.process_dead_npcs(&dead_npcs, state);
|
||||
let missile = self.inventory.has_weapon(WeaponType::MissileLauncher)
|
||||
| self.inventory.has_weapon(WeaponType::SuperMissileLauncher);
|
||||
self.npc_map.process_dead_npcs(&dead_npcs, missile, state);
|
||||
self.npc_map.garbage_collect();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue