1
0
Fork 0
mirror of https://github.com/doukutsu-rs/doukutsu-rs synced 2024-11-16 02:43:02 +00:00
doukutsu-rs/src/common.rs

374 lines
12 KiB
Rust
Raw Normal View History

use std::cmp::Ordering;
2020-12-06 14:50:31 +00:00
use std::fmt;
use lazy_static::lazy_static;
2020-09-11 00:55:07 +00:00
use num_traits::{AsPrimitive, Num};
2020-12-06 14:50:31 +00:00
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use serde::de::{SeqAccess, Visitor};
use serde::ser::SerializeTupleStruct;
2020-08-18 16:46:07 +00:00
2020-08-31 18:33:01 +00:00
use crate::bitfield;
2020-11-01 19:05:29 +00:00
/// Multiply cave story degrees (0-255, which corresponds to 0°-360°) with this to get
/// respective value in radians.
2020-11-17 10:46:51 +00:00
pub const CDEG_RAD: f64 = std::f64::consts::PI / 128.0;
lazy_static! {
pub static ref VERSION_BANNER: String = {
let version = option_env!("DRS_BUILD_VERSION_OVERRIDE").unwrap_or(env!("CARGO_PKG_VERSION"));
format!("doukutsu-rs {}", version)
};
}
2020-11-01 19:05:29 +00:00
2020-08-31 18:33:01 +00:00
bitfield! {
2020-09-11 16:30:18 +00:00
#[derive(Clone, Copy)]
2020-09-04 23:08:33 +00:00
pub struct Flag(u32);
2020-08-31 18:33:01 +00:00
impl Debug;
2020-12-06 23:42:19 +00:00
/// Set if left wall was hit. (corresponds to flag & 0x01)
pub hit_left_wall, set_hit_left_wall: 0;
/// Set if top wall was hit. (corresponds to flag & 0x02)
pub hit_top_wall, set_hit_top_wall: 1;
/// Set if right wall was hit. (corresponds to flag & 0x04)
pub hit_right_wall, set_hit_right_wall: 2;
/// Set if bottom wall was hit. (corresponds to flag & 0x08)
pub hit_bottom_wall, set_hit_bottom_wall: 3;
/// Set if entity stays on right slope. (corresponds to flag & 0x10)
pub hit_right_slope, set_hit_right_slope: 4;
/// Set if entity stays on left slope. (corresponds to flag & 0x20)
pub hit_left_slope, set_hit_left_slope: 5;
/// Unknown purpose (corresponds to flag & 0x40)
pub flag_x40, set_flag_x40: 6;
/// Unknown purpose (corresponds to flag & 0x80)
pub flag_x80, set_flag_x80: 7;
/// Set if entity is in water. (corresponds to flag & 0x100)
pub in_water, set_in_water: 8;
pub weapon_hit_block, set_weapon_hit_block: 9; // 0x200
2020-08-31 18:33:01 +00:00
pub hit_by_spike, set_hit_by_spike: 10; // 0x400
pub water_splash_facing_right, set_water_splash_facing_right: 11; // 0x800
pub force_left, set_force_left: 12; // 0x1000
pub force_up, set_force_up: 13; // 0x2000
pub force_right, set_force_right: 14; // 0x4000
pub force_down, set_force_down: 15; // 0x8000
pub hit_left_bigger_half, set_hit_left_bigger_half: 16; // 0x10000
pub hit_left_smaller_half, set_hit_left_smaller_half: 17; // 0x20000
pub hit_right_smaller_half, set_hit_right_smaller_half: 18; // 0x40000
pub hit_right_bigger_half, set_hit_right_bigger_half: 19; // 0x80000
}
bitfield! {
2020-09-11 16:30:18 +00:00
#[derive(Clone, Copy)]
2020-09-04 23:08:33 +00:00
pub struct Equipment(u16);
2020-08-31 18:33:01 +00:00
impl Debug;
pub has_booster_0_8, set_booster_0_8: 0; // 0x01 / 0001
pub has_map, set_map: 1; // 0x02 / 0002
pub has_arms_barrier, set_arms_barrier: 2; // 0x04 / 0004
pub has_turbocharge, set_turbocharge: 3; // 0x08 / 0008
pub has_air_tank, set_air_tank: 4; // 0x10 / 0016
pub has_booster_2_0, set_booster_2_0: 5; // 0x20 / 0032
pub has_mimiga_mask, set_mimiga_mask: 6; // 0x40 / 0064
pub has_whimsical_star, set_whimsical_star: 7; // 0x080 / 0128
pub has_nikumaru, set_nikumaru: 8; // 0x100 / 0256
// for custom equips
pub unused_1, set_unused_1: 9; // 0x200 / 0512
pub unused_2, set_unused_2: 10; // 0x400 / 1024
pub unused_3, set_unused_3: 11; // 0x800 / 2048
pub unused_4, set_unused_4: 12; // 0x1000 / 4096
pub unused_5, set_unused_5: 13; // 0x2000 / 8192
// bit 14 and 15 aren't accessible via TSC without abusing overflows (won't work in strict mode)
pub unused_6, set_unused_6: 14; // 0x4000 / @384
pub unused_7, set_unused_7: 15; // 0x8000 / P768
2020-08-31 18:33:01 +00:00
}
bitfield! {
2020-09-11 16:30:18 +00:00
#[derive(Clone, Copy)]
2020-09-04 23:08:33 +00:00
pub struct Condition(u16);
2020-08-31 18:33:01 +00:00
impl Debug;
2020-08-31 19:46:03 +00:00
pub interacted, set_interacted: 0; // 0x01
pub hidden, set_hidden: 1; // 0x02
pub fallen, set_fallen: 2; // 0x04
pub explode_die, set_explode_die: 3; // 0x08
pub damage_boss, set_damage_boss: 4; // 0x10
pub increase_acceleration, set_increase_acceleration: 5; // 0x20
2020-08-31 19:46:03 +00:00
pub cond_x40, set_cond_x40: 6; // 0x40
pub alive, set_alive: 7; // 0x80
2020-11-01 19:05:29 +00:00
// engine specific flags
pub drs_boss, set_drs_boss: 15;
2020-08-31 18:33:01 +00:00
}
bitfield! {
#[derive(Clone, Copy, Serialize, Deserialize)]
pub struct ControlFlags(u16);
impl Debug;
pub tick_world, set_tick_world: 0; // 0x01
pub control_enabled, set_control_enabled: 1; // 0x02
pub interactions_disabled, set_interactions_disabled: 2; // 0x04
pub credits_running, set_credits_running: 3; // 0x08
2020-09-12 21:43:27 +00:00
// engine specific flags
pub friendly_fire, set_friendly_fire: 14;
2020-09-12 21:43:27 +00:00
pub wind, set_wind: 15;
}
2020-12-04 18:58:59 +00:00
bitfield! {
#[derive(Clone, Copy)]
pub struct BulletFlag(u16);
impl Debug;
pub flag_x01, set_flag_x01: 0; // 0x01
pub flag_x02, set_flag_x02: 1; // 0x02
pub flag_x04, set_flag_x04: 2; // 0x04
pub flag_x08, set_flag_x08: 3; // 0x08
pub flag_x10, set_flag_x10: 4; // 0x10
pub flag_x20, set_flag_x20: 5; // 0x20
pub flag_x40, set_flag_x40: 6; // 0x40
pub flag_x80, set_flag_x80: 7; // 0x80
}
2020-08-18 16:46:07 +00:00
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2020-08-28 01:41:14 +00:00
#[repr(u8)]
pub enum FadeDirection {
Left = 0,
Up,
Right,
Down,
Center,
}
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 }
}
}
2020-09-05 01:14:58 +00:00
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 }
}
}
2020-08-28 01:41:14 +00:00
}
#[derive(Debug, PartialEq, Copy, Clone)]
#[repr(u8)]
pub enum FadeState {
Visible,
FadeIn(i8, FadeDirection),
Hidden,
FadeOut(i8, FadeDirection),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
2020-08-18 16:46:07 +00:00
pub enum Direction {
Left = 0,
2020-08-28 01:41:14 +00:00
Up,
Right,
Bottom,
2020-09-30 03:11:25 +00:00
FacingPlayer,
2020-08-18 16:46:07 +00:00
}
2020-08-29 06:59:46 +00:00
pub const FILE_TYPES: [&str; 3] = [".png", ".bmp", ".pbm"];
2020-08-18 16:46:07 +00:00
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 }
}
}
2020-08-20 18:31:47 +00:00
2020-09-30 03:11:25 +00:00
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 }
}
}
2020-08-20 18:31:47 +00:00
pub fn opposite(&self) -> Direction {
match self {
Direction::Left => { Direction::Right }
Direction::Up => { Direction::Bottom }
Direction::Right => { Direction::Left }
Direction::Bottom => { Direction::Up }
2020-09-30 03:11:25 +00:00
Direction::FacingPlayer => unreachable!(),
2020-08-20 18:31:47 +00:00
}
}
2020-08-23 02:17:24 +00:00
pub fn vector_x(&self) -> isize {
match self {
Direction::Left => { -1 }
Direction::Up => { 0 }
Direction::Right => { 1 }
Direction::Bottom => { 0 }
2020-09-30 03:11:25 +00:00
Direction::FacingPlayer => unreachable!(),
2020-08-23 02:17:24 +00:00
}
}
pub fn vector_y(&self) -> isize {
match self {
Direction::Left => { 0 }
Direction::Up => { -1 }
Direction::Right => { 0 }
Direction::Bottom => { 1 }
2020-09-30 03:11:25 +00:00
Direction::FacingPlayer => unreachable!(),
2020-08-23 02:17:24 +00:00
}
}
2020-08-18 16:46:07 +00:00
}
2020-12-06 14:50:31 +00:00
#[derive(Debug, Clone, Copy)]
pub struct Rect<T: Num + PartialOrd + Copy = isize> {
2020-08-18 16:46:07 +00:00
pub left: T,
pub top: T,
pub right: T,
pub bottom: T,
}
impl<T: Num + PartialOrd + Copy> Rect<T> {
2020-09-04 23:08:33 +00:00
pub fn new(left: T, top: T, right: T, bottom: T) -> Rect<T> {
2020-08-18 16:46:07 +00:00
Rect {
left,
top,
right,
bottom,
}
}
2020-09-04 23:08:33 +00:00
pub fn new_size(x: T, y: T, width: T, height: T) -> Rect<T> {
2020-08-18 16:46:07 +00:00
Rect {
left: x,
top: y,
right: x.add(width),
bottom: y.add(height),
}
}
pub fn from(rect: ggez::graphics::Rect) -> Rect<f32> {
2020-08-18 16:46:07 +00:00
Rect {
left: rect.x,
top: rect.y,
right: (rect.x + rect.w),
bottom: (rect.y + rect.h),
}
}
pub fn width(&self) -> T {
if let Some(Ordering::Greater) = self.left.partial_cmp(&self.right) {
self.left.sub(self.right)
} else {
self.right.sub(self.left)
}
}
pub fn height(&self) -> T {
if let Some(Ordering::Greater) = self.top.partial_cmp(&self.bottom) {
self.top.sub(self.bottom)
} else {
self.bottom.sub(self.top)
}
}
2020-08-18 16:46:07 +00:00
}
impl<T: Num + PartialOrd + Copy + AsPrimitive<f32>> Into<ggez::graphics::Rect> for Rect<T> {
fn into(self) -> ggez::graphics::Rect {
ggez::graphics::Rect::new(self.left.as_(),
self.top.as_(),
self.width().as_(),
self.height().as_())
}
}
2020-10-29 22:14:53 +00:00
2020-12-06 14:50:31 +00:00
impl<T: Num + PartialOrd + Copy + Serialize> Serialize for Rect<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_tuple_struct("Rect", 4)?;
state.serialize_field(&self.left)?;
state.serialize_field(&self.top)?;
state.serialize_field(&self.right)?;
state.serialize_field(&self.bottom)?;
state.end()
}
}
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>,
{
struct RectVisitor;
impl<'de> Visitor<'de> for RectVisitor {
type Value = Rect<$num_type>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("Expected Rect structure.")
}
fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
where
V: SeqAccess<'de>
{
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)?;
let right = seq.next_element()?.ok_or_else(invalid_length)?;
let bottom = seq.next_element()?.ok_or_else(invalid_length)?;
Ok(Rect { left, top, right, bottom })
}
}
deserializer.deserialize_tuple_struct("Rect", 4, RectVisitor)
}
}
};
}
rect_deserialze!(u8);
rect_deserialze!(u16);
rect_deserialze!(isize);
rect_deserialze!(usize);
2020-10-29 22:14:53 +00:00
#[inline(always)]
pub fn fix9_scale(val: isize, scale: f32) -> f32 {
(val as f64 * scale as f64 / 512.0).floor() as f32 / scale
}
#[inline(always)]
fn lerp_f64(v1: f64, v2: f64, t: f64) -> f64 {
v1 * (1.0 - t.fract()) + v2 * t.fract()
}
2020-11-07 17:17:01 +00:00
pub fn interpolate_fix9_scale(old_val: isize, val: isize, frame_delta: f64) -> f32 {
2020-11-14 01:24:32 +00:00
if (frame_delta - 1.0).abs() < 0.001 {
return (val / 0x200) as f32;
}
2020-11-07 17:17:01 +00:00
(lerp_f64(old_val as f64, val as f64, frame_delta) / 512.0) as f32
//((lerp_f64(old_val as f64, val as f64, frame_delta) * scale as f64 / 512.0).floor() / (scale as f64)) as f32
}