Server event used to deal damage/heal with buffs. Buff kills now award xp.

This commit is contained in:
Sam 2020-10-03 13:48:56 -05:00
parent de7191b985
commit 1a1ceb54bc
11 changed files with 102 additions and 25 deletions

View File

@ -184,6 +184,7 @@ https://account.veloren.net."#,
"hud.chat.pvp_ranged_kill_msg": "[{attacker}] shot [{victim}]", "hud.chat.pvp_ranged_kill_msg": "[{attacker}] shot [{victim}]",
"hud.chat.pvp_explosion_kill_msg": "[{attacker}] blew up [{victim}]", "hud.chat.pvp_explosion_kill_msg": "[{attacker}] blew up [{victim}]",
"hud.chat.pvp_energy_kill_msg": "[{attacker}] used magic to kill [{victim}]", "hud.chat.pvp_energy_kill_msg": "[{attacker}] used magic to kill [{victim}]",
"hud.chat.pvp_buff_kill_msg": "[{attacker}] killed [{victim}]",
"hud.chat.npc_melee_kill_msg": "{attacker} killed [{victim}]", "hud.chat.npc_melee_kill_msg": "{attacker} killed [{victim}]",
"hud.chat.npc_ranged_kill_msg": "{attacker} shot [{victim}]", "hud.chat.npc_ranged_kill_msg": "{attacker} shot [{victim}]",

View File

