use std::cell::RefCell;
use std::rc::Rc;
use crate::command::CommandV2;
use crate::commands::mr::objects::get_object_explosion;
use crate::commands::mr::objects::get_object_mini;
use crate::commands::mr::objects::get_object_sign_fail;
use crate::commands::mr::objects::get_object_sign_land;
use crate::commands::mr::objects::get_object_sign_success;
use crate::commands::mr::objects::get_object_sign_tryagain;
use crate::commands::mr::objects::get_object_spaceport;
use crate::commands::mr::objects::get_object_std;
use crate::engine_v2::collision::Collision;
use crate::engine_v2::collision::ScreenEdge;
use crate::engine_v2::coords::Coords;
use crate::engine_v2::engine::Engine;
use crate::engine_v2::entity::movement::Movement;
use crate::engine_v2::entity::object::Object;
use crate::engine_v2::entity::object::ObjectRef;
use crate::engine_v2::position::Position;
use crate::engine_v2::position::XTermPosition;
use crate::engine_v2::position::YTermPosition;
use crate::tools::get_terminal_size;
use crate::tools::parse_args;
use crossterm::event::KeyCode;
use rand::Rng;
pub struct Mr {
pub landed: Rc<RefCell<bool>>,
pub retry: Rc<RefCell<bool>>,
}
impl CommandV2 for Mr {
fn get_all_objects(&self) -> Vec<fn() -> ObjectRef> {
vec![get_object_std, get_object_mini, get_object_spaceport]
}
fn select_objects(
&mut self,
args: impl Iterator<Item = String>,
) -> (Vec<ObjectRef>, Vec<Collision>) {
let mut rng = rand::rng();
let term_size = get_terminal_size();
let landed_clone = self.landed.clone();
let retry_clone = self.retry.clone();
let mut object_list: Vec<ObjectRef> = Vec::new();
let rocket_speed: usize = 20;
let short_flags = ['f', 'r'];
let long_flags = ["force", "recursive"];
let params: &[&str] = &[];
let (flags, _) = parse_args(args.collect(), &short_flags, &long_flags, params);
let mut is_recursive = false;
if flags.contains("r") || flags.contains("recursive") {
is_recursive = true;
*retry_clone.borrow_mut() = true;
}
let end_sign_position = Movement::new_stationary(
Position::new(XTermPosition::Middle, YTermPosition::Middle, 0),
20,
);
let land_sign_object = get_object_sign_land();
let sign_position = Movement::new_stationary(
Position::new(XTermPosition::LeftIn, YTermPosition::TopIn, 0),
0,
);
land_sign_object
.borrow_mut()
.set_movement(sign_position.clone());
object_list.push(land_sign_object.clone());
let success_sign_object = get_object_sign_success();
success_sign_object
.borrow_mut()
.set_movement(end_sign_position.clone());
success_sign_object.borrow_mut().set_visible(false);
object_list.push(success_sign_object.clone());
let failed_sign_object = get_object_sign_fail();
failed_sign_object.borrow_mut().set_visible(false);
failed_sign_object
.borrow_mut()
.set_movement(end_sign_position.clone());
object_list.push(failed_sign_object.clone());
let tryagain_sign_object = get_object_sign_tryagain();
tryagain_sign_object.borrow_mut().set_visible(false);
tryagain_sign_object
.borrow_mut()
.set_movement(end_sign_position.clone());
object_list.push(tryagain_sign_object.clone());
let mut rocket_object: ObjectRef = get_object_mini();
if flags.contains("f") || flags.contains("force") {
rocket_object = get_object_std();
}
Object::on_key(&rocket_object, KeyCode::Char('d'), move |o| {
o.borrow_mut().movement().add_offset(Coords::new(1, 0, 0))
});
Object::on_key(&rocket_object, KeyCode::Right, move |o| {
o.borrow_mut().movement().add_offset(Coords::new(1, 0, 0))
});
Object::on_key(&rocket_object, KeyCode::Char('a'), move |o| {
o.borrow_mut().movement().add_offset(Coords::new(-1, 0, 0));
});
Object::on_key(&rocket_object, KeyCode::Left, move |o| {
o.borrow_mut().movement().add_offset(Coords::new(-1, 0, 0))
});
let movement = Movement::new_linear(
Position::new(XTermPosition::Middle, YTermPosition::TopOut, 0),
Position::new(XTermPosition::Middle, YTermPosition::Coord(-2), 0),
rocket_speed as i32,
);
rocket_object.borrow_mut().set_movement(movement);
object_list.push(rocket_object.clone());
let spaceport_object = get_object_spaceport();
let spaceport_x_position: i32 = rng.random_range(
0..(term_size.width() as i32)
- spaceport_object.borrow().current_frame().get_width() as i32,
);
let spaceport_position = Movement::new_stationary(
Position::new(
XTermPosition::Coord(spaceport_x_position),
YTermPosition::Coord(0),
0,
),
300,
);
spaceport_object
.borrow_mut()
.set_movement(spaceport_position);
object_list.push(spaceport_object.clone());
let explosion_object = get_object_explosion();
explosion_object.borrow_mut().set_visible(false);
let movement = Movement::new_stationary(
Position::new(XTermPosition::LeftIn, YTermPosition::TopIn, 0),
0,
);
explosion_object.borrow_mut().set_movement(movement);
object_list.push(explosion_object.clone());
let mut collision_list: Vec<Collision> = Vec::new();
let collision = Collision::new_object(
rocket_object.clone(),
spaceport_object.clone(),
move |rocket_object, _, counter, engine| {
let rocket_coord = rocket_object.borrow().coords();
let rocket_landed_traj = Movement::new_stationary(
Position::new(
XTermPosition::Coord(rocket_coord.x()),
YTermPosition::Coord(rocket_coord.y()),
0,
),
20,
);
rocket_object.borrow_mut().set_movement(rocket_landed_traj);
rocket_object.borrow_mut().set_frame_id(0);
rocket_object
.borrow_mut()
.compute_predefined_path(engine.terminal_size());
success_sign_object.borrow_mut().set_visible(true);
*landed_clone.borrow_mut() = true;
if counter >= 200 {
engine.stop();
}
},
);
collision_list.push(collision);
let collision_bottom = Collision::new_edge(
rocket_object.clone(),
ScreenEdge::Bottom,
move |rocket_object, counter, engine| {
if rocket_object.borrow().visible() && counter > rocket_speed {
rocket_object.borrow_mut().set_visible(false);
let rocket_coord = rocket_object.borrow_mut().coords();
let explosion_position = Movement::new_stationary(
Position::new(
XTermPosition::Coord(
rocket_coord.x()
- (explosion_object.borrow().current_frame().get_width() / 2)
as i32
+ (rocket_object.borrow().current_frame().get_width() / 2)
as i32,
),
YTermPosition::Coord(0),
0,
),
0,
);
explosion_object
.borrow_mut()
.set_movement(explosion_position);
explosion_object
.borrow_mut()
.compute_predefined_path(engine.terminal_size());
explosion_object.borrow_mut().set_visible(true);
explosion_object
.borrow_mut()
.reset_animation(engine.tick_id());
if is_recursive {
tryagain_sign_object.borrow_mut().set_visible(true);
} else {
failed_sign_object.borrow_mut().set_visible(true);
}
} else if counter > 500 {
engine.stop();
}
},
);
collision_list.push(collision_bottom);
(object_list, collision_list)
}
fn execute(&mut self) {
loop {
let (objects, collisions) = self.select_objects(std::env::args());
let mut engine = Engine::new(objects, collisions, 0);
engine.run();
if engine.is_killed() {
break;
}
if !*self.retry.borrow() {
break;
}
if *self.landed.borrow() {
break;
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::commands::mr::cli_v2::Mr;
#[test]
fn test_select_sprite_std() {
let mut mr = Mr {
landed: Rc::new(RefCell::new(false)),
retry: Rc::new(RefCell::new(false)),
};
let args: Vec<String> = vec![String::from("mr")];
let (objects, collisions) = mr.select_objects(args.into_iter());
assert_eq!(objects.len(), 7);
assert_eq!(objects[0].borrow_mut().movement().speed(), 0);
assert_eq!(objects[4].borrow_mut().tdid(), 14);
assert_eq!(objects[5].borrow_mut().tdid(), 18);
assert_eq!(collisions.len(), 2);
}
#[test]
fn test_select_sprite_force() {
let mut mr = Mr {
landed: Rc::new(RefCell::new(false)),
retry: Rc::new(RefCell::new(false)),
};
let args: Vec<String> = vec![String::from("mr"), String::from("-f")];
let (objects, collisions) = mr.select_objects(args.into_iter());
assert_eq!(objects.len(), 7);
assert_eq!(objects[0].borrow_mut().movement().speed(), 0);
assert_eq!(objects[4].borrow_mut().tdid(), 16);
assert_eq!(objects[5].borrow_mut().tdid(), 18);
assert_eq!(collisions.len(), 2);
}
#[test]
fn test_select_sprite_recursive() {
let mut mr = Mr {
landed: Rc::new(RefCell::new(false)),
retry: Rc::new(RefCell::new(true)),
};
let args: Vec<String> = vec![String::from("mr"), String::from("-r")];
let (objects, collisions) = mr.select_objects(args.into_iter());
assert_eq!(objects.len(), 7);
assert_eq!(objects[0].borrow_mut().movement().speed(), 0);
assert_eq!(objects[3].borrow_mut().tdid(), 23);
assert_eq!(collisions.len(), 2);
}
}