mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2024-11-25 07:02:58 +00:00
add Monster X and some tweaks
This commit is contained in:
parent
ff0046abbd
commit
091892b339
11
README.md
11
README.md
|
@ -61,14 +61,19 @@ Because methods used to extract game data from cartridge vary, you have to find
|
|||
- [x] PixTone SFX
|
||||
- [ ] NPCs/entities
|
||||
- [x] Initial implementation
|
||||
- [ ] Miscellaneous entities (~30% done)
|
||||
- [ ] Bosses (~20% done)
|
||||
- [ ] Miscellaneous entities (~40% done)
|
||||
- [ ] Bosses (~30% done)
|
||||
- [x] Omega
|
||||
- [x] Balfrog
|
||||
- [x] Monster X
|
||||
- [x] First Cave
|
||||
- [x] Mimiga Village
|
||||
- [x] Egg Corridor
|
||||
- [x] Grasstown
|
||||
- [ ] Sand Zone (~30% done)
|
||||
- [ ] Sand Zone (~50% done)
|
||||
- [ ] Labirynth (~10% done)
|
||||
- [x] Waterway
|
||||
- [ ] Egg Corridor? (~20% done)
|
||||
- [ ] Outer Wall
|
||||
- [ ] Plantation
|
||||
- [ ] Last Cave
|
||||
|
|
|
@ -43,8 +43,8 @@ impl BulletManager {
|
|||
self.bullets.iter().filter(|b| b.owner == player_id && b.btype == btype).count()
|
||||
}
|
||||
|
||||
pub fn count_bullets_all(&self, btype: u16) -> usize {
|
||||
self.bullets.iter().filter(|b| b.btype == btype).count()
|
||||
pub fn count_bullets_type_idx_all(&self, type_idx: u16) -> usize {
|
||||
self.bullets.iter().filter(|b| (b.btype.saturating_sub(2) / 3) == type_idx).count()
|
||||
}
|
||||
|
||||
pub fn count_bullets_multi(&self, btypes: [u16; 3], player_id: TargetPlayer) -> usize {
|
||||
|
|
16
src/caret.rs
16
src/caret.rs
|
@ -1,7 +1,7 @@
|
|||
use std::fs::read_to_string;
|
||||
|
||||
use crate::bitfield;
|
||||
use crate::common::{Condition, Direction, Rect, CDEG_RAD};
|
||||
use crate::common::{CDEG_RAD, Condition, Direction, Rect};
|
||||
use crate::engine_constants::EngineConstants;
|
||||
use crate::rng::RNG;
|
||||
|
||||
|
@ -173,11 +173,11 @@ impl Caret {
|
|||
}
|
||||
|
||||
match self.direction {
|
||||
Direction::Left => self.x -= 0x400, // 2.0fix9
|
||||
Direction::Up => self.y -= 0x400,
|
||||
Direction::Right => self.x += 0x400,
|
||||
Direction::Bottom => self.y += 0x400,
|
||||
Direction::FacingPlayer => unreachable!(),
|
||||
Direction::Left => self.x -= 0x400, // 2.0fix9
|
||||
Direction::Up => self.y -= 0x400,
|
||||
Direction::Right => self.x += 0x400,
|
||||
Direction::Bottom => self.y += 0x400,
|
||||
Direction::FacingPlayer => {},
|
||||
}
|
||||
}
|
||||
CaretType::DrownedQuote => {
|
||||
|
@ -185,8 +185,8 @@ impl Caret {
|
|||
self.anim_counter = 1;
|
||||
|
||||
match self.direction {
|
||||
Direction::Left => self.anim_rect = constants.caret.drowned_quote_left_rect,
|
||||
Direction::Right => self.anim_rect = constants.caret.drowned_quote_right_rect,
|
||||
Direction::Left => self.anim_rect = constants.caret.drowned_quote_left_rect,
|
||||
Direction::Right => self.anim_rect = constants.caret.drowned_quote_right_rect,
|
||||
Direction::FacingPlayer => unreachable!(),
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
@ -1071,6 +1071,8 @@ pub struct NPCConsts {
|
|||
#[serde(default = "default_b02_balfrog")]
|
||||
pub b02_balfrog: [Rect<u16>; 18],
|
||||
|
||||
#[serde(default = "default_b03_monster_x")]
|
||||
pub b03_monster_x: [Rect<u16>; 29],
|
||||
}
|
||||
|
||||
fn default_n001_experience() -> [Rect<u16>; 6] {
|
||||
|
@ -4788,3 +4790,37 @@ fn default_b02_balfrog() -> [Rect<u16>; 18] {
|
|||
Rect { left: 120, top: 24, right: 160, bottom: 48 },
|
||||
]
|
||||
}
|
||||
|
||||
fn default_b03_monster_x() -> [Rect<u16>; 29] {
|
||||
[
|
||||
Rect { left: 216, top: 0, right: 320, bottom: 48 }, // face
|
||||
Rect { left: 216, top: 48, right: 320, bottom: 96 },
|
||||
Rect { left: 216, top: 144, right: 320, bottom: 192 },
|
||||
Rect { left: 0, top: 0, right: 72, bottom: 32 }, // tracks up
|
||||
Rect { left: 0, top: 32, right: 72, bottom: 64 },
|
||||
Rect { left: 72, top: 0, right: 144, bottom: 32 },
|
||||
Rect { left: 144, top: 0, right: 216, bottom: 32 },
|
||||
Rect { left: 72, top: 32, right: 144, bottom: 64 },
|
||||
Rect { left: 144, top: 32, right: 216, bottom: 64 },
|
||||
Rect { left: 0, top: 64, right: 72, bottom: 96 }, // tracks down
|
||||
Rect { left: 0, top: 96, right: 72, bottom: 128 },
|
||||
Rect { left: 72, top: 64, right: 144, bottom: 96 },
|
||||
Rect { left: 144, top: 64, right: 216, bottom: 96 },
|
||||
Rect { left: 72, top: 96, right: 144, bottom: 128 },
|
||||
Rect { left: 144, top: 96, right: 216, bottom: 128 },
|
||||
Rect { left: 0, top: 128, right: 72, bottom: 160 }, // frame
|
||||
Rect { left: 72, top: 128, right: 144, bottom: 160 },
|
||||
Rect { left: 0, top: 160, right: 72, bottom: 192 },
|
||||
Rect { left: 72, top: 160, right: 144, bottom: 192 },
|
||||
Rect { left: 216, top: 96, right: 264, bottom: 144 }, // shield left
|
||||
Rect { left: 264, top: 96, right: 312, bottom: 144 }, // shield right
|
||||
Rect { left: 0, top: 192, right: 16, bottom: 208 }, // part 4
|
||||
Rect { left: 16, top: 192, right: 32, bottom: 208 },
|
||||
Rect { left: 32, top: 192, right: 48, bottom: 208 },
|
||||
Rect { left: 48, top: 192, right: 64, bottom: 208 },
|
||||
Rect { left: 0, top: 208, right: 16, bottom: 224 },
|
||||
Rect { left: 16, top: 208, right: 32, bottom: 224 },
|
||||
Rect { left: 32, top: 208, right: 48, bottom: 224 },
|
||||
Rect { left: 48, top: 208, right: 64, bottom: 224 },
|
||||
]
|
||||
}
|
||||
|
|
|
@ -115,7 +115,7 @@ impl Game {
|
|||
}
|
||||
|
||||
if self.loops != 0 {
|
||||
scene.draw_tick(&mut self.state, ctx)?;
|
||||
scene.draw_tick(&mut self.state)?;
|
||||
self.last_tick = last_tick;
|
||||
}
|
||||
|
||||
|
|
|
@ -242,7 +242,6 @@ impl BossNPC {
|
|||
|
||||
let deg = f64::atan2(py as f64, px as f64)
|
||||
+ self.parts[0].rng.range(-16..16) as f64 * CDEG_RAD;
|
||||
// todo rand
|
||||
|
||||
let mut npc = NPCMap::create_npc(108, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
|
|
|
@ -24,9 +24,9 @@ pub mod undead_core;
|
|||
|
||||
pub struct BossNPC {
|
||||
pub boss_type: u16,
|
||||
pub parts: [NPC; 16],
|
||||
pub hurt_sound: [u8; 16],
|
||||
pub death_sound: [u8; 16],
|
||||
pub parts: [NPC; 20],
|
||||
pub hurt_sound: [u8; 20],
|
||||
pub death_sound: [u8; 20],
|
||||
}
|
||||
|
||||
impl BossNPC {
|
||||
|
@ -35,7 +35,7 @@ impl BossNPC {
|
|||
let mut part = NPC::empty();
|
||||
part.cond.set_drs_boss(true);
|
||||
part
|
||||
}; 16];
|
||||
}; 20];
|
||||
parts[0].cond.set_alive(true);
|
||||
for (i, part) in parts.iter_mut().enumerate() {
|
||||
part.rng.load_state((i
|
||||
|
@ -48,8 +48,8 @@ impl BossNPC {
|
|||
BossNPC {
|
||||
boss_type: 0,
|
||||
parts,
|
||||
hurt_sound: [0; 16],
|
||||
death_sound: [0; 16],
|
||||
hurt_sound: [0; 20],
|
||||
death_sound: [0; 20],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ impl GameEntity<([&mut Player; 2], &BTreeMap<u16, RefCell<NPC>>, &mut Stage, &Bu
|
|||
match self.boss_type {
|
||||
1 => self.tick_b01_omega(state, players, map, bullet_manager),
|
||||
2 => self.tick_b02_balfrog(state, players),
|
||||
3 => self.tick_b03_monster_x(),
|
||||
3 => self.tick_b03_monster_x(state, players, map),
|
||||
4 => self.tick_b04_core(),
|
||||
5 => self.tick_b05_ironhead(),
|
||||
6 => self.tick_b06_twins(),
|
||||
|
@ -83,7 +83,7 @@ impl GameEntity<([&mut Player; 2], &BTreeMap<u16, RefCell<NPC>>, &mut Stage, &Bu
|
|||
fn draw(&self, state: &mut SharedGameState, ctx: &mut Context, frame: &Frame) -> GameResult {
|
||||
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, state.npc_table.tex_npc2_name.as_str())?;
|
||||
|
||||
for npc in self.parts.iter() {
|
||||
for npc in self.parts.iter().rev() {
|
||||
if !npc.cond.alive() || npc.cond.hidden() {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,840 @@
|
|||
use std::cell::RefCell;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use ggez::GameResult;
|
||||
use num_traits::{abs, clamp};
|
||||
|
||||
use crate::caret::CaretType;
|
||||
use crate::common::{CDEG_RAD, Direction, Rect};
|
||||
use crate::npc::{NPC, NPCMap};
|
||||
use crate::npc::boss::BossNPC;
|
||||
use crate::player::Player;
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
|
||||
impl BossNPC {
|
||||
pub(crate) fn tick_b03_monster_x(&mut self) {
|
||||
impl NPC {
|
||||
pub(crate) fn tick_n158_fish_missile(&mut self, state: &mut SharedGameState, players: [&mut Player; 2]) -> GameResult {
|
||||
match self.action_num {
|
||||
0 | 1 => {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
|
||||
self.action_counter2 = match self.direction {
|
||||
Direction::Left => 0xa0,
|
||||
Direction::Up => 0xe0,
|
||||
Direction::Right => 0x20,
|
||||
Direction::Bottom => 0x60,
|
||||
Direction::FacingPlayer => 0,
|
||||
};
|
||||
}
|
||||
|
||||
let radians = self.action_counter2 as f64 * CDEG_RAD;
|
||||
self.vel_x = 2 * (radians.cos() * 512.0) as isize;
|
||||
self.vel_y = 2 * (radians.sin() * 512.0) as isize;
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
|
||||
let player = self.get_closest_player_mut(players);
|
||||
let direction = f64::atan2(-(self.y - player.y) as f64, -(self.x - player.x) as f64);
|
||||
|
||||
if direction < radians {
|
||||
if radians - direction < std::f64::consts::PI {
|
||||
self.action_counter2 = self.action_counter2.wrapping_sub(1) & 0xff;
|
||||
} else {
|
||||
self.action_counter2 = (self.action_counter2 + 1) & 0xff;
|
||||
}
|
||||
} else {
|
||||
if direction - radians < std::f64::consts::PI {
|
||||
self.action_counter2 = (self.action_counter2 + 1) & 0xff;
|
||||
} else {
|
||||
self.action_counter2 = self.action_counter2.wrapping_sub(1) & 0xff;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.anim_counter += 1;
|
||||
if self.anim_counter > 2 {
|
||||
self.anim_counter = 0;
|
||||
state.create_caret(self.x, self.y, CaretType::Exhaust, Direction::FacingPlayer);
|
||||
}
|
||||
|
||||
self.anim_num = (self.action_counter2 + 0x10) / 0x20;
|
||||
|
||||
if self.anim_num > 7 {
|
||||
self.anim_num = 7;
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.npc.n158_fish_missile[self.anim_num as usize];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl BossNPC {
|
||||
pub(crate) fn tick_b03_monster_x(&mut self, state: &mut SharedGameState, players: [&mut Player; 2], npc_map: &BTreeMap<u16, RefCell<NPC>>) {
|
||||
match self.parts[0].action_num {
|
||||
0 => {
|
||||
self.parts[0].life = 1;
|
||||
self.parts[0].x = -320 * 0x200;
|
||||
}
|
||||
1 => {
|
||||
self.parts[0].life = 700;
|
||||
self.parts[0].exp = 1;
|
||||
self.parts[0].action_num = 2;
|
||||
self.parts[0].anim_num = 0;
|
||||
self.parts[0].x = 2048 * 0x200;
|
||||
self.parts[0].y = 200 * 0x200;
|
||||
self.parts[0].size = 3;
|
||||
self.parts[0].event_num = 1000;
|
||||
self.parts[0].hit_bounds = Rect {
|
||||
left: 24 * 0x200,
|
||||
top: 24 * 0x200,
|
||||
right: 24 * 0x200,
|
||||
bottom: 24 * 0x200,
|
||||
};
|
||||
self.parts[0].npc_flags.set_ignore_solidity(true);
|
||||
self.parts[0].npc_flags.set_event_when_killed(true);
|
||||
self.parts[0].npc_flags.set_show_damage(true);
|
||||
self.hurt_sound[0] = 54;
|
||||
|
||||
self.parts[1].cond.set_alive(true);
|
||||
self.parts[1].size = 3;
|
||||
self.parts[1].direction = Direction::Left;
|
||||
self.parts[1].display_bounds = Rect {
|
||||
left: 24 * 0x200,
|
||||
top: 24 * 0x200,
|
||||
right: 24 * 0x200,
|
||||
bottom: 24 * 0x200,
|
||||
};
|
||||
self.parts[1].npc_flags.set_ignore_solidity(true);
|
||||
|
||||
self.parts[2] = self.parts[1];
|
||||
self.parts[2].direction = Direction::Right;
|
||||
|
||||
self.parts[3].cond.set_alive(true);
|
||||
self.parts[3].life = 60;
|
||||
self.parts[3].size = 2;
|
||||
self.parts[3].target_x = 0;
|
||||
self.parts[3].display_bounds = Rect {
|
||||
left: 8 * 0x200,
|
||||
top: 8 * 0x200,
|
||||
right: 8 * 0x200,
|
||||
bottom: 8 * 0x200,
|
||||
};
|
||||
self.parts[3].hit_bounds = Rect {
|
||||
left: 5 * 0x200,
|
||||
top: 5 * 0x200,
|
||||
right: 5 * 0x200,
|
||||
bottom: 5 * 0x200,
|
||||
};
|
||||
self.parts[3].npc_flags.set_ignore_solidity(true);
|
||||
self.hurt_sound[3] = 54;
|
||||
self.death_sound[3] = 71;
|
||||
|
||||
self.parts[4] = self.parts[3];
|
||||
self.parts[3].target_x = 1;
|
||||
|
||||
self.parts[5] = self.parts[3];
|
||||
self.parts[6] = self.parts[3];
|
||||
self.parts[5].target_x = 2;
|
||||
self.parts[6].target_x = 3;
|
||||
self.parts[5].life = 100;
|
||||
self.parts[6].life = 100;
|
||||
|
||||
self.parts[7].cond.set_alive(true);
|
||||
self.parts[7].x = self.parts[0].x;
|
||||
self.parts[7].y = self.parts[0].y;
|
||||
self.parts[7].size = 3;
|
||||
self.parts[7].anim_num = 0;
|
||||
self.parts[7].display_bounds = Rect {
|
||||
left: 52 * 0x200,
|
||||
top: 24 * 0x200,
|
||||
right: 52 * 0x200,
|
||||
bottom: 24 * 0x200,
|
||||
};
|
||||
self.parts[7].hit_bounds = Rect {
|
||||
left: 8 * 0x200,
|
||||
top: 24 * 0x200,
|
||||
right: 8 * 0x200,
|
||||
bottom: 16 * 0x200,
|
||||
};
|
||||
self.parts[7].npc_flags.set_ignore_solidity(true);
|
||||
|
||||
self.parts[9].cond.set_alive(true);
|
||||
self.parts[9].x = self.parts[0].x - 64 * 0x200;
|
||||
self.parts[9].y = self.parts[0].y - 56 * 0x200;
|
||||
self.parts[9].size = 3;
|
||||
self.parts[9].action_num = 0;
|
||||
self.parts[9].direction = Direction::Up;
|
||||
self.parts[9].display_bounds = Rect {
|
||||
left: 36 * 0x200,
|
||||
top: 8 * 0x200,
|
||||
right: 36 * 0x200,
|
||||
bottom: 24 * 0x200,
|
||||
};
|
||||
self.parts[9].hit_bounds = Rect {
|
||||
left: 28 * 0x200,
|
||||
top: 8 * 0x200,
|
||||
right: 28 * 0x200,
|
||||
bottom: 16 * 0x200,
|
||||
};
|
||||
self.hurt_sound[9] = 52;
|
||||
self.parts[9].npc_flags.set_rear_and_top_not_hurt(true);
|
||||
self.parts[9].npc_flags.set_ignore_solidity(true);
|
||||
self.parts[9].npc_flags.set_invulnerable(true);
|
||||
self.parts[9].npc_flags.set_solid_soft(true);
|
||||
|
||||
self.parts[10] = self.parts[9];
|
||||
self.parts[10].x = self.parts[0].x + 64 * 0x200;
|
||||
|
||||
self.parts[11] = self.parts[9];
|
||||
self.parts[11].x = self.parts[0].x - 64 * 0x200;
|
||||
self.parts[11].y = self.parts[0].y + 56 * 0x200;
|
||||
self.parts[11].direction = Direction::Bottom;
|
||||
self.parts[11].display_bounds.top = 24 * 0x200;
|
||||
self.parts[11].display_bounds.bottom = 8 * 0x200;
|
||||
self.parts[11].hit_bounds.top = 16 * 0x200;
|
||||
self.parts[11].hit_bounds.bottom = 8 * 0x200;
|
||||
|
||||
self.parts[12] = self.parts[11];
|
||||
self.parts[12].x = self.parts[0].x + 64 * 0x200;
|
||||
|
||||
self.parts[13] = self.parts[9];
|
||||
self.parts[13].display_bounds = Rect {
|
||||
left: 30 * 0x200,
|
||||
top: 16 * 0x200,
|
||||
right: 42 * 0x200,
|
||||
bottom: 16 * 0x200,
|
||||
};
|
||||
self.parts[13].action_counter2 = 9;
|
||||
self.parts[13].anim_num = 0;
|
||||
self.parts[13].npc_flags.0 = 0;
|
||||
self.parts[13].npc_flags.set_ignore_solidity(true);
|
||||
|
||||
self.parts[14] = self.parts[13];
|
||||
self.parts[14].action_counter2 = 10;
|
||||
self.parts[14].anim_num = 1;
|
||||
self.parts[14].display_bounds.left = 42 * 0x200;
|
||||
self.parts[14].display_bounds.right = 30 * 0x200;
|
||||
|
||||
self.parts[15] = self.parts[13];
|
||||
self.parts[15].action_counter2 = 11;
|
||||
self.parts[15].anim_num = 2;
|
||||
self.parts[15].display_bounds.top = 16 * 0x200;
|
||||
self.parts[15].display_bounds.bottom = 16 * 0x200;
|
||||
|
||||
self.parts[16] = self.parts[15];
|
||||
self.parts[16].action_counter2 = 12;
|
||||
self.parts[16].anim_num = 3;
|
||||
self.parts[16].display_bounds.left = 42 * 0x200;
|
||||
self.parts[16].display_bounds.right = 30 * 0x200;
|
||||
}
|
||||
10 | 11 => {
|
||||
if self.parts[0].action_num == 10 {
|
||||
self.parts[0].action_num = 11;
|
||||
self.parts[0].action_counter = 0;
|
||||
self.parts[0].action_counter2 = 0;
|
||||
}
|
||||
|
||||
self.parts[0].action_counter += 1;
|
||||
if self.parts[0].action_counter > 100 {
|
||||
self.parts[0].action_counter = 0;
|
||||
|
||||
let player_idx = self.parts[0].get_closest_player_idx_mut(&players);
|
||||
self.parts[0].action_num = if self.parts[0].x > players[player_idx].x { 100 } else { 200 };
|
||||
}
|
||||
}
|
||||
100 | 101 => {
|
||||
if self.parts[0].action_num == 100 {
|
||||
self.parts[0].action_num = 101;
|
||||
self.parts[0].action_counter = 0;
|
||||
self.parts[0].action_counter2 += 1;
|
||||
}
|
||||
|
||||
self.parts[0].action_counter += 1;
|
||||
|
||||
match self.parts[0].action_counter {
|
||||
4 => self.parts[9].action_num = 100,
|
||||
8 => self.parts[10].action_num = 100,
|
||||
10 => self.parts[11].action_num = 100,
|
||||
12 => self.parts[12].action_num = 100,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if self.parts[0].action_counter > 120 && self.parts[0].action_counter2 > 2 {
|
||||
self.parts[0].action_num = 300;
|
||||
}
|
||||
|
||||
let player_idx = self.parts[0].get_closest_player_idx_mut(&players);
|
||||
if self.parts[0].action_counter > 121 && players[player_idx].x > self.parts[0].x {
|
||||
self.parts[0].action_num = 200;
|
||||
}
|
||||
}
|
||||
200 | 201 => {
|
||||
if self.parts[0].action_num == 200 {
|
||||
self.parts[0].action_num = 201;
|
||||
self.parts[0].action_counter = 0;
|
||||
self.parts[0].action_counter2 += 1;
|
||||
}
|
||||
|
||||
self.parts[0].action_counter += 1;
|
||||
|
||||
match self.parts[0].action_counter {
|
||||
4 => self.parts[9].action_num = 200,
|
||||
8 => self.parts[10].action_num = 200,
|
||||
10 => self.parts[11].action_num = 200,
|
||||
12 => self.parts[12].action_num = 200,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if self.parts[0].action_counter > 120 && self.parts[0].action_counter2 > 2 {
|
||||
self.parts[0].action_num = 400;
|
||||
}
|
||||
|
||||
let player_idx = self.parts[0].get_closest_player_idx_mut(&players);
|
||||
if self.parts[0].action_counter > 121 && players[player_idx].x < self.parts[0].x {
|
||||
self.parts[0].action_num = 100;
|
||||
}
|
||||
}
|
||||
300 | 301 => {
|
||||
if self.parts[0].action_num == 300 {
|
||||
self.parts[0].action_num = 301;
|
||||
self.parts[0].action_counter = 0;
|
||||
}
|
||||
|
||||
self.parts[0].action_counter += 1;
|
||||
|
||||
match self.parts[0].action_counter {
|
||||
4 => self.parts[9].action_num = 300,
|
||||
8 => self.parts[10].action_num = 300,
|
||||
10 => self.parts[11].action_num = 300,
|
||||
12 => self.parts[12].action_num = 300,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if self.parts[0].action_counter > 50 {
|
||||
if !self.parts[3].cond.alive() && !self.parts[4].cond.alive()
|
||||
&& !self.parts[5].cond.alive() && !self.parts[6].cond.alive() {
|
||||
self.parts[0].action_num = 600;
|
||||
} else {
|
||||
self.parts[0].action_num = 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
400 | 401 => {
|
||||
if self.parts[0].action_num == 400 {
|
||||
self.parts[0].action_num = 401;
|
||||
self.parts[0].action_counter = 0;
|
||||
}
|
||||
|
||||
self.parts[0].action_counter += 1;
|
||||
|
||||
match self.parts[0].action_counter {
|
||||
4 => self.parts[9].action_num = 400,
|
||||
8 => self.parts[10].action_num = 400,
|
||||
10 => self.parts[11].action_num = 400,
|
||||
12 => self.parts[12].action_num = 400,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if self.parts[0].action_counter > 50 {
|
||||
if !self.parts[3].cond.alive() && !self.parts[4].cond.alive()
|
||||
&& !self.parts[5].cond.alive() && !self.parts[6].cond.alive() {
|
||||
self.parts[0].action_num = 600;
|
||||
} else {
|
||||
self.parts[0].action_num = 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
500 | 501 => {
|
||||
if self.parts[0].action_num == 500 {
|
||||
self.parts[0].action_num = 501;
|
||||
self.parts[0].action_counter = 0;
|
||||
self.parts[1].action_num = 10;
|
||||
self.parts[2].action_num = 10;
|
||||
}
|
||||
|
||||
self.parts[0].action_counter += 1;
|
||||
|
||||
if self.parts[0].action_counter > 300 {
|
||||
self.parts[0].action_num = 502;
|
||||
self.parts[0].action_counter = 0;
|
||||
}
|
||||
|
||||
if !self.parts[3].cond.alive() && !self.parts[4].cond.alive()
|
||||
&& !self.parts[5].cond.alive() && !self.parts[6].cond.alive() {
|
||||
self.parts[0].action_num = 502;
|
||||
self.parts[0].action_counter = 0;
|
||||
}
|
||||
}
|
||||
502 | 503 => {
|
||||
if self.parts[0].action_num == 502 {
|
||||
self.parts[0].action_num = 503;
|
||||
self.parts[0].action_counter = 0;
|
||||
self.parts[0].action_counter2 = 0;
|
||||
self.parts[1].action_num = 20;
|
||||
self.parts[2].action_num = 20;
|
||||
}
|
||||
|
||||
self.parts[0].action_counter += 1;
|
||||
|
||||
if self.parts[0].action_counter > 50 {
|
||||
let player_idx = self.parts[0].get_closest_player_idx_mut(&players);
|
||||
self.parts[0].action_num = if self.parts[0].x > players[player_idx].x { 100 } else { 200 };
|
||||
}
|
||||
}
|
||||
600 | 601 => {
|
||||
if self.parts[0].action_num == 600 {
|
||||
self.parts[0].action_num = 601;
|
||||
self.parts[0].action_counter = 0;
|
||||
self.parts[0].vel_y2 = self.parts[0].life as isize;
|
||||
self.parts[1].action_num = 30;
|
||||
self.parts[2].action_num = 30;
|
||||
}
|
||||
|
||||
self.parts[0].action_counter += 1;
|
||||
if (self.parts[0].life as isize) < self.parts[0].vel_y2.saturating_sub(200)
|
||||
|| self.parts[0].action_counter > 300 {
|
||||
self.parts[0].action_num = 602;
|
||||
self.parts[0].action_counter = 0;
|
||||
}
|
||||
}
|
||||
602 | 603 => {
|
||||
if self.parts[0].action_num == 602 {
|
||||
self.parts[0].action_num = 603;
|
||||
self.parts[0].action_counter = 0;
|
||||
self.parts[0].action_counter2 = 0;
|
||||
self.parts[1].action_num = 40;
|
||||
self.parts[2].action_num = 40;
|
||||
}
|
||||
|
||||
self.parts[0].action_counter += 1;
|
||||
|
||||
if self.parts[0].action_counter > 50 {
|
||||
let player_idx = self.parts[0].get_closest_player_idx_mut(&players);
|
||||
self.parts[0].action_num = if self.parts[0].x > players[player_idx].x { 100 } else { 200 };
|
||||
}
|
||||
}
|
||||
1000 => {
|
||||
state.quake_counter = 2;
|
||||
|
||||
self.parts[0].action_counter += 1;
|
||||
if self.parts[0].action_counter % 8 == 0 {
|
||||
state.sound_manager.play_sfx(52);
|
||||
}
|
||||
|
||||
let mut npc = NPCMap::create_npc(4, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
npc.x = self.parts[0].x + self.parts[0].rng.range(-72..72) as isize * 0x200;
|
||||
npc.y = self.parts[0].y + self.parts[0].rng.range(-64..64) as isize * 0x200;
|
||||
state.new_npcs.push(npc);
|
||||
|
||||
if self.parts[0].action_counter > 100 {
|
||||
self.parts[0].action_num = 1001;
|
||||
self.parts[0].action_counter = 0;
|
||||
// todo flash
|
||||
state.sound_manager.play_sfx(35);
|
||||
}
|
||||
}
|
||||
1001 => {
|
||||
state.quake_counter = 40;
|
||||
self.parts[0].action_counter += 1;
|
||||
|
||||
if self.parts[0].action_counter > 50 {
|
||||
for part in self.parts.iter_mut() {
|
||||
part.cond.set_alive(false);
|
||||
}
|
||||
|
||||
for npc_cell in npc_map.values() {
|
||||
let npc = npc_cell.borrow_mut();
|
||||
if npc.cond.alive() && npc.npc_type == 158 {
|
||||
npc.cond.set_alive(false);
|
||||
}
|
||||
}
|
||||
|
||||
let mut npc = NPCMap::create_npc(159, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
npc.x = self.parts[0].x;
|
||||
npc.y = self.parts[1].y - 24 * 0x200;
|
||||
|
||||
state.new_npcs.push(npc);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.tick_b03_monster_x_track(9, state, &players);
|
||||
self.tick_b03_monster_x_track(10, state, &players);
|
||||
self.tick_b03_monster_x_track(11, state, &players);
|
||||
self.tick_b03_monster_x_track(12, state, &players);
|
||||
|
||||
self.parts[0].x += (((self.parts[9].x + self.parts[10].x + self.parts[11].x + self.parts[12].x) / 4) - self.parts[0].x) / 16;
|
||||
self.tick_b03_monster_x_face(7, state);
|
||||
|
||||
self.tick_b03_monster_x_frame(13, state);
|
||||
self.tick_b03_monster_x_frame(14, state);
|
||||
self.tick_b03_monster_x_frame(15, state);
|
||||
self.tick_b03_monster_x_frame(16, state);
|
||||
|
||||
self.tick_b03_monster_x_shield(1, state);
|
||||
self.tick_b03_monster_x_shield(2, state);
|
||||
|
||||
if self.parts[3].cond.alive() { self.tick_b03_monster_x_eye(3, state, &players); }
|
||||
if self.parts[4].cond.alive() { self.tick_b03_monster_x_eye(4, state, &players); }
|
||||
if self.parts[5].cond.alive() { self.tick_b03_monster_x_eye(5, state, &players); }
|
||||
if self.parts[6].cond.alive() { self.tick_b03_monster_x_eye(6, state, &players); }
|
||||
|
||||
if self.parts[0].life == 0 && self.parts[0].action_num < 1000 {
|
||||
self.parts[0].action_num = 1000;
|
||||
self.parts[0].action_counter = 0;
|
||||
self.parts[0].shock = 150;
|
||||
|
||||
self.parts[9].action_num = 300;
|
||||
self.parts[10].action_num = 300;
|
||||
self.parts[11].action_num = 300;
|
||||
self.parts[12].action_num = 300;
|
||||
}
|
||||
}
|
||||
|
||||
fn tick_b03_monster_x_face(&mut self, i: usize, state: &mut SharedGameState) {
|
||||
match self.parts[i].action_num {
|
||||
0 => {
|
||||
self.parts[0].npc_flags.set_shootable(false);
|
||||
self.parts[i].anim_num = 2;
|
||||
}
|
||||
10 | 11 => {
|
||||
if self.parts[i].action_num == 10 {
|
||||
self.parts[i].action_num = 11;
|
||||
self.parts[i].action_counter = (self.parts[i].target_x * 10 + 40) as u16;
|
||||
self.parts[i].anim_num = 2;
|
||||
self.parts[0].npc_flags.set_shootable(true);
|
||||
}
|
||||
|
||||
if self.parts[0].shock > 0 {
|
||||
self.parts[i].action_counter2 += 1;
|
||||
if self.parts[i].action_counter2 / 2 % 2 != 0 {
|
||||
self.parts[i].anim_num = 1;
|
||||
} else {
|
||||
self.parts[i].anim_num = 0;
|
||||
}
|
||||
} else {
|
||||
self.parts[i].anim_num = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.parts[7].x = self.parts[0].x;
|
||||
self.parts[7].y = self.parts[0].y;
|
||||
|
||||
self.parts[i].anim_rect = state.constants.npc.b03_monster_x[self.parts[i].anim_num as usize];
|
||||
}
|
||||
|
||||
fn tick_b03_monster_x_track(&mut self, i: usize, state: &mut SharedGameState, players: &[&mut Player; 2]) {
|
||||
match self.parts[i].action_num {
|
||||
10 => {
|
||||
self.parts[i].anim_num = 0;
|
||||
self.parts[i].npc_flags.set_bouncy(false);
|
||||
}
|
||||
100 | 101 => {
|
||||
if self.parts[i].action_num == 100 {
|
||||
self.parts[i].action_num = 101;
|
||||
self.parts[i].action_counter = 0;
|
||||
self.parts[i].anim_num = 2;
|
||||
self.parts[i].anim_counter = 0;
|
||||
self.parts[i].npc_flags.set_bouncy(true);
|
||||
}
|
||||
|
||||
self.parts[i].action_counter += 1;
|
||||
if self.parts[i].action_counter > 30 {
|
||||
self.parts[i].action_num = 102;
|
||||
}
|
||||
|
||||
self.parts[i].animate(0, 2, 3);
|
||||
self.parts[i].vel_x -= 0x20;
|
||||
}
|
||||
102 | 103 => {
|
||||
if self.parts[i].action_num == 102 {
|
||||
self.parts[i].action_num = 103;
|
||||
self.parts[i].anim_num = 0;
|
||||
self.parts[i].anim_counter = 0;
|
||||
self.parts[i].npc_flags.set_bouncy(false);
|
||||
}
|
||||
|
||||
self.parts[i].action_counter += 1;
|
||||
self.parts[i].animate(1, 0, 1);
|
||||
self.parts[i].vel_x -= 0x20;
|
||||
}
|
||||
200 | 201 => {
|
||||
if self.parts[i].action_num == 200 {
|
||||
self.parts[i].action_num = 201;
|
||||
self.parts[i].action_counter = 0;
|
||||
self.parts[i].anim_num = 4;
|
||||
self.parts[i].anim_counter = 0;
|
||||
self.parts[i].npc_flags.set_bouncy(true);
|
||||
self.parts[i].npc_flags.set_rear_and_top_not_hurt(true);
|
||||
}
|
||||
|
||||
self.parts[i].action_counter += 1;
|
||||
if self.parts[i].action_counter > 30 {
|
||||
self.parts[i].action_num = 202;
|
||||
}
|
||||
|
||||
self.parts[i].animate(0, 4, 5);
|
||||
self.parts[i].vel_x += 0x20;
|
||||
}
|
||||
202 | 203 => {
|
||||
if self.parts[i].action_num == 202 {
|
||||
self.parts[i].action_num = 203;
|
||||
self.parts[i].anim_num = 0;
|
||||
self.parts[i].anim_counter = 0;
|
||||
self.parts[i].npc_flags.set_bouncy(false);
|
||||
}
|
||||
|
||||
self.parts[i].action_counter += 1;
|
||||
|
||||
self.parts[i].animate(1, 0, 1);
|
||||
self.parts[i].vel_x += 0x20;
|
||||
}
|
||||
300 | 301 => {
|
||||
if self.parts[i].action_num == 300 {
|
||||
self.parts[i].action_num = 301;
|
||||
self.parts[i].anim_num = 4;
|
||||
self.parts[i].anim_counter = 0;
|
||||
self.parts[i].npc_flags.set_bouncy(true);
|
||||
}
|
||||
|
||||
self.parts[i].animate(0, 4, 5);
|
||||
|
||||
self.parts[i].vel_x += 0x20;
|
||||
if self.parts[i].vel_x > 0 {
|
||||
self.parts[i].vel_x = 0;
|
||||
self.parts[i].action_num = 10;
|
||||
}
|
||||
}
|
||||
400 | 401 => {
|
||||
if self.parts[i].action_num == 400 {
|
||||
self.parts[i].action_num = 401;
|
||||
self.parts[i].anim_num = 2;
|
||||
self.parts[i].anim_counter = 0;
|
||||
self.parts[i].npc_flags.set_bouncy(true);
|
||||
}
|
||||
|
||||
self.parts[i].animate(0, 2, 3);
|
||||
|
||||
self.parts[i].vel_x -= 0x20;
|
||||
if self.parts[i].vel_x < 0 {
|
||||
self.parts[i].vel_x = 0;
|
||||
self.parts[i].action_num = 10;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if self.parts[i].action_counter % 2 == 1 && [101, 201, 301, 401].contains(&self.parts[i].action_num) {
|
||||
state.sound_manager.play_sfx(112);
|
||||
}
|
||||
|
||||
if self.parts[i].action_counter % 4 == 1 && [103, 203].contains(&self.parts[i].action_num) {
|
||||
state.sound_manager.play_sfx(111);
|
||||
}
|
||||
|
||||
let player_idx = self.parts[i].get_closest_player_idx_mut(players);
|
||||
if self.parts[i].action_num >= 100 && abs(players[player_idx].y - self.parts[i].y) < 4 * 0x200 {
|
||||
self.parts[i].damage = 10;
|
||||
self.parts[i].npc_flags.set_rear_and_top_not_hurt(true);
|
||||
} else {
|
||||
self.parts[i].damage = 0;
|
||||
self.parts[i].npc_flags.set_rear_and_top_not_hurt(false);
|
||||
}
|
||||
|
||||
self.parts[i].vel_x = clamp(self.parts[i].vel_x, -0x400, 0x400);
|
||||
self.parts[i].x += self.parts[i].vel_x;
|
||||
|
||||
let dir_offset = if self.parts[i].direction == Direction::Up { 3 } else { 9 };
|
||||
|
||||
self.parts[i].anim_rect = state.constants.npc.b03_monster_x[self.parts[i].anim_num as usize + dir_offset];
|
||||
}
|
||||
|
||||
fn tick_b03_monster_x_frame(&mut self, i: usize, state: &mut SharedGameState) {
|
||||
match self.parts[i].action_num {
|
||||
10 | 11 => {
|
||||
if self.parts[i].action_num == 10 {
|
||||
self.parts[i].action_num = 11;
|
||||
self.parts[i].action_counter = (self.parts[i].anim_num * 30 + 30) as u16;
|
||||
}
|
||||
|
||||
if self.parts[i].action_counter > 0 {
|
||||
self.parts[i].action_counter -= 1;
|
||||
} else {
|
||||
self.parts[i].action_counter = 120;
|
||||
state.sound_manager.play_sfx(39);
|
||||
|
||||
let mut npc = NPCMap::create_npc(158, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
|
||||
match self.parts[i].anim_num {
|
||||
0 => {
|
||||
npc.direction = Direction::Bottom;
|
||||
npc.x = self.parts[i].x + -30 * 0x200;
|
||||
npc.y = self.parts[i].y + 6 * 0x200;
|
||||
}
|
||||
1 => {
|
||||
npc.direction = Direction::Right;
|
||||
npc.x = self.parts[i].x + 30 * 0x200;
|
||||
npc.y = self.parts[i].y + 6 * 0x200;
|
||||
}
|
||||
2 => {
|
||||
npc.direction = Direction::Left;
|
||||
npc.x = self.parts[i].x - 30 * 0x200;
|
||||
npc.y = self.parts[i].y - 6 * 0x200;
|
||||
}
|
||||
3 => {
|
||||
npc.direction = Direction::Up;
|
||||
npc.x = self.parts[i].x + 30 * 0x200;
|
||||
npc.y = self.parts[i].y - 6 * 0x200;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
state.new_npcs.push(npc);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.parts[i].x = (self.parts[0].x + self.parts[self.parts[i].action_counter2 as usize].x) / 2;
|
||||
self.parts[i].y = (self.parts[0].y + self.parts[self.parts[i].action_counter2 as usize].y) / 2;
|
||||
|
||||
self.parts[i].anim_rect = state.constants.npc.b03_monster_x[15 + self.parts[i].anim_num as usize];
|
||||
}
|
||||
|
||||
fn tick_b03_monster_x_shield(&mut self, i: usize, state: &mut SharedGameState) {
|
||||
match self.parts[i].action_num {
|
||||
10 => {
|
||||
self.parts[i].target_x += 0x200;
|
||||
|
||||
if self.parts[i].target_x > 32 * 0x200 {
|
||||
self.parts[i].target_x = 32 * 0x200;
|
||||
self.parts[i].action_num = 0;
|
||||
self.parts[3].action_num = 10;
|
||||
self.parts[4].action_num = 10;
|
||||
self.parts[5].action_num = 10;
|
||||
self.parts[6].action_num = 10;
|
||||
}
|
||||
}
|
||||
20 => {
|
||||
self.parts[i].target_x -= 0x200;
|
||||
|
||||
if self.parts[i].target_x < 0 {
|
||||
self.parts[i].target_x = 0;
|
||||
self.parts[i].action_num = 0;
|
||||
self.parts[3].action_num = 0;
|
||||
self.parts[4].action_num = 0;
|
||||
self.parts[5].action_num = 0;
|
||||
self.parts[6].action_num = 0;
|
||||
}
|
||||
}
|
||||
30 => {
|
||||
self.parts[i].target_x += 0x200;
|
||||
|
||||
if self.parts[i].target_x > 20 * 0x200 {
|
||||
self.parts[i].target_x = 20 * 0x200;
|
||||
self.parts[i].action_num = 0;
|
||||
self.parts[7].action_num = 10;
|
||||
self.parts[13].action_num = 10;
|
||||
self.parts[14].action_num = 10;
|
||||
self.parts[15].action_num = 10;
|
||||
self.parts[16].action_num = 10;
|
||||
}
|
||||
}
|
||||
40 => {
|
||||
self.parts[i].target_x -= 0x200;
|
||||
|
||||
if self.parts[i].target_x < 0 {
|
||||
self.parts[i].target_x = 0;
|
||||
self.parts[i].action_num = 0;
|
||||
self.parts[7].action_num = 0;
|
||||
self.parts[13].action_num = 0;
|
||||
self.parts[14].action_num = 0;
|
||||
self.parts[15].action_num = 0;
|
||||
self.parts[16].action_num = 0;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.parts[i].x = self.parts[0].x + self.parts[i].direction.vector_x() * (24 * 0x200 + self.parts[i].target_x);
|
||||
self.parts[i].y = self.parts[0].y;
|
||||
|
||||
let dir_offset = if self.parts[i].direction == Direction::Left { 19 } else { 20 };
|
||||
|
||||
self.parts[i].anim_rect = state.constants.npc.b03_monster_x[dir_offset];
|
||||
}
|
||||
|
||||
fn tick_b03_monster_x_eye(&mut self, i: usize, state: &mut SharedGameState, players: &[&mut Player; 2]) {
|
||||
match self.parts[i].action_num {
|
||||
0 => {
|
||||
self.parts[i].npc_flags.set_shootable(false);
|
||||
self.parts[i].anim_num = 0;
|
||||
}
|
||||
10 | 11 => {
|
||||
if self.parts[i].action_num == 10 {
|
||||
self.parts[i].action_num = 11;
|
||||
self.parts[i].action_counter = (self.parts[i].target_x * 10 + 40) as u16;
|
||||
self.parts[i].npc_flags.set_shootable(true);
|
||||
}
|
||||
|
||||
self.parts[i].anim_num = if self.parts[i].action_counter < 16
|
||||
&& self.parts[i].action_counter / 2 % 2 != 0 { 1 } else { 0 };
|
||||
|
||||
if self.parts[i].action_counter > 0 {
|
||||
self.parts[i].action_counter -= 1;
|
||||
} else {
|
||||
let player_idx = self.parts[i].get_closest_player_idx_mut(players);
|
||||
let px = self.parts[i].x - players[player_idx].x;
|
||||
let py = self.parts[i].y - players[player_idx].y;
|
||||
|
||||
let deg = f64::atan2(py as f64, px as f64)
|
||||
+ self.parts[i].rng.range(-2..2) as f64 * CDEG_RAD;
|
||||
|
||||
let mut npc = NPCMap::create_npc(156, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
npc.x = self.parts[i].x;
|
||||
npc.y = self.parts[i].y;
|
||||
npc.vel_x = (deg.cos() * -1536.0) as isize;
|
||||
npc.vel_y = (deg.sin() * -1536.0) as isize;
|
||||
|
||||
state.new_npcs.push(npc);
|
||||
|
||||
state.sound_manager.play_sfx(39);
|
||||
self.parts[i].action_counter = 40;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match self.parts[i].target_x {
|
||||
0 => {
|
||||
self.parts[i].x = self.parts[0].x - 22 * 0x200;
|
||||
self.parts[i].y = self.parts[0].y - 16 * 0x200;
|
||||
}
|
||||
1 => {
|
||||
self.parts[i].x = self.parts[0].x + 28 * 0x200;
|
||||
self.parts[i].y = self.parts[0].y - 16 * 0x200;
|
||||
}
|
||||
2 => {
|
||||
self.parts[i].x = self.parts[0].x - 15 * 0x200;
|
||||
self.parts[i].y = self.parts[0].y + 14 * 0x200;
|
||||
}
|
||||
3 => {
|
||||
self.parts[i].x = self.parts[0].x + 17 * 0x200;
|
||||
self.parts[i].y = self.parts[0].y + 14 * 0x200;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.parts[i].anim_rect = state.constants.npc.b03_monster_x[21 + self.parts[i].target_x as usize + 4 * self.parts[i].anim_num as usize];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,9 +13,8 @@ use crate::shared_game_state::SharedGameState;
|
|||
|
||||
impl NPC {
|
||||
pub(crate) fn tick_n048_omega_projectiles(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.flags.hit_left_wall() && self.vel_x < 0 {
|
||||
self.vel_x = -self.vel_x;
|
||||
} else if self.flags.hit_right_wall() && self.vel_x > 0 {
|
||||
if (self.flags.hit_left_wall() && self.vel_x < 0)
|
||||
|| (self.flags.hit_right_wall() && self.vel_x > 0) {
|
||||
self.vel_x = -self.vel_x;
|
||||
} else if self.flags.hit_bottom_wall() {
|
||||
self.action_counter2 += 1;
|
||||
|
@ -202,7 +201,7 @@ impl BossNPC {
|
|||
state.sound_manager.play_sfx(39);
|
||||
}
|
||||
|
||||
if self.parts[0].action_counter == 200 || bullet_manager.count_bullets_all(6) > 0 {
|
||||
if self.parts[0].action_counter == 200 || bullet_manager.count_bullets_type_idx_all(6) > 0 {
|
||||
self.parts[0].action_num = 70;
|
||||
self.parts[0].anim_counter = 0;
|
||||
|
||||
|
@ -275,7 +274,7 @@ impl BossNPC {
|
|||
}
|
||||
120 => {
|
||||
self.parts[0].action_counter += 1;
|
||||
if self.parts[0].action_counter == 50 || bullet_manager.count_bullets_all(6) > 0 {
|
||||
if self.parts[0].action_counter == 50 || bullet_manager.count_bullets_type_idx_all(6) > 0 {
|
||||
self.parts[0].action_num = 130;
|
||||
self.parts[0].action_counter = 0;
|
||||
self.parts[0].anim_counter = 0;
|
||||
|
|
|
@ -5,6 +5,7 @@ use crate::common::Direction;
|
|||
use crate::npc::NPC;
|
||||
use crate::player::Player;
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
use crate::caret::CaretType;
|
||||
|
||||
impl NPC {
|
||||
pub(crate) fn tick_n154_gaudi_dead(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
|
@ -14,6 +15,22 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n156_gaudi_projectile(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.action_counter > 300 || (self.flags.0 & 0xff) != 0 {
|
||||
self.cond.set_alive(false);
|
||||
state.create_caret(self.x, self.y, CaretType::ProjectileDissipation, Direction::Left);
|
||||
}
|
||||
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
|
||||
self.anim_num = (self.anim_num + 1) % 3;
|
||||
|
||||
self.anim_rect = state.constants.npc.n156_gaudi_projectile[self.anim_num as usize];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n361_gaudi_dashing(&mut self, state: &mut SharedGameState, players: [&mut Player; 2]) -> GameResult {
|
||||
match self.action_num {
|
||||
0 | 1 => {
|
||||
|
|
|
@ -285,7 +285,9 @@ impl GameEntity<([&mut Player; 2], &BTreeMap<u16, RefCell<NPC>>, &mut Stage, &Bu
|
|||
150 => self.tick_n150_quote(state, players),
|
||||
151 => self.tick_n151_blue_robot_standing(state),
|
||||
154 => self.tick_n154_gaudi_dead(state),
|
||||
156 => self.tick_n156_gaudi_projectile(state),
|
||||
157 => self.tick_n157_vertical_moving_block(state, players),
|
||||
158 => self.tick_n158_fish_missile(state, players),
|
||||
192 => self.tick_n192_scooter(state),
|
||||
193 => self.tick_n193_broken_scooter(state),
|
||||
194 => self.tick_n194_broken_blue_robot(state),
|
||||
|
|
|
@ -1301,7 +1301,7 @@ impl Scene for GameScene {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn draw_tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||
fn draw_tick(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
self.frame.prev_x = self.frame.x;
|
||||
self.frame.prev_y = self.frame.y;
|
||||
self.player1.prev_x = self.player1.x;
|
||||
|
|
|
@ -7,14 +7,21 @@ pub mod game_scene;
|
|||
pub mod loading_scene;
|
||||
pub mod title_scene;
|
||||
|
||||
/// Implement this trait on any object that represents an interactive game screen.
|
||||
pub trait Scene {
|
||||
/// Called when the scene is shown.
|
||||
fn init(&mut self, _state: &mut SharedGameState, _ctx: &mut Context) -> GameResult { Ok(()) }
|
||||
|
||||
/// Called at game tick. Perform any game state updates there.
|
||||
fn tick(&mut self, _state: &mut SharedGameState, _ctx: &mut Context) -> GameResult { Ok(()) }
|
||||
|
||||
fn draw_tick(&mut self, _state: &mut SharedGameState, _ctx: &mut Context) -> GameResult { Ok(()) }
|
||||
/// Called before draws between two ticks to update previous positions used for interpolation.
|
||||
/// DO NOT perform updates of the game state there.
|
||||
fn draw_tick(&mut self, _state: &mut SharedGameState) -> GameResult { Ok(()) }
|
||||
|
||||
/// Called during frame rendering operation.
|
||||
fn draw(&self, _state: &mut SharedGameState, _ctx: &mut Context) -> GameResult { Ok(()) }
|
||||
|
||||
/// Independent draw meant for debug overlay, that lets you mutate the game state.
|
||||
fn debug_overlay_draw(&mut self, _game_ui: &mut Components, _state: &mut SharedGameState, _ctx: &mut Context, _frame: &mut imgui::Ui) -> GameResult { Ok(()) }
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::io::{BufReader, Read, Seek, SeekFrom};
|
|||
use ggez;
|
||||
use ggez::{Context, GameError, GameResult, graphics};
|
||||
use ggez::filesystem;
|
||||
use ggez::graphics::{Color, Drawable, DrawMode, DrawParam, FilterMode, Image, Mesh, mint, Rect};
|
||||
use ggez::graphics::{Drawable, DrawMode, DrawParam, FilterMode, Image, Mesh, mint, Rect};
|
||||
use ggez::graphics::spritebatch::SpriteBatch;
|
||||
use ggez::nalgebra::{Point2, Vector2};
|
||||
use image::RgbaImage;
|
||||
|
@ -182,20 +182,6 @@ impl TextureSet {
|
|||
Image::from_rgba8(ctx, width as u16, height as u16, img.as_ref())
|
||||
}
|
||||
|
||||
fn load_image_from_buf(&self, ctx: &mut Context, buf: &[u8]) -> GameResult<Image> {
|
||||
let img = {
|
||||
let image = image::load_from_memory(buf)?;
|
||||
let mut rgba = image.to_rgba();
|
||||
if image.color().channel_count() != 4 {
|
||||
TextureSet::make_transparent(&mut rgba);
|
||||
}
|
||||
rgba
|
||||
};
|
||||
let (width, height) = img.dimensions();
|
||||
|
||||
Image::from_rgba8(ctx, width as u16, height as u16, img.as_ref())
|
||||
}
|
||||
|
||||
pub fn load_texture(&self, ctx: &mut Context, constants: &EngineConstants, name: &str) -> GameResult<SizedBatch> {
|
||||
let path = self.paths.iter().find_map(|s| FILE_TYPES
|
||||
.iter()
|
||||
|
|
Loading…
Reference in a new issue