mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added stance component that persists even after sheathing weapon (does not yet work with M1 replacement).
This commit is contained in:
parent
d0a46ed82b
commit
9875008efa
@ -15,34 +15,34 @@
|
||||
Simple(Some(Sword(ReachingCombo)), "common.abilities.sword.reaching_combo"),
|
||||
// Damagey ones
|
||||
Contextualized({
|
||||
Sword(Balanced): (Some(Sword(BalancedFinisher)), "common.abilities.sword.balanced_finisher"),
|
||||
Sword(Offensive): (Some(Sword(OffensiveFinisher)), "common.abilities.sword.offensive_finisher"),
|
||||
Sword(Crippling): (Some(Sword(CripplingFinisher)), "common.abilities.sword.crippling_finisher"),
|
||||
Sword(Cleaving): (Some(Sword(CleavingFinisher)), "common.abilities.sword.cleaving_finisher"),
|
||||
Sword(Parrying): (Some(Sword(ParryingCounter)), "common.abilities.sword.parrying_counter"),
|
||||
Sword(Heavy): (Some(Sword(HeavyFinisher)), "common.abilities.sword.heavy_finisher"),
|
||||
Sword(Reaching): (Some(Sword(ReachingFlurry)), "common.abilities.sword.reaching_flurry"),
|
||||
Stance(None): (Some(Sword(BalancedFinisher)), "common.abilities.sword.balanced_finisher"),
|
||||
Stance(Sword(Offensive)): (Some(Sword(OffensiveFinisher)), "common.abilities.sword.offensive_finisher"),
|
||||
Stance(Sword(Crippling)): (Some(Sword(CripplingFinisher)), "common.abilities.sword.crippling_finisher"),
|
||||
Stance(Sword(Cleaving)): (Some(Sword(CleavingFinisher)), "common.abilities.sword.cleaving_finisher"),
|
||||
Stance(Sword(Parrying)): (Some(Sword(ParryingCounter)), "common.abilities.sword.parrying_counter"),
|
||||
Stance(Sword(Heavy)): (Some(Sword(HeavyFinisher)), "common.abilities.sword.heavy_finisher"),
|
||||
Stance(Sword(Reaching)): (Some(Sword(ReachingFlurry)), "common.abilities.sword.reaching_flurry"),
|
||||
}),
|
||||
// Movementy ones
|
||||
Contextualized({
|
||||
Sword(Offensive): (Some(Sword(OffensiveAdvance)), "common.abilities.sword.offensive_advance"),
|
||||
Sword(Crippling): (Some(Sword(CripplingStrike)), "common.abilities.sword.crippling_strike"),
|
||||
Sword(Cleaving): (Some(Sword(CleavingDive)), "common.abilities.sword.cleaving_dive"),
|
||||
Sword(Defensive): (Some(Sword(DefensiveRetreat)), "common.abilities.sword.defensive_retreat"),
|
||||
Sword(Parrying): (Some(Sword(ParryingRiposte)), "common.abilities.sword.parrying_riposte"),
|
||||
Sword(Heavy): (Some(Sword(HeavyFortitude)), "common.abilities.sword.heavy_fortitude"),
|
||||
Sword(Mobility): (Some(Sword(MobilityFeint)), "common.abilities.sword.mobility_feint"),
|
||||
Sword(Reaching): (Some(Sword(ReachingCharge)), "common.abilities.sword.reaching_charge"),
|
||||
Stance(Sword(Offensive)): (Some(Sword(OffensiveAdvance)), "common.abilities.sword.offensive_advance"),
|
||||
Stance(Sword(Crippling)): (Some(Sword(CripplingStrike)), "common.abilities.sword.crippling_strike"),
|
||||
Stance(Sword(Cleaving)): (Some(Sword(CleavingDive)), "common.abilities.sword.cleaving_dive"),
|
||||
Stance(Sword(Defensive)): (Some(Sword(DefensiveRetreat)), "common.abilities.sword.defensive_retreat"),
|
||||
Stance(Sword(Parrying)): (Some(Sword(ParryingRiposte)), "common.abilities.sword.parrying_riposte"),
|
||||
Stance(Sword(Heavy)): (Some(Sword(HeavyFortitude)), "common.abilities.sword.heavy_fortitude"),
|
||||
Stance(Sword(Mobility)): (Some(Sword(MobilityFeint)), "common.abilities.sword.mobility_feint"),
|
||||
Stance(Sword(Reaching)): (Some(Sword(ReachingCharge)), "common.abilities.sword.reaching_charge"),
|
||||
}),
|
||||
// Utilityy ones
|
||||
Contextualized({
|
||||
Sword(Crippling): (Some(Sword(CripplingGouge)), "common.abilities.sword.crippling_gouge"),
|
||||
Sword(Cleaving): (Some(Sword(CleavingSpin)), "common.abilities.sword.cleaving_spin"),
|
||||
Sword(Defensive): (Some(Sword(DefensiveBulwark)), "common.abilities.sword.defensive_bulwark"),
|
||||
Sword(Parrying): (Some(Sword(ParryingParry)), "common.abilities.sword.parrying_parry"),
|
||||
Sword(Heavy): (Some(Sword(HeavyPommelStrike)), "common.abilities.sword.heavy_pommelstrike"),
|
||||
Sword(Mobility): (Some(Sword(MobilityAgility)), "common.abilities.sword.mobility_agility"),
|
||||
Sword(Reaching): (Some(Sword(ReachingSkewer)), "common.abilities.sword.reaching_skewer"),
|
||||
Stance(Sword(Crippling)): (Some(Sword(CripplingGouge)), "common.abilities.sword.crippling_gouge"),
|
||||
Stance(Sword(Cleaving)): (Some(Sword(CleavingSpin)), "common.abilities.sword.cleaving_spin"),
|
||||
Stance(Sword(Defensive)): (Some(Sword(DefensiveBulwark)), "common.abilities.sword.defensive_bulwark"),
|
||||
Stance(Sword(Parrying)): (Some(Sword(ParryingParry)), "common.abilities.sword.parrying_parry"),
|
||||
Stance(Sword(Heavy)): (Some(Sword(HeavyPommelStrike)), "common.abilities.sword.heavy_pommelstrike"),
|
||||
Stance(Sword(Mobility)): (Some(Sword(MobilityAgility)), "common.abilities.sword.mobility_agility"),
|
||||
Stance(Sword(Reaching)): (Some(Sword(ReachingSkewer)), "common.abilities.sword.reaching_skewer"),
|
||||
}),
|
||||
],
|
||||
),
|
||||
|
@ -37,7 +37,4 @@ ComboMelee2(
|
||||
],
|
||||
is_stance: true,
|
||||
energy_cost_per_strike: 0,
|
||||
meta: (
|
||||
kind: Some(Sword(Balanced)),
|
||||
),
|
||||
)
|
@ -14,7 +14,4 @@ FinisherMelee(
|
||||
angle: 15.0,
|
||||
),
|
||||
minimum_combo: 10,
|
||||
meta: (
|
||||
kind: Some(Sword(Balanced)),
|
||||
),
|
||||
)
|
@ -21,7 +21,4 @@ ChargedMelee(
|
||||
swing_duration: 0.1,
|
||||
hit_timing: 0.2,
|
||||
recover_duration: 0.2,
|
||||
meta: (
|
||||
kind: Some(Sword(Balanced)),
|
||||
),
|
||||
)
|
||||
|
@ -48,8 +48,6 @@ ComboMelee2(
|
||||
),
|
||||
],
|
||||
is_stance: true,
|
||||
stance: Some(Sword(Cleaving)),
|
||||
energy_cost_per_strike: 5,
|
||||
meta: (
|
||||
kind: Some(Sword(Cleaving)),
|
||||
),
|
||||
)
|
@ -21,7 +21,4 @@ DiveMelee(
|
||||
angle: 15.0,
|
||||
multi_target: Some(Normal),
|
||||
),
|
||||
meta: (
|
||||
kind: Some(Sword(Cleaving)),
|
||||
),
|
||||
)
|
@ -15,7 +15,4 @@ FinisherMelee(
|
||||
multi_target: Some(Scaling(0.5)),
|
||||
),
|
||||
minimum_combo: 10,
|
||||
meta: (
|
||||
kind: Some(Sword(Cleaving)),
|
||||
),
|
||||
)
|
@ -21,7 +21,4 @@ ComboMelee2(
|
||||
],
|
||||
is_stance: false,
|
||||
energy_cost_per_strike: 20,
|
||||
meta: (
|
||||
kind: Some(Sword(Cleaving)),
|
||||
),
|
||||
)
|
@ -48,8 +48,6 @@ ComboMelee2(
|
||||
),
|
||||
],
|
||||
is_stance: true,
|
||||
stance: Some(Sword(Crippling)),
|
||||
energy_cost_per_strike: 4,
|
||||
meta: (
|
||||
kind: Some(Sword(Crippling)),
|
||||
),
|
||||
)
|
@ -24,7 +24,4 @@ FinisherMelee(
|
||||
kind: Sqrt,
|
||||
)),
|
||||
minimum_combo: 10,
|
||||
meta: (
|
||||
kind: Some(Sword(Crippling)),
|
||||
),
|
||||
)
|
@ -26,7 +26,4 @@ ComboMelee2(
|
||||
],
|
||||
is_stance: false,
|
||||
energy_cost_per_strike: 25,
|
||||
meta: (
|
||||
kind: Some(Sword(Crippling)),
|
||||
),
|
||||
)
|
@ -26,7 +26,4 @@ ComboMelee2(
|
||||
],
|
||||
is_stance: false,
|
||||
energy_cost_per_strike: 25,
|
||||
meta: (
|
||||
kind: Some(Sword(Crippling)),
|
||||
),
|
||||
)
|
@ -6,7 +6,4 @@ SelfBuff(
|
||||
buff_strength: 0.4,
|
||||
buff_duration: Some(30.0),
|
||||
energy_cost: 40,
|
||||
meta: (
|
||||
kind: Some(Sword(Defensive)),
|
||||
),
|
||||
)
|
@ -36,9 +36,9 @@ ComboMelee2(
|
||||
),
|
||||
],
|
||||
is_stance: true,
|
||||
stance: Some(Sword(Defensive)),
|
||||
energy_cost_per_strike: 2,
|
||||
meta: (
|
||||
kind: Some(Sword(Defensive)),
|
||||
capabilities: (
|
||||
// Blocking can interrupt attack
|
||||
bits: 0b00000010,
|
||||
|
@ -25,7 +25,4 @@ ComboMelee2(
|
||||
],
|
||||
is_stance: false,
|
||||
energy_cost_per_strike: 10,
|
||||
meta: (
|
||||
kind: Some(Sword(Defensive)),
|
||||
),
|
||||
)
|
@ -36,9 +36,9 @@ ComboMelee2(
|
||||
),
|
||||
],
|
||||
is_stance: true,
|
||||
stance: Some(Sword(Heavy)),
|
||||
energy_cost_per_strike: 4,
|
||||
meta: (
|
||||
kind: Some(Sword(Heavy)),
|
||||
capabilities: (
|
||||
// Poise and knockback resistant during attack
|
||||
bits: 0b00011000,
|
||||
|
@ -24,7 +24,4 @@ FinisherMelee(
|
||||
kind: Linear,
|
||||
)),
|
||||
minimum_combo: 10,
|
||||
meta: (
|
||||
kind: Some(Sword(Heavy)),
|
||||
),
|
||||
)
|
@ -6,7 +6,4 @@ SelfBuff(
|
||||
buff_strength: 0.5,
|
||||
buff_duration: Some(30.0),
|
||||
energy_cost: 40,
|
||||
meta: (
|
||||
kind: Some(Sword(Heavy)),
|
||||
),
|
||||
)
|
@ -20,7 +20,4 @@ ComboMelee2(
|
||||
],
|
||||
is_stance: false,
|
||||
energy_cost_per_strike: 15,
|
||||
meta: (
|
||||
kind: Some(Sword(Heavy)),
|
||||
),
|
||||
)
|
@ -6,7 +6,4 @@ SelfBuff(
|
||||
buff_strength: 0.2,
|
||||
buff_duration: Some(20.0),
|
||||
energy_cost: 40,
|
||||
meta: (
|
||||
kind: Some(Sword(Mobility)),
|
||||
),
|
||||
)
|
@ -70,9 +70,9 @@ ComboMelee2(
|
||||
),
|
||||
],
|
||||
is_stance: true,
|
||||
stance: Some(Sword(Mobility)),
|
||||
energy_cost_per_strike: 2,
|
||||
meta: (
|
||||
kind: Some(Sword(Mobility)),
|
||||
capabilities: (
|
||||
// Rolling can interrupt attack
|
||||
bits: 0b00000001,
|
||||
|
@ -25,7 +25,4 @@ ComboMelee2(
|
||||
],
|
||||
is_stance: false,
|
||||
energy_cost_per_strike: 10,
|
||||
meta: (
|
||||
kind: Some(Sword(Mobility)),
|
||||
),
|
||||
)
|
@ -25,7 +25,4 @@ ComboMelee2(
|
||||
],
|
||||
is_stance: false,
|
||||
energy_cost_per_strike: 10,
|
||||
meta: (
|
||||
kind: Some(Sword(Offensive)),
|
||||
),
|
||||
)
|
@ -58,8 +58,6 @@ ComboMelee2(
|
||||
),
|
||||
],
|
||||
is_stance: true,
|
||||
stance: Some(Sword(Offensive)),
|
||||
energy_cost_per_strike: 3,
|
||||
meta: (
|
||||
kind: Some(Sword(Offensive)),
|
||||
),
|
||||
)
|
@ -24,7 +24,4 @@ FinisherMelee(
|
||||
kind: Sqrt,
|
||||
)),
|
||||
minimum_combo: 10,
|
||||
meta: (
|
||||
kind: Some(Sword(Offensive)),
|
||||
),
|
||||
)
|
@ -36,9 +36,9 @@ ComboMelee2(
|
||||
),
|
||||
],
|
||||
is_stance: true,
|
||||
stance: Some(Sword(Parrying)),
|
||||
energy_cost_per_strike: 5,
|
||||
meta: (
|
||||
kind: Some(Sword(Parrying)),
|
||||
capabilities: (
|
||||
// Buildup auto parries melee attacks
|
||||
bits: 0b00000100,
|
||||
|
@ -26,7 +26,4 @@ ComboMelee2(
|
||||
],
|
||||
is_stance: false,
|
||||
energy_cost_per_strike: 15,
|
||||
meta: (
|
||||
kind: Some(Sword(Parrying)),
|
||||
),
|
||||
)
|
@ -9,7 +9,4 @@ BasicBlock(
|
||||
),
|
||||
energy_cost: 15,
|
||||
can_hold: false,
|
||||
meta: (
|
||||
kind: Some(Sword(Parrying)),
|
||||
),
|
||||
)
|
@ -13,7 +13,4 @@ RiposteMelee(
|
||||
range: 4.0,
|
||||
angle: 20.0,
|
||||
),
|
||||
meta: (
|
||||
kind: Some(Sword(Parrying)),
|
||||
)
|
||||
)
|
@ -24,7 +24,4 @@ DashMelee(
|
||||
recover_duration: 0.5,
|
||||
ori_modifier: 0.1,
|
||||
charge_through: false,
|
||||
meta: (
|
||||
kind: Some(Sword(Reaching)),
|
||||
),
|
||||
)
|
||||
|
@ -36,8 +36,6 @@ ComboMelee2(
|
||||
),
|
||||
],
|
||||
is_stance: true,
|
||||
stance: Some(Sword(Reaching)),
|
||||
energy_cost_per_strike: 4,
|
||||
meta: (
|
||||
kind: Some(Sword(Reaching)),
|
||||
),
|
||||
)
|
@ -14,7 +14,4 @@ RapidMelee(
|
||||
),
|
||||
energy_cost: 8,
|
||||
max_strikes: 6,
|
||||
meta: (
|
||||
kind: Some(Sword(Reaching)),
|
||||
),
|
||||
)
|
||||
|
@ -26,7 +26,4 @@ ComboMelee2(
|
||||
],
|
||||
is_stance: false,
|
||||
energy_cost_per_strike: 15,
|
||||
meta: (
|
||||
kind: Some(Sword(Reaching)),
|
||||
),
|
||||
)
|
@ -43,6 +43,7 @@ macro_rules! synced_components {
|
||||
shockwave: Shockwave,
|
||||
beam_segment: BeamSegment,
|
||||
alignment: Alignment,
|
||||
stance: Stance,
|
||||
// TODO: change this to `SyncFrom::ClientEntity` and sync the bare minimum
|
||||
// from other entities (e.g. just keys needed to show appearance
|
||||
// based on their loadout). Also, it looks like this actually has
|
||||
@ -220,6 +221,10 @@ impl NetSync for SkillSet {
|
||||
const SYNC_FROM: SyncFrom = SyncFrom::AnyEntity;
|
||||
}
|
||||
|
||||
impl NetSync for Stance {
|
||||
const SYNC_FROM: SyncFrom = SyncFrom::AnyEntity;
|
||||
}
|
||||
|
||||
// These are synced only from the client's own entity.
|
||||
|
||||
impl NetSync for Admin {
|
||||
|
@ -566,6 +566,7 @@ pub enum CharacterAbility {
|
||||
ComboMelee2 {
|
||||
strikes: Vec<combo_melee2::Strike<f32>>,
|
||||
is_stance: bool,
|
||||
stance: Option<Stance>,
|
||||
energy_cost_per_strike: f32,
|
||||
#[serde(default)]
|
||||
meta: AbilityMeta,
|
||||
@ -1085,6 +1086,7 @@ impl CharacterAbility {
|
||||
is_stance: _,
|
||||
ref mut energy_cost_per_strike,
|
||||
meta: _,
|
||||
stance: _,
|
||||
} => {
|
||||
*energy_cost_per_strike /= stats.energy_efficiency;
|
||||
*strikes = strikes
|
||||
@ -2273,11 +2275,13 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState {
|
||||
strikes,
|
||||
energy_cost_per_strike,
|
||||
is_stance,
|
||||
stance,
|
||||
meta: _,
|
||||
} => CharacterState::ComboMelee2(combo_melee2::Data {
|
||||
static_data: combo_melee2::StaticData {
|
||||
strikes: strikes.iter().map(|s| s.to_duration()).collect(),
|
||||
is_stance: *is_stance,
|
||||
stance: *stance,
|
||||
energy_cost_per_strike: *energy_cost_per_strike,
|
||||
ability_info,
|
||||
},
|
||||
@ -2809,21 +2813,12 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState {
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct AbilityMeta {
|
||||
pub kind: Option<AbilityKind>,
|
||||
#[serde(default)]
|
||||
pub capabilities: Capability,
|
||||
}
|
||||
|
||||
// Only extend this if it is needed to control certain functionality of
|
||||
// abilities
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum AbilityKind {
|
||||
Sword(SwordStance),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
|
||||
pub enum SwordStance {
|
||||
Balanced,
|
||||
Offensive,
|
||||
Crippling,
|
||||
Cleaving,
|
||||
@ -2849,3 +2844,17 @@ bitflags::bitflags! {
|
||||
const KNOCKBACK_RESISTANT = 0b00010000;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
|
||||
pub enum Stance {
|
||||
None,
|
||||
Sword(SwordStance),
|
||||
}
|
||||
|
||||
impl Default for Stance {
|
||||
fn default() -> Self { Self::None }
|
||||
}
|
||||
|
||||
impl Component for Stance {
|
||||
type Storage = DerefFlaggedStorage<Self, specs::VecStorage<Self>>;
|
||||
}
|
||||
|
@ -3,11 +3,7 @@
|
||||
|
||||
use crate::{
|
||||
assets::{self, Asset, AssetExt, AssetHandle},
|
||||
comp::{
|
||||
ability::{AbilityKind, SwordStance},
|
||||
skills::Skill,
|
||||
CharacterAbility, CharacterState,
|
||||
},
|
||||
comp::{ability::Stance, skills::Skill, CharacterAbility},
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -333,20 +329,12 @@ impl<T> AuxiliaryAbilityKind<T> {
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, Copy, Eq, PartialEq, Hash)]
|
||||
pub enum AbilityContext {
|
||||
Sword(SwordStance),
|
||||
Stance(Stance),
|
||||
}
|
||||
|
||||
impl AbilityContext {
|
||||
pub fn try_from(char_state: Option<&CharacterState>) -> Option<Self> {
|
||||
if let Some(AbilityKind::Sword(stance)) = char_state
|
||||
.and_then(|cs| cs.ability_info())
|
||||
.and_then(|info| info.ability_meta)
|
||||
.and_then(|meta| meta.kind)
|
||||
{
|
||||
Some(Self::Sword(stance))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
pub fn try_from(stance: Option<&Stance>) -> Option<Self> {
|
||||
stance.map(|stance| Self::Stance(*stance))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ pub mod visual;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub use self::{
|
||||
ability::{
|
||||
Ability, AbilityInput, ActiveAbilities, CharacterAbility, CharacterAbilityType,
|
||||
Ability, AbilityInput, ActiveAbilities, CharacterAbility, CharacterAbilityType, Stance,
|
||||
MAX_ABILITIES,
|
||||
},
|
||||
admin::{Admin, AdminRole},
|
||||
|
@ -238,6 +238,10 @@ pub enum ServerEvent {
|
||||
requesting_player_uuid: String,
|
||||
character_id: CharacterId,
|
||||
},
|
||||
ChangeStance {
|
||||
entity: EcsEntity,
|
||||
stance: comp::Stance,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct EventBus<E> {
|
||||
|
@ -5,7 +5,8 @@ use crate::{
|
||||
item::{tool::AbilityMap, MaterialStatManifest},
|
||||
ActiveAbilities, Beam, Body, CharacterState, Combo, ControlAction, Controller,
|
||||
ControllerInputs, Density, Energy, Health, InputAttr, InputKind, Inventory,
|
||||
InventoryAction, Mass, Melee, Ori, PhysicsState, Pos, SkillSet, StateUpdate, Stats, Vel,
|
||||
InventoryAction, Mass, Melee, Ori, PhysicsState, Pos, SkillSet, Stance, StateUpdate, Stats,
|
||||
Vel,
|
||||
},
|
||||
link::Is,
|
||||
mounting::Rider,
|
||||
@ -144,6 +145,7 @@ pub struct JoinData<'a> {
|
||||
pub alignment: Option<&'a comp::Alignment>,
|
||||
pub terrain: &'a TerrainGrid,
|
||||
pub mount_data: Option<&'a Is<Rider>>,
|
||||
pub stance: Option<&'a Stance>,
|
||||
}
|
||||
|
||||
pub struct JoinStruct<'a> {
|
||||
@ -170,6 +172,7 @@ pub struct JoinStruct<'a> {
|
||||
pub alignment: Option<&'a comp::Alignment>,
|
||||
pub terrain: &'a TerrainGrid,
|
||||
pub mount_data: Option<&'a Is<Rider>>,
|
||||
pub stance: Option<&'a Stance>,
|
||||
}
|
||||
|
||||
impl<'a> JoinData<'a> {
|
||||
@ -210,6 +213,7 @@ impl<'a> JoinData<'a> {
|
||||
terrain: j.terrain,
|
||||
active_abilities: j.active_abilities,
|
||||
mount_data: j.mount_data,
|
||||
stance: j.stance,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,10 @@ use crate::{
|
||||
character_state::OutputEvents,
|
||||
slot::{EquipSlot, Slot},
|
||||
tool::Stats,
|
||||
CharacterState, InputAttr, InputKind, InventoryAction, MeleeConstructor, StateUpdate,
|
||||
CharacterState, InputAttr, InputKind, InventoryAction, MeleeConstructor, Stance,
|
||||
StateUpdate,
|
||||
},
|
||||
event::ServerEvent,
|
||||
states::{
|
||||
behavior::{CharacterBehavior, JoinData},
|
||||
idle,
|
||||
@ -83,6 +85,9 @@ pub struct StaticData {
|
||||
/// Whether or not combo melee should function as a stance (where it remains
|
||||
/// in the character state after a strike has finished)
|
||||
pub is_stance: bool,
|
||||
/// If a stance is added, character state will attempt to enter that stance
|
||||
/// if not already in it
|
||||
pub stance: Option<Stance>,
|
||||
/// The amount of energy consumed with each swing
|
||||
pub energy_cost_per_strike: f32,
|
||||
/// What key is used to press ability
|
||||
@ -116,6 +121,15 @@ impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
|
||||
if let Some(stance) = self.static_data.stance {
|
||||
if data.stance != Some(&stance) {
|
||||
output_events.emit_server(ServerEvent::ChangeStance {
|
||||
entity: data.entity,
|
||||
stance,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// If is a stance, use M1 to control strikes, otherwise use the input that
|
||||
// activated the ability
|
||||
let ability_input = if self.static_data.is_stance {
|
||||
|
@ -1034,7 +1034,7 @@ pub fn handle_jump(
|
||||
}
|
||||
|
||||
fn handle_ability(data: &JoinData<'_>, update: &mut StateUpdate, input: InputKind) -> bool {
|
||||
let context = AbilityContext::try_from(Some(data.character));
|
||||
let context = AbilityContext::try_from(data.stance);
|
||||
if let Some(ability_input) = input.into() {
|
||||
if let Some((ability, from_offhand)) = data
|
||||
.active_abilities
|
||||
@ -1279,7 +1279,8 @@ pub fn get_buff_strength(data: &JoinData<'_>, ai: AbilityInfo) -> f32 {
|
||||
}
|
||||
|
||||
pub fn input_is_pressed(data: &JoinData<'_>, input: InputKind) -> bool {
|
||||
data.controller.queued_inputs.contains_key(&input) || data.controller.held_inputs.contains_key(&input)
|
||||
data.controller.queued_inputs.contains_key(&input)
|
||||
|| data.controller.held_inputs.contains_key(&input)
|
||||
}
|
||||
|
||||
/// Checked `Duration` addition. Computes `timer` + `dt`, applying relevant stat
|
||||
|
@ -209,6 +209,7 @@ impl State {
|
||||
ecs.register::<comp::Alignment>();
|
||||
ecs.register::<comp::LootOwner>();
|
||||
ecs.register::<comp::Admin>();
|
||||
ecs.register::<comp::Stance>();
|
||||
|
||||
// Register components send from clients -> server
|
||||
ecs.register::<comp::Controller>();
|
||||
|
@ -9,7 +9,7 @@ use common::{
|
||||
character_state::OutputEvents,
|
||||
inventory::item::{tool::AbilityMap, MaterialStatManifest},
|
||||
ActiveAbilities, Beam, Body, CharacterState, Combo, Controller, Density, Energy, Health,
|
||||
Inventory, InventoryManip, Mass, Melee, Ori, PhysicsState, Poise, Pos, SkillSet,
|
||||
Inventory, InventoryManip, Mass, Melee, Ori, PhysicsState, Poise, Pos, SkillSet, Stance,
|
||||
StateUpdate, Stats, Vel,
|
||||
},
|
||||
event::{EventBus, LocalEvent, ServerEvent},
|
||||
@ -51,6 +51,7 @@ pub struct ReadData<'a> {
|
||||
alignments: ReadStorage<'a, comp::Alignment>,
|
||||
terrain: ReadExpect<'a, TerrainGrid>,
|
||||
inventories: ReadStorage<'a, Inventory>,
|
||||
stances: ReadStorage<'a, Stance>,
|
||||
}
|
||||
|
||||
/// ## Character Behavior System
|
||||
@ -200,6 +201,7 @@ impl<'a> System<'a> for Sys {
|
||||
alignment: read_data.alignments.get(entity),
|
||||
terrain: &read_data.terrain,
|
||||
mount_data: read_data.is_riders.get(entity),
|
||||
stance: read_data.stances.get(entity),
|
||||
};
|
||||
|
||||
for action in actions {
|
||||
|
@ -1,12 +1,12 @@
|
||||
use crate::{consts::MAX_PATH_DIST, data::*, util::entities_have_line_of_sight};
|
||||
use common::{
|
||||
comp::{
|
||||
ability::{self, Ability, AbilityKind, ActiveAbilities, AuxiliaryAbility, Capability},
|
||||
ability::{self, Ability, ActiveAbilities, AuxiliaryAbility, Capability},
|
||||
buff::BuffKind,
|
||||
item::tool::AbilityContext,
|
||||
skills::{AxeSkill, BowSkill, HammerSkill, SceptreSkill, Skill, StaffSkill, SwordSkill},
|
||||
AbilityInput, Agent, CharacterAbility, CharacterState, ControlAction, ControlEvent,
|
||||
Controller, InputKind,
|
||||
Controller, InputKind, Stance,
|
||||
},
|
||||
path::TraversalConfig,
|
||||
states::{self_buff, sprite_summon, utils::StageSection},
|
||||
@ -476,15 +476,15 @@ impl<'a> AgentData<'a> {
|
||||
const INT_COUNTER_STANCE: usize = 0;
|
||||
use ability::SwordStance;
|
||||
let stance = |stance| match stance {
|
||||
1 => SwordStance::Offensive,
|
||||
2 => SwordStance::Defensive,
|
||||
3 => SwordStance::Mobility,
|
||||
4 => SwordStance::Crippling,
|
||||
5 => SwordStance::Cleaving,
|
||||
6 => SwordStance::Parrying,
|
||||
7 => SwordStance::Heavy,
|
||||
8 => SwordStance::Reaching,
|
||||
_ => SwordStance::Balanced,
|
||||
1 => Stance::Sword(SwordStance::Offensive),
|
||||
2 => Stance::Sword(SwordStance::Defensive),
|
||||
3 => Stance::Sword(SwordStance::Mobility),
|
||||
4 => Stance::Sword(SwordStance::Crippling),
|
||||
5 => Stance::Sword(SwordStance::Cleaving),
|
||||
6 => Stance::Sword(SwordStance::Parrying),
|
||||
7 => Stance::Sword(SwordStance::Heavy),
|
||||
8 => Stance::Sword(SwordStance::Reaching),
|
||||
_ => Stance::None,
|
||||
};
|
||||
if !agent.action_state.initialized {
|
||||
// TODO: Don't always assume that if they have skill checked for, they have
|
||||
@ -519,11 +519,11 @@ impl<'a> AgentData<'a> {
|
||||
})
|
||||
};
|
||||
match stance(agent.action_state.int_counters[INT_COUNTER_STANCE]) {
|
||||
SwordStance::Balanced => {
|
||||
Stance::None => {
|
||||
// Balanced finisher
|
||||
set_sword_ability(0, 8);
|
||||
},
|
||||
SwordStance::Offensive => {
|
||||
Stance::Sword(SwordStance::Offensive) => {
|
||||
// Offensive combo
|
||||
set_sword_ability(0, 0);
|
||||
// Offensive advance
|
||||
@ -531,7 +531,7 @@ impl<'a> AgentData<'a> {
|
||||
// Offensive finisher
|
||||
set_sword_ability(2, 8);
|
||||
},
|
||||
SwordStance::Defensive => {
|
||||
Stance::Sword(SwordStance::Defensive) => {
|
||||
// Defensive combo
|
||||
set_sword_ability(0, 3);
|
||||
// Defensive retreat
|
||||
@ -539,7 +539,7 @@ impl<'a> AgentData<'a> {
|
||||
// Defensive bulwark
|
||||
set_sword_ability(2, 10);
|
||||
},
|
||||
SwordStance::Mobility => {
|
||||
Stance::Sword(SwordStance::Mobility) => {
|
||||
// Mobility combo
|
||||
set_sword_ability(0, 6);
|
||||
// Mobility feint
|
||||
@ -547,7 +547,7 @@ impl<'a> AgentData<'a> {
|
||||
// Mobility agility
|
||||
set_sword_ability(2, 10);
|
||||
},
|
||||
SwordStance::Crippling => {
|
||||
Stance::Sword(SwordStance::Crippling) => {
|
||||
// Crippling combo
|
||||
set_sword_ability(0, 1);
|
||||
// Crippling finisher
|
||||
@ -557,7 +557,7 @@ impl<'a> AgentData<'a> {
|
||||
// Crippling gouge
|
||||
set_sword_ability(3, 10);
|
||||
},
|
||||
SwordStance::Cleaving => {
|
||||
Stance::Sword(SwordStance::Cleaving) => {
|
||||
// Cleaving combo
|
||||
set_sword_ability(0, 2);
|
||||
// Cleaving finisher
|
||||
@ -567,7 +567,7 @@ impl<'a> AgentData<'a> {
|
||||
// Cleaving dive
|
||||
set_sword_ability(3, 9);
|
||||
},
|
||||
SwordStance::Parrying => {
|
||||
Stance::Sword(SwordStance::Parrying) => {
|
||||
// Parrying combo
|
||||
set_sword_ability(0, 4);
|
||||
// Parrying parry
|
||||
@ -577,7 +577,7 @@ impl<'a> AgentData<'a> {
|
||||
// Parrying counter
|
||||
set_sword_ability(3, 8);
|
||||
},
|
||||
SwordStance::Heavy => {
|
||||
Stance::Sword(SwordStance::Heavy) => {
|
||||
// Heavy combo
|
||||
set_sword_ability(0, 5);
|
||||
// Heavy finisher
|
||||
@ -587,7 +587,7 @@ impl<'a> AgentData<'a> {
|
||||
// Heavy fortitude
|
||||
set_sword_ability(3, 9);
|
||||
},
|
||||
SwordStance::Reaching => {
|
||||
Stance::Sword(SwordStance::Reaching) => {
|
||||
// Reaching combo
|
||||
set_sword_ability(0, 7);
|
||||
// Reaching charge
|
||||
@ -680,20 +680,15 @@ impl<'a> AgentData<'a> {
|
||||
};
|
||||
|
||||
let in_stance = |stance| {
|
||||
if let CharacterState::ComboMelee2(c) = self.char_state {
|
||||
c.static_data.is_stance
|
||||
&& c.static_data
|
||||
.ability_info
|
||||
.ability_meta
|
||||
.and_then(|meta| meta.kind)
|
||||
.map_or(false, |kind| AbilityKind::Sword(stance) == kind)
|
||||
if let Some(Stance::Sword(sword_stance)) = self.stance {
|
||||
stance == *sword_stance
|
||||
} else {
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
match stance(agent.action_state.int_counters[INT_COUNTER_STANCE]) {
|
||||
SwordStance::Balanced => {
|
||||
Stance::None => {
|
||||
const BALANCED_FINISHER: FinisherMeleeData = FinisherMeleeData {
|
||||
range: 2.5,
|
||||
angle: 12.5,
|
||||
@ -717,7 +712,7 @@ impl<'a> AgentData<'a> {
|
||||
fallback_tactics(agent, controller);
|
||||
}
|
||||
},
|
||||
SwordStance::Offensive => {
|
||||
Stance::Sword(SwordStance::Offensive) => {
|
||||
const OFFENSIVE_COMBO: ComboMeleeData = ComboMeleeData {
|
||||
min_range: 0.0,
|
||||
max_range: 2.0,
|
||||
@ -786,7 +781,7 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
}
|
||||
},
|
||||
SwordStance::Defensive => {
|
||||
Stance::Sword(SwordStance::Defensive) => {
|
||||
const DEFENSIVE_COMBO: ComboMeleeData = ComboMeleeData {
|
||||
min_range: 0.0,
|
||||
max_range: 2.5,
|
||||
@ -898,7 +893,7 @@ impl<'a> AgentData<'a> {
|
||||
);
|
||||
}
|
||||
},
|
||||
SwordStance::Mobility => {
|
||||
Stance::Sword(SwordStance::Mobility) => {
|
||||
const MOBILITY_COMBO: ComboMeleeData = ComboMeleeData {
|
||||
min_range: 0.0,
|
||||
max_range: 2.5,
|
||||
@ -998,7 +993,7 @@ impl<'a> AgentData<'a> {
|
||||
};
|
||||
controller.inputs.move_dir.rotated_z(PI / 4.0 * dir);
|
||||
},
|
||||
SwordStance::Crippling => {
|
||||
Stance::Sword(SwordStance::Crippling) => {
|
||||
const CRIPPLING_COMBO: ComboMeleeData = ComboMeleeData {
|
||||
min_range: 0.0,
|
||||
max_range: 2.5,
|
||||
@ -1076,7 +1071,7 @@ impl<'a> AgentData<'a> {
|
||||
);
|
||||
}
|
||||
},
|
||||
SwordStance::Cleaving => {
|
||||
Stance::Sword(SwordStance::Cleaving) => {
|
||||
// TODO: Rewrite cleaving stance tactics when agents can consider multiple
|
||||
// targets at once. Remove hack to make cleaving AI appear less frequently above
|
||||
// when doing so.
|
||||
@ -1188,7 +1183,7 @@ impl<'a> AgentData<'a> {
|
||||
);
|
||||
}
|
||||
},
|
||||
SwordStance::Parrying => {
|
||||
Stance::Sword(SwordStance::Parrying) => {
|
||||
const PARRYING_COMBO: ComboMeleeData = ComboMeleeData {
|
||||
min_range: 0.0,
|
||||
max_range: 2.5,
|
||||
@ -1294,7 +1289,7 @@ impl<'a> AgentData<'a> {
|
||||
);
|
||||
}
|
||||
},
|
||||
SwordStance::Heavy => {
|
||||
Stance::Sword(SwordStance::Heavy) => {
|
||||
const HEAVY_COMBO: ComboMeleeData = ComboMeleeData {
|
||||
min_range: 0.0,
|
||||
max_range: 2.5,
|
||||
@ -1371,7 +1366,7 @@ impl<'a> AgentData<'a> {
|
||||
advance(agent, controller, HEAVY_COMBO.max_range, HEAVY_COMBO.angle);
|
||||
}
|
||||
},
|
||||
SwordStance::Reaching => {
|
||||
Stance::Sword(SwordStance::Reaching) => {
|
||||
const REACHING_COMBO: ComboMeleeData = ComboMeleeData {
|
||||
min_range: 0.0,
|
||||
max_range: 4.5,
|
||||
@ -1622,7 +1617,7 @@ impl<'a> AgentData<'a> {
|
||||
enum ActionStateConditions {
|
||||
ConditionStaffCanShockwave = 0,
|
||||
}
|
||||
let context = AbilityContext::try_from(Some(self.char_state));
|
||||
let context = AbilityContext::try_from(self.stance);
|
||||
let extract_ability = |input: AbilityInput| {
|
||||
self.active_abilities
|
||||
.activate_ability(
|
||||
|
@ -4,7 +4,8 @@ use common::{
|
||||
group,
|
||||
item::MaterialStatManifest,
|
||||
ActiveAbilities, Alignment, Body, CharacterState, Combo, Energy, Health, Inventory,
|
||||
LightEmitter, LootOwner, Ori, PhysicsState, Poise, Pos, Scale, SkillSet, Stats, Vel,
|
||||
LightEmitter, LootOwner, Ori, PhysicsState, Poise, Pos, Scale, SkillSet, Stance, Stats,
|
||||
Vel,
|
||||
},
|
||||
link::Is,
|
||||
mounting::Mount,
|
||||
@ -47,6 +48,7 @@ pub struct AgentData<'a> {
|
||||
pub buffs: Option<&'a Buffs>,
|
||||
pub stats: Option<&'a Stats>,
|
||||
pub poise: Option<&'a Poise>,
|
||||
pub stance: Option<&'a Stance>,
|
||||
pub cached_spatial_grid: &'a common::CachedSpatialGrid,
|
||||
pub msm: &'a MaterialStatManifest,
|
||||
}
|
||||
@ -182,6 +184,7 @@ pub struct ReadData<'a> {
|
||||
pub loot_owners: ReadStorage<'a, LootOwner>,
|
||||
pub msm: ReadExpect<'a, MaterialStatManifest>,
|
||||
pub poises: ReadStorage<'a, Poise>,
|
||||
pub stances: ReadStorage<'a, Stance>,
|
||||
}
|
||||
|
||||
pub enum Path {
|
||||
|
@ -1480,3 +1480,14 @@ pub fn handle_make_admin(server: &mut Server, entity: EcsEntity, admin: comp::Ad
|
||||
.write_component_ignore_entity_dead(entity, admin);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_stance_change(server: &mut Server, entity: EcsEntity, new_stance: comp::Stance) {
|
||||
if let Some(mut stance) = server
|
||||
.state
|
||||
.ecs_mut()
|
||||
.write_storage::<comp::Stance>()
|
||||
.get_mut(entity)
|
||||
{
|
||||
*stance = new_stance;
|
||||
}
|
||||
}
|
||||
|
@ -13,8 +13,8 @@ use entity_manipulation::{
|
||||
handle_aura, handle_bonk, handle_buff, handle_change_ability, handle_combo_change,
|
||||
handle_delete, handle_destroy, handle_energy_change, handle_entity_attacked_hook,
|
||||
handle_explosion, handle_health_change, handle_knockback, handle_land_on_ground,
|
||||
handle_make_admin, handle_parry_hook, handle_poise, handle_respawn, handle_teleport_to,
|
||||
handle_update_map_marker,
|
||||
handle_make_admin, handle_parry_hook, handle_poise, handle_respawn, handle_stance_change,
|
||||
handle_teleport_to, handle_update_map_marker,
|
||||
};
|
||||
use group_manip::handle_group;
|
||||
use information::handle_site_info;
|
||||
@ -300,6 +300,9 @@ impl Server {
|
||||
admin,
|
||||
uuid,
|
||||
} => handle_make_admin(self, entity, admin, uuid),
|
||||
ServerEvent::ChangeStance { entity, stance } => {
|
||||
handle_stance_change(self, entity, stance)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -288,6 +288,7 @@ impl StateExt for State {
|
||||
.with(comp::Buffs::default())
|
||||
.with(comp::Combo::default())
|
||||
.with(comp::Auras::default())
|
||||
.with(comp::Stance::default())
|
||||
}
|
||||
|
||||
fn create_object(&mut self, pos: comp::Pos, object: comp::object::Body) -> EcsEntityBuilder {
|
||||
@ -560,6 +561,7 @@ impl StateExt for State {
|
||||
self.write_component_ignore_entity_dead(entity, comp::Buffs::default());
|
||||
self.write_component_ignore_entity_dead(entity, comp::Auras::default());
|
||||
self.write_component_ignore_entity_dead(entity, comp::Combo::default());
|
||||
self.write_component_ignore_entity_dead(entity, comp::Stance::default());
|
||||
|
||||
// Make sure physics components are updated
|
||||
self.write_component_ignore_entity_dead(entity, comp::ForceUpdate::forced());
|
||||
|
@ -203,6 +203,7 @@ impl<'a> System<'a> for Sys {
|
||||
cached_spatial_grid: &read_data.cached_spatial_grid,
|
||||
msm: &read_data.msm,
|
||||
poise: read_data.poises.get(entity),
|
||||
stance: read_data.stances.get(entity),
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
|
@ -10,7 +10,7 @@ use crate::{
|
||||
use i18n::Localization;
|
||||
|
||||
use common::{
|
||||
comp::{BuffKind, Buffs, CharacterState, Energy, Health},
|
||||
comp::{BuffKind, Buffs, Energy, Health, Stance},
|
||||
resources::Time,
|
||||
};
|
||||
use conrod_core::{
|
||||
@ -47,7 +47,7 @@ pub struct BuffsBar<'a> {
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
localized_strings: &'a Localization,
|
||||
buffs: &'a Buffs,
|
||||
char_state: &'a CharacterState,
|
||||
stance: Option<&'a Stance>,
|
||||
pulse: f32,
|
||||
global_state: &'a GlobalState,
|
||||
health: &'a Health,
|
||||
@ -63,7 +63,7 @@ impl<'a> BuffsBar<'a> {
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
localized_strings: &'a Localization,
|
||||
buffs: &'a Buffs,
|
||||
char_state: &'a CharacterState,
|
||||
stance: Option<&'a Stance>,
|
||||
pulse: f32,
|
||||
global_state: &'a GlobalState,
|
||||
health: &'a Health,
|
||||
@ -78,7 +78,7 @@ impl<'a> BuffsBar<'a> {
|
||||
tooltip_manager,
|
||||
localized_strings,
|
||||
buffs,
|
||||
char_state,
|
||||
stance,
|
||||
pulse,
|
||||
global_state,
|
||||
health,
|
||||
@ -138,7 +138,7 @@ impl<'a> Widget for BuffsBar<'a> {
|
||||
.desc_font_size(self.fonts.cyri.scale(12))
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.desc_text_color(TEXT_COLOR);
|
||||
let buff_icons = BuffIcon::icons_vec(self.buffs, self.char_state);
|
||||
let buff_icons = BuffIcon::icons_vec(self.buffs, self.stance);
|
||||
if let BuffPosition::Bar = buff_position {
|
||||
let decayed_health = 1.0 - self.health.maximum() / self.health.base_max();
|
||||
let show_health = self.global_state.settings.interface.always_show_bars
|
||||
|
@ -359,9 +359,7 @@ impl<'a> Widget for Group<'a> {
|
||||
let uid_allocator = client_state.ecs().read_resource::<UidAllocator>();
|
||||
let bodies = client_state.ecs().read_storage::<common::comp::Body>();
|
||||
let poises = client_state.ecs().read_storage::<common::comp::Poise>();
|
||||
let char_states = client_state
|
||||
.ecs()
|
||||
.read_storage::<common::comp::CharacterState>();
|
||||
let stances = client_state.ecs().read_storage::<common::comp::Stance>();
|
||||
|
||||
// Keep track of the total number of widget ids we are using for buffs
|
||||
let mut total_buff_count = 0;
|
||||
@ -377,7 +375,7 @@ impl<'a> Widget for Group<'a> {
|
||||
let is_leader = uid == leader;
|
||||
let body = entity.and_then(|entity| bodies.get(entity));
|
||||
let poise = entity.and_then(|entity| poises.get(entity));
|
||||
let char_state = entity.and_then(|entity| char_states.get(entity));
|
||||
let stance = entity.and_then(|entity| stances.get(entity));
|
||||
|
||||
if let (
|
||||
Some(stats),
|
||||
@ -387,10 +385,8 @@ impl<'a> Widget for Group<'a> {
|
||||
Some(energy),
|
||||
Some(body),
|
||||
Some(poise),
|
||||
Some(char_state),
|
||||
) = (
|
||||
stats, skill_set, inventory, health, energy, body, poise, char_state,
|
||||
) {
|
||||
) = (stats, skill_set, inventory, health, energy, body, poise)
|
||||
{
|
||||
let combat_rating = combat::combat_rating(
|
||||
inventory, health, energy, poise, skill_set, *body, self.msm,
|
||||
);
|
||||
@ -509,7 +505,7 @@ impl<'a> Widget for Group<'a> {
|
||||
.top_left_with_margins_on(state.ids.member_panels_bg[i], 26.0, 2.0)
|
||||
.set(state.ids.member_energy[i], ui);
|
||||
if let Some(buffs) = buffs {
|
||||
let buff_icons = BuffIcon::icons_vec(buffs, char_state);
|
||||
let buff_icons = BuffIcon::icons_vec(buffs, stance);
|
||||
// Limit displayed buffs to 11
|
||||
let buff_count = buff_icons.len().min(11);
|
||||
total_buff_count += buff_count;
|
||||
|
@ -580,29 +580,34 @@ impl<'a> BuffIcon<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn icons_vec(buffs: &comp::Buffs, char_state: &comp::CharacterState) -> Vec<Self> {
|
||||
pub fn icons_vec(buffs: &comp::Buffs, stance: Option<&comp::Stance>) -> Vec<Self> {
|
||||
buffs
|
||||
.iter_active()
|
||||
.filter_map(BuffIcon::from_buffs)
|
||||
.chain(BuffIcon::from_char_state(char_state).into_iter())
|
||||
.chain(stance.and_then(BuffIcon::from_stance).into_iter())
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn from_char_state(char_state: &comp::CharacterState) -> Option<Self> {
|
||||
if let Some(ability_kind) = char_state
|
||||
.ability_info()
|
||||
.and_then(|info| info.ability_meta)
|
||||
.and_then(|meta| meta.kind)
|
||||
{
|
||||
let id = util::representative_ability_id(ability_kind);
|
||||
Some(BuffIcon {
|
||||
kind: BuffIconKind::Ability { ability_id: id },
|
||||
is_buff: true,
|
||||
end_time: None,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
fn from_stance(stance: &comp::Stance) -> Option<Self> {
|
||||
use comp::ability::{Stance, SwordStance};
|
||||
let id = match stance {
|
||||
Stance::Sword(SwordStance::Offensive) => "common.abilities.sword.offensive_combo",
|
||||
Stance::Sword(SwordStance::Crippling) => "common.abilities.sword.crippling_combo",
|
||||
Stance::Sword(SwordStance::Cleaving) => "common.abilities.sword.cleaving_combo",
|
||||
Stance::Sword(SwordStance::Defensive) => "common.abilities.sword.defensive_combo",
|
||||
Stance::Sword(SwordStance::Parrying) => "common.abilities.sword.parrying_combo",
|
||||
Stance::Sword(SwordStance::Heavy) => "common.abilities.sword.heavy_combo",
|
||||
Stance::Sword(SwordStance::Mobility) => "common.abilities.sword.mobility_combo",
|
||||
Stance::Sword(SwordStance::Reaching) => "common.abilities.sword.reaching_combo",
|
||||
Stance::None => {
|
||||
return None;
|
||||
},
|
||||
};
|
||||
Some(BuffIcon {
|
||||
kind: BuffIconKind::Ability { ability_id: id },
|
||||
is_buff: true,
|
||||
end_time: None,
|
||||
})
|
||||
}
|
||||
|
||||
fn from_buffs<'b, I: Iterator<Item = &'b comp::Buff>>(buffs: I) -> Option<Self> {
|
||||
@ -1489,7 +1494,7 @@ impl Hud {
|
||||
let poises = ecs.read_storage::<comp::Poise>();
|
||||
let alignments = ecs.read_storage::<comp::Alignment>();
|
||||
let is_mount = ecs.read_storage::<Is<Mount>>();
|
||||
let char_states = ecs.read_storage::<comp::CharacterState>();
|
||||
let stances = ecs.read_storage::<comp::Stance>();
|
||||
let time = ecs.read_resource::<Time>();
|
||||
|
||||
// Check if there was a persistence load error of the skillset, and if so
|
||||
@ -2230,7 +2235,7 @@ impl Hud {
|
||||
&uids,
|
||||
&inventories,
|
||||
poises.maybe(),
|
||||
(alignments.maybe(), is_mount.maybe(), &char_states),
|
||||
(alignments.maybe(), is_mount.maybe(), stances.maybe()),
|
||||
)
|
||||
.join()
|
||||
.filter(|t| {
|
||||
@ -2253,7 +2258,7 @@ impl Hud {
|
||||
uid,
|
||||
inventory,
|
||||
poise,
|
||||
(alignment, is_mount, char_state),
|
||||
(alignment, is_mount, stance),
|
||||
)| {
|
||||
// Use interpolated position if available
|
||||
let pos = interpolated.map_or(pos.0, |i| i.pos);
|
||||
@ -2304,7 +2309,7 @@ impl Hud {
|
||||
} else {
|
||||
0.0
|
||||
},
|
||||
char_state,
|
||||
stance,
|
||||
});
|
||||
// Only render bubble if nearby or if its me and setting is on
|
||||
let bubble = if (dist_sqr < SPEECH_BUBBLE_RANGE.powi(2) && !is_me)
|
||||
@ -2849,7 +2854,6 @@ impl Hud {
|
||||
let stats = ecs.read_storage::<comp::Stats>();
|
||||
let skill_sets = ecs.read_storage::<comp::SkillSet>();
|
||||
let buffs = ecs.read_storage::<comp::Buffs>();
|
||||
let char_states = ecs.read_storage::<comp::CharacterState>();
|
||||
let msm = ecs.read_resource::<MaterialStatManifest>();
|
||||
let time = ecs.read_resource::<Time>();
|
||||
|
||||
@ -2968,6 +2972,7 @@ impl Hud {
|
||||
let poises = ecs.read_storage::<comp::Poise>();
|
||||
let combos = ecs.read_storage::<comp::Combo>();
|
||||
let time = ecs.read_resource::<Time>();
|
||||
let stances = ecs.read_storage::<comp::Stance>();
|
||||
// Combo floater stuffs
|
||||
self.floaters.combo_floater = self.floaters.combo_floater.map(|mut f| {
|
||||
f.timer -= dt.as_secs_f64();
|
||||
@ -2990,7 +2995,7 @@ impl Hud {
|
||||
skillsets.get(entity),
|
||||
bodies.get(entity),
|
||||
) {
|
||||
let context = AbilityContext::try_from(char_states.get(entity));
|
||||
let context = AbilityContext::try_from(stances.get(entity));
|
||||
match Skillbar::new(
|
||||
client,
|
||||
&info,
|
||||
@ -3018,7 +3023,6 @@ impl Hud {
|
||||
self.floaters.combo_floater,
|
||||
context,
|
||||
combos.get(entity),
|
||||
char_states.get(entity),
|
||||
)
|
||||
.set(self.ids.skillbar, ui_widgets)
|
||||
{
|
||||
@ -3138,11 +3142,10 @@ impl Hud {
|
||||
}
|
||||
|
||||
// Buffs
|
||||
if let (Some(player_buffs), Some(health), Some(energy), Some(char_state)) = (
|
||||
if let (Some(player_buffs), Some(health), Some(energy)) = (
|
||||
buffs.get(info.viewpoint_entity),
|
||||
healths.get(entity),
|
||||
energies.get(entity),
|
||||
char_states.get(entity),
|
||||
) {
|
||||
for event in BuffsBar::new(
|
||||
&self.imgs,
|
||||
@ -3151,7 +3154,7 @@ impl Hud {
|
||||
tooltip_manager,
|
||||
i18n,
|
||||
player_buffs,
|
||||
char_state,
|
||||
stances.get(entity),
|
||||
self.pulse,
|
||||
global_state,
|
||||
health,
|
||||
@ -3463,7 +3466,7 @@ impl Hud {
|
||||
bodies.get(entity),
|
||||
poises.get(entity),
|
||||
) {
|
||||
let context = AbilityContext::try_from(char_states.get(entity));
|
||||
let context = AbilityContext::try_from(stances.get(entity));
|
||||
for event in Diary::new(
|
||||
&self.show,
|
||||
client,
|
||||
|
@ -10,7 +10,7 @@ use crate::{
|
||||
ui::{fonts::Fonts, Ingameable},
|
||||
};
|
||||
use common::{
|
||||
comp::{Buffs, CharacterState, Energy, Health, SpeechBubble, SpeechBubbleType},
|
||||
comp::{Buffs, Energy, Health, SpeechBubble, SpeechBubbleType, Stance},
|
||||
resources::Time,
|
||||
};
|
||||
use conrod_core::{
|
||||
@ -72,7 +72,7 @@ pub struct Info<'a> {
|
||||
pub buffs: &'a Buffs,
|
||||
pub energy: Option<&'a Energy>,
|
||||
pub combat_rating: f32,
|
||||
pub char_state: &'a CharacterState,
|
||||
pub stance: Option<&'a Stance>,
|
||||
}
|
||||
|
||||
/// Determines whether to show the healthbar
|
||||
@ -168,9 +168,7 @@ impl<'a> Ingameable for Overhead<'a> {
|
||||
self.info.map_or(0, |info| {
|
||||
2 + 1
|
||||
+ if self.bubble.is_none() {
|
||||
2 * BuffIcon::icons_vec(info.buffs, info.char_state)
|
||||
.len()
|
||||
.min(11)
|
||||
2 * BuffIcon::icons_vec(info.buffs, info.stance).len().min(11)
|
||||
} else {
|
||||
0
|
||||
}
|
||||
@ -209,7 +207,7 @@ impl<'a> Widget for Overhead<'a> {
|
||||
buffs,
|
||||
energy,
|
||||
combat_rating,
|
||||
char_state,
|
||||
stance,
|
||||
}) = self.info
|
||||
{
|
||||
// Used to set healthbar colours based on hp_percentage
|
||||
@ -239,7 +237,7 @@ impl<'a> Widget for Overhead<'a> {
|
||||
};
|
||||
// Buffs
|
||||
// Alignment
|
||||
let buff_icons = BuffIcon::icons_vec(buffs, char_state);
|
||||
let buff_icons = BuffIcon::icons_vec(buffs, stance);
|
||||
let buff_count = buff_icons.len().min(11);
|
||||
Rectangle::fill_with([168.0, 100.0], color::TRANSPARENT)
|
||||
.x_y(-1.0, name_y + 60.0)
|
||||
|
@ -30,8 +30,7 @@ use common::comp::{
|
||||
ItemDesc, MaterialStatManifest,
|
||||
},
|
||||
skillset::SkillGroupKind,
|
||||
Ability, ActiveAbilities, Body, CharacterState, Combo, Energy, Health, Inventory, Poise,
|
||||
PoiseState, SkillSet,
|
||||
Ability, ActiveAbilities, Body, Combo, Energy, Health, Inventory, Poise, PoiseState, SkillSet,
|
||||
};
|
||||
use conrod_core::{
|
||||
color,
|
||||
@ -313,7 +312,6 @@ pub struct Skillbar<'a> {
|
||||
combo_floater: Option<ComboFloater>,
|
||||
context: Option<AbilityContext>,
|
||||
combo: Option<&'a Combo>,
|
||||
char_state: Option<&'a CharacterState>,
|
||||
}
|
||||
|
||||
impl<'a> Skillbar<'a> {
|
||||
@ -345,7 +343,6 @@ impl<'a> Skillbar<'a> {
|
||||
combo_floater: Option<ComboFloater>,
|
||||
context: Option<AbilityContext>,
|
||||
combo: Option<&'a Combo>,
|
||||
char_state: Option<&'a CharacterState>,
|
||||
) -> Self {
|
||||
Self {
|
||||
client,
|
||||
@ -375,7 +372,6 @@ impl<'a> Skillbar<'a> {
|
||||
combo_floater,
|
||||
context,
|
||||
combo,
|
||||
char_state,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1088,18 +1084,6 @@ impl<'a> Skillbar<'a> {
|
||||
.active_abilities
|
||||
.and_then(|a| Ability::from(a.primary).ability_id(Some(self.inventory), self.context));
|
||||
|
||||
let primary_ability_id = if let Some(override_id) = self
|
||||
.char_state
|
||||
.and_then(|cs| cs.ability_info())
|
||||
.and_then(|info| info.ability_meta)
|
||||
.and_then(|meta| meta.kind)
|
||||
.map(util::representative_ability_id)
|
||||
{
|
||||
Some(override_id)
|
||||
} else {
|
||||
primary_ability_id
|
||||
};
|
||||
|
||||
let (primary_ability_title, primary_ability_desc) =
|
||||
util::ability_description(primary_ability_id.unwrap_or(""), self.localized_strings);
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
use super::img_ids;
|
||||
use common::{
|
||||
comp::{
|
||||
ability::{AbilityKind, SwordStance},
|
||||
inventory::trade_pricing::TradePricing,
|
||||
item::{
|
||||
armor::{Armor, ArmorKind, Protection},
|
||||
@ -431,17 +430,3 @@ pub fn ability_description<'a>(
|
||||
|
||||
(loc.get_msg(&ability), loc.get_attr(&ability, "desc"))
|
||||
}
|
||||
|
||||
pub fn representative_ability_id(ability_kind: AbilityKind) -> &'static str {
|
||||
match ability_kind {
|
||||
AbilityKind::Sword(SwordStance::Balanced) => "common.abilities.sword.balanced_combo",
|
||||
AbilityKind::Sword(SwordStance::Offensive) => "common.abilities.sword.offensive_combo",
|
||||
AbilityKind::Sword(SwordStance::Crippling) => "common.abilities.sword.crippling_combo",
|
||||
AbilityKind::Sword(SwordStance::Cleaving) => "common.abilities.sword.cleaving_combo",
|
||||
AbilityKind::Sword(SwordStance::Defensive) => "common.abilities.sword.defensive_combo",
|
||||
AbilityKind::Sword(SwordStance::Parrying) => "common.abilities.sword.parrying_combo",
|
||||
AbilityKind::Sword(SwordStance::Heavy) => "common.abilities.sword.heavy_combo",
|
||||
AbilityKind::Sword(SwordStance::Mobility) => "common.abilities.sword.mobility_combo",
|
||||
AbilityKind::Sword(SwordStance::Reaching) => "common.abilities.sword.reaching_combo",
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ use common::{
|
||||
inventory::slot::EquipSlot,
|
||||
item::{tool::AbilityContext, Hands, ItemKind, ToolKind},
|
||||
Body, CharacterState, Collider, Controller, Health, Inventory, Item, ItemKey, Last,
|
||||
LightAnimation, LightEmitter, Ori, PhysicsState, PoiseState, Pos, Scale, Vel,
|
||||
LightAnimation, LightEmitter, Ori, PhysicsState, PoiseState, Pos, Scale, Stance, Vel,
|
||||
},
|
||||
link::Is,
|
||||
mounting::Rider,
|
||||
@ -747,7 +747,7 @@ impl FigureMgr {
|
||||
item,
|
||||
light_emitter,
|
||||
is_rider,
|
||||
collider,
|
||||
(collider, stance),
|
||||
),
|
||||
) in (
|
||||
&ecs.entities(),
|
||||
@ -765,7 +765,10 @@ impl FigureMgr {
|
||||
ecs.read_storage::<Item>().maybe(),
|
||||
ecs.read_storage::<LightEmitter>().maybe(),
|
||||
ecs.read_storage::<Is<Rider>>().maybe(),
|
||||
ecs.read_storage::<Collider>().maybe(),
|
||||
(
|
||||
ecs.read_storage::<Collider>().maybe(),
|
||||
ecs.read_storage::<Stance>().maybe(),
|
||||
),
|
||||
)
|
||||
.join()
|
||||
.enumerate()
|
||||
@ -917,7 +920,7 @@ impl FigureMgr {
|
||||
let second_tool_spec = second_tool_spec.as_deref();
|
||||
let hands = (active_tool_hand, second_tool_hand);
|
||||
|
||||
let context = AbilityContext::try_from(character);
|
||||
let context = AbilityContext::try_from(stance);
|
||||
|
||||
let ability_id = character.and_then(|c| {
|
||||
c.ability_info()
|
||||
|
Loading…
Reference in New Issue
Block a user