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
89
//! The game engine
//!
//! This module was formerly the home of a [specs][specs] implementation but is
//! now home to a zero-dependency version of the engine that functions almost
//! identically. It ended up being a little more straightforward when entities
//! did not need to be queried.
//!
//! When `start` is called, a mutable `World` instance is created. This keeps
//! track of things like the warrior's health and position, plus all enemy
//! units' health and position as well.
//!
//! Within the game's loop, mutable references to the `World` are handed to
//! various systems that live in the `systems` module and define a portion
//! of the game's logic.
//!
//! [specs]: https://github.com/slide-rs/specs

use std::{thread, time};

use crate::{floor::Floor, unit::UnitType, Player};

pub mod systems;
pub mod world;

use systems::{player_system, shooter_system, sludge_system, ui_system};
use world::World;

/// The entry point for the engine, called by [`Game`](crate::game::Game)
pub fn start(
    player_name: String,
    warrior_level: usize,
    floor: Floor,
    player_generator: fn() -> Box<dyn Player + Send + Sync>,
) -> Result<(), String> {
    let player = player_generator();

    floor.draw();

    let mut step = 0;

    let mut warrior = None;
    let mut other_units = Vec::new();
    for unit in &floor.units {
        match unit.unit_type {
            UnitType::Warrior => {
                warrior = Some(unit.clone());
            }
            _ => {
                other_units.push(unit.clone());
            }
        }
    }
    let warrior = warrior.unwrap();

    let mut world = World::new(
        player_name,
        warrior_level,
        floor,
        player,
        warrior,
        other_units,
    );

    loop {
        step += 1;

        if step > 100 {
            return Err(format!(
                "{} seems to have gotten lost...",
                &world.player_name
            ));
        }

        let (current, _) = world.warrior.hp;
        if current == 0 {
            return Err(format!("{} died!", &world.player_name));
        }
        if world.warrior.position == world.floor.stairs {
            return Ok(());
        }

        player_system(&mut world);
        sludge_system(&mut world);
        shooter_system(&mut world);
        ui_system(&mut world);

        thread::sleep(time::Duration::from_millis(500));
    }
}