mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Melee weapons can now block.
This commit is contained in:
parent
3cfc94af45
commit
91c6288213
@ -1 +1,6 @@
|
|||||||
BasicBlock
|
BasicBlock(
|
||||||
|
buildup_duration: 0.1,
|
||||||
|
recover_duration: 0.1,
|
||||||
|
max_angle: 90.0,
|
||||||
|
block_strength: 0.8,
|
||||||
|
)
|
@ -12,8 +12,8 @@ use crate::{
|
|||||||
},
|
},
|
||||||
poise::PoiseChange,
|
poise::PoiseChange,
|
||||||
skills::SkillGroupKind,
|
skills::SkillGroupKind,
|
||||||
Body, Combo, Energy, EnergyChange, EnergySource, Health, HealthChange, HealthSource,
|
Body, CharacterState, Combo, Energy, EnergyChange, EnergySource, Health, HealthChange, HealthSource,
|
||||||
Inventory, SkillSet, Stats,
|
Inventory, Ori, SkillSet, Stats,
|
||||||
},
|
},
|
||||||
event::ServerEvent,
|
event::ServerEvent,
|
||||||
outcome::Outcome,
|
outcome::Outcome,
|
||||||
@ -39,6 +39,15 @@ pub enum GroupTarget {
|
|||||||
OutOfGroup,
|
OutOfGroup,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub enum AttackSource {
|
||||||
|
Melee,
|
||||||
|
Projectile,
|
||||||
|
Beam,
|
||||||
|
Shockwave,
|
||||||
|
Explosion,
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct AttackerInfo<'a> {
|
pub struct AttackerInfo<'a> {
|
||||||
@ -55,6 +64,8 @@ pub struct TargetInfo<'a> {
|
|||||||
pub stats: Option<&'a Stats>,
|
pub stats: Option<&'a Stats>,
|
||||||
pub health: Option<&'a Health>,
|
pub health: Option<&'a Health>,
|
||||||
pub pos: Vec3<f32>,
|
pub pos: Vec3<f32>,
|
||||||
|
pub ori: Option<&'a Ori>,
|
||||||
|
pub char_state: Option<&'a CharacterState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
@ -105,6 +116,28 @@ impl Attack {
|
|||||||
|
|
||||||
pub fn effects(&self) -> impl Iterator<Item = &AttackEffect> { self.effects.iter() }
|
pub fn effects(&self) -> impl Iterator<Item = &AttackEffect> { self.effects.iter() }
|
||||||
|
|
||||||
|
pub fn compute_damage_reduction(target: &TargetInfo, source: AttackSource, dir: Dir) -> f32 {
|
||||||
|
let damage_reduction = Damage::compute_damage_reduction(target.inventory, target.stats);
|
||||||
|
let block_reduction = match source {
|
||||||
|
AttackSource::Melee => {
|
||||||
|
if let (Some(CharacterState::BasicBlock(data)), Some(ori)) =
|
||||||
|
(target.char_state, target.ori)
|
||||||
|
{
|
||||||
|
if ori.look_vec().angle_between(-*dir) < data.static_data.max_angle.to_radians()
|
||||||
|
{
|
||||||
|
data.static_data.block_strength
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => 0.0,
|
||||||
|
};
|
||||||
|
1.0 - (1.0 - damage_reduction) * (1.0 - block_reduction)
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn apply_attack(
|
pub fn apply_attack(
|
||||||
&self,
|
&self,
|
||||||
@ -115,6 +148,7 @@ impl Attack {
|
|||||||
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,
|
||||||
|
attack_source: AttackSource,
|
||||||
mut emit: impl FnMut(ServerEvent),
|
mut emit: impl FnMut(ServerEvent),
|
||||||
mut emit_outcome: impl FnMut(Outcome),
|
mut emit_outcome: impl FnMut(Outcome),
|
||||||
) {
|
) {
|
||||||
@ -126,7 +160,7 @@ impl Attack {
|
|||||||
.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 damage_reduction = Damage::compute_damage_reduction(target.inventory, target.stats);
|
let damage_reduction = Attack::compute_damage_reduction(&target, attack_source, dir);
|
||||||
let change = damage.damage.calculate_health_change(
|
let change = damage.damage.calculate_health_change(
|
||||||
damage_reduction,
|
damage_reduction,
|
||||||
attacker.map(|a| a.uid),
|
attacker.map(|a| a.uid),
|
||||||
|
@ -39,7 +39,7 @@ impl From<&CharacterState> for CharacterAbilityType {
|
|||||||
CharacterState::BasicRanged(_) => Self::BasicRanged,
|
CharacterState::BasicRanged(_) => Self::BasicRanged,
|
||||||
CharacterState::Boost(_) => Self::Boost,
|
CharacterState::Boost(_) => Self::Boost,
|
||||||
CharacterState::DashMelee(data) => Self::DashMelee(data.stage_section),
|
CharacterState::DashMelee(data) => Self::DashMelee(data.stage_section),
|
||||||
CharacterState::BasicBlock => Self::BasicBlock,
|
CharacterState::BasicBlock(_) => Self::BasicBlock,
|
||||||
CharacterState::LeapMelee(data) => Self::LeapMelee(data.stage_section),
|
CharacterState::LeapMelee(data) => Self::LeapMelee(data.stage_section),
|
||||||
CharacterState::ComboMelee(data) => Self::ComboMelee(data.stage_section, data.stage),
|
CharacterState::ComboMelee(data) => Self::ComboMelee(data.stage_section, data.stage),
|
||||||
CharacterState::SpinMelee(data) => Self::SpinMelee(data.stage_section),
|
CharacterState::SpinMelee(data) => Self::SpinMelee(data.stage_section),
|
||||||
@ -114,7 +114,12 @@ pub enum CharacterAbility {
|
|||||||
charge_through: bool,
|
charge_through: bool,
|
||||||
is_interruptible: bool,
|
is_interruptible: bool,
|
||||||
},
|
},
|
||||||
BasicBlock,
|
BasicBlock {
|
||||||
|
buildup_duration: f32,
|
||||||
|
recover_duration: f32,
|
||||||
|
max_angle: f32,
|
||||||
|
block_strength: f32,
|
||||||
|
},
|
||||||
Roll {
|
Roll {
|
||||||
energy_cost: f32,
|
energy_cost: f32,
|
||||||
buildup_duration: f32,
|
buildup_duration: f32,
|
||||||
@ -341,6 +346,15 @@ impl CharacterAbility {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn default_block() -> CharacterAbility {
|
||||||
|
CharacterAbility::BasicBlock {
|
||||||
|
buildup_duration: 0.1,
|
||||||
|
recover_duration: 0.1,
|
||||||
|
max_angle: 60.0,
|
||||||
|
block_strength: 0.5,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn adjusted_by_stats(mut self, power: f32, poise_strength: f32, speed: f32) -> Self {
|
pub fn adjusted_by_stats(mut self, power: f32, poise_strength: f32, speed: f32) -> Self {
|
||||||
use CharacterAbility::*;
|
use CharacterAbility::*;
|
||||||
match self {
|
match self {
|
||||||
@ -408,7 +422,15 @@ impl CharacterAbility {
|
|||||||
*swing_duration /= speed;
|
*swing_duration /= speed;
|
||||||
*recover_duration /= speed;
|
*recover_duration /= speed;
|
||||||
},
|
},
|
||||||
BasicBlock => {},
|
BasicBlock {
|
||||||
|
ref mut buildup_duration,
|
||||||
|
ref mut recover_duration,
|
||||||
|
// Block strength explicitly not modified by power, that will be a separate stat
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
*buildup_duration /= speed;
|
||||||
|
*recover_duration /= speed;
|
||||||
|
},
|
||||||
Roll {
|
Roll {
|
||||||
ref mut buildup_duration,
|
ref mut buildup_duration,
|
||||||
ref mut movement_duration,
|
ref mut movement_duration,
|
||||||
@ -586,7 +608,11 @@ impl CharacterAbility {
|
|||||||
0
|
0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
BasicBlock | Boost { .. } | ComboMelee { .. } | Blink { .. } | BasicSummon { .. } => 0,
|
BasicBlock { .. }
|
||||||
|
| Boost { .. }
|
||||||
|
| ComboMelee { .. }
|
||||||
|
| Blink { .. }
|
||||||
|
| BasicSummon { .. } => 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1235,7 +1261,23 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
|
|||||||
stage_section: StageSection::Buildup,
|
stage_section: StageSection::Buildup,
|
||||||
exhausted: false,
|
exhausted: false,
|
||||||
}),
|
}),
|
||||||
CharacterAbility::BasicBlock => CharacterState::BasicBlock,
|
CharacterAbility::BasicBlock {
|
||||||
|
buildup_duration,
|
||||||
|
recover_duration,
|
||||||
|
max_angle,
|
||||||
|
block_strength,
|
||||||
|
} => CharacterState::BasicBlock(basic_block::Data {
|
||||||
|
static_data: basic_block::StaticData {
|
||||||
|
buildup_duration: Duration::from_secs_f32(*buildup_duration),
|
||||||
|
recover_duration: Duration::from_secs_f32(*recover_duration),
|
||||||
|
max_angle: *max_angle,
|
||||||
|
block_strength: *block_strength,
|
||||||
|
ability_info,
|
||||||
|
},
|
||||||
|
timer: Duration::default(),
|
||||||
|
stage_section: StageSection::Buildup,
|
||||||
|
parry: false,
|
||||||
|
}),
|
||||||
CharacterAbility::Roll {
|
CharacterAbility::Roll {
|
||||||
energy_cost: _,
|
energy_cost: _,
|
||||||
buildup_duration,
|
buildup_duration,
|
||||||
|
@ -55,7 +55,7 @@ pub enum CharacterState {
|
|||||||
/// A stunned state
|
/// A stunned state
|
||||||
Stunned(stunned::Data),
|
Stunned(stunned::Data),
|
||||||
/// A basic blocking state
|
/// A basic blocking state
|
||||||
BasicBlock,
|
BasicBlock(basic_block::Data),
|
||||||
/// Player is busy equipping or unequipping weapons
|
/// Player is busy equipping or unequipping weapons
|
||||||
Equipping(equipping::Data),
|
Equipping(equipping::Data),
|
||||||
/// Player is holding a weapon and can perform other actions
|
/// Player is holding a weapon and can perform other actions
|
||||||
@ -110,7 +110,7 @@ impl CharacterState {
|
|||||||
| CharacterState::BasicRanged(_)
|
| CharacterState::BasicRanged(_)
|
||||||
| CharacterState::DashMelee(_)
|
| CharacterState::DashMelee(_)
|
||||||
| CharacterState::ComboMelee(_)
|
| CharacterState::ComboMelee(_)
|
||||||
| CharacterState::BasicBlock
|
| CharacterState::BasicBlock(_)
|
||||||
| CharacterState::LeapMelee(_)
|
| CharacterState::LeapMelee(_)
|
||||||
| CharacterState::SpinMelee(_)
|
| CharacterState::SpinMelee(_)
|
||||||
| CharacterState::ChargedMelee(_)
|
| CharacterState::ChargedMelee(_)
|
||||||
@ -153,7 +153,7 @@ impl CharacterState {
|
|||||||
| CharacterState::BasicRanged(_)
|
| CharacterState::BasicRanged(_)
|
||||||
| CharacterState::DashMelee(_)
|
| CharacterState::DashMelee(_)
|
||||||
| CharacterState::ComboMelee(_)
|
| CharacterState::ComboMelee(_)
|
||||||
| CharacterState::BasicBlock
|
| CharacterState::BasicBlock(_)
|
||||||
| CharacterState::LeapMelee(_)
|
| CharacterState::LeapMelee(_)
|
||||||
| CharacterState::ChargedMelee(_)
|
| CharacterState::ChargedMelee(_)
|
||||||
| CharacterState::ChargedRanged(_)
|
| CharacterState::ChargedRanged(_)
|
||||||
@ -180,7 +180,7 @@ impl CharacterState {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_block(&self) -> bool { matches!(self, CharacterState::BasicBlock) }
|
pub fn is_block(&self) -> bool { matches!(self, CharacterState::BasicBlock(_)) }
|
||||||
|
|
||||||
pub fn is_dodge(&self) -> bool { matches!(self, CharacterState::Roll(_)) }
|
pub fn is_dodge(&self) -> bool { matches!(self, CharacterState::Roll(_)) }
|
||||||
|
|
||||||
|
@ -149,10 +149,11 @@ impl ControlAction {
|
|||||||
pub enum InputKind {
|
pub enum InputKind {
|
||||||
Primary = 0,
|
Primary = 0,
|
||||||
Secondary = 1,
|
Secondary = 1,
|
||||||
Ability(usize) = 2,
|
Block = 2,
|
||||||
Roll = 3,
|
Ability(usize) = 3,
|
||||||
Jump = 4,
|
Roll = 4,
|
||||||
Fly = 5,
|
Jump = 5,
|
||||||
|
Fly = 6,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InputKind {
|
impl InputKind {
|
||||||
|
@ -326,6 +326,17 @@ impl Tool {
|
|||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn can_block(&self) -> bool {
|
||||||
|
matches!(
|
||||||
|
self.kind,
|
||||||
|
ToolKind::Sword
|
||||||
|
| ToolKind::Axe
|
||||||
|
| ToolKind::Hammer
|
||||||
|
| ToolKind::Shield
|
||||||
|
| ToolKind::Dagger
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
@ -1,15 +1,38 @@
|
|||||||
use super::utils::*;
|
use super::utils::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
comp::StateUpdate,
|
comp::{CharacterState, InputKind, StateUpdate},
|
||||||
states::behavior::{CharacterBehavior, JoinData},
|
states::behavior::{CharacterBehavior, JoinData},
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
// const BLOCK_ACCEL: f32 = 30.0;
|
/// Separated out to condense update portions of character state
|
||||||
// const BLOCK_SPEED: f32 = 75.0;
|
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct StaticData {
|
||||||
|
/// How long until state should deal damage
|
||||||
|
pub buildup_duration: Duration,
|
||||||
|
/// How long the state has until exiting
|
||||||
|
pub recover_duration: Duration,
|
||||||
|
/// Max angle (45.0 will give you a 90.0 angle window)
|
||||||
|
pub max_angle: f32,
|
||||||
|
/// What percentage incoming damage is reduced by
|
||||||
|
pub block_strength: f32,
|
||||||
|
/// What key is used to press ability
|
||||||
|
pub ability_info: AbilityInfo,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct Data;
|
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,
|
||||||
|
/// Whether the block was cancelled early enough to become a parry
|
||||||
|
pub parry: bool,
|
||||||
|
}
|
||||||
|
|
||||||
impl CharacterBehavior for Data {
|
impl CharacterBehavior for Data {
|
||||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||||
@ -17,6 +40,72 @@ impl CharacterBehavior for Data {
|
|||||||
|
|
||||||
handle_move(&data, &mut update, 0.4);
|
handle_move(&data, &mut update, 0.4);
|
||||||
|
|
||||||
|
match self.stage_section {
|
||||||
|
StageSection::Buildup => {
|
||||||
|
if self.timer < self.static_data.buildup_duration {
|
||||||
|
// Build up
|
||||||
|
update.character = CharacterState::BasicBlock(Data {
|
||||||
|
timer: self
|
||||||
|
.timer
|
||||||
|
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||||
|
.unwrap_or_default(),
|
||||||
|
parry: !input_is_pressed(data, InputKind::Block),
|
||||||
|
..*self
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Transitions to swing section of stage
|
||||||
|
update.character = CharacterState::BasicBlock(Data {
|
||||||
|
timer: Duration::default(),
|
||||||
|
stage_section: StageSection::Swing,
|
||||||
|
..*self
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
StageSection::Swing => {
|
||||||
|
if input_is_pressed(data, InputKind::Block) {
|
||||||
|
// Block
|
||||||
|
update.character = CharacterState::BasicBlock(Data {
|
||||||
|
timer: self
|
||||||
|
.timer
|
||||||
|
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||||
|
.unwrap_or_default(),
|
||||||
|
..*self
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Transitions to recover section of stage
|
||||||
|
update.character = CharacterState::BasicBlock(Data {
|
||||||
|
timer: Duration::default(),
|
||||||
|
stage_section: StageSection::Recover,
|
||||||
|
..*self
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
StageSection::Recover => {
|
||||||
|
if self.timer < self.static_data.recover_duration {
|
||||||
|
// Recovery
|
||||||
|
update.character = CharacterState::BasicBlock(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;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// At end of state logic so an interrupt isn't overwritten
|
||||||
|
if !input_is_pressed(data, self.static_data.ability_info.input) {
|
||||||
|
handle_state_interrupt(data, &mut update, false);
|
||||||
|
}
|
||||||
|
|
||||||
update
|
update
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -579,7 +579,7 @@ fn handle_ability(data: &JoinData, update: &mut StateUpdate, input: InputKind) {
|
|||||||
.get(skill_index)
|
.get(skill_index)
|
||||||
.cloned()
|
.cloned()
|
||||||
.and_then(unlocked),
|
.and_then(unlocked),
|
||||||
InputKind::Roll | InputKind::Jump | InputKind::Fly => None,
|
InputKind::Roll | InputKind::Jump | InputKind::Fly | InputKind::Block => None,
|
||||||
})
|
})
|
||||||
.map(|a| {
|
.map(|a| {
|
||||||
let tool = unwrap_tool_data(data, equip_slot).map(|t| t.kind);
|
let tool = unwrap_tool_data(data, equip_slot).map(|t| t.kind);
|
||||||
@ -615,6 +615,7 @@ pub fn handle_input(data: &JoinData, update: &mut StateUpdate, input: InputKind)
|
|||||||
InputKind::Jump => {
|
InputKind::Jump => {
|
||||||
handle_jump(data, update, 1.0);
|
handle_jump(data, update, 1.0);
|
||||||
},
|
},
|
||||||
|
InputKind::Block => handle_block_input(data, update),
|
||||||
InputKind::Fly => {},
|
InputKind::Fly => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -626,6 +627,21 @@ pub fn attempt_input(data: &JoinData, update: &mut StateUpdate) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks that player can block, then attempts to block
|
||||||
|
pub fn handle_block_input(data: &JoinData, update: &mut StateUpdate) {
|
||||||
|
let can_block =
|
||||||
|
|equip_slot| matches!(unwrap_tool_data(data, equip_slot), Some(tool) if tool.can_block());
|
||||||
|
if input_is_pressed(data, InputKind::Block) && can_block(EquipSlot::Mainhand) {
|
||||||
|
let ability = CharacterAbility::default_block();
|
||||||
|
if ability.requirements_paid(data, update) {
|
||||||
|
update.character = CharacterState::from((
|
||||||
|
&ability,
|
||||||
|
AbilityInfo::from_input(data, false, InputKind::Roll),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks that player can perform a dodge, then
|
/// Checks that player can perform a dodge, then
|
||||||
/// attempts to perform their dodge ability
|
/// attempts to perform their dodge ability
|
||||||
pub fn handle_dodge_input(data: &JoinData, update: &mut StateUpdate) {
|
pub fn handle_dodge_input(data: &JoinData, update: &mut StateUpdate) {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use common::{
|
use common::{
|
||||||
combat::{AttackerInfo, TargetInfo},
|
combat::{AttackSource, AttackerInfo, TargetInfo},
|
||||||
comp::{
|
comp::{
|
||||||
Beam, BeamSegment, Body, Combo, Energy, Group, Health, HealthSource, Inventory, Ori, Pos,
|
Beam, BeamSegment, Body, CharacterState, Combo, Energy, Group, Health, HealthSource,
|
||||||
Scale, Stats,
|
Inventory, Ori, Pos, Scale, Stats,
|
||||||
},
|
},
|
||||||
event::{EventBus, ServerEvent},
|
event::{EventBus, ServerEvent},
|
||||||
outcome::Outcome,
|
outcome::Outcome,
|
||||||
@ -40,6 +40,7 @@ pub struct ReadData<'a> {
|
|||||||
energies: ReadStorage<'a, Energy>,
|
energies: ReadStorage<'a, Energy>,
|
||||||
stats: ReadStorage<'a, Stats>,
|
stats: ReadStorage<'a, Stats>,
|
||||||
combos: ReadStorage<'a, Combo>,
|
combos: ReadStorage<'a, Combo>,
|
||||||
|
character_states: ReadStorage<'a, CharacterState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This system is responsible for handling beams that heal or do damage
|
/// This system is responsible for handling beams that heal or do damage
|
||||||
@ -188,6 +189,8 @@ impl<'a> System<'a> for Sys {
|
|||||||
stats: read_data.stats.get(target),
|
stats: read_data.stats.get(target),
|
||||||
health: read_data.healths.get(target),
|
health: read_data.healths.get(target),
|
||||||
pos: pos.0,
|
pos: pos.0,
|
||||||
|
ori: read_data.orientations.get(target),
|
||||||
|
char_state: read_data.character_states.get(target),
|
||||||
};
|
};
|
||||||
|
|
||||||
beam_segment.properties.attack.apply_attack(
|
beam_segment.properties.attack.apply_attack(
|
||||||
@ -197,6 +200,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
ori.look_dir(),
|
ori.look_dir(),
|
||||||
false,
|
false,
|
||||||
1.0,
|
1.0,
|
||||||
|
AttackSource::Beam,
|
||||||
|e| server_events.push(e),
|
|e| server_events.push(e),
|
||||||
|o| outcomes.push(o),
|
|o| outcomes.push(o),
|
||||||
);
|
);
|
||||||
|
@ -301,9 +301,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
CharacterState::Sneak => {
|
CharacterState::Sneak => {
|
||||||
states::sneak::Data::handle_event(&states::sneak::Data, &j, action)
|
states::sneak::Data::handle_event(&states::sneak::Data, &j, action)
|
||||||
},
|
},
|
||||||
CharacterState::BasicBlock => {
|
CharacterState::BasicBlock(data) => data.handle_event(&j, action),
|
||||||
states::basic_block::Data.handle_event(&j, action)
|
|
||||||
},
|
|
||||||
CharacterState::Roll(data) => data.handle_event(&j, action),
|
CharacterState::Roll(data) => data.handle_event(&j, action),
|
||||||
CharacterState::Wielding => states::wielding::Data.handle_event(&j, action),
|
CharacterState::Wielding => states::wielding::Data.handle_event(&j, action),
|
||||||
CharacterState::Equipping(data) => data.handle_event(&j, action),
|
CharacterState::Equipping(data) => data.handle_event(&j, action),
|
||||||
@ -357,7 +355,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
CharacterState::Sit => states::sit::Data::behavior(&states::sit::Data, &j),
|
CharacterState::Sit => states::sit::Data::behavior(&states::sit::Data, &j),
|
||||||
CharacterState::Dance => states::dance::Data::behavior(&states::dance::Data, &j),
|
CharacterState::Dance => states::dance::Data::behavior(&states::dance::Data, &j),
|
||||||
CharacterState::Sneak => states::sneak::Data::behavior(&states::sneak::Data, &j),
|
CharacterState::Sneak => states::sneak::Data::behavior(&states::sneak::Data, &j),
|
||||||
CharacterState::BasicBlock => states::basic_block::Data.behavior(&j),
|
CharacterState::BasicBlock(data) => data.behavior(&j),
|
||||||
CharacterState::Roll(data) => data.behavior(&j),
|
CharacterState::Roll(data) => data.behavior(&j),
|
||||||
CharacterState::Wielding => states::wielding::Data.behavior(&j),
|
CharacterState::Wielding => states::wielding::Data.behavior(&j),
|
||||||
CharacterState::Equipping(data) => data.behavior(&j),
|
CharacterState::Equipping(data) => data.behavior(&j),
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use common::{
|
use common::{
|
||||||
combat::{AttackerInfo, TargetInfo},
|
combat::{AttackSource, AttackerInfo, TargetInfo},
|
||||||
comp::{
|
comp::{
|
||||||
Body, CharacterState, Combo, Energy, Group, Health, Inventory, Melee, Ori, Pos, Scale,
|
Body, CharacterState, Combo, Energy, Group, Health, Inventory, Melee, Ori, Pos, Scale,
|
||||||
Stats,
|
Stats,
|
||||||
@ -147,6 +147,8 @@ impl<'a> System<'a> for Sys {
|
|||||||
stats: read_data.stats.get(target),
|
stats: read_data.stats.get(target),
|
||||||
health: read_data.healths.get(target),
|
health: read_data.healths.get(target),
|
||||||
pos: pos.0,
|
pos: pos.0,
|
||||||
|
ori: read_data.orientations.get(target),
|
||||||
|
char_state: read_data.char_states.get(target),
|
||||||
};
|
};
|
||||||
|
|
||||||
melee_attack.attack.apply_attack(
|
melee_attack.attack.apply_attack(
|
||||||
@ -156,6 +158,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
dir,
|
dir,
|
||||||
is_dodge,
|
is_dodge,
|
||||||
1.0,
|
1.0,
|
||||||
|
AttackSource::Melee,
|
||||||
|e| server_emitter.emit(e),
|
|e| server_emitter.emit(e),
|
||||||
|o| outcomes.push(o),
|
|o| outcomes.push(o),
|
||||||
);
|
);
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use common::{
|
use common::{
|
||||||
combat::{AttackerInfo, TargetInfo},
|
combat::{AttackSource, AttackerInfo, TargetInfo},
|
||||||
comp::{
|
comp::{
|
||||||
projectile, Body, Combo, Energy, Group, Health, HealthSource, Inventory, Ori, PhysicsState,
|
projectile, Body, CharacterState, Combo, Energy, Group, Health, HealthSource, Inventory,
|
||||||
Pos, Projectile, Stats, Vel,
|
Ori, PhysicsState, Pos, Projectile, Stats, Vel,
|
||||||
},
|
},
|
||||||
event::{EventBus, ServerEvent},
|
event::{EventBus, ServerEvent},
|
||||||
outcome::Outcome,
|
outcome::Outcome,
|
||||||
@ -36,6 +36,7 @@ pub struct ReadData<'a> {
|
|||||||
combos: ReadStorage<'a, Combo>,
|
combos: ReadStorage<'a, Combo>,
|
||||||
healths: ReadStorage<'a, Health>,
|
healths: ReadStorage<'a, Health>,
|
||||||
bodies: ReadStorage<'a, Body>,
|
bodies: ReadStorage<'a, Body>,
|
||||||
|
character_states: ReadStorage<'a, CharacterState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This system is responsible for handling projectile effect triggers
|
/// This system is responsible for handling projectile effect triggers
|
||||||
@ -130,6 +131,10 @@ impl<'a> System<'a> for Sys {
|
|||||||
stats: read_data.stats.get(target),
|
stats: read_data.stats.get(target),
|
||||||
health: read_data.healths.get(target),
|
health: read_data.healths.get(target),
|
||||||
pos: pos.0,
|
pos: pos.0,
|
||||||
|
// TODO: Let someone smarter figure this out
|
||||||
|
// ori: orientations.get(target),
|
||||||
|
ori: None,
|
||||||
|
char_state: read_data.character_states.get(target),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(&body) = read_data.bodies.get(entity) {
|
if let Some(&body) = read_data.bodies.get(entity) {
|
||||||
@ -152,6 +157,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
ori.look_dir(),
|
ori.look_dir(),
|
||||||
false,
|
false,
|
||||||
1.0,
|
1.0,
|
||||||
|
AttackSource::Projectile,
|
||||||
|e| server_emitter.emit(e),
|
|e| server_emitter.emit(e),
|
||||||
|o| outcomes.push(o),
|
|o| outcomes.push(o),
|
||||||
);
|
);
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use common::{
|
use common::{
|
||||||
combat::{AttackerInfo, TargetInfo},
|
combat::{AttackSource, AttackerInfo, TargetInfo},
|
||||||
comp::{
|
comp::{
|
||||||
Body, Combo, Energy, Group, Health, HealthSource, Inventory, Ori, PhysicsState, Pos, Scale,
|
Body, CharacterState, Combo, Energy, Group, Health, HealthSource, Inventory, Ori,
|
||||||
Shockwave, ShockwaveHitEntities, Stats,
|
PhysicsState, Pos, Scale, Shockwave, ShockwaveHitEntities, Stats,
|
||||||
},
|
},
|
||||||
event::{EventBus, ServerEvent},
|
event::{EventBus, ServerEvent},
|
||||||
outcome::Outcome,
|
outcome::Outcome,
|
||||||
@ -37,6 +37,7 @@ pub struct ReadData<'a> {
|
|||||||
energies: ReadStorage<'a, Energy>,
|
energies: ReadStorage<'a, Energy>,
|
||||||
stats: ReadStorage<'a, Stats>,
|
stats: ReadStorage<'a, Stats>,
|
||||||
combos: ReadStorage<'a, Combo>,
|
combos: ReadStorage<'a, Combo>,
|
||||||
|
character_states: ReadStorage<'a, CharacterState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This system is responsible for handling accepted inputs like moving or
|
/// This system is responsible for handling accepted inputs like moving or
|
||||||
@ -193,6 +194,8 @@ impl<'a> System<'a> for Sys {
|
|||||||
stats: read_data.stats.get(target),
|
stats: read_data.stats.get(target),
|
||||||
health: read_data.healths.get(target),
|
health: read_data.healths.get(target),
|
||||||
pos: pos.0,
|
pos: pos.0,
|
||||||
|
ori: read_data.orientations.get(target),
|
||||||
|
char_state: read_data.character_states.get(target),
|
||||||
};
|
};
|
||||||
|
|
||||||
shockwave.properties.attack.apply_attack(
|
shockwave.properties.attack.apply_attack(
|
||||||
@ -202,6 +205,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
dir,
|
dir,
|
||||||
false,
|
false,
|
||||||
1.0,
|
1.0,
|
||||||
|
AttackSource::Shockwave,
|
||||||
|e| server_emitter.emit(e),
|
|e| server_emitter.emit(e),
|
||||||
|o| outcomes.push(o),
|
|o| outcomes.push(o),
|
||||||
);
|
);
|
||||||
|
@ -253,26 +253,11 @@ impl<'a> System<'a> for Sys {
|
|||||||
energy.get_mut_unchecked().regen_rate = 0.0
|
energy.get_mut_unchecked().regen_rate = 0.0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// recover small amount of passive energy from blocking, and bonus energy from
|
// Abilities that temporarily stall energy gain, but preserve regen_rate.
|
||||||
// blocking attacks?
|
|
||||||
CharacterState::BasicBlock => {
|
|
||||||
let res = {
|
|
||||||
let energy = energy.get_unchecked();
|
|
||||||
energy.current() < energy.maximum()
|
|
||||||
};
|
|
||||||
|
|
||||||
if res {
|
|
||||||
energy.get_mut_unchecked().change_by(EnergyChange {
|
|
||||||
amount: -3,
|
|
||||||
source: EnergySource::Regen,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// Non-combat abilities that consume energy;
|
|
||||||
// temporarily stall energy gain, but preserve regen_rate.
|
|
||||||
CharacterState::Roll { .. }
|
CharacterState::Roll { .. }
|
||||||
| CharacterState::Climb { .. }
|
| CharacterState::Climb { .. }
|
||||||
| CharacterState::Stunned { .. } => {},
|
| CharacterState::Stunned { .. }
|
||||||
|
| CharacterState::BasicBlock { .. } => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -672,16 +672,31 @@ pub fn handle_explosion(server: &Server, pos: Vec3<f32>, explosion: Explosion, o
|
|||||||
RadiusEffect::Attack(attack) => {
|
RadiusEffect::Attack(attack) => {
|
||||||
let energies = &ecs.read_storage::<comp::Energy>();
|
let energies = &ecs.read_storage::<comp::Energy>();
|
||||||
let combos = &ecs.read_storage::<comp::Combo>();
|
let combos = &ecs.read_storage::<comp::Combo>();
|
||||||
for (entity_b, pos_b, health_b, inventory_b_maybe, stats_b_maybe, body_b_maybe) in (
|
for (
|
||||||
|
entity_b,
|
||||||
|
pos_b,
|
||||||
|
health_b,
|
||||||
|
(
|
||||||
|
body_b_maybe,
|
||||||
|
inventory_b_maybe,
|
||||||
|
stats_b_maybe,
|
||||||
|
ori_b_maybe,
|
||||||
|
char_state_b_maybe,
|
||||||
|
),
|
||||||
|
) in (
|
||||||
&ecs.entities(),
|
&ecs.entities(),
|
||||||
&ecs.read_storage::<comp::Pos>(),
|
&ecs.read_storage::<comp::Pos>(),
|
||||||
&ecs.read_storage::<comp::Health>(),
|
&ecs.read_storage::<comp::Health>(),
|
||||||
ecs.read_storage::<comp::Inventory>().maybe(),
|
(
|
||||||
ecs.read_storage::<comp::Stats>().maybe(),
|
ecs.read_storage::<comp::Body>().maybe(),
|
||||||
ecs.read_storage::<comp::Body>().maybe(),
|
ecs.read_storage::<comp::Inventory>().maybe(),
|
||||||
|
ecs.read_storage::<comp::Stats>().maybe(),
|
||||||
|
ecs.read_storage::<comp::Ori>().maybe(),
|
||||||
|
ecs.read_storage::<comp::CharacterState>().maybe(),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.join()
|
.join()
|
||||||
.filter(|(_, _, h, _, _, _)| !h.is_dead)
|
.filter(|(_, _, h, _)| !h.is_dead)
|
||||||
{
|
{
|
||||||
// Check if it is a hit
|
// Check if it is a hit
|
||||||
let strength = if let Some(body) = body_b_maybe {
|
let strength = if let Some(body) = body_b_maybe {
|
||||||
@ -725,6 +740,8 @@ pub fn handle_explosion(server: &Server, pos: Vec3<f32>, explosion: Explosion, o
|
|||||||
stats: stats_b_maybe,
|
stats: stats_b_maybe,
|
||||||
health: Some(health_b),
|
health: Some(health_b),
|
||||||
pos,
|
pos,
|
||||||
|
ori: ori_b_maybe,
|
||||||
|
char_state: char_state_b_maybe,
|
||||||
};
|
};
|
||||||
|
|
||||||
let server_eventbus = ecs.read_resource::<EventBus<ServerEvent>>();
|
let server_eventbus = ecs.read_resource::<EventBus<ServerEvent>>();
|
||||||
@ -736,6 +753,7 @@ pub fn handle_explosion(server: &Server, pos: Vec3<f32>, explosion: Explosion, o
|
|||||||
dir,
|
dir,
|
||||||
false,
|
false,
|
||||||
strength,
|
strength,
|
||||||
|
combat::AttackSource::Explosion,
|
||||||
|e| server_eventbus.emit_now(e),
|
|e| server_eventbus.emit_now(e),
|
||||||
|o| outcomes.push(o),
|
|o| outcomes.push(o),
|
||||||
);
|
);
|
||||||
|
@ -418,6 +418,15 @@ impl PlayState for SessionState {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
GameInput::Block => {
|
||||||
|
let mut client = self.client.borrow_mut();
|
||||||
|
client.handle_input(
|
||||||
|
InputKind::Block,
|
||||||
|
state,
|
||||||
|
select_pos,
|
||||||
|
target_entity.map(|t| t.0),
|
||||||
|
);
|
||||||
|
},
|
||||||
GameInput::Roll => {
|
GameInput::Roll => {
|
||||||
let mut client = self.client.borrow_mut();
|
let mut client = self.client.borrow_mut();
|
||||||
if can_build {
|
if can_build {
|
||||||
|
@ -111,6 +111,7 @@ impl ControlSettings {
|
|||||||
match game_input {
|
match game_input {
|
||||||
GameInput::Primary => KeyMouse::Mouse(MouseButton::Left),
|
GameInput::Primary => KeyMouse::Mouse(MouseButton::Left),
|
||||||
GameInput::Secondary => KeyMouse::Mouse(MouseButton::Right),
|
GameInput::Secondary => KeyMouse::Mouse(MouseButton::Right),
|
||||||
|
GameInput::Block => KeyMouse::Key(VirtualKeyCode::LAlt),
|
||||||
GameInput::ToggleCursor => KeyMouse::Key(VirtualKeyCode::Comma),
|
GameInput::ToggleCursor => KeyMouse::Key(VirtualKeyCode::Comma),
|
||||||
GameInput::Escape => KeyMouse::Key(VirtualKeyCode::Escape),
|
GameInput::Escape => KeyMouse::Key(VirtualKeyCode::Escape),
|
||||||
GameInput::Chat => KeyMouse::Key(VirtualKeyCode::Return),
|
GameInput::Chat => KeyMouse::Key(VirtualKeyCode::Return),
|
||||||
|
@ -21,6 +21,7 @@ use winit::monitor::VideoMode;
|
|||||||
pub enum GameInput {
|
pub enum GameInput {
|
||||||
Primary,
|
Primary,
|
||||||
Secondary,
|
Secondary,
|
||||||
|
Block,
|
||||||
Slot1,
|
Slot1,
|
||||||
Slot2,
|
Slot2,
|
||||||
Slot3,
|
Slot3,
|
||||||
@ -85,6 +86,7 @@ impl GameInput {
|
|||||||
match *self {
|
match *self {
|
||||||
GameInput::Primary => "gameinput.primary",
|
GameInput::Primary => "gameinput.primary",
|
||||||
GameInput::Secondary => "gameinput.secondary",
|
GameInput::Secondary => "gameinput.secondary",
|
||||||
|
GameInput::Block => "gameinput.block",
|
||||||
GameInput::ToggleCursor => "gameinput.togglecursor",
|
GameInput::ToggleCursor => "gameinput.togglecursor",
|
||||||
GameInput::MoveForward => "gameinput.moveforward",
|
GameInput::MoveForward => "gameinput.moveforward",
|
||||||
GameInput::MoveLeft => "gameinput.moveleft",
|
GameInput::MoveLeft => "gameinput.moveleft",
|
||||||
@ -149,6 +151,7 @@ impl GameInput {
|
|||||||
[
|
[
|
||||||
GameInput::Primary,
|
GameInput::Primary,
|
||||||
GameInput::Secondary,
|
GameInput::Secondary,
|
||||||
|
GameInput::Block,
|
||||||
GameInput::ToggleCursor,
|
GameInput::ToggleCursor,
|
||||||
GameInput::MoveForward,
|
GameInput::MoveForward,
|
||||||
GameInput::MoveLeft,
|
GameInput::MoveLeft,
|
||||||
|
Loading…
Reference in New Issue
Block a user