use specs;
use specs::{ReadStorage, WriteStorage, Fetch};
use slog::Logger;
use types::*;
use super::CellDweller;
use Spatial;
use globe::Globe;
use globe::chunk::Material;
pub struct PhysicsSystem {
log: Logger,
pub seconds_between_falls: TimeDelta,
}
impl PhysicsSystem {
pub fn new(parent_log: &Logger, seconds_between_falls: TimeDelta) -> PhysicsSystem {
PhysicsSystem {
log: parent_log.new(o!()),
seconds_between_falls: seconds_between_falls,
}
}
fn maybe_fall(&self, cd: &mut CellDweller, globe: &Globe, dt: TimeDelta) {
if cd.pos.z <= 0 {
return;
}
let under_pos = cd.pos.with_z(cd.pos.z - 1);
let under_cell = globe.maybe_non_authoritative_cell(under_pos);
if under_cell.material == Material::Dirt {
cd.seconds_until_next_fall = self.seconds_between_falls;
return;
}
if cd.seconds_until_next_fall > 0.0 {
cd.seconds_until_next_fall = (cd.seconds_until_next_fall - dt).max(0.0);
}
let still_waiting_to_fall = cd.seconds_until_next_fall > 0.0;
if still_waiting_to_fall {
return;
}
cd.set_grid_point(under_pos);
cd.seconds_until_next_fall = self.seconds_between_falls;
trace!(self.log, "Fell under force of gravity"; "new_pos" => format!("{:?}", cd.pos()));
}
}
impl<'a> specs::System<'a> for PhysicsSystem {
type SystemData = (Fetch<'a, TimeDeltaResource>,
WriteStorage<'a, CellDweller>,
WriteStorage<'a, Spatial>,
ReadStorage<'a, Globe>);
fn run(&mut self, data: Self::SystemData) {
use specs::Join;
let (dt, mut cell_dwellers, mut spatials, globes) = data;
for (cd, spatial) in (&mut cell_dwellers, &mut spatials).join() {
let globe_entity = match cd.globe_entity {
Some(globe_entity) => globe_entity,
None => {
warn!(
self.log,
"There was no associated globe entity or it wasn't actually a Globe! Can't proceed!"
);
continue;
}
};
let globe = match globes.get(globe_entity) {
Some(globe) => globe,
None => {
warn!(
self.log,
"The globe associated with this CellDweller is not alive! Can't proceed!"
);
continue;
}
};
self.maybe_fall(cd, globe, dt.0);
if cd.is_real_space_transform_dirty() {
spatial.set_local_transform(cd.get_real_transform_and_mark_as_clean());
}
}
}
}