1
0
Fork 0
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:
Alula 2020-10-30 11:24:55 +01:00
parent 771516f7e4
commit f7e7a8563e
No known key found for this signature in database
GPG key ID: 3E00485503A1D8BA
4 changed files with 218 additions and 45 deletions

View file

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

View file

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

View file

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

View file

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