mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'sam/ron-abilities' into 'master'
Move abilities to .ron files Closes #821 See merge request veloren/veloren!1508
This commit is contained in:
commit
1ed90bd0bf
36
assets/common/abilities/axe/doublestrike.ron
Normal file
36
assets/common/abilities/axe/doublestrike.ron
Normal file
@ -0,0 +1,36 @@
|
||||
ComboMelee(
|
||||
stage_data: [
|
||||
(
|
||||
stage: 1,
|
||||
base_damage: 90,
|
||||
max_damage: 110,
|
||||
damage_increase: 10,
|
||||
knockback: 8.0,
|
||||
range: 3.5,
|
||||
angle: 50.0,
|
||||
base_buildup_duration: 350,
|
||||
base_swing_duration: 75,
|
||||
base_recover_duration: 400,
|
||||
forward_movement: 0.5,
|
||||
),
|
||||
(
|
||||
stage: 2,
|
||||
base_damage: 130,
|
||||
max_damage: 160,
|
||||
damage_increase: 15,
|
||||
knockback: 12.0,
|
||||
range: 3.5,
|
||||
angle: 30.0,
|
||||
base_buildup_duration: 500,
|
||||
base_swing_duration: 100,
|
||||
base_recover_duration: 500,
|
||||
forward_movement: 0.25,
|
||||
),
|
||||
],
|
||||
initial_energy_gain: 0,
|
||||
max_energy_gain: 100,
|
||||
energy_increase: 20,
|
||||
speed_increase: 0.05,
|
||||
max_speed_increase: 1.6,
|
||||
is_interruptible: false,
|
||||
)
|
13
assets/common/abilities/axe/leap.ron
Normal file
13
assets/common/abilities/axe/leap.ron
Normal file
@ -0,0 +1,13 @@
|
||||
LeapMelee(
|
||||
energy_cost: 450,
|
||||
buildup_duration: 200,
|
||||
movement_duration: 200,
|
||||
swing_duration: 200,
|
||||
recover_duration: 200,
|
||||
base_damage: 240,
|
||||
knockback: 12.0,
|
||||
range: 4.5,
|
||||
max_angle: 30.0,
|
||||
forward_leap_strength: 28.0,
|
||||
vertical_leap_strength: 8.0,
|
||||
)
|
14
assets/common/abilities/axe/spin.ron
Normal file
14
assets/common/abilities/axe/spin.ron
Normal file
@ -0,0 +1,14 @@
|
||||
SpinMelee(
|
||||
buildup_duration: 100,
|
||||
swing_duration: 250,
|
||||
recover_duration: 100,
|
||||
base_damage: 60,
|
||||
knockback: 0.0,
|
||||
range: 3.5,
|
||||
energy_cost: 100,
|
||||
is_infinite: true,
|
||||
is_helicopter: true,
|
||||
is_interruptible: false,
|
||||
forward_speed: 0.0,
|
||||
num_spins: 1,
|
||||
)
|
15
assets/common/abilities/bow/basic.ron
Normal file
15
assets/common/abilities/bow/basic.ron
Normal file
@ -0,0 +1,15 @@
|
||||
BasicRanged(
|
||||
energy_cost: 0,
|
||||
buildup_duration: 200,
|
||||
recover_duration: 300,
|
||||
projectile: Arrow(
|
||||
damage: 40.0,
|
||||
knockback: 10.0,
|
||||
energy_regen: 50,
|
||||
),
|
||||
projectile_body: Object(Arrow),
|
||||
projectile_light: None,
|
||||
projectile_gravity: Some(Gravity(0.2)),
|
||||
projectile_speed: 100.0,
|
||||
can_continue: true,
|
||||
)
|
17
assets/common/abilities/bow/charged.ron
Normal file
17
assets/common/abilities/bow/charged.ron
Normal file
@ -0,0 +1,17 @@
|
||||
ChargedRanged(
|
||||
energy_cost: 0,
|
||||
energy_drain: 300,
|
||||
initial_damage: 40,
|
||||
max_damage: 200,
|
||||
initial_knockback: 10.0,
|
||||
max_knockback: 20.0,
|
||||
speed: 1.0,
|
||||
buildup_duration: 100,
|
||||
charge_duration: 1500,
|
||||
recover_duration: 500,
|
||||
projectile_body: Object(MultiArrow),
|
||||
projectile_light: None,
|
||||
projectile_gravity: Some(Gravity(0.2)),
|
||||
initial_projectile_speed: 100.0,
|
||||
max_projectile_speed: 500.0,
|
||||
)
|
18
assets/common/abilities/bow/repeater.ron
Normal file
18
assets/common/abilities/bow/repeater.ron
Normal file
@ -0,0 +1,18 @@
|
||||
RepeaterRanged(
|
||||
energy_cost: 450,
|
||||
movement_duration: 300,
|
||||
buildup_duration: 200,
|
||||
shoot_duration: 200,
|
||||
recover_duration: 800,
|
||||
leap: Some(5.0),
|
||||
projectile: Arrow(
|
||||
damage: 40.0,
|
||||
knockback: 10.0,
|
||||
energy_regen: 0,
|
||||
),
|
||||
projectile_body: Object(Arrow),
|
||||
projectile_light: None,
|
||||
projectile_gravity: Some(Gravity(0.2)),
|
||||
projectile_speed: 100.0,
|
||||
reps_remaining: 5,
|
||||
)
|
10
assets/common/abilities/dagger/tempbasic.ron
Normal file
10
assets/common/abilities/dagger/tempbasic.ron
Normal file
@ -0,0 +1,10 @@
|
||||
BasicMelee(
|
||||
energy_cost: 0,
|
||||
buildup_duration: 100,
|
||||
swing_duration: 100,
|
||||
recover_duration: 300,
|
||||
base_damage: 50,
|
||||
knockback: 0.0,
|
||||
range: 3.5,
|
||||
max_angle: 20.0,
|
||||
)
|
4
assets/common/abilities/debug/forwardboost.ron
Normal file
4
assets/common/abilities/debug/forwardboost.ron
Normal file
@ -0,0 +1,4 @@
|
||||
Boost(
|
||||
movement_duration: 50,
|
||||
only_up: false,
|
||||
)
|
14
assets/common/abilities/debug/possess.ron
Normal file
14
assets/common/abilities/debug/possess.ron
Normal file
@ -0,0 +1,14 @@
|
||||
BasicRanged(
|
||||
energy_cost: 0,
|
||||
buildup_duration: 0,
|
||||
recover_duration: 10,
|
||||
projectile: Possess,
|
||||
projectile_body: Object(ArrowSnake),
|
||||
/*projectile_light: Some(LightEmitter {
|
||||
col: (0.0, 1.0, 0.33).into(),
|
||||
..Default::default()
|
||||
}),*/
|
||||
projectile_gravity: None,
|
||||
projectile_speed: 100.0,
|
||||
can_continue: false,
|
||||
)
|
4
assets/common/abilities/debug/upboost.ron
Normal file
4
assets/common/abilities/debug/upboost.ron
Normal file
@ -0,0 +1,4 @@
|
||||
Boost(
|
||||
movement_duration: 50,
|
||||
only_up: true,
|
||||
)
|
10
assets/common/abilities/empty/basic.ron
Normal file
10
assets/common/abilities/empty/basic.ron
Normal file
@ -0,0 +1,10 @@
|
||||
BasicMelee(
|
||||
energy_cost: 0,
|
||||
buildup_duration: 0,
|
||||
swing_duration: 100,
|
||||
recover_duration: 900,
|
||||
base_damage: 20,
|
||||
knockback: 0.0,
|
||||
range: 3.5,
|
||||
max_angle: 15.0,
|
||||
)
|
10
assets/common/abilities/farming/basic.ron
Normal file
10
assets/common/abilities/farming/basic.ron
Normal file
@ -0,0 +1,10 @@
|
||||
BasicMelee(
|
||||
energy_cost: 0,
|
||||
buildup_duration: 600,
|
||||
swing_duration: 100,
|
||||
recover_duration: 150,
|
||||
base_damage: 50,
|
||||
knockback: 0.0,
|
||||
range: 3.5,
|
||||
max_angle: 20.0,
|
||||
)
|
14
assets/common/abilities/hammer/charged.ron
Normal file
14
assets/common/abilities/hammer/charged.ron
Normal file
@ -0,0 +1,14 @@
|
||||
ChargedMelee(
|
||||
energy_cost: 0,
|
||||
energy_drain: 300,
|
||||
initial_damage: 10,
|
||||
max_damage: 170,
|
||||
initial_knockback: 10.0,
|
||||
max_knockback: 60.0,
|
||||
range: 3.5,
|
||||
max_angle: 30.0,
|
||||
speed: 1.0,
|
||||
charge_duration: 1200,
|
||||
swing_duration: 200,
|
||||
recover_duration: 300,
|
||||
)
|
13
assets/common/abilities/hammer/leap.ron
Normal file
13
assets/common/abilities/hammer/leap.ron
Normal file
@ -0,0 +1,13 @@
|
||||
LeapMelee(
|
||||
energy_cost: 700,
|
||||
buildup_duration: 100,
|
||||
movement_duration: 800,
|
||||
swing_duration: 150,
|
||||
recover_duration: 200,
|
||||
base_damage: 240,
|
||||
knockback: 25.0,
|
||||
range: 4.5,
|
||||
max_angle: 360.0,
|
||||
forward_leap_strength: 28.0,
|
||||
vertical_leap_strength: 8.0,
|
||||
)
|
21
assets/common/abilities/hammer/singlestrike.ron
Normal file
21
assets/common/abilities/hammer/singlestrike.ron
Normal file
@ -0,0 +1,21 @@
|
||||
ComboMelee(
|
||||
stage_data: [(
|
||||
stage: 1,
|
||||
base_damage: 120,
|
||||
max_damage: 150,
|
||||
damage_increase: 10,
|
||||
knockback: 0.0,
|
||||
range: 3.5,
|
||||
angle: 20.0,
|
||||
base_buildup_duration: 600,
|
||||
base_swing_duration: 60,
|
||||
base_recover_duration: 300,
|
||||
forward_movement: 0.0,
|
||||
)],
|
||||
initial_energy_gain: 0,
|
||||
max_energy_gain: 100,
|
||||
energy_increase: 20,
|
||||
speed_increase: 0.05,
|
||||
max_speed_increase: 1.4,
|
||||
is_interruptible: false,
|
||||
)
|
14
assets/common/abilities/sceptre/healingbeam.ron
Normal file
14
assets/common/abilities/sceptre/healingbeam.ron
Normal file
@ -0,0 +1,14 @@
|
||||
BasicBeam(
|
||||
buildup_duration: 250,
|
||||
recover_duration: 250,
|
||||
beam_duration: 1000,
|
||||
base_hps: 60,
|
||||
base_dps: 60,
|
||||
tick_rate: 2.0,
|
||||
range: 25.0,
|
||||
max_angle: 1.0,
|
||||
lifesteal_eff: 0.20,
|
||||
energy_regen: 50,
|
||||
energy_cost: 100,
|
||||
energy_drain: 0,
|
||||
)
|
18
assets/common/abilities/sceptre/healingbomb.ron
Normal file
18
assets/common/abilities/sceptre/healingbomb.ron
Normal file
@ -0,0 +1,18 @@
|
||||
BasicRanged(
|
||||
energy_cost: 800,
|
||||
buildup_duration: 800,
|
||||
recover_duration: 50,
|
||||
projectile: Heal(
|
||||
heal: 140.0,
|
||||
damage: 50.0,
|
||||
radius: 6.0,
|
||||
),
|
||||
projectile_body: Object(BoltNature),
|
||||
/*projectile_light: Some(LightEmitter {
|
||||
col: (0.0, 1.0, 0.0).into(),
|
||||
..Default::default()
|
||||
}),*/
|
||||
projectile_gravity: Some(Gravity(0.5)),
|
||||
projectile_speed: 40.0,
|
||||
can_continue: false,
|
||||
)
|
1
assets/common/abilities/shield/block.ron
Normal file
1
assets/common/abilities/shield/block.ron
Normal file
@ -0,0 +1 @@
|
||||
BasicBlock
|
10
assets/common/abilities/shield/tempbasic.ron
Normal file
10
assets/common/abilities/shield/tempbasic.ron
Normal file
@ -0,0 +1,10 @@
|
||||
BasicMelee(
|
||||
energy_cost: 0,
|
||||
buildup_duration: 100,
|
||||
swing_duration: 100,
|
||||
recover_duration: 300,
|
||||
base_damage: 40,
|
||||
knockback: 0.0,
|
||||
range: 3.0,
|
||||
max_angle: 120.0,
|
||||
)
|
18
assets/common/abilities/staff/firebomb.ron
Normal file
18
assets/common/abilities/staff/firebomb.ron
Normal file
@ -0,0 +1,18 @@
|
||||
BasicRanged(
|
||||
energy_cost: 0,
|
||||
buildup_duration: 500,
|
||||
recover_duration: 350,
|
||||
projectile: Fireball(
|
||||
damage: 100.0,
|
||||
radius: 5.0,
|
||||
energy_regen: 50,
|
||||
),
|
||||
projectile_body: Object(BoltFire),
|
||||
/*projectile_light: Some(LightEmitter {
|
||||
col: (1.0, 0.75, 0.11).into(),
|
||||
..Default::default()
|
||||
}),*/
|
||||
projectile_gravity: Some(Gravity(0.3)),
|
||||
projectile_speed: 60.0,
|
||||
can_continue: true,
|
||||
)
|
14
assets/common/abilities/staff/fireshockwave.ron
Normal file
14
assets/common/abilities/staff/fireshockwave.ron
Normal file
@ -0,0 +1,14 @@
|
||||
Shockwave(
|
||||
energy_cost: 600,
|
||||
buildup_duration: 700,
|
||||
swing_duration: 100,
|
||||
recover_duration: 300,
|
||||
damage: 200,
|
||||
knockback: Away(25.0),
|
||||
shockwave_angle: 360.0,
|
||||
shockwave_vertical_angle: 90.0,
|
||||
shockwave_speed: 20.0,
|
||||
shockwave_duration: 500,
|
||||
requires_ground: false,
|
||||
move_efficiency: 0.1,
|
||||
)
|
14
assets/common/abilities/staff/flamethrower.ron
Normal file
14
assets/common/abilities/staff/flamethrower.ron
Normal file
@ -0,0 +1,14 @@
|
||||
BasicBeam(
|
||||
buildup_duration: 250,
|
||||
recover_duration: 250,
|
||||
beam_duration: 500,
|
||||
base_hps: 0,
|
||||
base_dps: 150,
|
||||
tick_rate: 3.0,
|
||||
range: 15.0,
|
||||
max_angle: 22.5,
|
||||
lifesteal_eff: 0.0,
|
||||
energy_regen: 0,
|
||||
energy_cost: 0,
|
||||
energy_drain: 350,
|
||||
)
|
17
assets/common/abilities/sword/dash.ron
Normal file
17
assets/common/abilities/sword/dash.ron
Normal file
@ -0,0 +1,17 @@
|
||||
DashMelee(
|
||||
energy_cost: 200,
|
||||
base_damage: 120,
|
||||
max_damage: 240,
|
||||
base_knockback: 8.0,
|
||||
max_knockback: 15.0,
|
||||
range: 5.0,
|
||||
angle: 45.0,
|
||||
energy_drain: 500,
|
||||
forward_speed: 4.0,
|
||||
buildup_duration: 250,
|
||||
charge_duration: 600,
|
||||
swing_duration: 100,
|
||||
recover_duration: 500,
|
||||
infinite_charge: true,
|
||||
is_interruptible: true,
|
||||
)
|
14
assets/common/abilities/sword/spin.ron
Normal file
14
assets/common/abilities/sword/spin.ron
Normal file
@ -0,0 +1,14 @@
|
||||
SpinMelee(
|
||||
buildup_duration: 750,
|
||||
swing_duration: 500,
|
||||
recover_duration: 500,
|
||||
base_damage: 140,
|
||||
knockback: 10.0,
|
||||
range: 3.5,
|
||||
energy_cost: 200,
|
||||
is_infinite: false,
|
||||
is_helicopter: false,
|
||||
is_interruptible: true,
|
||||
forward_speed: 1.0,
|
||||
num_spins: 3,
|
||||
)
|
49
assets/common/abilities/sword/triplestrike.ron
Normal file
49
assets/common/abilities/sword/triplestrike.ron
Normal file
@ -0,0 +1,49 @@
|
||||
ComboMelee(
|
||||
stage_data: [
|
||||
(
|
||||
stage: 1,
|
||||
base_damage: 100,
|
||||
max_damage: 120,
|
||||
damage_increase: 10,
|
||||
knockback: 10.0,
|
||||
range: 4.0,
|
||||
angle: 30.0,
|
||||
base_buildup_duration: 350,
|
||||
base_swing_duration: 100,
|
||||
base_recover_duration: 400,
|
||||
forward_movement: 0.5,
|
||||
),
|
||||
(
|
||||
stage: 2,
|
||||
base_damage: 80,
|
||||
max_damage: 110,
|
||||
damage_increase: 15,
|
||||
knockback: 12.0,
|
||||
range: 3.5,
|
||||
angle: 180.0,
|
||||
base_buildup_duration: 400,
|
||||
base_swing_duration: 600,
|
||||
base_recover_duration: 400,
|
||||
forward_movement: 0.0,
|
||||
),
|
||||
(
|
||||
stage: 3,
|
||||
base_damage: 130,
|
||||
max_damage: 170,
|
||||
damage_increase: 20,
|
||||
knockback: 14.0,
|
||||
range: 6.0,
|
||||
angle: 10.0,
|
||||
base_buildup_duration: 500,
|
||||
base_swing_duration: 200,
|
||||
base_recover_duration: 300,
|
||||
forward_movement: 1.2,
|
||||
),
|
||||
],
|
||||
initial_energy_gain: 0,
|
||||
max_energy_gain: 100,
|
||||
energy_increase: 20,
|
||||
speed_increase: 0.05,
|
||||
max_speed_increase: 1.8,
|
||||
is_interruptible: true,
|
||||
)
|
10
assets/common/abilities/unique/beastclaws/basic.ron
Normal file
10
assets/common/abilities/unique/beastclaws/basic.ron
Normal file
@ -0,0 +1,10 @@
|
||||
BasicMelee(
|
||||
energy_cost: 0,
|
||||
buildup_duration: 250,
|
||||
swing_duration: 250,
|
||||
recover_duration: 250,
|
||||
knockback: 25.0,
|
||||
base_damage: 200,
|
||||
range: 5.0,
|
||||
max_angle: 120.0,
|
||||
)
|
10
assets/common/abilities/unique/stonegolemfist/basic.ron
Normal file
10
assets/common/abilities/unique/stonegolemfist/basic.ron
Normal file
@ -0,0 +1,10 @@
|
||||
BasicMelee(
|
||||
energy_cost: 0,
|
||||
buildup_duration: 400,
|
||||
swing_duration: 100,
|
||||
recover_duration: 250,
|
||||
knockback: 25.0,
|
||||
base_damage: 200,
|
||||
range: 5.0,
|
||||
max_angle: 120.0,
|
||||
)
|
14
assets/common/abilities/unique/stonegolemfist/shockwave.ron
Normal file
14
assets/common/abilities/unique/stonegolemfist/shockwave.ron
Normal file
@ -0,0 +1,14 @@
|
||||
Shockwave(
|
||||
energy_cost: 0,
|
||||
buildup_duration: 500,
|
||||
swing_duration: 200,
|
||||
recover_duration: 800,
|
||||
damage: 500,
|
||||
knockback: TowardsUp(40.0),
|
||||
shockwave_angle: 90.0,
|
||||
shockwave_vertical_angle: 15.0,
|
||||
shockwave_speed: 20.0,
|
||||
shockwave_duration: 2000,
|
||||
requires_ground: true,
|
||||
move_efficiency: 0.05,
|
||||
)
|
81
assets/common/abilities/weapon_ability_manifest.ron
Normal file
81
assets/common/abilities/weapon_ability_manifest.ron
Normal file
@ -0,0 +1,81 @@
|
||||
// Maps a tool kind to a set of abilities
|
||||
// A set of abilities is a primary, a secondary, and a vec of all extra abilities
|
||||
({
|
||||
Sword: (
|
||||
primary: "common.abilities.sword.triplestrike",
|
||||
secondary: "common.abilities.sword.dash",
|
||||
skills: [
|
||||
"common.abilities.sword.spin",
|
||||
],
|
||||
),
|
||||
Axe: (
|
||||
primary: "common.abilities.axe.doublestrike",
|
||||
secondary: "common.abilities.axe.spin",
|
||||
skills: [
|
||||
"common.abilities.axe.leap",
|
||||
],
|
||||
),
|
||||
Hammer: (
|
||||
primary: "common.abilities.hammer.singlestrike",
|
||||
secondary: "common.abilities.hammer.charged",
|
||||
skills: [
|
||||
"common.abilities.hammer.leap",
|
||||
],
|
||||
),
|
||||
Bow: (
|
||||
primary: "common.abilities.bow.basic",
|
||||
secondary: "common.abilities.bow.charged",
|
||||
skills: [
|
||||
"common.abilities.bow.repeater",
|
||||
],
|
||||
),
|
||||
Staff: (
|
||||
primary: "common.abilities.staff.firebomb",
|
||||
secondary: "common.abilities.staff.flamethrower",
|
||||
skills: [
|
||||
"common.abilities.staff.fireshockwave",
|
||||
],
|
||||
),
|
||||
Sceptre: (
|
||||
primary: "common.abilities.sceptre.healingbeam",
|
||||
secondary: "common.abilities.sceptre.healingbomb",
|
||||
skills: [],
|
||||
),
|
||||
Dagger: (
|
||||
primary: "common.abilities.dagger.tempbasic",
|
||||
secondary: "common.abilities.dagger.tempbasic",
|
||||
skills: [],
|
||||
),
|
||||
Shield: (
|
||||
primary: "common.abilities.shield.tempbasic",
|
||||
secondary: "common.abilities.shield.block",
|
||||
skills: [],
|
||||
),
|
||||
Unique(StoneGolemFist): (
|
||||
primary: "common.abilities.unique.stonegolemfist.basic",
|
||||
secondary: "common.abilities.unique.stonegolemfist.shockwave",
|
||||
skills: [],
|
||||
),
|
||||
Unique(BeastClaws): (
|
||||
primary: "common.abilities.unique.beastclaws.basic",
|
||||
secondary: "common.abilities.unique.beastclaws.basic",
|
||||
skills: [],
|
||||
),
|
||||
Debug: (
|
||||
primary: "common.abilities.debug.forwardboost",
|
||||
secondary: "common.abilities.debug.upboost",
|
||||
skills: [
|
||||
"common.abilities.debug.possess",
|
||||
],
|
||||
),
|
||||
Farming: (
|
||||
primary: "common.abilities.farming.basic",
|
||||
secondary: "common.abilities.farming.basic",
|
||||
skills: [],
|
||||
),
|
||||
Empty: (
|
||||
primary: "common.abilities.empty.basic",
|
||||
secondary: "common.abilities.empty.basic",
|
||||
skills: [],
|
||||
),
|
||||
})
|
@ -1,7 +1,9 @@
|
||||
use crate::{
|
||||
assets::{self, Asset},
|
||||
comp::{
|
||||
item::{armor::Protection, Item, ItemKind},
|
||||
Body, CharacterState, EnergySource, Gravity, LightEmitter, Projectile, StateUpdate,
|
||||
item::{armor::Protection, tool::AbilityMap, Item, ItemKind},
|
||||
projectile::ProjectileConstructor,
|
||||
Body, CharacterState, EnergySource, Gravity, LightEmitter, StateUpdate,
|
||||
},
|
||||
states::{
|
||||
utils::{AbilityKey, StageSection},
|
||||
@ -14,7 +16,7 @@ use arraygen::Arraygen;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specs::{Component, FlaggedStorage};
|
||||
use specs_idvs::IdvStorage;
|
||||
use std::time::Duration;
|
||||
use std::{fs::File, io::BufReader, time::Duration};
|
||||
use vek::Vec3;
|
||||
|
||||
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug, Serialize, Deserialize)]
|
||||
@ -59,9 +61,9 @@ impl From<&CharacterState> for CharacterAbilityType {
|
||||
pub enum CharacterAbility {
|
||||
BasicMelee {
|
||||
energy_cost: u32,
|
||||
buildup_duration: Duration,
|
||||
swing_duration: Duration,
|
||||
recover_duration: Duration,
|
||||
buildup_duration: u64,
|
||||
swing_duration: u64,
|
||||
recover_duration: u64,
|
||||
base_damage: u32,
|
||||
knockback: f32,
|
||||
range: f32,
|
||||
@ -69,9 +71,9 @@ pub enum CharacterAbility {
|
||||
},
|
||||
BasicRanged {
|
||||
energy_cost: u32,
|
||||
buildup_duration: Duration,
|
||||
recover_duration: Duration,
|
||||
projectile: Projectile,
|
||||
buildup_duration: u64,
|
||||
recover_duration: u64,
|
||||
projectile: ProjectileConstructor,
|
||||
projectile_body: Body,
|
||||
projectile_light: Option<LightEmitter>,
|
||||
projectile_gravity: Option<Gravity>,
|
||||
@ -80,12 +82,12 @@ pub enum CharacterAbility {
|
||||
},
|
||||
RepeaterRanged {
|
||||
energy_cost: u32,
|
||||
movement_duration: Duration,
|
||||
buildup_duration: Duration,
|
||||
shoot_duration: Duration,
|
||||
recover_duration: Duration,
|
||||
movement_duration: u64,
|
||||
buildup_duration: u64,
|
||||
shoot_duration: u64,
|
||||
recover_duration: u64,
|
||||
leap: Option<f32>,
|
||||
projectile: Projectile,
|
||||
projectile: ProjectileConstructor,
|
||||
projectile_body: Body,
|
||||
projectile_light: Option<LightEmitter>,
|
||||
projectile_gravity: Option<Gravity>,
|
||||
@ -93,7 +95,7 @@ pub enum CharacterAbility {
|
||||
reps_remaining: u32,
|
||||
},
|
||||
Boost {
|
||||
movement_duration: Duration,
|
||||
movement_duration: u64,
|
||||
only_up: bool,
|
||||
},
|
||||
DashMelee {
|
||||
@ -106,23 +108,23 @@ pub enum CharacterAbility {
|
||||
angle: f32,
|
||||
energy_drain: u32,
|
||||
forward_speed: f32,
|
||||
buildup_duration: Duration,
|
||||
charge_duration: Duration,
|
||||
swing_duration: Duration,
|
||||
recover_duration: Duration,
|
||||
buildup_duration: u64,
|
||||
charge_duration: u64,
|
||||
swing_duration: u64,
|
||||
recover_duration: u64,
|
||||
infinite_charge: bool,
|
||||
is_interruptible: bool,
|
||||
},
|
||||
BasicBlock,
|
||||
Roll {
|
||||
energy_cost: u32,
|
||||
buildup_duration: Duration,
|
||||
movement_duration: Duration,
|
||||
recover_duration: Duration,
|
||||
buildup_duration: u64,
|
||||
movement_duration: u64,
|
||||
recover_duration: u64,
|
||||
roll_strength: f32,
|
||||
},
|
||||
ComboMelee {
|
||||
stage_data: Vec<combo_melee::Stage>,
|
||||
stage_data: Vec<combo_melee::Stage<u64>>,
|
||||
initial_energy_gain: u32,
|
||||
max_energy_gain: u32,
|
||||
energy_increase: u32,
|
||||
@ -132,10 +134,10 @@ pub enum CharacterAbility {
|
||||
},
|
||||
LeapMelee {
|
||||
energy_cost: u32,
|
||||
buildup_duration: Duration,
|
||||
movement_duration: Duration,
|
||||
swing_duration: Duration,
|
||||
recover_duration: Duration,
|
||||
buildup_duration: u64,
|
||||
movement_duration: u64,
|
||||
swing_duration: u64,
|
||||
recover_duration: u64,
|
||||
base_damage: u32,
|
||||
range: f32,
|
||||
max_angle: f32,
|
||||
@ -144,9 +146,9 @@ pub enum CharacterAbility {
|
||||
vertical_leap_strength: f32,
|
||||
},
|
||||
SpinMelee {
|
||||
buildup_duration: Duration,
|
||||
swing_duration: Duration,
|
||||
recover_duration: Duration,
|
||||
buildup_duration: u64,
|
||||
swing_duration: u64,
|
||||
recover_duration: u64,
|
||||
base_damage: u32,
|
||||
knockback: f32,
|
||||
range: f32,
|
||||
@ -167,9 +169,9 @@ pub enum CharacterAbility {
|
||||
range: f32,
|
||||
max_angle: f32,
|
||||
speed: f32,
|
||||
charge_duration: Duration,
|
||||
swing_duration: Duration,
|
||||
recover_duration: Duration,
|
||||
charge_duration: u64,
|
||||
swing_duration: u64,
|
||||
recover_duration: u64,
|
||||
},
|
||||
ChargedRanged {
|
||||
energy_cost: u32,
|
||||
@ -179,9 +181,9 @@ pub enum CharacterAbility {
|
||||
initial_knockback: f32,
|
||||
max_knockback: f32,
|
||||
speed: f32,
|
||||
buildup_duration: Duration,
|
||||
charge_duration: Duration,
|
||||
recover_duration: Duration,
|
||||
buildup_duration: u64,
|
||||
charge_duration: u64,
|
||||
recover_duration: u64,
|
||||
projectile_body: Body,
|
||||
projectile_light: Option<LightEmitter>,
|
||||
projectile_gravity: Option<Gravity>,
|
||||
@ -190,22 +192,22 @@ pub enum CharacterAbility {
|
||||
},
|
||||
Shockwave {
|
||||
energy_cost: u32,
|
||||
buildup_duration: Duration,
|
||||
swing_duration: Duration,
|
||||
recover_duration: Duration,
|
||||
buildup_duration: u64,
|
||||
swing_duration: u64,
|
||||
recover_duration: u64,
|
||||
damage: u32,
|
||||
knockback: Knockback,
|
||||
shockwave_angle: f32,
|
||||
shockwave_vertical_angle: f32,
|
||||
shockwave_speed: f32,
|
||||
shockwave_duration: Duration,
|
||||
shockwave_duration: u64,
|
||||
requires_ground: bool,
|
||||
move_efficiency: f32,
|
||||
},
|
||||
BasicBeam {
|
||||
buildup_duration: Duration,
|
||||
recover_duration: Duration,
|
||||
beam_duration: Duration,
|
||||
buildup_duration: u64,
|
||||
recover_duration: u64,
|
||||
beam_duration: u64,
|
||||
base_hps: u32,
|
||||
base_dps: u32,
|
||||
tick_rate: f32,
|
||||
@ -218,6 +220,29 @@ pub enum CharacterAbility {
|
||||
},
|
||||
}
|
||||
|
||||
impl Default for CharacterAbility {
|
||||
fn default() -> Self {
|
||||
CharacterAbility::BasicMelee {
|
||||
energy_cost: 0,
|
||||
buildup_duration: 250,
|
||||
swing_duration: 250,
|
||||
recover_duration: 500,
|
||||
base_damage: 10,
|
||||
knockback: 0.0,
|
||||
range: 3.5,
|
||||
max_angle: 15.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Asset for CharacterAbility {
|
||||
const ENDINGS: &'static [&'static str] = &["ron"];
|
||||
|
||||
fn parse(buf_reader: BufReader<File>, _specifier: &str) -> Result<Self, assets::Error> {
|
||||
ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error)
|
||||
}
|
||||
}
|
||||
|
||||
impl CharacterAbility {
|
||||
/// Attempts to fulfill requirements, mutating `update` (taking energy) if
|
||||
/// applicable.
|
||||
@ -282,12 +307,178 @@ impl CharacterAbility {
|
||||
fn default_roll() -> CharacterAbility {
|
||||
CharacterAbility::Roll {
|
||||
energy_cost: 100,
|
||||
buildup_duration: Duration::from_millis(100),
|
||||
movement_duration: Duration::from_millis(250),
|
||||
recover_duration: Duration::from_millis(150),
|
||||
buildup_duration: 100,
|
||||
movement_duration: 250,
|
||||
recover_duration: 150,
|
||||
roll_strength: 2.5,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn adjusted_by_stats(mut self, power: f32, speed: f32) -> Self {
|
||||
use CharacterAbility::*;
|
||||
match self {
|
||||
BasicMelee {
|
||||
ref mut buildup_duration,
|
||||
ref mut swing_duration,
|
||||
ref mut recover_duration,
|
||||
ref mut base_damage,
|
||||
..
|
||||
} => {
|
||||
*buildup_duration = (*buildup_duration as f32 / speed) as u64;
|
||||
*swing_duration = (*swing_duration as f32 / speed) as u64;
|
||||
*recover_duration = (*recover_duration as f32 / speed) as u64;
|
||||
*base_damage = (*base_damage as f32 * power) as u32;
|
||||
},
|
||||
BasicRanged {
|
||||
ref mut buildup_duration,
|
||||
ref mut recover_duration,
|
||||
ref mut projectile,
|
||||
..
|
||||
} => {
|
||||
*buildup_duration = (*buildup_duration as f32 / speed) as u64;
|
||||
*recover_duration = (*recover_duration as f32 / speed) as u64;
|
||||
*projectile = projectile.modified_projectile(power);
|
||||
},
|
||||
RepeaterRanged {
|
||||
ref mut movement_duration,
|
||||
ref mut buildup_duration,
|
||||
ref mut shoot_duration,
|
||||
ref mut recover_duration,
|
||||
ref mut projectile,
|
||||
..
|
||||
} => {
|
||||
*movement_duration = (*movement_duration as f32 / speed) as u64;
|
||||
*buildup_duration = (*buildup_duration as f32 / speed) as u64;
|
||||
*shoot_duration = (*shoot_duration as f32 / speed) as u64;
|
||||
*recover_duration = (*recover_duration as f32 / speed) as u64;
|
||||
*projectile = projectile.modified_projectile(power);
|
||||
},
|
||||
Boost {
|
||||
ref mut movement_duration,
|
||||
..
|
||||
} => {
|
||||
*movement_duration = (*movement_duration as f32 / speed) as u64;
|
||||
},
|
||||
DashMelee {
|
||||
ref mut base_damage,
|
||||
ref mut max_damage,
|
||||
ref mut buildup_duration,
|
||||
ref mut swing_duration,
|
||||
ref mut recover_duration,
|
||||
..
|
||||
} => {
|
||||
*base_damage = (*base_damage as f32 * power) as u32;
|
||||
*max_damage = (*max_damage as f32 * power) as u32;
|
||||
*buildup_duration = (*buildup_duration as f32 / speed) as u64;
|
||||
*swing_duration = (*swing_duration as f32 / speed) as u64;
|
||||
*recover_duration = (*recover_duration as f32 / speed) as u64;
|
||||
},
|
||||
BasicBlock => {},
|
||||
Roll {
|
||||
ref mut buildup_duration,
|
||||
ref mut movement_duration,
|
||||
ref mut recover_duration,
|
||||
..
|
||||
} => {
|
||||
*buildup_duration = (*buildup_duration as f32 / speed) as u64;
|
||||
*movement_duration = (*movement_duration as f32 / speed) as u64;
|
||||
*recover_duration = (*recover_duration as f32 / speed) as u64;
|
||||
},
|
||||
ComboMelee {
|
||||
ref mut stage_data, ..
|
||||
} => {
|
||||
*stage_data = stage_data
|
||||
.iter_mut()
|
||||
.map(|s| s.adjusted_by_stats(power, speed))
|
||||
.collect();
|
||||
},
|
||||
LeapMelee {
|
||||
ref mut buildup_duration,
|
||||
ref mut movement_duration,
|
||||
ref mut swing_duration,
|
||||
ref mut recover_duration,
|
||||
ref mut base_damage,
|
||||
..
|
||||
} => {
|
||||
*buildup_duration = (*buildup_duration as f32 / speed) as u64;
|
||||
*movement_duration = (*movement_duration as f32 / speed) as u64;
|
||||
*swing_duration = (*swing_duration as f32 / speed) as u64;
|
||||
*recover_duration = (*recover_duration as f32 / speed) as u64;
|
||||
*base_damage = (*base_damage as f32 * power) as u32;
|
||||
},
|
||||
SpinMelee {
|
||||
ref mut buildup_duration,
|
||||
ref mut swing_duration,
|
||||
ref mut recover_duration,
|
||||
ref mut base_damage,
|
||||
..
|
||||
} => {
|
||||
*buildup_duration = (*buildup_duration as f32 / speed) as u64;
|
||||
*swing_duration = (*swing_duration as f32 / speed) as u64;
|
||||
*recover_duration = (*recover_duration as f32 / speed) as u64;
|
||||
*base_damage = (*base_damage as f32 * power) as u32;
|
||||
},
|
||||
ChargedMelee {
|
||||
ref mut initial_damage,
|
||||
ref mut max_damage,
|
||||
speed: ref mut ability_speed,
|
||||
ref mut charge_duration,
|
||||
ref mut swing_duration,
|
||||
ref mut recover_duration,
|
||||
..
|
||||
} => {
|
||||
*initial_damage = (*initial_damage as f32 * power) as u32;
|
||||
*max_damage = (*max_damage as f32 * power) as u32;
|
||||
*ability_speed *= speed;
|
||||
*charge_duration = (*charge_duration as f32 / speed) as u64;
|
||||
*swing_duration = (*swing_duration as f32 / speed) as u64;
|
||||
*recover_duration = (*recover_duration as f32 / speed) as u64;
|
||||
},
|
||||
ChargedRanged {
|
||||
ref mut initial_damage,
|
||||
ref mut max_damage,
|
||||
speed: ref mut ability_speed,
|
||||
ref mut buildup_duration,
|
||||
ref mut charge_duration,
|
||||
ref mut recover_duration,
|
||||
..
|
||||
} => {
|
||||
*initial_damage = (*initial_damage as f32 * power) as u32;
|
||||
*max_damage = (*max_damage as f32 * power) as u32;
|
||||
*ability_speed *= speed;
|
||||
*buildup_duration = (*buildup_duration as f32 / speed) as u64;
|
||||
*charge_duration = (*charge_duration as f32 / speed) as u64;
|
||||
*recover_duration = (*recover_duration as f32 / speed) as u64;
|
||||
},
|
||||
Shockwave {
|
||||
ref mut buildup_duration,
|
||||
ref mut swing_duration,
|
||||
ref mut recover_duration,
|
||||
ref mut damage,
|
||||
..
|
||||
} => {
|
||||
*buildup_duration = (*buildup_duration as f32 / speed) as u64;
|
||||
*swing_duration = (*swing_duration as f32 / speed) as u64;
|
||||
*recover_duration = (*recover_duration as f32 / speed) as u64;
|
||||
*damage = (*damage as f32 * power) as u32;
|
||||
},
|
||||
BasicBeam {
|
||||
ref mut buildup_duration,
|
||||
ref mut recover_duration,
|
||||
ref mut base_hps,
|
||||
ref mut base_dps,
|
||||
ref mut tick_rate,
|
||||
..
|
||||
} => {
|
||||
*buildup_duration = (*buildup_duration as f32 / speed) as u64;
|
||||
*recover_duration = (*recover_duration as f32 / speed) as u64;
|
||||
*base_hps = (*base_hps as f32 * power) as u32;
|
||||
*base_dps = (*base_dps as f32 * power) as u32;
|
||||
*tick_rate *= speed;
|
||||
},
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||
@ -300,17 +491,16 @@ pub struct ItemConfig {
|
||||
pub dodge_ability: Option<CharacterAbility>,
|
||||
}
|
||||
|
||||
impl From<Item> for ItemConfig {
|
||||
fn from(item: Item) -> Self {
|
||||
impl From<(Item, &AbilityMap)> for ItemConfig {
|
||||
fn from((item, map): (Item, &AbilityMap)) -> Self {
|
||||
if let ItemKind::Tool(tool) = &item.kind() {
|
||||
let mut abilities = tool.get_abilities();
|
||||
let mut ability_drain = abilities.drain(..);
|
||||
let abilities = tool.get_abilities(map);
|
||||
|
||||
return ItemConfig {
|
||||
item,
|
||||
ability1: ability_drain.next(),
|
||||
ability2: ability_drain.next(),
|
||||
ability3: ability_drain.next(),
|
||||
ability1: Some(abilities.primary),
|
||||
ability2: Some(abilities.secondary),
|
||||
ability3: abilities.skills.get(0).cloned(),
|
||||
block_ability: None,
|
||||
dodge_ability: Some(CharacterAbility::default_roll()),
|
||||
};
|
||||
@ -392,9 +582,9 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
|
||||
energy_cost: _,
|
||||
} => CharacterState::BasicMelee(basic_melee::Data {
|
||||
static_data: basic_melee::StaticData {
|
||||
buildup_duration: *buildup_duration,
|
||||
swing_duration: *swing_duration,
|
||||
recover_duration: *recover_duration,
|
||||
buildup_duration: Duration::from_millis(*buildup_duration),
|
||||
swing_duration: Duration::from_millis(*swing_duration),
|
||||
recover_duration: Duration::from_millis(*recover_duration),
|
||||
base_damage: *base_damage,
|
||||
knockback: *knockback,
|
||||
range: *range,
|
||||
@ -416,9 +606,9 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
|
||||
energy_cost: _,
|
||||
} => CharacterState::BasicRanged(basic_ranged::Data {
|
||||
static_data: basic_ranged::StaticData {
|
||||
buildup_duration: *buildup_duration,
|
||||
recover_duration: *recover_duration,
|
||||
projectile: projectile.clone(),
|
||||
buildup_duration: Duration::from_millis(*buildup_duration),
|
||||
recover_duration: Duration::from_millis(*recover_duration),
|
||||
projectile: *projectile,
|
||||
projectile_body: *projectile_body,
|
||||
projectile_light: *projectile_light,
|
||||
projectile_gravity: *projectile_gravity,
|
||||
@ -436,7 +626,7 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
|
||||
only_up,
|
||||
} => CharacterState::Boost(boost::Data {
|
||||
static_data: boost::StaticData {
|
||||
movement_duration: *movement_duration,
|
||||
movement_duration: Duration::from_millis(*movement_duration),
|
||||
only_up: *only_up,
|
||||
},
|
||||
timer: Duration::default(),
|
||||
@ -468,10 +658,10 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
|
||||
energy_drain: *energy_drain,
|
||||
forward_speed: *forward_speed,
|
||||
infinite_charge: *infinite_charge,
|
||||
buildup_duration: *buildup_duration,
|
||||
charge_duration: *charge_duration,
|
||||
swing_duration: *swing_duration,
|
||||
recover_duration: *recover_duration,
|
||||
buildup_duration: Duration::from_millis(*buildup_duration),
|
||||
charge_duration: Duration::from_millis(*charge_duration),
|
||||
swing_duration: Duration::from_millis(*swing_duration),
|
||||
recover_duration: Duration::from_millis(*recover_duration),
|
||||
is_interruptible: *is_interruptible,
|
||||
ability_key: key,
|
||||
},
|
||||
@ -490,9 +680,9 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
|
||||
roll_strength,
|
||||
} => CharacterState::Roll(roll::Data {
|
||||
static_data: roll::StaticData {
|
||||
buildup_duration: *buildup_duration,
|
||||
movement_duration: *movement_duration,
|
||||
recover_duration: *recover_duration,
|
||||
buildup_duration: Duration::from_millis(*buildup_duration),
|
||||
movement_duration: Duration::from_millis(*movement_duration),
|
||||
recover_duration: Duration::from_millis(*recover_duration),
|
||||
roll_strength: *roll_strength,
|
||||
},
|
||||
timer: Duration::default(),
|
||||
@ -511,7 +701,7 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
|
||||
} => CharacterState::ComboMelee(combo_melee::Data {
|
||||
static_data: combo_melee::StaticData {
|
||||
num_stages: stage_data.len() as u32,
|
||||
stage_data: stage_data.clone(),
|
||||
stage_data: stage_data.iter().map(|stage| stage.to_duration()).collect(),
|
||||
initial_energy_gain: *initial_energy_gain,
|
||||
max_energy_gain: *max_energy_gain,
|
||||
energy_increase: *energy_increase,
|
||||
@ -540,10 +730,10 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
|
||||
vertical_leap_strength,
|
||||
} => CharacterState::LeapMelee(leap_melee::Data {
|
||||
static_data: leap_melee::StaticData {
|
||||
buildup_duration: *buildup_duration,
|
||||
movement_duration: *movement_duration,
|
||||
swing_duration: *swing_duration,
|
||||
recover_duration: *recover_duration,
|
||||
buildup_duration: Duration::from_millis(*buildup_duration),
|
||||
movement_duration: Duration::from_millis(*movement_duration),
|
||||
swing_duration: Duration::from_millis(*swing_duration),
|
||||
recover_duration: Duration::from_millis(*recover_duration),
|
||||
base_damage: *base_damage,
|
||||
knockback: *knockback,
|
||||
range: *range,
|
||||
@ -570,9 +760,9 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
|
||||
num_spins,
|
||||
} => CharacterState::SpinMelee(spin_melee::Data {
|
||||
static_data: spin_melee::StaticData {
|
||||
buildup_duration: *buildup_duration,
|
||||
swing_duration: *swing_duration,
|
||||
recover_duration: *recover_duration,
|
||||
buildup_duration: Duration::from_millis(*buildup_duration),
|
||||
swing_duration: Duration::from_millis(*swing_duration),
|
||||
recover_duration: Duration::from_millis(*recover_duration),
|
||||
base_damage: *base_damage,
|
||||
knockback: *knockback,
|
||||
range: *range,
|
||||
@ -613,9 +803,9 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
|
||||
speed: *speed,
|
||||
range: *range,
|
||||
max_angle: *max_angle,
|
||||
charge_duration: *charge_duration,
|
||||
swing_duration: *swing_duration,
|
||||
recover_duration: *recover_duration,
|
||||
charge_duration: Duration::from_millis(*charge_duration),
|
||||
swing_duration: Duration::from_millis(*swing_duration),
|
||||
recover_duration: Duration::from_millis(*recover_duration),
|
||||
ability_key: key,
|
||||
},
|
||||
stage_section: StageSection::Charge,
|
||||
@ -641,9 +831,9 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
|
||||
max_projectile_speed,
|
||||
} => CharacterState::ChargedRanged(charged_ranged::Data {
|
||||
static_data: charged_ranged::StaticData {
|
||||
buildup_duration: *buildup_duration,
|
||||
charge_duration: *charge_duration,
|
||||
recover_duration: *recover_duration,
|
||||
buildup_duration: Duration::from_millis(*buildup_duration),
|
||||
charge_duration: Duration::from_millis(*charge_duration),
|
||||
recover_duration: Duration::from_millis(*recover_duration),
|
||||
energy_drain: *energy_drain,
|
||||
initial_damage: *initial_damage,
|
||||
max_damage: *max_damage,
|
||||
@ -676,12 +866,12 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
|
||||
reps_remaining,
|
||||
} => CharacterState::RepeaterRanged(repeater_ranged::Data {
|
||||
static_data: repeater_ranged::StaticData {
|
||||
movement_duration: *movement_duration,
|
||||
buildup_duration: *buildup_duration,
|
||||
shoot_duration: *shoot_duration,
|
||||
recover_duration: *recover_duration,
|
||||
movement_duration: Duration::from_millis(*movement_duration),
|
||||
buildup_duration: Duration::from_millis(*buildup_duration),
|
||||
shoot_duration: Duration::from_millis(*shoot_duration),
|
||||
recover_duration: Duration::from_millis(*recover_duration),
|
||||
leap: *leap,
|
||||
projectile: projectile.clone(),
|
||||
projectile: *projectile,
|
||||
projectile_body: *projectile_body,
|
||||
projectile_light: *projectile_light,
|
||||
projectile_gravity: *projectile_gravity,
|
||||
@ -706,15 +896,15 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
|
||||
move_efficiency,
|
||||
} => CharacterState::Shockwave(shockwave::Data {
|
||||
static_data: shockwave::StaticData {
|
||||
buildup_duration: *buildup_duration,
|
||||
swing_duration: *swing_duration,
|
||||
recover_duration: *recover_duration,
|
||||
buildup_duration: Duration::from_millis(*buildup_duration),
|
||||
swing_duration: Duration::from_millis(*swing_duration),
|
||||
recover_duration: Duration::from_millis(*recover_duration),
|
||||
damage: *damage,
|
||||
knockback: *knockback,
|
||||
shockwave_angle: *shockwave_angle,
|
||||
shockwave_vertical_angle: *shockwave_vertical_angle,
|
||||
shockwave_speed: *shockwave_speed,
|
||||
shockwave_duration: *shockwave_duration,
|
||||
shockwave_duration: Duration::from_millis(*shockwave_duration),
|
||||
requires_ground: *requires_ground,
|
||||
move_efficiency: *move_efficiency,
|
||||
},
|
||||
@ -736,9 +926,9 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
|
||||
energy_drain,
|
||||
} => CharacterState::BasicBeam(basic_beam::Data {
|
||||
static_data: basic_beam::StaticData {
|
||||
buildup_duration: *buildup_duration,
|
||||
recover_duration: *recover_duration,
|
||||
beam_duration: *beam_duration,
|
||||
buildup_duration: Duration::from_millis(*buildup_duration),
|
||||
recover_duration: Duration::from_millis(*recover_duration),
|
||||
beam_duration: Duration::from_millis(*beam_duration),
|
||||
base_hps: *base_hps,
|
||||
base_dps: *base_dps,
|
||||
tick_rate: *tick_rate,
|
||||
|
@ -2,7 +2,7 @@ pub mod armor;
|
||||
pub mod tool;
|
||||
|
||||
// Reexports
|
||||
pub use tool::{Hands, Tool, ToolKind, UniqueKind};
|
||||
pub use tool::{AbilitySet, Hands, Tool, ToolKind, UniqueKind};
|
||||
|
||||
use crate::{
|
||||
assets::{self, Asset, Error},
|
||||
|
@ -2,17 +2,12 @@
|
||||
// version in voxygen\src\meta.rs in order to reset save files to being empty
|
||||
|
||||
use crate::{
|
||||
comp::{
|
||||
body::object,
|
||||
buff::{Buff, BuffCategory, BuffData, BuffKind, BuffSource},
|
||||
projectile, Body, CharacterAbility, Gravity, LightEmitter, Projectile,
|
||||
},
|
||||
effect::Effect,
|
||||
states::combo_melee,
|
||||
Damage, DamageSource, Explosion, GroupTarget, Knockback, RadiusEffect,
|
||||
assets::{self, Asset},
|
||||
comp::CharacterAbility,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use std::{collections::HashMap, fs::File, io::BufReader, time::Duration};
|
||||
use tracing::error;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum ToolKind {
|
||||
@ -90,578 +85,89 @@ impl Tool {
|
||||
Duration::from_millis(self.stats.equip_time_millis as u64)
|
||||
}
|
||||
|
||||
/// Converts milliseconds to a `Duration` adjusted by `base_speed()`
|
||||
pub fn adjusted_duration(&self, millis: u64) -> Duration {
|
||||
Duration::from_millis(millis).div_f32(self.base_speed())
|
||||
}
|
||||
|
||||
pub fn get_abilities(&self) -> Vec<CharacterAbility> {
|
||||
use CharacterAbility::*;
|
||||
use ToolKind::*;
|
||||
|
||||
use UniqueKind::*;
|
||||
match &self.kind {
|
||||
Sword => vec![
|
||||
ComboMelee {
|
||||
stage_data: vec![
|
||||
combo_melee::Stage {
|
||||
stage: 1,
|
||||
base_damage: (100.0 * self.base_power()) as u32,
|
||||
max_damage: (120.0 * self.base_power()) as u32,
|
||||
damage_increase: (10.0 * self.base_power()) as u32,
|
||||
knockback: 10.0,
|
||||
range: 4.0,
|
||||
angle: 30.0,
|
||||
base_buildup_duration: self.adjusted_duration(350),
|
||||
base_swing_duration: self.adjusted_duration(100),
|
||||
base_recover_duration: self.adjusted_duration(400),
|
||||
forward_movement: 0.5,
|
||||
},
|
||||
combo_melee::Stage {
|
||||
stage: 2,
|
||||
base_damage: (80.0 * self.base_power()) as u32,
|
||||
max_damage: (110.0 * self.base_power()) as u32,
|
||||
damage_increase: (15.0 * self.base_power()) as u32,
|
||||
knockback: 12.0,
|
||||
range: 3.5,
|
||||
angle: 180.0,
|
||||
base_buildup_duration: self.adjusted_duration(400),
|
||||
base_swing_duration: self.adjusted_duration(600),
|
||||
base_recover_duration: self.adjusted_duration(400),
|
||||
forward_movement: 0.0,
|
||||
},
|
||||
combo_melee::Stage {
|
||||
stage: 3,
|
||||
base_damage: (130.0 * self.base_power()) as u32,
|
||||
max_damage: (170.0 * self.base_power()) as u32,
|
||||
damage_increase: (20.0 * self.base_power()) as u32,
|
||||
knockback: 14.0,
|
||||
range: 6.0,
|
||||
angle: 10.0,
|
||||
base_buildup_duration: self.adjusted_duration(500),
|
||||
base_swing_duration: self.adjusted_duration(200),
|
||||
base_recover_duration: self.adjusted_duration(300),
|
||||
forward_movement: 1.2,
|
||||
},
|
||||
],
|
||||
initial_energy_gain: 0,
|
||||
max_energy_gain: 100,
|
||||
energy_increase: 20,
|
||||
speed_increase: 0.05,
|
||||
max_speed_increase: 1.8,
|
||||
is_interruptible: true,
|
||||
},
|
||||
DashMelee {
|
||||
energy_cost: 200,
|
||||
base_damage: (120.0 * self.base_power()) as u32,
|
||||
max_damage: (240.0 * self.base_power()) as u32,
|
||||
base_knockback: 8.0,
|
||||
max_knockback: 15.0,
|
||||
range: 5.0,
|
||||
angle: 45.0,
|
||||
energy_drain: 500,
|
||||
forward_speed: 4.0,
|
||||
buildup_duration: self.adjusted_duration(250),
|
||||
charge_duration: Duration::from_millis(600),
|
||||
swing_duration: self.adjusted_duration(100),
|
||||
recover_duration: self.adjusted_duration(500),
|
||||
infinite_charge: true,
|
||||
is_interruptible: true,
|
||||
},
|
||||
SpinMelee {
|
||||
buildup_duration: self.adjusted_duration(750),
|
||||
swing_duration: self.adjusted_duration(500),
|
||||
recover_duration: self.adjusted_duration(500),
|
||||
base_damage: (140.0 * self.base_power()) as u32,
|
||||
knockback: 10.0,
|
||||
range: 3.5,
|
||||
energy_cost: 200,
|
||||
is_infinite: false,
|
||||
is_helicopter: false,
|
||||
is_interruptible: true,
|
||||
forward_speed: 1.0,
|
||||
num_spins: 3,
|
||||
},
|
||||
],
|
||||
Axe => vec![
|
||||
ComboMelee {
|
||||
stage_data: vec![
|
||||
combo_melee::Stage {
|
||||
stage: 1,
|
||||
base_damage: (90.0 * self.base_power()) as u32,
|
||||
max_damage: (110.0 * self.base_power()) as u32,
|
||||
damage_increase: (10.0 * self.base_power()) as u32,
|
||||
knockback: 8.0,
|
||||
range: 3.5,
|
||||
angle: 50.0,
|
||||
base_buildup_duration: self.adjusted_duration(350),
|
||||
base_swing_duration: self.adjusted_duration(75),
|
||||
base_recover_duration: self.adjusted_duration(400),
|
||||
forward_movement: 0.5,
|
||||
},
|
||||
combo_melee::Stage {
|
||||
stage: 2,
|
||||
base_damage: (130.0 * self.base_power()) as u32,
|
||||
max_damage: (160.0 * self.base_power()) as u32,
|
||||
damage_increase: (15.0 * self.base_power()) as u32,
|
||||
knockback: 12.0,
|
||||
range: 3.5,
|
||||
angle: 30.0,
|
||||
base_buildup_duration: self.adjusted_duration(500),
|
||||
base_swing_duration: self.adjusted_duration(100),
|
||||
base_recover_duration: self.adjusted_duration(500),
|
||||
forward_movement: 0.25,
|
||||
},
|
||||
],
|
||||
initial_energy_gain: 0,
|
||||
max_energy_gain: 100,
|
||||
energy_increase: 20,
|
||||
speed_increase: 0.05,
|
||||
max_speed_increase: 1.6,
|
||||
is_interruptible: false,
|
||||
},
|
||||
SpinMelee {
|
||||
buildup_duration: self.adjusted_duration(100),
|
||||
swing_duration: self.adjusted_duration(250),
|
||||
recover_duration: self.adjusted_duration(100),
|
||||
base_damage: (60.0 * self.base_power()) as u32,
|
||||
knockback: 0.0,
|
||||
range: 3.5,
|
||||
energy_cost: 100,
|
||||
is_infinite: true,
|
||||
is_helicopter: true,
|
||||
is_interruptible: false,
|
||||
forward_speed: 0.0,
|
||||
num_spins: 1,
|
||||
},
|
||||
LeapMelee {
|
||||
energy_cost: 450,
|
||||
buildup_duration: self.adjusted_duration(200),
|
||||
movement_duration: Duration::from_millis(200),
|
||||
swing_duration: self.adjusted_duration(200),
|
||||
recover_duration: self.adjusted_duration(200),
|
||||
base_damage: (240.0 * self.base_power()) as u32,
|
||||
knockback: 12.0,
|
||||
range: 4.5,
|
||||
max_angle: 30.0,
|
||||
forward_leap_strength: 28.0,
|
||||
vertical_leap_strength: 8.0,
|
||||
},
|
||||
],
|
||||
Hammer => vec![
|
||||
ComboMelee {
|
||||
stage_data: vec![combo_melee::Stage {
|
||||
stage: 1,
|
||||
base_damage: (120.0 * self.base_power()) as u32,
|
||||
max_damage: (150.0 * self.base_power()) as u32,
|
||||
damage_increase: (10.0 * self.base_power()) as u32,
|
||||
knockback: 0.0,
|
||||
range: 3.5,
|
||||
angle: 20.0,
|
||||
base_buildup_duration: self.adjusted_duration(600),
|
||||
base_swing_duration: self.adjusted_duration(60),
|
||||
base_recover_duration: self.adjusted_duration(300),
|
||||
forward_movement: 0.0,
|
||||
}],
|
||||
initial_energy_gain: 0,
|
||||
max_energy_gain: 100,
|
||||
energy_increase: 20,
|
||||
speed_increase: 0.05,
|
||||
max_speed_increase: 1.4,
|
||||
is_interruptible: false,
|
||||
},
|
||||
ChargedMelee {
|
||||
energy_cost: 1,
|
||||
energy_drain: 300,
|
||||
initial_damage: (10.0 * self.base_power()) as u32,
|
||||
max_damage: (170.0 * self.base_power()) as u32,
|
||||
initial_knockback: 10.0,
|
||||
max_knockback: 60.0,
|
||||
range: 3.5,
|
||||
max_angle: 30.0,
|
||||
speed: self.base_speed(),
|
||||
charge_duration: Duration::from_millis(1200),
|
||||
swing_duration: self.adjusted_duration(200),
|
||||
recover_duration: self.adjusted_duration(300),
|
||||
},
|
||||
LeapMelee {
|
||||
energy_cost: 700,
|
||||
buildup_duration: self.adjusted_duration(100),
|
||||
movement_duration: Duration::from_millis(800),
|
||||
swing_duration: self.adjusted_duration(150),
|
||||
recover_duration: self.adjusted_duration(200),
|
||||
base_damage: (240.0 * self.base_power()) as u32,
|
||||
knockback: 25.0,
|
||||
range: 4.5,
|
||||
max_angle: 360.0,
|
||||
forward_leap_strength: 28.0,
|
||||
vertical_leap_strength: 8.0,
|
||||
},
|
||||
],
|
||||
Farming => vec![BasicMelee {
|
||||
energy_cost: 1,
|
||||
buildup_duration: self.adjusted_duration(600),
|
||||
swing_duration: self.adjusted_duration(100),
|
||||
recover_duration: self.adjusted_duration(150),
|
||||
base_damage: (50.0 * self.base_power()) as u32,
|
||||
knockback: 0.0,
|
||||
range: 3.5,
|
||||
max_angle: 20.0,
|
||||
}],
|
||||
Bow => vec![
|
||||
BasicRanged {
|
||||
energy_cost: 0,
|
||||
buildup_duration: self.adjusted_duration(200),
|
||||
recover_duration: self.adjusted_duration(300),
|
||||
projectile: Projectile {
|
||||
hit_solid: vec![projectile::Effect::Stick],
|
||||
hit_entity: vec![
|
||||
projectile::Effect::Damage(Some(GroupTarget::OutOfGroup), Damage {
|
||||
source: DamageSource::Projectile,
|
||||
value: 40.0 * self.base_power(),
|
||||
}),
|
||||
projectile::Effect::Knockback(Knockback::Away(10.0)),
|
||||
projectile::Effect::RewardEnergy(50),
|
||||
projectile::Effect::Vanish,
|
||||
projectile::Effect::Buff {
|
||||
buff: Buff::new(
|
||||
BuffKind::Bleeding,
|
||||
BuffData {
|
||||
strength: 20.0 * self.base_power(),
|
||||
duration: Some(Duration::from_secs(5)),
|
||||
},
|
||||
vec![BuffCategory::Physical],
|
||||
BuffSource::Unknown,
|
||||
),
|
||||
chance: Some(0.10),
|
||||
},
|
||||
],
|
||||
time_left: Duration::from_secs(15),
|
||||
owner: None,
|
||||
ignore_group: true,
|
||||
},
|
||||
projectile_body: Body::Object(object::Body::Arrow),
|
||||
projectile_light: None,
|
||||
projectile_gravity: Some(Gravity(0.2)),
|
||||
projectile_speed: 100.0,
|
||||
can_continue: true,
|
||||
},
|
||||
ChargedRanged {
|
||||
energy_cost: 0,
|
||||
energy_drain: 300,
|
||||
initial_damage: (40.0 * self.base_power()) as u32,
|
||||
max_damage: (200.0 * self.base_power()) as u32,
|
||||
initial_knockback: 10.0,
|
||||
max_knockback: 20.0,
|
||||
speed: self.base_speed(),
|
||||
buildup_duration: self.adjusted_duration(100),
|
||||
charge_duration: Duration::from_millis(1500),
|
||||
recover_duration: self.adjusted_duration(500),
|
||||
projectile_body: Body::Object(object::Body::MultiArrow),
|
||||
projectile_light: None,
|
||||
projectile_gravity: Some(Gravity(0.2)),
|
||||
initial_projectile_speed: 100.0,
|
||||
max_projectile_speed: 500.0,
|
||||
},
|
||||
RepeaterRanged {
|
||||
energy_cost: 450,
|
||||
movement_duration: Duration::from_millis(300),
|
||||
buildup_duration: self.adjusted_duration(200),
|
||||
shoot_duration: self.adjusted_duration(200),
|
||||
recover_duration: self.adjusted_duration(800),
|
||||
leap: Some(5.0),
|
||||
projectile: Projectile {
|
||||
hit_solid: vec![projectile::Effect::Stick],
|
||||
hit_entity: vec![
|
||||
projectile::Effect::Damage(Some(GroupTarget::OutOfGroup), Damage {
|
||||
source: DamageSource::Projectile,
|
||||
value: 40.0 * self.base_power(),
|
||||
}),
|
||||
projectile::Effect::Knockback(Knockback::Away(10.0)),
|
||||
projectile::Effect::Vanish,
|
||||
projectile::Effect::Buff {
|
||||
buff: Buff::new(
|
||||
BuffKind::Bleeding,
|
||||
BuffData {
|
||||
strength: 20.0 * self.base_power(),
|
||||
duration: Some(Duration::from_secs(5)),
|
||||
},
|
||||
vec![BuffCategory::Physical],
|
||||
BuffSource::Unknown,
|
||||
),
|
||||
chance: Some(0.10),
|
||||
},
|
||||
],
|
||||
time_left: Duration::from_secs(15),
|
||||
owner: None,
|
||||
ignore_group: true,
|
||||
},
|
||||
projectile_body: Body::Object(object::Body::Arrow),
|
||||
projectile_light: None,
|
||||
projectile_gravity: Some(Gravity(0.2)),
|
||||
projectile_speed: 100.0,
|
||||
reps_remaining: 5,
|
||||
},
|
||||
],
|
||||
Dagger => vec![BasicMelee {
|
||||
energy_cost: 0,
|
||||
buildup_duration: self.adjusted_duration(100),
|
||||
swing_duration: self.adjusted_duration(100),
|
||||
recover_duration: self.adjusted_duration(300),
|
||||
base_damage: (50.0 * self.base_power()) as u32,
|
||||
knockback: 0.0,
|
||||
range: 3.5,
|
||||
max_angle: 20.0,
|
||||
}],
|
||||
Sceptre => vec![
|
||||
BasicBeam {
|
||||
buildup_duration: self.adjusted_duration(250),
|
||||
recover_duration: self.adjusted_duration(250),
|
||||
beam_duration: Duration::from_secs(1),
|
||||
base_hps: (60.0 * self.base_power()) as u32,
|
||||
base_dps: (60.0 * self.base_power()) as u32,
|
||||
tick_rate: 2.0 * self.base_speed(),
|
||||
range: 25.0,
|
||||
max_angle: 1.0,
|
||||
lifesteal_eff: 0.20,
|
||||
energy_regen: 50,
|
||||
energy_cost: 100,
|
||||
energy_drain: 0,
|
||||
},
|
||||
BasicRanged {
|
||||
energy_cost: 800,
|
||||
buildup_duration: self.adjusted_duration(800),
|
||||
recover_duration: self.adjusted_duration(50),
|
||||
projectile: Projectile {
|
||||
hit_solid: vec![
|
||||
projectile::Effect::Explode(Explosion {
|
||||
effects: vec![
|
||||
RadiusEffect::Entity(
|
||||
Some(GroupTarget::OutOfGroup),
|
||||
Effect::Damage(Damage {
|
||||
source: DamageSource::Explosion,
|
||||
value: 50.0 * self.base_power(),
|
||||
}),
|
||||
),
|
||||
RadiusEffect::Entity(
|
||||
Some(GroupTarget::InGroup),
|
||||
Effect::Damage(Damage {
|
||||
source: DamageSource::Healing,
|
||||
value: 140.0 * self.base_power(),
|
||||
}),
|
||||
),
|
||||
],
|
||||
radius: 3.0 + 2.5 * self.base_power(),
|
||||
energy_regen: 0,
|
||||
}),
|
||||
projectile::Effect::Vanish,
|
||||
],
|
||||
hit_entity: vec![
|
||||
projectile::Effect::Explode(Explosion {
|
||||
effects: vec![
|
||||
RadiusEffect::Entity(
|
||||
Some(GroupTarget::OutOfGroup),
|
||||
Effect::Damage(Damage {
|
||||
source: DamageSource::Explosion,
|
||||
value: 50.0 * self.base_power(),
|
||||
}),
|
||||
),
|
||||
RadiusEffect::Entity(
|
||||
Some(GroupTarget::InGroup),
|
||||
Effect::Damage(Damage {
|
||||
source: DamageSource::Healing,
|
||||
value: 140.0 * self.base_power(),
|
||||
}),
|
||||
),
|
||||
],
|
||||
radius: 3.0 + 2.5 * self.base_power(),
|
||||
energy_regen: 0,
|
||||
}),
|
||||
projectile::Effect::Vanish,
|
||||
],
|
||||
time_left: Duration::from_secs(20),
|
||||
owner: None,
|
||||
ignore_group: true,
|
||||
},
|
||||
projectile_body: Body::Object(object::Body::BoltNature),
|
||||
projectile_light: Some(LightEmitter {
|
||||
col: (0.0, 1.0, 0.0).into(),
|
||||
..Default::default()
|
||||
}),
|
||||
projectile_gravity: Some(Gravity(0.5)),
|
||||
projectile_speed: 40.0,
|
||||
can_continue: false,
|
||||
},
|
||||
],
|
||||
Staff => vec![
|
||||
BasicRanged {
|
||||
energy_cost: 0,
|
||||
buildup_duration: self.adjusted_duration(500),
|
||||
recover_duration: self.adjusted_duration(350),
|
||||
projectile: Projectile {
|
||||
hit_solid: vec![
|
||||
projectile::Effect::Explode(Explosion {
|
||||
effects: vec![RadiusEffect::Entity(
|
||||
Some(GroupTarget::OutOfGroup),
|
||||
Effect::Damage(Damage {
|
||||
source: DamageSource::Explosion,
|
||||
value: 100.0 * self.base_power(),
|
||||
}),
|
||||
)],
|
||||
radius: 5.0,
|
||||
energy_regen: 50,
|
||||
}),
|
||||
projectile::Effect::Vanish,
|
||||
],
|
||||
hit_entity: vec![
|
||||
projectile::Effect::Explode(Explosion {
|
||||
effects: vec![RadiusEffect::Entity(
|
||||
Some(GroupTarget::OutOfGroup),
|
||||
Effect::Damage(Damage {
|
||||
source: DamageSource::Explosion,
|
||||
value: 100.0 * self.base_power(),
|
||||
}),
|
||||
)],
|
||||
radius: 5.0,
|
||||
energy_regen: 50,
|
||||
}),
|
||||
projectile::Effect::Vanish,
|
||||
],
|
||||
time_left: Duration::from_secs(20),
|
||||
owner: None,
|
||||
ignore_group: true,
|
||||
},
|
||||
projectile_body: Body::Object(object::Body::BoltFire),
|
||||
projectile_light: Some(LightEmitter {
|
||||
col: (1.0, 0.75, 0.11).into(),
|
||||
..Default::default()
|
||||
}),
|
||||
projectile_gravity: Some(Gravity(0.3)),
|
||||
projectile_speed: 60.0,
|
||||
can_continue: true,
|
||||
},
|
||||
BasicBeam {
|
||||
buildup_duration: self.adjusted_duration(250),
|
||||
recover_duration: self.adjusted_duration(250),
|
||||
beam_duration: self.adjusted_duration(500),
|
||||
base_hps: 0,
|
||||
base_dps: (150.0 * self.base_power()) as u32,
|
||||
tick_rate: 3.0 * self.base_speed(),
|
||||
range: 15.0,
|
||||
max_angle: 22.5,
|
||||
lifesteal_eff: 0.0,
|
||||
energy_regen: 0,
|
||||
energy_cost: 0,
|
||||
energy_drain: 350,
|
||||
},
|
||||
Shockwave {
|
||||
energy_cost: 600,
|
||||
buildup_duration: self.adjusted_duration(700),
|
||||
swing_duration: self.adjusted_duration(100),
|
||||
recover_duration: self.adjusted_duration(300),
|
||||
damage: (200.0 * self.base_power()) as u32,
|
||||
knockback: Knockback::Away(25.0),
|
||||
shockwave_angle: 360.0,
|
||||
shockwave_vertical_angle: 90.0,
|
||||
shockwave_speed: 20.0,
|
||||
shockwave_duration: Duration::from_millis(500),
|
||||
requires_ground: false,
|
||||
move_efficiency: 0.1,
|
||||
},
|
||||
],
|
||||
Shield => vec![
|
||||
BasicMelee {
|
||||
energy_cost: 0,
|
||||
buildup_duration: self.adjusted_duration(100),
|
||||
swing_duration: self.adjusted_duration(100),
|
||||
recover_duration: self.adjusted_duration(300),
|
||||
base_damage: (40.0 * self.base_power()) as u32,
|
||||
knockback: 0.0,
|
||||
range: 3.0,
|
||||
max_angle: 120.0,
|
||||
},
|
||||
BasicBlock,
|
||||
],
|
||||
Unique(StoneGolemFist) => vec![
|
||||
BasicMelee {
|
||||
energy_cost: 0,
|
||||
buildup_duration: self.adjusted_duration(400),
|
||||
swing_duration: self.adjusted_duration(100),
|
||||
recover_duration: self.adjusted_duration(250),
|
||||
knockback: 25.0,
|
||||
base_damage: 200,
|
||||
range: 5.0,
|
||||
max_angle: 120.0,
|
||||
},
|
||||
Shockwave {
|
||||
energy_cost: 0,
|
||||
buildup_duration: self.adjusted_duration(500),
|
||||
swing_duration: self.adjusted_duration(200),
|
||||
recover_duration: self.adjusted_duration(800),
|
||||
damage: 500,
|
||||
knockback: Knockback::TowardsUp(40.0),
|
||||
shockwave_angle: 90.0,
|
||||
shockwave_vertical_angle: 15.0,
|
||||
shockwave_speed: 20.0,
|
||||
shockwave_duration: Duration::from_millis(2000),
|
||||
requires_ground: true,
|
||||
move_efficiency: 0.05,
|
||||
},
|
||||
],
|
||||
Unique(BeastClaws) => vec![BasicMelee {
|
||||
energy_cost: 0,
|
||||
buildup_duration: self.adjusted_duration(250),
|
||||
swing_duration: self.adjusted_duration(250),
|
||||
recover_duration: self.adjusted_duration(250),
|
||||
knockback: 25.0,
|
||||
base_damage: 200,
|
||||
range: 5.0,
|
||||
max_angle: 120.0,
|
||||
}],
|
||||
Debug => vec![
|
||||
CharacterAbility::Boost {
|
||||
movement_duration: Duration::from_millis(50),
|
||||
only_up: false,
|
||||
},
|
||||
CharacterAbility::Boost {
|
||||
movement_duration: Duration::from_millis(50),
|
||||
only_up: true,
|
||||
},
|
||||
BasicRanged {
|
||||
energy_cost: 0,
|
||||
buildup_duration: Duration::from_millis(0),
|
||||
recover_duration: self.adjusted_duration(10),
|
||||
projectile: Projectile {
|
||||
hit_solid: vec![projectile::Effect::Stick],
|
||||
hit_entity: vec![projectile::Effect::Stick, projectile::Effect::Possess],
|
||||
time_left: Duration::from_secs(10),
|
||||
owner: None,
|
||||
ignore_group: false,
|
||||
},
|
||||
projectile_body: Body::Object(object::Body::ArrowSnake),
|
||||
projectile_light: Some(LightEmitter {
|
||||
col: (0.0, 1.0, 0.33).into(),
|
||||
..Default::default()
|
||||
}),
|
||||
projectile_gravity: None,
|
||||
projectile_speed: 100.0,
|
||||
can_continue: false,
|
||||
},
|
||||
],
|
||||
Empty => vec![BasicMelee {
|
||||
energy_cost: 0,
|
||||
buildup_duration: Duration::from_millis(0),
|
||||
swing_duration: self.adjusted_duration(100),
|
||||
recover_duration: self.adjusted_duration(900),
|
||||
base_damage: 20,
|
||||
knockback: 0.0,
|
||||
range: 3.5,
|
||||
max_angle: 15.0,
|
||||
}],
|
||||
pub fn get_abilities(&self, map: &AbilityMap) -> AbilitySet<CharacterAbility> {
|
||||
if let Some(set) = map.0.get(&self.kind).cloned() {
|
||||
set.modified_by_tool(&self)
|
||||
} else {
|
||||
error!(
|
||||
"ToolKind: {:?} has no AbilitySet in the ability map falling back to default",
|
||||
&self.kind
|
||||
);
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct AbilitySet<T> {
|
||||
pub primary: T,
|
||||
pub secondary: T,
|
||||
pub skills: Vec<T>,
|
||||
}
|
||||
|
||||
impl AbilitySet<CharacterAbility> {
|
||||
pub fn modified_by_tool(self, tool: &Tool) -> Self {
|
||||
self.map(|a| a.adjusted_by_stats(tool.base_power(), tool.base_speed()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AbilitySet<T> {
|
||||
pub fn map<U, F: FnMut(T) -> U>(self, mut f: F) -> AbilitySet<U> {
|
||||
AbilitySet {
|
||||
primary: f(self.primary),
|
||||
secondary: f(self.secondary),
|
||||
skills: self.skills.into_iter().map(|x| f(x)).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for AbilitySet<CharacterAbility> {
|
||||
fn default() -> Self {
|
||||
AbilitySet {
|
||||
primary: CharacterAbility::default(),
|
||||
secondary: CharacterAbility::default(),
|
||||
skills: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct AbilityMap<T = CharacterAbility>(HashMap<ToolKind, AbilitySet<T>>);
|
||||
|
||||
impl Asset for AbilityMap {
|
||||
const ENDINGS: &'static [&'static str] = &["ron"];
|
||||
|
||||
fn parse(buf_reader: BufReader<File>, specifier: &str) -> Result<Self, assets::Error> {
|
||||
ron::de::from_reader::<BufReader<File>, AbilityMap<String>>(buf_reader)
|
||||
.map(|map| {
|
||||
AbilityMap(
|
||||
map.0
|
||||
.into_iter()
|
||||
.map(|(kind, set)| {
|
||||
(
|
||||
kind,
|
||||
set.map(|s| match CharacterAbility::load(&s) {
|
||||
Ok(ability) => ability.as_ref().clone(),
|
||||
Err(err) => {
|
||||
error!(
|
||||
?err,
|
||||
"Error loading CharacterAbility: {} for the ability \
|
||||
map: {} replacing with default",
|
||||
s,
|
||||
specifier
|
||||
);
|
||||
CharacterAbility::default()
|
||||
},
|
||||
}),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
})
|
||||
.map_err(assets::Error::parse_error)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum UniqueKind {
|
||||
StoneGolemFist,
|
||||
|
@ -1,6 +1,9 @@
|
||||
use crate::{
|
||||
comp,
|
||||
comp::{item, item::armor, ItemConfig},
|
||||
comp::{
|
||||
item::{self, armor, tool::AbilityMap},
|
||||
ItemConfig,
|
||||
},
|
||||
};
|
||||
use comp::{Inventory, Loadout};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -90,6 +93,7 @@ fn loadout_replace(
|
||||
equip_slot: EquipSlot,
|
||||
item: Option<item::Item>,
|
||||
loadout: &mut Loadout,
|
||||
map: &AbilityMap,
|
||||
) -> Option<item::Item> {
|
||||
use std::mem::replace;
|
||||
match equip_slot {
|
||||
@ -106,12 +110,16 @@ fn loadout_replace(
|
||||
EquipSlot::Armor(ArmorSlot::Tabard) => replace(&mut loadout.tabard, item),
|
||||
EquipSlot::Lantern => replace(&mut loadout.lantern, item),
|
||||
EquipSlot::Glider => replace(&mut loadout.glider, item),
|
||||
EquipSlot::Mainhand => {
|
||||
replace(&mut loadout.active_item, item.map(ItemConfig::from)).map(|i| i.item)
|
||||
},
|
||||
EquipSlot::Offhand => {
|
||||
replace(&mut loadout.second_item, item.map(ItemConfig::from)).map(|i| i.item)
|
||||
},
|
||||
EquipSlot::Mainhand => replace(
|
||||
&mut loadout.active_item,
|
||||
item.map(|item| ItemConfig::from((item, map))),
|
||||
)
|
||||
.map(|i| i.item),
|
||||
EquipSlot::Offhand => replace(
|
||||
&mut loadout.second_item,
|
||||
item.map(|item| ItemConfig::from((item, map))),
|
||||
)
|
||||
.map(|i| i.item),
|
||||
}
|
||||
}
|
||||
|
||||
@ -122,15 +130,18 @@ fn loadout_insert(
|
||||
equip_slot: EquipSlot,
|
||||
item: item::Item,
|
||||
loadout: &mut Loadout,
|
||||
map: &AbilityMap,
|
||||
) -> Option<item::Item> {
|
||||
loadout_replace(equip_slot, Some(item), loadout)
|
||||
loadout_replace(equip_slot, Some(item), loadout, map)
|
||||
}
|
||||
|
||||
/// Remove an item from a loadout.
|
||||
///
|
||||
/// ```
|
||||
/// use veloren_common::{
|
||||
/// assets::Asset,
|
||||
/// comp::{
|
||||
/// item::tool::AbilityMap,
|
||||
/// slot::{loadout_remove, EquipSlot},
|
||||
/// Inventory,
|
||||
/// },
|
||||
@ -139,20 +150,27 @@ fn loadout_insert(
|
||||
///
|
||||
/// let mut inv = Inventory::new_empty();
|
||||
///
|
||||
/// let map = AbilityMap::load_expect_cloned("common.abilities.weapon_ability_manifest");
|
||||
///
|
||||
/// let mut loadout = LoadoutBuilder::new()
|
||||
/// .defaults()
|
||||
/// .active_item(Some(LoadoutBuilder::default_item_config_from_str(
|
||||
/// "common.items.weapons.sword.zweihander_sword_0",
|
||||
/// &map,
|
||||
/// )))
|
||||
/// .build();
|
||||
///
|
||||
/// let slot = EquipSlot::Mainhand;
|
||||
///
|
||||
/// loadout_remove(slot, &mut loadout);
|
||||
/// loadout_remove(slot, &mut loadout, &map);
|
||||
/// assert_eq!(None, loadout.active_item);
|
||||
/// ```
|
||||
pub fn loadout_remove(equip_slot: EquipSlot, loadout: &mut Loadout) -> Option<item::Item> {
|
||||
loadout_replace(equip_slot, None, loadout)
|
||||
pub fn loadout_remove(
|
||||
equip_slot: EquipSlot,
|
||||
loadout: &mut Loadout,
|
||||
map: &AbilityMap,
|
||||
) -> Option<item::Item> {
|
||||
loadout_replace(equip_slot, None, loadout, map)
|
||||
}
|
||||
|
||||
/// Swap item in an inventory slot with one in a loadout slot.
|
||||
@ -161,6 +179,7 @@ fn swap_inventory_loadout(
|
||||
equip_slot: EquipSlot,
|
||||
inventory: &mut Inventory,
|
||||
loadout: &mut Loadout,
|
||||
map: &AbilityMap,
|
||||
) {
|
||||
// Check if loadout slot can hold item
|
||||
if inventory
|
||||
@ -168,7 +187,7 @@ fn swap_inventory_loadout(
|
||||
.map_or(true, |item| equip_slot.can_hold(&item.kind()))
|
||||
{
|
||||
// Take item from loadout
|
||||
let from_equip = loadout_remove(equip_slot, loadout);
|
||||
let from_equip = loadout_remove(equip_slot, loadout, map);
|
||||
// Swap with item in the inventory
|
||||
let from_inv = if let Some(item) = from_equip {
|
||||
// If this fails and we get item back as an err it will just be put back in the
|
||||
@ -179,14 +198,14 @@ fn swap_inventory_loadout(
|
||||
};
|
||||
// Put item from the inventory in loadout
|
||||
if let Some(item) = from_inv {
|
||||
loadout_insert(equip_slot, item, loadout).unwrap_none(); // Can never fail
|
||||
loadout_insert(equip_slot, item, loadout, map).unwrap_none(); // Can never fail
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Swap items in loadout. Does nothing if items are not compatible with their
|
||||
/// new slots.
|
||||
fn swap_loadout(slot_a: EquipSlot, slot_b: EquipSlot, loadout: &mut Loadout) {
|
||||
fn swap_loadout(slot_a: EquipSlot, slot_b: EquipSlot, loadout: &mut Loadout, map: &AbilityMap) {
|
||||
// Ensure that the slots are not the same
|
||||
if slot_a == slot_b {
|
||||
warn!("Tried to swap equip slot with itself");
|
||||
@ -194,19 +213,19 @@ fn swap_loadout(slot_a: EquipSlot, slot_b: EquipSlot, loadout: &mut Loadout) {
|
||||
}
|
||||
|
||||
// Get items from the slots
|
||||
let item_a = loadout_remove(slot_a, loadout);
|
||||
let item_b = loadout_remove(slot_b, loadout);
|
||||
let item_a = loadout_remove(slot_a, loadout, map);
|
||||
let item_b = loadout_remove(slot_b, loadout, map);
|
||||
// Check if items can go in the other slots
|
||||
if item_a.as_ref().map_or(true, |i| slot_b.can_hold(&i.kind()))
|
||||
&& item_b.as_ref().map_or(true, |i| slot_a.can_hold(&i.kind()))
|
||||
{
|
||||
// Swap
|
||||
loadout_replace(slot_b, item_a, loadout).unwrap_none();
|
||||
loadout_replace(slot_a, item_b, loadout).unwrap_none();
|
||||
loadout_replace(slot_b, item_a, loadout, map).unwrap_none();
|
||||
loadout_replace(slot_a, item_b, loadout, map).unwrap_none();
|
||||
} else {
|
||||
// Otherwise put the items back
|
||||
loadout_replace(slot_a, item_a, loadout).unwrap_none();
|
||||
loadout_replace(slot_b, item_b, loadout).unwrap_none();
|
||||
loadout_replace(slot_a, item_a, loadout, map).unwrap_none();
|
||||
loadout_replace(slot_b, item_b, loadout, map).unwrap_none();
|
||||
}
|
||||
}
|
||||
|
||||
@ -219,6 +238,7 @@ pub fn swap(
|
||||
slot_b: Slot,
|
||||
inventory: Option<&mut Inventory>,
|
||||
loadout: Option<&mut Loadout>,
|
||||
map: &AbilityMap,
|
||||
) {
|
||||
match (slot_a, slot_b) {
|
||||
(Slot::Inventory(slot_a), Slot::Inventory(slot_b)) => {
|
||||
@ -227,12 +247,12 @@ pub fn swap(
|
||||
(Slot::Inventory(inv_slot), Slot::Equip(equip_slot))
|
||||
| (Slot::Equip(equip_slot), Slot::Inventory(inv_slot)) => {
|
||||
if let Some((inventory, loadout)) = loadout.and_then(|l| inventory.map(|i| (i, l))) {
|
||||
swap_inventory_loadout(inv_slot, equip_slot, inventory, loadout);
|
||||
swap_inventory_loadout(inv_slot, equip_slot, inventory, loadout, map);
|
||||
}
|
||||
},
|
||||
|
||||
(Slot::Equip(slot_a), Slot::Equip(slot_b)) => {
|
||||
loadout.map(|l| swap_loadout(slot_a, slot_b, l));
|
||||
loadout.map(|l| swap_loadout(slot_a, slot_b, l, map));
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -245,6 +265,7 @@ pub fn swap(
|
||||
/// use veloren_common::{
|
||||
/// assets::Asset,
|
||||
/// comp::{
|
||||
/// item::tool::AbilityMap,
|
||||
/// slot::{equip, EquipSlot},
|
||||
/// Inventory, Item,
|
||||
/// },
|
||||
@ -258,10 +279,12 @@ pub fn swap(
|
||||
///
|
||||
/// let mut loadout = LoadoutBuilder::new().defaults().build();
|
||||
///
|
||||
/// equip(0, &mut inv, &mut loadout);
|
||||
/// let map = AbilityMap::load_expect_cloned("common.abilities.weapon_ability_manifest");
|
||||
///
|
||||
/// equip(0, &mut inv, &mut loadout, &map);
|
||||
/// assert_eq!(Some(boots), loadout.foot);
|
||||
/// ```
|
||||
pub fn equip(slot: usize, inventory: &mut Inventory, loadout: &mut Loadout) {
|
||||
pub fn equip(slot: usize, inventory: &mut Inventory, loadout: &mut Loadout, map: &AbilityMap) {
|
||||
use armor::Armor;
|
||||
use item::{armor::ArmorKind, ItemKind};
|
||||
|
||||
@ -289,10 +312,10 @@ pub fn equip(slot: usize, inventory: &mut Inventory, loadout: &mut Loadout) {
|
||||
// If item is going to mainhand, put mainhand in offhand and place offhand in
|
||||
// inventory
|
||||
if let EquipSlot::Mainhand = equip_slot {
|
||||
swap_loadout(EquipSlot::Mainhand, EquipSlot::Offhand, loadout);
|
||||
swap_loadout(EquipSlot::Mainhand, EquipSlot::Offhand, loadout, map);
|
||||
}
|
||||
|
||||
swap_inventory_loadout(slot, equip_slot, inventory, loadout);
|
||||
swap_inventory_loadout(slot, equip_slot, inventory, loadout, map);
|
||||
}
|
||||
}
|
||||
|
||||
@ -301,7 +324,9 @@ pub fn equip(slot: usize, inventory: &mut Inventory, loadout: &mut Loadout) {
|
||||
///
|
||||
/// ```
|
||||
/// use veloren_common::{
|
||||
/// assets::Asset,
|
||||
/// comp::{
|
||||
/// item::tool::AbilityMap,
|
||||
/// slot::{unequip, EquipSlot},
|
||||
/// Inventory,
|
||||
/// },
|
||||
@ -310,22 +335,30 @@ pub fn equip(slot: usize, inventory: &mut Inventory, loadout: &mut Loadout) {
|
||||
///
|
||||
/// let mut inv = Inventory::new_empty();
|
||||
///
|
||||
/// let map = AbilityMap::load_expect_cloned("common.abilities.weapon_ability_manifest");
|
||||
///
|
||||
/// let mut loadout = LoadoutBuilder::new()
|
||||
/// .defaults()
|
||||
/// .active_item(Some(LoadoutBuilder::default_item_config_from_str(
|
||||
/// "common.items.weapons.sword.zweihander_sword_0",
|
||||
/// &map,
|
||||
/// )))
|
||||
/// .build();
|
||||
///
|
||||
/// let slot = EquipSlot::Mainhand;
|
||||
///
|
||||
/// unequip(slot, &mut inv, &mut loadout);
|
||||
/// unequip(slot, &mut inv, &mut loadout, &map);
|
||||
/// assert_eq!(None, loadout.active_item);
|
||||
/// ```
|
||||
pub fn unequip(slot: EquipSlot, inventory: &mut Inventory, loadout: &mut Loadout) {
|
||||
loadout_remove(slot, loadout) // Remove item from loadout
|
||||
pub fn unequip(
|
||||
slot: EquipSlot,
|
||||
inventory: &mut Inventory,
|
||||
loadout: &mut Loadout,
|
||||
map: &AbilityMap,
|
||||
) {
|
||||
loadout_remove(slot, loadout, map) // Remove item from loadout
|
||||
.and_then(|i| inventory.push(i)) // Insert into inventory
|
||||
.and_then(|i| loadout_insert(slot, i, loadout)) // If that fails put back in loadout
|
||||
.and_then(|i| loadout_insert(slot, i, loadout, map)) // If that fails put back in loadout
|
||||
.unwrap_none(); // Never fails
|
||||
}
|
||||
|
||||
@ -341,8 +374,12 @@ mod tests {
|
||||
amount: 0,
|
||||
};
|
||||
|
||||
use crate::assets::Asset;
|
||||
let map = AbilityMap::load_expect_cloned("common.abilities.weapon_ability_manifest");
|
||||
|
||||
let sword = LoadoutBuilder::default_item_config_from_str(
|
||||
"common.items.weapons.sword.zweihander_sword_0",
|
||||
&map,
|
||||
);
|
||||
|
||||
let mut loadout = LoadoutBuilder::new()
|
||||
@ -352,11 +389,11 @@ mod tests {
|
||||
.build();
|
||||
|
||||
assert_eq!(Some(sword.clone()), loadout.active_item);
|
||||
unequip(EquipSlot::Mainhand, &mut inv, &mut loadout);
|
||||
unequip(EquipSlot::Mainhand, &mut inv, &mut loadout, &map);
|
||||
// We have space in the inventory, so this should have unequipped
|
||||
assert_eq!(None, loadout.active_item);
|
||||
|
||||
unequip(EquipSlot::Offhand, &mut inv, &mut loadout);
|
||||
unequip(EquipSlot::Offhand, &mut inv, &mut loadout, &map);
|
||||
// There is no more space in the inventory, so this should still be equipped
|
||||
assert_eq!(Some(sword.clone()), loadout.second_item);
|
||||
|
||||
@ -382,9 +419,12 @@ mod tests {
|
||||
|
||||
let mut loadout = LoadoutBuilder::new().defaults().build();
|
||||
|
||||
use crate::assets::Asset;
|
||||
let map = AbilityMap::load_expect_cloned("common.abilities.weapon_ability_manifest");
|
||||
|
||||
// We should start with the starting sandles
|
||||
assert_eq!(starting_sandles, loadout.foot);
|
||||
equip(0, &mut inv, &mut loadout);
|
||||
equip(0, &mut inv, &mut loadout, &map);
|
||||
|
||||
// We should now have the testing boots equiped
|
||||
assert_eq!(boots, loadout.foot);
|
||||
@ -404,6 +444,9 @@ mod tests {
|
||||
"common.items.armor.starter.sandals_0",
|
||||
));
|
||||
|
||||
use crate::assets::Asset;
|
||||
let map = AbilityMap::load_expect_cloned("common.abilities.weapon_ability_manifest");
|
||||
|
||||
let mut loadout = LoadoutBuilder::new().defaults().build();
|
||||
|
||||
// We should start with the starting sandles
|
||||
@ -416,6 +459,7 @@ mod tests {
|
||||
EquipSlot::Armor(ArmorSlot::Feet),
|
||||
boots.clone(),
|
||||
&mut loadout,
|
||||
&map,
|
||||
)
|
||||
);
|
||||
|
||||
@ -425,8 +469,12 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_loadout_remove() {
|
||||
use crate::assets::Asset;
|
||||
let map = AbilityMap::load_expect_cloned("common.abilities.weapon_ability_manifest");
|
||||
|
||||
let sword = LoadoutBuilder::default_item_config_from_str(
|
||||
"common.items.weapons.sword.zweihander_sword_0",
|
||||
&map,
|
||||
);
|
||||
|
||||
let mut loadout = LoadoutBuilder::new()
|
||||
@ -437,7 +485,7 @@ mod tests {
|
||||
// The swap should return the sword
|
||||
assert_eq!(
|
||||
Some(sword.item),
|
||||
loadout_remove(EquipSlot::Mainhand, &mut loadout,)
|
||||
loadout_remove(EquipSlot::Mainhand, &mut loadout, &map)
|
||||
);
|
||||
|
||||
// We should now have nothing equiped
|
||||
|
@ -61,7 +61,7 @@ pub use phys::{
|
||||
Sticky, Vel,
|
||||
};
|
||||
pub use player::Player;
|
||||
pub use projectile::Projectile;
|
||||
pub use projectile::{Projectile, ProjectileConstructor};
|
||||
pub use shockwave::{Shockwave, ShockwaveHitEntities};
|
||||
pub use skills::{Skill, SkillGroup, SkillGroupType, SkillSet};
|
||||
pub use stats::{Exp, Level, Stats};
|
||||
|
@ -1,4 +1,9 @@
|
||||
use crate::{comp::Buff, sync::Uid, Damage, Explosion, GroupTarget, Knockback};
|
||||
use crate::{
|
||||
comp::buff::{BuffCategory, BuffData, BuffKind},
|
||||
effect::{self, BuffEffect},
|
||||
sync::Uid,
|
||||
Damage, DamageSource, Explosion, GroupTarget, Knockback, RadiusEffect,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specs::{Component, FlaggedStorage};
|
||||
use specs_idvs::IdvStorage;
|
||||
@ -13,7 +18,10 @@ pub enum Effect {
|
||||
Vanish,
|
||||
Stick,
|
||||
Possess,
|
||||
Buff { buff: Buff, chance: Option<f32> },
|
||||
Buff {
|
||||
buff: BuffEffect,
|
||||
chance: Option<f32>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
@ -32,3 +40,185 @@ pub struct Projectile {
|
||||
impl Component for Projectile {
|
||||
type Storage = FlaggedStorage<Self, IdvStorage<Self>>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ProjectileConstructor {
|
||||
Arrow {
|
||||
damage: f32,
|
||||
knockback: f32,
|
||||
energy_regen: u32,
|
||||
},
|
||||
Fireball {
|
||||
damage: f32,
|
||||
radius: f32,
|
||||
energy_regen: u32,
|
||||
},
|
||||
Heal {
|
||||
heal: f32,
|
||||
damage: f32,
|
||||
radius: f32,
|
||||
},
|
||||
Possess,
|
||||
}
|
||||
|
||||
impl ProjectileConstructor {
|
||||
pub fn create_projectile(self, owner: Option<Uid>) -> Projectile {
|
||||
use ProjectileConstructor::*;
|
||||
match self {
|
||||
Arrow {
|
||||
damage,
|
||||
knockback,
|
||||
energy_regen,
|
||||
} => {
|
||||
let buff = BuffEffect {
|
||||
kind: BuffKind::Bleeding,
|
||||
data: BuffData {
|
||||
strength: damage / 2.0,
|
||||
duration: Some(Duration::from_secs(5)),
|
||||
},
|
||||
cat_ids: vec![BuffCategory::Physical],
|
||||
};
|
||||
Projectile {
|
||||
hit_solid: vec![Effect::Stick],
|
||||
hit_entity: vec![
|
||||
Effect::Damage(Some(GroupTarget::OutOfGroup), Damage {
|
||||
source: DamageSource::Projectile,
|
||||
value: damage,
|
||||
}),
|
||||
Effect::Knockback(Knockback::Away(knockback)),
|
||||
Effect::RewardEnergy(energy_regen),
|
||||
Effect::Vanish,
|
||||
Effect::Buff {
|
||||
buff,
|
||||
chance: Some(0.10),
|
||||
},
|
||||
],
|
||||
time_left: Duration::from_secs(15),
|
||||
owner,
|
||||
ignore_group: true,
|
||||
}
|
||||
},
|
||||
Fireball {
|
||||
damage,
|
||||
radius,
|
||||
energy_regen,
|
||||
} => Projectile {
|
||||
hit_solid: vec![
|
||||
Effect::Explode(Explosion {
|
||||
effects: vec![RadiusEffect::Entity(
|
||||
Some(GroupTarget::OutOfGroup),
|
||||
effect::Effect::Damage(Damage {
|
||||
source: DamageSource::Explosion,
|
||||
value: damage,
|
||||
}),
|
||||
)],
|
||||
radius,
|
||||
energy_regen,
|
||||
}),
|
||||
Effect::Vanish,
|
||||
],
|
||||
hit_entity: vec![
|
||||
Effect::Explode(Explosion {
|
||||
effects: vec![RadiusEffect::Entity(
|
||||
Some(GroupTarget::OutOfGroup),
|
||||
effect::Effect::Damage(Damage {
|
||||
source: DamageSource::Explosion,
|
||||
value: damage,
|
||||
}),
|
||||
)],
|
||||
radius,
|
||||
energy_regen,
|
||||
}),
|
||||
Effect::Vanish,
|
||||
],
|
||||
time_left: Duration::from_secs(20),
|
||||
owner,
|
||||
ignore_group: true,
|
||||
},
|
||||
Heal {
|
||||
heal,
|
||||
damage,
|
||||
radius,
|
||||
} => Projectile {
|
||||
hit_solid: vec![
|
||||
Effect::Explode(Explosion {
|
||||
effects: vec![
|
||||
RadiusEffect::Entity(
|
||||
Some(GroupTarget::OutOfGroup),
|
||||
effect::Effect::Damage(Damage {
|
||||
source: DamageSource::Explosion,
|
||||
value: damage,
|
||||
}),
|
||||
),
|
||||
RadiusEffect::Entity(
|
||||
Some(GroupTarget::InGroup),
|
||||
effect::Effect::Damage(Damage {
|
||||
source: DamageSource::Healing,
|
||||
value: heal,
|
||||
}),
|
||||
),
|
||||
],
|
||||
radius,
|
||||
energy_regen: 0,
|
||||
}),
|
||||
Effect::Vanish,
|
||||
],
|
||||
hit_entity: vec![
|
||||
Effect::Explode(Explosion {
|
||||
effects: vec![
|
||||
RadiusEffect::Entity(
|
||||
Some(GroupTarget::OutOfGroup),
|
||||
effect::Effect::Damage(Damage {
|
||||
source: DamageSource::Explosion,
|
||||
value: damage,
|
||||
}),
|
||||
),
|
||||
RadiusEffect::Entity(
|
||||
Some(GroupTarget::InGroup),
|
||||
effect::Effect::Damage(Damage {
|
||||
source: DamageSource::Healing,
|
||||
value: heal,
|
||||
}),
|
||||
),
|
||||
],
|
||||
radius,
|
||||
energy_regen: 0,
|
||||
}),
|
||||
Effect::Vanish,
|
||||
],
|
||||
time_left: Duration::from_secs(20),
|
||||
owner,
|
||||
ignore_group: true,
|
||||
},
|
||||
Possess => Projectile {
|
||||
hit_solid: vec![Effect::Stick],
|
||||
hit_entity: vec![Effect::Stick, Effect::Possess],
|
||||
time_left: Duration::from_secs(10),
|
||||
owner,
|
||||
ignore_group: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn modified_projectile(mut self, power: f32) -> Self {
|
||||
use ProjectileConstructor::*;
|
||||
match self {
|
||||
Arrow { ref mut damage, .. } => {
|
||||
*damage *= power;
|
||||
},
|
||||
Fireball { ref mut damage, .. } => {
|
||||
*damage *= power;
|
||||
},
|
||||
Heal {
|
||||
ref mut damage,
|
||||
ref mut heal,
|
||||
..
|
||||
} => {
|
||||
*damage *= power;
|
||||
*heal *= power;
|
||||
},
|
||||
Possess => {},
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,28 @@
|
||||
use crate::comp::{
|
||||
biped_large, golem,
|
||||
item::{Item, ItemKind},
|
||||
item::{tool::AbilityMap, Item, ItemKind},
|
||||
Alignment, Body, CharacterAbility, ItemConfig, Loadout,
|
||||
};
|
||||
use rand::Rng;
|
||||
use std::time::Duration;
|
||||
|
||||
/// Builder for character Loadouts, containing weapon and armour items belonging
|
||||
/// to a character, along with some helper methods for loading Items and
|
||||
/// ItemConfig
|
||||
///
|
||||
/// ```
|
||||
/// use veloren_common::LoadoutBuilder;
|
||||
/// use veloren_common::{
|
||||
/// assets::Asset,
|
||||
/// comp::item::tool::AbilityMap,
|
||||
/// LoadoutBuilder,
|
||||
/// };
|
||||
///
|
||||
/// let map = AbilityMap::load_expect_cloned("common.abilities.weapon_ability_manifest");
|
||||
///
|
||||
/// // Build a loadout with character starter defaults and a specific sword with default sword abilities
|
||||
/// let loadout = LoadoutBuilder::new()
|
||||
/// .defaults()
|
||||
/// .active_item(Some(LoadoutBuilder::default_item_config_from_str(
|
||||
/// "common.items.weapons.sword.zweihander_sword_0"
|
||||
/// "common.items.weapons.sword.zweihander_sword_0", &map
|
||||
/// )))
|
||||
/// .build();
|
||||
/// ```
|
||||
@ -72,6 +77,7 @@ impl LoadoutBuilder {
|
||||
alignment: Alignment,
|
||||
mut main_tool: Option<Item>,
|
||||
is_giant: bool,
|
||||
map: &AbilityMap,
|
||||
) -> Self {
|
||||
match body {
|
||||
Body::Golem(golem) => match golem.species {
|
||||
@ -145,21 +151,12 @@ impl LoadoutBuilder {
|
||||
};
|
||||
|
||||
let active_item = if let Some(ItemKind::Tool(_)) = main_tool.as_ref().map(|i| i.kind()) {
|
||||
main_tool.map(ItemConfig::from)
|
||||
main_tool.map(|item| ItemConfig::from((item, map)))
|
||||
} else {
|
||||
Some(ItemConfig {
|
||||
// We need the empty item so npcs can attack
|
||||
item: Item::new_from_asset_expect("common.items.weapons.empty.empty"),
|
||||
ability1: Some(CharacterAbility::BasicMelee {
|
||||
energy_cost: 0,
|
||||
buildup_duration: Duration::from_millis(0),
|
||||
swing_duration: Duration::from_millis(100),
|
||||
recover_duration: Duration::from_millis(300),
|
||||
base_damage: 40,
|
||||
knockback: 0.0,
|
||||
range: 3.5,
|
||||
max_angle: 15.0,
|
||||
}),
|
||||
ability1: Some(CharacterAbility::default()),
|
||||
ability2: None,
|
||||
ability3: None,
|
||||
block_ability: None,
|
||||
@ -334,9 +331,9 @@ impl LoadoutBuilder {
|
||||
item: Item::new_from_asset_expect("common.items.weapons.empty.empty"),
|
||||
ability1: Some(CharacterAbility::BasicMelee {
|
||||
energy_cost: 10,
|
||||
buildup_duration: Duration::from_millis(500),
|
||||
swing_duration: Duration::from_millis(100),
|
||||
recover_duration: Duration::from_millis(100),
|
||||
buildup_duration: 500,
|
||||
swing_duration: 100,
|
||||
recover_duration: 100,
|
||||
base_damage: body.base_dmg(),
|
||||
knockback: 0.0,
|
||||
range: body.base_range(),
|
||||
@ -370,7 +367,9 @@ impl LoadoutBuilder {
|
||||
/// abilities or their timings is desired, you should create and provide
|
||||
/// the item config directly to the [active_item](#method.active_item)
|
||||
/// method
|
||||
pub fn default_item_config_from_item(item: Item) -> ItemConfig { ItemConfig::from(item) }
|
||||
pub fn default_item_config_from_item(item: Item, map: &AbilityMap) -> ItemConfig {
|
||||
ItemConfig::from((item, map))
|
||||
}
|
||||
|
||||
/// Get an item's (weapon's) default
|
||||
/// [ItemConfig](../comp/struct.ItemConfig.html)
|
||||
@ -378,8 +377,8 @@ impl LoadoutBuilder {
|
||||
/// the default abilities for that item via the
|
||||
/// [default_item_config_from_item](#method.default_item_config_from_item)
|
||||
/// function
|
||||
pub fn default_item_config_from_str(item_ref: &str) -> ItemConfig {
|
||||
Self::default_item_config_from_item(Item::new_from_asset_expect(item_ref))
|
||||
pub fn default_item_config_from_str(item_ref: &str, map: &AbilityMap) -> ItemConfig {
|
||||
Self::default_item_config_from_item(Item::new_from_asset_expect(item_ref), map)
|
||||
}
|
||||
|
||||
pub fn active_item(mut self, item: Option<ItemConfig>) -> Self {
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::{
|
||||
assets::Asset,
|
||||
comp,
|
||||
event::{EventBus, LocalEvent, ServerEvent},
|
||||
metrics::{PhysicsMetrics, SysMetrics},
|
||||
@ -180,6 +181,9 @@ impl State {
|
||||
ecs.insert(BlockChange::default());
|
||||
ecs.insert(TerrainChanges::default());
|
||||
ecs.insert(EventBus::<LocalEvent>::default());
|
||||
ecs.insert(comp::item::tool::AbilityMap::load_expect_cloned(
|
||||
"common.abilities.weapon_ability_manifest",
|
||||
));
|
||||
// TODO: only register on the server
|
||||
ecs.insert(EventBus::<ServerEvent>::default());
|
||||
ecs.insert(comp::group::GroupManager::default());
|
||||
@ -253,6 +257,9 @@ impl State {
|
||||
/// Get the current delta time.
|
||||
pub fn get_delta_time(&self) -> f32 { self.ecs.read_resource::<DeltaTime>().0 }
|
||||
|
||||
/// Get a reference to this state's ability map.
|
||||
pub fn ability_map(&self) -> Fetch<comp::item::tool::AbilityMap> { self.ecs.read_resource() }
|
||||
|
||||
/// Get a reference to this state's terrain.
|
||||
pub fn terrain(&self) -> Fetch<TerrainGrid> { self.ecs.read_resource() }
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
comp::{Body, CharacterState, Gravity, LightEmitter, Projectile, StateUpdate},
|
||||
comp::{Body, CharacterState, Gravity, LightEmitter, ProjectileConstructor, StateUpdate},
|
||||
event::ServerEvent,
|
||||
states::utils::*,
|
||||
sys::character_behavior::{CharacterBehavior, JoinData},
|
||||
@ -8,14 +8,14 @@ use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
|
||||
/// Separated out to condense update portions of character state
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct StaticData {
|
||||
/// How much buildup is required before the attack
|
||||
pub buildup_duration: Duration,
|
||||
/// How long the state has until exiting
|
||||
pub recover_duration: Duration,
|
||||
/// Projectile variables
|
||||
pub projectile: Projectile,
|
||||
pub projectile: ProjectileConstructor,
|
||||
pub projectile_body: Body,
|
||||
pub projectile_light: Option<LightEmitter>,
|
||||
pub projectile_gravity: Option<Gravity>,
|
||||
@ -54,7 +54,6 @@ impl CharacterBehavior for Data {
|
||||
if self.timer < self.static_data.buildup_duration {
|
||||
// Build up
|
||||
update.character = CharacterState::BasicRanged(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||
@ -64,7 +63,6 @@ impl CharacterBehavior for Data {
|
||||
} else {
|
||||
// Transitions to recover section of stage
|
||||
update.character = CharacterState::BasicRanged(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Recover,
|
||||
..*self
|
||||
@ -74,8 +72,10 @@ impl CharacterBehavior for Data {
|
||||
StageSection::Recover => {
|
||||
if !self.exhausted {
|
||||
// Fire
|
||||
let mut projectile = self.static_data.projectile.clone();
|
||||
projectile.owner = Some(*data.uid);
|
||||
let projectile = self
|
||||
.static_data
|
||||
.projectile
|
||||
.create_projectile(Some(*data.uid));
|
||||
update.server_events.push_front(ServerEvent::Shoot {
|
||||
entity: data.entity,
|
||||
dir: data.inputs.look_dir,
|
||||
@ -87,7 +87,6 @@ impl CharacterBehavior for Data {
|
||||
});
|
||||
|
||||
update.character = CharacterState::BasicRanged(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
exhausted: true,
|
||||
continue_next: false,
|
||||
..*self
|
||||
@ -96,7 +95,6 @@ impl CharacterBehavior for Data {
|
||||
if ability_key_is_pressed(data, self.static_data.ability_key) {
|
||||
// Recovers
|
||||
update.character = CharacterState::BasicRanged(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||
@ -107,7 +105,6 @@ impl CharacterBehavior for Data {
|
||||
} else {
|
||||
// Recovers
|
||||
update.character = CharacterState::BasicRanged(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||
@ -118,7 +115,6 @@ impl CharacterBehavior for Data {
|
||||
} else if self.continue_next {
|
||||
// Restarts character state
|
||||
update.character = CharacterState::BasicRanged(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Buildup,
|
||||
exhausted: false,
|
||||
|
@ -1,9 +1,10 @@
|
||||
use crate::{
|
||||
comp::{
|
||||
buff::{Buff, BuffCategory, BuffData, BuffKind, BuffSource},
|
||||
buff::{BuffCategory, BuffData, BuffKind},
|
||||
projectile, Body, CharacterState, EnergyChange, EnergySource, Gravity, LightEmitter,
|
||||
Projectile, StateUpdate,
|
||||
},
|
||||
effect::BuffEffect,
|
||||
event::ServerEvent,
|
||||
states::utils::*,
|
||||
sys::character_behavior::{CharacterBehavior, JoinData},
|
||||
@ -98,30 +99,28 @@ impl CharacterBehavior for Data {
|
||||
* (self.static_data.max_knockback - self.static_data.initial_knockback)
|
||||
as f32);
|
||||
// Fire
|
||||
let mut projectile = Projectile {
|
||||
let projectile = Projectile {
|
||||
hit_solid: vec![projectile::Effect::Stick],
|
||||
hit_entity: vec![
|
||||
projectile::Effect::Damage(Some(GroupTarget::OutOfGroup), damage),
|
||||
projectile::Effect::Knockback(Knockback::Away(knockback)),
|
||||
projectile::Effect::Vanish,
|
||||
projectile::Effect::Buff {
|
||||
buff: Buff::new(
|
||||
BuffKind::Bleeding,
|
||||
BuffData {
|
||||
buff: BuffEffect {
|
||||
kind: BuffKind::Bleeding,
|
||||
data: BuffData {
|
||||
strength: damage.value / 5.0,
|
||||
duration: Some(Duration::from_secs(5)),
|
||||
},
|
||||
vec![BuffCategory::Physical],
|
||||
BuffSource::Unknown,
|
||||
),
|
||||
cat_ids: vec![BuffCategory::Physical],
|
||||
},
|
||||
chance: Some(0.10),
|
||||
},
|
||||
],
|
||||
time_left: Duration::from_secs(15),
|
||||
owner: None,
|
||||
owner: Some(*data.uid),
|
||||
ignore_group: true,
|
||||
};
|
||||
projectile.owner = Some(*data.uid);
|
||||
update.server_events.push_front(ServerEvent::Shoot {
|
||||
entity: data.entity,
|
||||
dir: data.inputs.look_dir,
|
||||
|
@ -7,8 +7,8 @@ use crate::{
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Stage {
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Stage<T> {
|
||||
/// Specifies which stage the combo attack is in
|
||||
pub stage: u32,
|
||||
/// Initial damage of stage
|
||||
@ -24,23 +24,51 @@ pub struct Stage {
|
||||
/// Angle of attack
|
||||
pub angle: f32,
|
||||
/// Initial buildup duration of stage (how long until state can deal damage)
|
||||
pub base_buildup_duration: Duration,
|
||||
pub base_buildup_duration: T,
|
||||
/// Duration of stage spent in swing (controls animation stuff, and can also
|
||||
/// be used to handle movement separately to buildup)
|
||||
pub base_swing_duration: Duration,
|
||||
pub base_swing_duration: T,
|
||||
/// Initial recover duration of stage (how long until character exits state)
|
||||
pub base_recover_duration: Duration,
|
||||
pub base_recover_duration: T,
|
||||
/// How much forward movement there is in the swing portion of the stage
|
||||
pub forward_movement: f32,
|
||||
}
|
||||
|
||||
impl Stage<u64> {
|
||||
pub fn to_duration(self) -> Stage<Duration> {
|
||||
Stage::<Duration> {
|
||||
stage: self.stage,
|
||||
base_damage: self.base_damage,
|
||||
max_damage: self.max_damage,
|
||||
damage_increase: self.damage_increase,
|
||||
knockback: self.knockback,
|
||||
range: self.range,
|
||||
angle: self.angle,
|
||||
base_buildup_duration: Duration::from_millis(self.base_buildup_duration),
|
||||
base_swing_duration: Duration::from_millis(self.base_swing_duration),
|
||||
base_recover_duration: Duration::from_millis(self.base_recover_duration),
|
||||
forward_movement: self.forward_movement,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn adjusted_by_stats(mut self, power: f32, speed: f32) -> Self {
|
||||
self.base_damage = (self.base_damage as f32 * power) as u32;
|
||||
self.max_damage = (self.max_damage as f32 * power) as u32;
|
||||
self.damage_increase = (self.damage_increase as f32 * power) as u32;
|
||||
self.base_buildup_duration = (self.base_buildup_duration as f32 / speed) as u64;
|
||||
self.base_swing_duration = (self.base_swing_duration as f32 / speed) as u64;
|
||||
self.base_recover_duration = (self.base_recover_duration as f32 / speed) as u64;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
/// Separated out to condense update portions of character state
|
||||
pub struct StaticData {
|
||||
/// Indicates number of stages in combo
|
||||
pub num_stages: u32,
|
||||
/// Data for each stage
|
||||
pub stage_data: Vec<Stage>,
|
||||
pub stage_data: Vec<Stage<Duration>>,
|
||||
/// Initial energy gain per strike
|
||||
pub initial_energy_gain: u32,
|
||||
/// Max energy gain per strike
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
comp::{Body, CharacterState, Gravity, LightEmitter, Projectile, StateUpdate},
|
||||
comp::{Body, CharacterState, Gravity, LightEmitter, ProjectileConstructor, StateUpdate},
|
||||
event::ServerEvent,
|
||||
states::utils::{StageSection, *},
|
||||
sys::character_behavior::*,
|
||||
@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use vek::Vec3;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
/// Separated out to condense update portions of character state
|
||||
pub struct StaticData {
|
||||
/// How long the state is in movement
|
||||
@ -23,7 +23,7 @@ pub struct StaticData {
|
||||
/// Whether there should be a jump and how strong the leap is
|
||||
pub leap: Option<f32>,
|
||||
/// Projectile options
|
||||
pub projectile: Projectile,
|
||||
pub projectile: ProjectileConstructor,
|
||||
pub projectile_body: Body,
|
||||
pub projectile_light: Option<LightEmitter>,
|
||||
pub projectile_gravity: Option<Gravity>,
|
||||
@ -71,7 +71,6 @@ impl CharacterBehavior for Data {
|
||||
if self.timer < self.static_data.movement_duration {
|
||||
// Do movement
|
||||
update.character = CharacterState::RepeaterRanged(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||
@ -81,7 +80,6 @@ impl CharacterBehavior for Data {
|
||||
} else {
|
||||
// Transition to buildup
|
||||
update.character = CharacterState::RepeaterRanged(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Buildup,
|
||||
..*self
|
||||
@ -101,7 +99,6 @@ impl CharacterBehavior for Data {
|
||||
if self.timer < self.static_data.buildup_duration {
|
||||
// Buildup to attack
|
||||
update.character = CharacterState::RepeaterRanged(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||
@ -111,7 +108,6 @@ impl CharacterBehavior for Data {
|
||||
} else {
|
||||
// Transition to shoot
|
||||
update.character = CharacterState::RepeaterRanged(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Shoot,
|
||||
..*self
|
||||
@ -125,8 +121,10 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
if self.reps_remaining > 0 {
|
||||
// Fire
|
||||
let mut projectile = self.static_data.projectile.clone();
|
||||
projectile.owner = Some(*data.uid);
|
||||
let projectile = self
|
||||
.static_data
|
||||
.projectile
|
||||
.create_projectile(Some(*data.uid));
|
||||
update.server_events.push_front(ServerEvent::Shoot {
|
||||
entity: data.entity,
|
||||
// Provides slight variation to projectile direction
|
||||
@ -155,7 +153,6 @@ impl CharacterBehavior for Data {
|
||||
|
||||
// Shoot projectiles
|
||||
update.character = CharacterState::RepeaterRanged(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||
@ -166,7 +163,6 @@ impl CharacterBehavior for Data {
|
||||
} else if self.timer < self.static_data.shoot_duration {
|
||||
// Finish shooting
|
||||
update.character = CharacterState::RepeaterRanged(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||
@ -176,7 +172,6 @@ impl CharacterBehavior for Data {
|
||||
} else {
|
||||
// Transition to recover
|
||||
update.character = CharacterState::RepeaterRanged(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Recover,
|
||||
..*self
|
||||
@ -190,7 +185,6 @@ impl CharacterBehavior for Data {
|
||||
} else if self.timer < self.static_data.recover_duration {
|
||||
// Recover from attack
|
||||
update.character = CharacterState::RepeaterRanged(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
comp::{
|
||||
buff::{BuffChange, BuffSource},
|
||||
buff::{Buff, BuffChange, BuffSource},
|
||||
projectile, EnergyChange, EnergySource, Group, HealthSource, Loadout, Ori, PhysicsState,
|
||||
Pos, Projectile, Vel,
|
||||
},
|
||||
@ -176,10 +176,13 @@ impl<'a> System<'a> for Sys {
|
||||
uid_allocator.retrieve_entity_internal(other.into())
|
||||
{
|
||||
if chance.map_or(true, |c| thread_rng().gen::<f32>() < c) {
|
||||
let mut buff = buff.clone();
|
||||
if let Some(uid) = projectile.owner {
|
||||
buff.source = BuffSource::Character { by: uid };
|
||||
}
|
||||
let source = if let Some(owner) = projectile.owner {
|
||||
BuffSource::Character { by: owner }
|
||||
} else {
|
||||
BuffSource::Unknown
|
||||
};
|
||||
let buff =
|
||||
Buff::new(buff.kind, buff.data, buff.cat_ids, source);
|
||||
server_emitter.emit(ServerEvent::Buff {
|
||||
entity,
|
||||
buff_change: BuffChange::Add(buff),
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::persistence::character_loader::CharacterLoader;
|
||||
use common::{
|
||||
comp::{Body, Inventory, Stats},
|
||||
comp::{item::tool::AbilityMap, Body, Inventory, Stats},
|
||||
loadout_builder::LoadoutBuilder,
|
||||
};
|
||||
use specs::{Entity, ReadExpect};
|
||||
@ -12,6 +12,7 @@ pub fn create_character(
|
||||
character_tool: Option<String>,
|
||||
body: Body,
|
||||
character_loader: &ReadExpect<'_, CharacterLoader>,
|
||||
map: &AbilityMap,
|
||||
) {
|
||||
let stats = Stats::new(character_alias.to_string(), body);
|
||||
|
||||
@ -19,6 +20,7 @@ pub fn create_character(
|
||||
.defaults()
|
||||
.active_item(Some(LoadoutBuilder::default_item_config_from_str(
|
||||
character_tool.as_deref().unwrap(),
|
||||
map,
|
||||
)))
|
||||
.build();
|
||||
|
||||
|
@ -655,14 +655,19 @@ fn handle_spawn(
|
||||
|
||||
let body = body();
|
||||
|
||||
let map = server.state().ability_map();
|
||||
let loadout =
|
||||
LoadoutBuilder::build_loadout(body, alignment, None, false, &map)
|
||||
.build();
|
||||
drop(map);
|
||||
|
||||
let mut entity_base = server
|
||||
.state
|
||||
.create_npc(
|
||||
pos,
|
||||
comp::Stats::new(get_npc_name(id).into(), body),
|
||||
comp::Health::new(body, 1),
|
||||
LoadoutBuilder::build_loadout(body, alignment, None, false)
|
||||
.build(),
|
||||
loadout,
|
||||
body,
|
||||
)
|
||||
.with(comp::Vel(vel))
|
||||
|
@ -4,7 +4,11 @@ use crate::{
|
||||
Server,
|
||||
};
|
||||
use common::{
|
||||
comp::{self, item, Pos},
|
||||
comp::{
|
||||
self,
|
||||
item::{self, tool::AbilityMap},
|
||||
Pos,
|
||||
},
|
||||
consts::MAX_MOUNT_RANGE,
|
||||
msg::ServerGeneral,
|
||||
sync::{Uid, WorldSyncExt},
|
||||
@ -103,8 +107,8 @@ pub fn handle_unmount(server: &mut Server, mounter: EcsEntity) {
|
||||
|
||||
#[allow(clippy::nonminimal_bool)] // TODO: Pending review in #587
|
||||
pub fn handle_possess(server: &Server, possessor_uid: Uid, possesse_uid: Uid) {
|
||||
let state = &server.state;
|
||||
let ecs = state.ecs();
|
||||
let ecs = &server.state.ecs();
|
||||
let ability_map = ecs.fetch::<AbilityMap>();
|
||||
if let (Some(possessor), Some(possesse)) = (
|
||||
ecs.entity_from_uid(possessor_uid.into()),
|
||||
ecs.entity_from_uid(possesse_uid.into()),
|
||||
@ -177,7 +181,7 @@ pub fn handle_possess(server: &Server, possessor_uid: Uid, possesse_uid: Uid) {
|
||||
|
||||
let item = comp::Item::new_from_asset_expect("common.items.debug.possess");
|
||||
if let item::ItemKind::Tool(_) = item.kind() {
|
||||
let debug_item = comp::ItemConfig::from(item);
|
||||
let debug_item = comp::ItemConfig::from((item, &*ability_map));
|
||||
std::mem::swap(&mut loadout.active_item, &mut loadout.second_item);
|
||||
loadout.active_item = Some(debug_item);
|
||||
}
|
||||
|
@ -203,7 +203,8 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
|
||||
if let Some(lantern) = lantern_opt {
|
||||
swap_lantern(&mut state.ecs().write_storage(), entity, &lantern);
|
||||
}
|
||||
slot::equip(slot, inventory, loadout);
|
||||
let ability_map = state.ability_map();
|
||||
slot::equip(slot, inventory, loadout, &ability_map);
|
||||
Some(comp::InventoryUpdateEvent::Used)
|
||||
} else {
|
||||
None
|
||||
@ -338,7 +339,8 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
|
||||
if slot == slot::EquipSlot::Lantern {
|
||||
snuff_lantern(&mut state.ecs().write_storage(), entity);
|
||||
}
|
||||
slot::unequip(slot, inventory, loadout);
|
||||
let ability_map = state.ability_map();
|
||||
slot::unequip(slot, inventory, loadout, &ability_map);
|
||||
Some(comp::InventoryUpdateEvent::Used)
|
||||
} else {
|
||||
error!(?entity, "Entity doesn't have a loadout, can't unequip...");
|
||||
@ -364,12 +366,14 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
|
||||
let mut loadouts = ecs.write_storage();
|
||||
let inventory = inventories.get_mut(entity);
|
||||
let loadout = loadouts.get_mut(entity);
|
||||
let ability_map = state.ability_map();
|
||||
|
||||
slot::swap(a, b, inventory, loadout);
|
||||
slot::swap(a, b, inventory, loadout, &ability_map);
|
||||
|
||||
// :/
|
||||
drop(loadouts);
|
||||
drop(inventories);
|
||||
drop(ability_map);
|
||||
|
||||
state.write_component(
|
||||
entity,
|
||||
@ -378,6 +382,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
|
||||
},
|
||||
|
||||
comp::InventoryManip::Drop(slot) => {
|
||||
let ability_map = state.ability_map();
|
||||
let item = match slot {
|
||||
Slot::Inventory(slot) => state
|
||||
.ecs()
|
||||
@ -388,8 +393,9 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
|
||||
.ecs()
|
||||
.write_storage()
|
||||
.get_mut(entity)
|
||||
.and_then(|ldt| slot::loadout_remove(slot, ldt)),
|
||||
.and_then(|ldt| slot::loadout_remove(slot, ldt, &ability_map)),
|
||||
};
|
||||
drop(ability_map);
|
||||
|
||||
// FIXME: We should really require the drop and write to be atomic!
|
||||
if let (Some(mut item), Some(pos)) =
|
||||
|
@ -159,9 +159,9 @@ impl Server {
|
||||
state
|
||||
.ecs_mut()
|
||||
.insert(CharacterUpdater::new(&persistence_db_dir)?);
|
||||
state
|
||||
.ecs_mut()
|
||||
.insert(CharacterLoader::new(&persistence_db_dir)?);
|
||||
|
||||
let character_loader = CharacterLoader::new(&persistence_db_dir, &*state.ability_map());
|
||||
state.ecs_mut().insert(character_loader?);
|
||||
state.ecs_mut().insert(Vec::<Outcome>::new());
|
||||
|
||||
// System timers for performance monitoring
|
||||
|
@ -25,6 +25,7 @@ use crate::{
|
||||
};
|
||||
use common::{
|
||||
character::{CharacterId, CharacterItem, MAX_CHARACTERS_PER_PLAYER},
|
||||
comp::item::tool::AbilityMap,
|
||||
state::Time,
|
||||
};
|
||||
use core::ops::Range;
|
||||
@ -60,6 +61,7 @@ pub fn load_character_data(
|
||||
requesting_player_uuid: String,
|
||||
char_id: CharacterId,
|
||||
connection: VelorenTransaction,
|
||||
map: &AbilityMap,
|
||||
) -> CharacterDataResult {
|
||||
use schema::{body::dsl::*, character::dsl::*, item::dsl::*, stats::dsl::*};
|
||||
|
||||
@ -102,7 +104,7 @@ pub fn load_character_data(
|
||||
convert_body_from_database(&char_body)?,
|
||||
convert_stats_from_database(&stats_data, character_data.alias),
|
||||
convert_inventory_from_database_items(&inventory_items)?,
|
||||
convert_loadout_from_database_items(&loadout_items)?,
|
||||
convert_loadout_from_database_items(&loadout_items, map)?,
|
||||
waypoint,
|
||||
))
|
||||
}
|
||||
@ -117,6 +119,7 @@ pub fn load_character_data(
|
||||
pub fn load_character_list(
|
||||
player_uuid_: &str,
|
||||
connection: VelorenTransaction,
|
||||
map: &AbilityMap,
|
||||
) -> CharacterListResult {
|
||||
use schema::{body::dsl::*, character::dsl::*, item::dsl::*, stats::dsl::*};
|
||||
|
||||
@ -149,7 +152,7 @@ pub fn load_character_list(
|
||||
.filter(parent_container_item_id.eq(loadout_container_id))
|
||||
.load::<Item>(&*connection)?;
|
||||
|
||||
let loadout = convert_loadout_from_database_items(&loadout_items)?;
|
||||
let loadout = convert_loadout_from_database_items(&loadout_items, map)?;
|
||||
|
||||
Ok(CharacterItem {
|
||||
character: char,
|
||||
@ -166,6 +169,7 @@ pub fn create_character(
|
||||
character_alias: &str,
|
||||
persisted_components: PersistedComponents,
|
||||
connection: VelorenTransaction,
|
||||
map: &AbilityMap,
|
||||
) -> CharacterListResult {
|
||||
use schema::item::dsl::*;
|
||||
|
||||
@ -299,7 +303,7 @@ pub fn create_character(
|
||||
)));
|
||||
}
|
||||
|
||||
load_character_list(uuid, connection)
|
||||
load_character_list(uuid, connection, map)
|
||||
}
|
||||
|
||||
/// Delete a character. Returns the updated character list.
|
||||
@ -307,6 +311,7 @@ pub fn delete_character(
|
||||
requesting_player_uuid: &str,
|
||||
char_id: CharacterId,
|
||||
connection: VelorenTransaction,
|
||||
map: &AbilityMap,
|
||||
) -> CharacterListResult {
|
||||
use schema::{body::dsl::*, character::dsl::*, stats::dsl::*};
|
||||
|
||||
@ -387,7 +392,7 @@ pub fn delete_character(
|
||||
)));
|
||||
}
|
||||
|
||||
load_character_list(requesting_player_uuid, connection)
|
||||
load_character_list(requesting_player_uuid, connection, map)
|
||||
}
|
||||
|
||||
/// Before creating a character, we ensure that the limit on the number of
|
||||
|
@ -9,7 +9,7 @@ use crate::persistence::{
|
||||
};
|
||||
use common::{
|
||||
character::CharacterId,
|
||||
comp::{Body as CompBody, *},
|
||||
comp::{item::tool::AbilityMap, Body as CompBody, *},
|
||||
loadout_builder,
|
||||
};
|
||||
use core::{convert::TryFrom, num::NonZeroU64};
|
||||
@ -240,7 +240,10 @@ pub fn convert_inventory_from_database_items(database_items: &[Item]) -> Result<
|
||||
Ok(inventory)
|
||||
}
|
||||
|
||||
pub fn convert_loadout_from_database_items(database_items: &[Item]) -> Result<Loadout, Error> {
|
||||
pub fn convert_loadout_from_database_items(
|
||||
database_items: &[Item],
|
||||
map: &AbilityMap,
|
||||
) -> Result<Loadout, Error> {
|
||||
let mut loadout = loadout_builder::LoadoutBuilder::new();
|
||||
for db_item in database_items.iter() {
|
||||
let item = common::comp::Item::new_from_asset(db_item.item_definition_id.as_str())?;
|
||||
@ -251,8 +254,8 @@ pub fn convert_loadout_from_database_items(database_items: &[Item]) -> Result<Lo
|
||||
)?));
|
||||
|
||||
match db_item.position.as_str() {
|
||||
"active_item" => loadout = loadout.active_item(Some(ItemConfig::from(item))),
|
||||
"second_item" => loadout = loadout.second_item(Some(ItemConfig::from(item))),
|
||||
"active_item" => loadout = loadout.active_item(Some(ItemConfig::from((item, map)))),
|
||||
"second_item" => loadout = loadout.second_item(Some(ItemConfig::from((item, map)))),
|
||||
"lantern" => loadout = loadout.lantern(Some(item)),
|
||||
"shoulder" => loadout = loadout.shoulder(Some(item)),
|
||||
"chest" => loadout = loadout.chest(Some(item)),
|
||||
|
@ -3,7 +3,10 @@ use crate::persistence::{
|
||||
error::Error,
|
||||
establish_connection, PersistedComponents,
|
||||
};
|
||||
use common::character::{CharacterId, CharacterItem};
|
||||
use common::{
|
||||
character::{CharacterId, CharacterItem},
|
||||
comp::item::tool::AbilityMap,
|
||||
};
|
||||
use crossbeam::{channel, channel::TryIter};
|
||||
use std::path::Path;
|
||||
use tracing::error;
|
||||
@ -65,12 +68,14 @@ pub struct CharacterLoader {
|
||||
}
|
||||
|
||||
impl CharacterLoader {
|
||||
pub fn new(db_dir: &Path) -> diesel::QueryResult<Self> {
|
||||
pub fn new(db_dir: &Path, map: &AbilityMap) -> diesel::QueryResult<Self> {
|
||||
let (update_tx, internal_rx) = channel::unbounded::<CharacterLoaderRequest>();
|
||||
let (internal_tx, update_rx) = channel::unbounded::<CharacterLoaderResponse>();
|
||||
|
||||
let mut conn = establish_connection(db_dir)?;
|
||||
|
||||
let map = map.clone();
|
||||
|
||||
std::thread::spawn(move || {
|
||||
for request in internal_rx {
|
||||
let (entity, kind) = request;
|
||||
@ -88,19 +93,20 @@ impl CharacterLoader {
|
||||
&character_alias,
|
||||
persisted_components,
|
||||
txn,
|
||||
&map,
|
||||
)
|
||||
})),
|
||||
CharacterLoaderRequestKind::DeleteCharacter {
|
||||
player_uuid,
|
||||
character_id,
|
||||
} => {
|
||||
CharacterLoaderResponseType::CharacterList(conn.transaction(|txn| {
|
||||
delete_character(&player_uuid, character_id, txn)
|
||||
}))
|
||||
},
|
||||
} => CharacterLoaderResponseType::CharacterList(conn.transaction(|txn| {
|
||||
delete_character(&player_uuid, character_id, txn, &map)
|
||||
})),
|
||||
CharacterLoaderRequestKind::LoadCharacterList { player_uuid } => {
|
||||
CharacterLoaderResponseType::CharacterList(
|
||||
conn.transaction(|txn| load_character_list(&player_uuid, txn)),
|
||||
conn.transaction(|txn| {
|
||||
load_character_list(&player_uuid, txn, &map)
|
||||
}),
|
||||
)
|
||||
},
|
||||
CharacterLoaderRequestKind::LoadCharacterData {
|
||||
@ -108,7 +114,7 @@ impl CharacterLoader {
|
||||
character_id,
|
||||
} => {
|
||||
CharacterLoaderResponseType::CharacterData(Box::new(conn.transaction(
|
||||
|txn| load_character_data(player_uuid, character_id, txn),
|
||||
|txn| load_character_data(player_uuid, character_id, txn, &map),
|
||||
)))
|
||||
},
|
||||
},
|
||||
|
@ -4,7 +4,7 @@ use crate::{
|
||||
persistence::character_loader::CharacterLoader, presence::Presence, EditableSettings,
|
||||
};
|
||||
use common::{
|
||||
comp::{ChatType, Player, UnresolvedChatMsg},
|
||||
comp::{item::tool::AbilityMap, ChatType, Player, UnresolvedChatMsg},
|
||||
event::{EventBus, ServerEvent},
|
||||
msg::{ClientGeneral, ServerGeneral},
|
||||
span,
|
||||
@ -28,6 +28,7 @@ impl Sys {
|
||||
editable_settings: &ReadExpect<'_, EditableSettings>,
|
||||
alias_validator: &ReadExpect<'_, AliasValidator>,
|
||||
msg: ClientGeneral,
|
||||
map: &AbilityMap,
|
||||
) -> Result<(), crate::error::Error> {
|
||||
match msg {
|
||||
// Request spectator state
|
||||
@ -101,6 +102,7 @@ impl Sys {
|
||||
tool,
|
||||
body,
|
||||
character_loader,
|
||||
map,
|
||||
);
|
||||
}
|
||||
},
|
||||
@ -134,6 +136,7 @@ impl<'a> System<'a> for Sys {
|
||||
ReadStorage<'a, Presence>,
|
||||
ReadExpect<'a, EditableSettings>,
|
||||
ReadExpect<'a, AliasValidator>,
|
||||
ReadExpect<'a, AbilityMap>,
|
||||
);
|
||||
|
||||
fn run(
|
||||
@ -149,6 +152,7 @@ impl<'a> System<'a> for Sys {
|
||||
presences,
|
||||
editable_settings,
|
||||
alias_validator,
|
||||
map,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
span!(_guard, "run", "msg::character_screen::Sys::run");
|
||||
@ -171,6 +175,7 @@ impl<'a> System<'a> for Sys {
|
||||
&editable_settings,
|
||||
&alias_validator,
|
||||
msg,
|
||||
&map,
|
||||
)
|
||||
});
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use super::SysTimer;
|
||||
use crate::{chunk_generator::ChunkGenerator, client::Client, presence::Presence, Tick};
|
||||
use common::{
|
||||
comp::{self, bird_medium, Alignment, Pos},
|
||||
comp::{self, bird_medium, item::tool::AbilityMap, Alignment, Pos},
|
||||
event::{EventBus, ServerEvent},
|
||||
generation::get_npc_name,
|
||||
msg::ServerGeneral,
|
||||
@ -12,7 +12,7 @@ use common::{
|
||||
LoadoutBuilder,
|
||||
};
|
||||
use rand::Rng;
|
||||
use specs::{Join, Read, ReadStorage, System, Write, WriteExpect};
|
||||
use specs::{Join, Read, ReadExpect, ReadStorage, System, Write, WriteExpect};
|
||||
use std::sync::Arc;
|
||||
use vek::*;
|
||||
|
||||
@ -35,6 +35,7 @@ impl<'a> System<'a> for Sys {
|
||||
ReadStorage<'a, Pos>,
|
||||
ReadStorage<'a, Presence>,
|
||||
ReadStorage<'a, Client>,
|
||||
ReadExpect<'a, AbilityMap>,
|
||||
);
|
||||
|
||||
fn run(
|
||||
@ -49,6 +50,7 @@ impl<'a> System<'a> for Sys {
|
||||
positions,
|
||||
presences,
|
||||
clients,
|
||||
map,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
span!(_guard, "run", "terrain::Sys::run");
|
||||
@ -142,9 +144,14 @@ impl<'a> System<'a> for Sys {
|
||||
scale = 2.0 + rand::random::<f32>();
|
||||
}
|
||||
|
||||
let loadout =
|
||||
LoadoutBuilder::build_loadout(body, alignment, main_tool, entity.is_giant)
|
||||
.build();
|
||||
let loadout = LoadoutBuilder::build_loadout(
|
||||
body,
|
||||
alignment,
|
||||
main_tool,
|
||||
entity.is_giant,
|
||||
&map,
|
||||
)
|
||||
.build();
|
||||
|
||||
let health = comp::Health::new(stats.body_type, stats.level.level());
|
||||
|
||||
|
@ -24,7 +24,7 @@ use client::Client;
|
||||
use common::{
|
||||
assets::Asset,
|
||||
character::{CharacterId, CharacterItem, MAX_CHARACTERS_PER_PLAYER},
|
||||
comp::{self, humanoid},
|
||||
comp::{self, humanoid, item::tool::AbilityMap},
|
||||
LoadoutBuilder,
|
||||
};
|
||||
//ImageFrame, Tooltip,
|
||||
@ -179,12 +179,14 @@ impl Mode {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create(name: String) -> Self {
|
||||
pub fn create(name: String, map: &AbilityMap) -> Self {
|
||||
let tool = STARTER_SWORD;
|
||||
|
||||
let loadout = LoadoutBuilder::new()
|
||||
.defaults()
|
||||
.active_item(Some(LoadoutBuilder::default_item_config_from_str(tool)))
|
||||
.active_item(Some(LoadoutBuilder::default_item_config_from_str(
|
||||
tool, map,
|
||||
)))
|
||||
.build();
|
||||
|
||||
let loadout = Box::new(loadout);
|
||||
@ -1172,7 +1174,13 @@ impl Controls {
|
||||
.into()
|
||||
}
|
||||
|
||||
fn update(&mut self, message: Message, events: &mut Vec<Event>, characters: &[CharacterItem]) {
|
||||
fn update(
|
||||
&mut self,
|
||||
message: Message,
|
||||
events: &mut Vec<Event>,
|
||||
characters: &[CharacterItem],
|
||||
map: &AbilityMap,
|
||||
) {
|
||||
match message {
|
||||
Message::Back => {
|
||||
if matches!(&self.mode, Mode::Create { .. }) {
|
||||
@ -1206,7 +1214,7 @@ impl Controls {
|
||||
},
|
||||
Message::NewCharacter => {
|
||||
if matches!(&self.mode, Mode::Select { .. }) {
|
||||
self.mode = Mode::create(String::new());
|
||||
self.mode = Mode::create(String::new(), map);
|
||||
}
|
||||
},
|
||||
Message::CreateCharacter => {
|
||||
@ -1242,7 +1250,8 @@ impl Controls {
|
||||
Message::Tool(value) => {
|
||||
if let Mode::Create { tool, loadout, .. } = &mut self.mode {
|
||||
*tool = value;
|
||||
loadout.active_item = Some(LoadoutBuilder::default_item_config_from_str(*tool));
|
||||
loadout.active_item =
|
||||
Some(LoadoutBuilder::default_item_config_from_str(*tool, map));
|
||||
}
|
||||
},
|
||||
Message::RandomizeCharacter => {
|
||||
@ -1435,8 +1444,12 @@ impl CharSelectionUi {
|
||||
}
|
||||
|
||||
messages.into_iter().for_each(|message| {
|
||||
self.controls
|
||||
.update(message, &mut events, &client.character_list.characters)
|
||||
self.controls.update(
|
||||
message,
|
||||
&mut events,
|
||||
&client.character_list.characters,
|
||||
&*client.state().ability_map(),
|
||||
)
|
||||
});
|
||||
|
||||
events
|
||||
|
Loading…
Reference in New Issue
Block a user