use crate::server::components::PlanetSensor;
use crate::prelude::*;
use crate::shared::attachment::{PartInShip, Parts};
use crate::shared::config::planet::{Planet, PlanetResource};
use crate::shared::ecs::{Drill, Part, Player, SingleStorage, ToggleDrillEvent, VariableStorage};
pub fn drill_plugin(app: &mut App) {
app.add_systems(Update, (toggle_drill, drill_on_planet, do_drilling));
}
fn toggle_drill(
mut toggle_drill_reader: MessageReader<ToggleDrillEvent>,
mut drills: Query<&mut Drill>,
) {
for toggle_drill_event in toggle_drill_reader.read() {
// this getting of the drill also serves to check whether or not
// the entity is a drill
let Ok(mut drill) = drills.get_mut(toggle_drill_event.drill_entity) else { return };
drill.drilling = !drill.drilling;
}
}
fn drill_on_planet(
mut collision_start: MessageReader<CollisionStart>,
mut collision_end: MessageReader<CollisionEnd>,
planet_sensors: Query<&PlanetSensor>,
mut drills: Query<&mut Drill>,
) {
for event in collision_start.read() {
let (planet_sensor, mut drill) = if let (Ok(planet_sensor), Ok(drill)) = (planet_sensors.get(event.collider1), drills.get_mut(event.collider2)) {
(planet_sensor, drill)
} else if let (Ok(drill), Ok(planet_sensor)) = (drills.get_mut(event.collider1), planet_sensors.get(event.collider2)) {
(planet_sensor, drill)
} else {
continue
};
drill.on_planet = Some(planet_sensor.0.clone());
}
for event in collision_end.read() {
let (_, mut drill) = if let (Ok(planet_sensor), Ok(drill)) = (planet_sensors.get(event.collider1), drills.get_mut(event.collider2)) {
(planet_sensor, drill)
} else if let (Ok(drill), Ok(planet_sensor)) = (drills.get_mut(event.collider1), planet_sensors.get(event.collider2)) {
(planet_sensor, drill)
} else {
continue
};
drill.drilling = false;
drill.on_planet = None;
}
}
fn do_drilling(
drills: Query<(&Drill, &PartInShip)>,
hearty_drills: Query<(Entity, &Drill), With<Player>>,
parts_query: Query<&Parts>,
mut single_storage_part_query: Query<&mut SingleStorage, With<Part>>,
mut variable_storage_part_query: Query<&mut VariableStorage, With<Part>>,
planet_query: Query<&Planet>,
time: Res<Time>,
) {
for (entity, drill) in hearty_drills {
let Some(planet_resource) = find_drill_resource(drill, &planet_query) else { continue };
drill_into_parts(entity, drill, planet_resource, &parts_query, &mut single_storage_part_query, &time);
if let Ok(mut storage) = variable_storage_part_query.get_mut(entity) {
let to_add = planet_resource.mining_speed * drill.resource_multiplier * time.delta_secs();
add_to_variable_storage(&mut storage, to_add, &planet_resource.name);
}
}
for (drill, part_in_ship) in drills {
let Some(planet_resource) = find_drill_resource(drill, &planet_query) else { continue };
drill_into_parts(part_in_ship.0, drill, planet_resource, &parts_query, &mut single_storage_part_query, &time);
}
}
fn find_drill_resource<'a>(drill: &Drill, planet_query: &'a Query<&Planet>) -> Option<&'a PlanetResource> {
if !drill.drilling { return None; }
let planet_name = drill.on_planet.as_ref()?;
planet_query.iter()
.find(|p| p.name == *planet_name)
.expect("In do_drilling, a planet name didn't match a planet")
.planet_resource.as_ref()
}
fn drill_into_parts(
ship_entity: Entity,
drill: &Drill,
planet_resource: &PlanetResource,
parts_query: &Query<&Parts>,
single_storage_query: &mut Query<&mut SingleStorage, With<Part>>,
time: &Time,
) {
let Ok(parts_list) = parts_query.get(ship_entity) else { return };
for part_entity in parts_list.iter() {
let Ok(mut storage) = single_storage_query.get_mut(part_entity) else { continue };
let to_add = planet_resource.mining_speed * drill.resource_multiplier * time.delta_secs();
add_to_single_storage(&mut storage, to_add, &planet_resource.name);
}
}
fn add_to_variable_storage(
storage: &mut VariableStorage,
to_add: f32,
resource_name: &String
) {
let total_stored = storage.resources.iter().fold(0.0, |acc, (_, resource)| *resource + acc);
if to_add + total_stored > storage.capacity {
return;
}
if let Some(amount) = storage.resources.get_mut(resource_name) {
*amount += to_add;
} else {
storage.resources.insert(resource_name.clone(), to_add);
}
}
fn add_to_single_storage(
storage: &mut SingleStorage,
to_add: f32,
resource_name: &String
) {
if storage.resource_name.is_empty() {
storage.resource_name = resource_name.clone();
}
// now that the name isn't empty, this will trigger
if storage.resource_name == *resource_name {
storage.stored += to_add;
storage.stored = storage.stored.min(storage.capacity);
return;
}
}