use num_traits::PrimInt;
use crate::enums::*;
#[inline]
pub fn just_changed_state(curr_state: u16, prev_state: u16) -> bool {
curr_state != prev_state
}
#[inline]
pub fn just_entered_state(target: ActionState, curr_state: u16, prev_state: u16) -> bool {
curr_state == target && prev_state != target
}
#[inline]
pub fn just_exited_state(target: ActionState, curr_state: u16, prev_state: u16) -> bool {
curr_state != target && prev_state == target
}
#[inline]
pub fn just_input_lcancel(current: u32, prev: u32) -> bool {
EngineInput::ANY_TRIGGER.contained_by(current) && !EngineInput::ANY_TRIGGER.contained_by(prev)
}
#[inline]
pub fn just_took_damage(curr_percent: f32, prev_percent: f32) -> bool {
curr_percent > prev_percent
}
#[inline]
pub fn get_damage_taken(curr_percent: f32, prev_percent: f32) -> f32 {
(curr_percent - prev_percent).max(0.0)
}
pub fn is_magnifying_damage(damage_taken: f32, flags: &[u64], index: usize) -> bool {
if damage_taken != 1.0 {
return false;
}
let min = index.saturating_sub(60);
for flagset in &flags[min..=index] {
if !Flags::OFFSCREEN.contained_by(*flagset) {
return false;
}
}
true
}
#[inline]
pub fn is_in_hitlag(flags: u64) -> bool {
Flags::HITLAG.contained_by(flags)
}
#[inline]
pub fn is_in_hitstun(flags: u64) -> bool {
Flags::HITSTUN.contained_by(flags)
}
#[inline]
pub fn is_in_defender_hitlag(flags: u64) -> bool {
Flags::DEFENDER_HITLAG.contained_by(flags)
}
#[inline]
pub fn is_in_magnifying_glass(flags: u64) -> bool {
Flags::OFFSCREEN.contained_by(flags)
}
#[inline]
pub fn is_shielding_flag(flags: u64) -> bool {
Flags::SHIELDING.contained_by(flags)
}
#[inline]
pub fn is_fastfalling(flags: u64) -> bool {
Flags::FASTFALL.contained_by(flags)
}
#[inline]
pub fn is_damaged(state: u16) -> bool {
ActionState::DAMAGED_RANGE.contains(&state)
|| ActionState::DAMAGE_FALL == state
|| ActionState::DOWN_DAMAGE_D == state
|| ActionState::DOWN_DAMAGE_U == state
|| ActionState::FLY_REFLECT_CEIL == state
|| ActionState::FLY_REFLECT_WALL == state
}
#[inline]
pub fn is_grabbed(state: u16) -> bool {
ActionState::CAPTURE_RANGE.contains(&state)
}
#[inline]
pub fn is_cmd_grabbed(state: u16) -> bool {
ActionState::BARREL_WAIT != state
&& (ActionState::CMD_GRAB_RANGE_1.contains(&state)
|| ActionState::CMD_GRAB_RANGE_2.contains(&state))
}
#[inline]
pub fn is_teching(state: u16) -> bool {
ActionState::TECH_RANGE.contains(&state)
|| ActionState::FLY_REFLECT_CEIL == state
|| ActionState::FLY_REFLECT_WALL == state
}
#[inline]
pub fn is_downed(state: u16) -> bool {
ActionState::DOWNED_RANGE.contains(&state)
}
#[inline]
pub fn is_thrown(state: u16) -> bool {
ActionState::THROWN_RANGE.contains(&state)
}
#[inline]
pub fn is_dying(state: u16) -> bool {
ActionState::DYING_RANGE.contains(&state)
}
#[inline]
pub fn is_dodging(state: u16) -> bool {
ActionState::DODGE_RANGE.contains(&state)
}
#[inline]
pub fn is_shielding(state: u16) -> bool {
ActionState::GUARD_RANGE.contains(&state)
}
#[inline]
pub fn is_shield_broken(state: u16) -> bool {
ActionState::GUARD_BREAK_RANGE.contains(&state)
}
#[inline]
pub fn is_ledge_action(state: u16) -> bool {
ActionState::LEDGE_ACTION_RANGE.contains(&state)
}
#[inline]
pub fn is_special_fall(state: u16) -> bool {
ActionState::SPECIAL_FALL_RANGE.contains(&state)
}
#[inline]
pub fn is_upb_lag(state: u16, prev_state: u16) -> bool {
state == ActionState::LAND_FALL_SPECIAL
&& prev_state != ActionState::LAND_FALL_SPECIAL
&& prev_state != ActionState::KNEE_BEND
&& prev_state != ActionState::ESCAPE_AIR
}
#[inline]
pub fn just_lost_stock(current: u8, prev: u8) -> bool {
current < prev
}
#[inline]
pub fn just_pressed_any<T: PrimInt>(
target: impl BitFlags<Other = T> + Buttons,
current: T,
prev: T,
) -> bool {
target.intersects(current) && !target.intersects(prev)
}
#[inline]
pub fn just_pressed_all<T: PrimInt>(
target: impl BitFlags<Other = T> + Buttons,
current: T,
prev: T,
) -> bool {
target.contained_by(current) && !target.contained_by(prev)
}
pub fn is_electric_attack(attack: Attack, character: &Character) -> bool {
match character {
Character::CaptainFalcon => attack == Attack::FAIR,
Character::DrMario => attack == Attack::F_SMASH,
Character::Falco | Character::Fox => attack == Attack::DOWN_SPECIAL,
Character::Ganondorf => [Attack::JAB_1, Attack::DAIR, Attack::UP_SPECIAL].contains(&attack),
Character::Mewtwo => [Attack::NAIR, Attack::PUMMEL].contains(&attack),
Character::Ness => [Attack::BAIR, Attack::DASH_ATTACK, Attack::FAIR].contains(&attack),
Character::Pichu => {
[Attack::DAIR, Attack::F_SMASH, Attack::PUMMEL, Attack::FAIR].contains(&attack)
}
Character::Pikachu => [
Attack::DAIR,
Attack::D_SMASH,
Attack::FAIR,
Attack::F_SMASH,
Attack::PUMMEL,
]
.contains(&attack),
Character::Samus => [
Attack::NON_STALING,
Attack::NEUTRAL_SPECIAL,
Attack::UP_SPECIAL,
]
.contains(&attack),
Character::Zelda => [
Attack::BAIR,
Attack::DASH_ATTACK,
Attack::FAIR,
Attack::F_SMASH,
Attack::JAB_1,
Attack::PUMMEL,
Attack::U_SMASH,
Attack::U_TILT,
]
.contains(&attack),
_ => false,
}
}
pub fn is_vcancel_state(state: u16) -> bool {
(ActionState::JUMP_F..=ActionState::DAMAGE_FALL).contains(&state)
|| state == ActionState::ESCAPE_AIR
}