mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Initial WIP implementation of the Buff system
This commit is contained in:
parent
32d707e57f
commit
7ab99a3bbf
155
common/src/comp/buff.rs
Normal file
155
common/src/comp/buff.rs
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
use crate::sync::Uid;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use specs::{Component, FlaggedStorage};
|
||||||
|
use specs_idvs::IdvStorage;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
/// De/buff ID.
|
||||||
|
/// ID can be independant of an actual type/config of a `BuffData`.
|
||||||
|
/// Therefore, information provided by `BuffId` can be incomplete/incorrect.
|
||||||
|
///
|
||||||
|
/// For example, there could be two regeneration buffs, each with
|
||||||
|
/// different strength, but they could use the same `BuffId`,
|
||||||
|
/// making it harder to recognize which is which.
|
||||||
|
///
|
||||||
|
/// Also, this should be dehardcoded eventually.
|
||||||
|
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||||
|
pub enum BuffId {
|
||||||
|
/// Restores health/time for some period
|
||||||
|
Regeneration,
|
||||||
|
/// Lowers health/time for some period, but faster
|
||||||
|
Poison,
|
||||||
|
/// Changes entity name as to "Cursed {}"
|
||||||
|
Cursed,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// De/buff category ID.
|
||||||
|
/// Similar to `BuffId`, but to mark a category (for more generic usage, like
|
||||||
|
/// positive/negative buffs).
|
||||||
|
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||||
|
pub enum BuffCategoryId {
|
||||||
|
Natural,
|
||||||
|
Magical,
|
||||||
|
Divine,
|
||||||
|
Negative,
|
||||||
|
Positive,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Data indicating and configuring behaviour of a de/buff.
|
||||||
|
///
|
||||||
|
/// NOTE: Contents of this enum are WIP/Placeholder
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub enum BuffData {
|
||||||
|
/// Periodically damages health
|
||||||
|
RepeatedHealthChange { speed: f32, accumulated: f32 },
|
||||||
|
/// Changes name on_add/on_remove
|
||||||
|
NameChange { prefix: String },
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Actual de/buff.
|
||||||
|
/// Buff can timeout after some time if `time` is Some. If `time` is None,
|
||||||
|
/// Buff will last indefinitely, until removed manually (by some action, like
|
||||||
|
/// uncursing). The `time` field might be moved into the `Buffs` component
|
||||||
|
/// (so that `Buff` does not own this information).
|
||||||
|
///
|
||||||
|
/// Buff has an id and data, which can be independent on each other.
|
||||||
|
/// This makes it hard to create buff stacking "helpers", as the system
|
||||||
|
/// does not assume that the same id is always the same behaviour (data).
|
||||||
|
/// Therefore id=behaviour relationship has to be enforced elsewhere (if
|
||||||
|
/// desired).
|
||||||
|
///
|
||||||
|
/// To provide more classification info when needed,
|
||||||
|
/// buff can be in one or more buff category.
|
||||||
|
///
|
||||||
|
/// `data` is separate, to make this system more flexible
|
||||||
|
/// (at the cost of the fact that id=behaviour relationship might not apply).
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct Buff {
|
||||||
|
pub id: BuffId,
|
||||||
|
pub cat_ids: Vec<BuffCategoryId>,
|
||||||
|
pub time: Option<Duration>,
|
||||||
|
pub data: BuffData,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Information about whether buff addition or removal was requested.
|
||||||
|
/// This to implement "on_add" and "on_remove" hooks for constant buffs.
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub enum BuffChange {
|
||||||
|
/// Adds this buff.
|
||||||
|
Add(Buff),
|
||||||
|
/// Removes all buffs with this ID.
|
||||||
|
/// TODO: Better removal, allowing to specify which ability to remove
|
||||||
|
/// directly.
|
||||||
|
Remove(BuffId),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Source of the de/buff
|
||||||
|
#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)]
|
||||||
|
pub enum BuffSource {
|
||||||
|
/// Applied by a character
|
||||||
|
Character { by: Uid },
|
||||||
|
/// Applied by world, like a poisonous fumes from a swamp
|
||||||
|
World,
|
||||||
|
/// Applied by command
|
||||||
|
Command,
|
||||||
|
/// Applied by an item
|
||||||
|
Item,
|
||||||
|
/// Applied by another buff (like an after-effect)
|
||||||
|
Buff,
|
||||||
|
/// Some other source
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Component holding all de/buffs that gets resolved each tick.
|
||||||
|
/// On each tick, remaining time of buffs get lowered and
|
||||||
|
/// buff effect of each buff is applied or not, depending on the `BuffData`
|
||||||
|
/// (specs system will decide based on `BuffData`, to simplify implementation).
|
||||||
|
/// TODO: Something like `once` flag for `Buff` to remove the dependence on
|
||||||
|
/// `BuffData` enum?
|
||||||
|
///
|
||||||
|
/// In case of one-time buffs, buff effects will be applied on addition
|
||||||
|
/// and undone on removal of the buff (by the specs system).
|
||||||
|
/// Example could be decreasing max health, which, if repeated each tick,
|
||||||
|
/// would be probably an undesired effect).
|
||||||
|
///
|
||||||
|
/// TODO: Make this net/sync-friendly. Events could help there
|
||||||
|
/// (probably replacing `changes`). Also, the "buff ticking" is really
|
||||||
|
/// not needed to be synced often, only in case that a buff begins/ends
|
||||||
|
/// (as the buff ECS system will probably run on a client too).
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
|
||||||
|
pub struct Buffs {
|
||||||
|
/// Active de/buffs.
|
||||||
|
pub buffs: Vec<Buff>,
|
||||||
|
/// Request to add/remove a buff.
|
||||||
|
/// Used for reacting on buff changes by the ECS system.
|
||||||
|
/// TODO: Can be `EventBus<T>` used instead of this?
|
||||||
|
pub changes: Vec<BuffChange>,
|
||||||
|
/// Last time since any buff change to limit syncing.
|
||||||
|
pub last_change: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Buffs {
|
||||||
|
/// Adds a request for adding given `buff`.
|
||||||
|
pub fn add_buff(&mut self, buff: Buff) {
|
||||||
|
let change = BuffChange::Add(buff);
|
||||||
|
self.changes.push(change);
|
||||||
|
self.last_change = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds a request for removal of all buffs with given Id.
|
||||||
|
/// TODO: Better removal, allowing to specify which ability to remove
|
||||||
|
/// directly.
|
||||||
|
pub fn remove_buff_by_id(&mut self, id: BuffId) {
|
||||||
|
let change = BuffChange::Remove(id);
|
||||||
|
self.changes.push(change);
|
||||||
|
self.last_change = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This is a primitive check if a specific buff is present.
|
||||||
|
/// (for purposes like blocking usage of abilities or something like this).
|
||||||
|
pub fn has_buff_id(&self, id: &BuffId) -> bool { self.buffs.iter().any(|buff| buff.id == *id) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for Buffs {
|
||||||
|
type Storage = FlaggedStorage<Self, IdvStorage<Self>>;
|
||||||
|
}
|
@ -3,6 +3,7 @@ mod admin;
|
|||||||
pub mod agent;
|
pub mod agent;
|
||||||
pub mod beam;
|
pub mod beam;
|
||||||
pub mod body;
|
pub mod body;
|
||||||
|
mod buff;
|
||||||
mod character_state;
|
mod character_state;
|
||||||
pub mod chat;
|
pub mod chat;
|
||||||
mod controller;
|
mod controller;
|
||||||
@ -31,6 +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, BuffData, BuffId, 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,
|
||||||
|
@ -13,6 +13,7 @@ sum_type! {
|
|||||||
Player(comp::Player),
|
Player(comp::Player),
|
||||||
CanBuild(comp::CanBuild),
|
CanBuild(comp::CanBuild),
|
||||||
Stats(comp::Stats),
|
Stats(comp::Stats),
|
||||||
|
Buffs(comp::Buffs),
|
||||||
Energy(comp::Energy),
|
Energy(comp::Energy),
|
||||||
LightEmitter(comp::LightEmitter),
|
LightEmitter(comp::LightEmitter),
|
||||||
Item(comp::Item),
|
Item(comp::Item),
|
||||||
@ -42,6 +43,7 @@ sum_type! {
|
|||||||
Player(PhantomData<comp::Player>),
|
Player(PhantomData<comp::Player>),
|
||||||
CanBuild(PhantomData<comp::CanBuild>),
|
CanBuild(PhantomData<comp::CanBuild>),
|
||||||
Stats(PhantomData<comp::Stats>),
|
Stats(PhantomData<comp::Stats>),
|
||||||
|
Buffs(PhantomData<comp::Buffs>),
|
||||||
Energy(PhantomData<comp::Energy>),
|
Energy(PhantomData<comp::Energy>),
|
||||||
LightEmitter(PhantomData<comp::LightEmitter>),
|
LightEmitter(PhantomData<comp::LightEmitter>),
|
||||||
Item(PhantomData<comp::Item>),
|
Item(PhantomData<comp::Item>),
|
||||||
@ -71,6 +73,7 @@ impl sync::CompPacket for EcsCompPacket {
|
|||||||
EcsCompPacket::Player(comp) => sync::handle_insert(comp, entity, world),
|
EcsCompPacket::Player(comp) => sync::handle_insert(comp, entity, world),
|
||||||
EcsCompPacket::CanBuild(comp) => sync::handle_insert(comp, entity, world),
|
EcsCompPacket::CanBuild(comp) => sync::handle_insert(comp, entity, world),
|
||||||
EcsCompPacket::Stats(comp) => sync::handle_insert(comp, entity, world),
|
EcsCompPacket::Stats(comp) => sync::handle_insert(comp, entity, world),
|
||||||
|
EcsCompPacket::Buffs(comp) => sync::handle_insert(comp, entity, world),
|
||||||
EcsCompPacket::Energy(comp) => sync::handle_insert(comp, entity, world),
|
EcsCompPacket::Energy(comp) => sync::handle_insert(comp, entity, world),
|
||||||
EcsCompPacket::LightEmitter(comp) => sync::handle_insert(comp, entity, world),
|
EcsCompPacket::LightEmitter(comp) => sync::handle_insert(comp, entity, world),
|
||||||
EcsCompPacket::Item(comp) => sync::handle_insert(comp, entity, world),
|
EcsCompPacket::Item(comp) => sync::handle_insert(comp, entity, world),
|
||||||
@ -98,6 +101,7 @@ impl sync::CompPacket for EcsCompPacket {
|
|||||||
EcsCompPacket::Player(comp) => sync::handle_modify(comp, entity, world),
|
EcsCompPacket::Player(comp) => sync::handle_modify(comp, entity, world),
|
||||||
EcsCompPacket::CanBuild(comp) => sync::handle_modify(comp, entity, world),
|
EcsCompPacket::CanBuild(comp) => sync::handle_modify(comp, entity, world),
|
||||||
EcsCompPacket::Stats(comp) => sync::handle_modify(comp, entity, world),
|
EcsCompPacket::Stats(comp) => sync::handle_modify(comp, entity, world),
|
||||||
|
EcsCompPacket::Buffs(comp) => sync::handle_modify(comp, entity, world),
|
||||||
EcsCompPacket::Energy(comp) => sync::handle_modify(comp, entity, world),
|
EcsCompPacket::Energy(comp) => sync::handle_modify(comp, entity, world),
|
||||||
EcsCompPacket::LightEmitter(comp) => sync::handle_modify(comp, entity, world),
|
EcsCompPacket::LightEmitter(comp) => sync::handle_modify(comp, entity, world),
|
||||||
EcsCompPacket::Item(comp) => sync::handle_modify(comp, entity, world),
|
EcsCompPacket::Item(comp) => sync::handle_modify(comp, entity, world),
|
||||||
@ -125,6 +129,7 @@ impl sync::CompPacket for EcsCompPacket {
|
|||||||
EcsCompPhantom::Player(_) => sync::handle_remove::<comp::Player>(entity, world),
|
EcsCompPhantom::Player(_) => sync::handle_remove::<comp::Player>(entity, world),
|
||||||
EcsCompPhantom::CanBuild(_) => sync::handle_remove::<comp::CanBuild>(entity, world),
|
EcsCompPhantom::CanBuild(_) => sync::handle_remove::<comp::CanBuild>(entity, world),
|
||||||
EcsCompPhantom::Stats(_) => sync::handle_remove::<comp::Stats>(entity, world),
|
EcsCompPhantom::Stats(_) => sync::handle_remove::<comp::Stats>(entity, world),
|
||||||
|
EcsCompPhantom::Buffs(_) => sync::handle_remove::<comp::Buffs>(entity, world),
|
||||||
EcsCompPhantom::Energy(_) => sync::handle_remove::<comp::Energy>(entity, world),
|
EcsCompPhantom::Energy(_) => sync::handle_remove::<comp::Energy>(entity, world),
|
||||||
EcsCompPhantom::LightEmitter(_) => {
|
EcsCompPhantom::LightEmitter(_) => {
|
||||||
sync::handle_remove::<comp::LightEmitter>(entity, world)
|
sync::handle_remove::<comp::LightEmitter>(entity, world)
|
||||||
|
@ -112,6 +112,7 @@ impl State {
|
|||||||
ecs.register::<comp::Body>();
|
ecs.register::<comp::Body>();
|
||||||
ecs.register::<comp::Player>();
|
ecs.register::<comp::Player>();
|
||||||
ecs.register::<comp::Stats>();
|
ecs.register::<comp::Stats>();
|
||||||
|
ecs.register::<comp::Buffs>();
|
||||||
ecs.register::<comp::Energy>();
|
ecs.register::<comp::Energy>();
|
||||||
ecs.register::<comp::CanBuild>();
|
ecs.register::<comp::CanBuild>();
|
||||||
ecs.register::<comp::LightEmitter>();
|
ecs.register::<comp::LightEmitter>();
|
||||||
|
130
common/src/sys/buff.rs
Normal file
130
common/src/sys/buff.rs
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
use crate::{
|
||||||
|
comp::{BuffChange, BuffData, BuffId, Buffs, HealthChange, HealthSource, Stats},
|
||||||
|
state::DeltaTime,
|
||||||
|
};
|
||||||
|
use specs::{Entities, Join, Read, System, WriteStorage};
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
/// This system modifies entity stats, changing them using buffs
|
||||||
|
/// Currently, the system is VERY, VERY CRUDE and SYNC UN-FRIENDLY.
|
||||||
|
/// It does not use events and uses `Vec`s stored in component.
|
||||||
|
///
|
||||||
|
/// TODO: Make this production-quality system/design
|
||||||
|
pub struct Sys;
|
||||||
|
impl<'a> System<'a> for Sys {
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
type SystemData = (
|
||||||
|
Entities<'a>,
|
||||||
|
Read<'a, DeltaTime>,
|
||||||
|
WriteStorage<'a, Stats>,
|
||||||
|
WriteStorage<'a, Buffs>,
|
||||||
|
);
|
||||||
|
|
||||||
|
fn run(&mut self, (entities, dt, mut stats, mut buffs): Self::SystemData) {
|
||||||
|
// Increment last change timer
|
||||||
|
buffs.set_event_emission(false);
|
||||||
|
for buff in (&mut buffs).join() {
|
||||||
|
buff.last_change += f64::from(dt.0);
|
||||||
|
}
|
||||||
|
buffs.set_event_emission(true);
|
||||||
|
|
||||||
|
for (entity, mut buffs) in (&entities, &mut buffs.restrict_mut()).join() {
|
||||||
|
let buff_comp = buffs.get_mut_unchecked();
|
||||||
|
// Add/Remove de/buffs
|
||||||
|
// While adding/removing buffs, it could call respective hooks
|
||||||
|
// Currently, it is done based on enum variant
|
||||||
|
let changes = buff_comp.changes.drain(0..buff_comp.changes.len());
|
||||||
|
for change in changes {
|
||||||
|
match change {
|
||||||
|
// Hooks for on_add could be here
|
||||||
|
BuffChange::Add(new_buff) => {
|
||||||
|
match &new_buff.data {
|
||||||
|
BuffData::NameChange { prefix } => {
|
||||||
|
if let Some(stats) = stats.get_mut(entity) {
|
||||||
|
let mut pref = String::from(prefix);
|
||||||
|
pref.push_str(&stats.name);
|
||||||
|
stats.name = pref;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
buff_comp.buffs.push(new_buff.clone());
|
||||||
|
},
|
||||||
|
// Hooks for on_remove could be here
|
||||||
|
BuffChange::Remove(id) => {
|
||||||
|
let some_predicate = |current_id: &BuffId| *current_id == id;
|
||||||
|
let mut i = 0;
|
||||||
|
while i != buff_comp.buffs.len() {
|
||||||
|
if some_predicate(&mut buff_comp.buffs[i].id) {
|
||||||
|
let buff = buff_comp.buffs.remove(i);
|
||||||
|
match &buff.data {
|
||||||
|
BuffData::NameChange { prefix } => {
|
||||||
|
if let Some(stats) = stats.get_mut(entity) {
|
||||||
|
stats.name = stats.name.replace(prefix, "");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut buffs_for_removal = Vec::new();
|
||||||
|
// Tick all de/buffs on a Buffs component.
|
||||||
|
for active_buff in &mut buff_comp.buffs {
|
||||||
|
// First, tick the buff and subtract delta from it
|
||||||
|
// and return how much "real" time the buff took (for tick independence).
|
||||||
|
// TODO: handle delta for "indefinite" buffs, i.e. time since they got removed.
|
||||||
|
let buff_delta = if let Some(remaining_time) = &mut active_buff.time {
|
||||||
|
let pre_tick = remaining_time.as_secs_f32();
|
||||||
|
let new_duration = remaining_time.checked_sub(Duration::from_secs_f32(dt.0));
|
||||||
|
let post_tick = if let Some(dur) = new_duration {
|
||||||
|
// The buff still continues.
|
||||||
|
*remaining_time -= Duration::from_secs_f32(dt.0);
|
||||||
|
dur.as_secs_f32()
|
||||||
|
} else {
|
||||||
|
// The buff has expired.
|
||||||
|
// Mark it for removal.
|
||||||
|
// TODO: This removes by ID! better method required
|
||||||
|
buffs_for_removal.push(active_buff.id.clone());
|
||||||
|
0.0
|
||||||
|
};
|
||||||
|
pre_tick - post_tick
|
||||||
|
} else {
|
||||||
|
// The buff is indefinite, and it takes full tick (delta).
|
||||||
|
// TODO: Delta for indefinite buffs might be shorter since they can get removed
|
||||||
|
// *during a tick* and this treats it as it always happens on a *tick end*.
|
||||||
|
dt.0
|
||||||
|
};
|
||||||
|
|
||||||
|
// Now, execute the buff, based on it's delta
|
||||||
|
match &mut active_buff.data {
|
||||||
|
BuffData::RepeatedHealthChange { speed, accumulated } => {
|
||||||
|
*accumulated += *speed * buff_delta;
|
||||||
|
// Apply only 0.5 or higher damage
|
||||||
|
if accumulated.abs() > 5.0 {
|
||||||
|
if let Some(stats) = stats.get_mut(entity) {
|
||||||
|
let change = HealthChange {
|
||||||
|
amount: *accumulated as i32,
|
||||||
|
cause: HealthSource::Unknown,
|
||||||
|
};
|
||||||
|
stats.health.change_by(change);
|
||||||
|
}
|
||||||
|
*accumulated = 0.0;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Truly mark expired buffs for removal.
|
||||||
|
// TODO: Review this, as it is ugly.
|
||||||
|
for to_remove in buffs_for_removal {
|
||||||
|
buff_comp.remove_buff_by_id(to_remove);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
pub mod agent;
|
pub mod agent;
|
||||||
mod beam;
|
mod beam;
|
||||||
|
mod buff;
|
||||||
pub mod character_behavior;
|
pub mod character_behavior;
|
||||||
pub mod combat;
|
pub mod combat;
|
||||||
pub mod controller;
|
pub mod controller;
|
||||||
@ -23,6 +24,7 @@ pub const PHYS_SYS: &str = "phys_sys";
|
|||||||
pub const PROJECTILE_SYS: &str = "projectile_sys";
|
pub const PROJECTILE_SYS: &str = "projectile_sys";
|
||||||
pub const SHOCKWAVE_SYS: &str = "shockwave_sys";
|
pub const SHOCKWAVE_SYS: &str = "shockwave_sys";
|
||||||
pub const STATS_SYS: &str = "stats_sys";
|
pub const STATS_SYS: &str = "stats_sys";
|
||||||
|
pub const BUFFS_SYS: &str = "buffs_sys";
|
||||||
|
|
||||||
pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) {
|
pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) {
|
||||||
dispatch_builder.add(agent::Sys, AGENT_SYS, &[]);
|
dispatch_builder.add(agent::Sys, AGENT_SYS, &[]);
|
||||||
@ -32,6 +34,7 @@ pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) {
|
|||||||
CONTROLLER_SYS,
|
CONTROLLER_SYS,
|
||||||
]);
|
]);
|
||||||
dispatch_builder.add(stats::Sys, STATS_SYS, &[]);
|
dispatch_builder.add(stats::Sys, STATS_SYS, &[]);
|
||||||
|
dispatch_builder.add(buff::Sys, BUFFS_SYS, &[]);
|
||||||
dispatch_builder.add(phys::Sys, PHYS_SYS, &[CONTROLLER_SYS, MOUNT_SYS, STATS_SYS]);
|
dispatch_builder.add(phys::Sys, PHYS_SYS, &[CONTROLLER_SYS, MOUNT_SYS, STATS_SYS]);
|
||||||
dispatch_builder.add(projectile::Sys, PROJECTILE_SYS, &[PHYS_SYS]);
|
dispatch_builder.add(projectile::Sys, PROJECTILE_SYS, &[PHYS_SYS]);
|
||||||
dispatch_builder.add(shockwave::Sys, SHOCKWAVE_SYS, &[PHYS_SYS]);
|
dispatch_builder.add(shockwave::Sys, SHOCKWAVE_SYS, &[PHYS_SYS]);
|
||||||
|
@ -93,6 +93,39 @@ impl StateExt for State {
|
|||||||
loadout: comp::Loadout,
|
loadout: comp::Loadout,
|
||||||
body: comp::Body,
|
body: comp::Body,
|
||||||
) -> EcsEntityBuilder {
|
) -> EcsEntityBuilder {
|
||||||
|
// NOTE: This is placeholder code for testing and does not
|
||||||
|
// belongs here really
|
||||||
|
let mut buffs = comp::Buffs::default();
|
||||||
|
// Damages slightly each NPC spawned for 20 seconds
|
||||||
|
buffs.add_buff(comp::Buff {
|
||||||
|
id: comp::BuffId::Poison,
|
||||||
|
cat_ids: vec![],
|
||||||
|
time: Some(std::time::Duration::from_secs(20)),
|
||||||
|
data: comp::BuffData::RepeatedHealthChange {
|
||||||
|
speed: -10.0,
|
||||||
|
accumulated: 0.0,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// Prepends "Cursed " to each NPC's name for 35 secs
|
||||||
|
buffs.add_buff(comp::Buff {
|
||||||
|
id: comp::BuffId::Cursed,
|
||||||
|
cat_ids: vec![],
|
||||||
|
time: Some(std::time::Duration::from_secs(35)),
|
||||||
|
data: comp::BuffData::NameChange {
|
||||||
|
prefix: String::from("Cursed "),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// Adds super-slow regen to each NPC spawned, indefinitely
|
||||||
|
buffs.add_buff(comp::Buff {
|
||||||
|
id: comp::BuffId::Regeneration,
|
||||||
|
cat_ids: vec![],
|
||||||
|
time: None,
|
||||||
|
data: comp::BuffData::RepeatedHealthChange {
|
||||||
|
speed: 1.0,
|
||||||
|
accumulated: 0.0,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
self.ecs_mut()
|
self.ecs_mut()
|
||||||
.create_entity_synced()
|
.create_entity_synced()
|
||||||
.with(pos)
|
.with(pos)
|
||||||
@ -111,6 +144,7 @@ impl StateExt for State {
|
|||||||
.with(comp::Gravity(1.0))
|
.with(comp::Gravity(1.0))
|
||||||
.with(comp::CharacterState::default())
|
.with(comp::CharacterState::default())
|
||||||
.with(loadout)
|
.with(loadout)
|
||||||
|
.with(buffs)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_object(&mut self, pos: comp::Pos, object: comp::object::Body) -> EcsEntityBuilder {
|
fn create_object(&mut self, pos: comp::Pos, object: comp::object::Body) -> EcsEntityBuilder {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::SysTimer;
|
use super::SysTimer;
|
||||||
use common::{
|
use common::{
|
||||||
comp::{
|
comp::{
|
||||||
BeamSegment, Body, CanBuild, CharacterState, Collider, Energy, Gravity, Group, Item,
|
BeamSegment, Body, Buffs, CanBuild, CharacterState, Collider, Energy, Gravity, Group, Item,
|
||||||
LightEmitter, Loadout, Mass, MountState, Mounting, Ori, Player, Pos, Scale, Shockwave,
|
LightEmitter, Loadout, Mass, MountState, Mounting, Ori, Player, Pos, Scale, Shockwave,
|
||||||
Stats, Sticky, Vel,
|
Stats, Sticky, Vel,
|
||||||
},
|
},
|
||||||
@ -44,6 +44,7 @@ pub struct TrackedComps<'a> {
|
|||||||
pub body: ReadStorage<'a, Body>,
|
pub body: ReadStorage<'a, Body>,
|
||||||
pub player: ReadStorage<'a, Player>,
|
pub player: ReadStorage<'a, Player>,
|
||||||
pub stats: ReadStorage<'a, Stats>,
|
pub stats: ReadStorage<'a, Stats>,
|
||||||
|
pub buffs: ReadStorage<'a, Buffs>,
|
||||||
pub energy: ReadStorage<'a, Energy>,
|
pub energy: ReadStorage<'a, Energy>,
|
||||||
pub can_build: ReadStorage<'a, CanBuild>,
|
pub can_build: ReadStorage<'a, CanBuild>,
|
||||||
pub light_emitter: ReadStorage<'a, LightEmitter>,
|
pub light_emitter: ReadStorage<'a, LightEmitter>,
|
||||||
@ -85,6 +86,10 @@ impl<'a> TrackedComps<'a> {
|
|||||||
.get(entity)
|
.get(entity)
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(|c| comps.push(c.into()));
|
.map(|c| comps.push(c.into()));
|
||||||
|
self.buffs
|
||||||
|
.get(entity)
|
||||||
|
.cloned()
|
||||||
|
.map(|c| comps.push(c.into()));
|
||||||
self.energy
|
self.energy
|
||||||
.get(entity)
|
.get(entity)
|
||||||
.cloned()
|
.cloned()
|
||||||
@ -157,6 +162,7 @@ pub struct ReadTrackers<'a> {
|
|||||||
pub body: ReadExpect<'a, UpdateTracker<Body>>,
|
pub body: ReadExpect<'a, UpdateTracker<Body>>,
|
||||||
pub player: ReadExpect<'a, UpdateTracker<Player>>,
|
pub player: ReadExpect<'a, UpdateTracker<Player>>,
|
||||||
pub stats: ReadExpect<'a, UpdateTracker<Stats>>,
|
pub stats: ReadExpect<'a, UpdateTracker<Stats>>,
|
||||||
|
pub buffs: ReadExpect<'a, UpdateTracker<Buffs>>,
|
||||||
pub energy: ReadExpect<'a, UpdateTracker<Energy>>,
|
pub energy: ReadExpect<'a, UpdateTracker<Energy>>,
|
||||||
pub can_build: ReadExpect<'a, UpdateTracker<CanBuild>>,
|
pub can_build: ReadExpect<'a, UpdateTracker<CanBuild>>,
|
||||||
pub light_emitter: ReadExpect<'a, UpdateTracker<LightEmitter>>,
|
pub light_emitter: ReadExpect<'a, UpdateTracker<LightEmitter>>,
|
||||||
@ -187,6 +193,7 @@ impl<'a> ReadTrackers<'a> {
|
|||||||
.with_component(&comps.uid, &*self.body, &comps.body, filter)
|
.with_component(&comps.uid, &*self.body, &comps.body, filter)
|
||||||
.with_component(&comps.uid, &*self.player, &comps.player, filter)
|
.with_component(&comps.uid, &*self.player, &comps.player, filter)
|
||||||
.with_component(&comps.uid, &*self.stats, &comps.stats, filter)
|
.with_component(&comps.uid, &*self.stats, &comps.stats, filter)
|
||||||
|
.with_component(&comps.uid, &*self.buffs, &comps.buffs, filter)
|
||||||
.with_component(&comps.uid, &*self.energy, &comps.energy, filter)
|
.with_component(&comps.uid, &*self.energy, &comps.energy, filter)
|
||||||
.with_component(&comps.uid, &*self.can_build, &comps.can_build, filter)
|
.with_component(&comps.uid, &*self.can_build, &comps.can_build, filter)
|
||||||
.with_component(
|
.with_component(
|
||||||
@ -224,6 +231,7 @@ pub struct WriteTrackers<'a> {
|
|||||||
body: WriteExpect<'a, UpdateTracker<Body>>,
|
body: WriteExpect<'a, UpdateTracker<Body>>,
|
||||||
player: WriteExpect<'a, UpdateTracker<Player>>,
|
player: WriteExpect<'a, UpdateTracker<Player>>,
|
||||||
stats: WriteExpect<'a, UpdateTracker<Stats>>,
|
stats: WriteExpect<'a, UpdateTracker<Stats>>,
|
||||||
|
buffs: WriteExpect<'a, UpdateTracker<Buffs>>,
|
||||||
energy: WriteExpect<'a, UpdateTracker<Energy>>,
|
energy: WriteExpect<'a, UpdateTracker<Energy>>,
|
||||||
can_build: WriteExpect<'a, UpdateTracker<CanBuild>>,
|
can_build: WriteExpect<'a, UpdateTracker<CanBuild>>,
|
||||||
light_emitter: WriteExpect<'a, UpdateTracker<LightEmitter>>,
|
light_emitter: WriteExpect<'a, UpdateTracker<LightEmitter>>,
|
||||||
@ -248,6 +256,7 @@ fn record_changes(comps: &TrackedComps, trackers: &mut WriteTrackers) {
|
|||||||
trackers.body.record_changes(&comps.body);
|
trackers.body.record_changes(&comps.body);
|
||||||
trackers.player.record_changes(&comps.player);
|
trackers.player.record_changes(&comps.player);
|
||||||
trackers.stats.record_changes(&comps.stats);
|
trackers.stats.record_changes(&comps.stats);
|
||||||
|
trackers.buffs.record_changes(&comps.buffs);
|
||||||
trackers.energy.record_changes(&comps.energy);
|
trackers.energy.record_changes(&comps.energy);
|
||||||
trackers.can_build.record_changes(&comps.can_build);
|
trackers.can_build.record_changes(&comps.can_build);
|
||||||
trackers.light_emitter.record_changes(&comps.light_emitter);
|
trackers.light_emitter.record_changes(&comps.light_emitter);
|
||||||
@ -283,6 +292,7 @@ fn record_changes(comps: &TrackedComps, trackers: &mut WriteTrackers) {
|
|||||||
};
|
};
|
||||||
log_counts!(uid, "Uids");
|
log_counts!(uid, "Uids");
|
||||||
log_counts!(body, "Bodies");
|
log_counts!(body, "Bodies");
|
||||||
|
log_counts!(buffs, "Buffs");
|
||||||
log_counts!(player, "Players");
|
log_counts!(player, "Players");
|
||||||
log_counts!(stats, "Stats");
|
log_counts!(stats, "Stats");
|
||||||
log_counts!(energy, "Energies");
|
log_counts!(energy, "Energies");
|
||||||
@ -307,6 +317,7 @@ pub fn register_trackers(world: &mut World) {
|
|||||||
world.register_tracker::<Body>();
|
world.register_tracker::<Body>();
|
||||||
world.register_tracker::<Player>();
|
world.register_tracker::<Player>();
|
||||||
world.register_tracker::<Stats>();
|
world.register_tracker::<Stats>();
|
||||||
|
world.register_tracker::<Buffs>();
|
||||||
world.register_tracker::<Energy>();
|
world.register_tracker::<Energy>();
|
||||||
world.register_tracker::<CanBuild>();
|
world.register_tracker::<CanBuild>();
|
||||||
world.register_tracker::<LightEmitter>();
|
world.register_tracker::<LightEmitter>();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user