mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Tornado summoning attack
This commit is contained in:
parent
97ce50e5d4
commit
3ba0500b90
@ -3,11 +3,16 @@ BasicSummon(
|
||||
cast_duration: 1.0,
|
||||
recover_duration: 0.5,
|
||||
summon_amount: 6,
|
||||
summon_distance: (1, 5),
|
||||
summon_info: (
|
||||
body: Object(Tornado),
|
||||
scale: None,
|
||||
health_scaling: 80,
|
||||
health_scaling: None,
|
||||
loadout_config: None,
|
||||
skillset_config: None,
|
||||
),
|
||||
duration: Some((
|
||||
secs: 5,
|
||||
nanos: 0,
|
||||
)),
|
||||
)
|
@ -3,14 +3,16 @@ BasicSummon(
|
||||
cast_duration: 1.0,
|
||||
recover_duration: 0.5,
|
||||
summon_amount: 6,
|
||||
summon_distance: (3, 3),
|
||||
summon_info: (
|
||||
body: BipedSmall((
|
||||
species: Husk,
|
||||
body_type: Male,
|
||||
)),
|
||||
scale: None,
|
||||
health_scaling: 80,
|
||||
health_scaling: Some(80),
|
||||
loadout_config: Some(HuskSummon),
|
||||
skillset_config: None,
|
||||
),
|
||||
duration: None,
|
||||
)
|
||||
|
@ -3,11 +3,13 @@ BasicSummon(
|
||||
cast_duration: 1.0,
|
||||
recover_duration: 0.5,
|
||||
summon_amount: 1,
|
||||
summon_distance: (1, 1),
|
||||
summon_info: (
|
||||
body: Object(SeaLantern),
|
||||
scale: None,
|
||||
health_scaling: 0,
|
||||
health_scaling: Some(0),
|
||||
loadout_config: None,
|
||||
skillset_config: None,
|
||||
),
|
||||
duration: None,
|
||||
)
|
||||
|
@ -1,13 +1,13 @@
|
||||
SpinMelee(
|
||||
buildup_duration: 0.2,
|
||||
swing_duration: 0.6,
|
||||
recover_duration: 0.2,
|
||||
base_damage: 70,
|
||||
base_poise_damage: 25,
|
||||
knockback: ( strength: 0.0, direction: Away),
|
||||
buildup_duration: 0.0,
|
||||
swing_duration: 0.5,
|
||||
recover_duration: 0.0,
|
||||
base_damage: 15000,
|
||||
base_poise_damage: 200,
|
||||
knockback: ( strength: 200.0, direction: Away),
|
||||
range: 3.5,
|
||||
damage_effect: None,
|
||||
energy_cost: 100,
|
||||
energy_cost: 0,
|
||||
is_infinite: true,
|
||||
movement_behavior: AxeHover,
|
||||
is_interruptible: false,
|
||||
|
19
assets/common/items/npc_weapons/unique/tornado.ron
Normal file
19
assets/common/items/npc_weapons/unique/tornado.ron
Normal file
@ -0,0 +1,19 @@
|
||||
ItemDef(
|
||||
name: "Tornado",
|
||||
description: "Tornado weapon",
|
||||
kind: Tool((
|
||||
kind: Natural,
|
||||
hands: Two,
|
||||
stats: Direct((
|
||||
equip_time_secs: 0.01,
|
||||
power: 1.0,
|
||||
poise_strength: 1.0,
|
||||
speed: 1.0,
|
||||
crit_chance: 0.0,
|
||||
crit_mult: 0.0,
|
||||
)),
|
||||
)),
|
||||
quality: Low,
|
||||
tags: [],
|
||||
ability_spec: Some(Custom("Tornado")),
|
||||
)
|
@ -280,7 +280,9 @@ pub enum CharacterAbility {
|
||||
cast_duration: f32,
|
||||
recover_duration: f32,
|
||||
summon_amount: u32,
|
||||
summon_distance: (f32, f32),
|
||||
summon_info: basic_summon::SummonInfo,
|
||||
duration: Option<Duration>,
|
||||
},
|
||||
SelfBuff {
|
||||
buildup_duration: f32,
|
||||
@ -1737,15 +1739,19 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
|
||||
cast_duration,
|
||||
recover_duration,
|
||||
summon_amount,
|
||||
summon_distance,
|
||||
summon_info,
|
||||
duration,
|
||||
} => CharacterState::BasicSummon(basic_summon::Data {
|
||||
static_data: basic_summon::StaticData {
|
||||
buildup_duration: Duration::from_secs_f32(*buildup_duration),
|
||||
cast_duration: Duration::from_secs_f32(*cast_duration),
|
||||
recover_duration: Duration::from_secs_f32(*recover_duration),
|
||||
summon_amount: *summon_amount,
|
||||
summon_distance: *summon_distance,
|
||||
summon_info: *summon_info,
|
||||
ability_info,
|
||||
duration: *duration,
|
||||
},
|
||||
summon_count: 0,
|
||||
timer: Duration::default(),
|
||||
|
@ -306,6 +306,9 @@ fn default_main_tool(body: &Body) -> Item {
|
||||
object::Body::SeaLantern => Some(Item::new_from_asset_expect(
|
||||
"common.items.npc_weapons.unique.tidal_totem",
|
||||
)),
|
||||
object::Body::Tornado => Some(Item::new_from_asset_expect(
|
||||
"common.items.npc_weapons.unique.tornado",
|
||||
)),
|
||||
_ => None,
|
||||
},
|
||||
Body::BipedSmall(biped_small) => match (biped_small.species, biped_small.body_type) {
|
||||
|
@ -117,7 +117,7 @@ pub enum ServerEvent {
|
||||
pos: comp::Pos,
|
||||
stats: comp::Stats,
|
||||
skill_set: comp::SkillSet,
|
||||
health: comp::Health,
|
||||
health: Option<comp::Health>,
|
||||
poise: comp::Poise,
|
||||
loadout: comp::inventory::loadout::Loadout,
|
||||
body: comp::Body,
|
||||
@ -127,6 +127,7 @@ pub enum ServerEvent {
|
||||
home_chunk: Option<comp::HomeChunk>,
|
||||
drop_item: Option<Item>,
|
||||
rtsim_entity: Option<RtSimEntity>,
|
||||
projectile: Option<comp::Projectile>,
|
||||
},
|
||||
CreateShip {
|
||||
pos: comp::Pos,
|
||||
|
@ -2,7 +2,7 @@ use crate::{
|
||||
comp::{
|
||||
self,
|
||||
inventory::loadout_builder::{self, LoadoutBuilder},
|
||||
Behavior, BehaviorCapability, CharacterState, StateUpdate,
|
||||
Behavior, BehaviorCapability, CharacterState, Projectile, StateUpdate,
|
||||
},
|
||||
event::{LocalEvent, ServerEvent},
|
||||
outcome::Outcome,
|
||||
@ -11,9 +11,13 @@ use crate::{
|
||||
behavior::{CharacterBehavior, JoinData},
|
||||
utils::*,
|
||||
},
|
||||
terrain::Block,
|
||||
vol::ReadVol,
|
||||
};
|
||||
use rand::Rng;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use std::{f32::consts::PI, time::Duration};
|
||||
use vek::*;
|
||||
|
||||
/// Separated out to condense update portions of character state
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
@ -26,10 +30,14 @@ pub struct StaticData {
|
||||
pub recover_duration: Duration,
|
||||
/// How many creatures the state should summon
|
||||
pub summon_amount: u32,
|
||||
/// Range of the summons relative to the summonner
|
||||
pub summon_distance: (f32, f32),
|
||||
/// Information about the summoned creature
|
||||
pub summon_info: SummonInfo,
|
||||
/// Miscellaneous information about the ability
|
||||
pub ability_info: AbilityInfo,
|
||||
/// Duration of the summoned entity
|
||||
pub duration: Option<Duration>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
@ -102,15 +110,67 @@ impl CharacterBehavior for Data {
|
||||
};
|
||||
|
||||
let stats = comp::Stats::new("Summon".to_string());
|
||||
|
||||
let health_scaling = self
|
||||
.static_data
|
||||
.summon_info
|
||||
.health_scaling
|
||||
.map(|health_scaling| comp::Health::new(body, health_scaling));
|
||||
|
||||
// Ray cast to check where summon should happen
|
||||
let summon_frac =
|
||||
self.summon_count as f32 / self.static_data.summon_amount as f32;
|
||||
|
||||
let length = rand::thread_rng().gen_range(
|
||||
self.static_data.summon_distance.0..self.static_data.summon_distance.1,
|
||||
);
|
||||
|
||||
// Summon in a clockwise fashion
|
||||
let ray_vector = Vec3::new(
|
||||
(summon_frac * 2.0 * PI).sin() * length,
|
||||
(summon_frac * 2.0 * PI).cos() * length,
|
||||
data.body.eye_height(),
|
||||
);
|
||||
|
||||
// Check for collision on the xy plane
|
||||
let obstacle_xy = data
|
||||
.terrain
|
||||
.ray(data.pos.0, data.pos.0 + length * ray_vector)
|
||||
.until(Block::is_solid)
|
||||
.cast()
|
||||
.0;
|
||||
|
||||
let collision_vector = Vec3::new(
|
||||
data.pos.0.x + (summon_frac * 2.0 * PI).sin() * obstacle_xy,
|
||||
data.pos.0.y + (summon_frac * 2.0 * PI).cos() * obstacle_xy,
|
||||
data.pos.0.z,
|
||||
);
|
||||
|
||||
// Check for collision in z up to 50 blocks
|
||||
let obstacle_z = data
|
||||
.terrain
|
||||
.ray(collision_vector, collision_vector - Vec3::unit_z() * 50.0)
|
||||
.until(Block::is_solid)
|
||||
.cast()
|
||||
.0;
|
||||
|
||||
// If a duration is specified, create a projectile componenent for the npc
|
||||
let projectile = self.static_data.duration.map(|duration| Projectile {
|
||||
hit_solid: Vec::new(),
|
||||
hit_entity: Vec::new(),
|
||||
time_left: duration,
|
||||
owner: Some(*data.uid),
|
||||
ignore_group: true,
|
||||
is_sticky: false,
|
||||
is_point: false,
|
||||
});
|
||||
|
||||
// Send server event to create npc
|
||||
update.server_events.push_front(ServerEvent::CreateNpc {
|
||||
pos: *data.pos,
|
||||
pos: comp::Pos(collision_vector - Vec3::unit_z() * obstacle_z),
|
||||
stats,
|
||||
skill_set,
|
||||
health: comp::Health::new(
|
||||
body,
|
||||
self.static_data.summon_info.health_scaling,
|
||||
),
|
||||
health: health_scaling,
|
||||
poise: comp::Poise::new(body),
|
||||
loadout,
|
||||
body,
|
||||
@ -129,6 +189,7 @@ impl CharacterBehavior for Data {
|
||||
home_chunk: None,
|
||||
drop_item: None,
|
||||
rtsim_entity: None,
|
||||
projectile,
|
||||
});
|
||||
|
||||
// Send local event used for frontend shenanigans
|
||||
@ -186,7 +247,7 @@ impl CharacterBehavior for Data {
|
||||
pub struct SummonInfo {
|
||||
body: comp::Body,
|
||||
scale: Option<comp::Scale>,
|
||||
health_scaling: u16,
|
||||
health_scaling: Option<u16>,
|
||||
// TODO: use assets for specifying skills and loadout?
|
||||
loadout_config: Option<loadout_builder::Preset>,
|
||||
skillset_config: Option<skillset_builder::Preset>,
|
||||
|
@ -5,6 +5,7 @@ use crate::{
|
||||
InventoryAction, Mass, Melee, Ori, PhysicsState, Pos, SkillSet, StateUpdate, Stats, Vel,
|
||||
},
|
||||
resources::DeltaTime,
|
||||
terrain::TerrainGrid,
|
||||
uid::Uid,
|
||||
};
|
||||
use specs::{
|
||||
@ -96,6 +97,7 @@ pub struct JoinData<'a> {
|
||||
pub msm: &'a MaterialStatManifest,
|
||||
pub combo: &'a Combo,
|
||||
pub alignment: Option<&'a comp::Alignment>,
|
||||
pub terrain: &'a TerrainGrid,
|
||||
}
|
||||
|
||||
type RestrictedMut<'a, C> = PairedStorage<
|
||||
@ -128,6 +130,7 @@ pub struct JoinStruct<'a> {
|
||||
pub skill_set: &'a SkillSet,
|
||||
pub combo: &'a Combo,
|
||||
pub alignment: Option<&'a comp::Alignment>,
|
||||
pub terrain: &'a TerrainGrid,
|
||||
}
|
||||
|
||||
impl<'a> JoinData<'a> {
|
||||
@ -161,6 +164,7 @@ impl<'a> JoinData<'a> {
|
||||
msm,
|
||||
combo: j.combo,
|
||||
alignment: j.alignment,
|
||||
terrain: j.terrain,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use specs::{
|
||||
shred::ResourceId, Entities, Join, LazyUpdate, Read, ReadStorage, SystemData, World, Write,
|
||||
WriteStorage,
|
||||
shred::ResourceId, Entities, Join, LazyUpdate, Read, ReadExpect, ReadStorage, SystemData,
|
||||
World, Write, WriteStorage,
|
||||
};
|
||||
|
||||
use common::{
|
||||
@ -16,6 +16,7 @@ use common::{
|
||||
self,
|
||||
behavior::{CharacterBehavior, JoinData, JoinStruct},
|
||||
},
|
||||
terrain::TerrainGrid,
|
||||
uid::Uid,
|
||||
};
|
||||
use common_ecs::{Job, Origin, Phase, System};
|
||||
@ -67,6 +68,7 @@ pub struct ReadData<'a> {
|
||||
msm: Read<'a, MaterialStatManifest>,
|
||||
combos: ReadStorage<'a, Combo>,
|
||||
alignments: ReadStorage<'a, comp::Alignment>,
|
||||
terrain: ReadExpect<'a, TerrainGrid>,
|
||||
}
|
||||
|
||||
/// ## Character Behavior System
|
||||
@ -280,6 +282,7 @@ impl<'a> System<'a> for Sys {
|
||||
skill_set: &skill_set,
|
||||
combo: &combo,
|
||||
alignment: read_data.alignments.get(entity),
|
||||
terrain: &read_data.terrain,
|
||||
};
|
||||
|
||||
for action in actions {
|
||||
|
@ -1014,7 +1014,7 @@ fn handle_spawn(
|
||||
pos,
|
||||
comp::Stats::new(get_npc_name(id, npc::BodyType::from_body(body))),
|
||||
comp::SkillSet::default(),
|
||||
comp::Health::new(body, 1),
|
||||
Some(comp::Health::new(body, 1)),
|
||||
comp::Poise::new(body),
|
||||
inventory,
|
||||
body,
|
||||
@ -1116,7 +1116,7 @@ fn handle_spawn_training_dummy(
|
||||
pos,
|
||||
stats,
|
||||
skill_set,
|
||||
health,
|
||||
Some(health),
|
||||
poise,
|
||||
Inventory::new_empty(),
|
||||
body,
|
||||
|
@ -53,7 +53,7 @@ pub fn handle_create_npc(
|
||||
pos: Pos,
|
||||
stats: Stats,
|
||||
skill_set: SkillSet,
|
||||
health: Health,
|
||||
health: Option<Health>,
|
||||
poise: Poise,
|
||||
loadout: Loadout,
|
||||
body: Body,
|
||||
@ -63,6 +63,7 @@ pub fn handle_create_npc(
|
||||
drop_item: Option<Item>,
|
||||
home_chunk: Option<HomeChunk>,
|
||||
rtsim_entity: Option<RtSimEntity>,
|
||||
projectile: Option<Projectile>,
|
||||
) {
|
||||
let inventory = Inventory::new_with_loadout(loadout);
|
||||
|
||||
@ -96,6 +97,12 @@ pub fn handle_create_npc(
|
||||
entity
|
||||
};
|
||||
|
||||
let entity = if let Some(projectile) = projectile {
|
||||
entity.with(projectile)
|
||||
} else {
|
||||
entity
|
||||
};
|
||||
|
||||
let new_entity = entity.build();
|
||||
|
||||
// Add to group system if a pet
|
||||
|
@ -147,6 +147,7 @@ impl Server {
|
||||
home_chunk,
|
||||
drop_item,
|
||||
rtsim_entity,
|
||||
projectile,
|
||||
} => handle_create_npc(
|
||||
self,
|
||||
pos,
|
||||
@ -162,6 +163,7 @@ impl Server {
|
||||
drop_item,
|
||||
home_chunk,
|
||||
rtsim_entity,
|
||||
projectile,
|
||||
),
|
||||
ServerEvent::CreateShip {
|
||||
pos,
|
||||
|
@ -127,7 +127,7 @@ impl<'a> System<'a> for Sys {
|
||||
pos: comp::Pos(spawn_pos),
|
||||
stats: comp::Stats::new(entity.get_name()),
|
||||
skill_set: comp::SkillSet::default(),
|
||||
health: comp::Health::new(body, 10),
|
||||
health: Some(comp::Health::new(body, 10)),
|
||||
loadout: match body {
|
||||
comp::Body::Humanoid(_) => entity.get_loadout(),
|
||||
_ => LoadoutBuilder::new().build(),
|
||||
@ -146,6 +146,7 @@ impl<'a> System<'a> for Sys {
|
||||
drop_item: None,
|
||||
home_chunk: None,
|
||||
rtsim_entity,
|
||||
projectile: None,
|
||||
},
|
||||
};
|
||||
server_emitter.emit(event);
|
||||
|
@ -39,7 +39,7 @@ pub trait StateExt {
|
||||
pos: comp::Pos,
|
||||
stats: comp::Stats,
|
||||
skill_set: comp::SkillSet,
|
||||
health: comp::Health,
|
||||
health: Option<comp::Health>,
|
||||
poise: comp::Poise,
|
||||
inventory: comp::Inventory,
|
||||
body: comp::Body,
|
||||
@ -175,7 +175,7 @@ impl StateExt for State {
|
||||
pos: comp::Pos,
|
||||
stats: comp::Stats,
|
||||
skill_set: comp::SkillSet,
|
||||
health: comp::Health,
|
||||
health: Option<comp::Health>,
|
||||
poise: comp::Poise,
|
||||
inventory: comp::Inventory,
|
||||
body: comp::Body,
|
||||
@ -215,7 +215,7 @@ impl StateExt for State {
|
||||
))
|
||||
.with(stats)
|
||||
.with(skill_set)
|
||||
.with(health)
|
||||
.maybe_with(health)
|
||||
.with(poise)
|
||||
.with(comp::Alignment::Npc)
|
||||
.with(comp::CharacterState::default())
|
||||
|
@ -239,7 +239,7 @@ impl<'a> System<'a> for Sys {
|
||||
loadout_builder.build()
|
||||
};
|
||||
|
||||
let health = comp::Health::new(body, entity.level.unwrap_or(0));
|
||||
let health = Some(comp::Health::new(body, entity.level.unwrap_or(0)));
|
||||
let poise = comp::Poise::new(body);
|
||||
|
||||
let can_speak = match body {
|
||||
@ -293,6 +293,7 @@ impl<'a> System<'a> for Sys {
|
||||
home_chunk: Some(comp::HomeChunk(key)),
|
||||
drop_item: entity.loot_drop,
|
||||
rtsim_entity: None,
|
||||
projectile: None,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -209,7 +209,7 @@ impl<'a> From<&'a Body> for SkeletonAttr {
|
||||
feed: match (body.species, body.body_type) {
|
||||
(Phoenix, _) => (-0.65),
|
||||
(Cockatrice, _) => (-0.5),
|
||||
(Roc, _) => (-0.65),
|
||||
(Roc, _) => (-0.4),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user