Energy recovery stat functional.

This commit is contained in:
Sam 2021-05-18 20:42:14 -05:00 committed by Marcel Märtens
parent 58bd51a9e8
commit 6790b71d53
10 changed files with 91 additions and 27 deletions

View File

@ -7,6 +7,10 @@ ItemDef(
stats: ( stats: (
protection: Invincible, protection: Invincible,
poise_resilience: Invincible, poise_resilience: Invincible,
energy_max: 9000,
energy_recovery: 9.0,
crit_chance: 1000.0,
stealth: 1000.0,
), ),
) )
), ),

View File

@ -56,6 +56,7 @@ pub struct AttackerInfo<'a> {
pub uid: Uid, pub uid: Uid,
pub energy: Option<&'a Energy>, pub energy: Option<&'a Energy>,
pub combo: Option<&'a Combo>, pub combo: Option<&'a Combo>,
pub inventory: Option<&'a Inventory>,
} }
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
@ -213,11 +214,13 @@ impl Attack {
} }
}, },
CombatEffect::EnergyReward(ec) => { CombatEffect::EnergyReward(ec) => {
if let Some(attacker_entity) = attacker.map(|a| a.entity) { if let Some(attacker) = attacker {
emit(ServerEvent::EnergyChange { emit(ServerEvent::EnergyChange {
entity: attacker_entity, entity: attacker.entity,
change: EnergyChange { change: EnergyChange {
amount: *ec as i32, amount: (*ec
* Energy::compute_energy_reward_mod(attacker.inventory))
as i32,
source: EnergySource::HitEnemy, source: EnergySource::HitEnemy,
}, },
}); });
@ -348,11 +351,13 @@ impl Attack {
} }
}, },
CombatEffect::EnergyReward(ec) => { CombatEffect::EnergyReward(ec) => {
if let Some(attacker_entity) = attacker.map(|a| a.entity) { if let Some(attacker) = attacker {
emit(ServerEvent::EnergyChange { emit(ServerEvent::EnergyChange {
entity: attacker_entity, entity: attacker.entity,
change: EnergyChange { change: EnergyChange {
amount: ec as i32, amount: (ec
* Energy::compute_energy_reward_mod(attacker.inventory))
as i32,
source: EnergySource::HitEnemy, source: EnergySource::HitEnemy,
}, },
}); });

View File

@ -1,4 +1,4 @@
use crate::comp::Body; use crate::comp::{self, Body, Inventory};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use specs::{Component, DerefFlaggedStorage}; use specs::{Component, DerefFlaggedStorage};
use specs_idvs::IdvStorage; use specs_idvs::IdvStorage;
@ -120,6 +120,24 @@ impl Energy {
self.base_max = amount; self.base_max = amount;
self.current = self.current.min(self.maximum); self.current = self.current.min(self.maximum);
} }
/// Computes the energy reward modifer from worn armor
pub fn compute_energy_reward_mod(inventory: Option<&Inventory>) -> f32 {
use comp::item::ItemKind;
// Starts with a value of 1.0 when summing the stats from each armor piece, and
// defaults to a value of 1.0 if no inventory is equipped
inventory.map_or(1.0, |inv| {
inv.equipped_items()
.filter_map(|item| {
if let ItemKind::Armor(armor) = &item.kind() {
Some(armor.get_energy_recovery())
} else {
None
}
})
.fold(1.0, |a, b| a + b)
})
}
} }
pub struct EnergyChange { pub struct EnergyChange {

View File

@ -28,23 +28,52 @@ impl Armor {
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
pub struct Stats { pub struct Stats {
#[serde(default)]
protection: Protection, protection: Protection,
#[serde(default)]
poise_resilience: Protection, poise_resilience: Protection,
#[serde(default)]
energy_max: u32,
#[serde(default)]
energy_recovery: f32,
#[serde(default)]
crit_chance: f32,
#[serde(default)]
stealth: f32,
} }
impl Stats { impl Stats {
// DO NOT USE UNLESS YOU KNOW WHAT YOU ARE DOING // DO NOT USE UNLESS YOU KNOW WHAT YOU ARE DOING
// Added for csv import of stats // Added for csv import of stats
pub fn new(protection: Protection, poise_resilience: Protection) -> Self { pub fn new(
protection: Protection,
poise_resilience: Protection,
energy_max: u32,
energy_recovery: f32,
crit_chance: f32,
stealth: f32,
) -> Self {
Self { Self {
protection, protection,
poise_resilience, poise_resilience,
energy_max,
energy_recovery,
crit_chance,
stealth,
} }
} }
pub fn get_protection(&self) -> Protection { self.protection } pub fn get_protection(&self) -> Protection { self.protection }
pub fn get_poise_resilience(&self) -> Protection { self.poise_resilience } pub fn get_poise_resilience(&self) -> Protection { self.poise_resilience }
pub fn get_energy_max(&self) -> u32 { self.energy_max }
pub fn get_energy_recovery(&self) -> f32 { self.energy_recovery }
pub fn get_crit_chance(&self) -> f32 { self.crit_chance }
pub fn get_stealth(&self) -> f32 { self.stealth }
} }
impl Sub<Stats> for Stats { impl Sub<Stats> for Stats {
@ -54,6 +83,10 @@ impl Sub<Stats> for Stats {
Self { Self {
protection: self.protection - other.protection, protection: self.protection - other.protection,
poise_resilience: self.poise_resilience - other.poise_resilience, poise_resilience: self.poise_resilience - other.poise_resilience,
energy_max: self.energy_max.saturating_sub(other.energy_max),
energy_recovery: self.energy_recovery - other.energy_recovery,
crit_chance: self.crit_chance - other.crit_chance,
stealth: self.stealth - other.stealth,
} }
} }
} }
@ -64,6 +97,10 @@ pub enum Protection {
Normal(f32), Normal(f32),
} }
impl Default for Protection {
fn default() -> Self { Self::Normal(0.0) }
}
impl Sub for Protection { impl Sub for Protection {
type Output = Self; type Output = Self;
@ -96,20 +133,20 @@ pub struct Armor {
} }
impl Armor { impl Armor {
pub fn new(kind: ArmorKind, protection: Protection, poise_resilience: Protection) -> Self { pub fn new(kind: ArmorKind, stats: Stats) -> Self { Self { kind, stats } }
Self {
kind,
stats: Stats {
protection,
poise_resilience,
},
}
}
pub fn get_protection(&self) -> Protection { self.stats.protection } pub fn get_protection(&self) -> Protection { self.stats.protection }
pub fn get_poise_resilience(&self) -> Protection { self.stats.poise_resilience } pub fn get_poise_resilience(&self) -> Protection { self.stats.poise_resilience }
pub fn get_energy_max(&self) -> u32 { self.stats.energy_max }
pub fn get_energy_recovery(&self) -> f32 { self.stats.energy_recovery }
pub fn get_crit_chance(&self) -> f32 { self.stats.crit_chance }
pub fn get_stealth(&self) -> f32 { self.stats.stealth }
#[cfg(test)] #[cfg(test)]
pub fn test_armor( pub fn test_armor(
kind: ArmorKind, kind: ArmorKind,

View File

@ -64,6 +64,8 @@ pub struct Stats {
pub power: f32, pub power: f32,
pub poise_strength: f32, pub poise_strength: f32,
pub speed: f32, pub speed: f32,
// Done for testing purposes, properly remove stat from weapons later
#[serde(skip)]
pub crit_chance: f32, pub crit_chance: f32,
pub crit_mult: f32, pub crit_mult: f32,
} }

View File

@ -198,6 +198,7 @@ impl<'a> System<'a> for Sys {
uid, uid,
energy: read_data.energies.get(entity), energy: read_data.energies.get(entity),
combo: read_data.combos.get(entity), combo: read_data.combos.get(entity),
inventory: read_data.inventories.get(entity),
}); });
let target_info = TargetInfo { let target_info = TargetInfo {

View File

@ -146,6 +146,7 @@ impl<'a> System<'a> for Sys {
uid: *uid, uid: *uid,
energy: read_data.energies.get(attacker), energy: read_data.energies.get(attacker),
combo: read_data.combos.get(attacker), combo: read_data.combos.get(attacker),
inventory: read_data.inventories.get(attacker),
}); });
let target_info = TargetInfo { let target_info = TargetInfo {

View File

@ -135,6 +135,7 @@ impl<'a> System<'a> for Sys {
uid, uid,
energy: read_data.energies.get(entity), energy: read_data.energies.get(entity),
combo: read_data.combos.get(entity), combo: read_data.combos.get(entity),
inventory: read_data.inventories.get(entity),
} }
}); });

