Merge branch 'spawn_wyverns' into 'master'

spawn wyverns

See merge request veloren/veloren!3994
This commit is contained in:
Isse 2023-08-02 07:55:10 +00:00
commit b08b9cf8e8
78 changed files with 1505 additions and 1066 deletions

View File

@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- First version of multisalvage that allows to obtain more than one piece of material from salvage
- Axe
- Combat music toggle
- Spawn rtsim wyverns that travel the world, providing dragon scale loot drops
### Changed

View File

@ -724,42 +724,42 @@
),
Custom("Flame Wyvern"): (
primary: Simple(None, "common.abilities.custom.flamewyvern.firebomb"),
secondary: Simple(None, "common.abilities.custom.flamewyvern.fireshockwave"),
secondary: Simple(None, "common.abilities.custom.flamewyvern.triplestrike"),
abilities: [
Simple(None, "common.abilities.custom.flamewyvern.triplestrike"),
Simple(None, "common.abilities.custom.flamewyvern.fireshockwave"),
Simple(None, "common.abilities.custom.flamewyvern.flamethrower"),
],
),
Custom("Frost Wyvern"): (
primary: Simple(None, "common.abilities.custom.frostwyvern.frostbomb"),
secondary: Simple(None, "common.abilities.custom.frostwyvern.iceshockwave"),
secondary: Simple(None, "common.abilities.custom.frostwyvern.triplestrike"),
abilities: [
Simple(None, "common.abilities.custom.frostwyvern.triplestrike"),
Simple(None, "common.abilities.custom.frostwyvern.iceshockwave"),
Simple(None, "common.abilities.custom.frostwyvern.frostthrower"),
],
),
Custom("Cloud Wyvern"): (
primary: Simple(None, "common.abilities.custom.cloudwyvern.windbomb"),
secondary: Simple(None, "common.abilities.custom.cloudwyvern.windshockwave"),
primary: Simple(None, "common.abilities.custom.cloudwyvern.lightningbomb"),
secondary: Simple(None, "common.abilities.custom.cloudwyvern.triplestrike"),
abilities: [
Simple(None, "common.abilities.custom.cloudwyvern.triplestrike"),
Simple(None, "common.abilities.custom.cloudwyvern.windthrower"),
Simple(None, "common.abilities.custom.cloudwyvern.lightningshockwave"),
Simple(None, "common.abilities.custom.cloudwyvern.lightningthrower"),
],
),
Custom("Sea Wyvern"): (
primary: Simple(None, "common.abilities.custom.seawyvern.seabomb"),
secondary: Simple(None, "common.abilities.custom.seawyvern.seashockwave"),
primary: Simple(None, "common.abilities.custom.seawyvern.inkbomb"),
secondary: Simple(None, "common.abilities.custom.seawyvern.triplestrike"),
abilities: [
Simple(None, "common.abilities.custom.seawyvern.triplestrike"),
Simple(None, "common.abilities.custom.seawyvern.bubblethrower"),
Simple(None, "common.abilities.custom.seawyvern.inkshockwave"),
Simple(None, "common.abilities.custom.seawyvern.inkthrower"),
],
),
Custom("Weald Wyvern"): (
primary: Simple(None, "common.abilities.custom.wealdwyvern.firebomb"),
secondary: Simple(None, "common.abilities.custom.wealdwyvern.fireshockwave"),
primary: Simple(None, "common.abilities.custom.wealdwyvern.poisonbomb"),
secondary: Simple(None, "common.abilities.custom.wealdwyvern.triplestrike"),
abilities: [
Simple(None, "common.abilities.custom.wealdwyvern.triplestrike"),
Simple(None, "common.abilities.custom.wealdwyvern.flamethrower"),
Simple(None, "common.abilities.custom.wealdwyvern.poisonshockwave"),
Simple(None, "common.abilities.custom.wealdwyvern.poisonthrower"),
],
),
Custom("Bird Large Basic"): (

View File

@ -13,7 +13,7 @@ BasicRanged(
col: (1.0, 0.75, 0.11).into(),
..Default::default()
}),*/
projectile_speed: 260.0,
projectile_speed: 25.0,
num_projectiles: 1,
projectile_spread: 0.3,
move_efficiency: 0.3,

View File

