New abilities for sceptre are done

This commit is contained in:
Sam 2021-03-01 15:44:29 -05:00
parent afbc810b3e
commit a1bbc136fc
14 changed files with 294 additions and 65 deletions

View File

@ -2,13 +2,13 @@ BasicBeam(
buildup_duration: 0.25,
recover_duration: 0.25,
beam_duration: 1.0,
base_hps: 60,
base_dps: 60,
base_hps: 80,
base_dps: 0,
tick_rate: 2.0,
range: 25.0,
max_angle: 1.0,
lifesteal_eff: 0.15,
energy_regen: 25,
lifesteal_eff: 0.0,
energy_regen: 0,
energy_cost: 50,
energy_drain: 0,
orientation_behavior: Normal,

View File

@ -1,19 +0,0 @@
BasicRanged(
energy_cost: 450,
buildup_duration: 0.8,
recover_duration: 0.05,
projectile: Heal(
heal: 80.0,
damage: 60.0,
poise_damage: 0,
radius: 6.0,
),
projectile_body: Object(BoltNature),
/*projectile_light: Some(LightEmitter {
col: (0.0, 1.0, 0.0).into(),
..Default::default()
}),*/
projectile_gravity: Some(Gravity(0.5)),
projectile_speed: 40.0,
can_continue: false,
)

View File

@ -0,0 +1,15 @@
BasicBeam(
buildup_duration: 0.25,
recover_duration: 0.25,
beam_duration: 1.0,
base_hps: 0,
base_dps: 80,
tick_rate: 2.0,
range: 25.0,
max_angle: 1.0,
lifesteal_eff: 0.15,
energy_regen: 25,
energy_cost: 0,
energy_drain: 0,
orientation_behavior: Normal,
)

View File

@ -0,0 +1,14 @@
CastAura(
buildup_duration: 0.25,
cast_duration: 1.5,
recover_duration: 0.25,
targets: InGroup,
aura: (
kind: Invulnerability,
strength: 1.0,
duration: Some(0.5),
category: Magical,
),
range: 25.0,
energy_cost: 400,
)

View File

@ -70,9 +70,11 @@
],
),
Sceptre: (
primary: "common.abilities.sceptre.healingbeam",
secondary: "common.abilities.sceptre.healingbomb",
abilities: [],
primary: "common.abilities.sceptre.lifestealbeam",
secondary: "common.abilities.sceptre.healingbeam",
abilities: [
(None, "common.abilities.sceptre.wardingaura"),
],
),
Dagger: (
primary: "common.abilities.dagger.tempbasic",

View File

@ -1,7 +1,8 @@
use crate::{
assets::{self, Asset},
combat,
comp::{
inventory::item::tool::ToolKind, projectile::ProjectileConstructor, skills, Body,
aura, inventory::item::tool::ToolKind, projectile::ProjectileConstructor, skills, Body,
CharacterState, EnergySource, Gravity, LightEmitter, StateUpdate,
},
states::{
@ -227,6 +228,15 @@ pub enum CharacterAbility {
energy_drain: f32,
orientation_behavior: basic_beam::MovementBehavior,
},
CastAura {
buildup_duration: f32,
cast_duration: f32,
recover_duration: f32,
targets: combat::GroupTarget,
aura: aura::AuraBuffConstructor,
range: f32,
energy_cost: f32,
},
}
impl Default for CharacterAbility {
@ -264,34 +274,14 @@ impl CharacterAbility {
.try_change_by(-(*energy_cost as i32), EnergySource::Ability)
.is_ok()
},
CharacterAbility::DashMelee { energy_cost, .. } => update
.energy
.try_change_by(-(*energy_cost as i32), EnergySource::Ability)
.is_ok(),
CharacterAbility::BasicMelee { energy_cost, .. } => update
.energy
.try_change_by(-(*energy_cost as i32), EnergySource::Ability)
.is_ok(),
CharacterAbility::BasicRanged { energy_cost, .. } => update
.energy
.try_change_by(-(*energy_cost as i32), EnergySource::Ability)
.is_ok(),
CharacterAbility::LeapMelee { energy_cost, .. } => {
update.vel.0.z >= 0.0
&& update
.energy
.try_change_by(-(*energy_cost as i32), EnergySource::Ability)
.is_ok()
},
CharacterAbility::SpinMelee { energy_cost, .. } => update
.energy
.try_change_by(-(*energy_cost as i32), EnergySource::Ability)
.is_ok(),
CharacterAbility::ChargedRanged { energy_cost, .. } => update
.energy
.try_change_by(-(*energy_cost as i32), EnergySource::Ability)
.is_ok(),
CharacterAbility::ChargedMelee { energy_cost, .. } => update
CharacterAbility::DashMelee { energy_cost, .. }
| CharacterAbility::BasicMelee { energy_cost, .. }
| CharacterAbility::BasicRanged { energy_cost, .. }
| CharacterAbility::SpinMelee { energy_cost, .. }
| CharacterAbility::ChargedRanged { energy_cost, .. }
| CharacterAbility::ChargedMelee { energy_cost, .. }
| CharacterAbility::Shockwave { energy_cost, .. }
| CharacterAbility::CastAura { energy_cost, .. } => update
.energy
.try_change_by(-(*energy_cost as i32), EnergySource::Ability)
.is_ok(),
@ -304,10 +294,13 @@ impl CharacterAbility {
.try_change_by(-(*energy_cost as i32), EnergySource::Ability)
.is_ok()
},
CharacterAbility::Shockwave { energy_cost, .. } => update
.energy
.try_change_by(-(*energy_cost as i32), EnergySource::Ability)
.is_ok(),
CharacterAbility::LeapMelee { energy_cost, .. } => {
update.vel.0.z >= 0.0
&& update
.energy
.try_change_by(-(*energy_cost as i32), EnergySource::Ability)
.is_ok()
},
_ => true,
}
}
@ -500,6 +493,17 @@ impl CharacterAbility {
*base_dps *= power * speed;
*tick_rate *= speed;
},
CastAura {
ref mut buildup_duration,
ref mut recover_duration,
// cast_duration explicitly not affected by speed
ref mut aura,
..
} => {
*buildup_duration /= speed;
*recover_duration /= speed;
aura.strength *= power;
},
}
self
}
@ -517,7 +521,8 @@ impl CharacterAbility {
| ChargedMelee { energy_cost, .. }
| ChargedRanged { energy_cost, .. }
| Shockwave { energy_cost, .. }
| BasicBeam { energy_cost, .. } => *energy_cost as u32,
| BasicBeam { energy_cost, .. }
| CastAura { energy_cost, .. } => *energy_cost as u32,
BasicBlock | Boost { .. } | ComboMelee { .. } => 0,
}
}
@ -1467,6 +1472,27 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
stage_section: StageSection::Buildup,
offset: Vec3::zero(),
}),
CharacterAbility::CastAura {
buildup_duration,
cast_duration,
recover_duration,
targets,
aura,
range,
energy_cost: _,
} => CharacterState::CastAura(cast_aura::Data {
static_data: cast_aura::StaticData {
buildup_duration: Duration::from_secs_f32(*buildup_duration),
cast_duration: Duration::from_secs_f32(*cast_duration),
recover_duration: Duration::from_secs_f32(*recover_duration),
targets: *targets,
aura: *aura,
range: *range,
ability_info,
},
timer: Duration::default(),
stage_section: StageSection::Buildup,
}),
}
}
}

