mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Addressed comments.
This commit is contained in:
parent
80954f3ba4
commit
be8df9aef6
@ -30,10 +30,17 @@ pub enum GroupTarget {
|
|||||||
OutOfGroup,
|
OutOfGroup,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct AttackerInfo<'a> {
|
||||||
|
pub entity: EcsEntity,
|
||||||
|
pub uid: Uid,
|
||||||
|
pub energy: Option<&'a Energy>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)] // TODO: Yeet clone derive
|
#[derive(Clone, Debug, Serialize, Deserialize)] // TODO: Yeet clone derive
|
||||||
pub struct Attack {
|
pub struct Attack {
|
||||||
damages: Vec<DamageComponent>,
|
damages: Vec<AttackDamage>,
|
||||||
effects: Vec<EffectComponent>,
|
effects: Vec<AttackEffect>,
|
||||||
crit_chance: f32,
|
crit_chance: f32,
|
||||||
crit_multiplier: f32,
|
crit_multiplier: f32,
|
||||||
}
|
}
|
||||||
@ -50,50 +57,48 @@ impl Default for Attack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Attack {
|
impl Attack {
|
||||||
pub fn with_damage(mut self, damage: DamageComponent) -> Self {
|
pub fn with_damage(mut self, damage: AttackDamage) -> Self {
|
||||||
self.damages.push(damage);
|
self.damages.push(damage);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_effect(mut self, effect: EffectComponent) -> Self {
|
pub fn with_effect(mut self, effect: AttackEffect) -> Self {
|
||||||
self.effects.push(effect);
|
self.effects.push(effect);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_crit(mut self, cc: f32, cm: f32) -> Self {
|
pub fn with_crit(mut self, crit_chance: f32, crit_multiplier: f32) -> Self {
|
||||||
self.crit_chance = cc;
|
self.crit_chance = crit_chance;
|
||||||
self.crit_multiplier = cm;
|
self.crit_multiplier = crit_multiplier;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn effects(&self) -> impl Iterator<Item = &EffectComponent> { self.effects.iter() }
|
pub fn effects(&self) -> impl Iterator<Item = &AttackEffect> { self.effects.iter() }
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn apply_attack(
|
pub fn apply_attack(
|
||||||
&self,
|
&self,
|
||||||
target_group: GroupTarget,
|
target_group: GroupTarget,
|
||||||
attacker_entity: Option<EcsEntity>,
|
attacker_info: Option<AttackerInfo>,
|
||||||
target_entity: EcsEntity,
|
target_entity: EcsEntity,
|
||||||
target_inventory: Option<&Inventory>,
|
target_inventory: Option<&Inventory>,
|
||||||
attacker_uid: Option<Uid>,
|
|
||||||
attacker_energy: Option<&Energy>,
|
|
||||||
dir: Dir,
|
dir: Dir,
|
||||||
target_dodging: bool,
|
target_dodging: bool,
|
||||||
// Currently just modifies damage, maybe look into modifying strength of other effects?
|
// Currently just modifies damage, maybe look into modifying strength of other effects?
|
||||||
strength_modifier: f32,
|
strength_modifier: f32,
|
||||||
) -> Vec<ServerEvent> {
|
mut emit: impl FnMut(ServerEvent),
|
||||||
|
) {
|
||||||
let is_crit = thread_rng().gen::<f32>() < self.crit_chance;
|
let is_crit = thread_rng().gen::<f32>() < self.crit_chance;
|
||||||
let mut accumulated_damage = 0.0;
|
let mut accumulated_damage = 0.0;
|
||||||
let mut server_events = Vec::new();
|
|
||||||
for damage in self
|
for damage in self
|
||||||
.damages
|
.damages
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|d| d.target.map_or(true, |t| t == target_group))
|
.filter(|d| d.target.map_or(true, |t| t == target_group))
|
||||||
.filter(|d| !(matches!(d.target, Some(GroupTarget::OutOfGroup)) && target_dodging))
|
.filter(|d| !(matches!(d.target, Some(GroupTarget::OutOfGroup)) && target_dodging))
|
||||||
{
|
{
|
||||||
let change = damage.damage.modify_damage(
|
let change = damage.damage.calculate_health_change(
|
||||||
target_inventory,
|
target_inventory,
|
||||||
attacker_uid,
|
attacker_info.map(|a| a.uid),
|
||||||
is_crit,
|
is_crit,
|
||||||
self.crit_multiplier,
|
self.crit_multiplier,
|
||||||
strength_modifier,
|
strength_modifier,
|
||||||
@ -101,24 +106,24 @@ impl Attack {
|
|||||||
let applied_damage = -change.amount as f32;
|
let applied_damage = -change.amount as f32;
|
||||||
accumulated_damage += applied_damage;
|
accumulated_damage += applied_damage;
|
||||||
if change.amount != 0 {
|
if change.amount != 0 {
|
||||||
server_events.push(ServerEvent::Damage {
|
emit(ServerEvent::Damage {
|
||||||
entity: target_entity,
|
entity: target_entity,
|
||||||
change,
|
change,
|
||||||
});
|
});
|
||||||
for effect in damage.effects.iter() {
|
for effect in damage.effects.iter() {
|
||||||
match effect {
|
match effect {
|
||||||
AttackEffect::Knockback(kb) => {
|
CombatEffect::Knockback(kb) => {
|
||||||
let impulse = kb.calculate_impulse(dir);
|
let impulse = kb.calculate_impulse(dir);
|
||||||
if !impulse.is_approx_zero() {
|
if !impulse.is_approx_zero() {
|
||||||
server_events.push(ServerEvent::Knockback {
|
emit(ServerEvent::Knockback {
|
||||||
entity: target_entity,
|
entity: target_entity,
|
||||||
impulse,
|
impulse,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
AttackEffect::EnergyReward(ec) => {
|
CombatEffect::EnergyReward(ec) => {
|
||||||
if let Some(attacker_entity) = attacker_entity {
|
if let Some(attacker_entity) = attacker_info.map(|a| a.entity) {
|
||||||
server_events.push(ServerEvent::EnergyChange {
|
emit(ServerEvent::EnergyChange {
|
||||||
entity: attacker_entity,
|
entity: attacker_entity,
|
||||||
change: EnergyChange {
|
change: EnergyChange {
|
||||||
amount: *ec as i32,
|
amount: *ec as i32,
|
||||||
@ -127,45 +132,55 @@ impl Attack {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
AttackEffect::Buff(b) => {
|
CombatEffect::Buff(b) => {
|
||||||
if thread_rng().gen::<f32>() < b.chance {
|
if thread_rng().gen::<f32>() < b.chance {
|
||||||
server_events.push(ServerEvent::Buff {
|
emit(ServerEvent::Buff {
|
||||||
entity: target_entity,
|
entity: target_entity,
|
||||||
buff_change: BuffChange::Add(
|
buff_change: BuffChange::Add(
|
||||||
b.to_buff(attacker_uid, applied_damage),
|
b.to_buff(attacker_info.map(|a| a.uid), applied_damage),
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
AttackEffect::Lifesteal(l) => {
|
CombatEffect::Lifesteal(l) => {
|
||||||
if let Some(attacker_entity) = attacker_entity {
|
if let Some(attacker_entity) = attacker_info.map(|a| a.entity) {
|
||||||
let change = HealthChange {
|
let change = HealthChange {
|
||||||
amount: (applied_damage * l) as i32,
|
amount: (applied_damage * l) as i32,
|
||||||
cause: HealthSource::Heal { by: attacker_uid },
|
cause: HealthSource::Heal {
|
||||||
|
by: attacker_info.map(|a| a.uid),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
server_events.push(ServerEvent::Damage {
|
if change.amount != 0 {
|
||||||
entity: attacker_entity,
|
emit(ServerEvent::Damage {
|
||||||
|
entity: attacker_entity,
|
||||||
|
change,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
CombatEffect::Poise(p) => {
|
||||||
|
let change = PoiseChange::from_value(*p, target_inventory);
|
||||||
|
if change.amount != 0 {
|
||||||
|
emit(ServerEvent::PoiseChange {
|
||||||
|
entity: target_entity,
|
||||||
change,
|
change,
|
||||||
|
kb_dir: *dir,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
AttackEffect::Poise(p) => {
|
CombatEffect::Heal(h) => {
|
||||||
let change = PoiseChange::from_attack(*p, target_inventory);
|
|
||||||
server_events.push(ServerEvent::PoiseChange {
|
|
||||||
entity: target_entity,
|
|
||||||
change,
|
|
||||||
kb_dir: *dir,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
AttackEffect::Heal(h) => {
|
|
||||||
let change = HealthChange {
|
let change = HealthChange {
|
||||||
amount: *h as i32,
|
amount: *h as i32,
|
||||||
cause: HealthSource::Heal { by: attacker_uid },
|
cause: HealthSource::Heal {
|
||||||
|
by: attacker_info.map(|a| a.uid),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
server_events.push(ServerEvent::Damage {
|
if change.amount != 0 {
|
||||||
entity: target_entity,
|
emit(ServerEvent::Damage {
|
||||||
change,
|
entity: target_entity,
|
||||||
});
|
change,
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -180,17 +195,24 @@ impl Attack {
|
|||||||
if match &effect.requirement {
|
if match &effect.requirement {
|
||||||
Some(CombatRequirement::AnyDamage) => accumulated_damage > 0.0,
|
Some(CombatRequirement::AnyDamage) => accumulated_damage > 0.0,
|
||||||
Some(CombatRequirement::SufficientEnergy(r)) => {
|
Some(CombatRequirement::SufficientEnergy(r)) => {
|
||||||
if attacker_energy.map_or(true, |e| e.current() >= *r) {
|
if let Some(AttackerInfo {
|
||||||
if let Some(attacker_entity) = attacker_entity {
|
entity,
|
||||||
server_events.push(ServerEvent::EnergyChange {
|
energy: Some(e),
|
||||||
entity: attacker_entity,
|
..
|
||||||
|
}) = attacker_info
|
||||||
|
{
|
||||||
|
let sufficient_energy = e.current() >= *r;
|
||||||
|
if sufficient_energy {
|
||||||
|
emit(ServerEvent::EnergyChange {
|
||||||
|
entity,
|
||||||
change: EnergyChange {
|
change: EnergyChange {
|
||||||
amount: -(*r as i32),
|
amount: -(*r as i32),
|
||||||
source: EnergySource::Ability,
|
source: EnergySource::Ability,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
true
|
|
||||||
|
sufficient_energy
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
@ -198,18 +220,18 @@ impl Attack {
|
|||||||
None => true,
|
None => true,
|
||||||
} {
|
} {
|
||||||
match effect.effect {
|
match effect.effect {
|
||||||
AttackEffect::Knockback(kb) => {
|
CombatEffect::Knockback(kb) => {
|
||||||
let impulse = kb.calculate_impulse(dir);
|
let impulse = kb.calculate_impulse(dir);
|
||||||
if !impulse.is_approx_zero() {
|
if !impulse.is_approx_zero() {
|
||||||
server_events.push(ServerEvent::Knockback {
|
emit(ServerEvent::Knockback {
|
||||||
entity: target_entity,
|
entity: target_entity,
|
||||||
impulse,
|
impulse,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
AttackEffect::EnergyReward(ec) => {
|
CombatEffect::EnergyReward(ec) => {
|
||||||
if let Some(attacker_entity) = attacker_entity {
|
if let Some(attacker_entity) = attacker_info.map(|a| a.entity) {
|
||||||
server_events.push(ServerEvent::EnergyChange {
|
emit(ServerEvent::EnergyChange {
|
||||||
entity: attacker_entity,
|
entity: attacker_entity,
|
||||||
change: EnergyChange {
|
change: EnergyChange {
|
||||||
amount: ec as i32,
|
amount: ec as i32,
|
||||||
@ -218,61 +240,70 @@ impl Attack {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
AttackEffect::Buff(b) => {
|
CombatEffect::Buff(b) => {
|
||||||
if thread_rng().gen::<f32>() < b.chance {
|
if thread_rng().gen::<f32>() < b.chance {
|
||||||
server_events.push(ServerEvent::Buff {
|
emit(ServerEvent::Buff {
|
||||||
entity: target_entity,
|
entity: target_entity,
|
||||||
buff_change: BuffChange::Add(
|
buff_change: BuffChange::Add(
|
||||||
b.to_buff(attacker_uid, accumulated_damage),
|
b.to_buff(attacker_info.map(|a| a.uid), accumulated_damage),
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
AttackEffect::Lifesteal(l) => {
|
CombatEffect::Lifesteal(l) => {
|
||||||
if let Some(attacker_entity) = attacker_entity {
|
if let Some(attacker_entity) = attacker_info.map(|a| a.entity) {
|
||||||
let change = HealthChange {
|
let change = HealthChange {
|
||||||
amount: (accumulated_damage * l) as i32,
|
amount: (accumulated_damage * l) as i32,
|
||||||
cause: HealthSource::Heal { by: attacker_uid },
|
cause: HealthSource::Heal {
|
||||||
|
by: attacker_info.map(|a| a.uid),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
server_events.push(ServerEvent::Damage {
|
if change.amount != 0 {
|
||||||
entity: attacker_entity,
|
emit(ServerEvent::Damage {
|
||||||
|
entity: attacker_entity,
|
||||||
|
change,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
CombatEffect::Poise(p) => {
|
||||||
|
let change = PoiseChange::from_value(p, target_inventory);
|
||||||
|
if change.amount != 0 {
|
||||||
|
emit(ServerEvent::PoiseChange {
|
||||||
|
entity: target_entity,
|
||||||
|
change,
|
||||||
|
kb_dir: *dir,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
CombatEffect::Heal(h) => {
|
||||||
|
let change = HealthChange {
|
||||||
|
amount: h as i32,
|
||||||
|
cause: HealthSource::Heal {
|
||||||
|
by: attacker_info.map(|a| a.uid),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
if change.amount != 0 {
|
||||||
|
emit(ServerEvent::Damage {
|
||||||
|
entity: target_entity,
|
||||||
change,
|
change,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
AttackEffect::Poise(p) => {
|
|
||||||
let change = PoiseChange::from_attack(p, target_inventory);
|
|
||||||
server_events.push(ServerEvent::PoiseChange {
|
|
||||||
entity: target_entity,
|
|
||||||
change,
|
|
||||||
kb_dir: *dir,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
AttackEffect::Heal(h) => {
|
|
||||||
let change = HealthChange {
|
|
||||||
amount: h as i32,
|
|
||||||
cause: HealthSource::Heal { by: attacker_uid },
|
|
||||||
};
|
|
||||||
server_events.push(ServerEvent::Damage {
|
|
||||||
entity: target_entity,
|
|
||||||
change,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
server_events
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct DamageComponent {
|
pub struct AttackDamage {
|
||||||
damage: Damage,
|
damage: Damage,
|
||||||
target: Option<GroupTarget>,
|
target: Option<GroupTarget>,
|
||||||
effects: Vec<AttackEffect>,
|
effects: Vec<CombatEffect>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DamageComponent {
|
impl AttackDamage {
|
||||||
pub fn new(damage: Damage, target: Option<GroupTarget>) -> Self {
|
pub fn new(damage: Damage, target: Option<GroupTarget>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
damage,
|
damage,
|
||||||
@ -281,21 +312,21 @@ impl DamageComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_effect(mut self, effect: AttackEffect) -> Self {
|
pub fn with_effect(mut self, effect: CombatEffect) -> Self {
|
||||||
self.effects.push(effect);
|
self.effects.push(effect);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct EffectComponent {
|
pub struct AttackEffect {
|
||||||
target: Option<GroupTarget>,
|
target: Option<GroupTarget>,
|
||||||
effect: AttackEffect,
|
effect: CombatEffect,
|
||||||
requirement: Option<CombatRequirement>,
|
requirement: Option<CombatRequirement>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EffectComponent {
|
impl AttackEffect {
|
||||||
pub fn new(target: Option<GroupTarget>, effect: AttackEffect) -> Self {
|
pub fn new(target: Option<GroupTarget>, effect: CombatEffect) -> Self {
|
||||||
Self {
|
Self {
|
||||||
target,
|
target,
|
||||||
effect,
|
effect,
|
||||||
@ -308,11 +339,11 @@ impl EffectComponent {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn effect(&self) -> &AttackEffect { &self.effect }
|
pub fn effect(&self) -> &CombatEffect { &self.effect }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub enum AttackEffect {
|
pub enum CombatEffect {
|
||||||
Heal(f32),
|
Heal(f32),
|
||||||
Buff(CombatBuff),
|
Buff(CombatBuff),
|
||||||
Knockback(Knockback),
|
Knockback(Knockback),
|
||||||
@ -368,7 +399,7 @@ impl Damage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn modify_damage(
|
pub fn calculate_health_change(
|
||||||
self,
|
self,
|
||||||
inventory: Option<&Inventory>,
|
inventory: Option<&Inventory>,
|
||||||
uid: Option<Uid>,
|
uid: Option<Uid>,
|
||||||
@ -377,7 +408,7 @@ impl Damage {
|
|||||||
damage_modifier: f32,
|
damage_modifier: f32,
|
||||||
) -> HealthChange {
|
) -> HealthChange {
|
||||||
let mut damage = self.value * damage_modifier;
|
let mut damage = self.value * damage_modifier;
|
||||||
let damage_reduction = inventory.map_or(0.0, |inv| Damage::compute_damage_reduction(inv));
|
let damage_reduction = inventory.map_or(0.0, Damage::compute_damage_reduction);
|
||||||
match self.source {
|
match self.source {
|
||||||
DamageSource::Melee => {
|
DamageSource::Melee => {
|
||||||
// Critical hit
|
// Critical hit
|
||||||
|
@ -170,7 +170,7 @@ impl Component for CharacterState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct MeleeAttack {
|
pub struct Melee {
|
||||||
pub attack: Attack,
|
pub attack: Attack,
|
||||||
pub range: f32,
|
pub range: f32,
|
||||||
pub max_angle: f32,
|
pub max_angle: f32,
|
||||||
@ -178,6 +178,6 @@ pub struct MeleeAttack {
|
|||||||
pub hit_count: u32,
|
pub hit_count: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for MeleeAttack {
|
impl Component for Melee {
|
||||||
type Storage = VecStorage<Self>;
|
type Storage = VecStorage<Self>;
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ pub use buff::{
|
|||||||
Buff, BuffCategory, BuffChange, BuffData, BuffEffect, BuffId, BuffKind, BuffSource, Buffs,
|
Buff, BuffCategory, BuffChange, BuffData, BuffEffect, BuffId, BuffKind, BuffSource, Buffs,
|
||||||
ModifierKind,
|
ModifierKind,
|
||||||
};
|
};
|
||||||
pub use character_state::{CharacterState, MeleeAttack, StateUpdate};
|
pub use character_state::{CharacterState, Melee, StateUpdate};
|
||||||
pub use chat::{
|
pub use chat::{
|
||||||
ChatMode, ChatMsg, ChatType, Faction, SpeechBubble, SpeechBubbleType, UnresolvedChatMsg,
|
ChatMode, ChatMsg, ChatType, Faction, SpeechBubble, SpeechBubbleType, UnresolvedChatMsg,
|
||||||
};
|
};
|
||||||
|
@ -21,8 +21,7 @@ pub struct PoiseChange {
|
|||||||
impl PoiseChange {
|
impl PoiseChange {
|
||||||
/// Alters poise damage as a result of armor poise damage reduction
|
/// Alters poise damage as a result of armor poise damage reduction
|
||||||
pub fn modify_poise_damage(self, inventory: Option<&Inventory>) -> PoiseChange {
|
pub fn modify_poise_damage(self, inventory: Option<&Inventory>) -> PoiseChange {
|
||||||
let poise_damage_reduction =
|
let poise_damage_reduction = inventory.map_or(0.0, Poise::compute_poise_damage_reduction);
|
||||||
inventory.map_or(0.0, |inv| Poise::compute_poise_damage_reduction(inv));
|
|
||||||
let poise_damage = self.amount as f32 * (1.0 - poise_damage_reduction);
|
let poise_damage = self.amount as f32 * (1.0 - poise_damage_reduction);
|
||||||
// Add match on poise source when different calculations per source
|
// Add match on poise source when different calculations per source
|
||||||
// are needed/wanted
|
// are needed/wanted
|
||||||
@ -32,10 +31,9 @@ impl PoiseChange {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a poise change from an attack
|
/// Creates a poise change from a float
|
||||||
pub fn from_attack(poise_damage: f32, inventory: Option<&Inventory>) -> Self {
|
pub fn from_value(poise_damage: f32, inventory: Option<&Inventory>) -> Self {
|
||||||
let poise_damage_reduction =
|
let poise_damage_reduction = inventory.map_or(0.0, Poise::compute_poise_damage_reduction);
|
||||||
inventory.map_or(0.0, |inv| Poise::compute_poise_damage_reduction(inv));
|
|
||||||
let poise_change = -poise_damage * (1.0 - poise_damage_reduction);
|
let poise_change = -poise_damage * (1.0 - poise_damage_reduction);
|
||||||
Self {
|
Self {
|
||||||
amount: poise_change as i32,
|
amount: poise_change as i32,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
combat::{
|
combat::{
|
||||||
Attack, AttackEffect, CombatBuff, CombatRequirement, Damage, DamageComponent, DamageSource,
|
Attack, AttackDamage, AttackEffect, CombatBuff, CombatEffect, CombatRequirement, Damage,
|
||||||
EffectComponent, GroupTarget, Knockback, KnockbackDir,
|
DamageSource, GroupTarget, Knockback, KnockbackDir,
|
||||||
},
|
},
|
||||||
uid::Uid,
|
uid::Uid,
|
||||||
Explosion, RadiusEffect,
|
Explosion, RadiusEffect,
|
||||||
@ -14,16 +14,10 @@ use std::time::Duration;
|
|||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub enum Effect {
|
pub enum Effect {
|
||||||
Attack(Attack),
|
Attack(Attack),
|
||||||
//Knockback(Knockback),
|
|
||||||
//RewardEnergy(u32),
|
|
||||||
Explode(Explosion),
|
Explode(Explosion),
|
||||||
Vanish,
|
Vanish,
|
||||||
Stick,
|
Stick,
|
||||||
Possess,
|
Possess,
|
||||||
/* Buff {
|
|
||||||
* buff: BuffEffect,
|
|
||||||
* chance: Option<f32>,
|
|
||||||
* }, */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
@ -76,22 +70,25 @@ impl ProjectileConstructor {
|
|||||||
knockback,
|
knockback,
|
||||||
energy_regen,
|
energy_regen,
|
||||||
} => {
|
} => {
|
||||||
let knockback = AttackEffect::Knockback(Knockback {
|
let knockback = AttackEffect::new(
|
||||||
strength: knockback,
|
Some(GroupTarget::OutOfGroup),
|
||||||
direction: KnockbackDir::Away,
|
CombatEffect::Knockback(Knockback {
|
||||||
});
|
strength: knockback,
|
||||||
let knockback = EffectComponent::new(Some(GroupTarget::OutOfGroup), knockback)
|
direction: KnockbackDir::Away,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.with_requirement(CombatRequirement::AnyDamage);
|
||||||
|
let energy = AttackEffect::new(None, CombatEffect::EnergyReward(energy_regen))
|
||||||
.with_requirement(CombatRequirement::AnyDamage);
|
.with_requirement(CombatRequirement::AnyDamage);
|
||||||
let energy = AttackEffect::EnergyReward(energy_regen);
|
let buff = CombatEffect::Buff(CombatBuff::default_physical());
|
||||||
let energy = EffectComponent::new(None, energy)
|
let damage = AttackDamage::new(
|
||||||
.with_requirement(CombatRequirement::AnyDamage);
|
Damage {
|
||||||
let buff = AttackEffect::Buff(CombatBuff::default_physical());
|
source: DamageSource::Projectile,
|
||||||
let damage = Damage {
|
value: damage,
|
||||||
source: DamageSource::Projectile,
|
},
|
||||||
value: damage,
|
Some(GroupTarget::OutOfGroup),
|
||||||
};
|
)
|
||||||
let damage =
|
.with_effect(buff);
|
||||||
DamageComponent::new(damage, Some(GroupTarget::OutOfGroup)).with_effect(buff);
|
|
||||||
let attack = Attack::default()
|
let attack = Attack::default()
|
||||||
.with_damage(damage)
|
.with_damage(damage)
|
||||||
.with_crit(0.5, 1.2)
|
.with_crit(0.5, 1.2)
|
||||||
@ -111,14 +108,15 @@ impl ProjectileConstructor {
|
|||||||
radius,
|
radius,
|
||||||
energy_regen,
|
energy_regen,
|
||||||
} => {
|
} => {
|
||||||
let energy = AttackEffect::EnergyReward(energy_regen);
|
let energy = AttackEffect::new(None, CombatEffect::EnergyReward(energy_regen))
|
||||||
let energy = EffectComponent::new(None, energy)
|
|
||||||
.with_requirement(CombatRequirement::AnyDamage);
|
.with_requirement(CombatRequirement::AnyDamage);
|
||||||
let damage = Damage {
|
let damage = AttackDamage::new(
|
||||||
source: DamageSource::Explosion,
|
Damage {
|
||||||
value: damage,
|
source: DamageSource::Explosion,
|
||||||
};
|
value: damage,
|
||||||
let damage = DamageComponent::new(damage, Some(GroupTarget::OutOfGroup));
|
},
|
||||||
|
Some(GroupTarget::OutOfGroup),
|
||||||
|
);
|
||||||
let attack = Attack::default().with_damage(damage).with_effect(energy);
|
let attack = Attack::default().with_damage(damage).with_effect(energy);
|
||||||
let explosion = Explosion {
|
let explosion = Explosion {
|
||||||
effects: vec![
|
effects: vec![
|
||||||
@ -139,14 +137,15 @@ impl ProjectileConstructor {
|
|||||||
damage,
|
damage,
|
||||||
energy_regen,
|
energy_regen,
|
||||||
} => {
|
} => {
|
||||||
let energy = AttackEffect::EnergyReward(energy_regen);
|
let energy = AttackEffect::new(None, CombatEffect::EnergyReward(energy_regen))
|
||||||
let energy = EffectComponent::new(None, energy)
|
|
||||||
.with_requirement(CombatRequirement::AnyDamage);
|
.with_requirement(CombatRequirement::AnyDamage);
|
||||||
let damage = Damage {
|
let damage = AttackDamage::new(
|
||||||
source: DamageSource::Energy,
|
Damage {
|
||||||
value: damage,
|
source: DamageSource::Energy,
|
||||||
};
|
value: damage,
|
||||||
let damage = DamageComponent::new(damage, Some(GroupTarget::OutOfGroup));
|
},
|
||||||
|
Some(GroupTarget::OutOfGroup),
|
||||||
|
);
|
||||||
let attack = Attack::default().with_damage(damage).with_effect(energy);
|
let attack = Attack::default().with_damage(damage).with_effect(energy);
|
||||||
|
|
||||||
Projectile {
|
Projectile {
|
||||||
@ -162,13 +161,14 @@ impl ProjectileConstructor {
|
|||||||
damage,
|
damage,
|
||||||
radius,
|
radius,
|
||||||
} => {
|
} => {
|
||||||
let damage = Damage {
|
let damage = AttackDamage::new(
|
||||||
source: DamageSource::Explosion,
|
Damage {
|
||||||
value: damage,
|
source: DamageSource::Explosion,
|
||||||
};
|
value: damage,
|
||||||
let damage = DamageComponent::new(damage, Some(GroupTarget::OutOfGroup));
|
},
|
||||||
let heal = AttackEffect::Heal(heal);
|
Some(GroupTarget::OutOfGroup),
|
||||||
let heal = EffectComponent::new(Some(GroupTarget::InGroup), heal);
|
);
|
||||||
|
let heal = AttackEffect::new(Some(GroupTarget::InGroup), CombatEffect::Heal(heal));
|
||||||
let attack = Attack::default().with_damage(damage).with_effect(heal);
|
let attack = Attack::default().with_damage(damage).with_effect(heal);
|
||||||
let explosion = Explosion {
|
let explosion = Explosion {
|
||||||
effects: vec![RadiusEffect::Attack(attack)],
|
effects: vec![RadiusEffect::Attack(attack)],
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
combat::{
|
combat::{
|
||||||
Attack, AttackEffect, CombatRequirement, Damage, DamageComponent, DamageSource,
|
Attack, AttackDamage, AttackEffect, CombatEffect, CombatRequirement, Damage, DamageSource,
|
||||||
EffectComponent, GroupTarget,
|
GroupTarget,
|
||||||
},
|
},
|
||||||
comp::{beam, Body, CharacterState, EnergyChange, EnergySource, Ori, Pos, StateUpdate},
|
comp::{beam, Body, CharacterState, EnergyChange, EnergySource, Ori, Pos, StateUpdate},
|
||||||
event::ServerEvent,
|
event::ServerEvent,
|
||||||
@ -122,25 +122,32 @@ impl CharacterBehavior for Data {
|
|||||||
if ability_key_is_pressed(data, self.static_data.ability_key)
|
if ability_key_is_pressed(data, self.static_data.ability_key)
|
||||||
&& (self.static_data.energy_drain == 0 || update.energy.current() > 0)
|
&& (self.static_data.energy_drain == 0 || update.energy.current() > 0)
|
||||||
{
|
{
|
||||||
let damage = Damage {
|
|
||||||
source: DamageSource::Energy,
|
|
||||||
value: self.static_data.base_dps as f32 / self.static_data.tick_rate,
|
|
||||||
};
|
|
||||||
let heal = self.static_data.base_hps as f32 / self.static_data.tick_rate;
|
|
||||||
let heal = AttackEffect::Heal(heal);
|
|
||||||
let speed =
|
let speed =
|
||||||
self.static_data.range / self.static_data.beam_duration.as_secs_f32();
|
self.static_data.range / self.static_data.beam_duration.as_secs_f32();
|
||||||
|
|
||||||
let energy = AttackEffect::EnergyReward(self.static_data.energy_regen);
|
let energy = AttackEffect::new(
|
||||||
let energy = EffectComponent::new(None, energy)
|
None,
|
||||||
.with_requirement(CombatRequirement::AnyDamage);
|
CombatEffect::EnergyReward(self.static_data.energy_regen),
|
||||||
let lifesteal = AttackEffect::Lifesteal(self.static_data.lifesteal_eff);
|
)
|
||||||
let damage = DamageComponent::new(damage, Some(GroupTarget::OutOfGroup))
|
.with_requirement(CombatRequirement::AnyDamage);
|
||||||
.with_effect(lifesteal);
|
let lifesteal = CombatEffect::Lifesteal(self.static_data.lifesteal_eff);
|
||||||
let heal = EffectComponent::new(Some(GroupTarget::InGroup), heal)
|
let damage = AttackDamage::new(
|
||||||
.with_requirement(CombatRequirement::SufficientEnergy(
|
Damage {
|
||||||
self.static_data.energy_cost,
|
source: DamageSource::Energy,
|
||||||
));
|
value: self.static_data.base_dps as f32 / self.static_data.tick_rate,
|
||||||
|
},
|
||||||
|
Some(GroupTarget::OutOfGroup),
|
||||||
|
)
|
||||||
|
.with_effect(lifesteal);
|
||||||
|
let heal = AttackEffect::new(
|
||||||
|
Some(GroupTarget::InGroup),
|
||||||
|
CombatEffect::Heal(
|
||||||
|
self.static_data.base_hps as f32 / self.static_data.tick_rate,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.with_requirement(CombatRequirement::SufficientEnergy(
|
||||||
|
self.static_data.energy_cost,
|
||||||
|
));
|
||||||
let attack = Attack::default()
|
let attack = Attack::default()
|
||||||
.with_damage(damage)
|
.with_damage(damage)
|
||||||
.with_effect(energy)
|
.with_effect(energy)
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
combat::{
|
combat::{Attack, AttackDamage, AttackEffect, CombatBuff, CombatEffect, CombatRequirement},
|
||||||
Attack, AttackEffect, CombatBuff, CombatRequirement, DamageComponent, EffectComponent,
|
comp::{CharacterState, Melee, StateUpdate},
|
||||||
},
|
|
||||||
comp::{CharacterState, MeleeAttack, StateUpdate},
|
|
||||||
states::{
|
states::{
|
||||||
behavior::{CharacterBehavior, JoinData},
|
behavior::{CharacterBehavior, JoinData},
|
||||||
utils::*,
|
utils::*,
|
||||||
@ -92,25 +90,30 @@ impl CharacterBehavior for Data {
|
|||||||
..*self
|
..*self
|
||||||
});
|
});
|
||||||
|
|
||||||
let poise = AttackEffect::Poise(self.static_data.base_poise_damage as f32);
|
let poise = AttackEffect::new(
|
||||||
let poise = EffectComponent::new(Some(GroupTarget::OutOfGroup), poise)
|
Some(GroupTarget::OutOfGroup),
|
||||||
|
CombatEffect::Poise(self.static_data.base_poise_damage as f32),
|
||||||
|
)
|
||||||
|
.with_requirement(CombatRequirement::AnyDamage);
|
||||||
|
let knockback = AttackEffect::new(
|
||||||
|
Some(GroupTarget::OutOfGroup),
|
||||||
|
CombatEffect::Knockback(Knockback {
|
||||||
|
strength: self.static_data.knockback,
|
||||||
|
direction: KnockbackDir::Away,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.with_requirement(CombatRequirement::AnyDamage);
|
||||||
|
let energy = AttackEffect::new(None, CombatEffect::EnergyReward(50))
|
||||||
.with_requirement(CombatRequirement::AnyDamage);
|
.with_requirement(CombatRequirement::AnyDamage);
|
||||||
let knockback = AttackEffect::Knockback(Knockback {
|
let buff = CombatEffect::Buff(CombatBuff::default_physical());
|
||||||
strength: self.static_data.knockback,
|
let damage = AttackDamage::new(
|
||||||
direction: KnockbackDir::Away,
|
Damage {
|
||||||
});
|
source: DamageSource::Melee,
|
||||||
let knockback = EffectComponent::new(Some(GroupTarget::OutOfGroup), knockback)
|
value: self.static_data.base_damage as f32,
|
||||||
.with_requirement(CombatRequirement::AnyDamage);
|
},
|
||||||
let energy = AttackEffect::EnergyReward(50);
|
Some(GroupTarget::OutOfGroup),
|
||||||
let energy = EffectComponent::new(None, energy)
|
)
|
||||||
.with_requirement(CombatRequirement::AnyDamage);
|
.with_effect(buff);
|
||||||
let buff = AttackEffect::Buff(CombatBuff::default_physical());
|
|
||||||
let damage = Damage {
|
|
||||||
source: DamageSource::Melee,
|
|
||||||
value: self.static_data.base_damage as f32,
|
|
||||||
};
|
|
||||||
let damage = DamageComponent::new(damage, Some(GroupTarget::OutOfGroup))
|
|
||||||
.with_effect(buff);
|
|
||||||
let attack = Attack::default()
|
let attack = Attack::default()
|
||||||
.with_damage(damage)
|
.with_damage(damage)
|
||||||
.with_crit(0.5, 1.3)
|
.with_crit(0.5, 1.3)
|
||||||
@ -119,7 +122,7 @@ impl CharacterBehavior for Data {
|
|||||||
.with_effect(knockback);
|
.with_effect(knockback);
|
||||||
|
|
||||||
// Hit attempt
|
// Hit attempt
|
||||||
data.updater.insert(data.entity, MeleeAttack {
|
data.updater.insert(data.entity, Melee {
|
||||||
attack,
|
attack,
|
||||||
range: self.static_data.range,
|
range: self.static_data.range,
|
||||||
max_angle: self.static_data.max_angle,
|
max_angle: self.static_data.max_angle,
|
||||||
@ -158,14 +161,14 @@ impl CharacterBehavior for Data {
|
|||||||
// Done
|
// Done
|
||||||
update.character = CharacterState::Wielding;
|
update.character = CharacterState::Wielding;
|
||||||
// Make sure attack component is removed
|
// Make sure attack component is removed
|
||||||
data.updater.remove::<MeleeAttack>(data.entity);
|
data.updater.remove::<Melee>(data.entity);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
// If it somehow ends up in an incorrect stage section
|
// If it somehow ends up in an incorrect stage section
|
||||||
update.character = CharacterState::Wielding;
|
update.character = CharacterState::Wielding;
|
||||||
// Make sure attack component is removed
|
// Make sure attack component is removed
|
||||||
data.updater.remove::<MeleeAttack>(data.entity);
|
data.updater.remove::<Melee>(data.entity);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
comp::{
|
comp::{
|
||||||
Beam, Body, CharacterState, ControlAction, Controller, ControllerInputs, Energy, Health,
|
Beam, Body, CharacterState, ControlAction, Controller, ControllerInputs, Energy, Health,
|
||||||
Inventory, MeleeAttack, Ori, PhysicsState, Pos, StateUpdate, Stats, Vel,
|
Inventory, Melee, Ori, PhysicsState, Pos, StateUpdate, Stats, Vel,
|
||||||
},
|
},
|
||||||
resources::DeltaTime,
|
resources::DeltaTime,
|
||||||
uid::Uid,
|
uid::Uid,
|
||||||
@ -57,7 +57,7 @@ pub struct JoinData<'a> {
|
|||||||
pub inventory: &'a Inventory,
|
pub inventory: &'a Inventory,
|
||||||
pub body: &'a Body,
|
pub body: &'a Body,
|
||||||
pub physics: &'a PhysicsState,
|
pub physics: &'a PhysicsState,
|
||||||
pub melee_attack: Option<&'a MeleeAttack>,
|
pub melee_attack: Option<&'a Melee>,
|
||||||
pub updater: &'a LazyUpdate,
|
pub updater: &'a LazyUpdate,
|
||||||
pub stats: &'a Stats,
|
pub stats: &'a Stats,
|
||||||
}
|
}
|
||||||
@ -84,7 +84,7 @@ pub type JoinTuple<'a> = (
|
|||||||
&'a Health,
|
&'a Health,
|
||||||
&'a Body,
|
&'a Body,
|
||||||
&'a PhysicsState,
|
&'a PhysicsState,
|
||||||
Option<&'a MeleeAttack>,
|
Option<&'a Melee>,
|
||||||
Option<&'a Beam>,
|
Option<&'a Beam>,
|
||||||
&'a Stats,
|
&'a Stats,
|
||||||
);
|
);
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
combat::{
|
combat::{Attack, AttackDamage, AttackEffect, CombatBuff, CombatEffect, CombatRequirement},
|
||||||
Attack, AttackEffect, CombatBuff, CombatRequirement, DamageComponent, EffectComponent,
|
comp::{CharacterState, EnergyChange, EnergySource, Melee, StateUpdate},
|
||||||
},
|
|
||||||
comp::{CharacterState, EnergyChange, EnergySource, MeleeAttack, StateUpdate},
|
|
||||||
states::{
|
states::{
|
||||||
behavior::{CharacterBehavior, JoinData},
|
behavior::{CharacterBehavior, JoinData},
|
||||||
utils::{StageSection, *},
|
utils::{StageSection, *},
|
||||||
@ -155,27 +153,33 @@ impl CharacterBehavior for Data {
|
|||||||
exhausted: true,
|
exhausted: true,
|
||||||
..*self
|
..*self
|
||||||
});
|
});
|
||||||
let poise = self.static_data.initial_poise_damage as f32
|
let poise = AttackEffect::new(
|
||||||
+ self.charge_amount * self.static_data.scaled_poise_damage as f32;
|
Some(GroupTarget::OutOfGroup),
|
||||||
let poise = AttackEffect::Poise(poise);
|
CombatEffect::Poise(
|
||||||
let poise = EffectComponent::new(Some(GroupTarget::OutOfGroup), poise)
|
self.static_data.initial_poise_damage as f32
|
||||||
.with_requirement(CombatRequirement::AnyDamage);
|
+ self.charge_amount * self.static_data.scaled_poise_damage as f32,
|
||||||
let knockback = self.static_data.initial_knockback
|
),
|
||||||
+ self.charge_amount * self.static_data.scaled_knockback;
|
)
|
||||||
let knockback = AttackEffect::Knockback(Knockback {
|
.with_requirement(CombatRequirement::AnyDamage);
|
||||||
strength: knockback,
|
let knockback = AttackEffect::new(
|
||||||
direction: KnockbackDir::Away,
|
Some(GroupTarget::OutOfGroup),
|
||||||
});
|
CombatEffect::Knockback(Knockback {
|
||||||
let knockback = EffectComponent::new(Some(GroupTarget::OutOfGroup), knockback)
|
strength: self.static_data.initial_knockback
|
||||||
.with_requirement(CombatRequirement::AnyDamage);
|
+ self.charge_amount * self.static_data.scaled_knockback,
|
||||||
let buff = AttackEffect::Buff(CombatBuff::default_physical());
|
direction: KnockbackDir::Away,
|
||||||
let damage = Damage {
|
}),
|
||||||
source: DamageSource::Melee,
|
)
|
||||||
value: self.static_data.initial_damage as f32
|
.with_requirement(CombatRequirement::AnyDamage);
|
||||||
+ self.charge_amount * self.static_data.scaled_damage as f32,
|
let buff = CombatEffect::Buff(CombatBuff::default_physical());
|
||||||
};
|
let damage = AttackDamage::new(
|
||||||
let damage = DamageComponent::new(damage, Some(GroupTarget::OutOfGroup))
|
Damage {
|
||||||
.with_effect(buff);
|
source: DamageSource::Melee,
|
||||||
|
value: self.static_data.initial_damage as f32
|
||||||
|
+ self.charge_amount * self.static_data.scaled_damage as f32,
|
||||||
|
},
|
||||||
|
Some(GroupTarget::OutOfGroup),
|
||||||
|
)
|
||||||
|
.with_effect(buff);
|
||||||
let attack = Attack::default()
|
let attack = Attack::default()
|
||||||
.with_damage(damage)
|
.with_damage(damage)
|
||||||
.with_crit(0.5, 1.3)
|
.with_crit(0.5, 1.3)
|
||||||
@ -183,7 +187,7 @@ impl CharacterBehavior for Data {
|
|||||||
.with_effect(knockback);
|
.with_effect(knockback);
|
||||||
|
|
||||||
// Hit attempt
|
// Hit attempt
|
||||||
data.updater.insert(data.entity, MeleeAttack {
|
data.updater.insert(data.entity, Melee {
|
||||||
attack,
|
attack,
|
||||||
range: self.static_data.range,
|
range: self.static_data.range,
|
||||||
max_angle: self.static_data.max_angle.to_radians(),
|
max_angle: self.static_data.max_angle.to_radians(),
|
||||||
@ -222,14 +226,14 @@ impl CharacterBehavior for Data {
|
|||||||
// Done
|
// Done
|
||||||
update.character = CharacterState::Wielding;
|
update.character = CharacterState::Wielding;
|
||||||
// Make sure attack component is removed
|
// Make sure attack component is removed
|
||||||
data.updater.remove::<MeleeAttack>(data.entity);
|
data.updater.remove::<Melee>(data.entity);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
// If it somehow ends up in an incorrect stage section
|
// If it somehow ends up in an incorrect stage section
|
||||||
update.character = CharacterState::Wielding;
|
update.character = CharacterState::Wielding;
|
||||||
// Make sure attack component is removed
|
// Make sure attack component is removed
|
||||||
data.updater.remove::<MeleeAttack>(data.entity);
|
data.updater.remove::<Melee>(data.entity);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
combat::{
|
combat::{
|
||||||
Attack, AttackEffect, CombatBuff, CombatRequirement, Damage, DamageComponent, DamageSource,
|
Attack, AttackDamage, AttackEffect, CombatBuff, CombatEffect, CombatRequirement, Damage,
|
||||||
EffectComponent, GroupTarget, Knockback, KnockbackDir,
|
DamageSource, GroupTarget, Knockback, KnockbackDir,
|
||||||
},
|
},
|
||||||
comp::{
|
comp::{
|
||||||
projectile, Body, CharacterState, EnergyChange, EnergySource, Gravity, LightEmitter,
|
projectile, Body, CharacterState, EnergyChange, EnergySource, Gravity, LightEmitter,
|
||||||
@ -103,22 +103,25 @@ impl CharacterBehavior for Data {
|
|||||||
let charge_frac = (self.timer.as_secs_f32()
|
let charge_frac = (self.timer.as_secs_f32()
|
||||||
/ self.static_data.charge_duration.as_secs_f32())
|
/ self.static_data.charge_duration.as_secs_f32())
|
||||||
.min(1.0);
|
.min(1.0);
|
||||||
let knockback = self.static_data.initial_knockback
|
let knockback = AttackEffect::new(
|
||||||
+ charge_frac * self.static_data.scaled_knockback;
|
Some(GroupTarget::OutOfGroup),
|
||||||
let knockback = AttackEffect::Knockback(Knockback {
|
CombatEffect::Knockback(Knockback {
|
||||||
strength: knockback,
|
strength: self.static_data.initial_knockback
|
||||||
direction: KnockbackDir::Away,
|
+ charge_frac * self.static_data.scaled_knockback,
|
||||||
});
|
direction: KnockbackDir::Away,
|
||||||
let knockback = EffectComponent::new(Some(GroupTarget::OutOfGroup), knockback)
|
}),
|
||||||
.with_requirement(CombatRequirement::AnyDamage);
|
)
|
||||||
let buff = AttackEffect::Buff(CombatBuff::default_physical());
|
.with_requirement(CombatRequirement::AnyDamage);
|
||||||
let damage = Damage {
|
let buff = CombatEffect::Buff(CombatBuff::default_physical());
|
||||||
source: DamageSource::Projectile,
|
let damage = AttackDamage::new(
|
||||||
value: self.static_data.initial_damage as f32
|
Damage {
|
||||||
+ charge_frac * self.static_data.scaled_damage as f32,
|
source: DamageSource::Projectile,
|
||||||
};
|
value: self.static_data.initial_damage as f32
|
||||||
let damage = DamageComponent::new(damage, Some(GroupTarget::OutOfGroup))
|
+ charge_frac * self.static_data.scaled_damage as f32,
|
||||||
.with_effect(buff);
|
},
|
||||||
|
Some(GroupTarget::OutOfGroup),
|
||||||
|
)
|
||||||
|
.with_effect(buff);
|
||||||
let attack = Attack::default()
|
let attack = Attack::default()
|
||||||
.with_damage(damage)
|
.with_damage(damage)
|
||||||
.with_crit(0.5, 1.2)
|
.with_crit(0.5, 1.2)
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
combat::{
|
combat::{Attack, AttackDamage, AttackEffect, CombatBuff, CombatEffect, CombatRequirement},
|
||||||
Attack, AttackEffect, CombatBuff, CombatRequirement, DamageComponent, EffectComponent,
|
comp::{CharacterState, Melee, StateUpdate},
|
||||||
},
|
|
||||||
comp::{CharacterState, MeleeAttack, StateUpdate},
|
|
||||||
states::{
|
states::{
|
||||||
behavior::{CharacterBehavior, JoinData},
|
behavior::{CharacterBehavior, JoinData},
|
||||||
utils::*,
|
utils::*,
|
||||||
@ -174,37 +172,40 @@ impl CharacterBehavior for Data {
|
|||||||
.scales_from_combo
|
.scales_from_combo
|
||||||
.min(self.combo / self.static_data.num_stages)
|
.min(self.combo / self.static_data.num_stages)
|
||||||
* self.static_data.stage_data[stage_index].damage_increase;
|
* self.static_data.stage_data[stage_index].damage_increase;
|
||||||
|
|
||||||
let poise = self.static_data.stage_data[stage_index].base_poise_damage
|
let poise = self.static_data.stage_data[stage_index].base_poise_damage
|
||||||
+ self
|
+ self
|
||||||
.static_data
|
.static_data
|
||||||
.scales_from_combo
|
.scales_from_combo
|
||||||
.min(self.combo / self.static_data.num_stages)
|
.min(self.combo / self.static_data.num_stages)
|
||||||
* self.static_data.stage_data[stage_index].poise_damage_increase;
|
* self.static_data.stage_data[stage_index].poise_damage_increase;
|
||||||
let poise = AttackEffect::Poise(poise as f32);
|
let poise = AttackEffect::new(
|
||||||
let poise = EffectComponent::new(Some(GroupTarget::OutOfGroup), poise)
|
Some(GroupTarget::OutOfGroup),
|
||||||
.with_requirement(CombatRequirement::AnyDamage);
|
CombatEffect::Poise(poise as f32),
|
||||||
|
)
|
||||||
let knockback = AttackEffect::Knockback(Knockback {
|
.with_requirement(CombatRequirement::AnyDamage);
|
||||||
strength: self.static_data.stage_data[stage_index].knockback,
|
let knockback = AttackEffect::new(
|
||||||
direction: KnockbackDir::Away,
|
Some(GroupTarget::OutOfGroup),
|
||||||
});
|
CombatEffect::Knockback(Knockback {
|
||||||
let knockback = EffectComponent::new(Some(GroupTarget::OutOfGroup), knockback)
|
strength: self.static_data.stage_data[stage_index].knockback,
|
||||||
.with_requirement(CombatRequirement::AnyDamage);
|
direction: KnockbackDir::Away,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.with_requirement(CombatRequirement::AnyDamage);
|
||||||
let energy = self.static_data.max_energy_gain.min(
|
let energy = self.static_data.max_energy_gain.min(
|
||||||
self.static_data.initial_energy_gain
|
self.static_data.initial_energy_gain
|
||||||
+ self.combo * self.static_data.energy_increase,
|
+ self.combo * self.static_data.energy_increase,
|
||||||
);
|
);
|
||||||
let energy = AttackEffect::EnergyReward(energy);
|
let energy = AttackEffect::new(None, CombatEffect::EnergyReward(energy))
|
||||||
let energy = EffectComponent::new(None, energy)
|
|
||||||
.with_requirement(CombatRequirement::AnyDamage);
|
.with_requirement(CombatRequirement::AnyDamage);
|
||||||
let buff = AttackEffect::Buff(CombatBuff::default_physical());
|
let buff = CombatEffect::Buff(CombatBuff::default_physical());
|
||||||
let damage = Damage {
|
let damage = AttackDamage::new(
|
||||||
source: DamageSource::Melee,
|
Damage {
|
||||||
value: damage as f32,
|
source: DamageSource::Melee,
|
||||||
};
|
value: damage as f32,
|
||||||
let damage = DamageComponent::new(damage, Some(GroupTarget::OutOfGroup))
|
},
|
||||||
.with_effect(buff);
|
Some(GroupTarget::OutOfGroup),
|
||||||
|
)
|
||||||
|
.with_effect(buff);
|
||||||
let attack = Attack::default()
|
let attack = Attack::default()
|
||||||
.with_damage(damage)
|
.with_damage(damage)
|
||||||
.with_crit(0.5, 1.3)
|
.with_crit(0.5, 1.3)
|
||||||
@ -212,7 +213,7 @@ impl CharacterBehavior for Data {
|
|||||||
.with_effect(poise)
|
.with_effect(poise)
|
||||||
.with_effect(knockback);
|
.with_effect(knockback);
|
||||||
|
|
||||||
data.updater.insert(data.entity, MeleeAttack {
|
data.updater.insert(data.entity, Melee {
|
||||||
attack,
|
attack,
|
||||||
range: self.static_data.stage_data[stage_index].range,
|
range: self.static_data.stage_data[stage_index].range,
|
||||||
max_angle: self.static_data.stage_data[stage_index].angle.to_radians(),
|
max_angle: self.static_data.stage_data[stage_index].angle.to_radians(),
|
||||||
@ -290,14 +291,14 @@ impl CharacterBehavior for Data {
|
|||||||
// Done
|
// Done
|
||||||
update.character = CharacterState::Wielding;
|
update.character = CharacterState::Wielding;
|
||||||
// Make sure attack component is removed
|
// Make sure attack component is removed
|
||||||
data.updater.remove::<MeleeAttack>(data.entity);
|
data.updater.remove::<Melee>(data.entity);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
// If it somehow ends up in an incorrect stage section
|
// If it somehow ends up in an incorrect stage section
|
||||||
update.character = CharacterState::Wielding;
|
update.character = CharacterState::Wielding;
|
||||||
// Make sure attack component is removed
|
// Make sure attack component is removed
|
||||||
data.updater.remove::<MeleeAttack>(data.entity);
|
data.updater.remove::<Melee>(data.entity);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,7 +313,7 @@ impl CharacterBehavior for Data {
|
|||||||
stage_section: self.stage_section,
|
stage_section: self.stage_section,
|
||||||
next_stage: self.next_stage,
|
next_stage: self.next_stage,
|
||||||
});
|
});
|
||||||
data.updater.remove::<MeleeAttack>(data.entity);
|
data.updater.remove::<Melee>(data.entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
combat::{
|
combat::{Attack, AttackDamage, AttackEffect, CombatBuff, CombatEffect, CombatRequirement},
|
||||||
Attack, AttackEffect, CombatBuff, CombatRequirement, DamageComponent, EffectComponent,
|
comp::{CharacterState, EnergyChange, EnergySource, Melee, StateUpdate},
|
||||||
},
|
|
||||||
comp::{CharacterState, EnergyChange, EnergySource, MeleeAttack, StateUpdate},
|
|
||||||
states::{
|
states::{
|
||||||
behavior::{CharacterBehavior, JoinData},
|
behavior::{CharacterBehavior, JoinData},
|
||||||
utils::*,
|
utils::*,
|
||||||
@ -132,36 +130,40 @@ impl CharacterBehavior for Data {
|
|||||||
if !self.exhausted {
|
if !self.exhausted {
|
||||||
// Hit attempt (also checks if player is moving)
|
// Hit attempt (also checks if player is moving)
|
||||||
if update.vel.0.distance_squared(Vec3::zero()) > 1.0 {
|
if update.vel.0.distance_squared(Vec3::zero()) > 1.0 {
|
||||||
let poise = self.static_data.base_poise_damage as f32
|
let poise = AttackEffect::new(
|
||||||
+ charge_frac * self.static_data.scaled_poise_damage as f32;
|
Some(GroupTarget::OutOfGroup),
|
||||||
let poise = AttackEffect::Poise(poise);
|
CombatEffect::Poise(
|
||||||
let poise = EffectComponent::new(Some(GroupTarget::OutOfGroup), poise)
|
self.static_data.base_poise_damage as f32
|
||||||
.with_requirement(CombatRequirement::AnyDamage);
|
+ charge_frac * self.static_data.scaled_poise_damage as f32,
|
||||||
let knockback = self.static_data.base_knockback
|
),
|
||||||
+ charge_frac * self.static_data.scaled_knockback;
|
)
|
||||||
let knockback = AttackEffect::Knockback(Knockback {
|
.with_requirement(CombatRequirement::AnyDamage);
|
||||||
strength: knockback,
|
let knockback = AttackEffect::new(
|
||||||
direction: KnockbackDir::Away,
|
Some(GroupTarget::OutOfGroup),
|
||||||
});
|
CombatEffect::Knockback(Knockback {
|
||||||
let knockback =
|
strength: self.static_data.base_knockback
|
||||||
EffectComponent::new(Some(GroupTarget::OutOfGroup), knockback)
|
+ charge_frac * self.static_data.scaled_knockback,
|
||||||
.with_requirement(CombatRequirement::AnyDamage);
|
direction: KnockbackDir::Away,
|
||||||
let buff = AttackEffect::Buff(CombatBuff::default_physical());
|
}),
|
||||||
let damage = Damage {
|
)
|
||||||
source: DamageSource::Melee,
|
.with_requirement(CombatRequirement::AnyDamage);
|
||||||
value: self.static_data.base_damage as f32
|
let buff = CombatEffect::Buff(CombatBuff::default_physical());
|
||||||
+ charge_frac * self.static_data.scaled_damage as f32,
|
let damage = AttackDamage::new(
|
||||||
};
|
Damage {
|
||||||
let damage =
|
source: DamageSource::Melee,
|
||||||
DamageComponent::new(damage, Some(GroupTarget::OutOfGroup))
|
value: self.static_data.base_damage as f32
|
||||||
.with_effect(buff);
|
+ charge_frac * self.static_data.scaled_damage as f32,
|
||||||
|
},
|
||||||
|
Some(GroupTarget::OutOfGroup),
|
||||||
|
)
|
||||||
|
.with_effect(buff);
|
||||||
let attack = Attack::default()
|
let attack = Attack::default()
|
||||||
.with_damage(damage)
|
.with_damage(damage)
|
||||||
.with_crit(0.5, 1.3)
|
.with_crit(0.5, 1.3)
|
||||||
.with_effect(poise)
|
.with_effect(poise)
|
||||||
.with_effect(knockback);
|
.with_effect(knockback);
|
||||||
|
|
||||||
data.updater.insert(data.entity, MeleeAttack {
|
data.updater.insert(data.entity, Melee {
|
||||||
attack,
|
attack,
|
||||||
range: self.static_data.range,
|
range: self.static_data.range,
|
||||||
max_angle: self.static_data.angle.to_radians(),
|
max_angle: self.static_data.angle.to_radians(),
|
||||||
@ -246,14 +248,14 @@ impl CharacterBehavior for Data {
|
|||||||
// Done
|
// Done
|
||||||
update.character = CharacterState::Wielding;
|
update.character = CharacterState::Wielding;
|
||||||
// Make sure attack component is removed
|
// Make sure attack component is removed
|
||||||
data.updater.remove::<MeleeAttack>(data.entity);
|
data.updater.remove::<Melee>(data.entity);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
// If it somehow ends up in an incorrect stage section
|
// If it somehow ends up in an incorrect stage section
|
||||||
update.character = CharacterState::Wielding;
|
update.character = CharacterState::Wielding;
|
||||||
// Make sure attack component is removed
|
// Make sure attack component is removed
|
||||||
data.updater.remove::<MeleeAttack>(data.entity);
|
data.updater.remove::<Melee>(data.entity);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
combat::{
|
combat::{Attack, AttackDamage, AttackEffect, CombatBuff, CombatEffect, CombatRequirement},
|
||||||
Attack, AttackEffect, CombatBuff, CombatRequirement, DamageComponent, EffectComponent,
|
comp::{CharacterState, Melee, StateUpdate},
|
||||||
},
|
|
||||||
comp::{CharacterState, MeleeAttack, StateUpdate},
|
|
||||||
states::{
|
states::{
|
||||||
behavior::{CharacterBehavior, JoinData},
|
behavior::{CharacterBehavior, JoinData},
|
||||||
utils::{StageSection, *},
|
utils::{StageSection, *},
|
||||||
@ -150,22 +148,28 @@ impl CharacterBehavior for Data {
|
|||||||
},
|
},
|
||||||
StageSection::Recover => {
|
StageSection::Recover => {
|
||||||
if !self.exhausted {
|
if !self.exhausted {
|
||||||
let poise = AttackEffect::Poise(self.static_data.base_poise_damage as f32);
|
let poise = AttackEffect::new(
|
||||||
let poise = EffectComponent::new(Some(GroupTarget::OutOfGroup), poise)
|
Some(GroupTarget::OutOfGroup),
|
||||||
.with_requirement(CombatRequirement::AnyDamage);
|
CombatEffect::Poise(self.static_data.base_poise_damage as f32),
|
||||||
let knockback = AttackEffect::Knockback(Knockback {
|
)
|
||||||
strength: self.static_data.knockback,
|
.with_requirement(CombatRequirement::AnyDamage);
|
||||||
direction: KnockbackDir::Away,
|
let knockback = AttackEffect::new(
|
||||||
});
|
Some(GroupTarget::OutOfGroup),
|
||||||
let knockback = EffectComponent::new(Some(GroupTarget::OutOfGroup), knockback)
|
CombatEffect::Knockback(Knockback {
|
||||||
.with_requirement(CombatRequirement::AnyDamage);
|
strength: self.static_data.knockback,
|
||||||
let buff = AttackEffect::Buff(CombatBuff::default_physical());
|
direction: KnockbackDir::Away,
|
||||||
let damage = Damage {
|
}),
|
||||||
source: DamageSource::Melee,
|
)
|
||||||
value: self.static_data.base_damage as f32,
|
.with_requirement(CombatRequirement::AnyDamage);
|
||||||
};
|
let buff = CombatEffect::Buff(CombatBuff::default_physical());
|
||||||
let damage = DamageComponent::new(damage, Some(GroupTarget::OutOfGroup))
|
let damage = AttackDamage::new(
|
||||||
.with_effect(buff);
|
Damage {
|
||||||
|
source: DamageSource::Melee,
|
||||||
|
value: self.static_data.base_damage as f32,
|
||||||
|
},
|
||||||
|
Some(GroupTarget::OutOfGroup),
|
||||||
|
)
|
||||||
|
.with_effect(buff);
|
||||||
let attack = Attack::default()
|
let attack = Attack::default()
|
||||||
.with_damage(damage)
|
.with_damage(damage)
|
||||||
.with_crit(0.5, 1.3)
|
.with_crit(0.5, 1.3)
|
||||||
@ -173,7 +177,7 @@ impl CharacterBehavior for Data {
|
|||||||
.with_effect(knockback);
|
.with_effect(knockback);
|
||||||
|
|
||||||
// Hit attempt, when animation plays
|
// Hit attempt, when animation plays
|
||||||
data.updater.insert(data.entity, MeleeAttack {
|
data.updater.insert(data.entity, Melee {
|
||||||
attack,
|
attack,
|
||||||
range: self.static_data.range,
|
range: self.static_data.range,
|
||||||
max_angle: self.static_data.max_angle.to_radians(),
|
max_angle: self.static_data.max_angle.to_radians(),
|
||||||
@ -202,14 +206,14 @@ impl CharacterBehavior for Data {
|
|||||||
// Done
|
// Done
|
||||||
update.character = CharacterState::Wielding;
|
update.character = CharacterState::Wielding;
|
||||||
// Make sure attack component is removed
|
// Make sure attack component is removed
|
||||||
data.updater.remove::<MeleeAttack>(data.entity);
|
data.updater.remove::<Melee>(data.entity);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
// If it somehow ends up in an incorrect stage section
|
// If it somehow ends up in an incorrect stage section
|
||||||
update.character = CharacterState::Wielding;
|
update.character = CharacterState::Wielding;
|
||||||
// Make sure attack component is removed
|
// Make sure attack component is removed
|
||||||
data.updater.remove::<MeleeAttack>(data.entity);
|
data.updater.remove::<Melee>(data.entity);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
combat::{
|
combat::{
|
||||||
Attack, AttackEffect, CombatRequirement, Damage, DamageComponent, DamageSource,
|
Attack, AttackDamage, AttackEffect, CombatEffect, CombatRequirement, Damage, DamageSource,
|
||||||
EffectComponent, GroupTarget, Knockback,
|
GroupTarget, Knockback,
|
||||||
},
|
},
|
||||||
comp::{shockwave, CharacterState, StateUpdate},
|
comp::{shockwave, CharacterState, StateUpdate},
|
||||||
event::ServerEvent,
|
event::ServerEvent,
|
||||||
@ -83,17 +83,23 @@ impl CharacterBehavior for Data {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Attack
|
// Attack
|
||||||
let poise = AttackEffect::Poise(self.static_data.poise_damage as f32);
|
let poise = AttackEffect::new(
|
||||||
let poise = EffectComponent::new(Some(GroupTarget::OutOfGroup), poise)
|
Some(GroupTarget::OutOfGroup),
|
||||||
.with_requirement(CombatRequirement::AnyDamage);
|
CombatEffect::Poise(self.static_data.poise_damage as f32),
|
||||||
let knockback = AttackEffect::Knockback(self.static_data.knockback);
|
)
|
||||||
let knockback = EffectComponent::new(Some(GroupTarget::OutOfGroup), knockback)
|
.with_requirement(CombatRequirement::AnyDamage);
|
||||||
.with_requirement(CombatRequirement::AnyDamage);
|
let knockback = AttackEffect::new(
|
||||||
let damage = Damage {
|
Some(GroupTarget::OutOfGroup),
|
||||||
source: DamageSource::Shockwave,
|
CombatEffect::Knockback(self.static_data.knockback),
|
||||||
value: self.static_data.damage as f32,
|
)
|
||||||
};
|
.with_requirement(CombatRequirement::AnyDamage);
|
||||||
let damage = DamageComponent::new(damage, Some(GroupTarget::OutOfGroup));
|
let damage = AttackDamage::new(
|
||||||
|
Damage {
|
||||||
|
source: DamageSource::Shockwave,
|
||||||
|
value: self.static_data.damage as f32,
|
||||||
|
},
|
||||||
|
Some(GroupTarget::OutOfGroup),
|
||||||
|
);
|
||||||
let attack = Attack::default()
|
let attack = Attack::default()
|
||||||
.with_damage(damage)
|
.with_damage(damage)
|
||||||
.with_effect(poise)
|
.with_effect(poise)
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
combat::{
|
combat::{Attack, AttackDamage, AttackEffect, CombatBuff, CombatEffect, CombatRequirement},
|
||||||
Attack, AttackEffect, CombatBuff, CombatRequirement, DamageComponent, EffectComponent,
|
comp::{CharacterState, EnergyChange, EnergySource, Melee, StateUpdate},
|
||||||
},
|
|
||||||
comp::{CharacterState, EnergyChange, EnergySource, MeleeAttack, StateUpdate},
|
|
||||||
consts::GRAVITY,
|
consts::GRAVITY,
|
||||||
states::{
|
states::{
|
||||||
behavior::{CharacterBehavior, JoinData},
|
behavior::{CharacterBehavior, JoinData},
|
||||||
@ -115,22 +113,28 @@ impl CharacterBehavior for Data {
|
|||||||
..*self
|
..*self
|
||||||
});
|
});
|
||||||
|
|
||||||
let poise = AttackEffect::Poise(self.static_data.base_poise_damage as f32);
|
let poise = AttackEffect::new(
|
||||||
let poise = EffectComponent::new(Some(GroupTarget::OutOfGroup), poise)
|
Some(GroupTarget::OutOfGroup),
|
||||||
.with_requirement(CombatRequirement::AnyDamage);
|
CombatEffect::Poise(self.static_data.base_poise_damage as f32),
|
||||||
let knockback = AttackEffect::Knockback(Knockback {
|
)
|
||||||
strength: self.static_data.knockback,
|
.with_requirement(CombatRequirement::AnyDamage);
|
||||||
direction: KnockbackDir::Away,
|
let knockback = AttackEffect::new(
|
||||||
});
|
Some(GroupTarget::OutOfGroup),
|
||||||
let knockback = EffectComponent::new(Some(GroupTarget::OutOfGroup), knockback)
|
CombatEffect::Knockback(Knockback {
|
||||||
.with_requirement(CombatRequirement::AnyDamage);
|
strength: self.static_data.knockback,
|
||||||
let buff = AttackEffect::Buff(CombatBuff::default_physical());
|
direction: KnockbackDir::Away,
|
||||||
let damage = Damage {
|
}),
|
||||||
source: DamageSource::Melee,
|
)
|
||||||
value: self.static_data.base_damage as f32,
|
.with_requirement(CombatRequirement::AnyDamage);
|
||||||
};
|
let buff = CombatEffect::Buff(CombatBuff::default_physical());
|
||||||
let damage = DamageComponent::new(damage, Some(GroupTarget::OutOfGroup))
|
let damage = AttackDamage::new(
|
||||||
.with_effect(buff);
|
Damage {
|
||||||
|
source: DamageSource::Melee,
|
||||||
|
value: self.static_data.base_damage as f32,
|
||||||
|
},
|
||||||
|
Some(GroupTarget::OutOfGroup),
|
||||||
|
)
|
||||||
|
.with_effect(buff);
|
||||||
let attack = Attack::default()
|
let attack = Attack::default()
|
||||||
.with_damage(damage)
|
.with_damage(damage)
|
||||||
.with_crit(0.5, 1.3)
|
.with_crit(0.5, 1.3)
|
||||||
@ -138,7 +142,7 @@ impl CharacterBehavior for Data {
|
|||||||
.with_effect(knockback);
|
.with_effect(knockback);
|
||||||
|
|
||||||
// Hit attempt
|
// Hit attempt
|
||||||
data.updater.insert(data.entity, MeleeAttack {
|
data.updater.insert(data.entity, Melee {
|
||||||
attack,
|
attack,
|
||||||
range: self.static_data.range,
|
range: self.static_data.range,
|
||||||
max_angle: 180_f32.to_radians(),
|
max_angle: 180_f32.to_radians(),
|
||||||
@ -213,14 +217,14 @@ impl CharacterBehavior for Data {
|
|||||||
// Done
|
// Done
|
||||||
update.character = CharacterState::Wielding;
|
update.character = CharacterState::Wielding;
|
||||||
// Make sure attack component is removed
|
// Make sure attack component is removed
|
||||||
data.updater.remove::<MeleeAttack>(data.entity);
|
data.updater.remove::<Melee>(data.entity);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
// If it somehow ends up in an incorrect stage section
|
// If it somehow ends up in an incorrect stage section
|
||||||
update.character = CharacterState::Wielding;
|
update.character = CharacterState::Wielding;
|
||||||
// Make sure attack component is removed
|
// Make sure attack component is removed
|
||||||
data.updater.remove::<MeleeAttack>(data.entity);
|
data.updater.remove::<Melee>(data.entity);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use common::{
|
use common::{
|
||||||
|
combat::AttackerInfo,
|
||||||
comp::{
|
comp::{
|
||||||
group, Beam, BeamSegment, Body, Energy, Health, HealthSource, Inventory, Last, Ori, Pos,
|
group, Beam, BeamSegment, Body, Energy, Health, HealthSource, Inventory, Last, Ori, Pos,
|
||||||
Scale,
|
Scale,
|
||||||
@ -168,25 +169,27 @@ impl<'a> System<'a> for Sys {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let server_events = beam_segment.properties.attack.apply_attack(
|
let attacker_info =
|
||||||
|
beam_owner
|
||||||
|
.zip(beam_segment.owner)
|
||||||
|
.map(|(entity, uid)| AttackerInfo {
|
||||||
|
entity,
|
||||||
|
uid,
|
||||||
|
energy: energies.get(entity),
|
||||||
|
});
|
||||||
|
|
||||||
|
beam_segment.properties.attack.apply_attack(
|
||||||
target_group,
|
target_group,
|
||||||
beam_owner,
|
attacker_info,
|
||||||
b,
|
b,
|
||||||
inventory_b_maybe,
|
inventory_b_maybe,
|
||||||
beam_segment.owner,
|
|
||||||
beam_owner.and_then(|e| energies.get(e)),
|
|
||||||
ori.0,
|
ori.0,
|
||||||
false,
|
false,
|
||||||
1.0,
|
1.0,
|
||||||
|
|e| server_emitter.emit(e),
|
||||||
);
|
);
|
||||||
|
|
||||||
if !server_events.is_empty() {
|
hit_entities.push(*uid_b);
|
||||||
hit_entities.push(*uid_b);
|
|
||||||
}
|
|
||||||
|
|
||||||
for event in server_events {
|
|
||||||
server_emitter.emit(event);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,8 @@ use specs::{Entities, Join, LazyUpdate, Read, ReadExpect, ReadStorage, System, W
|
|||||||
use common::{
|
use common::{
|
||||||
comp::{
|
comp::{
|
||||||
inventory::slot::{EquipSlot, Slot},
|
inventory::slot::{EquipSlot, Slot},
|
||||||
Beam, Body, CharacterState, Controller, Energy, Health, Inventory, MeleeAttack, Mounting,
|
Beam, Body, CharacterState, Controller, Energy, Health, Inventory, Melee, Mounting, Ori,
|
||||||
Ori, PhysicsState, Poise, PoiseState, Pos, StateUpdate, Stats, Vel,
|
PhysicsState, Poise, PoiseState, Pos, StateUpdate, Stats, Vel,
|
||||||
},
|
},
|
||||||
event::{EventBus, LocalEvent, ServerEvent},
|
event::{EventBus, LocalEvent, ServerEvent},
|
||||||
metrics::SysMetrics,
|
metrics::SysMetrics,
|
||||||
@ -69,7 +69,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
WriteStorage<'a, Poise>,
|
WriteStorage<'a, Poise>,
|
||||||
ReadStorage<'a, Body>,
|
ReadStorage<'a, Body>,
|
||||||
ReadStorage<'a, PhysicsState>,
|
ReadStorage<'a, PhysicsState>,
|
||||||
ReadStorage<'a, MeleeAttack>,
|
ReadStorage<'a, Melee>,
|
||||||
ReadStorage<'a, Beam>,
|
ReadStorage<'a, Beam>,
|
||||||
ReadStorage<'a, Uid>,
|
ReadStorage<'a, Uid>,
|
||||||
ReadStorage<'a, Mounting>,
|
ReadStorage<'a, Mounting>,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use common::{
|
use common::{
|
||||||
comp::{group, Body, CharacterState, Energy, Health, Inventory, MeleeAttack, Ori, Pos, Scale},
|
combat::AttackerInfo,
|
||||||
|
comp::{group, Body, CharacterState, Energy, Health, Inventory, Melee, Ori, Pos, Scale},
|
||||||
event::{EventBus, LocalEvent, ServerEvent},
|
event::{EventBus, LocalEvent, ServerEvent},
|
||||||
metrics::SysMetrics,
|
metrics::SysMetrics,
|
||||||
span,
|
span,
|
||||||
@ -29,7 +30,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
ReadStorage<'a, Energy>,
|
ReadStorage<'a, Energy>,
|
||||||
ReadStorage<'a, Inventory>,
|
ReadStorage<'a, Inventory>,
|
||||||
ReadStorage<'a, group::Group>,
|
ReadStorage<'a, group::Group>,
|
||||||
WriteStorage<'a, MeleeAttack>,
|
WriteStorage<'a, Melee>,
|
||||||
ReadStorage<'a, CharacterState>,
|
ReadStorage<'a, CharacterState>,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -129,25 +130,24 @@ impl<'a> System<'a> for Sys {
|
|||||||
|
|
||||||
let dir = Dir::new((pos_b.0 - pos.0).try_normalized().unwrap_or(*ori.0));
|
let dir = Dir::new((pos_b.0 - pos.0).try_normalized().unwrap_or(*ori.0));
|
||||||
|
|
||||||
let server_events = attack.attack.apply_attack(
|
let attacker_info = Some(AttackerInfo {
|
||||||
|
entity,
|
||||||
|
uid: *uid,
|
||||||
|
energy: energies.get(entity),
|
||||||
|
});
|
||||||
|
|
||||||
|
attack.attack.apply_attack(
|
||||||
target_group,
|
target_group,
|
||||||
Some(entity),
|
attacker_info,
|
||||||
b,
|
b,
|
||||||
inventory_b_maybe,
|
inventory_b_maybe,
|
||||||
Some(*uid),
|
|
||||||
energies.get(entity),
|
|
||||||
dir,
|
dir,
|
||||||
is_dodge,
|
is_dodge,
|
||||||
1.0,
|
1.0,
|
||||||
|
|e| server_emitter.emit(e),
|
||||||
);
|
);
|
||||||
|
|
||||||
if !server_events.is_empty() {
|
attack.hit_count += 1;
|
||||||
attack.hit_count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for event in server_events {
|
|
||||||
server_emitter.emit(event);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use common::{
|
use common::{
|
||||||
|
combat::AttackerInfo,
|
||||||
comp::{
|
comp::{
|
||||||
projectile, Energy, Group, HealthSource, Inventory, Ori, PhysicsState, Pos, Projectile, Vel,
|
projectile, Energy, Group, HealthSource, Inventory, Ori, PhysicsState, Pos, Projectile, Vel,
|
||||||
},
|
},
|
||||||
@ -109,50 +110,28 @@ impl<'a> System<'a> for Sys {
|
|||||||
let owner_entity = projectile
|
let owner_entity = projectile
|
||||||
.owner
|
.owner
|
||||||
.and_then(|u| uid_allocator.retrieve_entity_internal(u.into()));
|
.and_then(|u| uid_allocator.retrieve_entity_internal(u.into()));
|
||||||
let server_events = attack.apply_attack(
|
|
||||||
|
let attacker_info =
|
||||||
|
owner_entity.zip(projectile.owner).map(|(entity, uid)| {
|
||||||
|
AttackerInfo {
|
||||||
|
entity,
|
||||||
|
uid,
|
||||||
|
energy: energies.get(entity),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
attack.apply_attack(
|
||||||
target_group,
|
target_group,
|
||||||
owner_entity,
|
attacker_info,
|
||||||
target_entity,
|
target_entity,
|
||||||
inventories.get(target_entity),
|
inventories.get(target_entity),
|
||||||
projectile.owner,
|
|
||||||
owner_entity.and_then(|e| energies.get(e)),
|
|
||||||
ori.0,
|
ori.0,
|
||||||
false,
|
false,
|
||||||
1.0,
|
1.0,
|
||||||
|
|e| server_emitter.emit(e),
|
||||||
);
|
);
|
||||||
|
|
||||||
for event in server_events {
|
|
||||||
server_emitter.emit(event);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// projectile::Effect::Knockback(knockback) => {
|
|
||||||
// if let Some(other_entity) =
|
|
||||||
// uid_allocator.retrieve_entity_internal(other.into())
|
|
||||||
// {
|
|
||||||
// let impulse = knockback.calculate_impulse(ori.0);
|
|
||||||
// if !impulse.is_approx_zero() {
|
|
||||||
// server_emitter.emit(ServerEvent::Knockback {
|
|
||||||
// entity: other_entity,
|
|
||||||
// impulse,
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// projectile::Effect::RewardEnergy(energy) => {
|
|
||||||
// if let Some(entity_owner) = projectile
|
|
||||||
// .owner
|
|
||||||
// .and_then(|u| uid_allocator.retrieve_entity_internal(u.into()))
|
|
||||||
// {
|
|
||||||
// server_emitter.emit(ServerEvent::EnergyChange {
|
|
||||||
// entity: entity_owner,
|
|
||||||
// change: EnergyChange {
|
|
||||||
// amount: energy as i32,
|
|
||||||
// source: EnergySource::HitEnemy,
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
projectile::Effect::Explode(e) => {
|
projectile::Effect::Explode(e) => {
|
||||||
server_emitter.emit(ServerEvent::Explosion {
|
server_emitter.emit(ServerEvent::Explosion {
|
||||||
pos: pos.0,
|
pos: pos.0,
|
||||||
@ -175,26 +154,6 @@ impl<'a> System<'a> for Sys {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// TODO: Change to effect after !1472 merges
|
|
||||||
// projectile::Effect::Buff { buff, chance } => {
|
|
||||||
// if let Some(entity) =
|
|
||||||
// uid_allocator.retrieve_entity_internal(other.into())
|
|
||||||
// {
|
|
||||||
// if chance.map_or(true, |c| thread_rng().gen::<f32>() < c) {
|
|
||||||
// let source = if let Some(owner) = projectile.owner {
|
|
||||||
// BuffSource::Character { by: owner }
|
|
||||||
// } else {
|
|
||||||
// BuffSource::Unknown
|
|
||||||
// };
|
|
||||||
// let buff =
|
|
||||||
// Buff::new(buff.kind, buff.data, buff.cat_ids, source);
|
|
||||||
// server_emitter.emit(ServerEvent::Buff {
|
|
||||||
// entity,
|
|
||||||
// buff_change: BuffChange::Add(buff),
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use common::{
|
use common::{
|
||||||
|
combat::AttackerInfo,
|
||||||
comp::{
|
comp::{
|
||||||
group, Body, Energy, Health, HealthSource, Inventory, Last, Ori, PhysicsState, Pos, Scale,
|
group, Body, Energy, Health, HealthSource, Inventory, Last, Ori, PhysicsState, Pos, Scale,
|
||||||
Shockwave, ShockwaveHitEntities,
|
Shockwave, ShockwaveHitEntities,
|
||||||
@ -195,25 +196,27 @@ impl<'a> System<'a> for Sys {
|
|||||||
if hit {
|
if hit {
|
||||||
let dir = Dir::new((pos_b.0 - pos.0).try_normalized().unwrap_or(*ori.0));
|
let dir = Dir::new((pos_b.0 - pos.0).try_normalized().unwrap_or(*ori.0));
|
||||||
|
|
||||||
let server_events = shockwave.properties.attack.apply_attack(
|
let attacker_info =
|
||||||
|
shockwave_owner
|
||||||
|
.zip(shockwave.owner)
|
||||||
|
.map(|(entity, uid)| AttackerInfo {
|
||||||
|
entity,
|
||||||
|
uid,
|
||||||
|
energy: energies.get(entity),
|
||||||
|
});
|
||||||
|
|
||||||
|
shockwave.properties.attack.apply_attack(
|
||||||
target_group,
|
target_group,
|
||||||
shockwave_owner,
|
attacker_info,
|
||||||
b,
|
b,
|
||||||
inventories.get(b),
|
inventories.get(b),
|
||||||
shockwave.owner,
|
|
||||||
shockwave_owner.and_then(|e| energies.get(e)),
|
|
||||||
dir,
|
dir,
|
||||||
false,
|
false,
|
||||||
1.0,
|
1.0,
|
||||||
|
|e| server_emitter.emit(e),
|
||||||
);
|
);
|
||||||
|
|
||||||
if !server_events.is_empty() {
|
shockwave_hit_list.hit_entities.push(*uid_b);
|
||||||
shockwave_hit_list.hit_entities.push(*uid_b);
|
|
||||||
}
|
|
||||||
|
|
||||||
for event in server_events {
|
|
||||||
server_emitter.emit(event);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,7 +163,7 @@ impl State {
|
|||||||
ecs.register::<comp::Admin>();
|
ecs.register::<comp::Admin>();
|
||||||
ecs.register::<comp::Waypoint>();
|
ecs.register::<comp::Waypoint>();
|
||||||
ecs.register::<comp::Projectile>();
|
ecs.register::<comp::Projectile>();
|
||||||
ecs.register::<comp::MeleeAttack>();
|
ecs.register::<comp::Melee>();
|
||||||
ecs.register::<comp::ItemDrop>();
|
ecs.register::<comp::ItemDrop>();
|
||||||
ecs.register::<comp::ChatMode>();
|
ecs.register::<comp::ChatMode>();
|
||||||
ecs.register::<comp::Faction>();
|
ecs.register::<comp::Faction>();
|
||||||
|
@ -174,7 +174,7 @@ pub fn handle_beam(server: &mut Server, properties: beam::Properties, pos: Pos,
|
|||||||
heal: properties
|
heal: properties
|
||||||
.attack
|
.attack
|
||||||
.effects()
|
.effects()
|
||||||
.any(|e| matches!(e.effect(), combat::AttackEffect::Heal(h) if *h > 0.0)),
|
.any(|e| matches!(e.effect(), combat::CombatEffect::Heal(h) if *h > 0.0)),
|
||||||
});
|
});
|
||||||
state.create_beam(properties, pos, ori).build();
|
state.create_beam(properties, pos, ori).build();
|
||||||
}
|
}
|
||||||
|
@ -510,7 +510,8 @@ pub fn handle_land_on_ground(server: &Server, entity: EcsEntity, vel: Vec3<f32>)
|
|||||||
source: DamageSource::Falling,
|
source: DamageSource::Falling,
|
||||||
value: falldmg,
|
value: falldmg,
|
||||||
};
|
};
|
||||||
let change = damage.modify_damage(inventories.get(entity), None, false, 0.0, 1.0);
|
let change =
|
||||||
|
damage.calculate_health_change(inventories.get(entity), None, false, 0.0, 1.0);
|
||||||
health.change_by(change);
|
health.change_by(change);
|
||||||
}
|
}
|
||||||
// Handle poise change
|
// Handle poise change
|
||||||
@ -578,7 +579,7 @@ pub fn handle_explosion(
|
|||||||
// Add an outcome
|
// Add an outcome
|
||||||
// Uses radius as outcome power, makes negative if explosion has healing effect
|
// Uses radius as outcome power, makes negative if explosion has healing effect
|
||||||
let outcome_power = explosion.radius
|
let outcome_power = explosion.radius
|
||||||
* if explosion.effects.iter().any(|e| matches!(e, RadiusEffect::Attack(a) if a.effects().any(|e| matches!(e.effect(), combat::AttackEffect::Heal(h) if *h > 0.0)))) {
|
* if explosion.effects.iter().any(|e| matches!(e, RadiusEffect::Attack(a) if a.effects().any(|e| matches!(e.effect(), combat::CombatEffect::Heal(h) if *h > 0.0)))) {
|
||||||
-1.0
|
-1.0
|
||||||
} else {
|
} else {
|
||||||
1.0
|
1.0
|
||||||
@ -708,23 +709,27 @@ pub fn handle_explosion(
|
|||||||
.unwrap_or_else(Vec3::unit_z),
|
.unwrap_or_else(Vec3::unit_z),
|
||||||
);
|
);
|
||||||
|
|
||||||
let server_events = attack.apply_attack(
|
let attacker_info =
|
||||||
target_group,
|
owner_entity
|
||||||
owner_entity,
|
.zip(owner)
|
||||||
entity_b,
|
.map(|(entity, uid)| combat::AttackerInfo {
|
||||||
inventory_b_maybe,
|
entity,
|
||||||
owner,
|
uid,
|
||||||
owner_entity.and_then(|e| energies.get(e)),
|
energy: energies.get(entity),
|
||||||
dir,
|
});
|
||||||
false,
|
|
||||||
strength,
|
|
||||||
);
|
|
||||||
|
|
||||||
let server_eventbus = ecs.read_resource::<EventBus<ServerEvent>>();
|
let server_eventbus = ecs.read_resource::<EventBus<ServerEvent>>();
|
||||||
|
|
||||||
for event in server_events {
|
attack.apply_attack(
|
||||||
server_eventbus.emit_now(event);
|
target_group,
|
||||||
}
|
attacker_info,
|
||||||
|
entity_b,
|
||||||
|
inventory_b_maybe,
|
||||||
|
dir,
|
||||||
|
false,
|
||||||
|
strength,
|
||||||
|
|e| server_eventbus.emit_now(e),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -90,7 +90,13 @@ impl StateExt for State {
|
|||||||
},
|
},
|
||||||
Effect::Damage(damage) => {
|
Effect::Damage(damage) => {
|
||||||
let inventories = self.ecs().read_storage::<Inventory>();
|
let inventories = self.ecs().read_storage::<Inventory>();
|
||||||
let change = damage.modify_damage(inventories.get(entity), source, false, 0.0, 1.0);
|
let change = damage.calculate_health_change(
|
||||||
|
inventories.get(entity),
|
||||||
|
source,
|
||||||
|
false,
|
||||||
|
0.0,
|
||||||
|
1.0,
|
||||||
|
);
|
||||||
self.ecs()
|
self.ecs()
|
||||||
.write_storage::<comp::Health>()
|
.write_storage::<comp::Health>()
|
||||||
.get_mut(entity)
|
.get_mut(entity)
|
||||||
|
Loading…
Reference in New Issue
Block a user