mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Attacks can now inflict de/buffs.
This commit is contained in:
parent
6d509932db
commit
78879d5189
@ -1,5 +1,6 @@
|
||||
use crate::{
|
||||
comp::{
|
||||
buff::{Buff, BuffChange, BuffData, BuffKind, BuffSource},
|
||||
inventory::{
|
||||
item::{
|
||||
armor::Protection,
|
||||
@ -9,10 +10,8 @@ use crate::{
|
||||
slot::EquipSlot,
|
||||
},
|
||||
skills::{SkillGroupKind, SkillSet},
|
||||
Body, BuffKind, EnergyChange, EnergySource, Health, HealthChange, HealthSource, Inventory,
|
||||
Stats,
|
||||
Body, EnergyChange, EnergySource, Health, HealthChange, HealthSource, Inventory, Stats,
|
||||
},
|
||||
effect,
|
||||
event::ServerEvent,
|
||||
uid::Uid,
|
||||
util::Dir,
|
||||
@ -20,6 +19,7 @@ use crate::{
|
||||
use rand::{thread_rng, Rng};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specs::Entity as EcsEntity;
|
||||
use std::time::Duration;
|
||||
use vek::*;
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
@ -70,7 +70,7 @@ impl Attack {
|
||||
attacker_entity: EcsEntity,
|
||||
target_entity: EcsEntity,
|
||||
inventory: Option<&Inventory>,
|
||||
uid: Uid,
|
||||
attacker_uid: Uid,
|
||||
dir: Dir,
|
||||
) -> Vec<ServerEvent> {
|
||||
let is_crit = thread_rng().gen::<f32>() < self.crit_chance;
|
||||
@ -81,10 +81,12 @@ impl Attack {
|
||||
.iter()
|
||||
.filter(|d| d.target.map_or(true, |t| t == target_group))
|
||||
{
|
||||
let change =
|
||||
damage
|
||||
.damage
|
||||
.modify_damage(inventory, Some(uid), is_crit, self.crit_multiplier);
|
||||
let change = damage.damage.modify_damage(
|
||||
inventory,
|
||||
Some(attacker_uid),
|
||||
is_crit,
|
||||
self.crit_multiplier,
|
||||
);
|
||||
if change.amount != 0 {
|
||||
server_events.push(ServerEvent::Damage {
|
||||
entity: target_entity,
|
||||
@ -110,6 +112,16 @@ impl Attack {
|
||||
},
|
||||
});
|
||||
},
|
||||
AttackEffect::Buff(b) => {
|
||||
if thread_rng().gen::<f32>() < b.chance {
|
||||
server_events.push(ServerEvent::Buff {
|
||||
entity: target_entity,
|
||||
buff_change: BuffChange::Add(
|
||||
b.to_buff(attacker_uid, -change.amount as f32),
|
||||
),
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -155,7 +167,7 @@ impl EffectComponent {
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum AttackEffect {
|
||||
//Heal(f32),
|
||||
//Buff(effect::BuffEffect),
|
||||
Buff(CombatBuff),
|
||||
Knockback(Knockback),
|
||||
EnergyReward(u32),
|
||||
//Lifesteal(f32),
|
||||
@ -358,6 +370,53 @@ impl Knockback {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
pub struct CombatBuff {
|
||||
pub kind: BuffKind,
|
||||
pub dur_secs: f32,
|
||||
pub strength: CombatBuffStrength,
|
||||
pub chance: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
pub enum CombatBuffStrength {
|
||||
DamageFraction(f32),
|
||||
Value(f32),
|
||||
}
|
||||
|
||||
impl CombatBuffStrength {
|
||||
fn to_strength(self, damage: f32) -> f32 {
|
||||
match self {
|
||||
CombatBuffStrength::DamageFraction(f) => damage * f,
|
||||
CombatBuffStrength::Value(v) => v,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CombatBuff {
|
||||
fn to_buff(self, uid: Uid, damage: f32) -> Buff {
|
||||
// TODO: Generate BufCategoryId vec (probably requires damage overhaul?)
|
||||
Buff::new(
|
||||
self.kind,
|
||||
BuffData::new(
|
||||
self.strength.to_strength(damage),
|
||||
Some(Duration::from_secs_f32(self.dur_secs)),
|
||||
),
|
||||
Vec::new(),
|
||||
BuffSource::Character { by: uid },
|
||||
)
|
||||
}
|
||||
|
||||
pub fn default_melee() -> Self {
|
||||
Self {
|
||||
kind: BuffKind::Bleeding,
|
||||
dur_secs: 10.0,
|
||||
strength: CombatBuffStrength::DamageFraction(0.1),
|
||||
chance: 0.1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn equipped_tool(inv: &Inventory, slot: EquipSlot) -> Option<&Tool> {
|
||||
inv.equipped(slot).and_then(|i| {
|
||||
if let ItemKind::Tool(tool) = &i.kind() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
combat::{Attack, AttackEffect, DamageComponent},
|
||||
combat::{Attack, AttackEffect, CombatBuff, DamageComponent},
|
||||
comp::{CharacterState, MeleeAttack, PoiseChange, PoiseSource, StateUpdate},
|
||||
states::{
|
||||
behavior::{CharacterBehavior, JoinData},
|
||||
@ -99,9 +99,11 @@ impl CharacterBehavior for Data {
|
||||
direction: KnockbackDir::Away,
|
||||
});
|
||||
let energy = AttackEffect::EnergyReward(50);
|
||||
let buff = AttackEffect::Buff(CombatBuff::default_melee());
|
||||
let damage = DamageComponent::new(damage, Some(GroupTarget::OutOfGroup))
|
||||
.with_effect(knockback)
|
||||
.with_effect(energy);
|
||||
.with_effect(energy)
|
||||
.with_effect(buff);
|
||||
let attack = Attack::default().with_damage(damage).with_crit(0.5, 1.3);
|
||||
|
||||
// Hit attempt
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
combat::{Attack, AttackEffect, DamageComponent},
|
||||
combat::{Attack, AttackEffect, CombatBuff, DamageComponent},
|
||||
comp::{
|
||||
CharacterState, EnergyChange, EnergySource, MeleeAttack, PoiseChange, PoiseSource,
|
||||
StateUpdate,
|
||||
@ -173,8 +173,10 @@ impl CharacterBehavior for Data {
|
||||
strength: knockback,
|
||||
direction: KnockbackDir::Away,
|
||||
});
|
||||
let buff = AttackEffect::Buff(CombatBuff::default_melee());
|
||||
let damage = DamageComponent::new(damage, Some(GroupTarget::OutOfGroup))
|
||||
.with_effect(knockback);
|
||||
.with_effect(knockback)
|
||||
.with_effect(buff);
|
||||
let attack = Attack::default().with_damage(damage).with_crit(0.5, 1.3);
|
||||
|
||||
// Hit attempt
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
combat::{Attack, AttackEffect, DamageComponent},
|
||||
combat::{Attack, AttackEffect, CombatBuff, DamageComponent},
|
||||
comp::{
|
||||
CharacterState, EnergyChange, EnergySource, MeleeAttack, PoiseChange, PoiseSource,
|
||||
StateUpdate,
|
||||
@ -196,9 +196,11 @@ impl CharacterBehavior for Data {
|
||||
+ self.combo * self.static_data.energy_increase,
|
||||
);
|
||||
let energy = AttackEffect::EnergyReward(energy);
|
||||
let buff = AttackEffect::Buff(CombatBuff::default_melee());
|
||||
let damage = DamageComponent::new(damage, Some(GroupTarget::OutOfGroup))
|
||||
.with_effect(knockback)
|
||||
.with_effect(energy);
|
||||
.with_effect(energy)
|
||||
.with_effect(buff);
|
||||
let attack = Attack::default().with_damage(damage).with_crit(0.5, 1.3);
|
||||
|
||||
data.updater.insert(data.entity, MeleeAttack {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
combat::{Attack, AttackEffect, DamageComponent},
|
||||
combat::{Attack, AttackEffect, CombatBuff, DamageComponent},
|
||||
comp::{
|
||||
CharacterState, EnergyChange, EnergySource, MeleeAttack, PoiseChange, PoiseSource,
|
||||
StateUpdate,
|
||||
@ -150,9 +150,11 @@ impl CharacterBehavior for Data {
|
||||
strength: knockback,
|
||||
direction: KnockbackDir::Away,
|
||||
});
|
||||
let buff = AttackEffect::Buff(CombatBuff::default_melee());
|
||||
let damage =
|
||||
DamageComponent::new(damage, Some(GroupTarget::OutOfGroup))
|
||||
.with_effect(knockback);
|
||||
.with_effect(knockback)
|
||||
.with_effect(buff);
|
||||
let attack = Attack::default().with_damage(damage).with_crit(0.5, 1.3);
|
||||
|
||||
data.updater.insert(data.entity, MeleeAttack {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
combat::{Attack, AttackEffect, DamageComponent},
|
||||
combat::{Attack, AttackEffect, CombatBuff, DamageComponent},
|
||||
comp::{CharacterState, MeleeAttack, PoiseChange, PoiseSource, StateUpdate},
|
||||
states::{
|
||||
behavior::{CharacterBehavior, JoinData},
|
||||
@ -156,8 +156,10 @@ impl CharacterBehavior for Data {
|
||||
strength: self.static_data.knockback,
|
||||
direction: KnockbackDir::Away,
|
||||
});
|
||||
let buff = AttackEffect::Buff(CombatBuff::default_melee());
|
||||
let damage = DamageComponent::new(damage, Some(GroupTarget::OutOfGroup))
|
||||
.with_effect(knockback);
|
||||
.with_effect(knockback)
|
||||
.with_effect(buff);
|
||||
let attack = Attack::default().with_damage(damage).with_crit(0.5, 1.3);
|
||||
|
||||
// Hit attempt, when animation plays
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
combat::{Attack, AttackEffect, DamageComponent},
|
||||
combat::{Attack, AttackEffect, CombatBuff, DamageComponent},
|
||||
comp::{
|
||||
CharacterState, EnergyChange, EnergySource, MeleeAttack, PoiseChange, PoiseSource,
|
||||
StateUpdate,
|
||||
@ -124,8 +124,10 @@ impl CharacterBehavior for Data {
|
||||
strength: self.static_data.knockback,
|
||||
direction: KnockbackDir::Away,
|
||||
});
|
||||
let buff = AttackEffect::Buff(CombatBuff::default_melee());
|
||||
let damage = DamageComponent::new(damage, Some(GroupTarget::OutOfGroup))
|
||||
.with_effect(knockback);
|
||||
.with_effect(knockback)
|
||||
.with_effect(buff);
|
||||
let attack = Attack::default().with_damage(damage).with_crit(0.5, 1.3);
|
||||
|
||||
// Hit attempt
|
||||
|
@ -1,5 +1,5 @@
|
||||
use common::{
|
||||
comp::{buff, group, Body, CharacterState, Health, Inventory, MeleeAttack, Ori, Pos, Scale},
|
||||
comp::{group, Body, CharacterState, Health, Inventory, MeleeAttack, Ori, Pos, Scale},
|
||||
event::{EventBus, LocalEvent, ServerEvent},
|
||||
metrics::SysMetrics,
|
||||
span,
|
||||
@ -7,9 +7,7 @@ use common::{
|
||||
util::Dir,
|
||||
GroupTarget,
|
||||
};
|
||||
use rand::{thread_rng, Rng};
|
||||
use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage};
|
||||
use std::time::Duration;
|
||||
use vek::*;
|
||||
|
||||
/// This system is responsible for handling accepted inputs like moving or
|
||||
@ -145,55 +143,6 @@ impl<'a> System<'a> for Sys {
|
||||
for event in server_events {
|
||||
server_emitter.emit(event);
|
||||
}
|
||||
|
||||
/*for (target, damage) in attack.damages.iter() {
|
||||
if let Some(target) = target {
|
||||
if *target != target_group
|
||||
|| (!matches!(target, GroupTarget::InGroup) && is_dodge)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let change = damage.modify_damage(inventories.get(b), Some(*uid));
|
||||
|
||||
server_emitter.emit(ServerEvent::Damage { entity: b, change });
|
||||
|
||||
// Apply bleeding buff on melee hits with 10% chance
|
||||
// TODO: Don't have buff uniformly applied on all melee attacks
|
||||
if change.amount < 0 && thread_rng().gen::<f32>() < 0.1 {
|
||||
use buff::*;
|
||||
server_emitter.emit(ServerEvent::Buff {
|
||||
entity: b,
|
||||
buff_change: BuffChange::Add(Buff::new(
|
||||
BuffKind::Bleeding,
|
||||
BuffData {
|
||||
strength: -change.amount as f32 / 10.0,
|
||||
duration: Some(Duration::from_secs(10)),
|
||||
},
|
||||
vec![BuffCategory::Physical],
|
||||
BuffSource::Character { by: *uid },
|
||||
)),
|
||||
});
|
||||
}
|
||||
|
||||
let kb_dir = Dir::new((pos_b.0 - pos.0).try_normalized().unwrap_or(*ori.0));
|
||||
let impulse = attack.knockback.calculate_impulse(kb_dir);
|
||||
if !impulse.is_approx_zero() {
|
||||
server_emitter.emit(ServerEvent::Knockback { entity: b, impulse });
|
||||
}
|
||||
|
||||
let poise_change = poise_change.modify_poise_damage(inventories.get(b));
|
||||
if poise_change.amount.abs() > 0 {
|
||||
server_emitter.emit(ServerEvent::PoiseChange {
|
||||
entity: b,
|
||||
change: poise_change,
|
||||
kb_dir: *kb_dir,
|
||||
});
|
||||
}
|
||||
|
||||
attack.hit_count += 1;
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user