@ -1715,6 +1715,11 @@ impl Client {
alias_of_uid(attacker_uid), alias_of_uid(attacker_uid),
alias_of_uid(victim) alias_of_uid(victim)
), ),
KillSource::Player(attacker_uid, KillType::Buff) => format!(
"[{}] killed [{}]",
alias_of_uid(attacker_uid),
alias_of_uid(victim)
),
KillSource::NonPlayer(attacker_name, KillType::Melee) => { KillSource::NonPlayer(attacker_name, KillType::Melee) => {
format!("{} killed [{}]", attacker_name, alias_of_uid(victim)) format!("{} killed [{}]", attacker_name, alias_of_uid(victim))
}, },
@ -1729,6 +1734,9 @@ impl Client {
attacker_name, attacker_name,
alias_of_uid(victim) alias_of_uid(victim)
), ),
KillSource::NonPlayer(attacker_name, KillType::Buff) => {
format!("{} killed [{}]", attacker_name, alias_of_uid(victim))
},
KillSource::Environment(environment) => { KillSource::Environment(environment) => {
format!("[{}] died in {}", alias_of_uid(victim), environment) format!("[{}] died in {}", alias_of_uid(victim), environment)
}, },
@ -1754,6 +1762,9 @@ impl Client {
KillSource::Player(attacker_uid, KillType::Energy) => message KillSource::Player(attacker_uid, KillType::Energy) => message
.replace("{attacker}", &alias_of_uid(attacker_uid)) .replace("{attacker}", &alias_of_uid(attacker_uid))
.replace("{victim}", &alias_of_uid(victim)), .replace("{victim}", &alias_of_uid(victim)),
KillSource::Player(attacker_uid, KillType::Buff) => message
.replace("{attacker}", &alias_of_uid(attacker_uid))
.replace("{victim}", &alias_of_uid(victim)),
KillSource::NonPlayer(attacker_name, KillType::Melee) => message KillSource::NonPlayer(attacker_name, KillType::Melee) => message
.replace("{attacker}", attacker_name) .replace("{attacker}", attacker_name)
.replace("{victim}", &alias_of_uid(victim)), .replace("{victim}", &alias_of_uid(victim)),
@ -1766,6 +1777,9 @@ impl Client {
KillSource::NonPlayer(attacker_name, KillType::Energy) => message KillSource::NonPlayer(attacker_name, KillType::Energy) => message
.replace("{attacker}", attacker_name) .replace("{attacker}", attacker_name)
.replace("{victim}", &alias_of_uid(victim)), .replace("{victim}", &alias_of_uid(victim)),
KillSource::NonPlayer(attacker_name, KillType::Buff) => message
.replace("{attacker}", attacker_name)
.replace("{victim}", &alias_of_uid(victim)),
KillSource::Environment(environment) => message KillSource::Environment(environment) => message
.replace("{name}", &alias_of_uid(victim)) .replace("{name}", &alias_of_uid(victim))
.replace("{environment}", environment), .replace("{environment}", environment),

View File

@ -16,11 +16,9 @@ use std::time::Duration;
#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)] #[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)]
pub enum BuffId { pub enum BuffId {
/// Restores health/time for some period /// Restores health/time for some period
/// Has fields: strength (f32) Regeneration { strength: f32 },
Regeneration(f32),
/// Lowers health over time for some duration /// Lowers health over time for some duration
/// Has fields: strength (f32) Bleeding { strength: f32 },
Bleeding(f32),
/// Prefixes an entity's name with "Cursed" /// Prefixes an entity's name with "Cursed"
/// Currently placeholder buff to show other stuff is possible /// Currently placeholder buff to show other stuff is possible
Cursed, Cursed,
@ -73,6 +71,7 @@ pub struct Buff {
pub cat_ids: Vec<BuffCategoryId>, pub cat_ids: Vec<BuffCategoryId>,
pub time: Option<Duration>, pub time: Option<Duration>,
pub effects: Vec<BuffEffect>, pub effects: Vec<BuffEffect>,
pub source: BuffSource,
} }
/// Information about whether buff addition or removal was requested. /// Information about whether buff addition or removal was requested.
@ -144,9 +143,14 @@ impl Buffs {
} }
impl Buff { impl Buff {
pub fn new(id: BuffId, time: Option<Duration>, cat_ids: Vec<BuffCategoryId>) -> Self { pub fn new(
id: BuffId,
time: Option<Duration>,
cat_ids: Vec<BuffCategoryId>,
source: BuffSource,
) -> Self {
let effects = match id { let effects = match id {
BuffId::Bleeding(strength) => vec![ BuffId::Bleeding { strength } => vec![
BuffEffect::HealthChangeOverTime { BuffEffect::HealthChangeOverTime {
rate: -strength, rate: -strength,
accumulated: 0.0, accumulated: 0.0,
@ -156,7 +160,7 @@ impl Buff {
prefix: String::from("Injured "), prefix: String::from("Injured "),
}, },
], ],
BuffId::Regeneration(strength) => vec![BuffEffect::HealthChangeOverTime { BuffId::Regeneration { strength } => vec![BuffEffect::HealthChangeOverTime {
rate: strength, rate: strength,
accumulated: 0.0, accumulated: 0.0,
}], }],
@ -169,6 +173,7 @@ impl Buff {
cat_ids, cat_ids,
time, time,
effects, effects,
source,
} }
} }
} }

View File

@ -51,6 +51,7 @@ pub enum KillType {
Projectile, Projectile,
Explosion, Explosion,
Energy, Energy,
Buff,
// Projectile(String), TODO: add projectile name when available // Projectile(String), TODO: add projectile name when available
} }

View File

@ -32,7 +32,7 @@ pub use body::{
biped_large, bird_medium, bird_small, dragon, fish_medium, fish_small, golem, humanoid, object, biped_large, bird_medium, bird_small, dragon, fish_medium, fish_small, golem, humanoid, object,
quadruped_low, quadruped_medium, quadruped_small, theropod, AllBodies, Body, BodyData, quadruped_low, quadruped_medium, quadruped_small, theropod, AllBodies, Body, BodyData,
}; };
pub use buff::{Buff, BuffCategoryId, BuffChange, BuffEffect, BuffId, Buffs}; pub use buff::{Buff, BuffCategoryId, BuffChange, BuffEffect, BuffId, BuffSource, Buffs};
pub use character_state::{Attacking, CharacterState, StateUpdate}; pub use character_state::{Attacking, CharacterState, StateUpdate};
pub use chat::{ pub use chat::{
ChatMode, ChatMsg, ChatType, Faction, SpeechBubble, SpeechBubbleType, UnresolvedChatMsg, ChatMode, ChatMsg, ChatType, Faction, SpeechBubble, SpeechBubbleType, UnresolvedChatMsg,

View File

@ -20,6 +20,7 @@ pub enum HealthSource {
Projectile { owner: Option<Uid> }, Projectile { owner: Option<Uid> },
Explosion { owner: Option<Uid> }, Explosion { owner: Option<Uid> },
Energy { owner: Option<Uid> }, Energy { owner: Option<Uid> },
Buff { owner: Option<Uid> },
Suicide, Suicide,
World, World,
Revive, Revive,

View File

@ -601,6 +601,7 @@ impl<'a> System<'a> for Sys {
if let comp::HealthSource::Attack { by } if let comp::HealthSource::Attack { by }
| comp::HealthSource::Projectile { owner: Some(by) } | comp::HealthSource::Projectile { owner: Some(by) }
| comp::HealthSource::Energy { owner: Some(by) } | comp::HealthSource::Energy { owner: Some(by) }
| comp::HealthSource::Buff { owner: Some(by) }
| comp::HealthSource::Explosion { owner: Some(by) } = | comp::HealthSource::Explosion { owner: Some(by) } =
my_stats.health.last_change.1.cause my_stats.health.last_change.1.cause
{ {

View File

@ -1,10 +1,10 @@
use crate::{ use crate::{
comp::{BuffChange, BuffEffect, Buffs, HealthChange, HealthSource, Stats}, comp::{BuffChange, BuffEffect, BuffSource, Buffs, HealthChange, HealthSource},
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
state::DeltaTime, state::DeltaTime,
sync::Uid, sync::Uid,
}; };
use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage}; use specs::{Join, Read, ReadStorage, System, WriteStorage};
use std::time::Duration; use std::time::Duration;
/// This system modifies entity stats, changing them using buffs /// This system modifies entity stats, changing them using buffs
@ -16,17 +16,15 @@ pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> System<'a> for Sys {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
type SystemData = ( type SystemData = (
Entities<'a>,
Read<'a, DeltaTime>, Read<'a, DeltaTime>,
Read<'a, EventBus<ServerEvent>>, Read<'a, EventBus<ServerEvent>>,
ReadStorage<'a, Uid>, ReadStorage<'a, Uid>,
WriteStorage<'a, Stats>,
WriteStorage<'a, Buffs>, WriteStorage<'a, Buffs>,
); );
fn run(&mut self, (entities, dt, server_bus, uids, mut stats, mut buffs): Self::SystemData) { fn run(&mut self, (dt, server_bus, uids, mut buffs): Self::SystemData) {
let mut server_emitter = server_bus.emitter(); let mut server_emitter = server_bus.emitter();
for (entity, uid, mut buffs) in (&entities, &uids, &mut buffs.restrict_mut()).join() { for (uid, mut buffs) in (&uids, &mut buffs.restrict_mut()).join() {
let buff_comp = buffs.get_mut_unchecked(); let buff_comp = buffs.get_mut_unchecked();
let (mut active_buff_indices_for_removal, mut inactive_buff_indices_for_removal) = let (mut active_buff_indices_for_removal, mut inactive_buff_indices_for_removal) =
(Vec::<usize>::new(), Vec::<usize>::new()); (Vec::<usize>::new(), Vec::<usize>::new());
@ -56,6 +54,12 @@ impl<'a> System<'a> for Sys {
dt.0 dt.0
}; };
let buff_owner =
if let BuffSource::Character { by: owner } = buff_comp.active_buffs[i].source {
Some(owner)
} else {
None
};
// Now, execute the buff, based on it's delta // Now, execute the buff, based on it's delta
for effect in &mut buff_comp.active_buffs[i].effects { for effect in &mut buff_comp.active_buffs[i].effects {
#[allow(clippy::single_match)] #[allow(clippy::single_match)]
@ -66,13 +70,18 @@ impl<'a> System<'a> for Sys {
*accumulated += *rate * buff_delta; *accumulated += *rate * buff_delta;
// Apply only 0.5 or higher damage // Apply only 0.5 or higher damage
if accumulated.abs() > 5.0 { if accumulated.abs() > 5.0 {
if let Some(stats) = stats.get_mut(entity) { let cause = if *accumulated > 0.0 {
let change = HealthChange { HealthSource::Healing { by: buff_owner }
amount: *accumulated as i32, } else {
cause: HealthSource::Unknown, HealthSource::Buff { owner: buff_owner }
}; };
stats.health.change_by(change); server_emitter.emit(ServerEvent::Damage {
} uid: *uid,
change: HealthChange {
amount: *accumulated as i32,
cause,
},
});
*accumulated = 0.0; *accumulated = 0.0;
}; };
}, },

View File

@ -155,9 +155,12 @@ impl<'a> System<'a> for Sys {
server_emitter.emit(ServerEvent::Buff { server_emitter.emit(ServerEvent::Buff {
uid: *uid_b, uid: *uid_b,
buff_change: buff::BuffChange::Add(buff::Buff::new( buff_change: buff::BuffChange::Add(buff::Buff::new(
buff::BuffId::Bleeding(-damage.healthchange), buff::BuffId::Bleeding {
strength: -damage.healthchange,
},
Some(Duration::from_millis(10000)), Some(Duration::from_millis(10000)),
vec![buff::BuffCategoryId::Physical], vec![buff::BuffCategoryId::Physical],
buff::BuffSource::Character { by: *uid },
)), )),
}); });
attack.hit_count += 1; attack.hit_count += 1;

View File

@ -166,11 +166,34 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc
KillSource::NonPlayer("<?>".to_string(), KillType::Energy) KillSource::NonPlayer("<?>".to_string(), KillType::Energy)
} }
}, },
HealthSource::Buff { owner: Some(by) } => {
// Get energy owner entity
if let Some(char_entity) = state.ecs().entity_from_uid(by.into()) {
// Check if attacker is another player or entity with stats (npc)
if state
.ecs()
.read_storage::<Player>()
.get(char_entity)
.is_some()
{
KillSource::Player(by, KillType::Buff)
} else if let Some(stats) =
state.ecs().read_storage::<Stats>().get(char_entity)
{
KillSource::NonPlayer(stats.name.clone(), KillType::Buff)
} else {
KillSource::NonPlayer("<?>".to_string(), KillType::Buff)
}
} else {
KillSource::NonPlayer("<?>".to_string(), KillType::Buff)
}
},
HealthSource::World => KillSource::FallDamage, HealthSource::World => KillSource::FallDamage,
HealthSource::Suicide => KillSource::Suicide, HealthSource::Suicide => KillSource::Suicide,
HealthSource::Projectile { owner: None } HealthSource::Projectile { owner: None }
| HealthSource::Explosion { owner: None } | HealthSource::Explosion { owner: None }
| HealthSource::Energy { owner: None } | HealthSource::Energy { owner: None }
| HealthSource::Buff { owner: None }
| HealthSource::Revive | HealthSource::Revive
| HealthSource::Command | HealthSource::Command
| HealthSource::LevelUp | HealthSource::LevelUp
@ -190,6 +213,7 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc
let by = if let HealthSource::Attack { by } let by = if let HealthSource::Attack { by }
| HealthSource::Projectile { owner: Some(by) } | HealthSource::Projectile { owner: Some(by) }
| HealthSource::Energy { owner: Some(by) } | HealthSource::Energy { owner: Some(by) }
| HealthSource::Buff { owner: Some(by) }
| HealthSource::Explosion { owner: Some(by) } = cause | HealthSource::Explosion { owner: Some(by) } = cause
{ {
by by
@ -836,15 +860,25 @@ pub fn handle_buff(server: &mut Server, uid: Uid, buff_change: buff::BuffChange)
fn determine_replace_active_buff(active_buff: buff::Buff, new_buff: buff::Buff) -> bool { fn determine_replace_active_buff(active_buff: buff::Buff, new_buff: buff::Buff) -> bool {
use buff::BuffId; use buff::BuffId;
match new_buff.id { match new_buff.id {
BuffId::Bleeding(new_strength) => { BuffId::Bleeding {
if let BuffId::Bleeding(active_strength) = active_buff.id { strength: new_strength,
} => {
if let BuffId::Bleeding {
strength: active_strength,
} = active_buff.id
{
new_strength > active_strength new_strength > active_strength
} else { } else {
false false
} }
}, },
BuffId::Regeneration(new_strength) => { BuffId::Regeneration {
if let BuffId::Regeneration(active_strength) = active_buff.id { strength: new_strength,
} => {
if let BuffId::Regeneration {
strength: active_strength,
} = active_buff.id
{
new_strength > active_strength new_strength > active_strength
} else { } else {
false false

View File

@ -373,6 +373,10 @@ impl<'a> Widget for Chat<'a> {
.localized_strings .localized_strings
.get("hud.chat.pvp_energy_kill_msg") .get("hud.chat.pvp_energy_kill_msg")
.to_string(), .to_string(),
KillSource::Player(_, KillType::Buff) => self
.localized_strings
.get("hud.chat.pvp_buff_kill_msg")
.to_string(),
KillSource::NonPlayer(_, KillType::Melee) => self KillSource::NonPlayer(_, KillType::Melee) => self
.localized_strings .localized_strings
.get("hud.chat.npc_melee_kill_msg") .get("hud.chat.npc_melee_kill_msg")
@ -389,6 +393,10 @@ impl<'a> Widget for Chat<'a> {
.localized_strings .localized_strings
.get("hud.chat.npc_energy_kill_msg") .get("hud.chat.npc_energy_kill_msg")
.to_string(), .to_string(),
KillSource::NonPlayer(_, KillType::Buff) => self
.localized_strings
.get("hud.chat.npc_buff_kill_msg")
.to_string(),
KillSource::Environment(_) => self KillSource::Environment(_) => self
.localized_strings .localized_strings
.get("hud.chat.environmental_kill_msg") .get("hud.chat.environmental_kill_msg")