View File

@ -1,4 +1,5 @@
use crate::{
combat::GroupTarget,
comp::buff::{BuffCategory, BuffData, BuffKind, BuffSource},
uid::Uid,
};
@ -62,11 +63,24 @@ pub enum AuraTarget {
/// Targets the group of the entity specified by the `Uid`. This is useful
/// for auras which should only affect a player's party.
GroupOf(Uid),
/// Targets everyone not in the group of the entity specified by the `Uid`.
/// This is useful for auras which should only affect a player's
/// enemies.
NotGroupOf(Uid),
/// Targets all entities. This is for auras which are global or neutral.
All,
}
impl From<(Option<GroupTarget>, Option<&Uid>)> for AuraTarget {
fn from((target, uid): (Option<GroupTarget>, Option<&Uid>)) -> Self {
match (target, uid) {
(Some(GroupTarget::InGroup), Some(uid)) => Self::GroupOf(*uid),
(Some(GroupTarget::OutOfGroup), Some(uid)) => Self::NotGroupOf(*uid),
_ => Self::All,
}
}
}
impl Aura {
/// Creates a new Aura to be assigned to an entity
pub fn new(
@ -104,6 +118,35 @@ impl Auras {
pub fn remove(&mut self, key: AuraKey) { self.auras.remove(key); }
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct AuraBuffConstructor {
pub kind: BuffKind,
pub strength: f32,
pub duration: Option<f32>,
pub category: BuffCategory,
}
impl AuraBuffConstructor {
pub fn to_aura(
self,
uid: &Uid,
radius: f32,
duration: Option<Duration>,
target: AuraTarget,
) -> Aura {
let aura_kind = AuraKind::Buff {
kind: self.kind,
data: BuffData {
strength: self.strength,
duration: self.duration.map(Duration::from_secs_f32),
},
category: self.category,
source: BuffSource::Character { by: *uid },
};
Aura::new(aura_kind, radius, duration, target)
}
}
impl Component for Auras {
type Storage = DerefFlaggedStorage<Self, IdvStorage<Self>>;
}

View File

@ -81,6 +81,8 @@ pub enum CharacterState {
/// A continuous attack that affects all creatures in a cone originating
/// from the source
BasicBeam(basic_beam::Data),
/// Creates an aura that persists as long as you are actively casting
CastAura(cast_aura::Data),
}
impl CharacterState {
@ -100,6 +102,7 @@ impl CharacterState {
| CharacterState::RepeaterRanged(_)
| CharacterState::Shockwave(_)
| CharacterState::BasicBeam(_)
| CharacterState::CastAura(_)
)
}
@ -121,6 +124,7 @@ impl CharacterState {
| CharacterState::RepeaterRanged(_)
| CharacterState::Shockwave(_)
| CharacterState::BasicBeam(_)
| CharacterState::CastAura(_)
)
}

View File

@ -0,0 +1,135 @@
use crate::{
combat::GroupTarget,
comp::{
aura::{AuraBuffConstructor, AuraChange, AuraTarget},
CharacterState, StateUpdate,
},
event::ServerEvent,
states::{
behavior::{CharacterBehavior, JoinData},
utils::*,
},
};
use serde::{Deserialize, Serialize};
use std::time::Duration;
/// Separated out to condense update portions of character state
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct StaticData {
/// How long until state should create the aura
pub buildup_duration: Duration,
/// How long the state is creating an aura
pub cast_duration: Duration,
/// How long the state has until exiting
pub recover_duration: Duration,
/// Determines how the aura selects its targets
pub targets: GroupTarget,
/// Has information used to construct the aura
pub aura: AuraBuffConstructor,
/// Radius of aura
pub range: f32,
/// What key is used to press ability
pub ability_info: AbilityInfo,
}
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Data {
/// Struct containing data that does not change over the course of the
/// character state
pub static_data: StaticData,
/// Timer for each stage
pub timer: Duration,
/// What section the character stage is in
pub stage_section: StageSection,
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_move(data, &mut update, 0.6);
handle_jump(data, &mut update);
if !ability_key_is_pressed(data, self.static_data.ability_info.key) {
handle_interrupt(data, &mut update, false);
match update.character {
CharacterState::CastAura(_) => {},
_ => {
return update;
},
}
}
match self.stage_section {
StageSection::Buildup => {
if self.timer < self.static_data.buildup_duration {
// Build up
update.character = CharacterState::CastAura(Data {
timer: self
.timer
.checked_add(Duration::from_secs_f32(data.dt.0))
.unwrap_or_default(),
..*self
});
} else {
// Creates aura
let targets =
AuraTarget::from((Some(self.static_data.targets), Some(data.uid)));
let aura = self.static_data.aura.to_aura(
data.uid,
self.static_data.range,
Some(self.static_data.cast_duration),
targets,
);
update.server_events.push_front(ServerEvent::Aura {
entity: data.entity,
aura_change: AuraChange::Add(aura),
});
// Build up
update.character = CharacterState::CastAura(Data {
timer: Duration::default(),
stage_section: StageSection::Cast,
..*self
});
}
},
StageSection::Cast => {
if self.timer < self.static_data.cast_duration {
// Cast
update.character = CharacterState::CastAura(Data {
timer: self
.timer
.checked_add(Duration::from_secs_f32(data.dt.0))
.unwrap_or_default(),
..*self
});
} else {
update.character = CharacterState::CastAura(Data {
timer: Duration::default(),
stage_section: StageSection::Recover,
..*self
});
}
},
StageSection::Recover => {
if self.timer < self.static_data.recover_duration {
update.character = CharacterState::CastAura(Data {
timer: self
.timer
.checked_add(Duration::from_secs_f32(data.dt.0))
.unwrap_or_default(),
..*self
});
} else {
// Done
update.character = CharacterState::Wielding;
}
},
_ => {
// If it somehow ends up in an incorrect stage section
update.character = CharacterState::Wielding;
},
}
update
}
}

View File

@ -4,6 +4,7 @@ pub mod basic_melee;
pub mod basic_ranged;
pub mod behavior;
pub mod boost;
pub mod cast_aura;
pub mod charged_melee;
pub mod charged_ranged;
pub mod climb;

View File

@ -7,7 +7,7 @@ use common::{
},
event::{EventBus, ServerEvent},
resources::DeltaTime,
uid::UidAllocator,
uid::{Uid, UidAllocator},
};
use common_ecs::{Job, Origin, Phase, System};
use specs::{
@ -26,6 +26,7 @@ pub struct ReadData<'a> {
char_states: ReadStorage<'a, CharacterState>,
healths: ReadStorage<'a, Health>,
groups: ReadStorage<'a, Group>,
uids: ReadStorage<'a, Uid>,
}
#[derive(Default)]
@ -79,11 +80,12 @@ impl<'a> System<'a> for Sys {
expired_auras.push(key);
}
}
for (target, target_pos, mut target_buffs, health) in (
for (target, target_pos, mut target_buffs, health, target_uid) in (
&read_data.entities,
&read_data.positions,
&mut buffs,
&read_data.healths,
&read_data.uids,
)
.join()
{
@ -96,7 +98,8 @@ impl<'a> System<'a> for Sys {
.and_then(|e| read_data.groups.get(e))
.map_or(false, |owner_group| {
Some(owner_group) == read_data.groups.get(target)
});
})
|| *target_uid == uid;
if !same_group {
continue;

View File

@ -303,6 +303,7 @@ impl<'a> System<'a> for Sys {
CharacterState::RepeaterRanged(data) => data.handle_event(&j, action),
CharacterState::Shockwave(data) => data.handle_event(&j, action),
CharacterState::BasicBeam(data) => data.handle_event(&j, action),
CharacterState::CastAura(data) => data.handle_event(&j, action),
};
local_emitter.append(&mut state_update.local_events);
server_emitter.append(&mut state_update.server_events);
@ -342,6 +343,7 @@ impl<'a> System<'a> for Sys {
CharacterState::RepeaterRanged(data) => data.behavior(&j),
CharacterState::Shockwave(data) => data.behavior(&j),
CharacterState::BasicBeam(data) => data.behavior(&j),
CharacterState::CastAura(data) => data.behavior(&j),
};
local_emitter.append(&mut state_update.local_events);

View File

@ -232,7 +232,8 @@ impl<'a> System<'a> for Sys {
| CharacterState::ChargedRanged { .. }
| CharacterState::RepeaterRanged { .. }
| CharacterState::Shockwave { .. }
| CharacterState::BasicBeam { .. } => {
| CharacterState::BasicBeam { .. }
| CharacterState::CastAura { .. } => {
if energy.get_unchecked().regen_rate != 0.0 {
energy.get_mut_unchecked().regen_rate = 0.0
}

View File

@ -184,6 +184,7 @@ impl StateExt for State {
.with(inventory)
.with(comp::Buffs::default())
.with(comp::Combo::default())
.with(comp::Auras::default())
}
fn create_object(&mut self, pos: comp::Pos, object: comp::object::Body) -> EcsEntityBuilder {
@ -275,6 +276,7 @@ impl StateExt for State {
comp::Alignment::Owned(self.read_component_copied(entity).unwrap()),
);
self.write_component(entity, comp::Buffs::default());
self.write_component(entity, comp::Auras::default());
self.write_component(entity, comp::Combo::default());
// Make sure physics components are updated