From e2c6ee8caf7ee4c7a1b3d4d644cb6062583e0ab7 Mon Sep 17 00:00:00 2001 From: Alula <6276139+alula@users.noreply.github.com> Date: Wed, 7 Jul 2021 11:36:02 +0200 Subject: [PATCH] various memery --- src/common.rs | 125 ++++++----------- src/npc/boss/core.rs | 295 ++++++++++++++++++++++++++++++++++++++- src/npc/boss/mod.rs | 2 +- src/npc/mod.rs | 63 ++++++--- src/player/skin/basic.rs | 2 +- 5 files changed, 381 insertions(+), 106 deletions(-) diff --git a/src/common.rs b/src/common.rs index 7a5e563..2ea6afa 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,11 +1,10 @@ -use std::cmp::Ordering; use std::fmt; use lazy_static::lazy_static; use num_traits::{abs, Num}; -use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use serde::de::{SeqAccess, Visitor}; use serde::ser::SerializeTupleStruct; +use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use crate::bitfield; use crate::texture_set::G_MAG; @@ -153,22 +152,22 @@ pub enum FadeDirection { impl FadeDirection { pub fn from_int(val: usize) -> Option { match val { - 0 => { Some(FadeDirection::Left) } - 1 => { Some(FadeDirection::Up) } - 2 => { Some(FadeDirection::Right) } - 3 => { Some(FadeDirection::Down) } - 4 => { Some(FadeDirection::Center) } - _ => { None } + 0 => Some(FadeDirection::Left), + 1 => Some(FadeDirection::Up), + 2 => Some(FadeDirection::Right), + 3 => Some(FadeDirection::Down), + 4 => Some(FadeDirection::Center), + _ => None, } } pub fn opposite(&self) -> FadeDirection { match self { - FadeDirection::Left => { FadeDirection::Right } - FadeDirection::Up => { FadeDirection::Down } - FadeDirection::Right => { FadeDirection::Left } - FadeDirection::Down => { FadeDirection::Up } - FadeDirection::Center => { FadeDirection::Center } + FadeDirection::Left => FadeDirection::Right, + FadeDirection::Up => FadeDirection::Down, + FadeDirection::Right => FadeDirection::Left, + FadeDirection::Down => FadeDirection::Up, + FadeDirection::Center => FadeDirection::Center, } } } @@ -197,72 +196,56 @@ pub const FILE_TYPES: [&str; 3] = [".png", ".bmp", ".pbm"]; impl Direction { pub fn from_int(val: usize) -> Option { match val { - 0 => { Some(Direction::Left) } - 1 => { Some(Direction::Up) } - 2 => { Some(Direction::Right) } - 3 => { Some(Direction::Bottom) } - _ => { None } + 0 => Some(Direction::Left), + 1 => Some(Direction::Up), + 2 => Some(Direction::Right), + 3 => Some(Direction::Bottom), + _ => None, } } pub fn from_int_facing(val: usize) -> Option { match val { - 0 => { Some(Direction::Left) } - 1 => { Some(Direction::Up) } - 2 => { Some(Direction::Right) } - 3 => { Some(Direction::Bottom) } - 4 => { Some(Direction::FacingPlayer) } - _ => { None } + 0 => Some(Direction::Left), + 1 => Some(Direction::Up), + 2 => Some(Direction::Right), + 3 => Some(Direction::Bottom), + 4 => Some(Direction::FacingPlayer), + _ => None, } } pub fn opposite(&self) -> Direction { match self { - Direction::Left => { Direction::Right } - Direction::Up => { Direction::Bottom } - Direction::Right => { Direction::Left } - Direction::Bottom => { Direction::Up } + Direction::Left => Direction::Right, + Direction::Up => Direction::Bottom, + Direction::Right => Direction::Left, + Direction::Bottom => Direction::Up, Direction::FacingPlayer => unreachable!(), } } pub fn vector_x(&self) -> i32 { match self { - Direction::Left => { -1 } - Direction::Up => { 0 } - Direction::Right => { 1 } - Direction::Bottom => { 0 } + Direction::Left => -1, + Direction::Up => 0, + Direction::Right => 1, + Direction::Bottom => 0, Direction::FacingPlayer => unreachable!(), } } pub fn vector_y(&self) -> i32 { match self { - Direction::Left => { 0 } - Direction::Up => { -1 } - Direction::Right => { 0 } - Direction::Bottom => { 1 } + Direction::Left => 0, + Direction::Up => -1, + Direction::Right => 0, + Direction::Bottom => 1, Direction::FacingPlayer => unreachable!(), } } } -#[derive(Debug, Clone, Copy)] -pub struct Point { - pub x: T, - pub y: T, -} - -impl Point { - #[inline(always)] - pub fn new(x: T, y: T) -> Point { - Point { - x, - y, - } - } -} - #[derive(Debug, Clone, Copy)] #[repr(C)] pub struct Rect { @@ -274,21 +257,11 @@ pub struct Rect { impl Rect { pub fn new(left: T, top: T, right: T, bottom: T) -> Rect { - Rect { - left, - top, - right, - bottom, - } + Rect { left, top, right, bottom } } pub fn new_size(x: T, y: T, width: T, height: T) -> Rect { - Rect { - left: x, - top: y, - right: x.add(width), - bottom: y.add(height), - } + Rect { left: x, top: y, right: x.add(width), bottom: y.add(height) } } pub fn has_point(&self, x: T, y: T) -> bool { @@ -314,8 +287,8 @@ impl Rect { impl Serialize for Rect { fn serialize(&self, serializer: S) -> Result - where - S: Serializer, + where + S: Serializer, { let mut state = serializer.serialize_tuple_struct("Rect", 4)?; state.serialize_field(&self.left)?; @@ -332,7 +305,7 @@ impl Default for Rect { left: num_traits::zero(), top: num_traits::zero(), right: num_traits::zero(), - bottom: num_traits::zero() + bottom: num_traits::zero(), } } } @@ -341,8 +314,8 @@ macro_rules! rect_deserialze { ($num_type: ident) => { impl<'de> Deserialize<'de> for Rect<$num_type> { fn deserialize(deserializer: D) -> Result, D::Error> - where - D: Deserializer<'de>, + where + D: Deserializer<'de>, { struct RectVisitor; @@ -354,12 +327,10 @@ macro_rules! rect_deserialze { } fn visit_seq(self, mut seq: V) -> Result - where - V: SeqAccess<'de> + where + V: SeqAccess<'de>, { - let invalid_length = || { - de::Error::invalid_length(0, &self) - }; + let invalid_length = || de::Error::invalid_length(0, &self); let left = seq.next_element()?.ok_or_else(invalid_length)?; let top = seq.next_element()?.ok_or_else(invalid_length)?; @@ -395,11 +366,6 @@ fn lerp_f64(v1: f64, v2: f64, t: f64) -> f64 { v1 * (1.0 - t) + v2 * t } -#[inline(always)] -fn lerp_f32(v1: f32, v2: f32, t: f32) -> f32 { - v1 * (1.0 - t) + v2 * t -} - pub fn interpolate_fix9_scale(old_val: i32, val: i32, frame_delta: f64) -> f32 { if abs(old_val - val) > 0x1800 { return val as f32 / 512.0; @@ -412,7 +378,6 @@ pub fn interpolate_fix9_scale(old_val: i32, val: i32, frame_delta: f64) -> f32 { } } - /// A RGBA color in the `sRGB` color space represented as `f32`'s in the range `[0.0-1.0]` /// /// For convenience, [`WHITE`](constant.WHITE.html) and [`BLACK`](constant.BLACK.html) are provided. diff --git a/src/npc/boss/core.rs b/src/npc/boss/core.rs index 266f790..ccdd0c3 100644 --- a/src/npc/boss/core.rs +++ b/src/npc/boss/core.rs @@ -1,7 +1,300 @@ use crate::npc::boss::BossNPC; +use crate::npc::list::NPCList; +use crate::npc::NPC; +use crate::player::Player; +use crate::rng::RNG; +use crate::shared_game_state::SharedGameState; impl BossNPC { - pub(crate) fn tick_b04_core(&mut self) { + pub(crate) fn tick_b04_core(&mut self, state: &mut SharedGameState, players: [&mut Player; 2], npc_list: &NPCList) { + let mut flag = false; + // i will refactor that one day + #[allow(mutable_transmutes)] + let flash_counter: &mut u16 = unsafe { std::mem::transmute(&self.parts[19].action_counter3) }; + match self.parts[0].action_num { + 0 => { + self.parts[0].action_num = 10; + self.parts[0].exp = 1; + self.parts[0].cond.set_alive(true); + self.parts[0].npc_flags.0 = 0; + self.parts[0].npc_flags.set_show_damage(true); + self.parts[0].npc_flags.set_event_when_killed(true); + self.parts[0].npc_flags.set_ignore_solidity(true); + self.parts[0].npc_flags.set_invulnerable(true); + self.parts[0].life = 650; + self.hurt_sound[0] = 114; + self.parts[0].x = 0x9a000; + self.parts[0].y = 0x1c000; + self.parts[0].vel_x = 0; + self.parts[0].vel_y = 0; + self.parts[0].event_num = 1000; + + self.parts[4].cond.set_alive(true); + self.parts[4].action_num = 10; + + self.parts[5].cond.set_alive(true); + self.parts[5].action_num = 10; + + self.parts[8].cond.set_alive(true); + self.parts[8].npc_flags.0 = 0; + self.parts[8].npc_flags.set_ignore_solidity(true); + self.parts[8].npc_flags.set_invulnerable(true); + self.parts[8].display_bounds.left = 0; + self.parts[8].display_bounds.top = 0; + self.parts[8].hit_bounds.right = 0x5000; + self.parts[8].hit_bounds.top = 0x2000; + self.parts[8].hit_bounds.bottom = 0x2000; + self.parts[8].action_counter2 = 0; + + self.parts[9] = self.parts[8].clone(); + self.parts[9].hit_bounds.right = 0x4800; + self.parts[9].hit_bounds.top = 0x3000; + self.parts[9].hit_bounds.bottom = 0x3000; + self.parts[9].action_counter2 = 1; + + self.parts[10] = self.parts[8].clone(); + self.parts[10].hit_bounds.right = 0x5800; + self.parts[10].hit_bounds.top = 0x1000; + self.parts[10].hit_bounds.bottom = 0x1000; + self.parts[10].action_counter2 = 2; + + self.parts[11] = self.parts[8].clone(); + self.parts[11].cond.set_damage_boss(true); + self.parts[11].hit_bounds.right = 0x2800; + self.parts[11].hit_bounds.top = 0x2800; + self.parts[11].hit_bounds.bottom = 0x2800; + self.parts[11].action_counter2 = 3; + + self.parts[1].cond.set_alive(true); + self.parts[1].action_num = 10; + self.parts[1].npc_flags.set_shootable(true); + self.parts[1].npc_flags.set_ignore_solidity(true); + self.parts[1].npc_flags.set_invulnerable(true); + self.parts[1].life = 1000; + self.hurt_sound[1] = 54; + self.parts[1].hit_bounds.right = 0x3000; + self.parts[1].hit_bounds.top = 0x2000; + self.parts[1].hit_bounds.bottom = 0x2000; + self.parts[1].display_bounds.top = 0x2800; + self.parts[1].display_bounds.left = 0x4000; + self.parts[1].x = self.parts[0].x - 0x1000; + self.parts[1].y = self.parts[0].y - 0x8000; + + self.parts[2] = self.parts[1].clone(); + self.parts[2].x = self.parts[0].x + 0x2000; + self.parts[2].x = self.parts[0].y; + + self.parts[3] = self.parts[1].clone(); + self.parts[3].x = self.parts[0].x - 0x1000; + self.parts[3].x = self.parts[0].y + 0x8000; + + self.parts[6] = self.parts[1].clone(); + self.parts[6].x = self.parts[0].x - 0x6000; + self.parts[6].x = self.parts[0].y - 0x4000; + + self.parts[7] = self.parts[1].clone(); + self.parts[7].x = self.parts[0].x - 0x6000; + self.parts[7].x = self.parts[0].y + 0x4000; + } + 200 => { + self.parts[0].action_num = 201; + self.parts[0].action_counter = 0; + self.parts[11].npc_flags.set_shootable(false); + state.npc_super_pos.1 = 0; + + state.sound_manager.stop_sfx(40); + state.sound_manager.stop_sfx(41); + state.sound_manager.stop_sfx(58); + } + 201 => { + self.parts[0].target_x = self.parts[0].x; + self.parts[0].target_y = self.parts[0].y; + + self.parts[0].action_counter += 1; + if self.parts[0].action_counter > 400 { + self.parts[0].action_counter2 += 2; + + state.sound_manager.play_sfx(115); + + if self.parts[0].action_counter2 < 4 { + self.parts[0].action_num = 210; + } else { + self.parts[0].action_counter2 = 0; + self.parts[0].action_num = 220; + } + } + + self.parts[4].anim_num = 0; + self.parts[5].anim_num = 0; + + flag = true; + } + 210 | 211 => { + if self.parts[0].action_num == 210 { + self.parts[0].action_num = 211; + self.parts[0].action_counter = 0; + self.parts[0].action_counter2 = self.parts[0].life; + self.parts[11].npc_flags.set_shootable(true); + } + + let player = self.parts[0].get_closest_player_mut(players); + self.parts[0].target_x = player.x; + self.parts[0].target_y = player.y; + + if self.parts[0].shock > 0 { + *flash_counter += 1; + if (*flash_counter & 2) != 0 { + self.parts[4].anim_num = 0; + self.parts[5].anim_num = 0; + } else { + self.parts[4].anim_num = 1; + self.parts[5].anim_num = 1; + } + } else { + self.parts[4].anim_num = 0; + self.parts[5].anim_num = 0; + } + + self.parts[0].action_counter += 1; + if self.parts[0].action_counter % 100 == 1 { + state.npc_curly_counter = self.parts[0].rng.range(80..100) as u16; + state.npc_curly_target = (self.parts[11].x, self.parts[11].y) + } + + if self.parts[0].action_counter < 200 && self.parts[0].action_counter % 20 == 1 { + let mut npc = NPC::create(179, &state.npc_table); + npc.cond.set_alive(true); + npc.x = self.parts[0].x + self.parts[0].rng.range(-48..-16) * 0x200; + npc.y = self.parts[0].y + self.parts[0].rng.range(-64..64) * 0x200; + let _ = npc_list.spawn(0x100, npc); + } + + if self.parts[0].action_counter > 400 + || (self.parts[0].life as i32) < self.parts[0].action_counter2 as i32 - 200 + { + self.parts[0].action_num = 200; + self.parts[4].anim_num = 2; + self.parts[5].anim_num = 0; + + flag = true; + } + } + 220 | 221 => { + if self.parts[0].action_num == 220 { + self.parts[0].action_num = 221; + self.parts[0].action_counter = 0; + self.parts[11].npc_flags.set_shootable(true); + + // todo 0 { + *flash_counter += 1; + if (*flash_counter & 2) != 0 { + self.parts[4].anim_num = 0; + self.parts[5].anim_num = 0; + } else { + self.parts[4].anim_num = 1; + self.parts[5].anim_num = 1; + } + } else { + self.parts[4].anim_num = 0; + self.parts[5].anim_num = 0; + } + + if [300, 350, 400].contains(&self.parts[0].action_counter) { + state.sound_manager.play_sfx(101); + let mut npc = NPC::create(218, &state.npc_table); + let angle = 0.0f64; + npc.cond.set_alive(true); + npc.x = self.parts[0].x - 0x5000; + npc.y = self.parts[0].y; + npc.vel_x = (angle.cos() * -1536.0) as i32; + npc.vel_y = (angle.sin() * -1536.0) as i32; + + let _ = npc_list.spawn(0x100, npc); + } else if self.parts[0].action_counter > 400 { + self.parts[0].action_num = 200; + self.parts[4].anim_num = 2; + self.parts[5].anim_num = 0; + + flag = true; + } + } + _ => {} + } + + if flag { + state.quake_counter = 20; + state.sound_manager.play_sfx(26); + + self.parts[1].action_num = 100; + self.parts[2].action_num = 100; + self.parts[3].action_num = 100; + self.parts[6].action_num = 100; + self.parts[7].action_num = 100; + + let mut npc = NPC::create(4, &state.npc_table); + npc.cond.set_alive(true); + npc.y = self.parts[4].y; + for _ in 0..8 { + npc.x = self.parts[4].x + self.parts[0].rng.range(-32..16) * 0x200; + npc.vel_x = self.parts[0].rng.range(-0x200..0x200); + npc.vel_y = self.parts[0].rng.range(-0x100..0x100); + npc_list.spawn(0x100, npc.clone()); + } + } + + if self.parts[0].action_num >= 200 && self.parts[0].action_num < 300 { + if self.parts[0].action_counter == 140 { + self.parts[3].action_num = 120; + } else if self.parts[0].action_counter == 170 { + self.parts[6].action_num = 120; + } else if self.parts[0].action_counter == 200 { + self.parts[7].action_num = 120; + } else if self.parts[0].action_counter == 80 { + self.parts[1].action_num = 120; + } else if self.parts[0].action_counter == 110 { + self.parts[2].action_num = 120; + } + + if self.parts[0].x < self.parts[0].target_x + 0x14000 { + self.parts[0].vel_x += 4; + } + + if self.parts[0].x > self.parts[0].target_x + 0x14000 { + self.parts[0].vel_x -= 4; + } + + if self.parts[0].y < self.parts[0].target_y { + self.parts[0].vel_y += 4; + } + + if self.parts[0].y > self.parts[0].target_y { + self.parts[0].vel_y -= 4; + } + } + + self.parts[0].vel_x = self.parts[0].vel_x.clamp(-0x100, 0x100); + self.parts[0].vel_y = self.parts[0].vel_y.clamp(-0x100, 0x100); + self.parts[0].x += self.parts[0].vel_x; + self.parts[0].y += self.parts[0].vel_y; } } diff --git a/src/npc/boss/mod.rs b/src/npc/boss/mod.rs index 7df214a..0cd7922 100644 --- a/src/npc/boss/mod.rs +++ b/src/npc/boss/mod.rs @@ -81,7 +81,7 @@ impl GameEntity<([&mut Player; 2], &NPCList, &mut Stage, &BulletManager, &mut Fl 1 => self.tick_b01_omega(state, players, npc_list, bullet_manager, flash), 2 => self.tick_b02_balfrog(state, players, npc_list), 3 => self.tick_b03_monster_x(state, players, npc_list, flash), - 4 => self.tick_b04_core(), + 4 => self.tick_b04_core(state, players, npc_list), 5 => self.tick_b05_ironhead(), 6 => self.tick_b06_twins(), 7 => self.tick_b07_undead_core(), diff --git a/src/npc/mod.rs b/src/npc/mod.rs index 15f9d32..2d9f0a8 100644 --- a/src/npc/mod.rs +++ b/src/npc/mod.rs @@ -1,13 +1,13 @@ use std::io; use std::io::Cursor; -use byteorder::{ReadBytesExt, LE}; +use byteorder::{LE, ReadBytesExt}; use num_traits::abs; use crate::bitfield; +use crate::common::{Condition, interpolate_fix9_scale, Rect}; use crate::common::Direction; use crate::common::Flag; -use crate::common::{interpolate_fix9_scale, Condition, Rect}; use crate::components::flash::Flash; use crate::components::number_popup::NumberPopup; use crate::entity::GameEntity; @@ -29,26 +29,41 @@ pub mod list; pub mod utils; bitfield! { - #[derive(Clone, Copy)] - pub struct NPCFlag(u16); - impl Debug; - - pub solid_soft, set_solid_soft: 0; // 0x01 - pub ignore_tile_44, set_ignore_tile_44: 1; // 0x02 - pub invulnerable, set_invulnerable: 2; // 0x04 - pub ignore_solidity, set_ignore_solidity: 3; // 0x08 - pub bouncy, set_bouncy: 4; // 0x10 - pub shootable, set_shootable: 5; // 0x20 - pub solid_hard, set_solid_hard: 6; // 0x40 - pub rear_and_top_not_hurt, set_rear_and_top_not_hurt: 7; // 0x80 - pub event_when_touched, set_event_when_touched: 8; // 0x100 - pub event_when_killed, set_event_when_killed: 9; // 0x200 - pub flag_x400, set_flag_x400: 10; // 0x400 - pub appear_when_flag_set, set_appear_when_flag_set: 11; // 0x800 - pub spawn_facing_right, set_spawn_facing_right: 12; // 0x1000 - pub interactable, set_interactable: 13; // 0x2000 - pub hide_unless_flag_set, set_hide_unless_flag_set: 14; // 0x4000 - pub show_damage, set_show_damage: 15; // 0x8000 + #[derive(Clone, Copy)] + pub struct NPCFlag(u16); + impl Debug; + /// Represented by 0x01 + pub solid_soft, set_solid_soft: 0; + /// Represented by 0x02 + pub ignore_tile_44, set_ignore_tile_44: 1; + /// Represented by 0x04 + pub invulnerable, set_invulnerable: 2; + /// Represented by 0x08 + pub ignore_solidity, set_ignore_solidity: 3; + /// Represented by 0x10 + pub bouncy, set_bouncy: 4; + /// Represented by 0x20 + pub shootable, set_shootable: 5; + /// Represented by 0x40 + pub solid_hard, set_solid_hard: 6; + /// Represented by 0x80 + pub rear_and_top_not_hurt, set_rear_and_top_not_hurt: 7; + /// Represented by 0x100 + pub event_when_touched, set_event_when_touched: 8; + /// Represented by 0x200 + pub event_when_killed, set_event_when_killed: 9; + /// Represented by 0x400 + pub flag_x400, set_flag_x400: 10; + /// Represented by 0x800 + pub appear_when_flag_set, set_appear_when_flag_set: 11; + /// Represented by 0x1000 + pub spawn_facing_right, set_spawn_facing_right: 12; + /// Represented by 0x2000 + pub interactable, set_interactable: 13; + /// Represented by 0x4000 + pub hide_unless_flag_set, set_hide_unless_flag_set: 14; + /// Represented by 0x8000 + pub show_damage, set_show_damage: 15; } #[derive(Debug, Copy, Clone, Eq, PartialOrd, PartialEq)] @@ -184,7 +199,9 @@ impl GameEntity<([&mut Player; 2], &NPCList, &mut Stage, &BulletManager, &mut Fl ) -> GameResult { let mut npc_hook_ran = false; #[cfg(feature = "scripting")] - { npc_hook_ran = state.lua.try_run_npc_hook(self.id, self.npc_type); } + { + npc_hook_ran = state.lua.try_run_npc_hook(self.id, self.npc_type); + } match self.npc_type { _ if npc_hook_ran => Ok(()), diff --git a/src/player/skin/basic.rs b/src/player/skin/basic.rs index f2c09af..09e56d8 100644 --- a/src/player/skin/basic.rs +++ b/src/player/skin/basic.rs @@ -110,7 +110,7 @@ impl BasicPlayerSkin { impl PlayerSkin for BasicPlayerSkin { fn animation_frame_for(&self, state: PlayerAnimationState, direction: Direction, tick: u16) -> Rect { - let frame_id = match self.state { + let frame_id = match state { PlayerAnimationState::Idle => 0u16, PlayerAnimationState::Walking => { const WALK_INDEXES: [u16; 4] = [1, 0, 2, 0];