use crate::{
components::{PowerBar, PowerLevel, PowerRegeneration},
events::*,
limits::PowerLimits,
systems::*,
ui::{setup_power_ui, update_power_bar_ui},
};
use bevy::ecs::system::SystemParam;
use bevy::prelude::*;
pub struct PowerSystemPlugin;
impl Plugin for PowerSystemPlugin {
fn build(&self, app: &mut App) {
app.add_message::<SpendPowerEvent>()
.add_message::<PowerChangeEvent>()
.add_message::<ApplyLimitEvent>()
.add_message::<LiftLimitEvent>()
.add_message::<KnockedOutEvent>()
.add_message::<ReviveEvent>()
.add_message::<LevelUpEvent>();
app.configure_sets(
Update,
(
PowerSystemSet::Input,
PowerSystemSet::Update,
PowerSystemSet::UI,
)
.chain(),
);
app.add_systems(Startup, setup_power_ui);
app.add_systems(
Update,
(
(
handle_spend_power,
handle_power_change,
handle_apply_limit,
handle_lift_limit,
handle_revive,
)
.in_set(PowerSystemSet::Input),
(
regenerate_power,
update_limit_timers,
detect_knockout,
handle_level_up,
)
.in_set(PowerSystemSet::Update),
update_power_bar_ui.in_set(PowerSystemSet::UI),
),
);
}
}
#[derive(Bundle, Default)]
pub struct PowerBundle {
pub power_bar: PowerBar,
pub power_level: PowerLevel,
pub power_regeneration: PowerRegeneration,
pub power_limits: PowerLimits,
}
impl PowerBundle {
pub fn new() -> Self {
Self::default()
}
pub fn with_max_power(max_power: f32) -> Self {
Self {
power_bar: PowerBar::new(max_power),
..Default::default()
}
}
pub fn custom(
max_power: f32,
regen_delay: f32,
base_regen_rate: f32,
max_regen_rate: f32,
) -> Self {
Self {
power_bar: PowerBar::new(max_power),
power_level: PowerLevel::default(),
power_regeneration: PowerRegeneration {
regen_delay,
base_rate: base_regen_rate,
max_rate: max_regen_rate,
ramp_speed: 2.0,
..Default::default()
},
power_limits: PowerLimits::default(),
}
}
}
#[derive(SystemParam)]
pub struct PowerSystem<'w, 's> {
pub spend_events: MessageWriter<'w, SpendPowerEvent>,
pub change_events: MessageWriter<'w, PowerChangeEvent>,
pub limit_events: MessageWriter<'w, ApplyLimitEvent>,
pub lift_events: MessageWriter<'w, LiftLimitEvent>,
pub revive_events: MessageWriter<'w, ReviveEvent>,
pub power_query: Query<'w, 's, (Entity, &'static mut PowerBar, Option<&'static PowerLimits>)>,
}
impl<'w, 's> PowerSystem<'w, 's> {
fn get_power_entity(&self) -> Option<Entity> {
self.power_query.iter().next().map(|(entity, _, _)| entity)
}
pub fn can_afford(&self, amount: f32) -> bool {
if let Some(entity) = self.get_power_entity() {
if let Ok((_, power_bar, _)) = self.power_query.get(entity) {
return !power_bar.is_knocked_out && power_bar.current > amount;
}
}
false
}
pub fn try_spend(&mut self, amount: f32) -> bool {
if let Some(entity) = self.get_power_entity() {
if self.can_afford(amount) {
self.spend_events.write(SpendPowerEvent { entity, amount });
return true;
}
}
false
}
pub fn try_limit_points(
&mut self,
id: u32,
points: f32,
color: Color,
duration: Option<f32>,
resets_cooldown: bool,
) -> bool {
if let Some(entity) = self.get_power_entity() {
if let Ok((_, power_bar, limits)) = self.power_query.get(entity) {
let total_current_reduction = limits.map(|l| l.total_reduction()).unwrap_or(0.0);
let new_total_reduction = total_current_reduction + points;
let new_max = (power_bar.base_max - new_total_reduction).max(0.0);
let new_current = power_bar.current.min(new_max);
if new_max > 0.0 && new_current > 0.0 {
self.limit_events.write(ApplyLimitEvent::points(
entity,
id,
points,
color,
duration,
resets_cooldown,
));
return true;
}
}
}
false
}
pub fn try_limit_percentage(
&mut self,
id: u32,
percentage: f32,
color: Color,
duration: Option<f32>,
resets_cooldown: bool,
) -> bool {
if let Some(entity) = self.get_power_entity() {
if let Ok((_, power_bar, limits)) = self.power_query.get(entity) {
let percentage_points = power_bar.base_max * (percentage / 100.0);
let total_current_reduction = limits.map(|l| l.total_reduction()).unwrap_or(0.0);
let new_total_reduction = total_current_reduction + percentage_points;
let new_max = (power_bar.base_max - new_total_reduction).max(0.0);
let new_current = power_bar.current.min(new_max);
if new_max > 0.0 && new_current > 0.0 {
self.limit_events.write(ApplyLimitEvent::percentage(
entity,
id,
percentage,
color,
duration,
resets_cooldown,
));
return true;
}
}
}
false
}
pub fn spend(&mut self, amount: f32) {
if let Some(entity) = self.get_power_entity() {
self.spend_events.write(SpendPowerEvent { entity, amount });
}
}
pub fn change(&mut self, amount: f32) {
if let Some(entity) = self.get_power_entity() {
self.change_events
.write(PowerChangeEvent { entity, amount });
}
}
pub fn limit_points(
&mut self,
id: u32,
points: f32,
color: Color,
duration: Option<f32>,
resets_cooldown: bool,
) {
if let Some(entity) = self.get_power_entity() {
self.limit_events.write(ApplyLimitEvent::points(
entity,
id,
points,
color,
duration,
resets_cooldown,
));
}
}
pub fn limit_percentage(
&mut self,
id: u32,
percentage: f32,
color: Color,
duration: Option<f32>,
resets_cooldown: bool,
) {
if let Some(entity) = self.get_power_entity() {
self.limit_events.write(ApplyLimitEvent::percentage(
entity,
id,
percentage,
color,
duration,
resets_cooldown,
));
}
}
pub fn lift(&mut self, limit_id: u32) {
if let Some(entity) = self.get_power_entity() {
self.lift_events.write(LiftLimitEvent {
entity,
id: limit_id,
});
}
}
pub fn revive(&mut self, power_amount: f32) {
if let Some(entity) = self.get_power_entity() {
self.revive_events.write(ReviveEvent {
entity,
power_amount,
});
}
}
}