View File

@ -194,6 +194,7 @@ impl<'a> System<'a> for Sys {
uid, uid,
energy: read_data.energies.get(entity), energy: read_data.energies.get(entity),
combo: read_data.combos.get(entity), combo: read_data.combos.get(entity),
inventory: read_data.inventories.get(entity),
}); });
let target_info = TargetInfo { let target_info = TargetInfo {

View File

@ -705,25 +705,18 @@ pub fn handle_explosion(server: &Server, pos: Vec3<f32>, explosion: Explosion, o
RadiusEffect::Attack(attack) => { RadiusEffect::Attack(attack) => {
let energies = &ecs.read_storage::<comp::Energy>(); let energies = &ecs.read_storage::<comp::Energy>();
let combos = &ecs.read_storage::<comp::Combo>(); let combos = &ecs.read_storage::<comp::Combo>();
let inventories = &ecs.read_storage::<comp::Inventory>();
for ( for (
entity_b, entity_b,
pos_b, pos_b,
health_b, health_b,
( (body_b_maybe, stats_b_maybe, ori_b_maybe, char_state_b_maybe, uid_b),
body_b_maybe,
inventory_b_maybe,
stats_b_maybe,
ori_b_maybe,
char_state_b_maybe,
uid_b,
),
) in ( ) in (
&ecs.entities(), &ecs.entities(),
&ecs.read_storage::<comp::Pos>(), &ecs.read_storage::<comp::Pos>(),
&ecs.read_storage::<comp::Health>(), &ecs.read_storage::<comp::Health>(),
( (
ecs.read_storage::<comp::Body>().maybe(), ecs.read_storage::<comp::Body>().maybe(),
ecs.read_storage::<comp::Inventory>().maybe(),
ecs.read_storage::<comp::Stats>().maybe(), ecs.read_storage::<comp::Stats>().maybe(),
ecs.read_storage::<comp::Ori>().maybe(), ecs.read_storage::<comp::Ori>().maybe(),
ecs.read_storage::<comp::CharacterState>().maybe(), ecs.read_storage::<comp::CharacterState>().maybe(),
@ -767,12 +760,13 @@ pub fn handle_explosion(server: &Server, pos: Vec3<f32>, explosion: Explosion, o
uid, uid,
energy: energies.get(entity), energy: energies.get(entity),
combo: combos.get(entity), combo: combos.get(entity),
inventory: inventories.get(entity),
}); });
let target_info = combat::TargetInfo { let target_info = combat::TargetInfo {
entity: entity_b, entity: entity_b,
uid: *uid_b, uid: *uid_b,
inventory: inventory_b_maybe, inventory: inventories.get(entity_b),
stats: stats_b_maybe, stats: stats_b_maybe,
health: Some(health_b), health: Some(health_b),
pos: pos_b.0, pos: pos_b.0,