#![allow(dead_code)]
use aeon_fighter::fighter::Action;
use aeon_fighter::geom::px;
use aeon_fighter::input::{Btn, Buttons, Chord, InputFrame};
use aeon_fighter::moves::MoveId;
use aeon_fighter::{CharacterId, DummyMode, EventKind, World};
pub fn idle() -> InputFrame {
InputFrame::default()
}
pub fn dir(d: u8) -> InputFrame {
InputFrame::dir(d)
}
pub fn press(b: Btn) -> InputFrame {
InputFrame::press(b)
}
pub fn dir_press(d: u8, b: Btn) -> InputFrame {
InputFrame::dir_press(d, b)
}
pub fn chord(c: Chord) -> InputFrame {
InputFrame::chord(c)
}
pub fn back() -> InputFrame {
dir(4)
}
pub fn down_back() -> InputFrame {
dir(1)
}
pub fn two(a: Btn, b: Btn) -> InputFrame {
InputFrame {
dir: 5,
buttons: Buttons::two(a, b),
}
}
pub fn tap(w: &mut World, p1: InputFrame) {
w.tick(p1, idle());
}
pub fn hold(w: &mut World, n: u32, p1: InputFrame) {
for _ in 0..n {
w.tick(p1, idle());
}
}
pub fn hold2(w: &mut World, n: u32, p1: InputFrame, p2: InputFrame) {
for _ in 0..n {
w.tick(p1, p2);
}
}
pub fn drain_hitstop(w: &mut World) {
while w.hitstop > 0 || w.rc_freeze > 0 {
w.tick(idle(), idle());
}
}
pub fn motion(w: &mut World, dirs: &[u8], b: Btn) {
for d in dirs {
w.tick(dir(*d), idle());
}
let last = *dirs.last().unwrap_or(&5);
w.tick(dir_press(last, b), idle());
}
pub fn buffered_special(w: &mut World, dirs: &[u8], b: Btn) {
let mut i = 0;
while !w.fighters[0].action.actionable() || w.hitstop > 0 {
w.tick(dir(dirs[i % dirs.len()]), idle());
i += 1;
}
let last = *dirs.last().unwrap_or(&5);
w.tick(dir_press(last, b), idle());
}
pub fn motion_p2(w: &mut World, dirs: &[u8], b: Btn) {
for d in dirs {
w.tick(idle(), dir(*d));
}
let last = *dirs.last().unwrap_or(&5);
w.tick(idle(), dir_press(last, b));
}
pub fn motion_chord(w: &mut World, dirs: &[u8], c: Chord) {
for d in dirs {
w.tick(dir(*d), idle());
}
let last = *dirs.last().unwrap_or(&5);
w.tick(
InputFrame {
dir: last,
buttons: Buttons::chord(c),
},
idle(),
);
}
pub fn close(p1: CharacterId, p2: CharacterId) -> World {
let mut w = World::training(p1, p2);
w.fighters[0].pos.x = px(370);
w.fighters[1].pos.x = px(408);
w.dummy = DummyMode::Stand;
w
}
pub fn close_kogan() -> World {
close(CharacterId::Kogan, CharacterId::Kogan)
}
pub fn free(p1: CharacterId, p2: CharacterId) -> World {
let mut w = close(p1, p2);
w.dummy = DummyMode::CpuOff;
w
}
pub fn attacking(w: &World, who: usize, id: MoveId) -> bool {
matches!(w.fighters[who].action, Action::Attack { move_id, .. } if move_id == id)
}
pub fn has_event(w: &World, kind: EventKind) -> bool {
w.events.iter().any(|e| e.kind == kind)
}
pub fn run_until(
w: &mut World,
max: u32,
p1: InputFrame,
p2: InputFrame,
pred: impl Fn(&World) -> bool,
) -> Option<u32> {
for i in 0..max {
w.tick(p1, p2);
if pred(w) {
return Some(i);
}
}
None
}
pub fn frames_until_actionable(w: &mut World, who: usize, max: u32) -> u32 {
for i in 0..max {
if w.fighters[who].action.actionable() && w.hitstop == 0 {
return i;
}
w.tick(idle(), idle());
}
max
}
pub fn knock_down_p2(w: &mut World) {
w.fighters[0].start_move(MoveId::CrST);
hold(w, 12, dir(2));
drain_hitstop(w);
assert!(
matches!(
w.fighters[1].action,
Action::Hit {
knockdown: true,
..
}
) || matches!(w.fighters[1].action, Action::Knockdown { .. }),
"sweep should knock down, got {}",
w.fighters[1].action.name()
);
}