1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
use std::cmp;

use specs::{prelude::*, System};

use crate::{
    actions::Action,
    engine::components::{UnitComponent, UnitType},
    Player, Warrior,
};

pub struct PlayerSystem {
    pub player: Box<dyn Player + Send + Sync>,
}

impl PlayerSystem {
    pub fn new(player: impl Player + Send + Sync + 'static) -> PlayerSystem {
        PlayerSystem {
            player: Box::new(player),
        }
    }
}

impl<'a> System<'a> for PlayerSystem {
    type SystemData = (Entities<'a>, WriteStorage<'a, UnitComponent>);

    fn run(&mut self, (entities, mut units): Self::SystemData) {
        let mut all_units = (&entities, &mut units).join();
        let warrior_unit = all_units
            .find(|(_, comp)| comp.unit_type == UnitType::Warrior)
            .unwrap();
        let (_, mut warrior_comp) = warrior_unit;
        let sludge = all_units
            .by_ref()
            .find(|(_, comp)| comp.unit_type == UnitType::Sludge);
        let path_clear = {
            match &sludge {
                Some((_, sludge_comp)) => {
                    let (wx, _) = warrior_comp.position;
                    let (sx, _) = sludge_comp.position;
                    (wx - sx).abs() > 1
                }
                None => true,
            }
        };
        let mut warrior = Warrior::new(path_clear);
        self.player.play_turn(&mut warrior);

        if let Some(action) = warrior.action {
            match action {
                Action::Walk => {
                    if path_clear {
                        println!("Warrior walks forward");
                        let (x, y) = warrior_comp.position;
                        warrior_comp.position = (x + 1, y);
                    } else {
                        println!("Warrior bumps into Sludge");
                    }
                }
                Action::Attack => {
                    if path_clear {
                        println!("Warrior attacks and hits nothing");
                    } else {
                        match sludge {
                            Some((sludge_entity, sludge_comp)) => {
                                println!("Warrior attacks Sludge");
                                let (current, max) = sludge_comp.hp;
                                let remaining = cmp::max(current - warrior_comp.atk, 0);
                                println!(
                                    "Sludge takes {} damage, {} HP left",
                                    warrior_comp.atk, remaining
                                );
                                sludge_comp.hp = (remaining, max);

                                if remaining == 0 {
                                    println!("Sludge is dead!");
                                    entities.delete(sludge_entity).unwrap();
                                }
                            }
                            None => {
                                println!("Warrior attacks but there is nothing there");
                            }
                        }
                    }
                }
            }
        }
    }
}