Maelstrom

This commit is contained in:
Sam 2023-05-18 19:33:47 -04:00
parent 0e771c9082
commit ff15780c22
14 changed files with 150 additions and 100 deletions

View File

@ -147,24 +147,30 @@
primary: Simple(None, "common.abilities.axe.triple_chop"), primary: Simple(None, "common.abilities.axe.triple_chop"),
secondary: Simple(None, "common.abilities.axe.cleave"), secondary: Simple(None, "common.abilities.axe.cleave"),
abilities: [ abilities: [
Simple(Some(Axe(BrutalSwing)), "common.abilities.axe.brutal_swing"), Simple(Axe(BrutalSwing), "common.abilities.axe.brutal_swing"),
Simple(Some(Axe(Berserk)), "common.abilities.axe.berserk"), Simple(Axe(Berserk), "common.abilities.axe.berserk"),
Simple(Some(Axe(RisingTide)), "common.abilities.axe.rising_tide"), Simple(Axe(RisingTide), "common.abilities.axe.rising_tide"),
Simple(Some(Axe(SavageSense)), "common.abilities.axe.savage_sense"), Simple(Axe(SavageSense), "common.abilities.axe.savage_sense"),
Simple(Some(Axe(AdrenalineRush)), "common.abilities.axe.adrenaline_rush"), Simple(Axe(AdrenalineRush), "common.abilities.axe.adrenaline_rush"),
Simple(Some(Axe(Execute)), "common.abilities.axe.execute"), Contextualized(
Simple(Some(Axe(Rake)), "common.abilities.axe.rake"), pseudo_id: "common.abilities.axe.execute",
Simple(Some(Axe(Bloodfeast)), "common.abilities.axe.bloodfeast"), abilities: [
Simple(Some(Axe(FierceRaze)), "common.abilities.axe.fierce_raze"), ([Combo(50)], (Axe(Maelstrom), "common.abilities.axe.maelstrom")),
Simple(Some(Axe(Furor)), "common.abilities.axe.furor"), ([], (Axe(Execute), "common.abilities.axe.execute")),
Simple(Some(Axe(Fracture)), "common.abilities.axe.fracture"), ],
Simple(Some(Axe(Lacerate)), "common.abilities.axe.lacerate"), ),
Simple(Some(Axe(SkullBash)), "common.abilities.axe.skull_bash"), Simple(Axe(Rake), "common.abilities.axe.rake"),
Simple(Some(Axe(Sunder)), "common.abilities.axe.sunder"), Simple(Axe(Bloodfeast), "common.abilities.axe.bloodfeast"),
Simple(Some(Axe(Plunder)), "common.abilities.axe.plunder"), Simple(Axe(FierceRaze), "common.abilities.axe.fierce_raze"),
Simple(Some(Axe(Defiance)), "common.abilities.axe.defiance"), Simple(Axe(Furor), "common.abilities.axe.furor"),
Simple(Some(Axe(Keelhaul)), "common.abilities.axe.keelhaul"), Simple(Axe(Fracture), "common.abilities.axe.fracture"),
Simple(Some(Axe(Bulkhead)), "common.abilities.axe.bulkhead"), Simple(Axe(Lacerate), "common.abilities.axe.lacerate"),
Simple(Axe(SkullBash), "common.abilities.axe.skull_bash"),
Simple(Axe(Sunder), "common.abilities.axe.sunder"),
Simple(Axe(Plunder), "common.abilities.axe.plunder"),
Simple(Axe(Defiance), "common.abilities.axe.defiance"),
Simple(Axe(Keelhaul), "common.abilities.axe.keelhaul"),
Simple(Axe(Bulkhead), "common.abilities.axe.bulkhead"),
], ],
), ),
Tool(Hammer): ( Tool(Hammer): (

View File

@ -1,6 +1,6 @@
FinisherMelee( FinisherMelee(
energy_cost: 0, energy_cost: 0,
buildup_duration: 0.6, buildup_duration: 0.5,
swing_duration: 0.2, swing_duration: 0.2,
recover_duration: 0.4, recover_duration: 0.4,
melee_constructor: ( melee_constructor: (

View File

@ -1,22 +1,18 @@
ComboMelee2( FinisherMelee(
strikes: [ energy_cost: 0,
( buildup_duration: 0.5,
melee_constructor: ( swing_duration: 0.4,
kind: Slash( recover_duration: 0.2,
damage: 4, melee_constructor: (
poise: 5, kind: Slash(
knockback: 0, damage: 75,
energy_regen: 5, poise: 100,
), knockback: 0,
range: 3.0, energy_regen: 0,
angle: 45.0,
),
buildup_duration: 0.15,
swing_duration: 0.05,
hit_timing: 0.5,
recover_duration: 0.1,
ori_modifier: 0.6,
), ),
], range: 3.0,
energy_cost_per_strike: 0, angle: 360.0,
multi_target: Some(Normal),
),
minimum_combo: 50,
) )

View File

@ -11,7 +11,7 @@ use crate::{
Inventory, Inventory,
}, },
skills::Skill, skills::Skill,
CharacterAbility, SkillSet, CharacterAbility, Combo, SkillSet,
}, },
}; };
use hashbrown::HashMap; use hashbrown::HashMap;
@ -361,7 +361,7 @@ impl<T> AbilityKind<T> {
.find_map(|(req_contexts, a)| { .find_map(|(req_contexts, a)| {
req_contexts req_contexts
.iter() .iter()
.all(|req| contexts.contains(req)) .all(|req| req.fulfilled_by(contexts))
.then_some(a) .then_some(a)
}), }),
} }
@ -376,10 +376,15 @@ pub enum AbilityContext {
/// files(s). /// files(s).
Stance(Stance), Stance(Stance),
DualWieldingSameKind, DualWieldingSameKind,
Combo(u32),
} }
impl AbilityContext { impl AbilityContext {
pub fn from(stance: Option<&Stance>, inv: Option<&Inventory>) -> Vec<Self> { pub fn from(
stance: Option<&Stance>,
inv: Option<&Inventory>,
combo: Option<&Combo>,
) -> Vec<Self> {
let mut contexts = Vec::new(); let mut contexts = Vec::new();
match stance { match stance {
Some(Stance::None) => {}, Some(Stance::None) => {},
@ -400,8 +405,29 @@ impl AbilityContext {
contexts.push(AbilityContext::DualWieldingSameKind) contexts.push(AbilityContext::DualWieldingSameKind)
} }
} }
if let Some(combo) = combo {
contexts.push(AbilityContext::Combo(combo.counter()));
}
contexts contexts
} }
fn fulfilled_by(&self, contexts: &[AbilityContext]) -> bool {
match self {
basic_context @ Self::Stance(_) | basic_context @ Self::DualWieldingSameKind => {
contexts.contains(basic_context)
},
Self::Combo(required) => contexts
.iter()
.filter_map(|context| {
if let Self::Combo(combo) = context {
Some(combo)
} else {
None
}
})
.any(|combo| combo >= required),
}
}
} }
impl AbilitySet<AbilityItem> { impl AbilitySet<AbilityItem> {

View File

@ -1204,7 +1204,7 @@ fn handle_ability(
output_events: &mut OutputEvents, output_events: &mut OutputEvents,
input: InputKind, input: InputKind,
) -> bool { ) -> bool {
let contexts = AbilityContext::from(data.stance, data.inventory); let contexts = AbilityContext::from(data.stance, data.inventory, data.combo);
if let Some(ability_input) = input.into() { if let Some(ability_input) = input.into() {
if let Some((ability, from_offhand)) = data if let Some((ability, from_offhand)) = data
.active_abilities .active_abilities

View File

@ -1359,7 +1359,7 @@ impl<'a> AgentData<'a> {
enum ActionStateConditions { enum ActionStateConditions {
ConditionStaffCanShockwave = 0, ConditionStaffCanShockwave = 0,
} }
let contexts = AbilityContext::from(self.stance, Some(self.inventory)); let contexts = AbilityContext::from(self.stance, Some(self.inventory), self.combo);
let extract_ability = |input: AbilityInput| { let extract_ability = |input: AbilityInput| {
self.active_abilities self.active_abilities
.activate_ability( .activate_ability(

View File

@ -208,7 +208,7 @@ impl<'a> AgentData<'a> {
} }
pub fn extract_ability(&self, input: AbilityInput) -> Option<AbilityData> { pub fn extract_ability(&self, input: AbilityInput) -> Option<AbilityData> {
let context = AbilityContext::from(self.stance, Some(self.inventory)); let context = AbilityContext::from(self.stance, Some(self.inventory), self.combo);
AbilityData::from_ability( AbilityData::from_ability(
&self &self
.active_abilities .active_abilities

View File

@ -37,10 +37,12 @@ impl Animation for ChargeswingAnimation {
next.main.position = Vec3::new(0.0, 0.0, 0.0); next.main.position = Vec3::new(0.0, 0.0, 0.0);
next.main.orientation = Quaternion::rotation_z(0.0); next.main.orientation = Quaternion::rotation_z(0.0);
next.main_weapon_trail = true;
next.second.position = Vec3::new(0.0, 0.0, 0.0); next.second.position = Vec3::new(0.0, 0.0, 0.0);
next.second.orientation = Quaternion::rotation_z(0.0); next.second.orientation = Quaternion::rotation_z(0.0);
next.off_weapon_trail = true; if matches!(stage_section, Some(StageSection::Action)) {
next.main_weapon_trail = true;
next.off_weapon_trail = true;
}
match ability_id { match ability_id {
Some( Some(
@ -237,16 +239,10 @@ impl Animation for ChargeswingAnimation {
Some("common.abilities.axe.cleave") => { Some("common.abilities.axe.cleave") => {
let (move1, move2, move3, tension) = match stage_section { let (move1, move2, move3, tension) = match stage_section {
Some(StageSection::Charge) => { Some(StageSection::Charge) => {
next.main_weapon_trail = false;
next.off_weapon_trail = false;
(anim_time.min(1.0), 0.0, 0.0, (anim_time * 20.0).sin()) (anim_time.min(1.0), 0.0, 0.0, (anim_time * 20.0).sin())
}, },
Some(StageSection::Action) => (1.0, anim_time.powi(2), 0.0, 0.0), Some(StageSection::Action) => (1.0, anim_time.powi(2), 0.0, 0.0),
Some(StageSection::Recover) => { Some(StageSection::Recover) => (1.0, 1.0, anim_time, 0.0),
next.main_weapon_trail = false;
next.off_weapon_trail = false;
(1.0, 1.0, anim_time, 0.0)
},
_ => (0.0, 0.0, 0.0, 0.0), _ => (0.0, 0.0, 0.0, 0.0),
}; };
let pullback = 1.0 - move3; let pullback = 1.0 - move3;

View File

@ -32,10 +32,12 @@ impl Animation for ComboAnimation {
next.main.position = Vec3::new(0.0, 0.0, 0.0); next.main.position = Vec3::new(0.0, 0.0, 0.0);
next.main.orientation = Quaternion::rotation_z(0.0); next.main.orientation = Quaternion::rotation_z(0.0);
next.main_weapon_trail = true;
next.second.position = Vec3::new(0.0, 0.0, 0.0); next.second.position = Vec3::new(0.0, 0.0, 0.0);
next.second.orientation = Quaternion::rotation_z(0.0); next.second.orientation = Quaternion::rotation_z(0.0);
next.off_weapon_trail = true; if matches!(stage_section, Some(StageSection::Action)) {
next.main_weapon_trail = true;
next.off_weapon_trail = true;
}
let multi_strike_pullback = 1.0 let multi_strike_pullback = 1.0
- if matches!(stage_section, Some(StageSection::Recover)) { - if matches!(stage_section, Some(StageSection::Recover)) {
anim_time.powi(4) anim_time.powi(4)
@ -882,17 +884,9 @@ impl Animation for ComboAnimation {
Some("common.abilities.axe.triple_chop") => { Some("common.abilities.axe.triple_chop") => {
let (move1, move2) = if strike == current_strike { let (move1, move2) = if strike == current_strike {
match stage_section { match stage_section {
Some(StageSection::Buildup) => { Some(StageSection::Buildup) => (anim_time, 0.0),
next.main_weapon_trail = false;
next.off_weapon_trail = false;
(anim_time, 0.0)
},
Some(StageSection::Action) => (1.0, anim_time), Some(StageSection::Action) => (1.0, anim_time),
Some(StageSection::Recover) => { Some(StageSection::Recover) => (1.0, 1.0),
next.main_weapon_trail = false;
next.off_weapon_trail = false;
(1.0, 1.0)
},
_ => (0.0, 0.0), _ => (0.0, 0.0),
} }
} else { } else {
@ -972,17 +966,9 @@ impl Animation for ComboAnimation {
}, },
Some("common.abilities.axe.brutal_swing") => { Some("common.abilities.axe.brutal_swing") => {
let (move1, move2_raw) = match stage_section { let (move1, move2_raw) = match stage_section {
Some(StageSection::Buildup) => { Some(StageSection::Buildup) => (anim_time, 0.0),
next.main_weapon_trail = false;
next.off_weapon_trail = false;
(anim_time, 0.0)
},
Some(StageSection::Action) => (1.0, anim_time), Some(StageSection::Action) => (1.0, anim_time),
Some(StageSection::Recover) => { Some(StageSection::Recover) => (1.0, 1.0),
next.main_weapon_trail = false;
next.off_weapon_trail = false;
(1.0, 1.0)
},
_ => (0.0, 0.0), _ => (0.0, 0.0),
}; };
let move1 = move1 * multi_strike_pullback; let move1 = move1 * multi_strike_pullback;
@ -1007,17 +993,9 @@ impl Animation for ComboAnimation {
}, },
Some("common.abilities.axe.rising_tide") => { Some("common.abilities.axe.rising_tide") => {
let (move1, move2_raw) = match stage_section { let (move1, move2_raw) = match stage_section {
Some(StageSection::Buildup) => { Some(StageSection::Buildup) => (anim_time, 0.0),
next.main_weapon_trail = false;
next.off_weapon_trail = false;
(anim_time, 0.0)
},
Some(StageSection::Action) => (1.0, anim_time), Some(StageSection::Action) => (1.0, anim_time),
Some(StageSection::Recover) => { Some(StageSection::Recover) => (1.0, 1.0),
next.main_weapon_trail = false;
next.off_weapon_trail = false;
(1.0, 1.0)
},
_ => (0.0, 0.0), _ => (0.0, 0.0),
}; };
let move1 = move1 * multi_strike_pullback; let move1 = move1 * multi_strike_pullback;

View File

@ -26,10 +26,12 @@ impl Animation for FinisherMeleeAnimation {
next.main.position = Vec3::new(0.0, 0.0, 0.0); next.main.position = Vec3::new(0.0, 0.0, 0.0);
next.main.orientation = Quaternion::rotation_z(0.0); next.main.orientation = Quaternion::rotation_z(0.0);
next.main_weapon_trail = true;
next.second.position = Vec3::new(0.0, 0.0, 0.0); next.second.position = Vec3::new(0.0, 0.0, 0.0);
next.second.orientation = Quaternion::rotation_z(0.0); next.second.orientation = Quaternion::rotation_z(0.0);
next.off_weapon_trail = true; if matches!(stage_section, Some(StageSection::Action)) {
next.main_weapon_trail = true;
next.off_weapon_trail = true;
}
match ability_id { match ability_id {
Some("common.abilities.sword.basic_mighty_strike") => { Some("common.abilities.sword.basic_mighty_strike") => {
@ -176,6 +178,46 @@ impl Animation for FinisherMeleeAnimation {
next.control.position += Vec3::new(move2 * -3.0, move2 * 12.0, move2 * -17.0); next.control.position += Vec3::new(move2 * -3.0, move2 * 12.0, move2 * -17.0);
next.control.orientation.rotate_z(move2 * 0.7); next.control.orientation.rotate_z(move2 * 0.7);
}, },
Some("common.abilities.axe.maelstrom") => {
let (move1, move2_raw, move3) = match stage_section {
Some(StageSection::Buildup) => (anim_time, 0.0, 0.0),
Some(StageSection::Action) => (1.0, anim_time, 0.0),
Some(StageSection::Recover) => (1.0, 1.0, anim_time),
_ => (0.0, 0.0, 0.0),
};
let pullback = 1.0 - move3;
let move1 = move1 * pullback;
let move2 = move2_raw * pullback;
next.hand_l.position = Vec3::new(s_a.ahl.0, s_a.ahl.1, s_a.ahl.2);
next.hand_l.orientation =
Quaternion::rotation_x(s_a.ahl.3) * Quaternion::rotation_y(s_a.ahl.4);
next.hand_r.position = Vec3::new(s_a.ahr.0, s_a.ahr.1, s_a.ahr.2);
next.hand_r.orientation =
Quaternion::rotation_x(s_a.ahr.3) * Quaternion::rotation_z(s_a.ahr.5);
next.control.position = Vec3::new(s_a.ac.0, s_a.ac.1, s_a.ac.2);
next.control.orientation = Quaternion::rotation_x(s_a.ac.3)
* Quaternion::rotation_y(s_a.ac.4)
* Quaternion::rotation_z(s_a.ac.5);
next.control.orientation.rotate_x(move1 * 0.9);
next.chest.orientation.rotate_z(move1 * 1.2);
next.head.orientation.rotate_z(move1 * -0.5);
next.belt.orientation.rotate_z(move1 * -0.3);
next.shorts.orientation.rotate_z(move1 * -0.7);
next.control.position += Vec3::new(move1 * 4.0, move1 * -12.0, move1 * 11.0);
next.chest.orientation.rotate_z(move2 * -2.0);
next.head.orientation.rotate_z(move2 * 0.9);
next.belt.orientation.rotate_z(move2 * 0.4);
next.shorts.orientation.rotate_z(move2 * 1.1);
next.control.orientation.rotate_x(move2 * -5.0);
next.control.position += Vec3::new(move2 * 5.0, move2 * 12.0, move2 * -17.0);
next.control.orientation.rotate_y(move2 * -2.0);
next.control.orientation.rotate_z(move2 * -1.0);
next.torso.orientation.rotate_z(move2_raw * -4.0 * PI);
},
_ => {}, _ => {},
} }

View File

@ -34,10 +34,12 @@ impl Animation for RapidMeleeAnimation {
next.main.position = Vec3::new(0.0, 0.0, 0.0); next.main.position = Vec3::new(0.0, 0.0, 0.0);
next.main.orientation = Quaternion::rotation_z(0.0); next.main.orientation = Quaternion::rotation_z(0.0);
next.main_weapon_trail = true;
next.second.position = Vec3::new(0.0, 0.0, 0.0); next.second.position = Vec3::new(0.0, 0.0, 0.0);
next.second.orientation = Quaternion::rotation_z(0.0); next.second.orientation = Quaternion::rotation_z(0.0);
next.off_weapon_trail = true; if matches!(stage_section, Some(StageSection::Action)) {
next.main_weapon_trail = true;
next.off_weapon_trail = true;
}
match ability_id { match ability_id {
Some( Some(

View File

@ -25,10 +25,12 @@ impl Animation for RiposteMeleeAnimation {
next.main.position = Vec3::new(0.0, 0.0, 0.0); next.main.position = Vec3::new(0.0, 0.0, 0.0);
next.main.orientation = Quaternion::rotation_z(0.0); next.main.orientation = Quaternion::rotation_z(0.0);
next.main_weapon_trail = true;
next.second.position = Vec3::new(0.0, 0.0, 0.0); next.second.position = Vec3::new(0.0, 0.0, 0.0);
next.second.orientation = Quaternion::rotation_z(0.0); next.second.orientation = Quaternion::rotation_z(0.0);
next.off_weapon_trail = true; if matches!(stage_section, Some(StageSection::Action)) {
next.main_weapon_trail = true;
next.off_weapon_trail = true;
}
match ability_id { match ability_id {
Some("common.abilities.sword.defensive_riposte") => { Some("common.abilities.sword.defensive_riposte") => {

View File

@ -3047,6 +3047,7 @@ impl Hud {
let bodies = ecs.read_storage::<comp::Body>(); let bodies = ecs.read_storage::<comp::Body>();
let poises = ecs.read_storage::<comp::Poise>(); let poises = ecs.read_storage::<comp::Poise>();
let combos = ecs.read_storage::<comp::Combo>(); let combos = ecs.read_storage::<comp::Combo>();
let combo = combos.get(entity);
let time = ecs.read_resource::<Time>(); let time = ecs.read_resource::<Time>();
let stances = ecs.read_storage::<comp::Stance>(); let stances = ecs.read_storage::<comp::Stance>();
let char_states = ecs.read_storage::<comp::CharacterState>(); let char_states = ecs.read_storage::<comp::CharacterState>();
@ -3073,7 +3074,7 @@ impl Hud {
bodies.get(entity), bodies.get(entity),
) { ) {
let stance = stances.get(entity); let stance = stances.get(entity);
let contexts = AbilityContext::from(stance, Some(inventory)); let contexts = AbilityContext::from(stance, Some(inventory), combo);
match Skillbar::new( match Skillbar::new(
client, client,
&info, &info,
@ -3100,7 +3101,7 @@ impl Hud {
&msm, &msm,
self.floaters.combo_floater, self.floaters.combo_floater,
&contexts, &contexts,
combos.get(entity), combo,
char_states.get(entity), char_states.get(entity),
stance, stance,
) )
@ -3581,7 +3582,7 @@ impl Hud {
bodies.get(entity), bodies.get(entity),
poises.get(entity), poises.get(entity),
) { ) {
let contexts = AbilityContext::from(stances.get(entity), Some(inventory)); let contexts = AbilityContext::from(stances.get(entity), Some(inventory), combo);
for event in Diary::new( for event in Diary::new(
&self.show, &self.show,
client, client,

View File

@ -39,9 +39,9 @@ use common::{
inventory::slot::EquipSlot, inventory::slot::EquipSlot,
item::{tool::AbilityContext, Hands, ItemKind, ToolKind}, item::{tool::AbilityContext, Hands, ItemKind, ToolKind},
ship::{self, figuredata::VOXEL_COLLIDER_MANIFEST}, ship::{self, figuredata::VOXEL_COLLIDER_MANIFEST},
Body, CharacterActivity, CharacterState, Collider, Controller, Health, Inventory, Item, Body, CharacterActivity, CharacterState, Collider, Combo, Controller, Health, Inventory,
ItemKey, Last, LightAnimation, LightEmitter, Object, Ori, PhysicsState, PoiseState, Pos, Item, ItemKey, Last, LightAnimation, LightEmitter, Object, Ori, PhysicsState, PoiseState,
Scale, SkillSet, Stance, Vel, Pos, Scale, SkillSet, Stance, Vel,
}, },
link::Is, link::Is,
mounting::{Rider, VolumeRider}, mounting::{Rider, VolumeRider},
@ -853,7 +853,7 @@ impl FigureMgr {
inventory, inventory,
item, item,
light_emitter, light_emitter,
(is_rider, is_volume_rider, collider, stance, skillset), (is_rider, is_volume_rider, collider, stance, skillset, combo),
), ),
) in ( ) in (
&ecs.entities(), &ecs.entities(),
@ -877,6 +877,7 @@ impl FigureMgr {
ecs.read_storage::<Collider>().maybe(), ecs.read_storage::<Collider>().maybe(),
ecs.read_storage::<Stance>().maybe(), ecs.read_storage::<Stance>().maybe(),
ecs.read_storage::<SkillSet>().maybe(), ecs.read_storage::<SkillSet>().maybe(),
ecs.read_storage::<Combo>().maybe(),
), ),
) )
.join() .join()
@ -1037,7 +1038,7 @@ impl FigureMgr {
let second_tool_spec = second_tool_spec.as_deref(); let second_tool_spec = second_tool_spec.as_deref();
let hands = (active_tool_hand, second_tool_hand); let hands = (active_tool_hand, second_tool_hand);
let contexts = AbilityContext::from(stance, inventory); let contexts = AbilityContext::from(stance, inventory, combo);
let ability_id = character.and_then(|c| { let ability_id = character.and_then(|c| {
c.ability_info() c.ability_info()