various memery

This commit is contained in:
Alula 2021-07-07 11:36:02 +02:00
parent e53944bcb5
commit e2c6ee8caf
No known key found for this signature in database
GPG Key ID: 3E00485503A1D8BA
5 changed files with 381 additions and 106 deletions

View File

@ -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<FadeDirection> {
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<Direction> {
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<Direction> {
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<T: Num + PartialOrd + Copy = isize> {
pub x: T,
pub y: T,
}
impl<T: Num + PartialOrd + Copy> Point<T> {
#[inline(always)]
pub fn new(x: T, y: T) -> Point<T> {
Point {
x,
y,
}
}
}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct Rect<T: Num + PartialOrd + Copy = isize> {
@ -274,21 +257,11 @@ pub struct Rect<T: Num + PartialOrd + Copy = isize> {
impl<T: Num + PartialOrd + Copy> Rect<T> {
pub fn new(left: T, top: T, right: T, bottom: T) -> Rect<T> {
Rect {
left,
top,
right,
bottom,
}
Rect { left, top, right, bottom }
}
pub fn new_size(x: T, y: T, width: T, height: T) -> Rect<T> {
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<T: Num + PartialOrd + Copy> Rect<T> {
impl<T: Num + PartialOrd + Copy + Serialize> Serialize for Rect<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
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<T: Num + PartialOrd + Copy + Serialize> Default for Rect<T> {
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<D>(deserializer: D) -> Result<Rect<$num_type>, D::Error>
where
D: Deserializer<'de>,
where
D: Deserializer<'de>,
{
struct RectVisitor;
@ -354,12 +327,10 @@ macro_rules! rect_deserialze {
}
fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
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.

View File

@ -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 <SSS1000 equivalent!!!!
state.quake_counter = 100;
state.npc_super_pos.1 = 1;
}
self.parts[0].action_counter += 1;
let idx = self.parts[0].get_closest_player_idx_mut(&players);
let mut npc = NPC::create(199, &state.npc_table);
npc.cond.set_alive(true);
npc.x = players[idx].x + self.parts[0].rng.range(-50..150) * 0x400;
npc.y = players[idx].y + self.parts[0].rng.range(-160..160) * 0x200;
let _ = npc_list.spawn(0x100, npc);
for player in players {
player.vel_x -= 0x20;
player.cond.set_increase_acceleration(true);
}
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;
}
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;
}
}

View File

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

View File

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

View File

@ -110,7 +110,7 @@ impl BasicPlayerSkin {
impl PlayerSkin for BasicPlayerSkin {
fn animation_frame_for(&self, state: PlayerAnimationState, direction: Direction, tick: u16) -> Rect<u16> {
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];