@ -1,59 +1,66 @@
ComboMelee(
stage_data: [
ComboMelee2(
strikes: [
(
stage: 1,
base_damage: 22.0,
damage_increase: 0,
base_poise_damage: 0,
poise_damage_increase: 0,
knockback: 5.0,
range: 4.5,
angle: 30.0,
base_buildup_duration: 0.8,
base_swing_duration: 0.1,
melee_constructor: (
kind: Slash(
damage: 22,
poise: 0,
knockback: 5,
energy_regen: 0,
),
range: 4.5,
angle: 30.0,
),
buildup_duration: 0.8,
swing_duration: 0.1,
hit_timing: 0.5,
base_recover_duration: 0.6,
forward_movement: 3.0,
damage_kind: Crushing,
recover_duration: 0.6,
movement: (
swing: Some(Forward(3.0)),
),
ori_modifier: 0.7,
),
(
stage: 2,
base_damage: 18.0,
damage_increase: 0,
base_poise_damage: 0,
poise_damage_increase: 0,
knockback: 5.0,
range: 3.5,
angle: 30.0,
base_buildup_duration: 0.8,
base_swing_duration: 0.1,
melee_constructor: (
kind: Slash(
damage: 18,
poise: 0,
knockback: 5,
energy_regen: 0,
),
range: 3.5,
angle: 30.0,
),
buildup_duration: 0.8,
swing_duration: 0.1,
hit_timing: 0.5,
base_recover_duration: 0.6,
forward_movement: 3.0,
damage_kind: Crushing,
recover_duration: 0.6,
movement: (
swing: Some(Forward(3.0)),
),
ori_modifier: 0.7,
),
(
stage: 3,
base_damage: 28.0,
damage_increase: 0,
base_poise_damage: 0,
poise_damage_increase: 0,
knockback: 10.0,
range: 3.5,
angle: 30.0,
base_buildup_duration: 1.3,
base_swing_duration: 0.1,
melee_constructor: (
kind: Slash(
damage: 28,
poise: 0,
knockback: 10,
energy_regen: 0,
),
range: 3.5,
angle: 30.0,
),
buildup_duration: 1.3,
swing_duration: 0.1,
hit_timing: 0.5,
base_recover_duration: 0.6,
forward_movement: 3.5,
damage_kind: Crushing,
recover_duration: 0.6,
movement: (
swing: Some(Forward(3.5)),
),
ori_modifier: 0.7,
),
],
initial_energy_gain: 0,
max_energy_gain: 0,
energy_increase: 0,
speed_increase: 0.0,
max_speed_increase: 0.0,
scales_from_combo: 0,
ori_modifier: 0.7,
)
energy_cost_per_strike: 0,
auto_progress: true,
)

View File

@ -1,77 +1,66 @@
ComboMelee(
stage_data: [
ComboMelee2(
strikes: [
(
stage: 1,
base_damage: 20.0,
damage_increase: 0,
base_poise_damage: 0,
poise_damage_increase: 0,
knockback: 5.0,
range: 4.5,
angle: 30.0,
base_buildup_duration: 0.8,
base_swing_duration: 0.1,
melee_constructor: (
kind: Slash(
damage: 20,
poise: 0,
knockback: 5,
energy_regen: 0,
),
range: 4.5,
angle: 30.0,
),
buildup_duration: 0.8,
swing_duration: 0.1,
hit_timing: 0.5,
base_recover_duration: 0.6,
forward_movement: 2.0,
damage_kind: Slashing,
damage_effect: Some(Buff((
kind: Bleeding,
dur_secs: 10.0,
strength: DamageFraction(0.1),
chance: 0.1,
))),
recover_duration: 0.6,
movement: (
swing: Some(Forward(2.0)),
),
ori_modifier: 0.7,
),
(
stage: 2,
base_damage: 16.0,
damage_increase: 0,
base_poise_damage: 0,
poise_damage_increase: 0,
knockback: 5.0,
range: 3.5,
angle: 30.0,
base_buildup_duration: 0.8,
base_swing_duration: 0.1,
melee_constructor: (
kind: Slash(
damage: 16,
poise: 0,
knockback: 5,
energy_regen: 0,
),
range: 3.5,
angle: 30.0,
),
buildup_duration: 0.8,
swing_duration: 0.1,
hit_timing: 0.5,
base_recover_duration: 0.6,
forward_movement: 1.5,
damage_kind: Slashing,
damage_effect: Some(Buff((
kind: Bleeding,
dur_secs: 10.0,
strength: DamageFraction(0.1),
chance: 0.1,
))),
recover_duration: 0.6,
movement: (
swing: Some(Forward(2.0)),
),
ori_modifier: 0.7,
),
(
stage: 3,
base_damage: 26.0,
damage_increase: 0,
base_poise_damage: 0,
poise_damage_increase: 0,
knockback: 10.0,
range: 3.5,
angle: 30.0,
base_buildup_duration: 1.3,
base_swing_duration: 0.1,
melee_constructor: (
kind: Slash(
damage: 26,
poise: 0,
knockback: 10,
energy_regen: 0,
),
range: 3.5,
angle: 30.0,
),
buildup_duration: 0.4,
swing_duration: 0.1,
hit_timing: 0.5,
base_recover_duration: 0.6,
forward_movement: 1.5,
damage_kind: Slashing,
damage_effect: Some(Buff((
kind: Bleeding,
dur_secs: 10.0,
strength: DamageFraction(0.1),
chance: 0.1,
))),
recover_duration: 0.6,
movement: (
swing: Some(Forward(1.5)),
),
ori_modifier: 0.7,
),
],
initial_energy_gain: 0,
max_energy_gain: 0,
energy_increase: 0,
speed_increase: 0.0,
max_speed_increase: 0.0,
scales_from_combo: 0,
ori_modifier: 0.7,
)
energy_cost_per_strike: 0,
auto_progress: true,
)

View File

@ -1,77 +1,66 @@
ComboMelee(
stage_data: [
ComboMelee2(
strikes: [
(
stage: 1,
base_damage: 20.0,
damage_increase: 0,
base_poise_damage: 0,
poise_damage_increase: 0,
knockback: 5.0,
range: 4.5,
angle: 30.0,
base_buildup_duration: 0.8,
base_swing_duration: 0.1,
melee_constructor: (
kind: Slash(
damage: 20,
poise: 0,
knockback: 5,
energy_regen: 0,
),
range: 4.5,
angle: 30.0,
),
buildup_duration: 0.8,
swing_duration: 0.1,
hit_timing: 0.5,
base_recover_duration: 0.6,
forward_movement: 2.0,
damage_kind: Slashing,
damage_effect: Some(Buff((
kind: Bleeding,
dur_secs: 10.0,
strength: DamageFraction(0.1),
chance: 0.1,
))),
recover_duration: 0.6,
movement: (
swing: Some(Forward(2.0)),
),
ori_modifier: 0.7,
),
(
stage: 2,
base_damage: 16.0,
damage_increase: 0,
base_poise_damage: 0,
poise_damage_increase: 0,
knockback: 5.0,
range: 3.5,
angle: 30.0,
base_buildup_duration: 0.8,
base_swing_duration: 0.1,
melee_constructor: (
kind: Slash(
damage: 16,
poise: 0,
knockback: 5,
energy_regen: 0,
),
range: 3.5,
angle: 30.0,
),
buildup_duration: 0.8,
swing_duration: 0.1,
hit_timing: 0.5,
base_recover_duration: 0.6,
forward_movement: 1.5,
damage_kind: Slashing,
damage_effect: Some(Buff((
kind: Bleeding,
dur_secs: 10.0,
strength: DamageFraction(0.1),
chance: 0.1,
))),
recover_duration: 0.6,
movement: (
swing: Some(Forward(2.0)),
),
ori_modifier: 0.7,
),
(
stage: 3,
base_damage: 26.0,
damage_increase: 0,
base_poise_damage: 0,
poise_damage_increase: 0,
knockback: 10.0,
range: 3.5,
angle: 30.0,
base_buildup_duration: 0.375,
base_swing_duration: 0.1,
melee_constructor: (
kind: Slash(
damage: 26,
poise: 0,
knockback: 10,
energy_regen: 0,
),
range: 3.5,
angle: 30.0,
),
buildup_duration: 0.4,
swing_duration: 0.1,
hit_timing: 0.5,
base_recover_duration: 0.6,
forward_movement: 1.5,
damage_kind: Slashing,
damage_effect: Some(Buff((
kind: Bleeding,
dur_secs: 10.0,
strength: DamageFraction(0.1),
chance: 0.1,
))),
recover_duration: 0.6,
movement: (
swing: Some(Forward(1.5)),
),
ori_modifier: 0.7,
),
],
initial_energy_gain: 0,
max_energy_gain: 0,
energy_increase: 0,
speed_increase: 0.0,
max_speed_increase: 0.0,
scales_from_combo: 0,
ori_modifier: 0.7,
)
energy_cost_per_strike: 0,
auto_progress: true,
)

View File

@ -0,0 +1,18 @@
BasicRanged(
energy_cost: 0,
buildup_duration: 0.5,
recover_duration: 1.5,
projectile: LaserBeam(
damage: 20.0,
radius: 5.0,
knockback: 5.0,
energy_regen: 20.0,
min_falloff: 0.1,
),
projectile_body: Object(LightningBolt),
projectile_light: None,
projectile_speed: 100.0,
num_projectiles: 1,
projectile_spread: 0.0,
move_efficiency: 0.3,
)

View File

@ -0,0 +1,24 @@
Shockwave(
energy_cost: 0,
buildup_duration: 0.3,
swing_duration: 0.3,
recover_duration: 2.0,
damage: 20.0,
poise_damage: 10,
knockback: (strength: 18.0, direction: Away),
shockwave_angle: 360.0,
shockwave_vertical_angle: 90.0,
shockwave_speed: 15.0,
shockwave_duration: 2.0,
requires_ground: true,
move_efficiency: 0.0,
damage_kind: Crushing,
specifier: Lightning,
ori_rate: 1.0,
damage_effect: Some(Buff((
kind: Crippled,
dur_secs: 2.0,
strength: Value(0.3),
chance: 1.0,
))),
)

View File

@ -0,0 +1,19 @@
BasicBeam(
buildup_duration: 0.3,
recover_duration: 1.5,
beam_duration: 2.0,
damage: 22.5,
tick_rate: 3.0,
range: 22.0,
max_angle: 22.5,
damage_effect: Some(Buff((
kind: Crippled,
dur_secs: 3.0,
strength: Value(0.5),
chance: 1.0,
))),
energy_regen: 2,
energy_drain: 0,
ori_rate: 0.5,
specifier: Lightning,
)

View File

@ -1,77 +1,66 @@
ComboMelee(
stage_data: [
ComboMelee2(
strikes: [
(
stage: 1,
base_damage: 20.0,
damage_increase: 0,
base_poise_damage: 0,
poise_damage_increase: 0,
knockback: 5.0,
range: 4.5,
angle: 30.0,
base_buildup_duration: 0.8,
base_swing_duration: 0.1,
melee_constructor: (
kind: Slash(
damage: 20,
poise: 0,
knockback: 5,
energy_regen: 0,
),
range: 4.5,
angle: 30.0,
),
buildup_duration: 0.8,
swing_duration: 0.1,
hit_timing: 0.5,
base_recover_duration: 0.6,
forward_movement: 2.0,
damage_kind: Slashing,
damage_effect: Some(Buff((
kind: Bleeding,
dur_secs: 10.0,
strength: DamageFraction(0.1),
chance: 0.1,
))),
recover_duration: 0.6,
movement: (
swing: Some(Forward(2.0)),
),
ori_modifier: 0.7,
),
(
stage: 2,
base_damage: 16.0,
damage_increase: 0,
base_poise_damage: 0,
poise_damage_increase: 0,
knockback: 5.0,
range: 3.5,
angle: 30.0,
base_buildup_duration: 0.8,
base_swing_duration: 0.1,
melee_constructor: (
kind: Slash(
damage: 16,
poise: 0,
knockback: 5,
energy_regen: 0,
),
range: 3.5,
angle: 30.0,
),
buildup_duration: 0.8,
swing_duration: 0.1,
hit_timing: 0.5,
base_recover_duration: 0.6,
forward_movement: 1.5,
damage_kind: Slashing,
damage_effect: Some(Buff((
kind: Bleeding,
dur_secs: 10.0,
strength: DamageFraction(0.1),
chance: 0.1,
))),
recover_duration: 0.6,
movement: (
swing: Some(Forward(2.0)),
),
ori_modifier: 0.7,
),
(
stage: 3,
base_damage: 26.0,
damage_increase: 0,
base_poise_damage: 0,
poise_damage_increase: 0,
knockback: 10.0,
range: 3.5,
angle: 30.0,
base_buildup_duration: 0.375,
base_swing_duration: 0.1,
melee_constructor: (
kind: Slash(
damage: 26,
poise: 0,
knockback: 10,
energy_regen: 0,
),
range: 3.5,
angle: 30.0,
),
buildup_duration: 0.4,
swing_duration: 0.1,
hit_timing: 0.5,
base_recover_duration: 0.6,
forward_movement: 1.5,
damage_kind: Slashing,
damage_effect: Some(Buff((
kind: Bleeding,
dur_secs: 10.0,
strength: DamageFraction(0.1),
chance: 0.1,
))),
recover_duration: 0.6,
movement: (
swing: Some(Forward(1.5)),
),
ori_modifier: 0.7,
),
],
initial_energy_gain: 0,
max_energy_gain: 0,
energy_increase: 0,
speed_increase: 0.0,
max_speed_increase: 0.0,
scales_from_combo: 0,
ori_modifier: 0.7,
)
energy_cost_per_strike: 0,
auto_progress: true,
)

View File

@ -1,20 +0,0 @@
BasicRanged(
energy_cost: 0,
buildup_duration: 1.0,
recover_duration: 0.7,
projectile: WindBomb(
damage: 20.0,
radius: 5.0,
energy_regen: 5.0,
min_falloff: 0.5,
),
projectile_body: Object(BoltFire),
/*projectile_light: Some(LightEmitter {
col: (1.0, 0.75, 0.11).into(),
..Default::default()
}),*/
projectile_speed: 60.0,
num_projectiles: 1,
projectile_spread: 0.0,
move_efficiency: 0.3,
)

View File

@ -1,18 +0,0 @@
Shockwave(
energy_cost: 60.0,
buildup_duration: 1.4,
swing_duration: 0.1,
recover_duration: 0.4,
damage: 40.0,
poise_damage: 0,
knockback: ( strength: 25.0, direction: Away),
shockwave_angle: 360.0,
shockwave_vertical_angle: 90.0,
shockwave_speed: 20.0,
shockwave_duration: 0.5,
requires_ground: false,
move_efficiency: 0.1,
damage_kind: Energy,
specifier: Water,
ori_rate: 1.0,
)

View File

@ -1,19 +0,0 @@
BasicBeam(
buildup_duration: 0.8,
recover_duration: 0.5,
beam_duration: 0.5,
damage: 10.0,
tick_rate: 3.0,
range: 15.0,
max_angle: 22.5,
damage_effect: Some(Buff((
kind: Burning,
dur_secs: 10.0,
strength: DamageFraction(0.5),
chance: 0.25,
))),
energy_regen: 0,
energy_drain: 0,
ori_rate: 0.3,
specifier: Bubbles,
)

View File

@ -1,20 +1,17 @@
BasicRanged(
energy_cost: 0,
buildup_duration: 1.0,
recover_duration: 0.7,
buildup_duration: 0.5,
recover_duration: 1.5,
projectile: Fireball(
damage: 20.0,
damage: 32.0,
radius: 5.0,
energy_regen: 5.0,
min_falloff: 0.5,
min_falloff: 0.1,
),
projectile_body: Object(BoltFire),
/*projectile_light: Some(LightEmitter {
col: (1.0, 0.75, 0.11).into(),
..Default::default()
}),*/
projectile_speed: 60.0,
projectile_light: None,
projectile_speed: 100.0,
num_projectiles: 1,
projectile_spread: 0.0,
move_efficiency: 0.3,
)
)

View File

@ -1,18 +1,24 @@
Shockwave(
energy_cost: 60.0,
buildup_duration: 1.4,
swing_duration: 0.1,
recover_duration: 0.4,
damage: 40.0,
poise_damage: 0,
knockback: ( strength: 25.0, direction: Away),
energy_cost: 0,
buildup_duration: 0.3,
swing_duration: 0.3,
recover_duration: 2.0,
damage: 20.0,
poise_damage: 10,
knockback: (strength: 18.0, direction: Away),
shockwave_angle: 360.0,
shockwave_vertical_angle: 90.0,
shockwave_speed: 20.0,
shockwave_duration: 0.5,
requires_ground: false,
move_efficiency: 0.1,
damage_kind: Energy,
shockwave_speed: 15.0,
shockwave_duration: 2.0,
requires_ground: true,
move_efficiency: 0.0,
damage_kind: Crushing,
specifier: Fire,
ori_rate: 1.0,
damage_effect: Some(Buff((
kind: Burning,
dur_secs: 2.0,
strength: DamageFraction(0.3),
chance: 1.0,
))),
)

View File

@ -1,19 +1,19 @@
BasicBeam(
buildup_duration: 0.8,
recover_duration: 0.5,
beam_duration: 0.5,
damage: 10.0,
buildup_duration: 0.3,
recover_duration: 1.5,
beam_duration: 2.0,
damage: 22.5,
tick_rate: 3.0,
range: 15.0,
range: 22.0,
max_angle: 22.5,
damage_effect: Some(Buff((
kind: Burning,
dur_secs: 10.0,
dur_secs: 3.0,
strength: DamageFraction(0.5),
chance: 0.25,
chance: 1.0,
))),
energy_regen: 0,
energy_regen: 2,
energy_drain: 0,
ori_rate: 0.3,
ori_rate: 0.5,
specifier: Flamethrower,
)

View File

@ -1,77 +1,66 @@
ComboMelee(
stage_data: [
ComboMelee2(
strikes: [
(
stage: 1,
base_damage: 20.0,
damage_increase: 0,
base_poise_damage: 0,
poise_damage_increase: 0,
knockback: 5.0,
range: 4.5,
angle: 30.0,
base_buildup_duration: 0.8,
base_swing_duration: 0.1,
melee_constructor: (
kind: Slash(
damage: 20,
poise: 0,
knockback: 5,
energy_regen: 0,
),
range: 4.5,
angle: 30.0,
),
buildup_duration: 0.8,
swing_duration: 0.1,
hit_timing: 0.5,
base_recover_duration: 0.6,
forward_movement: 2.0,
damage_kind: Slashing,
damage_effect: Some(Buff((
kind: Bleeding,
dur_secs: 10.0,
strength: DamageFraction(0.1),
chance: 0.1,
))),
recover_duration: 0.6,
movement: (
swing: Some(Forward(2.0)),
),
ori_modifier: 0.7,
),
(
stage: 2,
base_damage: 16.0,
damage_increase: 0,
base_poise_damage: 0,
poise_damage_increase: 0,
knockback: 5.0,
range: 3.5,
angle: 30.0,
base_buildup_duration: 0.8,
base_swing_duration: 0.1,
melee_constructor: (
kind: Slash(
damage: 16,
poise: 0,
knockback: 5,
energy_regen: 0,
),
range: 3.5,
angle: 30.0,
),
buildup_duration: 0.8,
swing_duration: 0.1,
hit_timing: 0.5,
base_recover_duration: 0.6,
forward_movement: 1.5,
damage_kind: Slashing,
damage_effect: Some(Buff((
kind: Bleeding,
dur_secs: 10.0,
strength: DamageFraction(0.1),
chance: 0.1,
))),
recover_duration: 0.6,
movement: (
swing: Some(Forward(2.0)),
),
ori_modifier: 0.7,
),
(
stage: 3,
base_damage: 26.0,
damage_increase: 0,
base_poise_damage: 0,
poise_damage_increase: 0,
knockback: 10.0,
range: 3.5,
angle: 30.0,
base_buildup_duration: 0.375,
base_swing_duration: 0.1,
melee_constructor: (
kind: Slash(
damage: 26,
poise: 0,
knockback: 10,
energy_regen: 0,
),
range: 3.5,
angle: 30.0,
),
buildup_duration: 0.4,
swing_duration: 0.1,
hit_timing: 0.5,
base_recover_duration: 0.6,
forward_movement: 1.5,
damage_kind: Slashing,
damage_effect: Some(Buff((
kind: Bleeding,
dur_secs: 10.0,
strength: DamageFraction(0.1),
chance: 0.1,
))),
recover_duration: 0.6,
movement: (
swing: Some(Forward(1.5)),
),
ori_modifier: 0.7,
),
],
initial_energy_gain: 0,
max_energy_gain: 0,
energy_increase: 0,
speed_increase: 0.0,
max_speed_increase: 0.0,
scales_from_combo: 0,
ori_modifier: 0.7,
)
energy_cost_per_strike: 0,
auto_progress: true,
)

View File

@ -1,19 +1,16 @@
BasicRanged(
energy_cost: 0,
buildup_duration: 1.0,
recover_duration: 0.7,
buildup_duration: 0.5,
recover_duration: 1.5,
projectile: Frostball(
damage: 20.0,
damage: 32.0,
radius: 5.0,
energy_regen: 5.0,
min_falloff: 0.5,
min_falloff: 0.1,
),
projectile_body: Object(BoltNature),
/*projectile_light: Some(LightEmitter {
col: (1.0, 0.75, 0.11).into(),
..Default::default()
}),*/
projectile_speed: 60.0,
projectile_body: Object(SpearIcicle),
projectile_light: None,
projectile_speed: 100.0,
num_projectiles: 1,
projectile_spread: 0.0,
move_efficiency: 0.3,

View File

@ -1,19 +1,19 @@
BasicBeam(
buildup_duration: 0.8,
recover_duration: 0.5,
beam_duration: 0.5,
damage: 10.0,
buildup_duration: 0.3,
recover_duration: 1.5,
beam_duration: 2.0,
damage: 22.5,
tick_rate: 3.0,
range: 15.0,
range: 22.0,
max_angle: 22.5,
damage_effect: Some(Buff((
kind: Burning,
dur_secs: 10.0,
strength: DamageFraction(0.5),
chance: 0.25,
kind: Frigid,
dur_secs: 3.0,
strength: Value(0.5),
chance: 1.0,
))),
energy_regen: 0,
energy_regen: 2,
energy_drain: 0,
ori_rate: 0.3,
ori_rate: 0.5,
specifier: Frost,
)

View File

@ -1,18 +1,24 @@
Shockwave(
energy_cost: 60.0,
buildup_duration: 1.4,
swing_duration: 0.1,
recover_duration: 0.4,
damage: 40.0,
poise_damage: 0,
knockback: ( strength: 25.0, direction: Away),
energy_cost: 0,
buildup_duration: 0.3,
swing_duration: 0.3,
recover_duration: 2.0,
damage: 20.0,
poise_damage: 10,
knockback: (strength: 18.0, direction: Away),
shockwave_angle: 360.0,
shockwave_vertical_angle: 90.0,
shockwave_speed: 20.0,
shockwave_duration: 0.5,
requires_ground: false,
move_efficiency: 0.1,
damage_kind: Energy,
specifier: IceSpikes,
shockwave_speed: 15.0,
shockwave_duration: 2.0,
requires_ground: true,
move_efficiency: 0.0,
damage_kind: Crushing,
specifier: Ice,
ori_rate: 1.0,
damage_effect: Some(Buff((
kind: Frozen,
dur_secs: 2.0,
strength: Value(0.3),
chance: 1.0,
))),
)

View File

@ -1,77 +1,66 @@
ComboMelee(
stage_data: [
ComboMelee2(
strikes: [
(
stage: 1,
base_damage: 20.0,
damage_increase: 0,
base_poise_damage: 0,
poise_damage_increase: 0,
knockback: 5.0,
range: 4.5,
angle: 30.0,
base_buildup_duration: 0.8,
base_swing_duration: 0.1,
melee_constructor: (
kind: Slash(
damage: 20,
poise: 0,
knockback: 5,
energy_regen: 0,
),
range: 4.5,
angle: 30.0,
),
buildup_duration: 0.8,
swing_duration: 0.1,
hit_timing: 0.5,
base_recover_duration: 0.6,
forward_movement: 2.0,
damage_kind: Slashing,
damage_effect: Some(Buff((
kind: Bleeding,
dur_secs: 10.0,
strength: DamageFraction(0.1),
chance: 0.1,
))),
recover_duration: 0.6,
movement: (
swing: Some(Forward(2.0)),
),
ori_modifier: 0.7,
),
(
stage: 2,
base_damage: 16.0,
damage_increase: 0,
base_poise_damage: 0,
poise_damage_increase: 0,
knockback: 5.0,
range: 3.5,
angle: 30.0,
base_buildup_duration: 0.8,
base_swing_duration: 0.1,
melee_constructor: (
kind: Slash(
damage: 16,
poise: 0,
knockback: 5,
energy_regen: 0,
),
range: 3.5,
angle: 30.0,
),
buildup_duration: 0.8,
swing_duration: 0.1,
hit_timing: 0.5,
base_recover_duration: 0.6,
forward_movement: 1.5,
damage_kind: Slashing,
damage_effect: Some(Buff((
kind: Bleeding,
dur_secs: 10.0,
strength: DamageFraction(0.1),
chance: 0.1,
))),
recover_duration: 0.6,
movement: (
swing: Some(Forward(2.0)),
),
ori_modifier: 0.7,
),
(
stage: 3,
base_damage: 26.0,
damage_increase: 0,
base_poise_damage: 0,
poise_damage_increase: 0,
knockback: 10.0,
range: 3.5,
angle: 30.0,
base_buildup_duration: 0.375,
base_swing_duration: 0.1,
melee_constructor: (
kind: Slash(
damage: 26,
poise: 0,
knockback: 10,
energy_regen: 0,
),
range: 3.5,
angle: 30.0,
),
buildup_duration: 0.4,
swing_duration: 0.1,
hit_timing: 0.5,
base_recover_duration: 0.6,
forward_movement: 1.5,
damage_kind: Slashing,
damage_effect: Some(Buff((
kind: Bleeding,
dur_secs: 10.0,
strength: DamageFraction(0.1),
chance: 0.1,
))),
recover_duration: 0.6,
movement: (
swing: Some(Forward(1.5)),
),
ori_modifier: 0.7,
),
],
initial_energy_gain: 0,
max_energy_gain: 0,
energy_increase: 0,
speed_increase: 0.0,
max_speed_increase: 0.0,
scales_from_combo: 0,
ori_modifier: 0.7,
)
energy_cost_per_strike: 0,
auto_progress: true,
)

View File

@ -1,19 +0,0 @@
BasicBeam(
buildup_duration: 0.8,
recover_duration: 0.5,
beam_duration: 0.5,
damage: 10.0,
tick_rate: 3.0,
range: 15.0,
max_angle: 22.5,
damage_effect: Some(Buff((
kind: Burning,
dur_secs: 10.0,
strength: DamageFraction(0.5),
chance: 0.25,
))),
energy_regen: 0,
energy_drain: 0,
ori_rate: 0.3,
specifier: Bubbles,
)

View File

@ -0,0 +1,17 @@
BasicRanged(
energy_cost: 0,
buildup_duration: 0.5,
recover_duration: 1.5,
projectile: InkBomb(
damage: 32.0,
radius: 5.0,
energy_regen: 5.0,
min_falloff: 0.1,
),
projectile_body: Object(SpitPoison),
projectile_light: None,
projectile_speed: 100.0,
num_projectiles: 1,
projectile_spread: 0.0,
move_efficiency: 0.3,
)

View File

@ -0,0 +1,25 @@
Shockwave(
energy_cost: 0,
buildup_duration: 0.3,
swing_duration: 0.3,
recover_duration: 2.0,
damage: 20.0,
poise_damage: 10,
knockback: (strength: 18.0, direction: Away),
shockwave_angle: 360.0,
shockwave_vertical_angle: 90.0,
shockwave_speed: 15.0,
shockwave_duration: 2.0,
requires_ground: true,
move_efficiency: 0.0,
damage_kind: Crushing,
specifier: Ink,
ori_rate: 1.0,
damage_effect: Some(Buff((
kind: Wet,
dur_secs: 8.0,
strength: Value(0.3),
chance: 1.0,
))),
)

View File

@ -0,0 +1,19 @@
BasicBeam(
buildup_duration: 0.3,
recover_duration: 1.5,
beam_duration: 2.0,
damage: 22.5,
tick_rate: 3.0,
range: 22.0,
max_angle: 22.5,
damage_effect: Some(Buff((
kind: Wet,
dur_secs: 8.0,
strength: Value(1.5),
chance: 1.0,
))),
energy_regen: 2,
energy_drain: 0,
ori_rate: 0.5,
specifier: Ink,
)

View File

@ -1,20 +0,0 @@
BasicRanged(
energy_cost: 0,
buildup_duration: 1.0,
recover_duration: 0.7,
projectile: SeaBomb(
damage: 20.0,
radius: 5.0,
energy_regen: 5.0,
min_falloff: 0.5,
),
projectile_body: Object(BoltFire),
/*projectile_light: Some(LightEmitter {
col: (1.0, 0.75, 0.11).into(),
..Default::default()
}),*/
projectile_speed: 60.0,
num_projectiles: 1,
projectile_spread: 0.0,
move_efficiency: 0.3,
)

View File

@ -1,18 +0,0 @@
Shockwave(
energy_cost: 60.0,
buildup_duration: 1.4,
swing_duration: 0.1,
recover_duration: 0.4,
damage: 40.0,
poise_damage: 0,
knockback: ( strength: 25.0, direction: Away),
shockwave_angle: 360.0,
shockwave_vertical_angle: 90.0,
shockwave_speed: 20.0,
shockwave_duration: 0.5,
requires_ground: false,
move_efficiency: 0.1,
damage_kind: Energy,
specifier: Water,
ori_rate: 1.0,
)

View File

@ -1,77 +1,66 @@
ComboMelee(
stage_data: [
ComboMelee2(
strikes: [
(
stage: 1,
base_damage: 20.0,
damage_increase: 0,
base_poise_damage: 0,
poise_damage_increase: 0,
knockback: 5.0,
range: 4.5,
angle: 30.0,
base_buildup_duration: 0.8,
base_swing_duration: 0.1,
melee_constructor: (
kind: Slash(
damage: 20,
poise: 0,
knockback: 5,
energy_regen: 0,
),
range: 4.5,
angle: 30.0,
),
buildup_duration: 0.8,
swing_duration: 0.1,
hit_timing: 0.5,
base_recover_duration: 0.6,
forward_movement: 2.0,
damage_kind: Slashing,
damage_effect: Some(Buff((
kind: Bleeding,
dur_secs: 10.0,
strength: DamageFraction(0.1),
chance: 0.1,
))),
recover_duration: 0.6,
movement: (
swing: Some(Forward(2.0)),
),
ori_modifier: 0.7,
),
(
stage: 2,
base_damage: 16.0,
damage_increase: 0,
base_poise_damage: 0,
poise_damage_increase: 0,
knockback: 5.0,
range: 3.5,
angle: 30.0,
base_buildup_duration: 0.8,
base_swing_duration: 0.1,
melee_constructor: (
kind: Slash(
damage: 16,
poise: 0,
knockback: 5,
energy_regen: 0,
),
range: 3.5,
angle: 30.0,
),
buildup_duration: 0.8,
swing_duration: 0.1,
hit_timing: 0.5,
base_recover_duration: 0.6,
forward_movement: 1.5,
damage_kind: Slashing,
damage_effect: Some(Buff((
kind: Bleeding,
dur_secs: 10.0,
strength: DamageFraction(0.1),
chance: 0.1,
))),
recover_duration: 0.6,
movement: (
swing: Some(Forward(2.0)),
),
ori_modifier: 0.7,
),
(
stage: 3,
base_damage: 26.0,
damage_increase: 0,
base_poise_damage: 0,
poise_damage_increase: 0,
knockback: 10.0,
range: 3.5,
angle: 30.0,
base_buildup_duration: 0.375,
base_swing_duration: 0.1,
melee_constructor: (
kind: Slash(
damage: 26,
poise: 0,
knockback: 10,
energy_regen: 0,
),
range: 3.5,
angle: 30.0,
),
buildup_duration: 0.4,
swing_duration: 0.1,
hit_timing: 0.5,
base_recover_duration: 0.6,
forward_movement: 1.5,
damage_kind: Slashing,
damage_effect: Some(Buff((
kind: Bleeding,
dur_secs: 10.0,
strength: DamageFraction(0.1),
chance: 0.1,
))),
recover_duration: 0.6,
movement: (
swing: Some(Forward(1.5)),
),
ori_modifier: 0.7,
),
],
initial_energy_gain: 0,
max_energy_gain: 0,
energy_increase: 0,
speed_increase: 0.0,
max_speed_increase: 0.0,
scales_from_combo: 0,
ori_modifier: 0.7,
)
energy_cost_per_strike: 0,
auto_progress: true,
)

View File

@ -1,20 +0,0 @@
BasicRanged(
energy_cost: 0,
buildup_duration: 1.0,
recover_duration: 0.7,
projectile: Fireball(
damage: 20.0,
radius: 5.0,
energy_regen: 5.0,
min_falloff: 0.5,
),
projectile_body: Object(BoltFire),
/*projectile_light: Some(LightEmitter {
col: (1.0, 0.75, 0.11).into(),
..Default::default()
}),*/
projectile_speed: 60.0,
num_projectiles: 1,
projectile_spread: 0.0,
move_efficiency: 0.3,
)

View File

@ -1,18 +0,0 @@
Shockwave(
energy_cost: 60.0,
buildup_duration: 1.4,
swing_duration: 0.1,
recover_duration: 0.4,
damage: 40.0,
poise_damage: 0,
knockback: ( strength: 25.0, direction: Away),
shockwave_angle: 360.0,
shockwave_vertical_angle: 90.0,
shockwave_speed: 20.0,
shockwave_duration: 0.5,
requires_ground: false,
move_efficiency: 0.1,
damage_kind: Energy,
specifier: Fire,
ori_rate: 1.0,
)

View File

@ -1,19 +0,0 @@
BasicBeam(
buildup_duration: 0.8,
recover_duration: 0.5,
beam_duration: 0.5,
damage: 10.0,
tick_rate: 3.0,
range: 15.0,
max_angle: 22.5,
damage_effect: Some(Buff((
kind: Burning,
dur_secs: 10.0,
strength: DamageFraction(0.5),
chance: 0.25,
))),
energy_regen: 0,
energy_drain: 0,
ori_rate: 0.3,
specifier: Flamethrower,
)

View File

@ -0,0 +1,17 @@
BasicRanged(
energy_cost: 0,
buildup_duration: 0.5,
recover_duration: 1.5,
projectile: Poisonball(
damage: 32.0,
radius: 5.0,
energy_regen: 5.0,
min_falloff: 0.1,
),
projectile_body: Object(SpitPoison),
projectile_light: None,
projectile_speed: 100.0,
num_projectiles: 1,
projectile_spread: 0.0,
move_efficiency: 0.3,
)

View File

@ -0,0 +1,25 @@
Shockwave(
energy_cost: 0,
buildup_duration: 0.3,
swing_duration: 0.3,
recover_duration: 2.0,
damage: 20.0,
poise_damage: 10,
knockback: (strength: 18.0, direction: Away),
shockwave_angle: 360.0,
shockwave_vertical_angle: 90.0,
shockwave_speed: 15.0,
shockwave_duration: 2.0,
requires_ground: true,
move_efficiency: 0.0,
damage_kind: Crushing,
specifier: Poison,
ori_rate: 1.0,
damage_effect: Some(Buff((
kind: Poisoned,
dur_secs: 8.0,
strength: DamageFraction(0.3),
chance: 1.0,
))),
)

View File

@ -0,0 +1,19 @@
BasicBeam(
buildup_duration: 0.3,
recover_duration: 1.5,
beam_duration: 2.0,
damage: 22.5,
tick_rate: 3.0,
range: 22.0,
max_angle: 22.5,
damage_effect: Some(Buff((
kind: Poisoned,
dur_secs: 3.0,
strength: DamageFraction(0.5),
chance: 1.0,
))),
energy_regen: 2,
energy_drain: 0,
ori_rate: 0.5,
specifier: Poison,
)

View File

@ -1,77 +1,66 @@
ComboMelee(
stage_data: [
ComboMelee2(
strikes: [
(
stage: 1,
base_damage: 20.0,
damage_increase: 0,
base_poise_damage: 0,
poise_damage_increase: 0,
knockback: 5.0,
range: 4.5,
angle: 30.0,
base_buildup_duration: 0.8,
base_swing_duration: 0.1,
melee_constructor: (
kind: Slash(
damage: 20,
poise: 0,
knockback: 5,
energy_regen: 0,
),
range: 4.5,
angle: 30.0,
),
buildup_duration: 0.8,
swing_duration: 0.1,
hit_timing: 0.5,
base_recover_duration: 0.6,
forward_movement: 2.0,
damage_kind: Slashing,
damage_effect: Some(Buff((
kind: Bleeding,
dur_secs: 10.0,
strength: DamageFraction(0.1),
chance: 0.1,
))),
recover_duration: 0.6,
movement: (
swing: Some(Forward(2.0)),
),
ori_modifier: 0.7,
),
(
stage: 2,
base_damage: 16.0,
damage_increase: 0,
base_poise_damage: 0,
poise_damage_increase: 0,
knockback: 5.0,
range: 3.5,
angle: 30.0,
base_buildup_duration: 0.8,
base_swing_duration: 0.1,
melee_constructor: (
kind: Slash(
damage: 16,
poise: 0,
knockback: 5,
energy_regen: 0,
),
range: 3.5,
angle: 30.0,
),
buildup_duration: 0.8,
swing_duration: 0.1,
hit_timing: 0.5,
base_recover_duration: 0.6,
forward_movement: 1.5,
damage_kind: Slashing,
damage_effect: Some(Buff((
kind: Bleeding,
dur_secs: 10.0,
strength: DamageFraction(0.1),
chance: 0.1,
))),
recover_duration: 0.6,
movement: (
swing: Some(Forward(2.0)),
),
ori_modifier: 0.7,
),
(
stage: 3,
base_damage: 26.0,
damage_increase: 0,
base_poise_damage: 0,
poise_damage_increase: 0,
knockback: 10.0,
range: 3.5,
angle: 30.0,
base_buildup_duration: 0.375,
base_swing_duration: 0.1,
melee_constructor: (
kind: Slash(
damage: 26,
poise: 0,
knockback: 10,
energy_regen: 0,
),
range: 3.5,
angle: 30.0,
),
buildup_duration: 0.4,
swing_duration: 0.1,
hit_timing: 0.5,
base_recover_duration: 0.6,
forward_movement: 1.5,
damage_kind: Slashing,
damage_effect: Some(Buff((
kind: Bleeding,
dur_secs: 10.0,
strength: DamageFraction(0.1),
chance: 0.1,
))),
recover_duration: 0.6,
movement: (
swing: Some(Forward(1.5)),
),
ori_modifier: 0.7,
),
],
initial_energy_gain: 0,
max_energy_gain: 0,
energy_increase: 0,
speed_increase: 0.0,
max_speed_increase: 0.0,
scales_from_combo: 0,
ori_modifier: 0.7,
)
energy_cost_per_strike: 0,
auto_progress: true,
)

View File

@ -3,7 +3,7 @@
name: Automatic,
body: RandomWith("wyvern_cloud"),
alignment: Alignment(Enemy),
loot: LootTable("common.loot_tables.creature.bird_large.wyvern"),
loot: LootTable("common.loot_tables.creature.bird_large.cloudwyvern"),
inventory: (
loadout: FromBody,
),

View File

@ -3,7 +3,7 @@
name: Automatic,
body: RandomWith("wyvern_flame"),
alignment: Alignment(Enemy),
loot: LootTable("common.loot_tables.creature.bird_large.wyvern"),
loot: LootTable("common.loot_tables.creature.bird_large.flamewyvern"),
inventory: (
loadout: FromBody,
),

View File

@ -3,7 +3,7 @@
name: Automatic,
body: RandomWith("wyvern_frost"),
alignment: Alignment(Enemy),
loot: LootTable("common.loot_tables.creature.bird_large.wyvern"),
loot: LootTable("common.loot_tables.creature.bird_large.frostwyvern"),
inventory: (
loadout: FromBody,
),

View File

@ -3,7 +3,7 @@
name: Automatic,
body: RandomWith("wyvern_sea"),
alignment: Alignment(Enemy),
loot: LootTable("common.loot_tables.creature.bird_large.wyvern"),
loot: LootTable("common.loot_tables.creature.bird_large.seawyvern"),
inventory: (
loadout: FromBody,
),

View File

@ -3,7 +3,7 @@
name: Automatic,
body: RandomWith("wyvern_weald"),
alignment: Alignment(Enemy),
loot: LootTable("common.loot_tables.creature.bird_large.wyvern"),
loot: LootTable("common.loot_tables.creature.bird_large.wealdwyvern"),
inventory: (
loadout: FromBody,
),

View File

@ -0,0 +1,7 @@
[
(1.0, MultiDrop(Item("common.items.mineral.gem.topaz"), 1, 3)),
(5.0, MultiDrop(Item("common.items.mineral.gem.amethyst"), 1, 3)),
(5.0, MultiDrop(Item("common.items.crafting_ing.animal_misc.elegant_crest"), 1, 3)),
(5.0, MultiDrop(Item("common.items.crafting_ing.animal_misc.claw"), 1, 3)),
(5.0, MultiDrop(Item("common.items.crafting_ing.hide.dragon_scale"), 2, 6)),
]

View File

@ -0,0 +1,7 @@
[
(1.0, MultiDrop(Item("common.items.mineral.gem.topaz"), 1, 3)),
(5.0, MultiDrop(Item("common.items.mineral.gem.ruby"), 1, 3)),
(5.0, MultiDrop(Item("common.items.crafting_ing.animal_misc.large_horn"), 1, 3)),
(5.0, MultiDrop(Item("common.items.crafting_ing.animal_misc.sharp_fang"), 1, 3)),
(5.0, MultiDrop(Item("common.items.crafting_ing.hide.dragon_scale"), 2, 6)),
]

View File

@ -0,0 +1,7 @@
[
(1.0, MultiDrop(Item("common.items.mineral.gem.topaz"), 1, 3)),
(5.0, MultiDrop(Item("common.items.mineral.gem.diamond"), 1, 3)),
(5.0, MultiDrop(Item("common.items.crafting_ing.animal_misc.large_horn"), 1, 3)),
(5.0, MultiDrop(Item("common.items.crafting_ing.animal_misc.claw"), 1, 3)),
(5.0, MultiDrop(Item("common.items.crafting_ing.hide.dragon_scale"), 2, 6)),
]

View File

@ -0,0 +1,7 @@
[
(1.0, MultiDrop(Item("common.items.mineral.gem.topaz"), 1, 3)),
(5.0, MultiDrop(Item("common.items.mineral.gem.sapphire"), 1, 3)),
(5.0, MultiDrop(Item("common.items.crafting_ing.animal_misc.sharp_fang"), 1, 3)),
(5.0, MultiDrop(Item("common.items.crafting_ing.animal_misc.claw"), 1, 3)),
(5.0, MultiDrop(Item("common.items.crafting_ing.hide.dragon_scale"), 2, 6)),
]

View File

@ -0,0 +1,7 @@
[
(1.0, MultiDrop(Item("common.items.mineral.gem.topaz"), 1, 3)),
(5.0, MultiDrop(Item("common.items.mineral.gem.emerald"), 1, 3)),
(5.0, MultiDrop(Item("common.items.crafting_ing.animal_misc.elegant_crest"), 1, 3)),
(1.0, MultiDrop(Item("common.items.crafting_ing.animal_misc.large_horn"), 1, 3)),
(5.0, MultiDrop(Item("common.items.crafting_ing.hide.dragon_scale"), 2, 6)),
]

View File

@ -1,6 +0,0 @@
[
(1.0, MultiDrop(Item("common.items.food.meat.bird_large_raw"), 1, 2)),
(1.0, MultiDrop(Item("common.items.food.meat.beast_large_raw"), 2, 2)),
(2.0, MultiDrop(Item("common.items.crafting_ing.animal_misc.elegant_crest"), 1, 3)),
(1.0, MultiDrop(Item("common.items.crafting_ing.hide.scales"), 2, 6)),
]

View File

@ -1,6 +1,5 @@
[
(1.0, MultiDrop(Item("common.items.crafting_ing.cloth.sunsilk"), 1, 3)),
(1.0, MultiDrop(Item("common.items.crafting_ing.hide.dragon_scale"), 3, 8)),
(1.0, MultiDrop(Item("common.items.mineral.ingot.orichalcum"), 1, 3)),
(1.0, MultiDrop(Item("common.items.log.eldwood"), 2, 6)),
]

View File

@ -8,6 +8,5 @@
(1.0, LootTable("common.loot_tables.weapons.legendary_melee")),
// Crafting material
// Allow for DS and Eldwood to drop till entity droppers are implemented
(1.0, MultiDrop(Item("common.items.crafting_ing.hide.dragon_scale"), 3, 8)),
(1.0, MultiDrop(Item("common.items.log.eldwood"), 2, 6)),
]

View File

@ -13,6 +13,5 @@
// Crafting material
// Allow for DS and Eldwood to drop till entity droppers are implemented
(1.0, Item("common.items.crafting_ing.mindflayer_bag_damaged")),
(1.0, MultiDrop(Item("common.items.crafting_ing.hide.dragon_scale"), 3, 8)),
(1.0, MultiDrop(Item("common.items.log.eldwood"), 2, 6)),
]

View File

@ -1430,12 +1430,18 @@
threshold: 1.25,
subtitle: "subtitle-attack-laser_beam",
),
Woosh: (
Whoosh: (
files: [
"voxygen.audio.sfx.abilities.woosh",
"voxygen.audio.sfx.abilities.whoosh",
],
threshold: 0.4,
),
Swoosh: (
files: [
"voxygen.audio.sfx.abilities.swoosh",
],
threshold: 1.3,
),
CyclopsCharge: (
files: [
"voxygen.audio.sfx.abilities.cyclops_charge",
@ -1518,6 +1524,13 @@
threshold: 1.0,
subtitle: "subtitle-utterance-bird-angry",
),
Utterance(Angry, Wyvern): (
files: [
"voxygen.audio.sfx.utterance.wyvern_angry",
],
threshold: 1.3,
subtitle: "subtitle-utterance-wyvern-angry",
),
Utterance(Angry, Adlet): (
files: [
"voxygen.audio.sfx.utterance.adlet_angry1",
@ -1719,6 +1732,13 @@
threshold: 1.0,
subtitle: "subtitle-utterance-asp-hurt",
),
Utterance(Hurt, Wyvern): (
files: [
"voxygen.audio.sfx.utterance.wyvern_hurt",
],
threshold: 1.2,
subtitle: "subtitle-utterance-wyvern-hurt",
),
Utterance(Angry, Wendigo): (
files: [
"voxygen.audio.sfx.utterance.wendigo_angry1",

BIN
assets/voxygen/audio/sfx/abilities/swoosh.ogg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
assets/voxygen/audio/sfx/utterance/wyvern_angry.ogg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
assets/voxygen/audio/sfx/utterance/wyvern_hurt.ogg (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -148,4 +148,6 @@ subtitle-utterance-asp-hurt = Asp hurting
subtitle-utterance-wendigo-angry = Wendigo screaming
subtitle-utterance-wendigo-calm = Wendigo mumbling
subtitle-utterance-wolf-angry = Wolf growling
subtitle-utterance-wolf-hurt = Wolf whining
subtitle-utterance-wolf-hurt = Wolf whining
subtitle-utterance-wyvern-angry = Wyvern roaring
subtitle-utterance-wyvern-hurt = Wyvern hurting

View File

@ -82,6 +82,7 @@ const int POTION_SICKNESS = 41;
const int GIGA_SNOW = 42;
const int CYCLOPS_CHARGE = 43;
const int PORTAL_FIZZ = 45;
const int INK = 46;
// meters per second squared (acceleration)
const float earth_gravity = 9.807;
@ -691,6 +692,17 @@ void main() {
spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3 + lifetime * 5)
);
break;
case INK:
f_reflect = 0.0; // Magic water doesn't reflect light, it emits it
float black_color = 0.3 + 0.2 * rand3 + 0.3 * max(floor(rand4 + 0.3), 0.0);
float ink_size = 8.0 * (1 - slow_start(0.1)) * slow_end(0.15);
attr = Attr(
(inst_dir * slow_end(1.5)) + vec3(rand0, rand1, rand2) * (percent() + 2) * 0.1,
vec3(ink_size),
vec4(0.5 * black_color, 0.75 * black_color, black_color, 1),
spin_in_axis(vec3(rand6, rand7, rand8), percent() * 10 + 3 * rand9)
);
break;
default:
attr = Attr(
linear_motion(

View File

@ -939,6 +939,26 @@
central: ("armor.empty"),
)
),
LightningBolt: (
bone0: (
offset: (-4.5, -80.0, -3.0),
central: ("weapon.projectile.lightning_bolt"),
),
bone1: (
offset: (0.0, 0.0, 0.0),
central: ("armor.empty"),
)
),
SpearIcicle: (
bone0: (
offset: (-2.5, -30.0, -2.5),
central: ("weapon.projectile.icicle-spear"),
),
bone1: (
offset: (0.0, 0.0, 0.0),
central: ("armor.empty"),
)
),
AdletSpear: (
bone0: (
offset: (5.0, -22.0, -2.0),

BIN
assets/voxygen/voxel/weapon/projectile/icicle-spear.vox (Stored with Git LFS) Normal file

Binary file not shown.

BIN
assets/voxygen/voxel/weapon/projectile/lightning_bolt.vox (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -354,7 +354,7 @@ impl<'a> From<&'a Body> for Psyche {
bird_medium::Species::Puffin => 0.8,
bird_medium::Species::Toucan => 0.4,
},
Body::BirdLarge(_) => 0.1,
Body::BirdLarge(_) => 0.0,
Body::FishSmall(_) => 1.0,
Body::FishMedium(_) => 0.75,
Body::BipedLarge(_) => 0.0,
@ -380,7 +380,10 @@ impl<'a> From<&'a Body> for Psyche {
arthropod::Species::Emberfly => 0.1,
},
},
sight_dist: 40.0,
sight_dist: match body {
Body::BirdLarge(_) => 80.0,
_ => 40.0,
},
listen_dist: 30.0,
aggro_dist: match body {
Body::Humanoid(_) => Some(20.0),

View File

@ -55,4 +55,7 @@ pub enum FrontendSpecifier {
Steam,
Frost,
WebStrand,
Poison,
Ink,
Lightning,
}

View File

@ -108,6 +108,8 @@ make_case_elim!(
AdletTrap = 93,
Flamethrower = 94,
Mine = 95,
LightningBolt = 96,
SpearIcicle = 97,
}
);
@ -118,7 +120,7 @@ impl Body {
}
}
pub const ALL_OBJECTS: [Body; 96] = [
pub const ALL_OBJECTS: [Body; 98] = [
Body::Arrow,
Body::Bomb,
Body::Scarecrow,
@ -215,6 +217,8 @@ pub const ALL_OBJECTS: [Body; 96] = [
Body::AdletTrap,
Body::Flamethrower,
Body::Mine,
Body::LightningBolt,
Body::SpearIcicle,
];
impl From<Body> for super::Body {
@ -320,6 +324,8 @@ impl Body {
Body::AdletTrap => "adlet_trap",
Body::Flamethrower => "flamethrower",
Body::Mine => "mine",
Body::LightningBolt => "lightning_bolt",
Body::SpearIcicle => "spear_icicle",
}
}
@ -372,11 +378,8 @@ impl Body {
Body::BedBlue => 50.0,
Body::Bedroll => 3.0,
Body::Bench => 100.0,
Body::BoltFire
| Body::BoltFireBig
| Body::BoltNature
| Body::BoltIcicle
| Body::SpitPoison => 1.0,
Body::BoltFire | Body::BoltFireBig | Body::BoltNature | Body::BoltIcicle => 1.0,
Body::SpitPoison => 100.0,
Body::Bomb | Body::DagonBomb => {
0.5 * IRON_DENSITY * std::f32::consts::PI / 6.0 * self.dimensions().x.powi(3)
},
@ -446,6 +449,7 @@ impl Body {
Body::AdletSpear => 1.5,
Body::AdletTrap => 10.0,
Body::Mine => 100.0,
Body::LightningBolt | Body::SpearIcicle => 20000.0,
};
Mass(m)
@ -477,6 +481,7 @@ impl Body {
Body::IceBomb => Vec3::broadcast(2.5),
Body::LaserBeam => Vec3::new(8.0, 8.0, 8.0),
Body::Mine => Vec3::new(0.8, 0.8, 0.5),
Body::LightningBolt | Body::SpearIcicle => Vec3::new(1.0, 1.0, 1.0),
// FIXME: this *must* be exhaustive match
_ => Vec3::broadcast(0.5),
}

View File

@ -91,12 +91,7 @@ pub enum ProjectileConstructor {
knockback: f32,
min_falloff: f32,
},
SeaBomb {
damage: f32,
radius: f32,
min_falloff: f32,
},
WindBomb {
InkBomb {
damage: f32,
radius: f32,
min_falloff: f32,
@ -527,7 +522,7 @@ impl ProjectileConstructor {
is_point: true,
}
},
SeaBomb {
InkBomb {
damage,
radius,
min_falloff,
@ -541,12 +536,27 @@ impl ProjectileConstructor {
Some(GroupTarget::OutOfGroup),
instance,
);
let buff = AttackEffect::new(
Some(GroupTarget::OutOfGroup),
CombatEffect::Buff(CombatBuff {
kind: BuffKind::Wet,
dur_secs: 8.0,
strength: CombatBuffStrength::Value(0.5),
chance: 1.0,
})
.adjusted_by_stats(tool_stats),
)
.with_requirement(CombatRequirement::AnyDamage);
let attack = Attack::default()
.with_damage(damage)
.with_crit(crit_chance, crit_mult)
.with_effect(buff)
.with_combo_increment();
let explosion = Explosion {
effects: vec![RadiusEffect::Attack(attack)],
effects: vec![
RadiusEffect::Attack(attack),
RadiusEffect::TerrainDestruction(18.0, Rgb::new(4.0, 7.0, 32.0)),
],
radius,
reagent: Some(Reagent::Blue),
min_falloff,
@ -561,40 +571,6 @@ impl ProjectileConstructor {
is_point: true,
}
},
WindBomb {
damage,
radius,
min_falloff,
} => {
let damage = AttackDamage::new(
Damage {
source: DamageSource::Explosion,
kind: DamageKind::Energy,
value: damage,
},
Some(GroupTarget::OutOfGroup),
instance,
);
let attack = Attack::default()
.with_damage(damage)
.with_crit(crit_chance, crit_mult)
.with_combo_increment();
let explosion = Explosion {
effects: vec![RadiusEffect::Attack(attack)],
radius,
reagent: Some(Reagent::White),
min_falloff,
};
Projectile {
hit_solid: vec![Effect::Explode(explosion.clone()), Effect::Vanish],
hit_entity: vec![Effect::Explode(explosion), Effect::Vanish],
time_left: Duration::from_secs(10),
owner,
ignore_group: true,
is_sticky: true,
is_point: true,
}
},
Snowball {
damage,
radius,
@ -982,15 +958,7 @@ impl ProjectileConstructor {
*damage *= power;
*radius *= range;
},
SeaBomb {
ref mut damage,
ref mut radius,
..
} => {
*damage *= power;
*radius *= range;
},
WindBomb {
InkBomb {
ref mut damage,
ref mut radius,
..
@ -1068,8 +1036,7 @@ impl ProjectileConstructor {
Snowball { .. } => true,
ExplodingPumpkin { .. } => true,
DagonBomb { .. } => true,
SeaBomb { .. } => true,
WindBomb { .. } => true,
InkBomb { .. } => true,
IceBomb { .. } => true,
LaserBeam { .. } => true,
Trap { .. } => false,

View File

@ -49,6 +49,10 @@ pub enum FrontendSpecifier {
Ground,
Fire,
Water,
Ice,
IceSpikes,
Steam,
Poison,
Ink,
Lightning,
}

View File

@ -128,7 +128,10 @@ pub enum Outcome {
FailedSpriteUnlock {
pos: Vec3<i32>,
},
Woosh {
Whoosh {
pos: Vec3<f32>,
},
Swoosh {
pos: Vec3<f32>,
},
FireShockwave {
@ -152,7 +155,8 @@ impl Outcome {
| Outcome::PoiseChange { pos, .. }
| Outcome::GroundSlam { pos }
| Outcome::FlashFreeze { pos }
| Outcome::Woosh { pos }
| Outcome::Whoosh { pos }
| Outcome::Swoosh { pos }
| Outcome::IceSpikes { pos }
| Outcome::Steam { pos }
| Outcome::FireShockwave { pos }

View File

@ -75,7 +75,7 @@ impl CharacterBehavior for Data {
});
if let Some(FrontendSpecifier::ElderLeap) = self.static_data.specifier {
// Send local event used for frontend shenanigans
output_events.emit_local(LocalEvent::CreateOutcome(Outcome::Woosh {
output_events.emit_local(LocalEvent::CreateOutcome(Outcome::Whoosh {
pos: data.pos.0 + *data.ori.look_dir() * (data.body.max_radius()),
}));
}

View File

@ -173,7 +173,11 @@ impl CharacterBehavior for Data {
},
));
},
_ => {},
_ => {
output_events.emit_local(LocalEvent::CreateOutcome(Outcome::Swoosh {
pos: data.pos.0 + *data.ori.look_dir() * (data.body.max_radius()),
}));
},
}
} else {
// Transitions to recover

View File

@ -29,7 +29,7 @@ use std::{
/// Note that this number does *not* need incrementing on every change: most
/// field removals/additions are fine. This number should only be incremented
/// when we wish to perform a *hard purge* of rtsim data.
pub const CURRENT_VERSION: u32 = 3;
pub const CURRENT_VERSION: u32 = 4;
#[derive(Clone, Serialize, Deserialize)]
pub struct Data {

View File

@ -218,6 +218,11 @@ impl Data {
comp::body::bird_large::Species::Phoenix,
comp::body::bird_large::Species::Cockatrice,
comp::body::bird_large::Species::Roc,
comp::body::bird_large::Species::FlameWyvern,
comp::body::bird_large::Species::CloudWyvern,
comp::body::bird_large::Species::FrostWyvern,
comp::body::bird_large::Species::SeaWyvern,
comp::body::bird_large::Species::WealdWyvern,
]
.choose(&mut rng)
.unwrap();

View File

@ -1147,45 +1147,74 @@ fn humanoid() -> impl Action<DefaultState> {
}
fn bird_large() -> impl Action<DefaultState> {
choose(|ctx, _| {
let data = ctx.state.data();
if let Some(home) = ctx.npc.home {
let is_home = ctx.npc.current_site.map_or(false, |site| home == site);
let goto = |wpos| {
casual(goto_2d_flying(
wpos,
1.0,
20.0,
32.0,
22.0,
ctx.npc.body.flying_height(),
))
};
if is_home {
if let Some((_, site)) = data
.sites
.iter()
.filter(|(id, site)| {
*id != home
&& site.world_site.map_or(false, |site| {
matches!(ctx.index.sites.get(site).kind, SiteKind::Dungeon(_))
})
})
.choose(&mut ctx.rng)
{
goto(site.wpos.as_::<f32>())
} else {
casual(idle())
}
} else if let Some(site) = data.sites.get(home) {
goto(site.wpos.as_::<f32>())
} else {
casual(idle())
}
now(|ctx, bearing: &mut Vec2<f32>| {
*bearing = bearing
.map(|e| e + ctx.rng.gen_range(-0.1..0.1))
.try_normalized()
.unwrap_or_default();
let bearing_dist = 24.0;
let mut pos = ctx.npc.wpos.xy() + *bearing * bearing_dist;
let is_deep_water = ctx
.world
.sim()
.get_interpolated(pos.as_(), |c| c.alt - c.water_alt)
.unwrap_or(f32::NEG_INFINITY)
< -120.0
&& ctx
.world
.sim()
.get(pos.as_().wpos_to_cpos())
.map_or(false, |c| c.river.is_ocean() || c.river.is_lake());
// when high tree_density fly high, otherwise fly low-mid
let npc_pos = ctx.npc.wpos.xy();
let tree_density = ctx
.world
.sim()
.get_interpolated(npc_pos.as_(), |c| c.tree_density)
.unwrap_or(1.0);
let height_factor = if tree_density > 0.1 {
2.0
} else {
casual(idle())
ctx.rng.gen_range(0.1..0.5)
};
if !is_deep_water {
goto_2d_flying(
pos,
0.2,
bearing_dist,
8.0,
8.0,
ctx.npc.body.flying_height() * height_factor,
)
} else {
*bearing *= -1.0;
pos = ctx.npc.wpos.xy() + *bearing * 24.0;
goto_2d_flying(
pos,
0.2,
bearing_dist,
8.0,
8.0,
ctx.npc.body.flying_height() * height_factor,
)
}
// If we are too far away from our goal position we can stop since we aren't going to a specific place.
.stop_if(move |ctx: &mut NpcCtx| {
ctx.npc.wpos.xy().distance_squared(pos) > (bearing_dist + 5.0).powi(2)
})
// If goal position wasn't reached within 20 seconds we're probably stuck and need to find a new goal position.
.stop_if(timeout(10.0))
.debug({
let bearing = *bearing;
move || format!("Moving with a bearing of {:?}", bearing)
})
})
.repeat()
.with_state(Vec2::<f32>::zero())
.map(|_, _| ())
}
fn monster() -> impl Action<DefaultState> {

View File

@ -106,68 +106,6 @@ impl<'a> AgentData<'a> {
}
}
pub fn handle_wyvern_attack(
&self,
_agent: &mut Agent,
controller: &mut Controller,
attack_data: &AttackData,
tgt_data: &TargetData,
read_data: &ReadData,
_rng: &mut impl Rng,
) {
// Fly to target
let dir_to_target = ((tgt_data.pos.0 + Vec3::unit_z() * 1.5) - self.pos.0)
.try_normalized()
.unwrap_or_else(Vec3::zero);
let speed = 1.0;
controller.inputs.move_dir = dir_to_target.xy() * speed;
// Always fly! If the floor can't touch you, it can't hurt you...
controller.push_basic_input(InputKind::Fly);
// Flee from the ground! The internet told me it was lava!
// If on the ground, jump with every last ounce of energy, holding onto all that
// is dear in life and straining for the wide open skies.
if self.physics_state.on_ground.is_some() {
controller.push_basic_input(InputKind::Jump);
} else {
// Only fly down if close enough to target in the xy plane
// Otherwise fly towards the target bouncing around a 5 block altitude
let mut maintain_altitude = |altitude| {
if read_data
.terrain
.ray(self.pos.0, self.pos.0 - (Vec3::unit_z() * altitude))
.until(Block::is_solid)
.cast()
.1
.map_or(true, |b| b.is_some())
{
// Fly up
controller.inputs.move_z = 1.0;
} else {
// Fly down
controller.inputs.move_z = -1.0;
}
};
if (tgt_data.pos.0 - self.pos.0).xy().magnitude_squared() > (30.0_f32).powi(2) {
// If above 30 blocks, fly down and attack
maintain_altitude(30.0);
// Shoot bombs
controller.push_basic_input(InputKind::Primary);
} else {
maintain_altitude(2.0);
// Attack if in range
if attack_data.dist_sqrd < 6.0_f32.powi(2) && attack_data.angle < 150.0 {
controller.push_basic_input(InputKind::Ability(0));
} else if attack_data.dist_sqrd < 8.0_f32.powi(2) && attack_data.angle < 150.0 {
controller.push_basic_input(InputKind::Ability(1));
} else if attack_data.dist_sqrd < 12.0_f32.powi(2) && attack_data.angle < 150.0 {
controller.push_basic_input(InputKind::Secondary);
}
}
}
}
// Intended for any agent that has one attack, that attack is a melee attack,
// the agent is able to freely walk around, and the agent is trying to attack
// from behind its target
@ -3034,27 +2972,26 @@ impl<'a> AgentData<'a> {
attack_data: &AttackData,
tgt_data: &TargetData,
read_data: &ReadData,
rng: &mut impl Rng,
_rng: &mut impl Rng,
) {
enum ActionStateTimers {
AttackTimer = 0,
}
// Set fly to false
controller.push_cancel_input(InputKind::Fly);
if attack_data.dist_sqrd > 30.0_f32.powi(2) {
let small_chance = rng.gen_bool(0.05);
if small_chance
&& entities_have_line_of_sight(
self.pos,
self.body,
self.scale,
tgt_data.pos,
tgt_data.body,
tgt_data.scale,
read_data,
)
&& attack_data.angle < 15.0
if entities_have_line_of_sight(
self.pos,
self.body,
self.scale,
tgt_data.pos,
tgt_data.body,
tgt_data.scale,
read_data,
) && attack_data.angle < 15.0
{
// Fireball
controller.push_basic_input(InputKind::Primary);
}
// If some target
if let Some((bearing, speed)) = agent.chaser.chase(
&*read_data.terrain,
self.pos.0,
@ -3065,23 +3002,14 @@ impl<'a> AgentData<'a> {
..self.traversal_config
},
) {
// Walk to target
controller.inputs.move_dir =
bearing.xy().try_normalized().unwrap_or_else(Vec2::zero) * speed;
// If less than 20 blocks higher than target
if (self.pos.0.z - tgt_data.pos.0.z) < 20.0 {
// Fly upward
controller.push_basic_input(InputKind::Fly);
controller.inputs.move_z = 1.0;
} else {
// Jump
self.jump_if(bearing.z > 1.5, controller);
controller.inputs.move_z = bearing.z;
}
}
}
// If higher than 2 blocks
else if !read_data
} else if !read_data
.terrain
.ray(self.pos.0, self.pos.0 - (Vec3::unit_z() * 2.0))
.until(Block::is_solid)
@ -3092,41 +3020,52 @@ impl<'a> AgentData<'a> {
// Do not increment the timer during this movement
// The next stage shouldn't trigger until the entity
// is on the ground
// Fly to target
controller.push_basic_input(InputKind::Fly);
let move_dir = tgt_data.pos.0 - self.pos.0;
controller.inputs.move_dir =
move_dir.xy().try_normalized().unwrap_or_else(Vec2::zero) * 2.0;
controller.inputs.move_z = move_dir.z - 0.5;
// If further than 4 blocks and random chance
if rng.gen_bool(0.05)
&& attack_data.dist_sqrd > (4.0 * attack_data.min_attack_dist).powi(2)
if attack_data.dist_sqrd > (4.0 * attack_data.min_attack_dist).powi(2)
&& attack_data.angle < 15.0
{
// Fireball
controller.push_basic_input(InputKind::Primary);
}
}
// If further than 4 blocks and random chance
else if rng.gen_bool(0.05)
&& attack_data.dist_sqrd > (4.0 * attack_data.min_attack_dist).powi(2)
} else if attack_data.dist_sqrd > (3.0 * attack_data.min_attack_dist).powi(2) {
self.path_toward_target(
agent,
controller,
tgt_data.pos.0,
read_data,
Path::Separate,
None,
);
} else if self.energy.current() > 60.0
&& agent.action_state.timers[ActionStateTimers::AttackTimer as usize] < 3.0
&& attack_data.angle < 15.0
{
// Fireball
controller.push_basic_input(InputKind::Primary);
}
// If random chance and less than 20 blocks higher than target and further than 4
// blocks
else if rng.gen_bool(0.5)
&& (self.pos.0.z - tgt_data.pos.0.z) < 15.0
&& attack_data.dist_sqrd > (4.0 * attack_data.min_attack_dist).powi(2)
// Shockwave
controller.push_basic_input(InputKind::Ability(0));
// Move towards the target slowly
self.path_toward_target(
agent,
controller,
tgt_data.pos.0,
read_data,
Path::Separate,
Some(0.5),
);
agent.action_state.timers[ActionStateTimers::AttackTimer as usize] += read_data.dt.0;
} else if agent.action_state.timers[ActionStateTimers::AttackTimer as usize] < 6.0
&& attack_data.angle < 90.0
&& attack_data.in_min_range()
{
controller.push_basic_input(InputKind::Fly);
controller.inputs.move_z = 1.0;
}
// If further than 2.5 blocks and random chance
else if attack_data.dist_sqrd > (2.5 * attack_data.min_attack_dist).powi(2) {
// Walk to target
// Triple strike
controller.push_basic_input(InputKind::Secondary);
agent.action_state.timers[ActionStateTimers::AttackTimer as usize] += read_data.dt.0;
} else {
// Reset timer
agent.action_state.timers[ActionStateTimers::AttackTimer as usize] = 0.0;
// Target is behind us or the timer needs to be reset. Chase target
self.path_toward_target(
agent,
controller,
@ -3136,15 +3075,113 @@ impl<'a> AgentData<'a> {
None,
);
}
// If energy higher than 600 and random chance
else if self.energy.current() > 60.0 && rng.gen_bool(0.4) {
// Shockwave
controller.push_basic_input(InputKind::Ability(0));
} else if attack_data.angle < 90.0 {
}
pub fn handle_wyvern_attack(
&self,
agent: &mut Agent,
controller: &mut Controller,
attack_data: &AttackData,
tgt_data: &TargetData,
read_data: &ReadData,
_rng: &mut impl Rng,
) {
enum ActionStateTimers {
AttackTimer = 0,
}
// Set fly to false
controller.push_cancel_input(InputKind::Fly);
if attack_data.dist_sqrd > 30.0_f32.powi(2) {
if entities_have_line_of_sight(
self.pos,
self.body,
self.scale,
tgt_data.pos,
tgt_data.body,
tgt_data.scale,
read_data,
) && attack_data.angle < 15.0
{
controller.push_basic_input(InputKind::Primary);
}
if let Some((bearing, speed)) = agent.chaser.chase(
&*read_data.terrain,
self.pos.0,
self.vel.0,
tgt_data.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;
if (self.pos.0.z - tgt_data.pos.0.z) < 35.0 {
controller.push_basic_input(InputKind::Fly);
controller.inputs.move_z = 1.0;
}
}
} else if !read_data
.terrain
.ray(self.pos.0, self.pos.0 - (Vec3::unit_z() * 2.0))
.until(Block::is_solid)
.cast()
.1
.map_or(true, |b| b.is_some())
{
// Do not increment the timer during this movement
// The next stage shouldn't trigger until the entity
// is on the ground
controller.push_basic_input(InputKind::Fly);
let move_dir = tgt_data.pos.0 - self.pos.0;
controller.inputs.move_dir =
move_dir.xy().try_normalized().unwrap_or_else(Vec2::zero) * 2.0;
controller.inputs.move_z = move_dir.z - 0.5;
if attack_data.dist_sqrd > (4.0 * attack_data.min_attack_dist).powi(2)
&& attack_data.angle < 15.0
{
controller.push_basic_input(InputKind::Primary);
}
} else if attack_data.dist_sqrd > (3.0 * attack_data.min_attack_dist).powi(2) {
self.path_toward_target(
agent,
controller,
tgt_data.pos.0,
read_data,
Path::Separate,
None,
);
} else if attack_data.angle < 15.0 {
if agent.action_state.timers[ActionStateTimers::AttackTimer as usize] < 5.0 {
// beam
controller.push_basic_input(InputKind::Ability(1));
} else if agent.action_state.timers[ActionStateTimers::AttackTimer as usize] < 9.0 {
// shockwave
controller.push_basic_input(InputKind::Ability(0));
} else {
agent.action_state.timers[ActionStateTimers::AttackTimer as usize] = 0.0;
}
// Move towards the target slowly
self.path_toward_target(
agent,
controller,
tgt_data.pos.0,
read_data,
Path::Separate,
Some(0.5),
);
agent.action_state.timers[ActionStateTimers::AttackTimer as usize] += read_data.dt.0;
} else if agent.action_state.timers[ActionStateTimers::AttackTimer as usize] < 9.0
&& attack_data.angle < 90.0
&& attack_data.in_min_range()
{
// Triple strike
controller.push_basic_input(InputKind::Secondary);
agent.action_state.timers[ActionStateTimers::AttackTimer as usize] += read_data.dt.0;
} else {
// Target is behind us. Turn around and chase target
// Reset timer
agent.action_state.timers[ActionStateTimers::AttackTimer as usize] = 0.0;
// Target is behind us or the timer needs to be reset. Chase target
self.path_toward_target(
agent,
controller,
@ -3201,9 +3238,6 @@ impl<'a> AgentData<'a> {
if (self.pos.0.z - tgt_data.pos.0.z) < 20.0 {
controller.push_basic_input(InputKind::Fly);
controller.inputs.move_z = 1.0;
} else {
self.jump_if(bearing.z > 1.5, controller);
controller.inputs.move_z = bearing.z;
}
}
} else if !read_data
@ -3311,22 +3345,7 @@ impl<'a> AgentData<'a> {
// Increase action timer
agent.action_state.timers[ActionStateTimers::TimerBirdLargeBasic as usize] +=
read_data.dt.0;
// If higher than 2 blocks
if !read_data
.terrain
.ray(self.pos.0, self.pos.0 - (Vec3::unit_z() * 2.0))
.until(Block::is_solid)
.cast()
.1
.map_or(true, |b| b.is_some())
{
// Fly to target and land
controller.push_basic_input(InputKind::Fly);
let move_dir = tgt_data.pos.0 - self.pos.0;
controller.inputs.move_dir =
move_dir.xy().try_normalized().unwrap_or_else(Vec2::zero) * 2.0;
controller.inputs.move_z = move_dir.z - 0.5;
} else if agent.action_state.timers[ActionStateTimers::TimerBirdLargeBasic as usize] > 8.0 {
if agent.action_state.timers[ActionStateTimers::TimerBirdLargeBasic as usize] > 8.0 {
// If action timer higher than 8, make bird summon tornadoes
controller.push_basic_input(InputKind::Secondary);
if matches!(self.char_state, CharacterState::BasicSummon(c) if matches!(c.stage_section, StageSection::Recover))

View File

@ -165,9 +165,19 @@ fn get_npc_entity_info(npc: &Npc, sites: &Sites, index: IndexRef) -> EntityInfo
comp::bird_large::Species::Phoenix => "common.entity.wild.peaceful.phoenix",
comp::bird_large::Species::Cockatrice => "common.entity.wild.aggressive.cockatrice",
comp::bird_large::Species::Roc => "common.entity.wild.aggressive.roc",
// Wildcard match used here as there is an array above
// which limits what species are used
_ => unimplemented!(),
comp::bird_large::Species::CloudWyvern => {
"common.entity.wild.aggressive.cloudwyvern"
},
comp::bird_large::Species::FlameWyvern => {
"common.entity.wild.aggressive.flamewyvern"
},
comp::bird_large::Species::FrostWyvern => {
"common.entity.wild.aggressive.frostwyvern"
},
comp::bird_large::Species::SeaWyvern => "common.entity.wild.aggressive.seawyvern",
comp::bird_large::Species::WealdWyvern => {
"common.entity.wild.aggressive.wealdwyvern"
},
},
Body::BipedLarge(body) => match body.species {
comp::biped_large::Species::Ogre => "common.entity.wild.aggressive.ogre",

View File

@ -0,0 +1,149 @@
use super::{
super::{vek::*, Animation},
BirdLargeSkeleton, SkeletonAttr,
};
use common::states::utils::StageSection;
pub struct ComboAnimation;
impl Animation for ComboAnimation {
type Dependency<'a> = (
Option<&'a str>,
Option<StageSection>,
usize,
f32,
f32,
Vec3<f32>,
Vec3<f32>,
bool,
);
type Skeleton = BirdLargeSkeleton;
#[cfg(feature = "use-dyn-lib")]
const UPDATE_FN: &'static [u8] = b"bird_large_combo\0";
#[cfg_attr(feature = "be-dyn-lib", export_name = "bird_large_combo")]
fn update_skeleton_inner(
skeleton: &Self::Skeleton,
(
_ability_id,
stage_section,
current_strike,
global_time,
timer,
orientation,
last_ori,
on_ground,
): Self::Dependency<'_>,
anim_time: f32,
rate: &mut f32,
s_a: &SkeletonAttr,
) -> Self::Skeleton {
*rate = 1.0;
let mut next = (*skeleton).clone();
let multi_strike_pullback = 1.0
- if matches!(stage_section, Some(StageSection::Recover)) {
anim_time.powi(4)
} else {
0.0
};
let (move1base, move2base, _move3) = match stage_section {
Some(StageSection::Buildup) => (anim_time.powf(0.25), 0.0, 0.0),
Some(StageSection::Action) => (1.0, anim_time, 0.0),
Some(StageSection::Recover) => (1.0, 1.0, anim_time.powf(4.0)),
_ => (0.0, 0.0, 0.0),
};
let wave_slow_cos = (anim_time * 4.5).cos();
let subtract = global_time - timer;
let check = subtract - subtract.trunc();
let mirror = (check - 0.5).signum();
let move1 = move1base * multi_strike_pullback;
let move2 = move2base * multi_strike_pullback;
let move1mirror = move1base * multi_strike_pullback * mirror;
let ori: Vec2<f32> = Vec2::from(orientation);
let last_ori = Vec2::from(last_ori);
let tilt = if vek::Vec2::new(ori, last_ori)
.map(|o| o.magnitude_squared())
.map(|m| m > 0.001 && m.is_finite())
.reduce_and()
&& ori.angle_between(last_ori).is_finite()
{
ori.angle_between(last_ori).min(0.2)
* last_ori.determine_side(Vec2::zero(), ori).signum()
} else {
0.0
} * 1.3;
for strike in 0..=current_strike {
match strike {
0..=2 => {
next.chest.position = Vec3::new(
0.0,
s_a.chest.0,
s_a.chest.1 + wave_slow_cos * 0.06 + move2 * -6.0,
);
next.chest.orientation = Quaternion::rotation_x(move1 * 0.5 - move2 * 0.8);
next.neck.position = Vec3::new(0.0, s_a.neck.0, s_a.neck.1);
next.neck.orientation = Quaternion::rotation_x(move1 * 0.5 - move2 * 0.4)
* Quaternion::rotation_z(move1 * tilt * 1.5)
* Quaternion::rotation_y(move1mirror * 0.3);
next.head.position = Vec3::new(0.0, s_a.head.0, s_a.head.1);
next.head.orientation = Quaternion::rotation_x(move1 * -0.2 - move2 * 0.2)
* Quaternion::rotation_y(move1mirror * 0.5);
next.beak.position = Vec3::new(0.0, s_a.beak.0, s_a.beak.1);
next.beak.orientation =
Quaternion::rotation_x(wave_slow_cos * -0.02 + move1 * -0.5 + move2 * 0.5);
if on_ground {
next.tail_front.position =
Vec3::new(0.0, s_a.tail_front.0, s_a.tail_front.1);
next.tail_front.orientation = Quaternion::rotation_x(-move1 * 0.2);
next.tail_rear.position = Vec3::new(0.0, s_a.tail_rear.0, s_a.tail_rear.1);
next.tail_rear.orientation = Quaternion::rotation_x(0.0);
next.wing_in_l.position =
Vec3::new(-s_a.wing_in.0, s_a.wing_in.1, s_a.wing_in.2);
next.wing_in_r.position =
Vec3::new(s_a.wing_in.0, s_a.wing_in.1, s_a.wing_in.2);
next.wing_in_l.orientation = Quaternion::rotation_y(
-1.0 + wave_slow_cos * 0.06 + move1 * 1.0 + move2 * 0.5,
) * Quaternion::rotation_z(0.2);
next.wing_in_r.orientation = Quaternion::rotation_y(
1.0 - wave_slow_cos * 0.06 + move1 * -1.0 + move2 * -0.5,
) * Quaternion::rotation_z(-0.2);
next.wing_mid_l.position =
Vec3::new(-s_a.wing_mid.0, s_a.wing_mid.1, s_a.wing_mid.2);
next.wing_mid_r.position =
Vec3::new(s_a.wing_mid.0, s_a.wing_mid.1, s_a.wing_mid.2);
next.wing_mid_l.orientation = Quaternion::rotation_y(-0.1 + move1 * -0.5)
* Quaternion::rotation_z(0.7 + move1 * -0.7);
next.wing_mid_r.orientation = Quaternion::rotation_y(0.1 + move1 * 0.5)
* Quaternion::rotation_z(-0.7 + move1 * 0.7);
next.wing_out_l.position =
Vec3::new(-s_a.wing_out.0, s_a.wing_out.1, s_a.wing_out.2);
next.wing_out_r.position =
Vec3::new(s_a.wing_out.0, s_a.wing_out.1, s_a.wing_out.2);
next.wing_out_l.orientation = Quaternion::rotation_y(-0.2 + move1 * -0.3)
* Quaternion::rotation_z(0.2);
next.wing_out_r.orientation = Quaternion::rotation_y(0.2 + move1 * 0.3)
* Quaternion::rotation_z(-0.2);
} else {
}
},
_ => {},
}
}
next
}
}

View File

@ -1,5 +1,6 @@
pub mod alpha;
pub mod breathe;
pub mod combomelee;
pub mod dash;
pub mod feed;
pub mod fly;
@ -13,9 +14,10 @@ pub mod swim;
// Reexports
pub use self::{
alpha::AlphaAnimation, breathe::BreatheAnimation, dash::DashAnimation, feed::FeedAnimation,
fly::FlyAnimation, idle::IdleAnimation, run::RunAnimation, shockwave::ShockwaveAnimation,
shoot::ShootAnimation, stunned::StunnedAnimation, summon::SummonAnimation, swim::SwimAnimation,
alpha::AlphaAnimation, breathe::BreatheAnimation, combomelee::ComboAnimation,
dash::DashAnimation, feed::FeedAnimation, fly::FlyAnimation, idle::IdleAnimation,
run::RunAnimation, shockwave::ShockwaveAnimation, shoot::ShootAnimation,
stunned::StunnedAnimation, summon::SummonAnimation, swim::SwimAnimation,
};
use super::{make_bone, vek::*, FigureBoneData, Offsets, Skeleton};

View File

@ -93,7 +93,7 @@ use client::Client;
use common::{
assets::{self, AssetExt, AssetHandle},
comp::{
beam, biped_large, biped_small, humanoid,
beam, biped_large, biped_small, bird_large, humanoid,
item::{AbilitySpec, ItemDefinitionId, ItemKind, ToolKind},
object,
poise::PoiseState,
@ -178,9 +178,10 @@ pub enum SfxEvent {
Yeet,
Klonk,
SmashKlonk,
Woosh,
FireShockwave,
DeepLaugh,
Whoosh,
Swoosh,
}
#[derive(Copy, Clone, Debug, PartialEq, Deserialize, Hash, Eq)]
@ -213,6 +214,7 @@ pub enum VoiceKind {
Fungome,
Truffler,
Wolf,
Wyvern,
}
fn body_to_voice(body: &Body) -> Option<VoiceKind> {
@ -261,7 +263,15 @@ fn body_to_voice(body: &Body) -> Option<VoiceKind> {
quadruped_medium::Species::Antelope => VoiceKind::Antelope,
_ => return None,
},
Body::BirdMedium(_) | Body::BirdLarge(_) => VoiceKind::Bird,
Body::BirdMedium(_) => VoiceKind::Bird,
Body::BirdLarge(body) => match body.species {
bird_large::Species::CloudWyvern
| bird_large::Species::FlameWyvern
| bird_large::Species::FrostWyvern
| bird_large::Species::SeaWyvern
| bird_large::Species::WealdWyvern => VoiceKind::Wyvern,
_ => VoiceKind::Bird,
},
Body::BipedSmall(body) => match body.species {
biped_small::Species::Adlet => VoiceKind::Adlet,
biped_small::Species::Mandragora => VoiceKind::Mandragora,
@ -510,12 +520,16 @@ impl SfxMgr {
Body::Object(
object::Body::BoltFire
| object::Body::BoltFireBig
| object::Body::BoltNature,
| object::Body::BoltNature
| object::Body::BoltIcicle
| object::Body::SpearIcicle
| object::Body::SpitPoison,
) => {
let sfx_trigger_item = triggers.get_key_value(&SfxEvent::FireShot);
audio.emit_sfx(sfx_trigger_item, *pos, None, underwater);
},
Body::Object(object::Body::LaserBeam) => {
Body::Object(object::Body::LaserBeam)
| Body::Object(object::Body::LightningBolt) => {
let sfx_trigger_item = triggers.get_key_value(&SfxEvent::LaserBeam);
audio.emit_sfx(sfx_trigger_item, *pos, None, underwater);
},
@ -589,6 +603,10 @@ impl SfxMgr {
Outcome::Beam { pos, specifier } => match specifier {
beam::FrontendSpecifier::LifestealBeam
| beam::FrontendSpecifier::Steam
| beam::FrontendSpecifier::Poison
| beam::FrontendSpecifier::Ink
| beam::FrontendSpecifier::Lightning
| beam::FrontendSpecifier::Frost
| beam::FrontendSpecifier::Bubbles => {
if thread_rng().gen_bool(0.5) {
let sfx_trigger_item = triggers.get_key_value(&SfxEvent::SceptreBeam);
@ -601,9 +619,7 @@ impl SfxMgr {
audio.emit_sfx(sfx_trigger_item, *pos, None, underwater);
}
},
beam::FrontendSpecifier::ClayGolem
| beam::FrontendSpecifier::Frost
| beam::FrontendSpecifier::WebStrand => {},
beam::FrontendSpecifier::ClayGolem | beam::FrontendSpecifier::WebStrand => {},
},
Outcome::SpriteUnlocked { pos } => {
// TODO: Dedicated sound effect!
@ -719,8 +735,17 @@ impl SfxMgr {
_ => {},
};
},
Outcome::Woosh { pos, .. } => {
let sfx_trigger_item = triggers.get_key_value(&SfxEvent::Woosh);
Outcome::Whoosh { pos, .. } => {
let sfx_trigger_item = triggers.get_key_value(&SfxEvent::Whoosh);
audio.emit_sfx(
sfx_trigger_item,
pos.map(|e| e + 0.5),
Some(3.0),
underwater,
);
},
Outcome::Swoosh { pos, .. } => {
let sfx_trigger_item = triggers.get_key_value(&SfxEvent::Swoosh);
audio.emit_sfx(
sfx_trigger_item,
pos.map(|e| e + 0.5),

View File

@ -97,6 +97,7 @@ pub enum ParticleMode {
CyclopsCharge = 43,
SnowStorm = 44,
PortalFizz = 45,
Ink = 46,
}
impl ParticleMode {

View File

@ -4944,38 +4944,36 @@ impl FigureMgr {
skeleton_attr,
)
},
CharacterState::ComboMelee(s) => {
let stage_index = (s.stage - 1) as usize;
let stage_time = s.timer.as_secs_f32();
let stage_progress =
if let Some(stage) = s.static_data.stage_data.get(stage_index) {
match s.stage_section {
StageSection::Buildup => {
stage_time / stage.base_buildup_duration.as_secs_f32()
},
StageSection::Action => {
stage_time / stage.base_swing_duration.as_secs_f32()
},
StageSection::Recover => {
stage_time / stage.base_recover_duration.as_secs_f32()
},
_ => 0.0,
}
} else {
0.0
};
CharacterState::ComboMelee2(s) => {
let timer = s.timer.as_secs_f32();
let current_strike = s.completed_strikes % s.static_data.strikes.len();
let strike_data = s.static_data.strikes[current_strike];
let progress = match s.stage_section {
StageSection::Buildup => {
timer / strike_data.buildup_duration.as_secs_f32()
},
StageSection::Action => {
timer / strike_data.swing_duration.as_secs_f32()
},
StageSection::Recover => {
timer / strike_data.recover_duration.as_secs_f32()
},
_ => 0.0,
};
anim::bird_large::AlphaAnimation::update_skeleton(
anim::bird_large::ComboAnimation::update_skeleton(
&target_base,
(
ability_id,
Some(s.stage_section),
current_strike,
time,
state.state_time,
ori * anim::vek::Vec3::<f32>::unit_y(),
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
physics.on_ground.is_some(),
),
stage_progress,
progress,
&mut state_animation_rate,
skeleton_attr,
)

View File

@ -397,7 +397,8 @@ impl ParticleMgr {
| Outcome::IceSpikes { .. }
| Outcome::IceCrack { .. }
| Outcome::Glider { .. }
| Outcome::Woosh { .. }
| Outcome::Whoosh { .. }
| Outcome::Swoosh { .. }
| Outcome::Steam { .. }
| Outcome::FireShockwave { .. }
| Outcome::LaserBeam { .. } => {},
@ -1071,6 +1072,56 @@ impl ParticleMgr {
},
);
},
beam::FrontendSpecifier::Poison => {
let mut rng = thread_rng();
let (from, to) = (Vec3::<f32>::unit_z(), *ori.look_dir());
let m = Mat3::<f32>::rotation_from_to_3d(from, to);
self.particles.resize_with(
self.particles.len() + usize::from(beam_tick_count) / 15,
|| {
let phi: f32 = rng.gen_range(0.0..beam.properties.angle);
let theta: f32 = rng.gen_range(0.0..2.0 * PI);
let offset_z = Vec3::new(
phi.sin() * theta.cos(),
phi.sin() * theta.sin(),
phi.cos(),
);
let random_ori = offset_z * m * Vec3::new(-1.0, -1.0, 1.0);
Particle::new_directed(
beam.properties.duration,
time,
ParticleMode::CultistFlame,
pos,
pos + random_ori * range,
)
},
);
},
beam::FrontendSpecifier::Ink => {
let mut rng = thread_rng();
let (from, to) = (Vec3::<f32>::unit_z(), *ori.look_dir());
let m = Mat3::<f32>::rotation_from_to_3d(from, to);
self.particles.resize_with(
self.particles.len() + usize::from(beam_tick_count) / 15,
|| {
let phi: f32 = rng.gen_range(0.0..beam.properties.angle);
let theta: f32 = rng.gen_range(0.0..2.0 * PI);
let offset_z = Vec3::new(
phi.sin() * theta.cos(),
phi.sin() * theta.sin(),
phi.cos(),
);
let random_ori = offset_z * m * Vec3::new(-1.0, -1.0, 1.0);
Particle::new_directed(
beam.properties.duration,
time,
ParticleMode::Ink,
pos,
pos + random_ori * range,
)
},
);
},
beam::FrontendSpecifier::Steam => {
let mut rng = thread_rng();
let (from, to) = (Vec3::<f32>::unit_z(), *ori.look_dir());
@ -1096,6 +1147,17 @@ impl ParticleMgr {
},
);
},
beam::FrontendSpecifier::Lightning => {
self.particles.resize_with(self.particles.len() + 2, || {
Particle::new_directed(
beam.properties.duration,
time,
ParticleMode::Lightning,
pos,
pos + *ori.look_dir() * range,
)
})
},
beam::FrontendSpecifier::Frost => {
let mut rng = thread_rng();
let (from, to) = (Vec3::<f32>::unit_z(), *ori.look_dir());
@ -1943,6 +2005,41 @@ impl ParticleMgr {
}
}
},
FrontendSpecifier::Lightning => {
// 1 particle per unit length of arc
let particles_per_length = arc_length as usize;
let dtheta = radians / particles_per_length as f32;
// Scales number of desired heartbeats from speed - thicker arc = higher speed =
// lower duration = more particles
let heartbeats = self
.scheduler
.heartbeats(Duration::from_secs_f32(1.0 / speed));
// Reserves capacity for new particles
let new_particle_count = particles_per_length * heartbeats as usize;
self.particles.reserve(new_particle_count);
for i in 0..particles_per_length {
let angle = dtheta * i as f32;
let direction = Vec3::new(angle.cos(), angle.sin(), 0.0);
for j in 0..heartbeats {
// Sub tick dt
let dt = (j as f32 / heartbeats as f32) * dt;
let distance = distance + speed * dt;
let pos1 = pos + distance * direction - Vec3::unit_z();
let pos2 = pos1 + (Vec3::unit_z() + direction) * 3.0;
let time = time + dt as f64;
self.particles.push(Particle::new_directed(
Duration::from_secs_f32(0.5),
time,
ParticleMode::Lightning,
pos1,
pos2,
));
}
}
},
FrontendSpecifier::Steam => {
// 1 particle per unit length of arc
let particles_per_length = arc_length as usize;
@ -1978,7 +2075,77 @@ impl ParticleMgr {
}
}
},
FrontendSpecifier::IceSpikes => {
FrontendSpecifier::Poison => {
// 1 particle per unit length of arc
let particles_per_length = arc_length as usize;
let dtheta = radians / particles_per_length as f32;
// Scales number of desired heartbeats from speed - thicker arc = higher speed =
// lower duration = more particles
let heartbeats = self
.scheduler
.heartbeats(Duration::from_secs_f32(1.0 / speed));
// Reserves capacity for new particles
let new_particle_count = particles_per_length * heartbeats as usize;
self.particles.reserve(new_particle_count);
for i in 0..particles_per_length {
let angle = dtheta * i as f32;
let direction = Vec3::new(angle.cos(), angle.sin(), 0.0);
for j in 0..heartbeats {
// Sub tick dt
let dt = (j as f32 / heartbeats as f32) * dt;
let distance = distance + speed * dt;
let pos1 = pos + distance * direction - Vec3::unit_z();
let pos2 = pos1 + (Vec3::unit_z() + direction) * 3.0;
let time = time + dt as f64;
self.particles.push(Particle::new_directed(
Duration::from_secs_f32(0.5),
time,
ParticleMode::CultistFlame,
pos1,
pos2,
));
}
}
},
FrontendSpecifier::Ink => {
// 1 particle per unit length of arc
let particles_per_length = arc_length as usize;
let dtheta = radians / particles_per_length as f32;
// Scales number of desired heartbeats from speed - thicker arc = higher speed =
// lower duration = more particles
let heartbeats = self
.scheduler
.heartbeats(Duration::from_secs_f32(1.0 / speed));
// Reserves capacity for new particles
let new_particle_count = particles_per_length * heartbeats as usize;
self.particles.reserve(new_particle_count);
for i in 0..particles_per_length {
let angle = dtheta * i as f32;
let direction = Vec3::new(angle.cos(), angle.sin(), 0.0);
for j in 0..heartbeats {
// Sub tick dt
let dt = (j as f32 / heartbeats as f32) * dt;
let distance = distance + speed * dt;
let pos1 = pos + distance * direction - Vec3::unit_z();
let pos2 = pos1 + (Vec3::unit_z() + direction) * 3.0;
let time = time + dt as f64;
self.particles.push(Particle::new_directed(
Duration::from_secs_f32(0.5),
time,
ParticleMode::Ink,
pos1,
pos2,
));
}
}
},
FrontendSpecifier::IceSpikes | FrontendSpecifier::Ice => {
// 1 / 3 the size of terrain voxel
let scale = 1.0 / 3.0;
let scaled_distance = distance / scale;