mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'sam/minotaur' into 'master'
Overhauled Minotaur See merge request veloren/veloren!2193
This commit is contained in:
commit
fb940ad27a
@ -92,6 +92,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Debug Kit is split to "admin_cosmetics" and "debug"
|
- Debug Kit is split to "admin_cosmetics" and "debug"
|
||||||
- Potion Kit is renamed to "consumables" and gives potions and mushroom curry
|
- Potion Kit is renamed to "consumables" and gives potions and mushroom curry
|
||||||
- Cultist Kit gives cape, rings and necklace in addition to armour and weapons.
|
- Cultist Kit gives cape, rings and necklace in addition to armour and weapons.
|
||||||
|
- Reworked minotaur to have unique attacks.
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
|
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -5542,6 +5542,8 @@ dependencies = [
|
|||||||
"specs-idvs",
|
"specs-idvs",
|
||||||
"spin_sleep",
|
"spin_sleep",
|
||||||
"structopt",
|
"structopt",
|
||||||
|
"strum",
|
||||||
|
"strum_macros",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
"uuid",
|
"uuid",
|
||||||
|
@ -207,6 +207,14 @@
|
|||||||
(None, "common.abilities.custom.mindflayer.summonminions"),
|
(None, "common.abilities.custom.mindflayer.summonminions"),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
Custom("Minotaur"): (
|
||||||
|
primary: "common.abilities.custom.minotaur.cleave",
|
||||||
|
secondary: "common.abilities.custom.minotaur.cripplingstrike",
|
||||||
|
abilities: [
|
||||||
|
(None, "common.abilities.custom.minotaur.charge"),
|
||||||
|
(None, "common.abilities.custom.minotaur.frenzy"),
|
||||||
|
],
|
||||||
|
),
|
||||||
Custom("Bird Large Breathe"): (
|
Custom("Bird Large Breathe"): (
|
||||||
primary: "common.abilities.custom.birdlargebreathe.firebomb",
|
primary: "common.abilities.custom.birdlargebreathe.firebomb",
|
||||||
secondary: "common.abilities.custom.birdlargebreathe.triplestrike",
|
secondary: "common.abilities.custom.birdlargebreathe.triplestrike",
|
||||||
|
@ -8,4 +8,5 @@ BasicMelee(
|
|||||||
base_poise_damage: 40,
|
base_poise_damage: 40,
|
||||||
range: 5.0,
|
range: 5.0,
|
||||||
max_angle: 120.0,
|
max_angle: 120.0,
|
||||||
|
damage_effect: None,
|
||||||
)
|
)
|
||||||
|
@ -2,7 +2,7 @@ BasicBeam(
|
|||||||
buildup_duration: 0.40,
|
buildup_duration: 0.40,
|
||||||
recover_duration: 0.50,
|
recover_duration: 0.50,
|
||||||
beam_duration: 1.0,
|
beam_duration: 1.0,
|
||||||
damage: 350,
|
damage: 500,
|
||||||
tick_rate: 0.9,
|
tick_rate: 0.9,
|
||||||
range: 22.0,
|
range: 22.0,
|
||||||
max_angle: 15.0,
|
max_angle: 15.0,
|
||||||
|
@ -2,7 +2,7 @@ SpinMelee(
|
|||||||
buildup_duration: 0.5,
|
buildup_duration: 0.5,
|
||||||
swing_duration: 0.2,
|
swing_duration: 0.2,
|
||||||
recover_duration: 0.6,
|
recover_duration: 0.6,
|
||||||
base_damage: 80.0,
|
base_damage: 100.0,
|
||||||
base_poise_damage: 1.0,
|
base_poise_damage: 1.0,
|
||||||
knockback: ( strength: 7.0, direction: Towards),
|
knockback: ( strength: 7.0, direction: Towards),
|
||||||
range: 16.0,
|
range: 16.0,
|
||||||
|
19
assets/common/abilities/custom/minotaur/charge.ron
Normal file
19
assets/common/abilities/custom/minotaur/charge.ron
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
DashMelee(
|
||||||
|
energy_cost: 0,
|
||||||
|
base_damage: 150,
|
||||||
|
scaled_damage: 600,
|
||||||
|
base_poise_damage: 25,
|
||||||
|
scaled_poise_damage: 100,
|
||||||
|
base_knockback: 10.0,
|
||||||
|
scaled_knockback: 30.0,
|
||||||
|
range: 5.0,
|
||||||
|
angle: 90.0,
|
||||||
|
energy_drain: 0,
|
||||||
|
forward_speed: 5.0,
|
||||||
|
buildup_duration: 0.4,
|
||||||
|
charge_duration: 4.0,
|
||||||
|
swing_duration: 0.1,
|
||||||
|
recover_duration: 0.5,
|
||||||
|
charge_through: false,
|
||||||
|
is_interruptible: false,
|
||||||
|
)
|
18
assets/common/abilities/custom/minotaur/cleave.ron
Normal file
18
assets/common/abilities/custom/minotaur/cleave.ron
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
ChargedMelee(
|
||||||
|
energy_cost: 0,
|
||||||
|
energy_drain: 0,
|
||||||
|
initial_damage: 0,
|
||||||
|
scaled_damage: 500,
|
||||||
|
initial_poise_damage: 50,
|
||||||
|
scaled_poise_damage: 150,
|
||||||
|
initial_knockback: 0.0,
|
||||||
|
scaled_knockback: 0.0,
|
||||||
|
range: 5.0,
|
||||||
|
max_angle: 45.0,
|
||||||
|
speed: 1.0,
|
||||||
|
charge_duration: 1.5,
|
||||||
|
swing_duration: 0.1,
|
||||||
|
hit_timing: 0.8,
|
||||||
|
recover_duration: 0.5,
|
||||||
|
specifier: Some(GroundCleave),
|
||||||
|
)
|
17
assets/common/abilities/custom/minotaur/cripplingstrike.ron
Normal file
17
assets/common/abilities/custom/minotaur/cripplingstrike.ron
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
BasicMelee(
|
||||||
|
energy_cost: 0,
|
||||||
|
buildup_duration: 0.3,
|
||||||
|
swing_duration: 0.1,
|
||||||
|
recover_duration: 0.6,
|
||||||
|
base_damage: 150.0,
|
||||||
|
base_poise_damage: 60.0,
|
||||||
|
knockback: 15.0,
|
||||||
|
range: 5.0,
|
||||||
|
max_angle: 60.0,
|
||||||
|
damage_effect: Some(Buff((
|
||||||
|
kind: Crippled,
|
||||||
|
dur_secs: 15.0,
|
||||||
|
strength: Value(0.5),
|
||||||
|
chance: 1.0,
|
||||||
|
))),
|
||||||
|
)
|
9
assets/common/abilities/custom/minotaur/frenzy.ron
Normal file
9
assets/common/abilities/custom/minotaur/frenzy.ron
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
SelfBuff(
|
||||||
|
buildup_duration: 0.25,
|
||||||
|
cast_duration: 0.8,
|
||||||
|
recover_duration: 0.25,
|
||||||
|
buff_kind: Frenzied,
|
||||||
|
buff_strength: 0.5,
|
||||||
|
buff_duration: Some(300.0),
|
||||||
|
energy_cost: 0,
|
||||||
|
)
|
@ -8,4 +8,5 @@ BasicMelee(
|
|||||||
knockback: 25.0,
|
knockback: 25.0,
|
||||||
range: 1.2,
|
range: 1.2,
|
||||||
max_angle: 50.0,
|
max_angle: 50.0,
|
||||||
|
damage_effect: None,
|
||||||
)
|
)
|
||||||
|
@ -8,4 +8,5 @@ BasicMelee(
|
|||||||
knockback: 0.0,
|
knockback: 0.0,
|
||||||
range: 3.5,
|
range: 3.5,
|
||||||
max_angle: 20.0,
|
max_angle: 20.0,
|
||||||
|
damage_effect: None,
|
||||||
)
|
)
|
||||||
|
@ -8,4 +8,5 @@ BasicMelee(
|
|||||||
knockback: 0.0,
|
knockback: 0.0,
|
||||||
range: 3.5,
|
range: 3.5,
|
||||||
max_angle: 15.0,
|
max_angle: 15.0,
|
||||||
|
damage_effect: None,
|
||||||
)
|
)
|
||||||
|
@ -8,4 +8,5 @@ BasicMelee(
|
|||||||
knockback: 0.0,
|
knockback: 0.0,
|
||||||
range: 3.5,
|
range: 3.5,
|
||||||
max_angle: 20.0,
|
max_angle: 20.0,
|
||||||
|
damage_effect: None,
|
||||||
)
|
)
|
||||||
|
@ -8,4 +8,5 @@ BasicMelee(
|
|||||||
knockback: 0.0,
|
knockback: 0.0,
|
||||||
range: 3.5,
|
range: 3.5,
|
||||||
max_angle: 20.0,
|
max_angle: 20.0,
|
||||||
|
damage_effect: None,
|
||||||
)
|
)
|
||||||
|
@ -8,4 +8,5 @@ BasicMelee(
|
|||||||
knockback: 0.0,
|
knockback: 0.0,
|
||||||
range: 3.0,
|
range: 3.0,
|
||||||
max_angle: 120.0,
|
max_angle: 120.0,
|
||||||
|
damage_effect: None,
|
||||||
)
|
)
|
||||||
|
@ -6,14 +6,14 @@ ItemDef(
|
|||||||
hands: Two,
|
hands: Two,
|
||||||
stats: Direct((
|
stats: Direct((
|
||||||
equip_time_secs: 0.5,
|
equip_time_secs: 0.5,
|
||||||
power: 1.8,
|
power: 1.0,
|
||||||
poise_strength: 1.0,
|
poise_strength: 1.0,
|
||||||
speed: 1.0,
|
speed: 1.0,
|
||||||
crit_chance: 0.048611112,
|
crit_chance: 0.1,
|
||||||
crit_mult: 1.6530613,
|
crit_mult: 1.5,
|
||||||
)),
|
)),
|
||||||
)),
|
)),
|
||||||
quality: Low,
|
quality: Legendary,
|
||||||
tags: [],
|
tags: [],
|
||||||
ability_spec: Some(Custom("Axe Simple")),
|
ability_spec: Some(Custom("Minotaur")),
|
||||||
)
|
)
|
@ -6,9 +6,9 @@ ItemDef(
|
|||||||
hands: Two,
|
hands: Two,
|
||||||
stats: Direct((
|
stats: Direct((
|
||||||
equip_time_secs: 0.5,
|
equip_time_secs: 0.5,
|
||||||
power: 4.0,
|
power: 2.5,
|
||||||
poise_strength: 1.0,
|
poise_strength: 1.0,
|
||||||
speed: 0.5,
|
speed: 0.8,
|
||||||
crit_chance: 0.078125,
|
crit_chance: 0.078125,
|
||||||
crit_mult: 1.3657143,
|
crit_mult: 1.3657143,
|
||||||
)),
|
)),
|
||||||
|
@ -6,9 +6,9 @@ ItemDef(
|
|||||||
hands: Two,
|
hands: Two,
|
||||||
stats: Direct((
|
stats: Direct((
|
||||||
equip_time_secs: 0.4,
|
equip_time_secs: 0.4,
|
||||||
power: 2.3,
|
power: 1.67,
|
||||||
poise_strength: 1.5,
|
poise_strength: 1.5,
|
||||||
speed: 1.0,
|
speed: 1.2,
|
||||||
crit_chance: 0.078125,
|
crit_chance: 0.078125,
|
||||||
crit_mult: 1.3657143,
|
crit_mult: 1.3657143,
|
||||||
)),
|
)),
|
||||||
|
@ -6,9 +6,9 @@ ItemDef(
|
|||||||
hands: Two,
|
hands: Two,
|
||||||
stats: Direct((
|
stats: Direct((
|
||||||
equip_time_secs: 0.4,
|
equip_time_secs: 0.4,
|
||||||
power: 4.0,
|
power: 2.5,
|
||||||
poise_strength: 1.5,
|
poise_strength: 1.0,
|
||||||
speed: 0.5,
|
speed: 0.8,
|
||||||
crit_chance: 0.078125,
|
crit_chance: 0.078125,
|
||||||
crit_mult: 1.3657143,
|
crit_mult: 1.3657143,
|
||||||
)),
|
)),
|
||||||
|
@ -6,9 +6,9 @@ ItemDef(
|
|||||||
hands: Two,
|
hands: Two,
|
||||||
stats: Direct((
|
stats: Direct((
|
||||||
equip_time_secs: 0.4,
|
equip_time_secs: 0.4,
|
||||||
power: 1.8,
|
power: 2.0,
|
||||||
poise_strength: 1.5,
|
poise_strength: 1.5,
|
||||||
speed: 1.2,
|
speed: 1.0,
|
||||||
crit_chance: 0.21153846,
|
crit_chance: 0.21153846,
|
||||||
crit_mult: 1.4502164,
|
crit_mult: 1.4502164,
|
||||||
)),
|
)),
|
||||||
|
@ -6,9 +6,9 @@ ItemDef(
|
|||||||
hands: Two,
|
hands: Two,
|
||||||
stats: Direct((
|
stats: Direct((
|
||||||
equip_time_secs: 0.6,
|
equip_time_secs: 0.6,
|
||||||
power: 1.8,
|
power: 1.67,
|
||||||
poise_strength: 1.0,
|
poise_strength: 1.0,
|
||||||
speed: 1.6,
|
speed: 1.2,
|
||||||
crit_chance: 0.2002994,
|
crit_chance: 0.2002994,
|
||||||
crit_mult: 1.3798152,
|
crit_mult: 1.3798152,
|
||||||
)),
|
)),
|
||||||
|
@ -6,9 +6,9 @@ ItemDef(
|
|||||||
hands: Two,
|
hands: Two,
|
||||||
stats: Direct((
|
stats: Direct((
|
||||||
equip_time_secs: 0.6,
|
equip_time_secs: 0.6,
|
||||||
power: 3.0,
|
power: 2.5,
|
||||||
poise_strength: 1.0,
|
poise_strength: 1.0,
|
||||||
speed: 0.67,
|
speed: 0.8,
|
||||||
crit_chance: 0.1002994,
|
crit_chance: 0.1002994,
|
||||||
crit_mult: 1.3798152,
|
crit_mult: 1.3798152,
|
||||||
)),
|
)),
|
||||||
|
@ -39,5 +39,20 @@
|
|||||||
("common.items.consumable.potion_med", 100),
|
("common.items.consumable.potion_med", 100),
|
||||||
("common.items.consumable.potion_big", 100),
|
("common.items.consumable.potion_big", 100),
|
||||||
("common.items.food.apple_mushroom_curry", 100),
|
("common.items.food.apple_mushroom_curry", 100),
|
||||||
]
|
],
|
||||||
|
"tier-4": [
|
||||||
|
("common.items.armor.steel.belt", 1),
|
||||||
|
("common.items.armor.steel.chest", 1),
|
||||||
|
("common.items.armor.steel.foot", 1),
|
||||||
|
("common.items.armor.steel.hand", 1),
|
||||||
|
("common.items.armor.steel.pants", 1),
|
||||||
|
("common.items.armor.steel.shoulder", 1),
|
||||||
|
("common.items.weapons.sword.cobalt-0", 1),
|
||||||
|
("common.items.weapons.axe.cobalt_axe-0", 1),
|
||||||
|
("common.items.weapons.hammer.cobalt_hammer-0", 1),
|
||||||
|
("common.items.weapons.bow.frostwood-0", 1),
|
||||||
|
("common.items.weapons.staff.frostwood_torch", 1),
|
||||||
|
("common.items.weapons.sceptre.fork0", 1),
|
||||||
|
("common.items.consumable.potion_med", 100),
|
||||||
|
],
|
||||||
})
|
})
|
||||||
|
@ -824,5 +824,12 @@
|
|||||||
],
|
],
|
||||||
threshold: 1.25,
|
threshold: 1.25,
|
||||||
),
|
),
|
||||||
|
GroundSlam: (
|
||||||
|
files: [
|
||||||
|
"voxygen.audio.sfx.abilities.minotaur_smash_1",
|
||||||
|
"voxygen.audio.sfx.abilities.minotaur_smash_2",
|
||||||
|
],
|
||||||
|
threshold: 0.2,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
BIN
assets/voxygen/audio/sfx/abilities/minotaur_smash_1.ogg
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/audio/sfx/abilities/minotaur_smash_1.ogg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/audio/sfx/abilities/minotaur_smash_2.ogg
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/audio/sfx/abilities/minotaur_smash_2.ogg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/de_buffs/buff_frenzy_0.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/de_buffs/buff_frenzy_0.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/de_buffs/debuff_cripple_0.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/de_buffs/debuff_cripple_0.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -19,6 +19,8 @@
|
|||||||
"buff.desc.invulnerability": "You cannot be damaged by any attack.",
|
"buff.desc.invulnerability": "You cannot be damaged by any attack.",
|
||||||
"buff.title.protectingward": "Protecting Ward",
|
"buff.title.protectingward": "Protecting Ward",
|
||||||
"buff.desc.protectingward": "You are protected, somewhat, from attacks.",
|
"buff.desc.protectingward": "You are protected, somewhat, from attacks.",
|
||||||
|
"buff.title.frenzied": "Frenzied",
|
||||||
|
"buff.desc.frenzied": "You are imbued with unnatural speed and can ignore minor injuries.",
|
||||||
// Debuffs
|
// Debuffs
|
||||||
"buff.title.bleed": "Bleeding",
|
"buff.title.bleed": "Bleeding",
|
||||||
"buff.desc.bleed": "Inflicts regular damage.",
|
"buff.desc.bleed": "Inflicts regular damage.",
|
||||||
@ -26,6 +28,8 @@
|
|||||||
"buff.desc.cursed": "You are cursed.",
|
"buff.desc.cursed": "You are cursed.",
|
||||||
"buff.title.burn": "On Fire",
|
"buff.title.burn": "On Fire",
|
||||||
"buff.desc.burn": "You are burning alive",
|
"buff.desc.burn": "You are burning alive",
|
||||||
|
"buff.title.crippled": "Crippled",
|
||||||
|
"buff.desc.crippled": "Your movement is crippled as your legs are heavily injured.",
|
||||||
// Buffs stats
|
// Buffs stats
|
||||||
"buff.stat.health": "Restores {str_total} Health",
|
"buff.stat.health": "Restores {str_total} Health",
|
||||||
"buff.stat.increase_max_stamina": "Raises Maximum Stamina by {strength}",
|
"buff.stat.increase_max_stamina": "Raises Maximum Stamina by {strength}",
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
"hud.outcome.burning": "died of: burning",
|
"hud.outcome.burning": "died of: burning",
|
||||||
"hud.outcome.curse": "died of: curse",
|
"hud.outcome.curse": "died of: curse",
|
||||||
"hud.outcome.bleeding": "died of: bleeding",
|
"hud.outcome.bleeding": "died of: bleeding",
|
||||||
|
"hud.outcome.crippled": "died of: crippled",
|
||||||
|
|
||||||
// Chat outputs
|
// Chat outputs
|
||||||
"hud.chat.online_msg": "[{name}] is online now",
|
"hud.chat.online_msg": "[{name}] is online now",
|
||||||
|
@ -64,6 +64,8 @@ const int LIFESTEAL_BEAM = 22;
|
|||||||
const int CULTIST_FLAME = 23;
|
const int CULTIST_FLAME = 23;
|
||||||
const int STATIC_SMOKE = 24;
|
const int STATIC_SMOKE = 24;
|
||||||
const int BLOOD = 25;
|
const int BLOOD = 25;
|
||||||
|
const int ENRAGED = 26;
|
||||||
|
const int BIG_SHRAPNEL = 27;
|
||||||
|
|
||||||
// meters per second squared (acceleration)
|
// meters per second squared (acceleration)
|
||||||
const float earth_gravity = 9.807;
|
const float earth_gravity = 9.807;
|
||||||
@ -218,6 +220,17 @@ void main() {
|
|||||||
vec4(vec3(0.25), 1),
|
vec4(vec3(0.25), 1),
|
||||||
spin_in_axis(vec3(1,0,0),0)
|
spin_in_axis(vec3(1,0,0),0)
|
||||||
);
|
);
|
||||||
|
} else if (inst_mode == BIG_SHRAPNEL) {
|
||||||
|
float brown_color = 0.05 + 0.1 * rand1;
|
||||||
|
attr = Attr(
|
||||||
|
linear_motion(
|
||||||
|
vec3(0),
|
||||||
|
normalize(vec3(rand4, rand5, rand6)) * 15.0 + grav_vel(earth_gravity)
|
||||||
|
),
|
||||||
|
vec3(5 * (1 - percent())),
|
||||||
|
vec4(vec3(brown_color, brown_color / 2, 0), 1),
|
||||||
|
spin_in_axis(vec3(1,0,0),0)
|
||||||
|
);
|
||||||
} else if (inst_mode == FIREWORK_BLUE) {
|
} else if (inst_mode == FIREWORK_BLUE) {
|
||||||
f_reflect = 0.0; // Fire doesn't reflect light, it emits it
|
f_reflect = 0.0; // Fire doesn't reflect light, it emits it
|
||||||
attr = Attr(
|
attr = Attr(
|
||||||
@ -421,6 +434,15 @@ void main() {
|
|||||||
vec4(1, 0, 0, 1),
|
vec4(1, 0, 0, 1),
|
||||||
spin_in_axis(vec3(1,0,0),0)
|
spin_in_axis(vec3(1,0,0),0)
|
||||||
);
|
);
|
||||||
|
} else if (inst_mode == ENRAGED) {
|
||||||
|
f_reflect = 0.0;
|
||||||
|
float red_color = 1.2 + 0.3 * rand3;
|
||||||
|
attr = Attr(
|
||||||
|
(inst_dir * slow_end(1.5)) + vec3(rand0, rand1, rand2) * (percent() + 2) * 0.1,
|
||||||
|
vec3((3.5 * (1 - slow_start(0.2)))),
|
||||||
|
vec4(red_color, 0.0, 0.0, 1),
|
||||||
|
spin_in_axis(vec3(rand6, rand7, rand8), percent() * 10 + 3 * rand9)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
attr = Attr(
|
attr = Attr(
|
||||||
linear_motion(
|
linear_motion(
|
||||||
|
@ -1043,7 +1043,7 @@
|
|||||||
color: None
|
color: None
|
||||||
),
|
),
|
||||||
"common.items.npc_weapons.axe.minotaur_axe": (
|
"common.items.npc_weapons.axe.minotaur_axe": (
|
||||||
vox_spec: ("weapon.axe.2haxe_minotaur", (-2.5, -9.0, -6.0)),
|
vox_spec: ("weapon.axe.2haxe_minotaur", (-2.5, -9.0, -8.0)),
|
||||||
color: None
|
color: None
|
||||||
),
|
),
|
||||||
"common.items.npc_weapons.hammer.yeti_hammer": (
|
"common.items.npc_weapons.hammer.yeti_hammer": (
|
||||||
|
BIN
assets/voxygen/voxel/weapon/axe/2haxe_minotaur.vox
(Stored with Git LFS)
BIN
assets/voxygen/voxel/weapon/axe/2haxe_minotaur.vox
(Stored with Git LFS)
Binary file not shown.
@ -49,7 +49,7 @@ ron = { version = "0.6", default-features = false }
|
|||||||
serde_json = "1.0.50"
|
serde_json = "1.0.50"
|
||||||
serde_repr = "0.1.6"
|
serde_repr = "0.1.6"
|
||||||
|
|
||||||
# esv export
|
# csv export
|
||||||
csv = { version = "1.1.3", optional = true }
|
csv = { version = "1.1.3", optional = true }
|
||||||
structopt = { version = "0.3.13", optional = true }
|
structopt = { version = "0.3.13", optional = true }
|
||||||
|
|
||||||
@ -59,6 +59,10 @@ slotmap = { version = "1.0", features = ["serde"] }
|
|||||||
indexmap = "1.3.0"
|
indexmap = "1.3.0"
|
||||||
slab = "0.4.2"
|
slab = "0.4.2"
|
||||||
|
|
||||||
|
# Strum
|
||||||
|
strum = "0.20"
|
||||||
|
strum_macros = "0.20"
|
||||||
|
|
||||||
# ECS
|
# ECS
|
||||||
specs = { git = "https://github.com/amethyst/specs.git", features = ["serde", "storage-event-control", "nightly"], rev = "5a9b71035007be0e3574f35184acac1cd4530496" }
|
specs = { git = "https://github.com/amethyst/specs.git", features = ["serde", "storage-event-control", "nightly"], rev = "5a9b71035007be0e3574f35184acac1cd4530496" }
|
||||||
specs-idvs = { git = "https://gitlab.com/veloren/specs-idvs.git", rev = "b65fb220e94f5d3c9bc30074a076149763795556" }
|
specs-idvs = { git = "https://gitlab.com/veloren/specs-idvs.git", rev = "b65fb220e94f5d3c9bc30074a076149763795556" }
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
use crate::{assets, comp, npc, terrain};
|
use crate::{
|
||||||
|
assets,
|
||||||
|
comp::{self, buff::BuffKind},
|
||||||
|
npc, terrain,
|
||||||
|
};
|
||||||
use assets::AssetExt;
|
use assets::AssetExt;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
@ -8,6 +12,7 @@ use std::{
|
|||||||
path::Path,
|
path::Path,
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
};
|
};
|
||||||
|
use strum::IntoEnumIterator;
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
|
|
||||||
/// Struct representing a command that a user can run from server chat.
|
/// Struct representing a command that a user can run from server chat.
|
||||||
@ -210,21 +215,40 @@ lazy_static! {
|
|||||||
.map(|s| s.to_string())
|
.map(|s| s.to_string())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
static ref BUFFS: Vec<String> = vec![
|
pub static ref BUFF_PARSER: HashMap<String, BuffKind> = {
|
||||||
// Debuffs
|
let string_from_buff = |kind| match kind {
|
||||||
"burning", "bleeding", "curse",
|
BuffKind::Burning => "burning",
|
||||||
// Heal
|
BuffKind::Regeneration => "regeration",
|
||||||
"regeneration", "saturation", "potion", "campfire_heal",
|
BuffKind::Saturation => "saturation",
|
||||||
// Outmaxing stats
|
BuffKind::Bleeding => "bleeding",
|
||||||
"increase_max_energy", "increase_max_health",
|
BuffKind::Cursed => "cursed",
|
||||||
// Defensive buffs
|
BuffKind::Potion => "potion",
|
||||||
"invulnerability", "protecting_ward",
|
BuffKind::CampfireHeal => "campfire_heal",
|
||||||
// One command to rule them all
|
BuffKind::IncreaseMaxEnergy => "increase_max_energy",
|
||||||
"all",
|
BuffKind::IncreaseMaxHealth => "increase_max_health",
|
||||||
]
|
BuffKind::Invulnerability => "invulnerability",
|
||||||
.iter()
|
BuffKind::ProtectingWard => "protecting_ward",
|
||||||
.map(|b| b.to_string())
|
BuffKind::Frenzied => "frenzied",
|
||||||
.collect();
|
BuffKind::Crippled => "crippled",
|
||||||
|
};
|
||||||
|
let mut buff_parser = HashMap::new();
|
||||||
|
BuffKind::iter().for_each(|kind| {buff_parser.insert(string_from_buff(kind).to_string(), kind);});
|
||||||
|
buff_parser
|
||||||
|
};
|
||||||
|
|
||||||
|
pub static ref BUFF_PACK: Vec<String> = {
|
||||||
|
let mut buff_pack: Vec<_> = BUFF_PARSER.keys().cloned().collect();
|
||||||
|
// Remove invulnerability as it removes debuffs
|
||||||
|
buff_pack.retain(|kind| kind != "invulnerability");
|
||||||
|
buff_pack
|
||||||
|
};
|
||||||
|
|
||||||
|
static ref BUFFS: Vec<String> = {
|
||||||
|
let mut buff_pack: Vec<_> = BUFF_PARSER.keys().cloned().collect();
|
||||||
|
// Add all as valid command
|
||||||
|
buff_pack.push("all".to_string());
|
||||||
|
buff_pack
|
||||||
|
};
|
||||||
|
|
||||||
static ref BLOCK_KINDS: Vec<String> = terrain::block::BLOCK_KINDS
|
static ref BLOCK_KINDS: Vec<String> = terrain::block::BLOCK_KINDS
|
||||||
.keys()
|
.keys()
|
||||||
|
@ -2,8 +2,8 @@ use crate::{
|
|||||||
assets::{self, Asset},
|
assets::{self, Asset},
|
||||||
combat::{self, CombatEffect, Knockback},
|
combat::{self, CombatEffect, Knockback},
|
||||||
comp::{
|
comp::{
|
||||||
aura, beam, inventory::item::tool::ToolKind, projectile::ProjectileConstructor, skills,
|
aura, beam, buff, inventory::item::tool::ToolKind, projectile::ProjectileConstructor,
|
||||||
Body, CharacterState, EnergySource, LightEmitter, StateUpdate,
|
skills, Body, CharacterState, EnergySource, LightEmitter, StateUpdate,
|
||||||
},
|
},
|
||||||
states::{
|
states::{
|
||||||
behavior::JoinData,
|
behavior::JoinData,
|
||||||
@ -30,6 +30,7 @@ pub enum CharacterAbilityType {
|
|||||||
BasicBeam,
|
BasicBeam,
|
||||||
RepeaterRanged,
|
RepeaterRanged,
|
||||||
BasicAura,
|
BasicAura,
|
||||||
|
SelfBuff,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&CharacterState> for CharacterAbilityType {
|
impl From<&CharacterState> for CharacterAbilityType {
|
||||||
@ -49,6 +50,7 @@ impl From<&CharacterState> for CharacterAbilityType {
|
|||||||
CharacterState::BasicBeam(_) => Self::BasicBeam,
|
CharacterState::BasicBeam(_) => Self::BasicBeam,
|
||||||
CharacterState::RepeaterRanged(_) => Self::RepeaterRanged,
|
CharacterState::RepeaterRanged(_) => Self::RepeaterRanged,
|
||||||
CharacterState::BasicAura(_) => Self::BasicAura,
|
CharacterState::BasicAura(_) => Self::BasicAura,
|
||||||
|
CharacterState::SelfBuff(_) => Self::SelfBuff,
|
||||||
_ => Self::BasicMelee,
|
_ => Self::BasicMelee,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,6 +68,7 @@ pub enum CharacterAbility {
|
|||||||
knockback: f32,
|
knockback: f32,
|
||||||
range: f32,
|
range: f32,
|
||||||
max_angle: f32,
|
max_angle: f32,
|
||||||
|
damage_effect: Option<CombatEffect>,
|
||||||
},
|
},
|
||||||
BasicRanged {
|
BasicRanged {
|
||||||
energy_cost: f32,
|
energy_cost: f32,
|
||||||
@ -188,6 +191,7 @@ pub enum CharacterAbility {
|
|||||||
swing_duration: f32,
|
swing_duration: f32,
|
||||||
hit_timing: f32,
|
hit_timing: f32,
|
||||||
recover_duration: f32,
|
recover_duration: f32,
|
||||||
|
specifier: Option<charged_melee::FrontendSpecifier>,
|
||||||
},
|
},
|
||||||
ChargedRanged {
|
ChargedRanged {
|
||||||
energy_cost: f32,
|
energy_cost: f32,
|
||||||
@ -268,6 +272,15 @@ pub enum CharacterAbility {
|
|||||||
summon_amount: u32,
|
summon_amount: u32,
|
||||||
summon_info: basic_summon::SummonInfo,
|
summon_info: basic_summon::SummonInfo,
|
||||||
},
|
},
|
||||||
|
SelfBuff {
|
||||||
|
buildup_duration: f32,
|
||||||
|
cast_duration: f32,
|
||||||
|
recover_duration: f32,
|
||||||
|
buff_kind: buff::BuffKind,
|
||||||
|
buff_strength: f32,
|
||||||
|
buff_duration: Option<f32>,
|
||||||
|
energy_cost: f32,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for CharacterAbility {
|
impl Default for CharacterAbility {
|
||||||
@ -282,6 +295,7 @@ impl Default for CharacterAbility {
|
|||||||
knockback: 0.0,
|
knockback: 0.0,
|
||||||
range: 3.5,
|
range: 3.5,
|
||||||
max_angle: 15.0,
|
max_angle: 15.0,
|
||||||
|
damage_effect: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -313,7 +327,8 @@ impl CharacterAbility {
|
|||||||
| CharacterAbility::ChargedMelee { energy_cost, .. }
|
| CharacterAbility::ChargedMelee { energy_cost, .. }
|
||||||
| CharacterAbility::Shockwave { energy_cost, .. }
|
| CharacterAbility::Shockwave { energy_cost, .. }
|
||||||
| CharacterAbility::BasicAura { energy_cost, .. }
|
| CharacterAbility::BasicAura { energy_cost, .. }
|
||||||
| CharacterAbility::BasicBlock { energy_cost, .. } => update
|
| CharacterAbility::BasicBlock { energy_cost, .. }
|
||||||
|
| CharacterAbility::SelfBuff { energy_cost, .. } => update
|
||||||
.energy
|
.energy
|
||||||
.try_change_by(-(*energy_cost as i32), EnergySource::Ability)
|
.try_change_by(-(*energy_cost as i32), EnergySource::Ability)
|
||||||
.is_ok(),
|
.is_ok(),
|
||||||
@ -334,7 +349,11 @@ impl CharacterAbility {
|
|||||||
.is_ok()
|
.is_ok()
|
||||||
},
|
},
|
||||||
CharacterAbility::HealingBeam { .. } => data.combo.counter() > 0,
|
CharacterAbility::HealingBeam { .. } => data.combo.counter() > 0,
|
||||||
_ => true,
|
CharacterAbility::ComboMelee { .. }
|
||||||
|
| CharacterAbility::Boost { .. }
|
||||||
|
| CharacterAbility::BasicBeam { .. }
|
||||||
|
| CharacterAbility::Blink { .. }
|
||||||
|
| CharacterAbility::BasicSummon { .. } => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -586,6 +605,18 @@ impl CharacterAbility {
|
|||||||
*cast_duration /= speed;
|
*cast_duration /= speed;
|
||||||
*recover_duration /= speed;
|
*recover_duration /= speed;
|
||||||
},
|
},
|
||||||
|
SelfBuff {
|
||||||
|
ref mut buff_strength,
|
||||||
|
ref mut buildup_duration,
|
||||||
|
ref mut cast_duration,
|
||||||
|
ref mut recover_duration,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
*buff_strength *= power;
|
||||||
|
*buildup_duration /= speed;
|
||||||
|
*cast_duration /= speed;
|
||||||
|
*recover_duration /= speed;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -605,7 +636,8 @@ impl CharacterAbility {
|
|||||||
| Shockwave { energy_cost, .. }
|
| Shockwave { energy_cost, .. }
|
||||||
| HealingBeam { energy_cost, .. }
|
| HealingBeam { energy_cost, .. }
|
||||||
| BasicAura { energy_cost, .. }
|
| BasicAura { energy_cost, .. }
|
||||||
| BasicBlock { energy_cost, .. } => *energy_cost as u32,
|
| BasicBlock { energy_cost, .. }
|
||||||
|
| SelfBuff { energy_cost, .. } => *energy_cost as u32,
|
||||||
BasicBeam { energy_drain, .. } => {
|
BasicBeam { energy_drain, .. } => {
|
||||||
if *energy_drain > f32::EPSILON {
|
if *energy_drain > f32::EPSILON {
|
||||||
1
|
1
|
||||||
@ -1164,6 +1196,7 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
|
|||||||
knockback,
|
knockback,
|
||||||
range,
|
range,
|
||||||
max_angle,
|
max_angle,
|
||||||
|
damage_effect,
|
||||||
energy_cost: _,
|
energy_cost: _,
|
||||||
} => CharacterState::BasicMelee(basic_melee::Data {
|
} => CharacterState::BasicMelee(basic_melee::Data {
|
||||||
static_data: basic_melee::StaticData {
|
static_data: basic_melee::StaticData {
|
||||||
@ -1175,6 +1208,7 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
|
|||||||
knockback: *knockback,
|
knockback: *knockback,
|
||||||
range: *range,
|
range: *range,
|
||||||
max_angle: *max_angle,
|
max_angle: *max_angle,
|
||||||
|
damage_effect: *damage_effect,
|
||||||
ability_info,
|
ability_info,
|
||||||
},
|
},
|
||||||
timer: Duration::default(),
|
timer: Duration::default(),
|
||||||
@ -1419,6 +1453,7 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
|
|||||||
recover_duration,
|
recover_duration,
|
||||||
range,
|
range,
|
||||||
max_angle,
|
max_angle,
|
||||||
|
specifier,
|
||||||
} => CharacterState::ChargedMelee(charged_melee::Data {
|
} => CharacterState::ChargedMelee(charged_melee::Data {
|
||||||
static_data: charged_melee::StaticData {
|
static_data: charged_melee::StaticData {
|
||||||
energy_cost: *energy_cost,
|
energy_cost: *energy_cost,
|
||||||
@ -1437,6 +1472,7 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
|
|||||||
hit_timing: *hit_timing,
|
hit_timing: *hit_timing,
|
||||||
recover_duration: Duration::from_secs_f32(*recover_duration),
|
recover_duration: Duration::from_secs_f32(*recover_duration),
|
||||||
ability_info,
|
ability_info,
|
||||||
|
specifier: *specifier,
|
||||||
},
|
},
|
||||||
stage_section: StageSection::Charge,
|
stage_section: StageSection::Charge,
|
||||||
timer: Duration::default(),
|
timer: Duration::default(),
|
||||||
@ -1657,6 +1693,27 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
|
|||||||
timer: Duration::default(),
|
timer: Duration::default(),
|
||||||
stage_section: StageSection::Buildup,
|
stage_section: StageSection::Buildup,
|
||||||
}),
|
}),
|
||||||
|
CharacterAbility::SelfBuff {
|
||||||
|
buildup_duration,
|
||||||
|
cast_duration,
|
||||||
|
recover_duration,
|
||||||
|
buff_kind,
|
||||||
|
buff_strength,
|
||||||
|
buff_duration,
|
||||||
|
energy_cost: _,
|
||||||
|
} => CharacterState::SelfBuff(self_buff::Data {
|
||||||
|
static_data: self_buff::StaticData {
|
||||||
|
buildup_duration: Duration::from_secs_f32(*buildup_duration),
|
||||||
|
cast_duration: Duration::from_secs_f32(*cast_duration),
|
||||||
|
recover_duration: Duration::from_secs_f32(*recover_duration),
|
||||||
|
buff_kind: *buff_kind,
|
||||||
|
buff_strength: *buff_strength,
|
||||||
|
buff_duration: buff_duration.map(Duration::from_secs_f32),
|
||||||
|
ability_info,
|
||||||
|
},
|
||||||
|
timer: Duration::default(),
|
||||||
|
stage_section: StageSection::Buildup,
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,7 @@ pub enum Tactic {
|
|||||||
Mindflayer,
|
Mindflayer,
|
||||||
BirdLargeBreathe,
|
BirdLargeBreathe,
|
||||||
BirdLargeFire,
|
BirdLargeFire,
|
||||||
|
Minotaur,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
@ -299,10 +300,17 @@ pub struct Agent {
|
|||||||
pub behavior: Behavior,
|
pub behavior: Behavior,
|
||||||
pub psyche: Psyche,
|
pub psyche: Psyche,
|
||||||
pub inbox: VecDeque<AgentEvent>,
|
pub inbox: VecDeque<AgentEvent>,
|
||||||
pub action_timer: f32,
|
pub action_state: ActionState,
|
||||||
pub bearing: Vec2<f32>,
|
pub bearing: Vec2<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
pub struct ActionState {
|
||||||
|
pub timer: f32,
|
||||||
|
pub counter: f32,
|
||||||
|
pub condition: bool,
|
||||||
|
}
|
||||||
|
|
||||||
impl Agent {
|
impl Agent {
|
||||||
pub fn with_patrol_origin(mut self, origin: Vec3<f32>) -> Self {
|
pub fn with_patrol_origin(mut self, origin: Vec3<f32>) -> Self {
|
||||||
self.patrol_origin = Some(origin);
|
self.patrol_origin = Some(origin);
|
||||||
|
@ -441,10 +441,10 @@ impl Body {
|
|||||||
biped_large::Species::Wendigo => 2800,
|
biped_large::Species::Wendigo => 2800,
|
||||||
biped_large::Species::Troll => 2400,
|
biped_large::Species::Troll => 2400,
|
||||||
biped_large::Species::Dullahan => 3000,
|
biped_large::Species::Dullahan => 3000,
|
||||||
biped_large::Species::Mindflayer => 8000,
|
biped_large::Species::Mindflayer => 25000,
|
||||||
biped_large::Species::Tidalwarrior => 2500,
|
biped_large::Species::Tidalwarrior => 2500,
|
||||||
biped_large::Species::Yeti => 4000,
|
biped_large::Species::Yeti => 4000,
|
||||||
biped_large::Species::Minotaur => 5000,
|
biped_large::Species::Minotaur => 30000,
|
||||||
biped_large::Species::Harvester => 3000,
|
biped_large::Species::Harvester => 3000,
|
||||||
biped_large::Species::Blueoni => 2400,
|
biped_large::Species::Blueoni => 2400,
|
||||||
biped_large::Species::Redoni => 2400,
|
biped_large::Species::Redoni => 2400,
|
||||||
@ -553,10 +553,12 @@ impl Body {
|
|||||||
biped_large::Species::Wendigo => 80,
|
biped_large::Species::Wendigo => 80,
|
||||||
biped_large::Species::Troll => 60,
|
biped_large::Species::Troll => 60,
|
||||||
biped_large::Species::Dullahan => 120,
|
biped_large::Species::Dullahan => 120,
|
||||||
biped_large::Species::Mindflayer => 250,
|
|
||||||
biped_large::Species::Tidalwarrior => 90,
|
biped_large::Species::Tidalwarrior => 90,
|
||||||
biped_large::Species::Yeti => 80,
|
biped_large::Species::Yeti => 80,
|
||||||
biped_large::Species::Harvester => 80,
|
biped_large::Species::Harvester => 80,
|
||||||
|
// Boss enemies have their health set, not adjusted by level.
|
||||||
|
biped_large::Species::Mindflayer => 0,
|
||||||
|
biped_large::Species::Minotaur => 0,
|
||||||
_ => 100,
|
_ => 100,
|
||||||
},
|
},
|
||||||
Body::BipedSmall(_) => 10,
|
Body::BipedSmall(_) => 10,
|
||||||
@ -605,7 +607,11 @@ impl Body {
|
|||||||
pub fn combat_multiplier(&self) -> f32 {
|
pub fn combat_multiplier(&self) -> f32 {
|
||||||
match self {
|
match self {
|
||||||
Body::Object(_) | Body::Ship(_) => 0.0,
|
Body::Object(_) | Body::Ship(_) => 0.0,
|
||||||
Body::BipedLarge(b) if matches!(b.species, biped_large::Species::Mindflayer) => 4.0,
|
Body::BipedLarge(b) => match b.species {
|
||||||
|
biped_large::Species::Mindflayer => 4.8,
|
||||||
|
biped_large::Species::Minotaur => 3.2,
|
||||||
|
_ => 1.0,
|
||||||
|
},
|
||||||
_ => 1.0,
|
_ => 1.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,33 +9,59 @@ use specs::{Component, DerefFlaggedStorage};
|
|||||||
use specs_idvs::IdvStorage;
|
use specs_idvs::IdvStorage;
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use std::{cmp::Ordering, time::Duration};
|
use std::{cmp::Ordering, time::Duration};
|
||||||
|
use strum_macros::EnumIter;
|
||||||
|
|
||||||
/// De/buff Kind.
|
/// De/buff Kind.
|
||||||
/// This is used to determine what effects a buff will have
|
/// This is used to determine what effects a buff will have
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize, Deserialize, PartialOrd, Ord)]
|
#[derive(
|
||||||
|
Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize, Deserialize, PartialOrd, Ord, EnumIter,
|
||||||
|
)]
|
||||||
pub enum BuffKind {
|
pub enum BuffKind {
|
||||||
/// Does damage to a creature over time
|
// Buffs
|
||||||
Burning,
|
|
||||||
/// Restores health/time for some period
|
/// Restores health/time for some period
|
||||||
|
/// Strength should be 10x the healing per second
|
||||||
Regeneration,
|
Regeneration,
|
||||||
/// Restores health/time for some period for consumables
|
/// Restores health/time for some period for consumables
|
||||||
|
/// Strength should be 10x the healing per second
|
||||||
Saturation,
|
Saturation,
|
||||||
/// Lowers health over time for some duration
|
|
||||||
Bleeding,
|
|
||||||
/// Lower a creature's max health over time
|
|
||||||
Cursed,
|
|
||||||
/// Applied when drinking a potion
|
/// Applied when drinking a potion
|
||||||
|
/// Strength should be 10x the healing per second
|
||||||
Potion,
|
Potion,
|
||||||
/// Applied when sitting at a campfire
|
/// Applied when sitting at a campfire
|
||||||
|
/// Strength is fraction of health resotred per second
|
||||||
CampfireHeal,
|
CampfireHeal,
|
||||||
/// Raises maximum stamina
|
/// Raises maximum stamina
|
||||||
|
/// Strength should be 10x the effect to max energy
|
||||||
IncreaseMaxEnergy,
|
IncreaseMaxEnergy,
|
||||||
/// Raises maximum health
|
/// Raises maximum health
|
||||||
|
/// Strength should be 10x the effect to max health
|
||||||
IncreaseMaxHealth,
|
IncreaseMaxHealth,
|
||||||
/// Makes you immune to attacks
|
/// Makes you immune to attacks
|
||||||
|
/// Strength does not affect this buff
|
||||||
Invulnerability,
|
Invulnerability,
|
||||||
/// Reduces incoming damage
|
/// Reduces incoming damage
|
||||||
|
/// Strength scales the damage reduction non-linearly. 0.5 provides 50% DR,
|
||||||
|
/// 1.0 provides 67% DR
|
||||||
ProtectingWard,
|
ProtectingWard,
|
||||||
|
/// Increases movement speed and gives health regeneration
|
||||||
|
/// Strength scales the movement speed linearly. 0.5 is 150% speed, 1.0 is
|
||||||
|
/// 200% speed. Provides regeneration at 10x the value of the strength
|
||||||
|
Frenzied,
|
||||||
|
// Debuffs
|
||||||
|
/// Does damage to a creature over time
|
||||||
|
/// Strength should be 10x the DPS of the debuff
|
||||||
|
Burning,
|
||||||
|
/// Lowers health over time for some duration
|
||||||
|
/// Strength should be 10x the DPS of the debuff
|
||||||
|
Bleeding,
|
||||||
|
/// Lower a creature's max health over time
|
||||||
|
/// Strength only affects the target max health, 0.5 targets 50% of base
|
||||||
|
/// max, 1.0 targets 100% of base max
|
||||||
|
Cursed,
|
||||||
|
/// Reduces movement speed and causes bleeding damage
|
||||||
|
/// Strength scales the movement speed debuff non-linearly. 0.5 is 50%
|
||||||
|
/// speed, 1.0 is 33% speed. Bleeding is at 10x the value of the strength.
|
||||||
|
Crippled,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
@ -54,6 +80,8 @@ impl BuffKind {
|
|||||||
BuffKind::Invulnerability => true,
|
BuffKind::Invulnerability => true,
|
||||||
BuffKind::ProtectingWard => true,
|
BuffKind::ProtectingWard => true,
|
||||||
BuffKind::Burning => false,
|
BuffKind::Burning => false,
|
||||||
|
BuffKind::Crippled => false,
|
||||||
|
BuffKind::Frenzied => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,6 +146,8 @@ pub enum BuffEffect {
|
|||||||
kind: ModifierKind,
|
kind: ModifierKind,
|
||||||
target_fraction: f32,
|
target_fraction: f32,
|
||||||
},
|
},
|
||||||
|
/// Modifies move speed of target
|
||||||
|
MovementSpeed(f32),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Actual de/buff.
|
/// Actual de/buff.
|
||||||
@ -174,6 +204,8 @@ impl Buff {
|
|||||||
cat_ids: Vec<BuffCategory>,
|
cat_ids: Vec<BuffCategory>,
|
||||||
source: BuffSource,
|
source: BuffSource,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
// Normalized nonlinear scaling
|
||||||
|
let nn_scaling = |a| a / (a + 0.5);
|
||||||
let (effects, time) = match kind {
|
let (effects, time) = match kind {
|
||||||
BuffKind::Bleeding => (
|
BuffKind::Bleeding => (
|
||||||
vec![BuffEffect::HealthChangeOverTime {
|
vec![BuffEffect::HealthChangeOverTime {
|
||||||
@ -235,7 +267,7 @@ impl Buff {
|
|||||||
// Causes non-linearity in effect strength, but necessary to allow for tool
|
// Causes non-linearity in effect strength, but necessary to allow for tool
|
||||||
// power and other things to affect the strength. 0.5 also still provides 50%
|
// power and other things to affect the strength. 0.5 also still provides 50%
|
||||||
// damage reduction.
|
// damage reduction.
|
||||||
data.strength / (0.5 + data.strength),
|
nn_scaling(data.strength),
|
||||||
)],
|
)],
|
||||||
data.duration,
|
data.duration,
|
||||||
),
|
),
|
||||||
@ -247,6 +279,28 @@ impl Buff {
|
|||||||
}],
|
}],
|
||||||
data.duration,
|
data.duration,
|
||||||
),
|
),
|
||||||
|
BuffKind::Crippled => (
|
||||||
|
vec![
|
||||||
|
BuffEffect::MovementSpeed(1.0 - nn_scaling(data.strength)),
|
||||||
|
BuffEffect::HealthChangeOverTime {
|
||||||
|
rate: -data.strength * 40.0,
|
||||||
|
accumulated: 0.0,
|
||||||
|
kind: ModifierKind::Additive,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
data.duration,
|
||||||
|
),
|
||||||
|
BuffKind::Frenzied => (
|
||||||
|
vec![
|
||||||
|
BuffEffect::MovementSpeed(1.0 + data.strength),
|
||||||
|
BuffEffect::HealthChangeOverTime {
|
||||||
|
rate: data.strength * 100.0,
|
||||||
|
accumulated: 0.0,
|
||||||
|
kind: ModifierKind::Additive,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
data.duration,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
Buff {
|
Buff {
|
||||||
kind,
|
kind,
|
||||||
|
@ -99,6 +99,8 @@ pub enum CharacterState {
|
|||||||
Blink(blink::Data),
|
Blink(blink::Data),
|
||||||
/// Summons creatures that fight for the caster
|
/// Summons creatures that fight for the caster
|
||||||
BasicSummon(basic_summon::Data),
|
BasicSummon(basic_summon::Data),
|
||||||
|
/// Inserts a buff on the caster
|
||||||
|
SelfBuff(self_buff::Data),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CharacterState {
|
impl CharacterState {
|
||||||
@ -120,6 +122,7 @@ impl CharacterState {
|
|||||||
| CharacterState::BasicBeam(_)
|
| CharacterState::BasicBeam(_)
|
||||||
| CharacterState::BasicAura(_)
|
| CharacterState::BasicAura(_)
|
||||||
| CharacterState::HealingBeam(_)
|
| CharacterState::HealingBeam(_)
|
||||||
|
| CharacterState::SelfBuff(_)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,6 +146,7 @@ impl CharacterState {
|
|||||||
| CharacterState::BasicBeam(_)
|
| CharacterState::BasicBeam(_)
|
||||||
| CharacterState::BasicAura(_)
|
| CharacterState::BasicAura(_)
|
||||||
| CharacterState::HealingBeam(_)
|
| CharacterState::HealingBeam(_)
|
||||||
|
| CharacterState::SelfBuff(_)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ pub struct Stats {
|
|||||||
pub name: String,
|
pub name: String,
|
||||||
pub damage_reduction: f32,
|
pub damage_reduction: f32,
|
||||||
pub max_health_modifier: f32,
|
pub max_health_modifier: f32,
|
||||||
|
pub move_speed_modifier: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Stats {
|
impl Stats {
|
||||||
@ -33,6 +34,7 @@ impl Stats {
|
|||||||
name,
|
name,
|
||||||
damage_reduction: 0.0,
|
damage_reduction: 0.0,
|
||||||
max_health_modifier: 1.0,
|
max_health_modifier: 1.0,
|
||||||
|
move_speed_modifier: 1.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,6 +45,7 @@ impl Stats {
|
|||||||
name: "".to_owned(),
|
name: "".to_owned(),
|
||||||
damage_reduction: 0.0,
|
damage_reduction: 0.0,
|
||||||
max_health_modifier: 1.0,
|
max_health_modifier: 1.0,
|
||||||
|
move_speed_modifier: 1.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,6 +53,7 @@ impl Stats {
|
|||||||
pub fn reset_temp_modifiers(&mut self) {
|
pub fn reset_temp_modifiers(&mut self) {
|
||||||
self.damage_reduction = 0.0;
|
self.damage_reduction = 0.0;
|
||||||
self.max_health_modifier = 1.0;
|
self.max_health_modifier = 1.0;
|
||||||
|
self.move_speed_modifier = 1.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +68,9 @@ pub enum Outcome {
|
|||||||
pos: Vec3<f32>,
|
pos: Vec3<f32>,
|
||||||
state: PoiseState,
|
state: PoiseState,
|
||||||
},
|
},
|
||||||
|
GroundSlam {
|
||||||
|
pos: Vec3<f32>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Outcome {
|
impl Outcome {
|
||||||
@ -81,7 +84,8 @@ impl Outcome {
|
|||||||
| Outcome::SummonedCreature { pos, .. }
|
| Outcome::SummonedCreature { pos, .. }
|
||||||
| Outcome::Damage { pos, .. }
|
| Outcome::Damage { pos, .. }
|
||||||
| Outcome::Block { pos, .. }
|
| Outcome::Block { pos, .. }
|
||||||
| Outcome::PoiseChange { pos, .. } => Some(*pos),
|
| Outcome::PoiseChange { pos, .. }
|
||||||
|
| Outcome::GroundSlam { pos } => Some(*pos),
|
||||||
Outcome::BreakBlock { pos, .. } => Some(pos.map(|e| e as f32 + 0.5)),
|
Outcome::BreakBlock { pos, .. } => Some(pos.map(|e| e as f32 + 0.5)),
|
||||||
Outcome::ExpChange { .. } | Outcome::ComboChange { .. } => None,
|
Outcome::ExpChange { .. } | Outcome::ComboChange { .. } => None,
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,8 @@ pub struct StaticData {
|
|||||||
pub range: f32,
|
pub range: f32,
|
||||||
/// Max angle (45.0 will give you a 90.0 angle window)
|
/// Max angle (45.0 will give you a 90.0 angle window)
|
||||||
pub max_angle: f32,
|
pub max_angle: f32,
|
||||||
|
/// Adds an effect onto the main damage of the attack
|
||||||
|
pub damage_effect: Option<CombatEffect>,
|
||||||
/// What key is used to press ability
|
/// What key is used to press ability
|
||||||
pub ability_info: AbilityInfo,
|
pub ability_info: AbilityInfo,
|
||||||
}
|
}
|
||||||
@ -50,6 +52,7 @@ impl CharacterBehavior for Data {
|
|||||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||||
let mut update = StateUpdate::from(data);
|
let mut update = StateUpdate::from(data);
|
||||||
|
|
||||||
|
handle_orientation(data, &mut update, 1.0);
|
||||||
handle_move(data, &mut update, 0.7);
|
handle_move(data, &mut update, 0.7);
|
||||||
handle_jump(data, &mut update, 1.0);
|
handle_jump(data, &mut update, 1.0);
|
||||||
handle_orientation(data, &mut update, 0.35);
|
handle_orientation(data, &mut update, 0.35);
|
||||||
@ -97,15 +100,20 @@ impl CharacterBehavior for Data {
|
|||||||
.with_requirement(CombatRequirement::AnyDamage);
|
.with_requirement(CombatRequirement::AnyDamage);
|
||||||
let energy = AttackEffect::new(None, CombatEffect::EnergyReward(50.0))
|
let energy = AttackEffect::new(None, CombatEffect::EnergyReward(50.0))
|
||||||
.with_requirement(CombatRequirement::AnyDamage);
|
.with_requirement(CombatRequirement::AnyDamage);
|
||||||
let buff = CombatEffect::Buff(CombatBuff::default_physical());
|
let mut damage = AttackDamage::new(
|
||||||
let damage = AttackDamage::new(
|
|
||||||
Damage {
|
Damage {
|
||||||
source: DamageSource::Melee,
|
source: DamageSource::Melee,
|
||||||
value: self.static_data.base_damage as f32,
|
value: self.static_data.base_damage as f32,
|
||||||
},
|
},
|
||||||
Some(GroupTarget::OutOfGroup),
|
Some(GroupTarget::OutOfGroup),
|
||||||
)
|
);
|
||||||
.with_effect(buff);
|
match self.static_data.damage_effect {
|
||||||
|
Some(effect) => damage = damage.with_effect(effect),
|
||||||
|
None => {
|
||||||
|
let buff = CombatEffect::Buff(CombatBuff::default_physical());
|
||||||
|
damage = damage.with_effect(buff);
|
||||||
|
},
|
||||||
|
}
|
||||||
let (crit_chance, crit_mult) =
|
let (crit_chance, crit_mult) =
|
||||||
get_crit_data(data, self.static_data.ability_info);
|
get_crit_data(data, self.static_data.ability_info);
|
||||||
let attack = Attack::default()
|
let attack = Attack::default()
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
combat::{Attack, AttackDamage, AttackEffect, CombatBuff, CombatEffect, CombatRequirement},
|
combat::{Attack, AttackDamage, AttackEffect, CombatBuff, CombatEffect, CombatRequirement},
|
||||||
comp::{tool::ToolKind, CharacterState, EnergyChange, EnergySource, Melee, StateUpdate},
|
comp::{tool::ToolKind, CharacterState, EnergyChange, EnergySource, Melee, StateUpdate},
|
||||||
|
event::LocalEvent,
|
||||||
|
outcome::Outcome,
|
||||||
states::{
|
states::{
|
||||||
behavior::{CharacterBehavior, JoinData},
|
behavior::{CharacterBehavior, JoinData},
|
||||||
utils::{StageSection, *},
|
utils::{StageSection, *},
|
||||||
@ -45,6 +47,8 @@ pub struct StaticData {
|
|||||||
pub recover_duration: Duration,
|
pub recover_duration: Duration,
|
||||||
/// What key is used to press ability
|
/// What key is used to press ability
|
||||||
pub ability_info: AbilityInfo,
|
pub ability_info: AbilityInfo,
|
||||||
|
/// Used to specify the melee attack to the frontend
|
||||||
|
pub specifier: Option<FrontendSpecifier>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
@ -199,6 +203,17 @@ impl CharacterBehavior for Data {
|
|||||||
})
|
})
|
||||||
.filter(|(_, tool)| tool == &Some(ToolKind::Pick)),
|
.filter(|(_, tool)| tool == &Some(ToolKind::Pick)),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if let Some(FrontendSpecifier::GroundCleave) = self.static_data.specifier {
|
||||||
|
// Send local event used for frontend shenanigans
|
||||||
|
update.local_events.push_front(LocalEvent::CreateOutcome(
|
||||||
|
Outcome::GroundSlam {
|
||||||
|
pos: data.pos.0
|
||||||
|
+ *data.ori.look_dir()
|
||||||
|
* (data.body.radius() + self.static_data.range),
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
} else if self.timer < self.static_data.swing_duration {
|
} else if self.timer < self.static_data.swing_duration {
|
||||||
// Swings
|
// Swings
|
||||||
update.character = CharacterState::ChargedMelee(Data {
|
update.character = CharacterState::ChargedMelee(Data {
|
||||||
@ -250,3 +265,9 @@ impl CharacterBehavior for Data {
|
|||||||
update
|
update
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Used to specify a particular effect for frontend purposes
|
||||||
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
pub enum FrontendSpecifier {
|
||||||
|
GroundCleave,
|
||||||
|
}
|
||||||
|
@ -71,12 +71,12 @@ impl CharacterBehavior for Data {
|
|||||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||||
let mut update = StateUpdate::from(data);
|
let mut update = StateUpdate::from(data);
|
||||||
|
|
||||||
handle_orientation(data, &mut update, 1.0);
|
|
||||||
handle_move(data, &mut update, 0.1);
|
handle_move(data, &mut update, 0.1);
|
||||||
|
|
||||||
match self.stage_section {
|
match self.stage_section {
|
||||||
StageSection::Buildup => {
|
StageSection::Buildup => {
|
||||||
if self.timer < self.static_data.buildup_duration {
|
if self.timer < self.static_data.buildup_duration {
|
||||||
|
handle_orientation(data, &mut update, 1.0);
|
||||||
// Build up
|
// Build up
|
||||||
update.character = CharacterState::DashMelee(Data {
|
update.character = CharacterState::DashMelee(Data {
|
||||||
timer: self
|
timer: self
|
||||||
@ -106,6 +106,7 @@ impl CharacterBehavior for Data {
|
|||||||
/ self.static_data.charge_duration.as_secs_f32())
|
/ self.static_data.charge_duration.as_secs_f32())
|
||||||
.min(1.0);
|
.min(1.0);
|
||||||
|
|
||||||
|
handle_orientation(data, &mut update, 0.6);
|
||||||
handle_forced_movement(
|
handle_forced_movement(
|
||||||
data,
|
data,
|
||||||
&mut update,
|
&mut update,
|
||||||
|
@ -21,6 +21,7 @@ pub mod idle;
|
|||||||
pub mod leap_melee;
|
pub mod leap_melee;
|
||||||
pub mod repeater_ranged;
|
pub mod repeater_ranged;
|
||||||
pub mod roll;
|
pub mod roll;
|
||||||
|
pub mod self_buff;
|
||||||
pub mod shockwave;
|
pub mod shockwave;
|
||||||
pub mod sit;
|
pub mod sit;
|
||||||
pub mod sneak;
|
pub mod sneak;
|
||||||
|
131
common/src/states/self_buff.rs
Normal file
131
common/src/states/self_buff.rs
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
use crate::{
|
||||||
|
comp::{
|
||||||
|
buff::{Buff, BuffChange, BuffData, BuffKind, BuffSource},
|
||||||
|
CharacterState, StateUpdate,
|
||||||
|
},
|
||||||
|
event::ServerEvent,
|
||||||
|
states::{
|
||||||
|
behavior::{CharacterBehavior, JoinData},
|
||||||
|
utils::*,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
/// Separated out to condense update portions of character state
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct StaticData {
|
||||||
|
/// How long until state should create the aura
|
||||||
|
pub buildup_duration: Duration,
|
||||||
|
/// How long the state is creating an aura
|
||||||
|
pub cast_duration: Duration,
|
||||||
|
/// How long the state has until exiting
|
||||||
|
pub recover_duration: Duration,
|
||||||
|
/// What kind of buff is created
|
||||||
|
pub buff_kind: BuffKind,
|
||||||
|
/// Strength of the created buff
|
||||||
|
pub buff_strength: f32,
|
||||||
|
/// How long buff lasts
|
||||||
|
pub buff_duration: Option<Duration>,
|
||||||
|
/// What key is used to press ability
|
||||||
|
pub ability_info: AbilityInfo,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct Data {
|
||||||
|
/// Struct containing data that does not change over the course of the
|
||||||
|
/// character state
|
||||||
|
pub static_data: StaticData,
|
||||||
|
/// Timer for each stage
|
||||||
|
pub timer: Duration,
|
||||||
|
/// What section the character stage is in
|
||||||
|
pub stage_section: StageSection,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CharacterBehavior for Data {
|
||||||
|
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||||
|
let mut update = StateUpdate::from(data);
|
||||||
|
|
||||||
|
handle_move(data, &mut update, 0.8);
|
||||||
|
handle_jump(data, &mut update, 1.0);
|
||||||
|
|
||||||
|
match self.stage_section {
|
||||||
|
StageSection::Buildup => {
|
||||||
|
if self.timer < self.static_data.buildup_duration {
|
||||||
|
// Build up
|
||||||
|
update.character = CharacterState::SelfBuff(Data {
|
||||||
|
timer: self
|
||||||
|
.timer
|
||||||
|
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||||
|
.unwrap_or_default(),
|
||||||
|
..*self
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Creates buff
|
||||||
|
let buff = Buff::new(
|
||||||
|
self.static_data.buff_kind,
|
||||||
|
BuffData {
|
||||||
|
strength: self.static_data.buff_strength,
|
||||||
|
duration: self.static_data.buff_duration,
|
||||||
|
},
|
||||||
|
Vec::new(),
|
||||||
|
BuffSource::Character { by: *data.uid },
|
||||||
|
);
|
||||||
|
update.server_events.push_front(ServerEvent::Buff {
|
||||||
|
entity: data.entity,
|
||||||
|
buff_change: BuffChange::Add(buff),
|
||||||
|
});
|
||||||
|
// Build up
|
||||||
|
update.character = CharacterState::SelfBuff(Data {
|
||||||
|
timer: Duration::default(),
|
||||||
|
stage_section: StageSection::Cast,
|
||||||
|
..*self
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
StageSection::Cast => {
|
||||||
|
if self.timer < self.static_data.cast_duration {
|
||||||
|
// Cast
|
||||||
|
update.character = CharacterState::SelfBuff(Data {
|
||||||
|
timer: self
|
||||||
|
.timer
|
||||||
|
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||||
|
.unwrap_or_default(),
|
||||||
|
..*self
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
update.character = CharacterState::SelfBuff(Data {
|
||||||
|
timer: Duration::default(),
|
||||||
|
stage_section: StageSection::Recover,
|
||||||
|
..*self
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
StageSection::Recover => {
|
||||||
|
if self.timer < self.static_data.recover_duration {
|
||||||
|
update.character = CharacterState::SelfBuff(Data {
|
||||||
|
timer: self
|
||||||
|
.timer
|
||||||
|
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||||
|
.unwrap_or_default(),
|
||||||
|
..*self
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Done
|
||||||
|
update.character = CharacterState::Wielding;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
// If it somehow ends up in an incorrect stage section
|
||||||
|
update.character = CharacterState::Wielding;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// At end of state logic so an interrupt isn't overwritten
|
||||||
|
if !input_is_pressed(data, self.static_data.ability_info.input) {
|
||||||
|
handle_state_interrupt(data, &mut update, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
update
|
||||||
|
}
|
||||||
|
}
|
@ -175,7 +175,6 @@ impl CharacterBehavior for Data {
|
|||||||
},
|
},
|
||||||
0.1,
|
0.1,
|
||||||
);
|
);
|
||||||
handle_orientation(data, &mut update, 1.0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Swings
|
// Swings
|
||||||
|
@ -71,7 +71,7 @@ impl Body {
|
|||||||
biped_large::Species::Occultsaurok => 100.0,
|
biped_large::Species::Occultsaurok => 100.0,
|
||||||
biped_large::Species::Mightysaurok => 100.0,
|
biped_large::Species::Mightysaurok => 100.0,
|
||||||
biped_large::Species::Mindflayer => 90.0,
|
biped_large::Species::Mindflayer => 90.0,
|
||||||
biped_large::Species::Minotaur => 90.0,
|
biped_large::Species::Minotaur => 60.0,
|
||||||
_ => 80.0,
|
_ => 80.0,
|
||||||
},
|
},
|
||||||
Body::BirdMedium(_) => 80.0,
|
Body::BirdMedium(_) => 80.0,
|
||||||
@ -243,6 +243,8 @@ pub fn handle_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32) {
|
|||||||
/// Updates components to move player as if theyre on ground or in air
|
/// Updates components to move player as if theyre on ground or in air
|
||||||
#[allow(clippy::assign_op_pattern)] // TODO: Pending review in #587
|
#[allow(clippy::assign_op_pattern)] // TODO: Pending review in #587
|
||||||
fn basic_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32) {
|
fn basic_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32) {
|
||||||
|
let efficiency = efficiency * data.stats.move_speed_modifier;
|
||||||
|
|
||||||
let accel = if data.physics.on_ground {
|
let accel = if data.physics.on_ground {
|
||||||
data.body.base_accel()
|
data.body.base_accel()
|
||||||
} else {
|
} else {
|
||||||
@ -267,6 +269,8 @@ pub fn handle_forced_movement(
|
|||||||
movement: ForcedMovement,
|
movement: ForcedMovement,
|
||||||
efficiency: f32,
|
efficiency: f32,
|
||||||
) {
|
) {
|
||||||
|
let efficiency = efficiency * data.stats.move_speed_modifier;
|
||||||
|
|
||||||
match movement {
|
match movement {
|
||||||
ForcedMovement::Forward { strength } => {
|
ForcedMovement::Forward { strength } => {
|
||||||
if let Some(accel) = data.physics.on_ground.then_some(data.body.base_accel()) {
|
if let Some(accel) = data.physics.on_ground.then_some(data.body.base_accel()) {
|
||||||
@ -324,6 +328,7 @@ pub fn handle_orientation(data: &JoinData, update: &mut StateUpdate, efficiency:
|
|||||||
|
|
||||||
/// Updates components to move player as if theyre swimming
|
/// Updates components to move player as if theyre swimming
|
||||||
fn swim_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32, submersion: f32) -> bool {
|
fn swim_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32, submersion: f32) -> bool {
|
||||||
|
let efficiency = efficiency * data.stats.move_speed_modifier;
|
||||||
if let Some(force) = data.body.swim_thrust() {
|
if let Some(force) = data.body.swim_thrust() {
|
||||||
let force = efficiency * force;
|
let force = efficiency * force;
|
||||||
let mut water_accel = force / data.mass.0;
|
let mut water_accel = force / data.mass.0;
|
||||||
@ -361,6 +366,8 @@ fn swim_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32, submers
|
|||||||
|
|
||||||
/// Updates components to move entity as if it's flying
|
/// Updates components to move entity as if it's flying
|
||||||
pub fn fly_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32) -> bool {
|
pub fn fly_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32) -> bool {
|
||||||
|
let efficiency = efficiency * data.stats.move_speed_modifier;
|
||||||
|
|
||||||
let glider = match data.character {
|
let glider = match data.character {
|
||||||
CharacterState::Glide(data) => Some(data),
|
CharacterState::Glide(data) => Some(data),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -189,6 +189,9 @@ impl<'a> System<'a> for Sys {
|
|||||||
stat.max_health_modifier *= current_fraction;
|
stat.max_health_modifier *= current_fraction;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
BuffEffect::MovementSpeed(ms) => {
|
||||||
|
stat.move_speed_modifier *= *ms;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -341,6 +341,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
CharacterState::HealingBeam(data) => data.handle_event(&j, action),
|
CharacterState::HealingBeam(data) => data.handle_event(&j, action),
|
||||||
CharacterState::Blink(data) => data.handle_event(&j, action),
|
CharacterState::Blink(data) => data.handle_event(&j, action),
|
||||||
CharacterState::BasicSummon(data) => data.handle_event(&j, action),
|
CharacterState::BasicSummon(data) => data.handle_event(&j, action),
|
||||||
|
CharacterState::SelfBuff(data) => data.handle_event(&j, action),
|
||||||
};
|
};
|
||||||
local_emitter.append(&mut state_update.local_events);
|
local_emitter.append(&mut state_update.local_events);
|
||||||
server_emitter.append(&mut state_update.server_events);
|
server_emitter.append(&mut state_update.server_events);
|
||||||
@ -395,6 +396,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
CharacterState::HealingBeam(data) => data.behavior(&j),
|
CharacterState::HealingBeam(data) => data.behavior(&j),
|
||||||
CharacterState::Blink(data) => data.behavior(&j),
|
CharacterState::Blink(data) => data.behavior(&j),
|
||||||
CharacterState::BasicSummon(data) => data.behavior(&j),
|
CharacterState::BasicSummon(data) => data.behavior(&j),
|
||||||
|
CharacterState::SelfBuff(data) => data.behavior(&j),
|
||||||
};
|
};
|
||||||
|
|
||||||
local_emitter.append(&mut state_update.local_events);
|
local_emitter.append(&mut state_update.local_events);
|
||||||
|
@ -248,7 +248,8 @@ impl<'a> System<'a> for Sys {
|
|||||||
| CharacterState::BasicAura { .. }
|
| CharacterState::BasicAura { .. }
|
||||||
| CharacterState::HealingBeam { .. }
|
| CharacterState::HealingBeam { .. }
|
||||||
| CharacterState::Blink { .. }
|
| CharacterState::Blink { .. }
|
||||||
| CharacterState::BasicSummon { .. } => {
|
| CharacterState::BasicSummon { .. }
|
||||||
|
| CharacterState::SelfBuff { .. } => {
|
||||||
if energy.get_unchecked().regen_rate != 0.0 {
|
if energy.get_unchecked().regen_rate != 0.0 {
|
||||||
energy.get_mut_unchecked().regen_rate = 0.0
|
energy.get_mut_unchecked().regen_rate = 0.0
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ use authc::Uuid;
|
|||||||
use chrono::{NaiveTime, Timelike};
|
use chrono::{NaiveTime, Timelike};
|
||||||
use common::{
|
use common::{
|
||||||
assets,
|
assets,
|
||||||
cmd::{ChatCommand, CHAT_COMMANDS, CHAT_SHORTCUTS},
|
cmd::{ChatCommand, BUFF_PACK, BUFF_PARSER, CHAT_COMMANDS, CHAT_SHORTCUTS},
|
||||||
comp::{
|
comp::{
|
||||||
self,
|
self,
|
||||||
aura::{Aura, AuraKind, AuraTarget},
|
aura::{Aura, AuraKind, AuraTarget},
|
||||||
@ -36,13 +36,11 @@ use common_net::{
|
|||||||
};
|
};
|
||||||
use common_state::{BuildAreaError, BuildAreas};
|
use common_state::{BuildAreaError, BuildAreas};
|
||||||
use core::{convert::TryFrom, ops::Not, time::Duration};
|
use core::{convert::TryFrom, ops::Not, time::Duration};
|
||||||
use hashbrown::HashSet;
|
use hashbrown::{HashMap, HashSet};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use specs::{Builder, Entity as EcsEntity, Join, WorldExt};
|
use specs::{Builder, Entity as EcsEntity, Join, WorldExt};
|
||||||
use wiring::{Circuit, Wire, WiringAction, WiringActionEffect, WiringElement};
|
|
||||||
|
|
||||||
use hashbrown::HashMap;
|
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
use wiring::{Circuit, Wire, WiringAction, WiringActionEffect, WiringElement};
|
||||||
use world::util::Sampler;
|
use world::util::Sampler;
|
||||||
|
|
||||||
use crate::{client::Client, login_provider::LoginProvider, wiring};
|
use crate::{client::Client, login_provider::LoginProvider, wiring};
|
||||||
@ -2615,22 +2613,6 @@ fn handle_apply_buff(
|
|||||||
args: String,
|
args: String,
|
||||||
action: &ChatCommand,
|
action: &ChatCommand,
|
||||||
) -> CmdResult<()> {
|
) -> CmdResult<()> {
|
||||||
const BUFF_PACK: &[&str] = &[
|
|
||||||
// Debuffs
|
|
||||||
"burning",
|
|
||||||
"bleeding",
|
|
||||||
"curse",
|
|
||||||
// Healing
|
|
||||||
"regeneration",
|
|
||||||
"saturation",
|
|
||||||
"potion",
|
|
||||||
"campfire_heal",
|
|
||||||
// Outmaxing stats
|
|
||||||
"increase_max_energy",
|
|
||||||
"increase_max_health",
|
|
||||||
// Defensive buffs (invulnerability is skipped because it ruins all debuffs)
|
|
||||||
"protecting_ward",
|
|
||||||
];
|
|
||||||
if let (Some(buff), strength, duration) =
|
if let (Some(buff), strength, duration) =
|
||||||
scan_fmt_some!(&args, &action.arg_fmt(), String, f32, f64)
|
scan_fmt_some!(&args, &action.arg_fmt(), String, f32, f64)
|
||||||
{
|
{
|
||||||
@ -2640,7 +2622,7 @@ fn handle_apply_buff(
|
|||||||
if buff != "all" {
|
if buff != "all" {
|
||||||
cast_buff(&buff, buffdata, server, target)
|
cast_buff(&buff, buffdata, server, target)
|
||||||
} else {
|
} else {
|
||||||
for kind in BUFF_PACK {
|
for kind in BUFF_PACK.iter() {
|
||||||
cast_buff(kind, buffdata, server, target)?;
|
cast_buff(kind, buffdata, server, target)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -2663,19 +2645,4 @@ fn cast_buff(kind: &str, data: BuffData, server: &mut Server, target: EcsEntity)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_buffkind(buff: &str) -> Option<BuffKind> {
|
fn parse_buffkind(buff: &str) -> Option<BuffKind> { BUFF_PARSER.get(buff).copied() }
|
||||||
match buff {
|
|
||||||
"burning" => Some(BuffKind::Burning),
|
|
||||||
"regeneration" => Some(BuffKind::Regeneration),
|
|
||||||
"saturation" => Some(BuffKind::Saturation),
|
|
||||||
"bleeding" => Some(BuffKind::Bleeding),
|
|
||||||
"curse" => Some(BuffKind::Cursed),
|
|
||||||
"potion" => Some(BuffKind::Potion),
|
|
||||||
"campfire_heal" => Some(BuffKind::CampfireHeal),
|
|
||||||
"increase_max_energy" => Some(BuffKind::IncreaseMaxEnergy),
|
|
||||||
"increase_max_health" => Some(BuffKind::IncreaseMaxHealth),
|
|
||||||
"invulnerability" => Some(BuffKind::Invulnerability),
|
|
||||||
"protecting_ward" => Some(BuffKind::ProtectingWard),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -550,10 +550,10 @@ impl<'a> AgentData<'a> {
|
|||||||
}
|
}
|
||||||
// Interact if incoming messages
|
// Interact if incoming messages
|
||||||
if !agent.inbox.is_empty() {
|
if !agent.inbox.is_empty() {
|
||||||
agent.action_timer = 0.1;
|
agent.action_state.timer = 0.1;
|
||||||
}
|
}
|
||||||
if agent.action_timer > 0.0 {
|
if agent.action_state.timer > 0.0 {
|
||||||
if agent.action_timer
|
if agent.action_state.timer
|
||||||
< (if agent.behavior.is(BehaviorState::TRADING) {
|
< (if agent.behavior.is(BehaviorState::TRADING) {
|
||||||
TRADE_INTERACTION_TIME
|
TRADE_INTERACTION_TIME
|
||||||
} else {
|
} else {
|
||||||
@ -562,7 +562,7 @@ impl<'a> AgentData<'a> {
|
|||||||
{
|
{
|
||||||
self.interact(agent, controller, &read_data, event_emitter);
|
self.interact(agent, controller, &read_data, event_emitter);
|
||||||
} else {
|
} else {
|
||||||
agent.action_timer = 0.0;
|
agent.action_state.timer = 0.0;
|
||||||
agent.target = None;
|
agent.target = None;
|
||||||
controller.actions.push(ControlAction::Stand);
|
controller.actions.push(ControlAction::Stand);
|
||||||
self.idle(agent, controller, &read_data);
|
self.idle(agent, controller, &read_data);
|
||||||
@ -582,7 +582,7 @@ impl<'a> AgentData<'a> {
|
|||||||
event_emitter: &mut Emitter<'_, ServerEvent>,
|
event_emitter: &mut Emitter<'_, ServerEvent>,
|
||||||
) {
|
) {
|
||||||
if self.damage < HEALING_ITEM_THRESHOLD && self.heal_self(agent, controller) {
|
if self.damage < HEALING_ITEM_THRESHOLD && self.heal_self(agent, controller) {
|
||||||
agent.action_timer = 0.01;
|
agent.action_state.timer = 0.01;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -596,12 +596,15 @@ impl<'a> AgentData<'a> {
|
|||||||
let dist_sqrd = self.pos.0.distance_squared(tgt_pos.0);
|
let dist_sqrd = self.pos.0.distance_squared(tgt_pos.0);
|
||||||
// Should the agent flee?
|
// Should the agent flee?
|
||||||
if 1.0 - agent.psyche.aggro > self.damage && self.flees {
|
if 1.0 - agent.psyche.aggro > self.damage && self.flees {
|
||||||
if agent.action_timer == 0.0 && agent.behavior.can(BehaviorCapability::SPEAK) {
|
if agent.action_state.timer == 0.0
|
||||||
|
&& agent.behavior.can(BehaviorCapability::SPEAK)
|
||||||
|
{
|
||||||
let msg = "npc.speech.villager_under_attack".to_string();
|
let msg = "npc.speech.villager_under_attack".to_string();
|
||||||
event_emitter
|
event_emitter
|
||||||
.emit(ServerEvent::Chat(UnresolvedChatMsg::npc(*self.uid, msg)));
|
.emit(ServerEvent::Chat(UnresolvedChatMsg::npc(*self.uid, msg)));
|
||||||
agent.action_timer = 0.01;
|
agent.action_state.timer = 0.01;
|
||||||
} else if agent.action_timer < FLEE_DURATION || dist_sqrd < MAX_FLEE_DIST {
|
} else if agent.action_state.timer < FLEE_DURATION || dist_sqrd < MAX_FLEE_DIST
|
||||||
|
{
|
||||||
self.flee(
|
self.flee(
|
||||||
agent,
|
agent,
|
||||||
controller,
|
controller,
|
||||||
@ -610,7 +613,7 @@ impl<'a> AgentData<'a> {
|
|||||||
&read_data.dt,
|
&read_data.dt,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
agent.action_timer = 0.0;
|
agent.action_state.timer = 0.0;
|
||||||
agent.target = None;
|
agent.target = None;
|
||||||
self.idle(agent, controller, &read_data);
|
self.idle(agent, controller, &read_data);
|
||||||
}
|
}
|
||||||
@ -705,11 +708,11 @@ impl<'a> AgentData<'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if self.damage < HEALING_ITEM_THRESHOLD && self.heal_self(agent, controller) {
|
if self.damage < HEALING_ITEM_THRESHOLD && self.heal_self(agent, controller) {
|
||||||
agent.action_timer = 0.01;
|
agent.action_state.timer = 0.01;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
agent.action_timer = 0.0;
|
agent.action_state.timer = 0.0;
|
||||||
if let Some((travel_to, _destination)) = &agent.rtsim_controller.travel_to {
|
if let Some((travel_to, _destination)) = &agent.rtsim_controller.travel_to {
|
||||||
// if it has an rtsim destination and can fly then it should
|
// if it has an rtsim destination and can fly then it should
|
||||||
// if it is flying and bumps something above it then it should move down
|
// if it is flying and bumps something above it then it should move down
|
||||||
@ -901,7 +904,7 @@ impl<'a> AgentData<'a> {
|
|||||||
// .events
|
// .events
|
||||||
// .push(ControlEvent::InviteResponse(InviteResponse::Decline));
|
// .push(ControlEvent::InviteResponse(InviteResponse::Decline));
|
||||||
// }
|
// }
|
||||||
agent.action_timer += read_data.dt.0;
|
agent.action_state.timer += read_data.dt.0;
|
||||||
let msg = agent.inbox.pop_back();
|
let msg = agent.inbox.pop_back();
|
||||||
match msg {
|
match msg {
|
||||||
Some(AgentEvent::Talk(by, subject)) => {
|
Some(AgentEvent::Talk(by, subject)) => {
|
||||||
@ -1250,7 +1253,7 @@ impl<'a> AgentData<'a> {
|
|||||||
if let Some(Target { target, .. }) = &agent.target {
|
if let Some(Target { target, .. }) = &agent.target {
|
||||||
self.look_toward(controller, read_data, target);
|
self.look_toward(controller, read_data, target);
|
||||||
} else {
|
} else {
|
||||||
agent.action_timer = 0.0;
|
agent.action_state.timer = 0.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1314,7 +1317,7 @@ impl<'a> AgentData<'a> {
|
|||||||
self.jump_if(controller, bearing.z > 1.5);
|
self.jump_if(controller, bearing.z > 1.5);
|
||||||
controller.inputs.move_z = bearing.z;
|
controller.inputs.move_z = bearing.z;
|
||||||
}
|
}
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to consume a healing item, and return whether any healing items
|
/// Attempt to consume a healing item, and return whether any healing items
|
||||||
@ -1379,7 +1382,7 @@ impl<'a> AgentData<'a> {
|
|||||||
read_data: &ReadData,
|
read_data: &ReadData,
|
||||||
event_emitter: &mut Emitter<'_, ServerEvent>,
|
event_emitter: &mut Emitter<'_, ServerEvent>,
|
||||||
) {
|
) {
|
||||||
agent.action_timer = 0.0;
|
agent.action_state.timer = 0.0;
|
||||||
|
|
||||||
// Search area
|
// Search area
|
||||||
let target = self.cached_spatial_grid.0
|
let target = self.cached_spatial_grid.0
|
||||||
@ -1538,6 +1541,7 @@ impl<'a> AgentData<'a> {
|
|||||||
"Bird Large Breathe" => Tactic::BirdLargeBreathe,
|
"Bird Large Breathe" => Tactic::BirdLargeBreathe,
|
||||||
"Bird Large Fire" => Tactic::BirdLargeFire,
|
"Bird Large Fire" => Tactic::BirdLargeFire,
|
||||||
"Mindflayer" => Tactic::Mindflayer,
|
"Mindflayer" => Tactic::Mindflayer,
|
||||||
|
"Minotaur" => Tactic::Minotaur,
|
||||||
_ => Tactic::Melee,
|
_ => Tactic::Melee,
|
||||||
},
|
},
|
||||||
AbilitySpec::Tool(tool_kind) => tool_tactic(*tool_kind),
|
AbilitySpec::Tool(tool_kind) => tool_tactic(*tool_kind),
|
||||||
@ -1644,16 +1648,16 @@ impl<'a> AgentData<'a> {
|
|||||||
Tactic::Axe => {
|
Tactic::Axe => {
|
||||||
if dist_sqrd < min_attack_dist.powi(2) && angle < 45.0 {
|
if dist_sqrd < min_attack_dist.powi(2) && angle < 45.0 {
|
||||||
controller.inputs.move_dir = Vec2::zero();
|
controller.inputs.move_dir = Vec2::zero();
|
||||||
if agent.action_timer > 6.0 {
|
if agent.action_state.timer > 6.0 {
|
||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::CancelInput(InputKind::Secondary));
|
.push(ControlAction::CancelInput(InputKind::Secondary));
|
||||||
agent.action_timer = 0.0;
|
agent.action_state.timer = 0.0;
|
||||||
} else if agent.action_timer > 4.0 && self.energy.current() > 10 {
|
} else if agent.action_state.timer > 4.0 && self.energy.current() > 10 {
|
||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Secondary));
|
.push(ControlAction::basic_input(InputKind::Secondary));
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
} else if self.skill_set.has_skill(Skill::Axe(AxeSkill::UnlockLeap))
|
} else if self.skill_set.has_skill(Skill::Axe(AxeSkill::UnlockLeap))
|
||||||
&& self.energy.current() > 800
|
&& self.energy.current() > 800
|
||||||
&& thread_rng().gen_bool(0.5)
|
&& thread_rng().gen_bool(0.5)
|
||||||
@ -1661,12 +1665,12 @@ impl<'a> AgentData<'a> {
|
|||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Ability(0)));
|
.push(ControlAction::basic_input(InputKind::Ability(0)));
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
} else {
|
} else {
|
||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Primary));
|
.push(ControlAction::basic_input(InputKind::Primary));
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
}
|
}
|
||||||
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
||||||
if let Some((bearing, speed)) = agent.chaser.chase(
|
if let Some((bearing, speed)) = agent.chaser.chase(
|
||||||
@ -1699,16 +1703,16 @@ impl<'a> AgentData<'a> {
|
|||||||
Tactic::Hammer => {
|
Tactic::Hammer => {
|
||||||
if dist_sqrd < min_attack_dist.powi(2) && angle < 45.0 {
|
if dist_sqrd < min_attack_dist.powi(2) && angle < 45.0 {
|
||||||
controller.inputs.move_dir = Vec2::zero();
|
controller.inputs.move_dir = Vec2::zero();
|
||||||
if agent.action_timer > 4.0 {
|
if agent.action_state.timer > 4.0 {
|
||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::CancelInput(InputKind::Secondary));
|
.push(ControlAction::CancelInput(InputKind::Secondary));
|
||||||
agent.action_timer = 0.0;
|
agent.action_state.timer = 0.0;
|
||||||
} else if agent.action_timer > 2.0 {
|
} else if agent.action_state.timer > 2.0 {
|
||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Secondary));
|
.push(ControlAction::basic_input(InputKind::Secondary));
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
} else if self
|
} else if self
|
||||||
.skill_set
|
.skill_set
|
||||||
.has_skill(Skill::Hammer(HammerSkill::UnlockLeap))
|
.has_skill(Skill::Hammer(HammerSkill::UnlockLeap))
|
||||||
@ -1718,12 +1722,12 @@ impl<'a> AgentData<'a> {
|
|||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Ability(0)));
|
.push(ControlAction::basic_input(InputKind::Ability(0)));
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
} else {
|
} else {
|
||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Primary));
|
.push(ControlAction::basic_input(InputKind::Primary));
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
}
|
}
|
||||||
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
||||||
if let Some((bearing, speed)) = agent.chaser.chase(
|
if let Some((bearing, speed)) = agent.chaser.chase(
|
||||||
@ -1742,14 +1746,14 @@ impl<'a> AgentData<'a> {
|
|||||||
if self
|
if self
|
||||||
.skill_set
|
.skill_set
|
||||||
.has_skill(Skill::Hammer(HammerSkill::UnlockLeap))
|
.has_skill(Skill::Hammer(HammerSkill::UnlockLeap))
|
||||||
&& agent.action_timer > 5.0
|
&& agent.action_state.timer > 5.0
|
||||||
{
|
{
|
||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Ability(0)));
|
.push(ControlAction::basic_input(InputKind::Ability(0)));
|
||||||
agent.action_timer = 0.0;
|
agent.action_state.timer = 0.0;
|
||||||
} else {
|
} else {
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
controller.inputs.move_dir =
|
controller.inputs.move_dir =
|
||||||
@ -1776,20 +1780,20 @@ impl<'a> AgentData<'a> {
|
|||||||
if self
|
if self
|
||||||
.skill_set
|
.skill_set
|
||||||
.has_skill(Skill::Sword(SwordSkill::UnlockSpin))
|
.has_skill(Skill::Sword(SwordSkill::UnlockSpin))
|
||||||
&& agent.action_timer < 2.0
|
&& agent.action_state.timer < 2.0
|
||||||
&& self.energy.current() > 600
|
&& self.energy.current() > 600
|
||||||
{
|
{
|
||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Ability(0)));
|
.push(ControlAction::basic_input(InputKind::Ability(0)));
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
} else if agent.action_timer > 2.0 {
|
} else if agent.action_state.timer > 2.0 {
|
||||||
agent.action_timer = 0.0;
|
agent.action_state.timer = 0.0;
|
||||||
} else {
|
} else {
|
||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Primary));
|
.push(ControlAction::basic_input(InputKind::Primary));
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
}
|
}
|
||||||
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
||||||
if let Some((bearing, speed)) = agent.chaser.chase(
|
if let Some((bearing, speed)) = agent.chaser.chase(
|
||||||
@ -1805,13 +1809,13 @@ impl<'a> AgentData<'a> {
|
|||||||
if can_see_tgt(&*terrain, self.pos, tgt_pos, dist_sqrd) {
|
if can_see_tgt(&*terrain, self.pos, tgt_pos, dist_sqrd) {
|
||||||
controller.inputs.move_dir =
|
controller.inputs.move_dir =
|
||||||
bearing.xy().try_normalized().unwrap_or_else(Vec2::zero) * speed;
|
bearing.xy().try_normalized().unwrap_or_else(Vec2::zero) * speed;
|
||||||
if agent.action_timer > 4.0 && angle < 45.0 {
|
if agent.action_state.timer > 4.0 && angle < 45.0 {
|
||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Secondary));
|
.push(ControlAction::basic_input(InputKind::Secondary));
|
||||||
agent.action_timer = 0.0;
|
agent.action_state.timer = 0.0;
|
||||||
} else {
|
} else {
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
controller.inputs.move_dir =
|
controller.inputs.move_dir =
|
||||||
@ -1886,16 +1890,17 @@ impl<'a> AgentData<'a> {
|
|||||||
.try_normalized()
|
.try_normalized()
|
||||||
.unwrap_or_else(Vec2::zero)
|
.unwrap_or_else(Vec2::zero)
|
||||||
* speed;
|
* speed;
|
||||||
if agent.action_timer > 4.0 {
|
if agent.action_state.timer > 4.0 {
|
||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::CancelInput(InputKind::Secondary));
|
.push(ControlAction::CancelInput(InputKind::Secondary));
|
||||||
agent.action_timer = 0.0;
|
agent.action_state.timer = 0.0;
|
||||||
} else if agent.action_timer > 2.0 && self.energy.current() > 300 {
|
} else if agent.action_state.timer > 2.0 && self.energy.current() > 300
|
||||||
|
{
|
||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Secondary));
|
.push(ControlAction::basic_input(InputKind::Secondary));
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
} else if self
|
} else if self
|
||||||
.skill_set
|
.skill_set
|
||||||
.has_skill(Skill::Bow(BowSkill::UnlockRepeater))
|
.has_skill(Skill::Bow(BowSkill::UnlockRepeater))
|
||||||
@ -1908,7 +1913,7 @@ impl<'a> AgentData<'a> {
|
|||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Ability(0)));
|
.push(ControlAction::basic_input(InputKind::Ability(0)));
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
} else {
|
} else {
|
||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
@ -1916,7 +1921,7 @@ impl<'a> AgentData<'a> {
|
|||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Primary));
|
.push(ControlAction::basic_input(InputKind::Primary));
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
controller.inputs.move_dir =
|
controller.inputs.move_dir =
|
||||||
@ -1961,22 +1966,22 @@ impl<'a> AgentData<'a> {
|
|||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Roll));
|
.push(ControlAction::basic_input(InputKind::Roll));
|
||||||
} else if dist_sqrd < (5.0 * min_attack_dist).powi(2) && angle < 15.0 {
|
} else if dist_sqrd < (5.0 * min_attack_dist).powi(2) && angle < 15.0 {
|
||||||
if agent.action_timer < 1.5 {
|
if agent.action_state.timer < 1.5 {
|
||||||
controller.inputs.move_dir = (tgt_pos.0 - self.pos.0)
|
controller.inputs.move_dir = (tgt_pos.0 - self.pos.0)
|
||||||
.xy()
|
.xy()
|
||||||
.rotated_z(0.47 * PI)
|
.rotated_z(0.47 * PI)
|
||||||
.try_normalized()
|
.try_normalized()
|
||||||
.unwrap_or_else(Vec2::unit_y);
|
.unwrap_or_else(Vec2::unit_y);
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
} else if agent.action_timer < 3.0 {
|
} else if agent.action_state.timer < 3.0 {
|
||||||
controller.inputs.move_dir = (tgt_pos.0 - self.pos.0)
|
controller.inputs.move_dir = (tgt_pos.0 - self.pos.0)
|
||||||
.xy()
|
.xy()
|
||||||
.rotated_z(-0.47 * PI)
|
.rotated_z(-0.47 * PI)
|
||||||
.try_normalized()
|
.try_normalized()
|
||||||
.unwrap_or_else(Vec2::unit_y);
|
.unwrap_or_else(Vec2::unit_y);
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
} else {
|
} else {
|
||||||
agent.action_timer = 0.0;
|
agent.action_state.timer = 0.0;
|
||||||
}
|
}
|
||||||
if self
|
if self
|
||||||
.skill_set
|
.skill_set
|
||||||
@ -2080,13 +2085,13 @@ impl<'a> AgentData<'a> {
|
|||||||
if can_see_tgt(&*terrain, self.pos, tgt_pos, dist_sqrd) && angle < 90.0 {
|
if can_see_tgt(&*terrain, self.pos, tgt_pos, dist_sqrd) && angle < 90.0 {
|
||||||
controller.inputs.move_dir =
|
controller.inputs.move_dir =
|
||||||
bearing.xy().try_normalized().unwrap_or_else(Vec2::zero) * speed;
|
bearing.xy().try_normalized().unwrap_or_else(Vec2::zero) * speed;
|
||||||
if agent.action_timer > 5.0 {
|
if agent.action_state.timer > 5.0 {
|
||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Secondary));
|
.push(ControlAction::basic_input(InputKind::Secondary));
|
||||||
agent.action_timer = 0.0;
|
agent.action_state.timer = 0.0;
|
||||||
} else {
|
} else {
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
controller.inputs.move_dir =
|
controller.inputs.move_dir =
|
||||||
@ -2116,7 +2121,7 @@ impl<'a> AgentData<'a> {
|
|||||||
} else if dist_sqrd < ((radius as f32 + 1.0) * min_attack_dist).powi(2)
|
} else if dist_sqrd < ((radius as f32 + 1.0) * min_attack_dist).powi(2)
|
||||||
&& dist_sqrd > (radius as f32 * min_attack_dist).powi(2)
|
&& dist_sqrd > (radius as f32 * min_attack_dist).powi(2)
|
||||||
{
|
{
|
||||||
if agent.action_timer < circle_time as f32 {
|
if agent.action_state.timer < circle_time as f32 {
|
||||||
let move_dir = (tgt_pos.0 - self.pos.0)
|
let move_dir = (tgt_pos.0 - self.pos.0)
|
||||||
.xy()
|
.xy()
|
||||||
.rotated_z(0.47 * PI)
|
.rotated_z(0.47 * PI)
|
||||||
@ -2133,16 +2138,16 @@ impl<'a> AgentData<'a> {
|
|||||||
.1
|
.1
|
||||||
.map_or(true, |b| b.is_some());
|
.map_or(true, |b| b.is_some());
|
||||||
if obstacle_left {
|
if obstacle_left {
|
||||||
agent.action_timer = circle_time as f32;
|
agent.action_state.timer = circle_time as f32;
|
||||||
}
|
}
|
||||||
controller.inputs.move_dir = move_dir;
|
controller.inputs.move_dir = move_dir;
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
} else if agent.action_timer < circle_time as f32 + 0.5 {
|
} else if agent.action_state.timer < circle_time as f32 + 0.5 {
|
||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Secondary));
|
.push(ControlAction::basic_input(InputKind::Secondary));
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
} else if agent.action_timer < 2.0 * circle_time as f32 + 0.5 {
|
} else if agent.action_state.timer < 2.0 * circle_time as f32 + 0.5 {
|
||||||
let move_dir = (tgt_pos.0 - self.pos.0)
|
let move_dir = (tgt_pos.0 - self.pos.0)
|
||||||
.xy()
|
.xy()
|
||||||
.rotated_z(-0.47 * PI)
|
.rotated_z(-0.47 * PI)
|
||||||
@ -2159,20 +2164,20 @@ impl<'a> AgentData<'a> {
|
|||||||
.1
|
.1
|
||||||
.map_or(true, |b| b.is_some());
|
.map_or(true, |b| b.is_some());
|
||||||
if obstacle_right {
|
if obstacle_right {
|
||||||
agent.action_timer = 2.0 * circle_time as f32 + 0.5;
|
agent.action_state.timer = 2.0 * circle_time as f32 + 0.5;
|
||||||
}
|
}
|
||||||
controller.inputs.move_dir = move_dir;
|
controller.inputs.move_dir = move_dir;
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
} else if agent.action_timer < 2.0 * circle_time as f32 + 1.0 {
|
} else if agent.action_state.timer < 2.0 * circle_time as f32 + 1.0 {
|
||||||
if agent.action_timer < 2.0 * circle_time as f32 {
|
if agent.action_state.timer < 2.0 * circle_time as f32 {
|
||||||
agent.action_timer = 2.0 * circle_time as f32;
|
agent.action_state.timer = 2.0 * circle_time as f32;
|
||||||
}
|
}
|
||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Secondary));
|
.push(ControlAction::basic_input(InputKind::Secondary));
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
} else {
|
} else {
|
||||||
agent.action_timer = 0.0;
|
agent.action_state.timer = 0.0;
|
||||||
}
|
}
|
||||||
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
||||||
if let Some((bearing, speed)) = agent.chaser.chase(
|
if let Some((bearing, speed)) = agent.chaser.chase(
|
||||||
@ -2215,16 +2220,16 @@ impl<'a> AgentData<'a> {
|
|||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
if can_see_tgt(&*terrain, self.pos, tgt_pos, dist_sqrd) && angle < 15.0 {
|
if can_see_tgt(&*terrain, self.pos, tgt_pos, dist_sqrd) && angle < 15.0 {
|
||||||
if agent.action_timer > 5.0 {
|
if agent.action_state.timer > 5.0 {
|
||||||
agent.action_timer = 0.0;
|
agent.action_state.timer = 0.0;
|
||||||
} else if agent.action_timer > 2.5 {
|
} else if agent.action_state.timer > 2.5 {
|
||||||
controller.inputs.move_dir = (tgt_pos.0 - self.pos.0)
|
controller.inputs.move_dir = (tgt_pos.0 - self.pos.0)
|
||||||
.xy()
|
.xy()
|
||||||
.rotated_z(1.75 * PI)
|
.rotated_z(1.75 * PI)
|
||||||
.try_normalized()
|
.try_normalized()
|
||||||
.unwrap_or_else(Vec2::zero)
|
.unwrap_or_else(Vec2::zero)
|
||||||
* speed;
|
* speed;
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
} else {
|
} else {
|
||||||
controller.inputs.move_dir = (tgt_pos.0 - self.pos.0)
|
controller.inputs.move_dir = (tgt_pos.0 - self.pos.0)
|
||||||
.xy()
|
.xy()
|
||||||
@ -2232,7 +2237,7 @@ impl<'a> AgentData<'a> {
|
|||||||
.try_normalized()
|
.try_normalized()
|
||||||
.unwrap_or_else(Vec2::zero)
|
.unwrap_or_else(Vec2::zero)
|
||||||
* speed;
|
* speed;
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
}
|
}
|
||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
@ -2254,21 +2259,21 @@ impl<'a> AgentData<'a> {
|
|||||||
},
|
},
|
||||||
Tactic::TailSlap => {
|
Tactic::TailSlap => {
|
||||||
if dist_sqrd < (1.5 * min_attack_dist).powi(2) && angle < 90.0 {
|
if dist_sqrd < (1.5 * min_attack_dist).powi(2) && angle < 90.0 {
|
||||||
if agent.action_timer > 4.0 {
|
if agent.action_state.timer > 4.0 {
|
||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::CancelInput(InputKind::Primary));
|
.push(ControlAction::CancelInput(InputKind::Primary));
|
||||||
agent.action_timer = 0.0;
|
agent.action_state.timer = 0.0;
|
||||||
} else if agent.action_timer > 1.0 {
|
} else if agent.action_state.timer > 1.0 {
|
||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Primary));
|
.push(ControlAction::basic_input(InputKind::Primary));
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
} else {
|
} else {
|
||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Secondary));
|
.push(ControlAction::basic_input(InputKind::Secondary));
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
}
|
}
|
||||||
controller.inputs.move_dir = (tgt_pos.0 - self.pos.0)
|
controller.inputs.move_dir = (tgt_pos.0 - self.pos.0)
|
||||||
.xy()
|
.xy()
|
||||||
@ -2336,18 +2341,18 @@ impl<'a> AgentData<'a> {
|
|||||||
Tactic::QuadLowBasic => {
|
Tactic::QuadLowBasic => {
|
||||||
if dist_sqrd < (1.5 * min_attack_dist).powi(2) {
|
if dist_sqrd < (1.5 * min_attack_dist).powi(2) {
|
||||||
controller.inputs.move_dir = Vec2::zero();
|
controller.inputs.move_dir = Vec2::zero();
|
||||||
if agent.action_timer > 5.0 {
|
if agent.action_state.timer > 5.0 {
|
||||||
agent.action_timer = 0.0;
|
agent.action_state.timer = 0.0;
|
||||||
} else if agent.action_timer > 2.0 && angle < 90.0 {
|
} else if agent.action_state.timer > 2.0 && angle < 90.0 {
|
||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Secondary));
|
.push(ControlAction::basic_input(InputKind::Secondary));
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
} else if angle < 90.0 {
|
} else if angle < 90.0 {
|
||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Primary));
|
.push(ControlAction::basic_input(InputKind::Primary));
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
}
|
}
|
||||||
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
||||||
if let Some((bearing, speed)) = agent.chaser.chase(
|
if let Some((bearing, speed)) = agent.chaser.chase(
|
||||||
@ -2410,18 +2415,18 @@ impl<'a> AgentData<'a> {
|
|||||||
Tactic::QuadMedBasic => {
|
Tactic::QuadMedBasic => {
|
||||||
if dist_sqrd < min_attack_dist.powi(2) && angle < 90.0 {
|
if dist_sqrd < min_attack_dist.powi(2) && angle < 90.0 {
|
||||||
controller.inputs.move_dir = Vec2::zero();
|
controller.inputs.move_dir = Vec2::zero();
|
||||||
if agent.action_timer < 2.0 {
|
if agent.action_state.timer < 2.0 {
|
||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Secondary));
|
.push(ControlAction::basic_input(InputKind::Secondary));
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
} else if agent.action_timer < 3.0 {
|
} else if agent.action_state.timer < 3.0 {
|
||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Primary));
|
.push(ControlAction::basic_input(InputKind::Primary));
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
} else {
|
} else {
|
||||||
agent.action_timer = 0.0;
|
agent.action_state.timer = 0.0;
|
||||||
}
|
}
|
||||||
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
||||||
if let Some((bearing, speed)) = agent.chaser.chase(
|
if let Some((bearing, speed)) = agent.chaser.chase(
|
||||||
@ -2450,7 +2455,7 @@ impl<'a> AgentData<'a> {
|
|||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Secondary));
|
.push(ControlAction::basic_input(InputKind::Secondary));
|
||||||
} else if dist_sqrd < (7.0 * min_attack_dist).powi(2) && angle < 15.0 {
|
} else if dist_sqrd < (7.0 * min_attack_dist).powi(2) && angle < 15.0 {
|
||||||
if agent.action_timer < 2.0 {
|
if agent.action_state.timer < 2.0 {
|
||||||
controller.inputs.move_dir = (tgt_pos.0 - self.pos.0)
|
controller.inputs.move_dir = (tgt_pos.0 - self.pos.0)
|
||||||
.xy()
|
.xy()
|
||||||
.rotated_z(0.47 * PI)
|
.rotated_z(0.47 * PI)
|
||||||
@ -2459,8 +2464,8 @@ impl<'a> AgentData<'a> {
|
|||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Primary));
|
.push(ControlAction::basic_input(InputKind::Primary));
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
} else if agent.action_timer < 4.0 && angle < 15.0 {
|
} else if agent.action_state.timer < 4.0 && angle < 15.0 {
|
||||||
controller.inputs.move_dir = (tgt_pos.0 - self.pos.0)
|
controller.inputs.move_dir = (tgt_pos.0 - self.pos.0)
|
||||||
.xy()
|
.xy()
|
||||||
.rotated_z(-0.47 * PI)
|
.rotated_z(-0.47 * PI)
|
||||||
@ -2469,14 +2474,14 @@ impl<'a> AgentData<'a> {
|
|||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Primary));
|
.push(ControlAction::basic_input(InputKind::Primary));
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
} else if agent.action_timer < 6.0 && angle < 15.0 {
|
} else if agent.action_state.timer < 6.0 && angle < 15.0 {
|
||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Ability(0)));
|
.push(ControlAction::basic_input(InputKind::Ability(0)));
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
} else {
|
} else {
|
||||||
agent.action_timer = 0.0;
|
agent.action_state.timer = 0.0;
|
||||||
}
|
}
|
||||||
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
||||||
if let Some((bearing, speed)) = agent.chaser.chase(
|
if let Some((bearing, speed)) = agent.chaser.chase(
|
||||||
@ -2563,21 +2568,20 @@ impl<'a> AgentData<'a> {
|
|||||||
const MINDFLAYER_ATTACK_DIST: f32 = 16.0;
|
const MINDFLAYER_ATTACK_DIST: f32 = 16.0;
|
||||||
const MINION_SUMMON_THRESHOLD: f32 = 0.20;
|
const MINION_SUMMON_THRESHOLD: f32 = 0.20;
|
||||||
let health_fraction = self.health.map_or(0.5, |h| h.fraction());
|
let health_fraction = self.health.map_or(0.5, |h| h.fraction());
|
||||||
// Extreme hack to set action_timer at start of combat
|
// Sets counter at start of combat
|
||||||
if agent.action_timer < MINION_SUMMON_THRESHOLD
|
if agent.action_state.condition {
|
||||||
&& health_fraction > MINION_SUMMON_THRESHOLD
|
agent.action_state.counter = 1.0 - MINION_SUMMON_THRESHOLD;
|
||||||
{
|
agent.action_state.condition = true;
|
||||||
agent.action_timer = health_fraction - MINION_SUMMON_THRESHOLD;
|
|
||||||
}
|
}
|
||||||
let mindflayer_is_far = dist_sqrd > MINDFLAYER_ATTACK_DIST.powi(2);
|
let mindflayer_is_far = dist_sqrd > MINDFLAYER_ATTACK_DIST.powi(2);
|
||||||
if agent.action_timer > health_fraction {
|
if agent.action_state.counter > health_fraction {
|
||||||
// Summon minions at particular thresholds of health
|
// Summon minions at particular thresholds of health
|
||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Ability(1)));
|
.push(ControlAction::basic_input(InputKind::Ability(1)));
|
||||||
if matches!(self.char_state, CharacterState::BasicSummon(c) if matches!(c.stage_section, StageSection::Recover))
|
if matches!(self.char_state, CharacterState::BasicSummon(c) if matches!(c.stage_section, StageSection::Recover))
|
||||||
{
|
{
|
||||||
agent.action_timer -= MINION_SUMMON_THRESHOLD;
|
agent.action_state.counter -= MINION_SUMMON_THRESHOLD;
|
||||||
}
|
}
|
||||||
} else if mindflayer_is_far {
|
} else if mindflayer_is_far {
|
||||||
// If too far from target, blink to them.
|
// If too far from target, blink to them.
|
||||||
@ -2605,7 +2609,7 @@ impl<'a> AgentData<'a> {
|
|||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Secondary));
|
.push(ControlAction::basic_input(InputKind::Secondary));
|
||||||
} else if thread_rng().gen_bool(health_fraction.into()) && angle < 30.0 {
|
} else if thread_rng().gen_bool(health_fraction.into()) {
|
||||||
// Else if at high health, use primary
|
// Else if at high health, use primary
|
||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
@ -2866,18 +2870,92 @@ impl<'a> AgentData<'a> {
|
|||||||
self.jump_if(controller, bearing.z > 1.5);
|
self.jump_if(controller, bearing.z > 1.5);
|
||||||
controller.inputs.move_z = bearing.z;
|
controller.inputs.move_z = bearing.z;
|
||||||
}
|
}
|
||||||
} else if self.energy.current() > 600 && agent.action_timer < 3.0 && angle < 15.0 {
|
} else if self.energy.current() > 600
|
||||||
|
&& agent.action_state.timer < 3.0
|
||||||
|
&& angle < 15.0
|
||||||
|
{
|
||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Ability(0)));
|
.push(ControlAction::basic_input(InputKind::Ability(0)));
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
} else if agent.action_timer < 6.0 && angle < 90.0 {
|
} else if agent.action_state.timer < 6.0 && angle < 90.0 {
|
||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Secondary));
|
.push(ControlAction::basic_input(InputKind::Secondary));
|
||||||
agent.action_timer += dt.0;
|
agent.action_state.timer += dt.0;
|
||||||
} else {
|
} else {
|
||||||
agent.action_timer = 0.0;
|
agent.action_state.timer = 0.0;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Tactic::Minotaur => {
|
||||||
|
const MINOTAUR_FRENZY_THRESHOLD: f32 = 0.5;
|
||||||
|
const MINOTAUR_ATTACK_RANGE: f32 = 5.0;
|
||||||
|
const MINOTAUR_CHARGE_DISTANCE: f32 = 15.0;
|
||||||
|
let minotaur_attack_distance =
|
||||||
|
self.body.map_or(0.0, |b| b.radius()) + MINOTAUR_ATTACK_RANGE;
|
||||||
|
let health_fraction = self.health.map_or(1.0, |h| h.fraction());
|
||||||
|
// Sets action float at start of combat
|
||||||
|
if agent.action_state.counter < MINOTAUR_FRENZY_THRESHOLD
|
||||||
|
&& health_fraction > MINOTAUR_FRENZY_THRESHOLD
|
||||||
|
{
|
||||||
|
agent.action_state.counter = MINOTAUR_FRENZY_THRESHOLD;
|
||||||
|
}
|
||||||
|
if health_fraction < agent.action_state.counter {
|
||||||
|
// Makes minotaur buff itself with frenzy
|
||||||
|
controller
|
||||||
|
.actions
|
||||||
|
.push(ControlAction::basic_input(InputKind::Ability(1)));
|
||||||
|
if matches!(self.char_state, CharacterState::SelfBuff(c) if matches!(c.stage_section, StageSection::Recover))
|
||||||
|
{
|
||||||
|
agent.action_state.counter = 0.0;
|
||||||
|
}
|
||||||
|
} else if matches!(self.char_state, CharacterState::DashMelee(c) if !matches!(c.stage_section, StageSection::Recover))
|
||||||
|
{
|
||||||
|
// If already charging, keep charging if not in recover
|
||||||
|
controller
|
||||||
|
.actions
|
||||||
|
.push(ControlAction::basic_input(InputKind::Ability(0)));
|
||||||
|
} else if matches!(self.char_state, CharacterState::ChargedMelee(c) if matches!(c.stage_section, StageSection::Charge) && c.timer < c.static_data.charge_duration)
|
||||||
|
{
|
||||||
|
// If already charging a melee attack, keep charging it if charging
|
||||||
|
controller
|
||||||
|
.actions
|
||||||
|
.push(ControlAction::basic_input(InputKind::Primary));
|
||||||
|
} else if dist_sqrd > MINOTAUR_CHARGE_DISTANCE.powi(2) {
|
||||||
|
// Charges at target if they are far enough away
|
||||||
|
if angle < 60.0 {
|
||||||
|
controller
|
||||||
|
.actions
|
||||||
|
.push(ControlAction::basic_input(InputKind::Ability(0)));
|
||||||
|
}
|
||||||
|
} else if dist_sqrd < minotaur_attack_distance.powi(2) {
|
||||||
|
if agent.action_state.condition && !self.char_state.is_attack() {
|
||||||
|
// Cripple target if not just used cripple
|
||||||
|
controller
|
||||||
|
.actions
|
||||||
|
.push(ControlAction::basic_input(InputKind::Secondary));
|
||||||
|
agent.action_state.condition = false;
|
||||||
|
} else if !self.char_state.is_attack() {
|
||||||
|
// Cleave target if not just used cleave
|
||||||
|
controller
|
||||||
|
.actions
|
||||||
|
.push(ControlAction::basic_input(InputKind::Primary));
|
||||||
|
agent.action_state.condition = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Make minotaur move towards target
|
||||||
|
if let Some((bearing, speed)) = agent.chaser.chase(
|
||||||
|
&*terrain,
|
||||||
|
self.pos.0,
|
||||||
|
self.vel.0,
|
||||||
|
tgt_pos.0,
|
||||||
|
TraversalConfig {
|
||||||
|
min_tgt_dist: 1.25,
|
||||||
|
..self.traversal_config
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
controller.inputs.move_dir =
|
||||||
|
bearing.xy().try_normalized().unwrap_or_else(Vec2::zero) * speed;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,8 @@ impl Animation for AlphaAnimation {
|
|||||||
let pullback = 1.0 - move3;
|
let pullback = 1.0 - move3;
|
||||||
let move1 = move1base * pullback;
|
let move1 = move1base * pullback;
|
||||||
let move2 = move2base * pullback;
|
let move2 = move2base * pullback;
|
||||||
|
next.second.position = Vec3::new(0.0, 0.0, 0.0);
|
||||||
|
next.second.orientation = Quaternion::rotation_x(0.0);
|
||||||
next.shoulder_l.position = Vec3::new(
|
next.shoulder_l.position = Vec3::new(
|
||||||
-s_a.shoulder.0,
|
-s_a.shoulder.0,
|
||||||
s_a.shoulder.1,
|
s_a.shoulder.1,
|
||||||
@ -79,7 +80,6 @@ impl Animation for AlphaAnimation {
|
|||||||
);
|
);
|
||||||
next.shoulder_r.orientation =
|
next.shoulder_r.orientation =
|
||||||
Quaternion::rotation_x(move1 * 0.8 + 0.6 * speednorm + (footrotl * -0.2) * speednorm);
|
Quaternion::rotation_x(move1 * 0.8 + 0.6 * speednorm + (footrotl * -0.2) * speednorm);
|
||||||
next.torso.orientation = Quaternion::rotation_z(0.0);
|
|
||||||
|
|
||||||
next.main.position = Vec3::new(0.0, 0.0, 0.0);
|
next.main.position = Vec3::new(0.0, 0.0, 0.0);
|
||||||
next.main.orientation = Quaternion::rotation_x(0.0);
|
next.main.orientation = Quaternion::rotation_x(0.0);
|
||||||
@ -231,6 +231,38 @@ impl Animation for AlphaAnimation {
|
|||||||
* Quaternion::rotation_z(move1 * -0.5 + move2 * 0.6);
|
* Quaternion::rotation_z(move1 * -0.5 + move2 * 0.6);
|
||||||
next.head.orientation = Quaternion::rotation_x(move1 * 0.3);
|
next.head.orientation = Quaternion::rotation_x(move1 * 0.3);
|
||||||
},
|
},
|
||||||
|
"Minotaur" => {
|
||||||
|
next.control_l.position = Vec3::new(0.0, 4.0, 5.0);
|
||||||
|
next.control_r.position = Vec3::new(0.0, 4.0, 5.0);
|
||||||
|
next.weapon_l.position = Vec3::new(
|
||||||
|
-12.0 + move1 * -9.0 + move2 * 16.0,
|
||||||
|
-6.0 + move2 * 8.0,
|
||||||
|
-18.0 + move1 * 8.0 + move2 * -4.0,
|
||||||
|
);
|
||||||
|
next.weapon_r.position = Vec3::new(
|
||||||
|
12.0 + move1 * 9.0 + move2 * -16.0,
|
||||||
|
-6.0 + move2 * 8.0,
|
||||||
|
-18.0 + move1 * 8.0 + move2 * -8.0,
|
||||||
|
);
|
||||||
|
|
||||||
|
next.weapon_l.orientation = Quaternion::rotation_x(-1.67)
|
||||||
|
* Quaternion::rotation_y(move1 * -0.3 + move2 * 1.0)
|
||||||
|
* Quaternion::rotation_z(move1 * 0.8 + move2 * -1.8);
|
||||||
|
next.weapon_r.orientation = Quaternion::rotation_x(-1.67)
|
||||||
|
* Quaternion::rotation_y(move1 * 0.3 + move2 * -0.6)
|
||||||
|
* Quaternion::rotation_z(move1 * -0.8 + move2 * 1.8);
|
||||||
|
|
||||||
|
next.control_l.orientation = Quaternion::rotation_x(1.57 + move2 * 1.0);
|
||||||
|
next.control_r.orientation = Quaternion::rotation_x(1.57 + move2 * 1.0);
|
||||||
|
|
||||||
|
next.shoulder_l.orientation = Quaternion::rotation_x(-0.3)
|
||||||
|
* Quaternion::rotation_y(move1 * 0.7 + move2 * -0.7);
|
||||||
|
|
||||||
|
next.shoulder_r.orientation = Quaternion::rotation_x(-0.3)
|
||||||
|
* Quaternion::rotation_y(move1 * -0.7 + move2 * 0.7);
|
||||||
|
next.head.orientation =
|
||||||
|
Quaternion::rotation_x(move1 * -0.6 + move2 * 0.4)
|
||||||
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
159
voxygen/anim/src/biped_large/chargemelee.rs
Normal file
159
voxygen/anim/src/biped_large/chargemelee.rs
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
use super::{
|
||||||
|
super::{vek::*, Animation},
|
||||||
|
BipedLargeSkeleton, SkeletonAttr,
|
||||||
|
};
|
||||||
|
use common::{
|
||||||
|
comp::item::tool::{AbilitySpec, ToolKind},
|
||||||
|
states::utils::StageSection,
|
||||||
|
};
|
||||||
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
|
pub struct ChargeMeleeAnimation;
|
||||||
|
|
||||||
|
impl Animation for ChargeMeleeAnimation {
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
type Dependency<'a> = (
|
||||||
|
(Option<ToolKind>, Option<&'a AbilitySpec>),
|
||||||
|
(Option<ToolKind>, Option<&'a AbilitySpec>),
|
||||||
|
Vec3<f32>,
|
||||||
|
f32,
|
||||||
|
Option<StageSection>,
|
||||||
|
f32,
|
||||||
|
);
|
||||||
|
type Skeleton = BipedLargeSkeleton;
|
||||||
|
|
||||||
|
#[cfg(feature = "use-dyn-lib")]
|
||||||
|
const UPDATE_FN: &'static [u8] = b"biped_large_chargemelee\0";
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "be-dyn-lib", export_name = "biped_large_chargemelee")]
|
||||||
|
#[allow(clippy::approx_constant)] // TODO: Pending review in #587
|
||||||
|
fn update_skeleton_inner<'a>(
|
||||||
|
skeleton: &Self::Skeleton,
|
||||||
|
(
|
||||||
|
(active_tool_kind, active_tool_spec),
|
||||||
|
_second_tool,
|
||||||
|
velocity,
|
||||||
|
_global_time,
|
||||||
|
stage_section,
|
||||||
|
acc_vel,
|
||||||
|
): Self::Dependency<'a>,
|
||||||
|
anim_time: f32,
|
||||||
|
rate: &mut f32,
|
||||||
|
s_a: &SkeletonAttr,
|
||||||
|
) -> Self::Skeleton {
|
||||||
|
*rate = 1.0;
|
||||||
|
let mut next = (*skeleton).clone();
|
||||||
|
let speed = Vec2::<f32>::from(velocity).magnitude();
|
||||||
|
|
||||||
|
let lab: f32 = 0.65 * s_a.tempo;
|
||||||
|
let speednorm = (speed / 12.0).powf(0.4);
|
||||||
|
let foothoril = (acc_vel * lab + PI * 1.45).sin() * speednorm;
|
||||||
|
let foothorir = (acc_vel * lab + PI * (0.45)).sin() * speednorm;
|
||||||
|
let footrotl = ((1.0 / (0.5 + (0.5) * ((acc_vel * lab + PI * 1.4).sin()).powi(2))).sqrt())
|
||||||
|
* ((acc_vel * lab + PI * 1.4).sin());
|
||||||
|
|
||||||
|
let footrotr = ((1.0 / (0.5 + (0.5) * ((acc_vel * lab + PI * 0.4).sin()).powi(2))).sqrt())
|
||||||
|
* ((acc_vel * lab + PI * 0.4).sin());
|
||||||
|
let (move1base, move2base, movement3, tension) = match stage_section {
|
||||||
|
Some(StageSection::Charge) => (
|
||||||
|
(anim_time.powf(0.25)).min(1.0),
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
(anim_time * 100.0).sin(),
|
||||||
|
),
|
||||||
|
Some(StageSection::Swing) => (1.0, anim_time.powf(0.25), 0.0, 0.0),
|
||||||
|
Some(StageSection::Recover) => (1.0, 1.0, anim_time.powi(4), 0.0),
|
||||||
|
_ => (0.0, 0.0, 0.0, 0.0),
|
||||||
|
};
|
||||||
|
|
||||||
|
let pullback = 1.0 - movement3;
|
||||||
|
let move1 = move1base * pullback;
|
||||||
|
let move2 = move2base * pullback;
|
||||||
|
next.second.position = Vec3::new(0.0, 0.0, 0.0);
|
||||||
|
next.second.orientation = Quaternion::rotation_x(0.0);
|
||||||
|
next.shoulder_l.position = Vec3::new(
|
||||||
|
-s_a.shoulder.0,
|
||||||
|
s_a.shoulder.1,
|
||||||
|
s_a.shoulder.2 - foothorir * 1.0,
|
||||||
|
);
|
||||||
|
next.shoulder_l.orientation =
|
||||||
|
Quaternion::rotation_x(move1 * 0.8 + 0.6 * speednorm + (footrotr * -0.2) * speednorm);
|
||||||
|
|
||||||
|
next.shoulder_r.position = Vec3::new(
|
||||||
|
s_a.shoulder.0,
|
||||||
|
s_a.shoulder.1,
|
||||||
|
s_a.shoulder.2 - foothoril * 1.0,
|
||||||
|
);
|
||||||
|
next.shoulder_r.orientation =
|
||||||
|
Quaternion::rotation_x(move1 * 0.8 + 0.6 * speednorm + (footrotl * -0.2) * speednorm);
|
||||||
|
next.torso.orientation = Quaternion::rotation_z(0.0);
|
||||||
|
|
||||||
|
next.main.position = Vec3::new(0.0, 0.0, 0.0);
|
||||||
|
next.main.orientation = Quaternion::rotation_x(0.0);
|
||||||
|
|
||||||
|
next.hand_l.position = Vec3::new(0.0, 0.0, s_a.grip.0);
|
||||||
|
next.hand_r.position = Vec3::new(0.0, 0.0, s_a.grip.0);
|
||||||
|
|
||||||
|
next.hand_l.orientation = Quaternion::rotation_x(0.0);
|
||||||
|
next.hand_r.orientation = Quaternion::rotation_x(0.0);
|
||||||
|
|
||||||
|
#[allow(clippy::single_match)]
|
||||||
|
match active_tool_kind {
|
||||||
|
Some(ToolKind::Natural) => {
|
||||||
|
if let Some(AbilitySpec::Custom(spec)) = active_tool_spec {
|
||||||
|
match spec.as_str() {
|
||||||
|
"Minotaur" => {
|
||||||
|
next.upper_torso.orientation =
|
||||||
|
Quaternion::rotation_x(move1 * 0.3 + move2 * -0.9);
|
||||||
|
next.lower_torso.orientation =
|
||||||
|
Quaternion::rotation_x(move1 * -0.3 + move2 * 0.9);
|
||||||
|
next.head.orientation =
|
||||||
|
Quaternion::rotation_x(move1 * -0.5 + move2 * 0.5);
|
||||||
|
|
||||||
|
next.control_l.position = Vec3::new(0.0, 4.0, 5.0);
|
||||||
|
next.control_r.position = Vec3::new(0.0, 4.0, 5.0);
|
||||||
|
next.weapon_l.position = Vec3::new(
|
||||||
|
-12.0 + move2 * 5.0,
|
||||||
|
-6.0 + move1 * 22.0 + move2 * 8.0,
|
||||||
|
-18.0 + move1 * 16.0 + move2 * -19.0,
|
||||||
|
);
|
||||||
|
next.weapon_r.position = Vec3::new(
|
||||||
|
12.0 + move2 * -5.0,
|
||||||
|
-6.0 + move1 * 22.0 + move2 * 8.0,
|
||||||
|
-18.0 + move1 * 14.0 + move2 * -19.0,
|
||||||
|
);
|
||||||
|
next.torso.position = Vec3::new(0.0, move2 * 1.5, 0.0);
|
||||||
|
|
||||||
|
next.weapon_l.orientation =
|
||||||
|
Quaternion::rotation_x(
|
||||||
|
-1.67 + move1 * 2.8 + tension * 0.03 + move2 * -2.3,
|
||||||
|
) * Quaternion::rotation_y(move1 * 0.3 + move2 * 0.5);
|
||||||
|
next.weapon_r.orientation = Quaternion::rotation_x(
|
||||||
|
-1.67 + move1 * 1.6 + tension * -0.03 + move2 * -0.7,
|
||||||
|
) * Quaternion::rotation_y(
|
||||||
|
move1 * -0.3 + move2 * -0.5,
|
||||||
|
) * Quaternion::rotation_z(0.0);
|
||||||
|
|
||||||
|
next.control_l.orientation =
|
||||||
|
Quaternion::rotation_x(1.57 + move1 * 0.2 + move2 * 0.1);
|
||||||
|
next.control_r.orientation =
|
||||||
|
Quaternion::rotation_x(1.57 + move1 * 0.4 + move2 * -0.4);
|
||||||
|
|
||||||
|
next.control.orientation =
|
||||||
|
Quaternion::rotation_x(0.0) * Quaternion::rotation_y(0.0);
|
||||||
|
next.shoulder_l.orientation =
|
||||||
|
Quaternion::rotation_x(-0.3 + move1 * 1.0);
|
||||||
|
|
||||||
|
next.shoulder_r.orientation =
|
||||||
|
Quaternion::rotation_x(-0.3 + move1 * 1.0);
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
next
|
||||||
|
}
|
||||||
|
}
|
@ -2,15 +2,19 @@ use super::{
|
|||||||
super::{vek::*, Animation},
|
super::{vek::*, Animation},
|
||||||
BipedLargeSkeleton, SkeletonAttr,
|
BipedLargeSkeleton, SkeletonAttr,
|
||||||
};
|
};
|
||||||
use common::{comp::item::ToolKind, states::utils::StageSection};
|
use common::{
|
||||||
|
comp::item::tool::{AbilitySpec, ToolKind},
|
||||||
|
states::utils::StageSection,
|
||||||
|
};
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
pub struct DashAnimation;
|
pub struct DashAnimation;
|
||||||
|
|
||||||
impl Animation for DashAnimation {
|
impl Animation for DashAnimation {
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
type Dependency<'a> = (
|
type Dependency<'a> = (
|
||||||
Option<ToolKind>,
|
(Option<ToolKind>, Option<&'a AbilitySpec>),
|
||||||
Option<ToolKind>,
|
(Option<ToolKind>, Option<&'a AbilitySpec>),
|
||||||
Vec3<f32>,
|
Vec3<f32>,
|
||||||
f32,
|
f32,
|
||||||
Option<StageSection>,
|
Option<StageSection>,
|
||||||
@ -25,7 +29,14 @@ impl Animation for DashAnimation {
|
|||||||
#[allow(clippy::single_match)] // TODO: Pending review in #587
|
#[allow(clippy::single_match)] // TODO: Pending review in #587
|
||||||
fn update_skeleton_inner<'a>(
|
fn update_skeleton_inner<'a>(
|
||||||
skeleton: &Self::Skeleton,
|
skeleton: &Self::Skeleton,
|
||||||
(active_tool_kind, _second_tool_kind, velocity, _global_time, stage_section, acc_vel): Self::Dependency<'a>,
|
(
|
||||||
|
(active_tool_kind, active_tool_spec),
|
||||||
|
_second_tool,
|
||||||
|
velocity,
|
||||||
|
_global_time,
|
||||||
|
stage_section,
|
||||||
|
acc_vel,
|
||||||
|
): Self::Dependency<'a>,
|
||||||
anim_time: f32,
|
anim_time: f32,
|
||||||
rate: &mut f32,
|
rate: &mut f32,
|
||||||
s_a: &SkeletonAttr,
|
s_a: &SkeletonAttr,
|
||||||
@ -49,7 +60,8 @@ impl Animation for DashAnimation {
|
|||||||
|
|
||||||
next.hand_l.position = Vec3::new(0.0, 0.0, s_a.grip.0);
|
next.hand_l.position = Vec3::new(0.0, 0.0, s_a.grip.0);
|
||||||
next.hand_r.position = Vec3::new(0.0, 0.0, s_a.grip.0);
|
next.hand_r.position = Vec3::new(0.0, 0.0, s_a.grip.0);
|
||||||
|
next.second.position = Vec3::new(0.0, 0.0, 0.0);
|
||||||
|
next.second.orientation = Quaternion::rotation_x(0.0);
|
||||||
next.hand_l.orientation = Quaternion::rotation_x(0.0);
|
next.hand_l.orientation = Quaternion::rotation_x(0.0);
|
||||||
next.hand_r.orientation = Quaternion::rotation_x(0.0);
|
next.hand_r.orientation = Quaternion::rotation_x(0.0);
|
||||||
let (move1base, move2base, move3base, move4) = match stage_section {
|
let (move1base, move2base, move3base, move4) = match stage_section {
|
||||||
@ -136,6 +148,51 @@ impl Animation for DashAnimation {
|
|||||||
* Quaternion::rotation_y(-1.8 + move1 * -0.2 + move3 * -0.2)
|
* Quaternion::rotation_y(-1.8 + move1 * -0.2 + move3 * -0.2)
|
||||||
* Quaternion::rotation_z(move1 * -0.8 + move3 * -0.1);
|
* Quaternion::rotation_z(move1 * -0.8 + move3 * -0.1);
|
||||||
},
|
},
|
||||||
|
Some(ToolKind::Natural) => {
|
||||||
|
if let Some(AbilitySpec::Custom(spec)) = active_tool_spec {
|
||||||
|
match spec.as_str() {
|
||||||
|
"Minotaur" => {
|
||||||
|
next.head.orientation =
|
||||||
|
Quaternion::rotation_x(move1 * 0.4 + move3 * 0.5)
|
||||||
|
* Quaternion::rotation_z(move1 * -0.3 + move3 * -0.3);
|
||||||
|
next.upper_torso.orientation =
|
||||||
|
Quaternion::rotation_x(move1 * -0.4 + move3 * 0.9)
|
||||||
|
* Quaternion::rotation_z(move1 * 0.6 + move3 * -1.5);
|
||||||
|
next.lower_torso.orientation =
|
||||||
|
Quaternion::rotation_y(move1 * -0.2 + move3 * -0.1)
|
||||||
|
* Quaternion::rotation_x(
|
||||||
|
move1 * 0.4 + move3 * -0.7 + footrotr * 0.1,
|
||||||
|
)
|
||||||
|
* Quaternion::rotation_z(move1 * -0.6 + move3 * 1.6);
|
||||||
|
next.control_l.position = Vec3::new(0.0, 4.0, 5.0);
|
||||||
|
next.control_r.position = Vec3::new(0.0, 4.0, 5.0);
|
||||||
|
next.weapon_l.position = Vec3::new(-12.0 + move1 * -3.0, -6.0, -18.0);
|
||||||
|
next.weapon_r.position = Vec3::new(
|
||||||
|
12.0 + move1 * -3.0,
|
||||||
|
-6.0 + move1 * 2.0,
|
||||||
|
-18.0 + move1 * 2.0,
|
||||||
|
);
|
||||||
|
|
||||||
|
next.weapon_l.orientation = Quaternion::rotation_x(-1.67 + move1 * 0.4)
|
||||||
|
* Quaternion::rotation_y(move1 * 0.4 + move2 * 0.2)
|
||||||
|
* Quaternion::rotation_z(move3 * -0.5);
|
||||||
|
next.weapon_r.orientation = Quaternion::rotation_x(-1.67 + move1 * 0.3)
|
||||||
|
* Quaternion::rotation_y(move1 * 0.6 + move2 * -0.6)
|
||||||
|
* Quaternion::rotation_z(move3 * -0.5);
|
||||||
|
|
||||||
|
next.control_l.orientation = Quaternion::rotation_x(1.57);
|
||||||
|
next.control_r.orientation = Quaternion::rotation_x(1.57);
|
||||||
|
|
||||||
|
next.control.orientation =
|
||||||
|
Quaternion::rotation_x(0.0) * Quaternion::rotation_y(0.0);
|
||||||
|
next.shoulder_l.orientation = Quaternion::rotation_x(-0.3);
|
||||||
|
|
||||||
|
next.shoulder_r.orientation = Quaternion::rotation_x(-0.3);
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,8 +101,11 @@ impl Animation for IdleAnimation {
|
|||||||
next.main.orientation = Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57);
|
next.main.orientation = Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57);
|
||||||
},
|
},
|
||||||
Some(ToolKind::Hammer) | Some(ToolKind::Axe) => {
|
Some(ToolKind::Hammer) | Some(ToolKind::Axe) => {
|
||||||
next.main.position = Vec3::new(-10.0, -8.0, 12.0);
|
next.main.position = Vec3::new(-6.0, -8.0, 8.0);
|
||||||
next.main.orientation = Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57);
|
next.main.orientation = Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57);
|
||||||
|
next.second.position = Vec3::new(6.0, -8.0, 8.0);
|
||||||
|
next.second.orientation =
|
||||||
|
Quaternion::rotation_y(-2.5) * Quaternion::rotation_z(1.57);
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
next.main.position = Vec3::new(-2.0, -5.0, -6.0);
|
next.main.position = Vec3::new(-2.0, -5.0, -6.0);
|
||||||
|
@ -28,6 +28,7 @@ impl Animation for JumpAnimation {
|
|||||||
let torso = (anim_time * lab + 1.5 * PI).sin();
|
let torso = (anim_time * lab + 1.5 * PI).sin();
|
||||||
|
|
||||||
let wave_slow = (anim_time * 0.8).sin();
|
let wave_slow = (anim_time * 0.8).sin();
|
||||||
|
next.hold.scale = Vec3::one() * 0.0;
|
||||||
|
|
||||||
next.head.scale = Vec3::one() * 1.02;
|
next.head.scale = Vec3::one() * 1.02;
|
||||||
|
|
||||||
@ -57,7 +58,7 @@ impl Animation for JumpAnimation {
|
|||||||
next.second.position = Vec3::new(0.0, 0.0, 0.0);
|
next.second.position = Vec3::new(0.0, 0.0, 0.0);
|
||||||
next.second.orientation =
|
next.second.orientation =
|
||||||
Quaternion::rotation_x(PI) * Quaternion::rotation_y(0.0) * Quaternion::rotation_z(0.0);
|
Quaternion::rotation_x(PI) * Quaternion::rotation_y(0.0) * Quaternion::rotation_z(0.0);
|
||||||
next.second.scale = Vec3::one() * 0.0;
|
next.second.scale = Vec3::one() * 1.0;
|
||||||
|
|
||||||
match active_tool_kind {
|
match active_tool_kind {
|
||||||
Some(ToolKind::Bow) => {
|
Some(ToolKind::Bow) => {
|
||||||
|
@ -3,12 +3,14 @@ pub mod beam;
|
|||||||
pub mod beta;
|
pub mod beta;
|
||||||
pub mod blink;
|
pub mod blink;
|
||||||
pub mod charge;
|
pub mod charge;
|
||||||
|
pub mod chargemelee;
|
||||||
pub mod dash;
|
pub mod dash;
|
||||||
pub mod equip;
|
pub mod equip;
|
||||||
pub mod idle;
|
pub mod idle;
|
||||||
pub mod jump;
|
pub mod jump;
|
||||||
pub mod leapmelee;
|
pub mod leapmelee;
|
||||||
pub mod run;
|
pub mod run;
|
||||||
|
pub mod selfbuff;
|
||||||
pub mod shockwave;
|
pub mod shockwave;
|
||||||
pub mod shoot;
|
pub mod shoot;
|
||||||
pub mod spin;
|
pub mod spin;
|
||||||
@ -20,11 +22,11 @@ pub mod wield;
|
|||||||
// Reexports
|
// Reexports
|
||||||
pub use self::{
|
pub use self::{
|
||||||
alpha::AlphaAnimation, beam::BeamAnimation, beta::BetaAnimation, blink::BlinkAnimation,
|
alpha::AlphaAnimation, beam::BeamAnimation, beta::BetaAnimation, blink::BlinkAnimation,
|
||||||
charge::ChargeAnimation, dash::DashAnimation, equip::EquipAnimation, idle::IdleAnimation,
|
charge::ChargeAnimation, chargemelee::ChargeMeleeAnimation, dash::DashAnimation,
|
||||||
jump::JumpAnimation, leapmelee::LeapAnimation, run::RunAnimation,
|
equip::EquipAnimation, idle::IdleAnimation, jump::JumpAnimation, leapmelee::LeapAnimation,
|
||||||
shockwave::ShockwaveAnimation, shoot::ShootAnimation, spin::SpinAnimation,
|
run::RunAnimation, selfbuff::SelfBuffAnimation, shockwave::ShockwaveAnimation,
|
||||||
spinmelee::SpinMeleeAnimation, stunned::StunnedAnimation, summon::SummonAnimation,
|
shoot::ShootAnimation, spin::SpinAnimation, spinmelee::SpinMeleeAnimation,
|
||||||
wield::WieldAnimation,
|
stunned::StunnedAnimation, summon::SummonAnimation, wield::WieldAnimation,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{make_bone, vek::*, FigureBoneData, Skeleton};
|
use super::{make_bone, vek::*, FigureBoneData, Skeleton};
|
||||||
@ -54,6 +56,8 @@ skeleton_impls!(struct BipedLargeSkeleton {
|
|||||||
control,
|
control,
|
||||||
control_l,
|
control_l,
|
||||||
control_r,
|
control_r,
|
||||||
|
weapon_l,
|
||||||
|
weapon_r,
|
||||||
leg_control_l,
|
leg_control_l,
|
||||||
leg_control_r,
|
leg_control_r,
|
||||||
arm_control_l,
|
arm_control_l,
|
||||||
@ -78,8 +82,11 @@ impl Skeleton for BipedLargeSkeleton {
|
|||||||
|
|
||||||
let torso_mat = base_mat * Mat4::<f32>::from(self.torso);
|
let torso_mat = base_mat * Mat4::<f32>::from(self.torso);
|
||||||
let upper_torso_mat = torso_mat * upper_torso;
|
let upper_torso_mat = torso_mat * upper_torso;
|
||||||
|
let control_mat = Mat4::<f32>::from(self.control);
|
||||||
let control_l_mat = Mat4::<f32>::from(self.control_l);
|
let control_l_mat = Mat4::<f32>::from(self.control_l);
|
||||||
let control_r_mat = Mat4::<f32>::from(self.control_r);
|
let control_r_mat = Mat4::<f32>::from(self.control_r);
|
||||||
|
let weapon_l_mat = control_mat * Mat4::<f32>::from(self.weapon_l);
|
||||||
|
let weapon_r_mat = control_mat * Mat4::<f32>::from(self.weapon_r);
|
||||||
let lower_torso_mat = upper_torso_mat * Mat4::<f32>::from(self.lower_torso);
|
let lower_torso_mat = upper_torso_mat * Mat4::<f32>::from(self.lower_torso);
|
||||||
|
|
||||||
let leg_l = Mat4::<f32>::from(self.leg_l);
|
let leg_l = Mat4::<f32>::from(self.leg_l);
|
||||||
@ -92,8 +99,6 @@ impl Skeleton for BipedLargeSkeleton {
|
|||||||
let arm_control_r = upper_torso_mat * Mat4::<f32>::from(self.arm_control_r);
|
let arm_control_r = upper_torso_mat * Mat4::<f32>::from(self.arm_control_r);
|
||||||
|
|
||||||
let head_mat = upper_torso_mat * Mat4::<f32>::from(self.head);
|
let head_mat = upper_torso_mat * Mat4::<f32>::from(self.head);
|
||||||
let control_mat = Mat4::<f32>::from(self.control);
|
|
||||||
|
|
||||||
let hand_l_mat = Mat4::<f32>::from(self.hand_l);
|
let hand_l_mat = Mat4::<f32>::from(self.hand_l);
|
||||||
|
|
||||||
*(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [
|
*(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [
|
||||||
@ -102,12 +107,16 @@ impl Skeleton for BipedLargeSkeleton {
|
|||||||
make_bone(upper_torso_mat),
|
make_bone(upper_torso_mat),
|
||||||
make_bone(lower_torso_mat),
|
make_bone(lower_torso_mat),
|
||||||
make_bone(lower_torso_mat * Mat4::<f32>::from(self.tail)),
|
make_bone(lower_torso_mat * Mat4::<f32>::from(self.tail)),
|
||||||
make_bone(upper_torso_mat * control_mat * Mat4::<f32>::from(self.main)),
|
make_bone(upper_torso_mat * weapon_l_mat * Mat4::<f32>::from(self.main)),
|
||||||
make_bone(upper_torso_mat * control_mat * Mat4::<f32>::from(self.second)),
|
make_bone(upper_torso_mat * weapon_r_mat * Mat4::<f32>::from(self.second)),
|
||||||
make_bone(arm_control_l * Mat4::<f32>::from(self.shoulder_l)),
|
make_bone(arm_control_l * Mat4::<f32>::from(self.shoulder_l)),
|
||||||
make_bone(arm_control_r * Mat4::<f32>::from(self.shoulder_r)),
|
make_bone(arm_control_r * Mat4::<f32>::from(self.shoulder_r)),
|
||||||
make_bone(arm_control_l * control_mat * control_l_mat * Mat4::<f32>::from(self.hand_l)),
|
make_bone(
|
||||||
make_bone(arm_control_r * control_mat * control_r_mat * Mat4::<f32>::from(self.hand_r)),
|
arm_control_l * weapon_l_mat * control_l_mat * Mat4::<f32>::from(self.hand_l),
|
||||||
|
),
|
||||||
|
make_bone(
|
||||||
|
arm_control_r * weapon_r_mat * control_r_mat * Mat4::<f32>::from(self.hand_r),
|
||||||
|
),
|
||||||
make_bone(leg_control_l * leg_l),
|
make_bone(leg_control_l * leg_l),
|
||||||
make_bone(leg_control_r * leg_r),
|
make_bone(leg_control_r * leg_r),
|
||||||
make_bone(leg_control_l * Mat4::<f32>::from(self.foot_l)),
|
make_bone(leg_control_l * Mat4::<f32>::from(self.foot_l)),
|
||||||
|
@ -271,12 +271,12 @@ impl Animation for RunAnimation {
|
|||||||
s_a.upper_torso.1 + shortalt * -1.5 * speednorm,
|
s_a.upper_torso.1 + shortalt * -1.5 * speednorm,
|
||||||
);
|
);
|
||||||
next.upper_torso.orientation =
|
next.upper_torso.orientation =
|
||||||
Quaternion::rotation_z(short * 0.18 * speednorm + tilt * -1.0)
|
Quaternion::rotation_z(short * 0.07 * speednorm + tilt * -1.0)
|
||||||
* Quaternion::rotation_y(tilt);
|
* Quaternion::rotation_y(tilt);
|
||||||
|
|
||||||
next.lower_torso.position = Vec3::new(0.0, s_a.lower_torso.0, s_a.lower_torso.1);
|
next.lower_torso.position = Vec3::new(0.0, s_a.lower_torso.0, s_a.lower_torso.1);
|
||||||
next.lower_torso.orientation =
|
next.lower_torso.orientation =
|
||||||
Quaternion::rotation_z(short * 0.15 * speednorm + tilt * 0.5)
|
Quaternion::rotation_z(short * 0.05 * speednorm + tilt * 0.5)
|
||||||
* Quaternion::rotation_y(tilt * -0.5)
|
* Quaternion::rotation_y(tilt * -0.5)
|
||||||
* Quaternion::rotation_x(0.14 * speednorm);
|
* Quaternion::rotation_x(0.14 * speednorm);
|
||||||
|
|
||||||
@ -287,7 +287,7 @@ impl Animation for RunAnimation {
|
|||||||
next.tail.orientation = Quaternion::rotation_x(shortalt * 0.3 * speednorm);
|
next.tail.orientation = Quaternion::rotation_x(shortalt * 0.3 * speednorm);
|
||||||
|
|
||||||
next.second.position = Vec3::new(0.0, 0.0, 0.0);
|
next.second.position = Vec3::new(0.0, 0.0, 0.0);
|
||||||
next.second.orientation = Quaternion::rotation_x(PI)
|
next.second.orientation = Quaternion::rotation_x(0.0)
|
||||||
* Quaternion::rotation_y(0.0)
|
* Quaternion::rotation_y(0.0)
|
||||||
* Quaternion::rotation_z(0.0);
|
* Quaternion::rotation_z(0.0);
|
||||||
|
|
||||||
@ -308,9 +308,12 @@ impl Animation for RunAnimation {
|
|||||||
Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57);
|
Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57);
|
||||||
},
|
},
|
||||||
Some(ToolKind::Hammer) | Some(ToolKind::Axe) => {
|
Some(ToolKind::Hammer) | Some(ToolKind::Axe) => {
|
||||||
next.main.position = Vec3::new(-10.0, -8.0, 12.0);
|
next.main.position = Vec3::new(-6.0, -8.0, 8.0);
|
||||||
next.main.orientation =
|
next.main.orientation =
|
||||||
Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57);
|
Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57);
|
||||||
|
next.second.position = Vec3::new(6.0, -8.0, 8.0);
|
||||||
|
next.second.orientation =
|
||||||
|
Quaternion::rotation_y(-2.5) * Quaternion::rotation_z(1.57);
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
next.main.position = Vec3::new(-2.0, -5.0, -6.0);
|
next.main.position = Vec3::new(-2.0, -5.0, -6.0);
|
||||||
|
163
voxygen/anim/src/biped_large/selfbuff.rs
Normal file
163
voxygen/anim/src/biped_large/selfbuff.rs
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
use super::{
|
||||||
|
super::{vek::*, Animation},
|
||||||
|
BipedLargeSkeleton, SkeletonAttr,
|
||||||
|
};
|
||||||
|
use common::{
|
||||||
|
comp::item::tool::{AbilitySpec, ToolKind},
|
||||||
|
states::utils::StageSection,
|
||||||
|
};
|
||||||
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
|
pub struct SelfBuffAnimation;
|
||||||
|
|
||||||
|
impl Animation for SelfBuffAnimation {
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
type Dependency<'a> = (
|
||||||
|
(Option<ToolKind>, Option<&'a AbilitySpec>),
|
||||||
|
(Option<ToolKind>, Option<&'a AbilitySpec>),
|
||||||
|
Vec3<f32>,
|
||||||
|
f32,
|
||||||
|
Option<StageSection>,
|
||||||
|
f32,
|
||||||
|
);
|
||||||
|
type Skeleton = BipedLargeSkeleton;
|
||||||
|
|
||||||
|
#[cfg(feature = "use-dyn-lib")]
|
||||||
|
const UPDATE_FN: &'static [u8] = b"biped_large_selfbuff\0";
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "be-dyn-lib", export_name = "biped_large_selfbuff")]
|
||||||
|
fn update_skeleton_inner<'a>(
|
||||||
|
skeleton: &Self::Skeleton,
|
||||||
|
(
|
||||||
|
(active_tool_kind, active_tool_spec),
|
||||||
|
_second_tool,
|
||||||
|
velocity,
|
||||||
|
_global_time,
|
||||||
|
stage_section,
|
||||||
|
acc_vel,
|
||||||
|
): Self::Dependency<'a>,
|
||||||
|
anim_time: f32,
|
||||||
|
rate: &mut f32,
|
||||||
|
s_a: &SkeletonAttr,
|
||||||
|
) -> Self::Skeleton {
|
||||||
|
*rate = 1.0;
|
||||||
|
let mut next = (*skeleton).clone();
|
||||||
|
let speed = Vec2::<f32>::from(velocity).magnitude();
|
||||||
|
|
||||||
|
let lab: f32 = 0.65 * s_a.tempo;
|
||||||
|
let speednorm = (speed / 12.0).powf(0.4);
|
||||||
|
let foothoril = (acc_vel * lab + PI * 1.45).sin() * speednorm;
|
||||||
|
let foothorir = (acc_vel * lab + PI * (0.45)).sin() * speednorm;
|
||||||
|
let footrotl = ((1.0 / (0.5 + (0.5) * ((acc_vel * lab + PI * 1.4).sin()).powi(2))).sqrt())
|
||||||
|
* ((acc_vel * lab + PI * 1.4).sin());
|
||||||
|
|
||||||
|
let footrotr = ((1.0 / (0.5 + (0.5) * ((acc_vel * lab + PI * 0.4).sin()).powi(2))).sqrt())
|
||||||
|
* ((acc_vel * lab + PI * 0.4).sin());
|
||||||
|
let (move1base, movement3, tensionbase, tension2base) = match stage_section {
|
||||||
|
Some(StageSection::Buildup) => (
|
||||||
|
(anim_time.powf(0.25)).min(1.0),
|
||||||
|
0.0,
|
||||||
|
(anim_time * 10.0).sin(),
|
||||||
|
0.0,
|
||||||
|
),
|
||||||
|
Some(StageSection::Cast) => {
|
||||||
|
(1.0, 0.0, (anim_time * 30.0).sin(), (anim_time * 12.0).sin())
|
||||||
|
},
|
||||||
|
Some(StageSection::Recover) => (1.0, anim_time.powi(4), 1.0, 1.0),
|
||||||
|
_ => (0.0, 0.0, 0.0, 0.0),
|
||||||
|
};
|
||||||
|
|
||||||
|
let pullback = 1.0 - movement3;
|
||||||
|
let move1 = move1base * pullback;
|
||||||
|
let tension = tensionbase * pullback;
|
||||||
|
let tension2 = tension2base * pullback;
|
||||||
|
|
||||||
|
next.second.position = Vec3::new(0.0, 0.0, 0.0);
|
||||||
|
next.second.orientation = Quaternion::rotation_x(0.0);
|
||||||
|
next.shoulder_l.position = Vec3::new(
|
||||||
|
-s_a.shoulder.0,
|
||||||
|
s_a.shoulder.1,
|
||||||
|
s_a.shoulder.2 - foothorir * 1.0,
|
||||||
|
);
|
||||||
|
next.shoulder_l.orientation =
|
||||||
|
Quaternion::rotation_x(move1 * 0.8 + 0.6 * speednorm + (footrotr * -0.2) * speednorm);
|
||||||
|
|
||||||
|
next.shoulder_r.position = Vec3::new(
|
||||||
|
s_a.shoulder.0,
|
||||||
|
s_a.shoulder.1,
|
||||||
|
s_a.shoulder.2 - foothoril * 1.0,
|
||||||
|
);
|
||||||
|
next.shoulder_r.orientation =
|
||||||
|
Quaternion::rotation_x(move1 * 0.8 + 0.6 * speednorm + (footrotl * -0.2) * speednorm);
|
||||||
|
next.torso.orientation = Quaternion::rotation_z(0.0);
|
||||||
|
|
||||||
|
next.main.position = Vec3::new(0.0, 0.0, 0.0);
|
||||||
|
next.main.orientation = Quaternion::rotation_x(0.0);
|
||||||
|
|
||||||
|
next.hand_l.position = Vec3::new(0.0, 0.0, s_a.grip.0);
|
||||||
|
next.hand_r.position = Vec3::new(0.0, 0.0, s_a.grip.0);
|
||||||
|
|
||||||
|
next.hand_l.orientation = Quaternion::rotation_x(0.0);
|
||||||
|
next.hand_r.orientation = Quaternion::rotation_x(0.0);
|
||||||
|
|
||||||
|
// TODO: Remove clippy allow when second species is added
|
||||||
|
#[allow(clippy::single_match)]
|
||||||
|
match active_tool_kind {
|
||||||
|
Some(ToolKind::Natural) => {
|
||||||
|
if let Some(AbilitySpec::Custom(spec)) = active_tool_spec {
|
||||||
|
match spec.as_str() {
|
||||||
|
"Minotaur" => {
|
||||||
|
next.upper_torso.orientation =
|
||||||
|
Quaternion::rotation_x(move1 * -0.1 + tension2 * 0.05);
|
||||||
|
next.lower_torso.orientation =
|
||||||
|
Quaternion::rotation_x(move1 * 0.1 + tension2 * -0.05);
|
||||||
|
|
||||||
|
next.head.orientation =
|
||||||
|
Quaternion::rotation_x(move1 * 0.8 + tension2 * -0.1)
|
||||||
|
* Quaternion::rotation_y(tension2 * -0.1);
|
||||||
|
|
||||||
|
next.control_l.position = Vec3::new(0.0, 4.0, 5.0);
|
||||||
|
next.control_r.position = Vec3::new(0.0, 4.0, 5.0);
|
||||||
|
next.weapon_l.position = Vec3::new(
|
||||||
|
-12.0 + move1 * -15.0,
|
||||||
|
-6.0 + move1 * 13.0,
|
||||||
|
-18.0 + move1 * 16.0 + tension2 * 3.0,
|
||||||
|
);
|
||||||
|
next.weapon_r.position = Vec3::new(
|
||||||
|
12.0 + move1 * 1.0,
|
||||||
|
-6.0 + move1 * 7.0 + tension * 0.3,
|
||||||
|
-18.0 + move1 * -2.0,
|
||||||
|
);
|
||||||
|
|
||||||
|
next.weapon_l.orientation = Quaternion::rotation_x(-1.67 + move1 * 1.9)
|
||||||
|
* Quaternion::rotation_y(move1 * 0.25 + tension2 * 0.06)
|
||||||
|
* Quaternion::rotation_z(move1 * 1.3);
|
||||||
|
next.weapon_r.orientation = Quaternion::rotation_x(-1.67 + move1 * 0.8)
|
||||||
|
* Quaternion::rotation_y(move1 * -0.85 + tension * 0.12)
|
||||||
|
* Quaternion::rotation_z(move1 * 0.7);
|
||||||
|
|
||||||
|
next.control_l.orientation = Quaternion::rotation_x(1.57 + move1 * 0.1)
|
||||||
|
* Quaternion::rotation_y(0.0);
|
||||||
|
next.control_r.orientation = Quaternion::rotation_x(1.57 + move1 * 0.1)
|
||||||
|
* Quaternion::rotation_y(0.0);
|
||||||
|
|
||||||
|
next.control.orientation =
|
||||||
|
Quaternion::rotation_x(0.0) * Quaternion::rotation_y(0.0);
|
||||||
|
next.shoulder_l.orientation =
|
||||||
|
Quaternion::rotation_x(-0.3 + move1 * 2.2 + tension2 * 0.17)
|
||||||
|
* Quaternion::rotation_y(move1 * 0.95);
|
||||||
|
|
||||||
|
next.shoulder_r.orientation =
|
||||||
|
Quaternion::rotation_x(-0.3 + move1 * 0.1)
|
||||||
|
* Quaternion::rotation_y(move1 * -0.35);
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
next
|
||||||
|
}
|
||||||
|
}
|
@ -65,7 +65,8 @@ impl Animation for StunnedAnimation {
|
|||||||
let short = (acc_vel * lab).sin() * speednorm;
|
let short = (acc_vel * lab).sin() * speednorm;
|
||||||
|
|
||||||
let shortalt = (anim_time * lab * 16.0 + PI / 2.0).sin();
|
let shortalt = (anim_time * lab * 16.0 + PI / 2.0).sin();
|
||||||
|
next.second.position = Vec3::new(0.0, 0.0, 0.0);
|
||||||
|
next.second.orientation = Quaternion::rotation_x(0.0);
|
||||||
if s_a.beast {
|
if s_a.beast {
|
||||||
next.jaw.position = Vec3::new(0.0, s_a.jaw.0, s_a.jaw.1);
|
next.jaw.position = Vec3::new(0.0, s_a.jaw.0, s_a.jaw.1);
|
||||||
} else {
|
} else {
|
||||||
@ -391,6 +392,24 @@ impl Animation for StunnedAnimation {
|
|||||||
next.torso.orientation = Quaternion::rotation_x(-0.25);
|
next.torso.orientation = Quaternion::rotation_x(-0.25);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Minotaur" => {
|
||||||
|
next.control_l.position = Vec3::new(0.0, 4.0, 5.0);
|
||||||
|
next.control_r.position = Vec3::new(0.0, 4.0, 5.0);
|
||||||
|
next.weapon_l.position = Vec3::new(-12.0, -6.0, -18.0);
|
||||||
|
next.weapon_r.position = Vec3::new(12.0, -6.0, -18.0);
|
||||||
|
|
||||||
|
next.weapon_l.orientation = Quaternion::rotation_x(-1.57 - 0.1);
|
||||||
|
next.weapon_r.orientation = Quaternion::rotation_x(-1.57 - 0.1);
|
||||||
|
|
||||||
|
next.control_l.orientation = Quaternion::rotation_x(1.57);
|
||||||
|
next.control_r.orientation = Quaternion::rotation_x(1.57);
|
||||||
|
|
||||||
|
next.control.orientation =
|
||||||
|
Quaternion::rotation_x(0.0) * Quaternion::rotation_y(0.0);
|
||||||
|
next.shoulder_l.orientation = Quaternion::rotation_x(-0.3);
|
||||||
|
|
||||||
|
next.shoulder_r.orientation = Quaternion::rotation_x(-0.3);
|
||||||
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,6 +91,8 @@ impl Animation for WieldAnimation {
|
|||||||
let short = (acc_vel * lab).sin() * speednorm;
|
let short = (acc_vel * lab).sin() * speednorm;
|
||||||
|
|
||||||
let shortalt = (anim_time * lab * 16.0 + PI / 2.0).sin();
|
let shortalt = (anim_time * lab * 16.0 + PI / 2.0).sin();
|
||||||
|
next.second.position = Vec3::new(0.0, 0.0, 0.0);
|
||||||
|
next.second.orientation = Quaternion::rotation_x(0.0);
|
||||||
|
|
||||||
if s_a.beast {
|
if s_a.beast {
|
||||||
next.jaw.position = Vec3::new(0.0, s_a.jaw.0, s_a.jaw.1);
|
next.jaw.position = Vec3::new(0.0, s_a.jaw.0, s_a.jaw.1);
|
||||||
@ -169,12 +171,12 @@ impl Animation for WieldAnimation {
|
|||||||
5.0 + s_a.grip.0 / 1.2,
|
5.0 + s_a.grip.0 / 1.2,
|
||||||
-4.0 + -s_a.grip.0 / 2.0 + short * -1.5,
|
-4.0 + -s_a.grip.0 / 2.0 + short * -1.5,
|
||||||
);
|
);
|
||||||
|
next.second.scale = Vec3::one() * 0.0;
|
||||||
|
|
||||||
next.control_l.orientation =
|
next.control_l.orientation =
|
||||||
Quaternion::rotation_x(PI / 2.0) * Quaternion::rotation_y(-0.2);
|
Quaternion::rotation_x(PI / 2.0) * Quaternion::rotation_y(-0.2);
|
||||||
next.control_r.orientation = Quaternion::rotation_x(PI / 2.2)
|
next.control_r.orientation =
|
||||||
* Quaternion::rotation_y(0.2)
|
Quaternion::rotation_x(PI / 2.2) * Quaternion::rotation_y(0.2);
|
||||||
* Quaternion::rotation_z(0.0);
|
|
||||||
|
|
||||||
next.control.orientation =
|
next.control.orientation =
|
||||||
Quaternion::rotation_x(-0.2 + short * 0.2) * Quaternion::rotation_y(-0.1);
|
Quaternion::rotation_x(-0.2 + short * 0.2) * Quaternion::rotation_y(-0.1);
|
||||||
@ -430,6 +432,24 @@ impl Animation for WieldAnimation {
|
|||||||
next.torso.orientation = Quaternion::rotation_x(-0.25);
|
next.torso.orientation = Quaternion::rotation_x(-0.25);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Minotaur" => {
|
||||||
|
next.control_l.position = Vec3::new(0.0, 4.0, 5.0);
|
||||||
|
next.control_r.position = Vec3::new(0.0, 4.0, 5.0);
|
||||||
|
next.weapon_l.position = Vec3::new(-12.0, -6.0, -18.0);
|
||||||
|
next.weapon_r.position = Vec3::new(12.0, -6.0, -18.0);
|
||||||
|
|
||||||
|
next.weapon_l.orientation = Quaternion::rotation_x(-1.57 - 0.1);
|
||||||
|
next.weapon_r.orientation = Quaternion::rotation_x(-1.57 - 0.1);
|
||||||
|
|
||||||
|
next.control_l.orientation = Quaternion::rotation_x(1.57);
|
||||||
|
next.control_r.orientation = Quaternion::rotation_x(1.57);
|
||||||
|
|
||||||
|
next.control.orientation =
|
||||||
|
Quaternion::rotation_x(0.0) * Quaternion::rotation_y(0.0);
|
||||||
|
next.shoulder_l.orientation = Quaternion::rotation_x(-0.3);
|
||||||
|
|
||||||
|
next.shoulder_r.orientation = Quaternion::rotation_x(-0.3);
|
||||||
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,6 +79,7 @@ fn maps_basic_melee() {
|
|||||||
range: 1.0,
|
range: 1.0,
|
||||||
max_angle: 1.0,
|
max_angle: 1.0,
|
||||||
ability_info: empty_ability_info(),
|
ability_info: empty_ability_info(),
|
||||||
|
damage_effect: None,
|
||||||
},
|
},
|
||||||
timer: Duration::default(),
|
timer: Duration::default(),
|
||||||
stage_section: states::utils::StageSection::Buildup,
|
stage_section: states::utils::StageSection::Buildup,
|
||||||
|
@ -181,6 +181,7 @@ pub enum SfxEvent {
|
|||||||
FireShot,
|
FireShot,
|
||||||
FlameThrower,
|
FlameThrower,
|
||||||
PoiseChange(PoiseState),
|
PoiseChange(PoiseState),
|
||||||
|
GroundSlam,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Deserialize, Hash, Eq)]
|
#[derive(Clone, Debug, PartialEq, Deserialize, Hash, Eq)]
|
||||||
@ -325,6 +326,10 @@ impl SfxMgr {
|
|||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
Outcome::GroundSlam { pos, .. } => {
|
||||||
|
let sfx_trigger_item = triggers.get_key_value(&SfxEvent::GroundSlam);
|
||||||
|
audio.emit_sfx(sfx_trigger_item, *pos, Some(1.0), false);
|
||||||
|
},
|
||||||
Outcome::ProjectileShot { pos, body, .. } => {
|
Outcome::ProjectileShot { pos, body, .. } => {
|
||||||
match body {
|
match body {
|
||||||
Body::Object(
|
Body::Object(
|
||||||
|
@ -628,6 +628,7 @@ fn insert_killing_buff(buff: BuffKind, localized_strings: &Localization, templat
|
|||||||
BuffKind::Burning => localized_strings.get("hud.outcome.burning"),
|
BuffKind::Burning => localized_strings.get("hud.outcome.burning"),
|
||||||
BuffKind::Bleeding => localized_strings.get("hud.outcome.bleeding"),
|
BuffKind::Bleeding => localized_strings.get("hud.outcome.bleeding"),
|
||||||
BuffKind::Cursed => localized_strings.get("hud.outcome.curse"),
|
BuffKind::Cursed => localized_strings.get("hud.outcome.curse"),
|
||||||
|
BuffKind::Crippled => localized_strings.get("hud.outcome.crippled"),
|
||||||
BuffKind::Regeneration
|
BuffKind::Regeneration
|
||||||
| BuffKind::Saturation
|
| BuffKind::Saturation
|
||||||
| BuffKind::Potion
|
| BuffKind::Potion
|
||||||
@ -635,7 +636,8 @@ fn insert_killing_buff(buff: BuffKind, localized_strings: &Localization, templat
|
|||||||
| BuffKind::IncreaseMaxEnergy
|
| BuffKind::IncreaseMaxEnergy
|
||||||
| BuffKind::IncreaseMaxHealth
|
| BuffKind::IncreaseMaxHealth
|
||||||
| BuffKind::Invulnerability
|
| BuffKind::Invulnerability
|
||||||
| BuffKind::ProtectingWard => {
|
| BuffKind::ProtectingWard
|
||||||
|
| BuffKind::Frenzied => {
|
||||||
tracing::error!("Player was killed by a positive buff!");
|
tracing::error!("Player was killed by a positive buff!");
|
||||||
localized_strings.get("hud.outcome.mysterious")
|
localized_strings.get("hud.outcome.mysterious")
|
||||||
},
|
},
|
||||||
|
@ -569,11 +569,13 @@ image_ids! {
|
|||||||
buff_healthplus_0: "voxygen.element.de_buffs.buff_healthplus_0",
|
buff_healthplus_0: "voxygen.element.de_buffs.buff_healthplus_0",
|
||||||
buff_invincibility_0: "voxygen.element.de_buffs.buff_invincibility_0",
|
buff_invincibility_0: "voxygen.element.de_buffs.buff_invincibility_0",
|
||||||
buff_dmg_red_0: "voxygen.element.de_buffs.buff_damage_reduce_0",
|
buff_dmg_red_0: "voxygen.element.de_buffs.buff_damage_reduce_0",
|
||||||
|
buff_frenzy_0: "voxygen.element.de_buffs.buff_frenzy_0",
|
||||||
|
|
||||||
// Debuffs
|
// Debuffs
|
||||||
debuff_skull_0: "voxygen.element.de_buffs.debuff_skull_0",
|
debuff_skull_0: "voxygen.element.de_buffs.debuff_skull_0",
|
||||||
debuff_bleed_0: "voxygen.element.de_buffs.debuff_bleed_0",
|
debuff_bleed_0: "voxygen.element.de_buffs.debuff_bleed_0",
|
||||||
debuff_burning_0: "voxygen.element.de_buffs.debuff_burning_0",
|
debuff_burning_0: "voxygen.element.de_buffs.debuff_burning_0",
|
||||||
|
debuff_crippled_0: "voxygen.element.de_buffs.debuff_cripple_0",
|
||||||
|
|
||||||
// Animation Frames
|
// Animation Frames
|
||||||
// Buff Frame
|
// Buff Frame
|
||||||
|
@ -3622,10 +3622,12 @@ pub fn get_buff_image(buff: BuffKind, imgs: &Imgs) -> conrod_core::image::Id {
|
|||||||
BuffKind::IncreaseMaxHealth { .. } => imgs.buff_healthplus_0,
|
BuffKind::IncreaseMaxHealth { .. } => imgs.buff_healthplus_0,
|
||||||
BuffKind::Invulnerability => imgs.buff_invincibility_0,
|
BuffKind::Invulnerability => imgs.buff_invincibility_0,
|
||||||
BuffKind::ProtectingWard => imgs.buff_dmg_red_0,
|
BuffKind::ProtectingWard => imgs.buff_dmg_red_0,
|
||||||
|
BuffKind::Frenzied { .. } => imgs.buff_frenzy_0,
|
||||||
// Debuffs
|
// Debuffs
|
||||||
BuffKind::Bleeding { .. } => imgs.debuff_bleed_0,
|
BuffKind::Bleeding { .. } => imgs.debuff_bleed_0,
|
||||||
BuffKind::Cursed { .. } => imgs.debuff_skull_0,
|
BuffKind::Cursed { .. } => imgs.debuff_skull_0,
|
||||||
BuffKind::Burning { .. } => imgs.debuff_burning_0,
|
BuffKind::Burning { .. } => imgs.debuff_burning_0,
|
||||||
|
BuffKind::Crippled { .. } => imgs.debuff_crippled_0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3640,10 +3642,12 @@ pub fn get_buff_title(buff: BuffKind, localized_strings: &Localization) -> &str
|
|||||||
BuffKind::IncreaseMaxEnergy { .. } => localized_strings.get("buff.title.staminaup"),
|
BuffKind::IncreaseMaxEnergy { .. } => localized_strings.get("buff.title.staminaup"),
|
||||||
BuffKind::Invulnerability => localized_strings.get("buff.title.invulnerability"),
|
BuffKind::Invulnerability => localized_strings.get("buff.title.invulnerability"),
|
||||||
BuffKind::ProtectingWard => localized_strings.get("buff.title.protectingward"),
|
BuffKind::ProtectingWard => localized_strings.get("buff.title.protectingward"),
|
||||||
|
BuffKind::Frenzied => localized_strings.get("buff.title.frenzied"),
|
||||||
// Debuffs
|
// Debuffs
|
||||||
BuffKind::Bleeding { .. } => localized_strings.get("buff.title.bleed"),
|
BuffKind::Bleeding { .. } => localized_strings.get("buff.title.bleed"),
|
||||||
BuffKind::Cursed { .. } => localized_strings.get("buff.title.cursed"),
|
BuffKind::Cursed { .. } => localized_strings.get("buff.title.cursed"),
|
||||||
BuffKind::Burning { .. } => localized_strings.get("buff.title.burn"),
|
BuffKind::Burning { .. } => localized_strings.get("buff.title.burn"),
|
||||||
|
BuffKind::Crippled { .. } => localized_strings.get("buff.title.crippled"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3670,10 +3674,12 @@ pub fn get_buff_desc(buff: BuffKind, data: BuffData, localized_strings: &Localiz
|
|||||||
BuffKind::ProtectingWard => {
|
BuffKind::ProtectingWard => {
|
||||||
Cow::Borrowed(localized_strings.get("buff.desc.protectingward"))
|
Cow::Borrowed(localized_strings.get("buff.desc.protectingward"))
|
||||||
},
|
},
|
||||||
|
BuffKind::Frenzied => Cow::Borrowed(localized_strings.get("buff.desc.frenzied")),
|
||||||
// Debuffs
|
// Debuffs
|
||||||
BuffKind::Bleeding { .. } => Cow::Borrowed(localized_strings.get("buff.desc.bleed")),
|
BuffKind::Bleeding { .. } => Cow::Borrowed(localized_strings.get("buff.desc.bleed")),
|
||||||
BuffKind::Cursed { .. } => Cow::Borrowed(localized_strings.get("buff.desc.cursed")),
|
BuffKind::Cursed { .. } => Cow::Borrowed(localized_strings.get("buff.desc.cursed")),
|
||||||
BuffKind::Burning { .. } => Cow::Borrowed(localized_strings.get("buff.desc.burn")),
|
BuffKind::Burning { .. } => Cow::Borrowed(localized_strings.get("buff.desc.burn")),
|
||||||
|
BuffKind::Crippled { .. } => Cow::Borrowed(localized_strings.get("buff.desc.crippled")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +118,9 @@ pub fn consumable_desc(effects: &[Effect], i18n: &Localization) -> String {
|
|||||||
| BuffKind::Burning
|
| BuffKind::Burning
|
||||||
| BuffKind::CampfireHeal
|
| BuffKind::CampfireHeal
|
||||||
| BuffKind::Cursed
|
| BuffKind::Cursed
|
||||||
| BuffKind::ProtectingWard => continue,
|
| BuffKind::ProtectingWard
|
||||||
|
| BuffKind::Crippled
|
||||||
|
| BuffKind::Frenzied => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
write!(&mut description, "{}", buff_desc).unwrap();
|
write!(&mut description, "{}", buff_desc).unwrap();
|
||||||
@ -138,7 +140,9 @@ pub fn consumable_desc(effects: &[Effect], i18n: &Localization) -> String {
|
|||||||
| BuffKind::Potion
|
| BuffKind::Potion
|
||||||
| BuffKind::CampfireHeal
|
| BuffKind::CampfireHeal
|
||||||
| BuffKind::Cursed
|
| BuffKind::Cursed
|
||||||
| BuffKind::ProtectingWard => continue,
|
| BuffKind::ProtectingWard
|
||||||
|
| BuffKind::Crippled
|
||||||
|
| BuffKind::Frenzied => continue,
|
||||||
}
|
}
|
||||||
} else if let BuffKind::Saturation | BuffKind::Regeneration = buff.kind {
|
} else if let BuffKind::Saturation | BuffKind::Regeneration = buff.kind {
|
||||||
i18n.get("buff.text.every_second").to_string()
|
i18n.get("buff.text.every_second").to_string()
|
||||||
|
@ -122,6 +122,8 @@ pub enum ParticleMode {
|
|||||||
CultistFlame = 23,
|
CultistFlame = 23,
|
||||||
StaticSmoke = 24,
|
StaticSmoke = 24,
|
||||||
Blood = 25,
|
Blood = 25,
|
||||||
|
Enraged = 26,
|
||||||
|
BigShrapnel = 27,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParticleMode {
|
impl ParticleMode {
|
||||||
|
@ -3495,7 +3495,6 @@ struct SidedBLCentralVoxSpec {
|
|||||||
torso_upper: BipedLargeCentralSubSpec,
|
torso_upper: BipedLargeCentralSubSpec,
|
||||||
torso_lower: BipedLargeCentralSubSpec,
|
torso_lower: BipedLargeCentralSubSpec,
|
||||||
tail: BipedLargeCentralSubSpec,
|
tail: BipedLargeCentralSubSpec,
|
||||||
second: BipedLargeCentralSubSpec,
|
|
||||||
}
|
}
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct BipedLargeCentralSubSpec {
|
struct BipedLargeCentralSubSpec {
|
||||||
@ -3523,13 +3522,16 @@ struct BipedLargeLateralSubSpec {
|
|||||||
lateral: VoxSimple,
|
lateral: VoxSimple,
|
||||||
}
|
}
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct BipedLargeWeaponSpec(HashMap<String, ArmorVoxSpec>);
|
struct BipedLargeMainSpec(HashMap<String, ArmorVoxSpec>);
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct BipedLargeSecondSpec(HashMap<String, ArmorVoxSpec>);
|
||||||
make_vox_spec!(
|
make_vox_spec!(
|
||||||
biped_large::Body,
|
biped_large::Body,
|
||||||
struct BipedLargeSpec {
|
struct BipedLargeSpec {
|
||||||
central: BipedLargeCentralSpec = "voxygen.voxel.biped_large_central_manifest",
|
central: BipedLargeCentralSpec = "voxygen.voxel.biped_large_central_manifest",
|
||||||
lateral: BipedLargeLateralSpec = "voxygen.voxel.biped_large_lateral_manifest",
|
lateral: BipedLargeLateralSpec = "voxygen.voxel.biped_large_lateral_manifest",
|
||||||
weapon: BipedLargeWeaponSpec = "voxygen.voxel.biped_weapon_manifest",
|
main: BipedLargeMainSpec = "voxygen.voxel.biped_weapon_manifest",
|
||||||
|
second: BipedLargeSecondSpec = "voxygen.voxel.biped_weapon_manifest",
|
||||||
},
|
},
|
||||||
|FigureKey { body, extra }, spec| {
|
|FigureKey { body, extra }, spec| {
|
||||||
const DEFAULT_LOADOUT: super::cache::CharacterCacheKey = super::cache::CharacterCacheKey {
|
const DEFAULT_LOADOUT: super::cache::CharacterCacheKey = super::cache::CharacterCacheKey {
|
||||||
@ -3567,15 +3569,17 @@ make_vox_spec!(
|
|||||||
body.body_type,
|
body.body_type,
|
||||||
)),
|
)),
|
||||||
tool.and_then(|tool| tool.active.as_ref()).map(|tool| {
|
tool.and_then(|tool| tool.active.as_ref()).map(|tool| {
|
||||||
spec.weapon.read().0.mesh_main(
|
spec.main.read().0.mesh_main(
|
||||||
|
&tool.name,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
tool.and_then(|tool| tool.active.as_ref()).map(|tool| {
|
||||||
|
spec.second.read().0.mesh_second(
|
||||||
&tool.name,
|
&tool.name,
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
Some(spec.central.read().0.mesh_second(
|
|
||||||
body.species,
|
|
||||||
body.body_type,
|
|
||||||
)),
|
|
||||||
Some(spec.lateral.read().0.mesh_shoulder_l(
|
Some(spec.lateral.read().0.mesh_shoulder_l(
|
||||||
body.species,
|
body.species,
|
||||||
body.body_type,
|
body.body_type,
|
||||||
@ -3693,22 +3697,6 @@ impl BipedLargeCentralSpec {
|
|||||||
|
|
||||||
(central, Vec3::from(spec.tail.offset))
|
(central, Vec3::from(spec.tail.offset))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mesh_second(&self, species: BLSpecies, body_type: BLBodyType) -> BoneMeshes {
|
|
||||||
let spec = match self.0.get(&(species, body_type)) {
|
|
||||||
Some(spec) => spec,
|
|
||||||
None => {
|
|
||||||
error!(
|
|
||||||
"No second weapon specification exists for the combination of {:?} and {:?}",
|
|
||||||
species, body_type
|
|
||||||
);
|
|
||||||
return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let central = graceful_load_segment(&spec.second.central.0);
|
|
||||||
|
|
||||||
(central, Vec3::from(spec.second.offset))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
impl BipedLargeLateralSpec {
|
impl BipedLargeLateralSpec {
|
||||||
fn mesh_shoulder_l(&self, species: BLSpecies, body_type: BLBodyType) -> BoneMeshes {
|
fn mesh_shoulder_l(&self, species: BLSpecies, body_type: BLBodyType) -> BoneMeshes {
|
||||||
@ -3839,7 +3827,7 @@ impl BipedLargeLateralSpec {
|
|||||||
(lateral, Vec3::from(spec.foot_r.offset))
|
(lateral, Vec3::from(spec.foot_r.offset))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl BipedLargeWeaponSpec {
|
impl BipedLargeMainSpec {
|
||||||
fn mesh_main(&self, item_definition_id: &str, flipped: bool) -> BoneMeshes {
|
fn mesh_main(&self, item_definition_id: &str, flipped: bool) -> BoneMeshes {
|
||||||
let spec = match self.0.get(item_definition_id) {
|
let spec = match self.0.get(item_definition_id) {
|
||||||
Some(spec) => spec,
|
Some(spec) => spec,
|
||||||
@ -3868,6 +3856,35 @@ impl BipedLargeWeaponSpec {
|
|||||||
(tool_kind_segment, offset)
|
(tool_kind_segment, offset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl BipedLargeSecondSpec {
|
||||||
|
fn mesh_second(&self, item_definition_id: &str, flipped: bool) -> BoneMeshes {
|
||||||
|
let spec = match self.0.get(item_definition_id) {
|
||||||
|
Some(spec) => spec,
|
||||||
|
None => {
|
||||||
|
error!(?item_definition_id, "No tool/weapon specification exists");
|
||||||
|
return load_mesh("not_found", Vec3::new(-1.5, -1.5, -7.0));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let tool_kind_segment = if flipped {
|
||||||
|
graceful_load_segment_flipped(&spec.vox_spec.0, true)
|
||||||
|
} else {
|
||||||
|
graceful_load_segment(&spec.vox_spec.0)
|
||||||
|
};
|
||||||
|
|
||||||
|
let offset = Vec3::new(
|
||||||
|
if flipped {
|
||||||
|
0.0 - spec.vox_spec.1[0] - (tool_kind_segment.sz.x as f32)
|
||||||
|
} else {
|
||||||
|
spec.vox_spec.1[0]
|
||||||
|
},
|
||||||
|
spec.vox_spec.1[1],
|
||||||
|
spec.vox_spec.1[2],
|
||||||
|
);
|
||||||
|
|
||||||
|
(tool_kind_segment, offset)
|
||||||
|
}
|
||||||
|
}
|
||||||
////
|
////
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct GolemCentralSpec(HashMap<(GSpecies, GBodyType), SidedGCentralVoxSpec>);
|
struct GolemCentralSpec(HashMap<(GSpecies, GBodyType), SidedGCentralVoxSpec>);
|
||||||
|
@ -3713,7 +3713,84 @@ impl FigureMgr {
|
|||||||
skeleton_attr,
|
skeleton_attr,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
CharacterState::BasicMelee(_) => {
|
CharacterState::ChargedMelee(s) => {
|
||||||
|
let stage_time = s.timer.as_secs_f32();
|
||||||
|
|
||||||
|
let stage_progress = match s.stage_section {
|
||||||
|
StageSection::Charge => {
|
||||||
|
stage_time / s.static_data.charge_duration.as_secs_f32()
|
||||||
|
},
|
||||||
|
StageSection::Swing => {
|
||||||
|
stage_time / s.static_data.swing_duration.as_secs_f32()
|
||||||
|
},
|
||||||
|
StageSection::Recover => {
|
||||||
|
stage_time / s.static_data.recover_duration.as_secs_f32()
|
||||||
|
},
|
||||||
|
_ => 0.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
anim::biped_large::ChargeMeleeAnimation::update_skeleton(
|
||||||
|
&target_base,
|
||||||
|
(
|
||||||
|
(active_tool_kind, active_tool_spec),
|
||||||
|
(second_tool_kind, second_tool_spec),
|
||||||
|
rel_vel,
|
||||||
|
time,
|
||||||
|
Some(s.stage_section),
|
||||||
|
state.acc_vel,
|
||||||
|
),
|
||||||
|
stage_progress,
|
||||||
|
&mut state_animation_rate,
|
||||||
|
skeleton_attr,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
CharacterState::SelfBuff(s) => {
|
||||||
|
let stage_time = s.timer.as_secs_f32();
|
||||||
|
|
||||||
|
let stage_progress = match s.stage_section {
|
||||||
|
StageSection::Buildup => {
|
||||||
|
stage_time / s.static_data.buildup_duration.as_secs_f32()
|
||||||
|
},
|
||||||
|
StageSection::Cast => {
|
||||||
|
stage_time / s.static_data.cast_duration.as_secs_f32()
|
||||||
|
},
|
||||||
|
StageSection::Recover => {
|
||||||
|
stage_time / s.static_data.recover_duration.as_secs_f32()
|
||||||
|
},
|
||||||
|
_ => 0.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
anim::biped_large::SelfBuffAnimation::update_skeleton(
|
||||||
|
&target_base,
|
||||||
|
(
|
||||||
|
(active_tool_kind, active_tool_spec),
|
||||||
|
(second_tool_kind, second_tool_spec),
|
||||||
|
rel_vel,
|
||||||
|
time,
|
||||||
|
Some(s.stage_section),
|
||||||
|
state.acc_vel,
|
||||||
|
),
|
||||||
|
stage_progress,
|
||||||
|
&mut state_animation_rate,
|
||||||
|
skeleton_attr,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
CharacterState::BasicMelee(s) => {
|
||||||
|
let stage_time = s.timer.as_secs_f32();
|
||||||
|
|
||||||
|
let stage_progress = match s.stage_section {
|
||||||
|
StageSection::Buildup => {
|
||||||
|
stage_time / s.static_data.buildup_duration.as_secs_f32()
|
||||||
|
},
|
||||||
|
StageSection::Swing => {
|
||||||
|
stage_time / s.static_data.swing_duration.as_secs_f32()
|
||||||
|
},
|
||||||
|
StageSection::Recover => {
|
||||||
|
stage_time / s.static_data.recover_duration.as_secs_f32()
|
||||||
|
},
|
||||||
|
_ => 0.0,
|
||||||
|
};
|
||||||
|
|
||||||
anim::biped_large::AlphaAnimation::update_skeleton(
|
anim::biped_large::AlphaAnimation::update_skeleton(
|
||||||
&target_base,
|
&target_base,
|
||||||
(
|
(
|
||||||
@ -3721,10 +3798,10 @@ impl FigureMgr {
|
|||||||
(second_tool_kind, second_tool_spec),
|
(second_tool_kind, second_tool_spec),
|
||||||
rel_vel,
|
rel_vel,
|
||||||
time,
|
time,
|
||||||
None,
|
Some(s.stage_section),
|
||||||
state.acc_vel,
|
state.acc_vel,
|
||||||
),
|
),
|
||||||
state.state_time,
|
stage_progress,
|
||||||
&mut state_animation_rate,
|
&mut state_animation_rate,
|
||||||
skeleton_attr,
|
skeleton_attr,
|
||||||
)
|
)
|
||||||
@ -3875,8 +3952,8 @@ impl FigureMgr {
|
|||||||
anim::biped_large::DashAnimation::update_skeleton(
|
anim::biped_large::DashAnimation::update_skeleton(
|
||||||
&target_base,
|
&target_base,
|
||||||
(
|
(
|
||||||
active_tool_kind,
|
(active_tool_kind, active_tool_spec),
|
||||||
second_tool_kind,
|
(second_tool_kind, second_tool_spec),
|
||||||
rel_vel,
|
rel_vel,
|
||||||
time,
|
time,
|
||||||
Some(s.stage_section),
|
Some(s.stage_section),
|
||||||
|
@ -215,6 +215,16 @@ impl ParticleMgr {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Outcome::GroundSlam { pos, .. } => {
|
||||||
|
self.particles.resize_with(self.particles.len() + 100, || {
|
||||||
|
Particle::new(
|
||||||
|
Duration::from_millis(1000),
|
||||||
|
time,
|
||||||
|
ParticleMode::BigShrapnel,
|
||||||
|
*pos,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
},
|
||||||
Outcome::ProjectileShot { .. }
|
Outcome::ProjectileShot { .. }
|
||||||
| Outcome::Beam { .. }
|
| Outcome::Beam { .. }
|
||||||
| Outcome::ExpChange { .. }
|
| Outcome::ExpChange { .. }
|
||||||
@ -643,6 +653,36 @@ impl ParticleMgr {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
CharacterState::SelfBuff(c) => {
|
||||||
|
use buff::BuffKind;
|
||||||
|
if let BuffKind::Frenzied = c.static_data.buff_kind {
|
||||||
|
if matches!(c.stage_section, StageSection::Cast) {
|
||||||
|
self.particles.resize_with(
|
||||||
|
self.particles.len()
|
||||||
|
+ usize::from(
|
||||||
|
self.scheduler.heartbeats(Duration::from_millis(5)),
|
||||||
|
),
|
||||||
|
|| {
|
||||||
|
let start_pos = pos.0
|
||||||
|
+ Vec3::new(
|
||||||
|
body.radius(),
|
||||||
|
body.radius(),
|
||||||
|
body.height() / 2.0,
|
||||||
|
)
|
||||||
|
.map(|d| d * rng.gen_range(-1.0..1.0));
|
||||||
|
let end_pos = pos.0 + (start_pos - pos.0) * 6.0;
|
||||||
|
Particle::new_directed(
|
||||||
|
Duration::from_secs(1),
|
||||||
|
time,
|
||||||
|
ParticleMode::Enraged,
|
||||||
|
start_pos,
|
||||||
|
end_pos,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -818,9 +858,9 @@ impl ParticleMgr {
|
|||||||
.join()
|
.join()
|
||||||
{
|
{
|
||||||
for (buff_kind, _) in buffs.kinds.iter() {
|
for (buff_kind, _) in buffs.kinds.iter() {
|
||||||
#[allow(clippy::single_match)]
|
use buff::BuffKind;
|
||||||
match buff_kind {
|
match buff_kind {
|
||||||
buff::BuffKind::Cursed | buff::BuffKind::Burning => {
|
BuffKind::Cursed | BuffKind::Burning => {
|
||||||
self.particles.resize_with(
|
self.particles.resize_with(
|
||||||
self.particles.len()
|
self.particles.len()
|
||||||
+ usize::from(self.scheduler.heartbeats(Duration::from_millis(15))),
|
+ usize::from(self.scheduler.heartbeats(Duration::from_millis(15))),
|
||||||
@ -850,6 +890,29 @@ impl ParticleMgr {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
BuffKind::Frenzied => {
|
||||||
|
self.particles.resize_with(
|
||||||
|
self.particles.len()
|
||||||
|
+ usize::from(self.scheduler.heartbeats(Duration::from_millis(15))),
|
||||||
|
|| {
|
||||||
|
let start_pos = pos.0
|
||||||
|
+ Vec3::new(body.radius(), body.radius(), body.height() / 2.0)
|
||||||
|
.map(|d| d * rng.gen_range(-1.0..1.0));
|
||||||
|
let end_pos = start_pos
|
||||||
|
+ Vec3::unit_z() * body.height()
|
||||||
|
+ Vec3::<f32>::zero()
|
||||||
|
.map(|_| rng.gen_range(-1.0..1.0))
|
||||||
|
.normalized();
|
||||||
|
Particle::new_directed(
|
||||||
|
Duration::from_secs(1),
|
||||||
|
time,
|
||||||
|
ParticleMode::Enraged,
|
||||||
|
start_pos,
|
||||||
|
end_pos,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user