use bevy::prelude::*;
use bevy_alchemy::{
AlchemyPlugin, Delay, EffectCommandsExt, EffectMode, EffectStacks, EffectTimer, Effecting,
Lifetime,
};
fn main() {
App::new()
.add_plugins((DefaultPlugins, AlchemyPlugin))
.add_systems(Startup, init_scene)
.add_systems(Update, (on_space_pressed, deal_poison_damage))
.add_systems(PostUpdate, update_ui)
.run();
}
#[derive(Component)]
struct Health(i32);
#[derive(Component, Default, Clone)]
struct Poison {
damage: i32,
}
fn init_scene(mut commands: Commands) {
commands.spawn((Name::new("Target"), Health(500)));
commands.spawn((
Node {
margin: UiRect::all(Val::Px(10.0)),
..default()
},
Text::default(),
));
commands.spawn(Camera2d);
}
fn on_space_pressed(
mut commands: Commands,
keyboard_input: Res<ButtonInput<KeyCode>>,
target: Single<Entity, With<Health>>,
) {
if !keyboard_input.just_pressed(KeyCode::Space) {
return;
}
commands.entity(*target).with_effect((
EffectMode::Merge, EffectStacks::default(), Lifetime::from_seconds(3.0), Delay::from_seconds(1.0) .trigger_immediately(), Poison { damage: 5 }, ));
}
fn deal_poison_damage(
effects: Query<(&Effecting, &EffectStacks, &Delay, &Poison)>,
mut targets: Query<&mut Health>,
) {
for (target, stacks, delay, poison) in effects {
if !delay.timer.is_finished() {
continue;
}
let Ok(mut health) = targets.get_mut(target.0) else {
continue;
};
let stacks = poison.damage.min(stacks.0 as i32); let sub = (stacks * (stacks - 1)) / 2;
let damage = poison.damage * stacks - sub;
info!("Dealt {damage} damage!");
health.0 -= damage;
}
}
fn update_ui(
mut ui: Single<&mut Text>,
target: Single<&Health>,
effects: Query<(Entity, &EffectStacks, &Lifetime, &Delay), With<Poison>>,
) {
ui.0 = "Press Space to apply poison\n\n".to_string();
ui.0 += &format!("Health: {}\n\n", target.0);
for (entity, stacks, lifetime, delay) in &effects {
ui.0 += &format!(
"{}, {} stacks - {:.1}s (tick in {:.1}s)\n",
entity,
stacks.0,
lifetime.timer.remaining_secs(),
delay.timer.remaining_secs()
);
}
}