veloren/common/systems/src/stats.rs

228 lines
8.0 KiB
Rust
Raw Normal View History

use common::{
combat,
comp::{
2021-03-04 20:43:58 +00:00
self,
2022-11-17 02:28:19 +00:00
ability::Stance,
2022-05-28 23:41:31 +00:00
item::MaterialStatManifest,
skills::{GeneralSkill, Skill},
2023-02-07 18:02:26 +00:00
Body, CharacterState, Combo, Energy, Health, Inventory, Poise, Pos, SkillSet, Stats,
StatsModifier,
},
event::{EventBus, ServerEvent},
2021-05-05 13:54:24 +00:00
resources::{DeltaTime, EntitiesDiedLastTick, Time},
};
use common_ecs::{Job, Origin, Phase, System};
use specs::{
2022-05-28 23:41:31 +00:00
shred::ResourceId, Entities, Join, Read, ReadExpect, ReadStorage, SystemData, World, Write,
WriteStorage,
};
const ENERGY_REGEN_ACCEL: f32 = 1.0;
2023-02-07 18:02:26 +00:00
const SIT_ENERGY_REGEN_ACCEL: f32 = 2.5;
2020-12-16 23:30:33 +00:00
const POISE_REGEN_ACCEL: f32 = 2.0;
#[derive(SystemData)]
pub struct ReadData<'a> {
entities: Entities<'a>,
dt: Read<'a, DeltaTime>,
2021-02-27 19:55:06 +00:00
time: Read<'a, Time>,
server_bus: Read<'a, EventBus<ServerEvent>>,
positions: ReadStorage<'a, Pos>,
bodies: ReadStorage<'a, Body>,
char_states: ReadStorage<'a, CharacterState>,
2021-05-21 00:52:29 +00:00
inventories: ReadStorage<'a, Inventory>,
2022-05-28 23:41:31 +00:00
msm: ReadExpect<'a, MaterialStatManifest>,
}
/// This system kills players, levels them up, and regenerates energy.
#[derive(Default)]
pub struct Sys;
2021-03-08 11:13:59 +00:00
impl<'a> System<'a> for Sys {
type SystemData = (
ReadData<'a>,
WriteStorage<'a, Stats>,
WriteStorage<'a, SkillSet>,
WriteStorage<'a, Health>,
2020-12-10 00:32:24 +00:00
WriteStorage<'a, Poise>,
WriteStorage<'a, Energy>,
2021-02-27 19:55:06 +00:00
WriteStorage<'a, Combo>,
2021-05-05 13:54:24 +00:00
Write<'a, EntitiesDiedLastTick>,
);
const NAME: &'static str = "stats";
const ORIGIN: Origin = Origin::Common;
const PHASE: Phase = Phase::Create;
fn run(
2021-03-08 11:13:59 +00:00
_job: &mut Job<Self>,
(
read_data,
stats,
mut skill_sets,
mut healths,
2020-12-10 00:32:24 +00:00
mut poises,
mut energies,
2021-02-27 19:55:06 +00:00
mut combos,
2021-05-05 13:54:24 +00:00
mut entities_died_last_tick,
): Self::SystemData,
) {
2021-05-05 13:54:24 +00:00
entities_died_last_tick.0.clear();
let mut server_event_emitter = read_data.server_bus.emitter();
let dt = read_data.dt.0;
2020-07-05 12:39:28 +00:00
// Update stats
for (entity, stats, mut health, pos, mut energy, inventory) in (
&read_data.entities,
&stats,
&mut healths,
&read_data.positions,
&mut energies,
2021-05-21 00:52:29 +00:00
read_data.inventories.maybe(),
)
.join()
{
let set_dead = { health.should_die() && !health.is_dead };
if set_dead {
2021-05-05 13:54:24 +00:00
let cloned_entity = (entity, *pos);
entities_died_last_tick.0.push(cloned_entity);
server_event_emitter.emit(ServerEvent::Destroy {
entity,
cause: health.last_change,
});
health.is_dead = true;
}
let stat = stats;
2022-01-18 05:17:20 +00:00
if let Some(new_max) = health.needs_maximum_update(stat.max_health_modifiers) {
// Only call this if we need to since mutable access will trigger sending an
// update to the client.
2022-01-18 05:52:31 +00:00
health.update_internal_integer_maximum(new_max);
}
2022-01-18 05:17:20 +00:00
// Calculates energy scaling from stats and inventory
let energy_mods = StatsModifier {
add_mod: stat.max_energy_modifiers.add_mod
2022-05-28 23:41:31 +00:00
+ combat::compute_max_energy_mod(inventory, &read_data.msm),
2022-01-18 05:17:20 +00:00
mult_mod: stat.max_energy_modifiers.mult_mod,
};
2022-01-18 05:17:20 +00:00
if let Some(new_max) = energy.needs_maximum_update(energy_mods) {
// Only call this if we need to since mutable access will trigger sending an
// update to the client.
2022-01-18 05:52:31 +00:00
energy.update_internal_integer_maximum(new_max);
}
2020-07-05 12:39:28 +00:00
}
// Apply effects from leveling skills
for (mut skill_set, mut health, mut energy, body) in (
&mut skill_sets,
&mut healths,
&mut energies,
&read_data.bodies,
)
.join()
{
if skill_set.modify_health {
let health_level = skill_set
.skill_level(Skill::General(GeneralSkill::HealthIncrease))
.unwrap_or(0);
health.update_max_hp(*body, health_level);
skill_set.modify_health = false;
}
if skill_set.modify_energy {
let energy_level = skill_set
.skill_level(Skill::General(GeneralSkill::EnergyIncrease))
.unwrap_or(0);
energy.update_max_energy(*body, energy_level);
skill_set.modify_energy = false;
}
}
2020-12-10 00:32:24 +00:00
// Update energies and poises
2022-11-17 02:28:19 +00:00
for (entity, character_state, mut energy, mut poise) in (
&read_data.entities,
&read_data.char_states,
&mut energies,
&mut poises,
)
.join()
2020-07-05 12:39:28 +00:00
{
match character_state {
2023-02-07 18:02:26 +00:00
// Sitting accelerates recharging energy the most
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);
}
},
2020-06-13 11:35:31 +00:00
// Accelerate recharging energy.
2022-02-21 04:39:28 +00:00
CharacterState::Idle(_)
| CharacterState::Talk
| CharacterState::Dance
| CharacterState::Glide(_)
| CharacterState::Skate(_)
| CharacterState::GlideWield(_)
| CharacterState::Wielding(_)
| CharacterState::Equipping(_)
| CharacterState::Boost(_) => {
2023-02-07 18:02:26 +00:00
if energy.needs_regen() {
energy.regen(ENERGY_REGEN_ACCEL, dt);
2020-01-19 19:19:44 +00:00
}
2023-02-07 18:02:26 +00:00
if poise.needs_regen() {
poise.regen(POISE_REGEN_ACCEL, dt, *read_data.time);
2020-12-16 23:30:33 +00:00
}
},
2021-04-27 14:41:48 +00:00
// Ability use does not regen and sets the rate back to zero.
2022-02-21 04:39:28 +00:00
CharacterState::BasicMelee(_)
| CharacterState::DashMelee(_)
| CharacterState::LeapMelee(_)
2023-02-15 00:10:37 +00:00
| CharacterState::LeapShockwave(_)
2022-02-21 04:39:28 +00:00
| CharacterState::SpinMelee(_)
| CharacterState::ComboMelee(_)
| CharacterState::ComboMelee2(_)
| CharacterState::BasicRanged(_)
| CharacterState::Music(_)
| CharacterState::ChargedMelee(_)
| CharacterState::ChargedRanged(_)
| CharacterState::RepeaterRanged(_)
| CharacterState::Shockwave(_)
| CharacterState::BasicBeam(_)
| CharacterState::BasicAura(_)
| CharacterState::Blink(_)
2023-02-07 18:02:26 +00:00
| CharacterState::Climb(_)
2022-02-21 04:39:28 +00:00
| CharacterState::BasicSummon(_)
| CharacterState::SelfBuff(_)
| CharacterState::SpriteSummon(_)
2022-03-05 06:35:57 +00:00
| CharacterState::FinisherMelee(_)
2022-03-05 18:52:43 +00:00
| CharacterState::DiveMelee(_)
2022-03-06 01:02:08 +00:00
| CharacterState::RiposteMelee(_)
2022-11-17 02:28:19 +00:00
| CharacterState::RapidMelee(_) => {
2023-02-07 18:02:26 +00:00
if energy.needs_regen_rate_reset() {
energy.reset_regen_rate();
2020-01-19 19:19:44 +00:00
}
},
2021-04-10 03:40:20 +00:00
// Abilities that temporarily stall energy gain, but preserve regen_rate.
2022-02-21 04:39:28 +00:00
CharacterState::Roll(_)
| CharacterState::Wallrun(_)
| CharacterState::Stunned(_)
| CharacterState::BasicBlock(_)
| CharacterState::UseItem(_)
| CharacterState::SpriteInteract(_) => {},
}
}
2021-01-15 03:32:12 +00:00
2021-02-27 19:55:06 +00:00
// Decay combo
for (_, mut combo) in (&read_data.entities, &mut combos).join() {
2021-03-04 20:43:58 +00:00
if combo.counter() > 0
&& read_data.time.0 - combo.last_increase() > comp::combo::COMBO_DECAY_START
{
2021-02-27 19:55:06 +00:00
combo.reset();
}
}
}
}