use common::{
combat,
comp::{
self, item::MaterialStatManifest, CharacterState, Combo, Energy, Health, Inventory, Poise,
Stats, StatsModifier,
},
event::{DestroyEvent, EmitExt},
event_emitters,
resources::{DeltaTime, Time},
};
use common_ecs::{Job, Origin, Phase, System};
use specs::{shred, Entities, LendJoin, Read, ReadExpect, ReadStorage, SystemData, WriteStorage};
const ENERGY_REGEN_ACCEL: f32 = 1.0;
const SIT_ENERGY_REGEN_ACCEL: f32 = 2.5;
const POISE_REGEN_ACCEL: f32 = 2.0;
event_emitters! {
struct Events[Emitters] {
destroy: DestroyEvent,
}
}
#[derive(SystemData)]
pub struct ReadData<'a> {
entities: Entities<'a>,
dt: Read<'a, DeltaTime>,
time: Read<'a, Time>,
events: Events<'a>,
char_states: ReadStorage<'a, CharacterState>,
inventories: ReadStorage<'a, Inventory>,
msm: ReadExpect<'a, MaterialStatManifest>,
}
#[derive(Default)]
pub struct Sys;
impl<'a> System<'a> for Sys {
type SystemData = (
ReadData<'a>,
WriteStorage<'a, Stats>,
WriteStorage<'a, Health>,
WriteStorage<'a, Poise>,
WriteStorage<'a, Energy>,
WriteStorage<'a, Combo>,
);
const NAME: &'static str = "stats";
const ORIGIN: Origin = Origin::Common;
const PHASE: Phase = Phase::Create;
fn run(
_job: &mut Job<Self>,
(read_data, stats, mut healths, mut poises, mut energies, mut combos): Self::SystemData,
) {
let mut emitters = read_data.events.get_emitters();
let dt = read_data.dt.0;
let join = (
&read_data.entities,
&stats,
&mut healths,
&mut energies,
read_data.inventories.maybe(),
)
.lend_join();
join.for_each(|(entity, stats, mut health, mut energy, inventory)| {
let set_dead = { health.should_die() && !health.is_dead };
if set_dead {
emitters.emit(DestroyEvent {
entity,
cause: health.last_change,
});
}
let stat = stats;
if let Some(new_max) = health.needs_maximum_update(stat.max_health_modifiers) {
health.update_internal_integer_maximum(new_max);
}
let energy_mods = StatsModifier {
add_mod: stat.max_energy_modifiers.add_mod
+ combat::compute_max_energy_mod(inventory, &read_data.msm),
mult_mod: stat.max_energy_modifiers.mult_mod,
};
if let Some(new_max) = energy.needs_maximum_update(energy_mods) {
energy.update_internal_integer_maximum(new_max);
}
});
let join = (&read_data.char_states, &mut energies, &mut poises).lend_join();
join.for_each(|(character_state, mut energy, mut poise)| {
match character_state {
CharacterState::Sit => {
if energy.needs_regen() {
energy.regen(SIT_ENERGY_REGEN_ACCEL, dt);
}
if poise.needs_regen() {
poise.regen(POISE_REGEN_ACCEL, dt, *read_data.time);
}
},
CharacterState::Idle(_)
| CharacterState::Talk
| CharacterState::Dance
| CharacterState::Pet(_)
| CharacterState::Skate(_)
| CharacterState::Glide(_)
| CharacterState::GlideWield(_)
| CharacterState::Wielding(_)
| CharacterState::Equipping(_)
| CharacterState::Boost(_) => {
if energy.needs_regen() {
energy.regen(ENERGY_REGEN_ACCEL, dt);
}
if poise.needs_regen() {
poise.regen(POISE_REGEN_ACCEL, dt, *read_data.time);
}
},
CharacterState::BasicMelee(_)
| CharacterState::DashMelee(_)
| CharacterState::LeapMelee(_)
| CharacterState::LeapShockwave(_)
| CharacterState::ComboMelee2(_)
| CharacterState::BasicRanged(_)
| CharacterState::Music(_)
| CharacterState::ChargedMelee(_)
| CharacterState::ChargedRanged(_)
| CharacterState::RepeaterRanged(_)
| CharacterState::Shockwave(_)
| CharacterState::BasicBeam(_)
| CharacterState::BasicAura(_)
| CharacterState::Blink(_)
| CharacterState::Climb(_)
| CharacterState::BasicSummon(_)
| CharacterState::SelfBuff(_)
| CharacterState::SpriteSummon(_)
| CharacterState::FinisherMelee(_)
| CharacterState::DiveMelee(_)
| CharacterState::RiposteMelee(_)
| CharacterState::RapidMelee(_)
| CharacterState::StaticAura(_) => {
if energy.needs_regen_rate_reset() {
energy.reset_regen_rate();
}
},
CharacterState::Roll(_)
| CharacterState::Wallrun(_)
| CharacterState::Stunned(_)
| CharacterState::BasicBlock(_)
| CharacterState::UseItem(_)
| CharacterState::Transform(_)
| CharacterState::RegrowHead(_)
| CharacterState::SpriteInteract(_) => {},
}
});
(&read_data.entities, &mut combos)
.lend_join()
.for_each(|(_, mut combo)| {
if combo.counter() > 0
&& read_data.time.0 - combo.last_increase() > comp::combo::COMBO_DECAY_START
{
combo.reset();
}
});
}
}