2022-01-27 04:56:32 +00:00
|
|
|
use crate::common::{Condition, Direction, Rect, CDEG_RAD};
|
2020-08-20 18:31:47 +00:00
|
|
|
use crate::engine_constants::EngineConstants;
|
2020-08-21 05:27:26 +00:00
|
|
|
use crate::rng::RNG;
|
2020-08-20 18:31:47 +00:00
|
|
|
|
|
|
|
#[derive(Debug, EnumIter, PartialEq, Eq, Hash, Copy, Clone)]
|
|
|
|
pub enum CaretType {
|
|
|
|
None,
|
|
|
|
Bubble,
|
|
|
|
ProjectileDissipation,
|
|
|
|
Shoot,
|
|
|
|
SnakeAfterimage,
|
|
|
|
Zzz,
|
|
|
|
SnakeAfterimage2,
|
|
|
|
Exhaust,
|
|
|
|
DrownedQuote,
|
|
|
|
QuestionMark,
|
|
|
|
LevelUp,
|
|
|
|
HurtParticles,
|
|
|
|
Explosion,
|
2020-08-21 05:27:26 +00:00
|
|
|
LittleParticles,
|
2020-08-20 18:31:47 +00:00
|
|
|
Unknown,
|
|
|
|
SmallProjectileDissipation,
|
2022-01-27 04:56:32 +00:00
|
|
|
EmptyText,
|
2020-08-20 18:31:47 +00:00
|
|
|
PushJumpKey,
|
|
|
|
}
|
|
|
|
|
2021-03-29 21:19:07 +00:00
|
|
|
impl CaretType {
|
|
|
|
pub fn from_int(id: usize) -> Option<CaretType> {
|
|
|
|
match id {
|
|
|
|
0 => Some(CaretType::None),
|
|
|
|
1 => Some(CaretType::Bubble),
|
|
|
|
2 => Some(CaretType::ProjectileDissipation),
|
|
|
|
3 => Some(CaretType::Shoot),
|
|
|
|
4 => Some(CaretType::SnakeAfterimage),
|
|
|
|
5 => Some(CaretType::Zzz),
|
|
|
|
6 => Some(CaretType::SnakeAfterimage2),
|
|
|
|
7 => Some(CaretType::Exhaust),
|
|
|
|
8 => Some(CaretType::DrownedQuote),
|
|
|
|
9 => Some(CaretType::QuestionMark),
|
|
|
|
10 => Some(CaretType::LevelUp),
|
|
|
|
11 => Some(CaretType::HurtParticles),
|
|
|
|
12 => Some(CaretType::Explosion),
|
|
|
|
13 => Some(CaretType::LittleParticles),
|
|
|
|
14 => Some(CaretType::Unknown),
|
|
|
|
15 => Some(CaretType::SmallProjectileDissipation),
|
2022-01-27 04:56:32 +00:00
|
|
|
16 => Some(CaretType::EmptyText),
|
2021-03-29 21:19:07 +00:00
|
|
|
17 => Some(CaretType::PushJumpKey),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-20 18:31:47 +00:00
|
|
|
pub struct Caret {
|
|
|
|
pub ctype: CaretType,
|
2021-01-01 01:46:01 +00:00
|
|
|
pub x: i32,
|
|
|
|
pub y: i32,
|
|
|
|
pub vel_x: i32,
|
|
|
|
pub vel_y: i32,
|
|
|
|
pub offset_x: i32,
|
|
|
|
pub offset_y: i32,
|
|
|
|
pub prev_x: i32,
|
|
|
|
pub prev_y: i32,
|
2020-09-05 04:43:14 +00:00
|
|
|
pub cond: Condition,
|
|
|
|
pub direction: Direction,
|
2020-11-17 02:42:45 +00:00
|
|
|
pub anim_rect: Rect<u16>,
|
2020-12-05 21:44:15 +00:00
|
|
|
action_num: u16,
|
2020-09-12 00:42:44 +00:00
|
|
|
anim_num: u16,
|
|
|
|
anim_counter: u16,
|
2020-08-20 18:31:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Caret {
|
2021-01-01 01:46:01 +00:00
|
|
|
pub fn new(x: i32, y: i32, ctype: CaretType, direct: Direction, constants: &EngineConstants) -> Caret {
|
2020-08-20 18:31:47 +00:00
|
|
|
let (offset_x, offset_y) = constants.caret.offsets[ctype as usize];
|
2020-09-12 00:42:44 +00:00
|
|
|
|
|
|
|
Caret {
|
2020-08-20 18:31:47 +00:00
|
|
|
ctype,
|
|
|
|
x,
|
|
|
|
y,
|
|
|
|
vel_x: 0,
|
|
|
|
vel_y: 0,
|
|
|
|
offset_x,
|
|
|
|
offset_y,
|
2020-11-07 17:17:01 +00:00
|
|
|
prev_x: x,
|
|
|
|
prev_y: y,
|
2020-09-05 04:43:14 +00:00
|
|
|
cond: Condition(0x80),
|
|
|
|
direction: direct,
|
2020-09-12 00:42:44 +00:00
|
|
|
anim_rect: Rect::new(0, 0, 0, 0),
|
2020-12-05 21:44:15 +00:00
|
|
|
action_num: 0,
|
2020-08-20 18:31:47 +00:00
|
|
|
anim_num: 0,
|
2020-09-05 04:43:14 +00:00
|
|
|
anim_counter: 0,
|
2020-08-20 18:31:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-25 22:39:41 +00:00
|
|
|
pub fn tick(&mut self, rng: &dyn RNG, constants: &EngineConstants) {
|
2020-08-20 18:31:47 +00:00
|
|
|
match self.ctype {
|
|
|
|
CaretType::None => {}
|
2022-01-27 14:43:03 +00:00
|
|
|
CaretType::Bubble => {
|
|
|
|
if self.action_num == 0 {
|
|
|
|
self.action_num = 1;
|
|
|
|
self.vel_x = rng.range(-0x400..0x400);
|
|
|
|
self.vel_y = rng.range(-0x400..0);
|
|
|
|
}
|
|
|
|
|
|
|
|
self.vel_y += 0x40;
|
|
|
|
self.x += self.vel_x;
|
|
|
|
self.y += self.vel_y;
|
|
|
|
|
|
|
|
self.anim_counter += 1;
|
|
|
|
if self.anim_counter > 5 {
|
|
|
|
self.anim_counter = 0;
|
|
|
|
self.anim_num += 1;
|
|
|
|
if self.anim_num > 3 {
|
|
|
|
self.cond.set_alive(false);
|
|
|
|
self.anim_num = 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
match self.direction {
|
|
|
|
Direction::Left => self.anim_rect = constants.caret.bubble_left_rects[self.anim_num as usize],
|
|
|
|
Direction::Right => self.anim_rect = constants.caret.bubble_right_rects[self.anim_num as usize],
|
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
}
|
2022-01-27 04:56:32 +00:00
|
|
|
CaretType::ProjectileDissipation => match self.direction {
|
|
|
|
Direction::Left => {
|
|
|
|
self.vel_y -= 0x10;
|
|
|
|
self.y += self.vel_y;
|
2020-09-12 00:42:44 +00:00
|
|
|
|
2022-01-27 04:56:32 +00:00
|
|
|
self.anim_counter += 1;
|
|
|
|
if self.anim_counter > 5 {
|
|
|
|
self.anim_counter = 0;
|
|
|
|
self.anim_num += 1;
|
2020-09-12 00:42:44 +00:00
|
|
|
|
2022-01-27 04:56:32 +00:00
|
|
|
if self.anim_num >= constants.caret.projectile_dissipation_left_rects.len() as u16 {
|
2020-09-12 00:42:44 +00:00
|
|
|
self.cond.set_alive(false);
|
2022-01-27 04:56:32 +00:00
|
|
|
return;
|
2020-09-12 00:42:44 +00:00
|
|
|
}
|
2022-01-27 04:56:32 +00:00
|
|
|
}
|
2022-02-21 22:22:14 +00:00
|
|
|
self.anim_rect = constants.caret.projectile_dissipation_left_rects[self.anim_num as usize];
|
2022-01-27 04:56:32 +00:00
|
|
|
}
|
|
|
|
Direction::Up => {
|
|
|
|
self.anim_counter += 1;
|
|
|
|
|
|
|
|
if self.anim_counter > 24 {
|
|
|
|
self.cond.set_alive(false);
|
2020-09-23 11:31:43 +00:00
|
|
|
}
|
2020-09-12 00:42:44 +00:00
|
|
|
|
2022-01-27 04:56:32 +00:00
|
|
|
let len = constants.caret.projectile_dissipation_up_rects.len();
|
|
|
|
self.anim_rect =
|
|
|
|
constants.caret.projectile_dissipation_up_rects[(self.anim_num as usize / 2) % len];
|
|
|
|
}
|
|
|
|
Direction::Right => {
|
|
|
|
self.anim_counter += 1;
|
|
|
|
if self.anim_counter > 2 {
|
|
|
|
self.anim_counter = 0;
|
|
|
|
self.anim_num += 1;
|
2020-09-12 00:42:44 +00:00
|
|
|
|
2022-01-27 04:56:32 +00:00
|
|
|
if self.anim_num >= constants.caret.projectile_dissipation_right_rects.len() as u16 {
|
|
|
|
self.cond.set_alive(false);
|
|
|
|
return;
|
2020-09-12 00:42:44 +00:00
|
|
|
}
|
2020-09-23 11:31:43 +00:00
|
|
|
}
|
2022-02-21 22:22:14 +00:00
|
|
|
self.anim_rect = constants.caret.projectile_dissipation_right_rects[self.anim_num as usize];
|
2020-09-12 00:42:44 +00:00
|
|
|
}
|
2022-01-27 04:56:32 +00:00
|
|
|
Direction::Bottom => {
|
|
|
|
self.cond.set_alive(false);
|
|
|
|
}
|
|
|
|
Direction::FacingPlayer => unreachable!(),
|
|
|
|
},
|
2020-09-12 00:42:44 +00:00
|
|
|
CaretType::Shoot => {
|
|
|
|
if self.anim_counter == 0 {
|
|
|
|
self.anim_rect = constants.caret.shoot_rects[self.anim_num as usize];
|
|
|
|
}
|
|
|
|
|
|
|
|
self.anim_counter += 1;
|
2022-01-10 03:02:27 +00:00
|
|
|
if self.anim_counter > 2 {
|
2020-09-12 00:42:44 +00:00
|
|
|
self.anim_counter = 0;
|
|
|
|
self.anim_num += 1;
|
|
|
|
|
2020-09-12 04:43:29 +00:00
|
|
|
if self.anim_num >= constants.caret.shoot_rects.len() as u16 {
|
|
|
|
self.cond.set_alive(false);
|
|
|
|
}
|
2020-09-12 00:42:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
CaretType::SnakeAfterimage | CaretType::SnakeAfterimage2 => {} // dupe, unused
|
2020-09-05 04:43:14 +00:00
|
|
|
CaretType::Zzz => {
|
|
|
|
if self.anim_counter == 0 {
|
2020-09-12 00:42:44 +00:00
|
|
|
self.anim_rect = constants.caret.zzz_rects[self.anim_num as usize];
|
2020-09-05 04:43:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
self.anim_counter += 1;
|
|
|
|
if self.anim_counter > 4 {
|
|
|
|
self.anim_counter = 0;
|
|
|
|
self.anim_num += 1;
|
|
|
|
|
2020-09-12 04:43:29 +00:00
|
|
|
if self.anim_num >= constants.caret.zzz_rects.len() as u16 {
|
|
|
|
self.cond.set_alive(false);
|
|
|
|
return;
|
|
|
|
}
|
2020-09-05 04:43:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
self.x += 0x80; // 0.4fix9
|
|
|
|
self.y -= 0x80;
|
|
|
|
}
|
2020-08-20 18:31:47 +00:00
|
|
|
CaretType::Exhaust => {
|
2020-09-12 00:42:44 +00:00
|
|
|
if self.anim_counter == 0 {
|
|
|
|
self.anim_rect = constants.caret.exhaust_rects[self.anim_num as usize];
|
|
|
|
}
|
|
|
|
|
2020-09-05 04:43:14 +00:00
|
|
|
self.anim_counter += 1;
|
|
|
|
if self.anim_counter > 1 {
|
|
|
|
self.anim_counter = 0;
|
2020-08-20 18:31:47 +00:00
|
|
|
self.anim_num += 1;
|
|
|
|
|
2020-09-12 00:42:44 +00:00
|
|
|
if self.anim_num >= constants.caret.exhaust_rects.len() as u16 {
|
|
|
|
self.cond.set_alive(false);
|
|
|
|
return;
|
|
|
|
}
|
2020-08-20 18:31:47 +00:00
|
|
|
}
|
|
|
|
|
2020-09-05 04:43:14 +00:00
|
|
|
match self.direction {
|
2021-12-02 05:57:44 +00:00
|
|
|
Direction::Left => self.x -= 0x400,
|
2020-12-15 22:09:14 +00:00
|
|
|
Direction::Up => self.y -= 0x400,
|
|
|
|
Direction::Right => self.x += 0x400,
|
|
|
|
Direction::Bottom => self.y += 0x400,
|
2021-12-02 05:57:44 +00:00
|
|
|
Direction::FacingPlayer => (),
|
2020-08-20 18:31:47 +00:00
|
|
|
}
|
|
|
|
}
|
2020-09-05 04:43:14 +00:00
|
|
|
CaretType::DrownedQuote => {
|
|
|
|
if self.anim_counter == 0 {
|
|
|
|
self.anim_counter = 1;
|
|
|
|
|
|
|
|
match self.direction {
|
2020-12-15 22:09:14 +00:00
|
|
|
Direction::Left => self.anim_rect = constants.caret.drowned_quote_left_rect,
|
|
|
|
Direction::Right => self.anim_rect = constants.caret.drowned_quote_right_rect,
|
2020-09-30 03:11:25 +00:00
|
|
|
Direction::FacingPlayer => unreachable!(),
|
2020-09-05 04:43:14 +00:00
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-20 18:31:47 +00:00
|
|
|
CaretType::QuestionMark => {
|
2020-09-05 04:43:14 +00:00
|
|
|
self.anim_counter += 1;
|
|
|
|
if self.anim_counter < 5 {
|
2020-08-23 02:17:24 +00:00
|
|
|
self.y -= 0x800; // 4.0fix9
|
2020-08-20 18:31:47 +00:00
|
|
|
}
|
|
|
|
|
2020-09-05 04:43:14 +00:00
|
|
|
if self.anim_counter == 32 {
|
|
|
|
self.cond.set_alive(false);
|
2020-08-20 18:31:47 +00:00
|
|
|
}
|
|
|
|
|
2020-09-05 04:43:14 +00:00
|
|
|
self.anim_rect = match self.direction {
|
2022-01-27 04:56:32 +00:00
|
|
|
Direction::Left => constants.caret.question_left_rect,
|
|
|
|
Direction::Right => constants.caret.question_right_rect,
|
|
|
|
_ => self.anim_rect,
|
2020-08-20 18:31:47 +00:00
|
|
|
}
|
|
|
|
}
|
2020-09-23 11:31:43 +00:00
|
|
|
CaretType::LevelUp => {
|
|
|
|
self.anim_counter += 1;
|
|
|
|
|
|
|
|
if self.anim_counter == 80 {
|
|
|
|
self.cond.set_alive(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
match self.direction {
|
|
|
|
Direction::Left => {
|
|
|
|
if self.anim_counter < 20 {
|
|
|
|
self.y -= 0x400; // 2.0fix9
|
|
|
|
}
|
|
|
|
|
|
|
|
let count = constants.caret.level_up_rects.len();
|
|
|
|
self.anim_rect = constants.caret.level_up_rects[self.anim_counter as usize / 2 % count]
|
|
|
|
}
|
|
|
|
Direction::Right => {
|
|
|
|
if self.anim_counter < 20 {
|
|
|
|
self.y -= 0x200; // 2.0fix9
|
|
|
|
}
|
|
|
|
|
|
|
|
let count = constants.caret.level_down_rects.len();
|
|
|
|
self.anim_rect = constants.caret.level_down_rects[self.anim_counter as usize / 2 % count]
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
2020-12-05 21:44:15 +00:00
|
|
|
CaretType::HurtParticles => {
|
|
|
|
if self.action_num == 0 {
|
|
|
|
self.action_num = 1;
|
|
|
|
let angle = rng.range(0..255) as f64 * CDEG_RAD;
|
2021-01-01 01:46:01 +00:00
|
|
|
self.vel_x = (angle.cos() * 1024.0) as i32;
|
|
|
|
self.vel_y = (angle.sin() * 1024.0) as i32;
|
2020-12-05 21:44:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
self.x += self.vel_x;
|
|
|
|
self.y += self.vel_y;
|
|
|
|
|
|
|
|
if self.anim_counter == 0 {
|
|
|
|
self.anim_rect = constants.caret.hurt_particles_rects[self.anim_num as usize];
|
|
|
|
}
|
|
|
|
|
|
|
|
self.anim_counter += 1;
|
|
|
|
if self.anim_counter > 2 {
|
|
|
|
self.anim_counter = 0;
|
|
|
|
self.anim_num += 1;
|
|
|
|
|
|
|
|
if self.anim_num >= constants.caret.hurt_particles_rects.len() as u16 {
|
|
|
|
self.cond.set_alive(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-09-12 04:43:29 +00:00
|
|
|
CaretType::Explosion => {
|
|
|
|
if self.anim_counter == 0 {
|
|
|
|
self.anim_rect = constants.caret.explosion_rects[self.anim_num as usize];
|
|
|
|
}
|
|
|
|
|
|
|
|
self.anim_counter += 1;
|
|
|
|
if self.anim_counter > 2 {
|
|
|
|
self.anim_counter = 0;
|
|
|
|
self.anim_num += 1;
|
|
|
|
|
|
|
|
if self.anim_num >= constants.caret.explosion_rects.len() as u16 {
|
|
|
|
self.cond.set_alive(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-21 05:27:26 +00:00
|
|
|
CaretType::LittleParticles => {
|
|
|
|
if self.anim_num == 0 {
|
2020-09-05 04:43:14 +00:00
|
|
|
match self.direction {
|
2020-08-21 05:27:26 +00:00
|
|
|
Direction::Left => {
|
2021-12-02 05:57:44 +00:00
|
|
|
self.vel_x = rng.range(-0x600..0x600) as i32;
|
|
|
|
self.vel_y = rng.range(-0x200..0x200) as i32;
|
2020-08-21 05:27:26 +00:00
|
|
|
}
|
|
|
|
Direction::Up => {
|
2021-01-01 01:46:01 +00:00
|
|
|
self.vel_y = rng.range(-3..-1) as i32 * 0x200;
|
2020-08-21 05:27:26 +00:00
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
self.anim_num += 1;
|
|
|
|
|
2020-09-05 04:43:14 +00:00
|
|
|
if self.direction == Direction::Left {
|
2020-08-21 05:27:26 +00:00
|
|
|
self.vel_x = (self.vel_x * 4) / 5;
|
|
|
|
self.vel_y = (self.vel_y * 4) / 5;
|
|
|
|
}
|
|
|
|
|
|
|
|
self.x += self.vel_x;
|
|
|
|
self.y += self.vel_y;
|
|
|
|
|
2020-10-30 13:50:10 +00:00
|
|
|
self.anim_counter += 1;
|
|
|
|
if self.anim_counter > 20 {
|
2020-09-05 04:43:14 +00:00
|
|
|
self.cond.set_alive(false);
|
2020-08-21 05:27:26 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-09-12 00:42:44 +00:00
|
|
|
let len = constants.caret.little_particles_rects.len();
|
|
|
|
self.anim_rect = constants.caret.little_particles_rects[self.anim_num as usize / 2 % len];
|
2020-08-21 05:27:26 +00:00
|
|
|
|
2020-09-05 04:43:14 +00:00
|
|
|
if self.direction == Direction::Right {
|
2021-05-05 16:34:23 +00:00
|
|
|
self.x -= 0x800;
|
2020-08-21 05:27:26 +00:00
|
|
|
}
|
|
|
|
}
|
2020-08-20 18:31:47 +00:00
|
|
|
CaretType::Unknown => {
|
|
|
|
// not implemented because it was apparently broken in og game?
|
2020-09-05 04:43:14 +00:00
|
|
|
self.cond.set_alive(false);
|
2020-08-20 18:31:47 +00:00
|
|
|
}
|
2022-01-27 04:56:32 +00:00
|
|
|
CaretType::SmallProjectileDissipation => {
|
|
|
|
self.anim_counter += 1;
|
|
|
|
if self.anim_counter > 2 {
|
|
|
|
self.anim_counter = 0;
|
|
|
|
|
|
|
|
self.anim_num += 1;
|
|
|
|
if self.anim_num > 3 {
|
|
|
|
self.cond.set_alive(false);
|
|
|
|
self.anim_num = 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
self.anim_rect = constants.caret.small_projectile_dissipation[self.anim_num as usize];
|
|
|
|
}
|
|
|
|
CaretType::EmptyText => {
|
|
|
|
self.anim_counter += 1;
|
|
|
|
|
|
|
|
if self.anim_counter < 10 {
|
|
|
|
self.y -= 0x400;
|
|
|
|
}
|
|
|
|
|
|
|
|
if self.anim_counter == 40 {
|
|
|
|
self.cond.set_alive(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
self.anim_rect = constants.caret.empty_text[self.anim_counter as usize / 2 % 2];
|
|
|
|
}
|
|
|
|
// Completely unused but whatever
|
|
|
|
CaretType::PushJumpKey => {
|
|
|
|
self.anim_counter += 1;
|
|
|
|
|
|
|
|
if self.anim_counter >= 40 {
|
|
|
|
self.anim_counter = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
self.anim_rect = constants.caret.push_jump_key[if self.anim_counter < 30 { 1 } else { 0 }];
|
|
|
|
}
|
2020-08-20 18:31:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-05 04:43:14 +00:00
|
|
|
#[inline]
|
2020-08-20 18:31:47 +00:00
|
|
|
pub fn is_dead(&self) -> bool {
|
2020-09-05 04:43:14 +00:00
|
|
|
!self.cond.alive()
|
2020-08-20 18:31:47 +00:00
|
|
|
}
|
|
|
|
}
|