mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
transform character state
This commit is contained in:
parent
b9a3fa1edc
commit
036e79284e
@ -930,6 +930,7 @@
|
|||||||
secondary: Simple(None, "common.abilities.debug.upboost"),
|
secondary: Simple(None, "common.abilities.debug.upboost"),
|
||||||
abilities: [
|
abilities: [
|
||||||
Simple(None, "common.abilities.debug.possess"),
|
Simple(None, "common.abilities.debug.possess"),
|
||||||
|
Simple(None, "common.abilities.debug.evolve"),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Tool(Farming): (
|
Tool(Farming): (
|
||||||
|
6
assets/common/abilities/debug/evolve.ron
Normal file
6
assets/common/abilities/debug/evolve.ron
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
Transform(
|
||||||
|
buildup_duration: 2.0,
|
||||||
|
recover_duration: 0.5,
|
||||||
|
target: "common.entity.wild.peaceful.crab",
|
||||||
|
specifier: Some(Evolve),
|
||||||
|
)
|
@ -1,5 +1,7 @@
|
|||||||
common-abilities-debug-possess = Possessing Arrow
|
common-abilities-debug-possess = Possessing Arrow
|
||||||
.desc = Shoots a poisonous arrow. Lets you control your target.
|
.desc = Shoots a poisonous arrow. Lets you control your target.
|
||||||
|
common-abilities-debug-evolve = Evolve
|
||||||
|
.desc = You become your better self.
|
||||||
common-abilities-hammer-leap = Smash of Doom
|
common-abilities-hammer-leap = Smash of Doom
|
||||||
.desc = An AOE attack with knockback. Leaps to position of cursor.
|
.desc = An AOE attack with knockback. Leaps to position of cursor.
|
||||||
common-abilities-bow-shotgun = Burst
|
common-abilities-bow-shotgun = Burst
|
||||||
|
@ -646,6 +646,7 @@ impl From<&CharacterState> for CharacterAbilityType {
|
|||||||
| CharacterState::UseItem(_)
|
| CharacterState::UseItem(_)
|
||||||
| CharacterState::SpriteInteract(_)
|
| CharacterState::SpriteInteract(_)
|
||||||
| CharacterState::Skate(_)
|
| CharacterState::Skate(_)
|
||||||
|
| CharacterState::Transform(_)
|
||||||
| CharacterState::Wallrun(_) => Self::Other,
|
| CharacterState::Wallrun(_) => Self::Other,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -997,6 +998,15 @@ pub enum CharacterAbility {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
meta: AbilityMeta,
|
meta: AbilityMeta,
|
||||||
},
|
},
|
||||||
|
Transform {
|
||||||
|
buildup_duration: f32,
|
||||||
|
recover_duration: f32,
|
||||||
|
target: String,
|
||||||
|
#[serde(default)]
|
||||||
|
specifier: Option<transform::FrontendSpecifier>,
|
||||||
|
#[serde(default)]
|
||||||
|
meta: AbilityMeta,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for CharacterAbility {
|
impl Default for CharacterAbility {
|
||||||
@ -1115,7 +1125,8 @@ impl CharacterAbility {
|
|||||||
| CharacterAbility::Blink { .. }
|
| CharacterAbility::Blink { .. }
|
||||||
| CharacterAbility::Music { .. }
|
| CharacterAbility::Music { .. }
|
||||||
| CharacterAbility::BasicSummon { .. }
|
| CharacterAbility::BasicSummon { .. }
|
||||||
| CharacterAbility::SpriteSummon { .. } => true,
|
| CharacterAbility::SpriteSummon { .. }
|
||||||
|
| CharacterAbility::Transform { .. } => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1662,6 +1673,16 @@ impl CharacterAbility {
|
|||||||
*energy_cost /= stats.energy_efficiency;
|
*energy_cost /= stats.energy_efficiency;
|
||||||
*melee_constructor = melee_constructor.adjusted_by_stats(stats);
|
*melee_constructor = melee_constructor.adjusted_by_stats(stats);
|
||||||
},
|
},
|
||||||
|
Transform {
|
||||||
|
ref mut buildup_duration,
|
||||||
|
ref mut recover_duration,
|
||||||
|
target: _,
|
||||||
|
specifier: _,
|
||||||
|
meta: _,
|
||||||
|
} => {
|
||||||
|
*buildup_duration /= stats.speed;
|
||||||
|
*recover_duration /= stats.speed;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -1702,7 +1723,8 @@ impl CharacterAbility {
|
|||||||
| Blink { .. }
|
| Blink { .. }
|
||||||
| Music { .. }
|
| Music { .. }
|
||||||
| BasicSummon { .. }
|
| BasicSummon { .. }
|
||||||
| SpriteSummon { .. } => 0.0,
|
| SpriteSummon { .. }
|
||||||
|
| Transform { .. } => 0.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1750,7 +1772,8 @@ impl CharacterAbility {
|
|||||||
| Blink { .. }
|
| Blink { .. }
|
||||||
| Music { .. }
|
| Music { .. }
|
||||||
| BasicSummon { .. }
|
| BasicSummon { .. }
|
||||||
| SpriteSummon { .. } => 0,
|
| SpriteSummon { .. }
|
||||||
|
| Transform { .. } => 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1782,7 +1805,8 @@ impl CharacterAbility {
|
|||||||
| Music { meta, .. }
|
| Music { meta, .. }
|
||||||
| DiveMelee { meta, .. }
|
| DiveMelee { meta, .. }
|
||||||
| RiposteMelee { meta, .. }
|
| RiposteMelee { meta, .. }
|
||||||
| RapidMelee { meta, .. } => *meta,
|
| RapidMelee { meta, .. }
|
||||||
|
| Transform { meta, .. } => *meta,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2935,6 +2959,23 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState {
|
|||||||
stage_section: StageSection::Buildup,
|
stage_section: StageSection::Buildup,
|
||||||
exhausted: false,
|
exhausted: false,
|
||||||
}),
|
}),
|
||||||
|
CharacterAbility::Transform {
|
||||||
|
buildup_duration,
|
||||||
|
recover_duration,
|
||||||
|
target,
|
||||||
|
specifier,
|
||||||
|
meta: _,
|
||||||
|
} => CharacterState::Transform(transform::Data {
|
||||||
|
static_data: transform::StaticData {
|
||||||
|
buildup_duration: Duration::from_secs_f32(*buildup_duration),
|
||||||
|
recover_duration: Duration::from_secs_f32(*recover_duration),
|
||||||
|
specifier: *specifier,
|
||||||
|
target: target.to_owned(),
|
||||||
|
ability_info,
|
||||||
|
},
|
||||||
|
timer: Duration::default(),
|
||||||
|
stage_section: StageSection::Buildup,
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,7 @@ event_emitters! {
|
|||||||
energy_change: event::EnergyChangeEvent,
|
energy_change: event::EnergyChangeEvent,
|
||||||
knockback: event::KnockbackEvent,
|
knockback: event::KnockbackEvent,
|
||||||
sprite_light: event::ToggleSpriteLightEvent,
|
sprite_light: event::ToggleSpriteLightEvent,
|
||||||
|
transform: event::TransformEvent,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,6 +173,8 @@ pub enum CharacterState {
|
|||||||
/// A series of consecutive, identical attacks that only go through buildup
|
/// A series of consecutive, identical attacks that only go through buildup
|
||||||
/// and recover once for the entire state
|
/// and recover once for the entire state
|
||||||
RapidMelee(rapid_melee::Data),
|
RapidMelee(rapid_melee::Data),
|
||||||
|
/// Transforms an entity into another
|
||||||
|
Transform(transform::Data),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CharacterState {
|
impl CharacterState {
|
||||||
@ -518,6 +521,7 @@ impl CharacterState {
|
|||||||
CharacterState::DiveMelee(data) => data.behavior(j, output_events),
|
CharacterState::DiveMelee(data) => data.behavior(j, output_events),
|
||||||
CharacterState::RiposteMelee(data) => data.behavior(j, output_events),
|
CharacterState::RiposteMelee(data) => data.behavior(j, output_events),
|
||||||
CharacterState::RapidMelee(data) => data.behavior(j, output_events),
|
CharacterState::RapidMelee(data) => data.behavior(j, output_events),
|
||||||
|
CharacterState::Transform(data) => data.behavior(j, output_events),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -573,6 +577,7 @@ impl CharacterState {
|
|||||||
CharacterState::DiveMelee(data) => data.handle_event(j, output_events, action),
|
CharacterState::DiveMelee(data) => data.handle_event(j, output_events, action),
|
||||||
CharacterState::RiposteMelee(data) => data.handle_event(j, output_events, action),
|
CharacterState::RiposteMelee(data) => data.handle_event(j, output_events, action),
|
||||||
CharacterState::RapidMelee(data) => data.handle_event(j, output_events, action),
|
CharacterState::RapidMelee(data) => data.handle_event(j, output_events, action),
|
||||||
|
CharacterState::Transform(data) => data.handle_event(j, output_events, action),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -625,6 +630,7 @@ impl CharacterState {
|
|||||||
CharacterState::DiveMelee(data) => Some(data.static_data.ability_info),
|
CharacterState::DiveMelee(data) => Some(data.static_data.ability_info),
|
||||||
CharacterState::RiposteMelee(data) => Some(data.static_data.ability_info),
|
CharacterState::RiposteMelee(data) => Some(data.static_data.ability_info),
|
||||||
CharacterState::RapidMelee(data) => Some(data.static_data.ability_info),
|
CharacterState::RapidMelee(data) => Some(data.static_data.ability_info),
|
||||||
|
CharacterState::Transform(data) => Some(data.static_data.ability_info),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -669,6 +675,7 @@ impl CharacterState {
|
|||||||
CharacterState::DiveMelee(data) => Some(data.stage_section),
|
CharacterState::DiveMelee(data) => Some(data.stage_section),
|
||||||
CharacterState::RiposteMelee(data) => Some(data.stage_section),
|
CharacterState::RiposteMelee(data) => Some(data.stage_section),
|
||||||
CharacterState::RapidMelee(data) => Some(data.stage_section),
|
CharacterState::RapidMelee(data) => Some(data.stage_section),
|
||||||
|
CharacterState::Transform(data) => Some(data.stage_section),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -857,6 +864,11 @@ impl CharacterState {
|
|||||||
recover: Some(data.static_data.recover_duration),
|
recover: Some(data.static_data.recover_duration),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
|
CharacterState::Transform(data) => Some(DurationsInfo {
|
||||||
|
buildup: Some(data.static_data.buildup_duration),
|
||||||
|
recover: Some(data.static_data.recover_duration),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -901,6 +913,7 @@ impl CharacterState {
|
|||||||
CharacterState::DiveMelee(data) => Some(data.timer),
|
CharacterState::DiveMelee(data) => Some(data.timer),
|
||||||
CharacterState::RiposteMelee(data) => Some(data.timer),
|
CharacterState::RiposteMelee(data) => Some(data.timer),
|
||||||
CharacterState::RapidMelee(data) => Some(data.timer),
|
CharacterState::RapidMelee(data) => Some(data.timer),
|
||||||
|
CharacterState::Transform(data) => Some(data.timer),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -960,6 +973,7 @@ impl CharacterState {
|
|||||||
CharacterState::DiveMelee(_) => Some(AttackSource::Melee),
|
CharacterState::DiveMelee(_) => Some(AttackSource::Melee),
|
||||||
CharacterState::RiposteMelee(_) => Some(AttackSource::Melee),
|
CharacterState::RiposteMelee(_) => Some(AttackSource::Melee),
|
||||||
CharacterState::RapidMelee(_) => Some(AttackSource::Melee),
|
CharacterState::RapidMelee(_) => Some(AttackSource::Melee),
|
||||||
|
CharacterState::Transform(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,7 @@ pub mod sprite_interact;
|
|||||||
pub mod sprite_summon;
|
pub mod sprite_summon;
|
||||||
pub mod stunned;
|
pub mod stunned;
|
||||||
pub mod talk;
|
pub mod talk;
|
||||||
|
pub mod transform;
|
||||||
pub mod use_item;
|
pub mod use_item;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
pub mod wallrun;
|
pub mod wallrun;
|
||||||
|
125
common/src/states/transform.rs
Normal file
125
common/src/states/transform.rs
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use common_assets::AssetExt;
|
||||||
|
use rand::thread_rng;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use vek::Vec3;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
comp::{item::Reagent, CharacterState, StateUpdate},
|
||||||
|
event::TransformEvent,
|
||||||
|
generation::{EntityConfig, EntityInfo},
|
||||||
|
states::utils::{end_ability, tick_attack_or_default},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
behavior::CharacterBehavior,
|
||||||
|
utils::{AbilityInfo, StageSection},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub enum FrontendSpecifier {
|
||||||
|
Evolve,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct StaticData {
|
||||||
|
/// How long until state has until transformation
|
||||||
|
pub buildup_duration: Duration,
|
||||||
|
/// How long the state has until exiting
|
||||||
|
pub recover_duration: Duration,
|
||||||
|
/// The entity configuration you will be transformed into
|
||||||
|
pub target: String,
|
||||||
|
pub ability_info: AbilityInfo,
|
||||||
|
/// Used to specify the transformation to the frontend
|
||||||
|
pub specifier: Option<FrontendSpecifier>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct Data {
|
||||||
|
/// Struct containing data that does not change over the course of the
|
||||||
|
/// character state
|
||||||
|
pub static_data: StaticData,
|
||||||
|
/// Timer for each stage
|
||||||
|
pub timer: Duration,
|
||||||
|
/// What section the character stage is in
|
||||||
|
pub stage_section: StageSection,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CharacterBehavior for Data {
|
||||||
|
fn behavior(
|
||||||
|
&self,
|
||||||
|
data: &super::behavior::JoinData,
|
||||||
|
output_events: &mut crate::comp::character_state::OutputEvents,
|
||||||
|
) -> crate::comp::StateUpdate {
|
||||||
|
let mut update = StateUpdate::from(data);
|
||||||
|
match self.stage_section {
|
||||||
|
StageSection::Buildup => {
|
||||||
|
// Tick the timer as long as buildup hasn't finihsed
|
||||||
|
if self.timer < self.static_data.buildup_duration {
|
||||||
|
update.character = CharacterState::Transform(Data {
|
||||||
|
static_data: self.static_data.clone(),
|
||||||
|
timer: tick_attack_or_default(data, self.timer, None),
|
||||||
|
..*self
|
||||||
|
});
|
||||||
|
// Buildup finished, start transformation
|
||||||
|
} else {
|
||||||
|
let Ok(entity_config) = EntityConfig::load(&self.static_data.target) else {
|
||||||
|
end_ability(data, &mut update);
|
||||||
|
return update;
|
||||||
|
};
|
||||||
|
|
||||||
|
let entity_info = EntityInfo::at(Vec3::zero()).with_entity_config(
|
||||||
|
entity_config.read().clone(),
|
||||||
|
Some(&self.static_data.target),
|
||||||
|
&mut thread_rng(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Handle frontend events
|
||||||
|
if let Some(specifier) = self.static_data.specifier {
|
||||||
|
match specifier {
|
||||||
|
FrontendSpecifier::Evolve => {
|
||||||
|
output_events.emit_local(crate::event::LocalEvent::CreateOutcome(
|
||||||
|
crate::outcome::Outcome::Explosion {
|
||||||
|
pos: data.pos.0,
|
||||||
|
power: 5.0,
|
||||||
|
radius: 2.0,
|
||||||
|
is_attack: false,
|
||||||
|
reagent: Some(Reagent::White),
|
||||||
|
},
|
||||||
|
))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output_events.emit_server(TransformEvent(*data.uid, entity_info));
|
||||||
|
update.character = CharacterState::Transform(Data {
|
||||||
|
static_data: self.static_data.clone(),
|
||||||
|
timer: Duration::default(),
|
||||||
|
stage_section: StageSection::Recover,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
StageSection::Recover => {
|
||||||
|
// Wait for recovery period to finish
|
||||||
|
if self.timer < self.static_data.recover_duration {
|
||||||
|
update.character = CharacterState::Transform(Data {
|
||||||
|
static_data: self.static_data.clone(),
|
||||||
|
timer: tick_attack_or_default(data, self.timer, None),
|
||||||
|
..*self
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// End the ability after recovery is done
|
||||||
|
end_ability(data, &mut update);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
// If we somehow ended up in an incorrect character state, end the ability
|
||||||
|
end_ability(data, &mut update);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
update
|
||||||
|
}
|
||||||
|
}
|
@ -209,6 +209,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
| CharacterState::Stunned(_)
|
| CharacterState::Stunned(_)
|
||||||
| CharacterState::BasicBlock(_)
|
| CharacterState::BasicBlock(_)
|
||||||
| CharacterState::UseItem(_)
|
| CharacterState::UseItem(_)
|
||||||
|
| CharacterState::Transform(_)
|
||||||
| CharacterState::SpriteInteract(_) => {},
|
| CharacterState::SpriteInteract(_) => {},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1384,6 +1384,38 @@ impl ParticleMgr {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
CharacterState::Transform(data) => {
|
||||||
|
if matches!(data.stage_section, StageSection::Buildup)
|
||||||
|
&& let Some(specifier) = data.static_data.specifier
|
||||||
|
{
|
||||||
|
match specifier {
|
||||||
|
states::transform::FrontendSpecifier::Evolve => {
|
||||||
|
self.particles.resize_with(
|
||||||
|
self.particles.len()
|
||||||
|
+ usize::from(
|
||||||
|
self.scheduler.heartbeats(Duration::from_millis(10)),
|
||||||
|
),
|
||||||
|
|| {
|
||||||
|
let start_pos = interpolated.pos
|
||||||
|
+ (Vec2::unit_y()
|
||||||
|
* rng.gen::<f32>()
|
||||||
|
* body.max_radius())
|
||||||
|
.rotated_z(rng.gen_range(0.0..(PI * 2.0)))
|
||||||
|
.with_z(body.height() * rng.gen::<f32>());
|
||||||
|
|
||||||
|
Particle::new_directed(
|
||||||
|
Duration::from_millis(100),
|
||||||
|
time,
|
||||||
|
ParticleMode::BarrelOrgan,
|
||||||
|
start_pos,
|
||||||
|
start_pos + Vec3::unit_z() * 2.0,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user