mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'qsto/phoenix' into 'master'
Phoenix overhaul See merge request veloren/veloren!4073
This commit is contained in:
commit
233f1d6bac
@ -716,10 +716,14 @@
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
Custom("Bird Large Fire"): (
|
Custom("Bird Large Fire"): (
|
||||||
primary: Simple(None, "common.abilities.custom.birdlargefire.firebomb"),
|
primary: Simple(None, "common.abilities.custom.birdlargefire.longstrike"),
|
||||||
secondary: Simple(None, "common.abilities.custom.birdlargefire.triplestrike"),
|
secondary: Simple(None, "common.abilities.custom.birdlargefire.shortstrike"),
|
||||||
abilities: [
|
abilities: [
|
||||||
Simple(None, "common.abilities.custom.birdlargefire.fireshockwave"),
|
Simple(None, "common.abilities.custom.birdlargefire.legstrike"),
|
||||||
|
Simple(None, "common.abilities.custom.birdlargefire.summontornadoes"),
|
||||||
|
Simple(None, "common.abilities.custom.birdlargefire.firerain"),
|
||||||
|
Simple(None, "common.abilities.custom.birdlargefire.heat_laser"),
|
||||||
|
Simple(None, "common.abilities.custom.birdlargefire.from_the_ashes"),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Custom("Flame Wyvern"): (
|
Custom("Flame Wyvern"): (
|
||||||
@ -807,6 +811,11 @@
|
|||||||
secondary: Simple(None, "common.abilities.empty.basic"),
|
secondary: Simple(None, "common.abilities.empty.basic"),
|
||||||
abilities: [],
|
abilities: [],
|
||||||
),
|
),
|
||||||
|
Custom("FieryTornado"): (
|
||||||
|
primary: Simple(None, "common.abilities.custom.fiery_tornado.fiery_spin"),
|
||||||
|
secondary: Simple(None, "common.abilities.custom.fiery_tornado.fiery_aura"),
|
||||||
|
abilities: [],
|
||||||
|
),
|
||||||
Custom("Golf Club"): (
|
Custom("Golf Club"): (
|
||||||
primary: Simple(None, "common.abilities.hammer.singlestrike"),
|
primary: Simple(None, "common.abilities.hammer.singlestrike"),
|
||||||
secondary: Simple(None, "common.abilities.tool.golf_club.charged"),
|
secondary: Simple(None, "common.abilities.tool.golf_club.charged"),
|
||||||
|
@ -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,
|
|
||||||
)
|
|
32
assets/common/abilities/custom/birdlargefire/firerain.ron
Normal file
32
assets/common/abilities/custom/birdlargefire/firerain.ron
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
RepeaterRanged(
|
||||||
|
energy_cost: 0.0,
|
||||||
|
buildup_duration: 0.2,
|
||||||
|
shoot_duration: 0.3,
|
||||||
|
recover_duration: 0.5,
|
||||||
|
max_speed: 8.0,
|
||||||
|
half_speed_at: 5,
|
||||||
|
projectile: FireDroplet(
|
||||||
|
damage: 30.0,
|
||||||
|
radius: 12.0,
|
||||||
|
min_falloff: 0.5,
|
||||||
|
energy_regen: 0,
|
||||||
|
reagent: Some(Phoenix),
|
||||||
|
),
|
||||||
|
projectile_body: Object(FireRainDrop),
|
||||||
|
projectile_light: Some(LightEmitter(
|
||||||
|
col: Rgb(
|
||||||
|
r: 1.0,
|
||||||
|
g: 0.8,
|
||||||
|
b: 0.3,
|
||||||
|
),
|
||||||
|
strength: 10.0,
|
||||||
|
flicker: 5.0,
|
||||||
|
animated: true,
|
||||||
|
)),
|
||||||
|
projectile_speed: 0.0,
|
||||||
|
properties_of_aoe: Some(ProjectileOffset(
|
||||||
|
radius: 30,
|
||||||
|
height: 20,
|
||||||
|
)),
|
||||||
|
specifier: Some(FireRain),
|
||||||
|
)
|
@ -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,
|
|
||||||
)
|
|
@ -0,0 +1,10 @@
|
|||||||
|
SelfBuff(
|
||||||
|
buildup_duration: 1.25,
|
||||||
|
cast_duration: 1.8,
|
||||||
|
recover_duration: 1.25,
|
||||||
|
buff_kind: Regeneration,
|
||||||
|
buff_strength: 1500.0,
|
||||||
|
buff_duration: Some(3.0),
|
||||||
|
energy_cost: 0,
|
||||||
|
specifier: Some(FromTheAshes),
|
||||||
|
)
|
19
assets/common/abilities/custom/birdlargefire/heat_laser.ron
Normal file
19
assets/common/abilities/custom/birdlargefire/heat_laser.ron
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
BasicBeam(
|
||||||
|
buildup_duration: 0.5,
|
||||||
|
recover_duration: 0.3,
|
||||||
|
beam_duration: 1.0,
|
||||||
|
damage: 30.0,
|
||||||
|
tick_rate: 1.0,
|
||||||
|
range: 120.0,
|
||||||
|
max_angle: 1.0,
|
||||||
|
damage_effect: Some(Buff((
|
||||||
|
kind: Burning,
|
||||||
|
dur_secs: 5.0,
|
||||||
|
strength: DamageFraction(0.75),
|
||||||
|
chance: 0.75,
|
||||||
|
))),
|
||||||
|
energy_regen: 0,
|
||||||
|
energy_drain: 0,
|
||||||
|
ori_rate: 0.07,
|
||||||
|
specifier: PhoenixLaser,
|
||||||
|
)
|
26
assets/common/abilities/custom/birdlargefire/legstrike.ron
Normal file
26
assets/common/abilities/custom/birdlargefire/legstrike.ron
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
ComboMelee2(
|
||||||
|
strikes: [
|
||||||
|
(
|
||||||
|
melee_constructor: (
|
||||||
|
kind: Slash(
|
||||||
|
damage: 35,
|
||||||
|
poise: 0,
|
||||||
|
knockback: 15,
|
||||||
|
energy_regen: 0,
|
||||||
|
),
|
||||||
|
range: 6.0,
|
||||||
|
angle: 90.0,
|
||||||
|
),
|
||||||
|
buildup_duration: 0.1,
|
||||||
|
swing_duration: 0.1,
|
||||||
|
hit_timing: 0.5,
|
||||||
|
recover_duration: 0.1,
|
||||||
|
movement: (
|
||||||
|
swing: Some(Forward(0.5)),
|
||||||
|
),
|
||||||
|
ori_modifier: 0.7,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
energy_cost_per_strike: 0,
|
||||||
|
auto_progress: false,
|
||||||
|
)
|
26
assets/common/abilities/custom/birdlargefire/longstrike.ron
Normal file
26
assets/common/abilities/custom/birdlargefire/longstrike.ron
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
ComboMelee2(
|
||||||
|
strikes: [
|
||||||
|
(
|
||||||
|
melee_constructor: (
|
||||||
|
kind: Slash(
|
||||||
|
damage: 30,
|
||||||
|
poise: 0,
|
||||||
|
knockback: 10,
|
||||||
|
energy_regen: 0,
|
||||||
|
),
|
||||||
|
range: 6.0,
|
||||||
|
angle: 90.0,
|
||||||
|
),
|
||||||
|
buildup_duration: 0.6,
|
||||||
|
swing_duration: 0.3,
|
||||||
|
hit_timing: 0.5,
|
||||||
|
recover_duration: 0.1,
|
||||||
|
movement: (
|
||||||
|
swing: Some(Forward(0.5)),
|
||||||
|
),
|
||||||
|
ori_modifier: 0.7,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
energy_cost_per_strike: 0,
|
||||||
|
auto_progress: true,
|
||||||
|
)
|
26
assets/common/abilities/custom/birdlargefire/shortstrike.ron
Normal file
26
assets/common/abilities/custom/birdlargefire/shortstrike.ron
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
ComboMelee2(
|
||||||
|
strikes: [
|
||||||
|
(
|
||||||
|
melee_constructor: (
|
||||||
|
kind: Slash(
|
||||||
|
damage: 20,
|
||||||
|
poise: 0,
|
||||||
|
knockback: 5,
|
||||||
|
energy_regen: 0,
|
||||||
|
),
|
||||||
|
range: 6.0,
|
||||||
|
angle: 90.0,
|
||||||
|
),
|
||||||
|
buildup_duration: 0.2,
|
||||||
|
swing_duration: 0.1,
|
||||||
|
hit_timing: 0.5,
|
||||||
|
recover_duration: 0.1,
|
||||||
|
movement: (
|
||||||
|
swing: Some(Forward(0.5)),
|
||||||
|
),
|
||||||
|
ori_modifier: 0.7,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
energy_cost_per_strike: 0,
|
||||||
|
auto_progress: true,
|
||||||
|
)
|
@ -0,0 +1,18 @@
|
|||||||
|
BasicSummon(
|
||||||
|
buildup_duration: 0.75,
|
||||||
|
cast_duration: 0.25,
|
||||||
|
recover_duration: 0.5,
|
||||||
|
summon_amount: 12,
|
||||||
|
summon_distance: (8, 10),
|
||||||
|
summon_info: (
|
||||||
|
body: Object(FieryTornado),
|
||||||
|
scale: None,
|
||||||
|
has_health: false,
|
||||||
|
loadout_config: None,
|
||||||
|
skillset_config: None,
|
||||||
|
),
|
||||||
|
duration: Some((
|
||||||
|
secs: 10,
|
||||||
|
nanos: 0,
|
||||||
|
)),
|
||||||
|
)
|
@ -11,7 +11,7 @@ BasicAura(
|
|||||||
category: Magical,
|
category: Magical,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
aura_duration: 2.0,
|
aura_duration: Some(2.0),
|
||||||
range: 10.0,
|
range: 10.0,
|
||||||
energy_cost: 0.0,
|
energy_cost: 0.0,
|
||||||
scales_with_combo: false,
|
scales_with_combo: false,
|
||||||
|
@ -11,7 +11,7 @@ BasicAura(
|
|||||||
category: Magical,
|
category: Magical,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
aura_duration: 2.0,
|
aura_duration: Some(2.0),
|
||||||
range: 10.0,
|
range: 10.0,
|
||||||
energy_cost: 0.0,
|
energy_cost: 0.0,
|
||||||
scales_with_combo: false,
|
scales_with_combo: false,
|
||||||
|
19
assets/common/abilities/custom/fiery_tornado/fiery_aura.ron
Normal file
19
assets/common/abilities/custom/fiery_tornado/fiery_aura.ron
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
BasicAura(
|
||||||
|
buildup_duration: 0.0,
|
||||||
|
cast_duration: 0.0,
|
||||||
|
recover_duration: 0.0,
|
||||||
|
targets: OutOfGroup,
|
||||||
|
auras: [
|
||||||
|
(
|
||||||
|
kind: Heatstroke,
|
||||||
|
strength: 1.0,
|
||||||
|
duration: Some(5.0),
|
||||||
|
category: Magical,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
aura_duration: None,
|
||||||
|
range: 20.0,
|
||||||
|
energy_cost: 0.0,
|
||||||
|
scales_with_combo: false,
|
||||||
|
specifier: Some(FieryAura),
|
||||||
|
)
|
25
assets/common/abilities/custom/fiery_tornado/fiery_spin.ron
Normal file
25
assets/common/abilities/custom/fiery_tornado/fiery_spin.ron
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
RapidMelee(
|
||||||
|
buildup_duration: 0.0,
|
||||||
|
swing_duration: 0.5,
|
||||||
|
recover_duration: 0.0,
|
||||||
|
melee_constructor: (
|
||||||
|
kind: Slash(
|
||||||
|
damage: 80,
|
||||||
|
poise: 0,
|
||||||
|
knockback: 50,
|
||||||
|
energy_regen: 0,
|
||||||
|
),
|
||||||
|
range: 3.5,
|
||||||
|
angle: 360,
|
||||||
|
multi_target: Some(Normal),
|
||||||
|
damage_effect: Some(Buff((
|
||||||
|
kind: Burning,
|
||||||
|
dur_secs: 8.0,
|
||||||
|
strength: Value(0.3),
|
||||||
|
chance: 1.0,
|
||||||
|
))),
|
||||||
|
),
|
||||||
|
energy_cost: 0,
|
||||||
|
ori_modifier: 1.0,
|
||||||
|
move_modifier: 1.0,
|
||||||
|
)
|
@ -11,7 +11,7 @@ BasicAura(
|
|||||||
category: Magical,
|
category: Magical,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
aura_duration: 34.75,
|
aura_duration: Some(34.75),
|
||||||
range: 18.0,
|
range: 18.0,
|
||||||
energy_cost: 0.0,
|
energy_cost: 0.0,
|
||||||
scales_with_combo: false,
|
scales_with_combo: false,
|
||||||
|
@ -17,7 +17,7 @@ BasicAura(
|
|||||||
category: Magical,
|
category: Magical,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
aura_duration: 2,
|
aura_duration: Some(2),
|
||||||
range: 50,
|
range: 50,
|
||||||
energy_cost: 0,
|
energy_cost: 0,
|
||||||
scales_with_combo: false,
|
scales_with_combo: false,
|
||||||
|
@ -11,7 +11,7 @@ BasicAura(
|
|||||||
category: Magical,
|
category: Magical,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
aura_duration: 2,
|
aura_duration: Some(2),
|
||||||
range: 50,
|
range: 50,
|
||||||
energy_cost: 0,
|
energy_cost: 0,
|
||||||
scales_with_combo: false,
|
scales_with_combo: false,
|
||||||
|
@ -11,7 +11,7 @@ BasicAura(
|
|||||||
category: Magical,
|
category: Magical,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
aura_duration: 2,
|
aura_duration: Some(2),
|
||||||
range: 50,
|
range: 50,
|
||||||
energy_cost: 0,
|
energy_cost: 0,
|
||||||
scales_with_combo: false,
|
scales_with_combo: false,
|
||||||
|
@ -11,7 +11,7 @@ BasicAura(
|
|||||||
category: Magical,
|
category: Magical,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
aura_duration: 1.0,
|
aura_duration: Some(1.0),
|
||||||
range: 25.0,
|
range: 25.0,
|
||||||
energy_cost: 20.0,
|
energy_cost: 20.0,
|
||||||
scales_with_combo: true,
|
scales_with_combo: true,
|
||||||
|
@ -11,7 +11,7 @@ BasicAura(
|
|||||||
category: Magical,
|
category: Magical,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
aura_duration: 1.0,
|
aura_duration: Some(1.0),
|
||||||
range: 25.0,
|
range: 25.0,
|
||||||
energy_cost: 35.0,
|
energy_cost: 35.0,
|
||||||
scales_with_combo: false,
|
scales_with_combo: false,
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
name: Automatic,
|
name: Automatic,
|
||||||
body: RandomWith("oni_blue"),
|
body: RandomWith("oni_blue"),
|
||||||
alignment: Alignment(Enemy),
|
alignment: Alignment(Enemy),
|
||||||
loot: LootTable("common.loot_tables.creature.biped_large.default"),
|
loot: LootTable("common.loot_tables.creature.biped_large.blue_oni"),
|
||||||
inventory: (
|
inventory: (
|
||||||
loadout: FromBody,
|
loadout: FromBody,
|
||||||
),
|
),
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
name: Automatic,
|
name: Automatic,
|
||||||
body: RandomWith("oni_red"),
|
body: RandomWith("oni_red"),
|
||||||
alignment: Alignment(Enemy),
|
alignment: Alignment(Enemy),
|
||||||
loot: LootTable("common.loot_tables.creature.biped_large.default"),
|
loot: LootTable("common.loot_tables.creature.biped_large.red_oni"),
|
||||||
inventory: (
|
inventory: (
|
||||||
loadout: FromBody,
|
loadout: FromBody,
|
||||||
),
|
),
|
||||||
|
13
assets/common/items/npc_armor/bird_large/phoenix.ron
Normal file
13
assets/common/items/npc_armor/bird_large/phoenix.ron
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
ItemDef(
|
||||||
|
name: "Phoenix Armor",
|
||||||
|
description: "The thickest feather you have ever seen!",
|
||||||
|
kind: Armor((
|
||||||
|
kind: Chest,
|
||||||
|
stats: Direct((
|
||||||
|
protection: Some(Normal(60.0)),
|
||||||
|
poise_resilience: Some(Normal(0.0)),
|
||||||
|
)),
|
||||||
|
)),
|
||||||
|
quality: Epic,
|
||||||
|
tags: [],
|
||||||
|
)
|
@ -1,6 +1,6 @@
|
|||||||
ItemDef(
|
ItemDef(
|
||||||
name: "Bird Large Fire",
|
name: "Bird Large Fire",
|
||||||
description: "testing123",
|
description: "Fiery touch of a mighty aerial beast",
|
||||||
kind: Tool((
|
kind: Tool((
|
||||||
kind: Natural,
|
kind: Natural,
|
||||||
hands: Two,
|
hands: Two,
|
||||||
@ -14,7 +14,7 @@ ItemDef(
|
|||||||
buff_strength: 1.0,
|
buff_strength: 1.0,
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
quality: Low,
|
quality: Epic,
|
||||||
tags: [],
|
tags: [],
|
||||||
ability_spec: Some(Custom("Bird Large Fire")),
|
ability_spec: Some(Custom("Bird Large Fire")),
|
||||||
)
|
)
|
20
assets/common/items/npc_weapons/unique/fiery_tornado.ron
Normal file
20
assets/common/items/npc_weapons/unique/fiery_tornado.ron
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
ItemDef(
|
||||||
|
name: "FieryTornado",
|
||||||
|
description: "Fiery Tornado weapon",
|
||||||
|
kind: Tool((
|
||||||
|
kind: Natural,
|
||||||
|
hands: Two,
|
||||||
|
stats: (
|
||||||
|
equip_time_secs: 0.01,
|
||||||
|
power: 1.0,
|
||||||
|
effect_power: 1.0,
|
||||||
|
speed: 1.0,
|
||||||
|
range: 1.0,
|
||||||
|
energy_efficiency: 1.0,
|
||||||
|
buff_strength: 1.0,
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
quality: Low,
|
||||||
|
tags: [],
|
||||||
|
ability_spec: Some(Custom("FieryTornado")),
|
||||||
|
)
|
@ -7,7 +7,7 @@ ItemDef(
|
|||||||
stats: (
|
stats: (
|
||||||
equip_time_secs: 0.01,
|
equip_time_secs: 0.01,
|
||||||
power: 1.0,
|
power: 1.0,
|
||||||
effect_power: 0.0,
|
effect_power: 1.0,
|
||||||
speed: 1.0,
|
speed: 1.0,
|
||||||
range: 1.0,
|
range: 1.0,
|
||||||
energy_efficiency: 1.0,
|
energy_efficiency: 1.0,
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
[
|
||||||
|
(1.0, LootTable("common.loot_tables.food.prepared")),
|
||||||
|
(2.0, LootTable("common.loot_tables.cave_large")),
|
||||||
|
(0.4, Item("common.items.glider.morpho")),
|
||||||
|
]
|
@ -1,9 +1,8 @@
|
|||||||
[
|
[
|
||||||
(1.8, All([
|
(1.9, All([
|
||||||
MultiDrop(Item("common.items.utility.coins"), 200, 500),
|
MultiDrop(Item("common.items.utility.coins"), 200, 500),
|
||||||
MultiDrop(Item("common.items.mineral.ingot.bloodsteel"), 2, 4),
|
MultiDrop(Item("common.items.mineral.ingot.bloodsteel"), 2, 4),
|
||||||
MultiDrop(Item("common.items.mineral.ingot.silver"), 0, 2),
|
MultiDrop(Item("common.items.mineral.ingot.silver"), 0, 2),
|
||||||
])),
|
])),
|
||||||
(0.1, Item("common.items.glider.morpho")),
|
|
||||||
(0.1, Item("common.items.weapons.sword.caladbolg")),
|
(0.1, Item("common.items.weapons.sword.caladbolg")),
|
||||||
]
|
]
|
@ -0,0 +1,5 @@
|
|||||||
|
[
|
||||||
|
(1.0, LootTable("common.loot_tables.food.prepared")),
|
||||||
|
(2.0, LootTable("common.loot_tables.cave_large")),
|
||||||
|
(0.4, Item("common.items.glider.monarch")),
|
||||||
|
]
|
@ -1,5 +1,4 @@
|
|||||||
[
|
[
|
||||||
(1.2, Nothing),
|
(1.6, Nothing),
|
||||||
(0.4, Item("common.items.glider.monarch")),
|
|
||||||
(0.4, Item("common.items.weapons.bow.sagitta")),
|
(0.4, Item("common.items.weapons.bow.sagitta")),
|
||||||
]
|
]
|
@ -1517,6 +1517,13 @@
|
|||||||
threshold: 0.8,
|
threshold: 0.8,
|
||||||
subtitle: "subtitle-portal-teleported",
|
subtitle: "subtitle-portal-teleported",
|
||||||
),
|
),
|
||||||
|
FromTheAshes: (
|
||||||
|
files: [
|
||||||
|
"voxygen.audio.sfx.abilities.heal",
|
||||||
|
],
|
||||||
|
threshold: 1.8,
|
||||||
|
subtitle: "subtitle-attack-from-the-ashes",
|
||||||
|
),
|
||||||
|
|
||||||
// Utterances (NPCs)
|
// Utterances (NPCs)
|
||||||
|
|
||||||
@ -1557,6 +1564,14 @@
|
|||||||
threshold: 1.3,
|
threshold: 1.3,
|
||||||
subtitle: "subtitle-utterance-wyvern-angry",
|
subtitle: "subtitle-utterance-wyvern-angry",
|
||||||
),
|
),
|
||||||
|
Utterance(Angry, Phoenix): (
|
||||||
|
files: [
|
||||||
|
"voxygen.audio.sfx.utterance.phoenix_angry_0",
|
||||||
|
"voxygen.audio.sfx.utterance.phoenix_angry_1",
|
||||||
|
],
|
||||||
|
threshold: 3.1,
|
||||||
|
subtitle: "subtitle-utterance-phoenix-angry",
|
||||||
|
),
|
||||||
Utterance(Angry, Adlet): (
|
Utterance(Angry, Adlet): (
|
||||||
files: [
|
files: [
|
||||||
"voxygen.audio.sfx.utterance.adlet_angry1",
|
"voxygen.audio.sfx.utterance.adlet_angry1",
|
||||||
@ -1765,6 +1780,14 @@
|
|||||||
threshold: 1.2,
|
threshold: 1.2,
|
||||||
subtitle: "subtitle-utterance-wyvern-hurt",
|
subtitle: "subtitle-utterance-wyvern-hurt",
|
||||||
),
|
),
|
||||||
|
Utterance(Hurt, Phoenix): (
|
||||||
|
files: [
|
||||||
|
"voxygen.audio.sfx.utterance.phoenix_hurt_0",
|
||||||
|
"voxygen.audio.sfx.utterance.phoenix_hurt_1",
|
||||||
|
],
|
||||||
|
threshold: 1.5,
|
||||||
|
subtitle: "subtitle-utterance-phoenix-hurt",
|
||||||
|
),
|
||||||
Utterance(Angry, Wendigo): (
|
Utterance(Angry, Wendigo): (
|
||||||
files: [
|
files: [
|
||||||
"voxygen.audio.sfx.utterance.wendigo_angry1",
|
"voxygen.audio.sfx.utterance.wendigo_angry1",
|
||||||
|
BIN
assets/voxygen/audio/sfx/abilities/heal.ogg
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/audio/sfx/abilities/heal.ogg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/audio/sfx/utterance/phoenix_angry_0.ogg
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/audio/sfx/utterance/phoenix_angry_0.ogg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/audio/sfx/utterance/phoenix_angry_1.ogg
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/audio/sfx/utterance/phoenix_angry_1.ogg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/audio/sfx/utterance/phoenix_hurt_0.ogg
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/audio/sfx/utterance/phoenix_hurt_0.ogg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/audio/sfx/utterance/phoenix_hurt_1.ogg
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/audio/sfx/utterance/phoenix_hurt_1.ogg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/de_buffs/debuff_heatstroke_0.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/de_buffs/debuff_heatstroke_0.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -109,6 +109,9 @@ buff-desc-bloodfeast = You restore life on attacks against bleeding enemies
|
|||||||
## Berserk
|
## Berserk
|
||||||
buff-title-berserk = Berserk
|
buff-title-berserk = Berserk
|
||||||
buff-desc-berserk = You are in a berserking rage, causing your attacks to be more powerful and swift, and increasing your speed. However, as a result your defensive capability is less.
|
buff-desc-berserk = You are in a berserking rage, causing your attacks to be more powerful and swift, and increasing your speed. However, as a result your defensive capability is less.
|
||||||
|
## Heatstroke
|
||||||
|
buff-title-heatstroke = Heatstroke
|
||||||
|
buff-desc-heatstroke = You were exposed to heat and now suffer from heatstroke, your energy reward and movement speed are cut down. Chill.
|
||||||
## Util
|
## Util
|
||||||
buff-text-over_seconds = over { $dur_secs } seconds
|
buff-text-over_seconds = over { $dur_secs } seconds
|
||||||
buff-text-for_seconds = for { $dur_secs } seconds
|
buff-text-for_seconds = for { $dur_secs } seconds
|
||||||
|
@ -111,6 +111,7 @@ subtitle-attack-icy_spikes = Icy spikes
|
|||||||
subtitle-attack-ice_crack = Ice crack
|
subtitle-attack-ice_crack = Ice crack
|
||||||
subtitle-attack-steam = Steam
|
subtitle-attack-steam = Steam
|
||||||
subtitle-attack-shovel = Shovel digging
|
subtitle-attack-shovel = Shovel digging
|
||||||
|
subtitle-attack-from-the-ashes = Heal Sound
|
||||||
|
|
||||||
subtitle-consume_potion = Drinking potion
|
subtitle-consume_potion = Drinking potion
|
||||||
subtitle-consume_apple = Eating apple
|
subtitle-consume_apple = Eating apple
|
||||||
@ -154,3 +155,5 @@ 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-angry = Wyvern roaring
|
||||||
subtitle-utterance-wyvern-hurt = Wyvern hurting
|
subtitle-utterance-wyvern-hurt = Wyvern hurting
|
||||||
|
subtitle-utterance-phoenix-angry = Phoenix screaming
|
||||||
|
subtitle-utterance-phoenix-hurt = Phoenix hurting
|
@ -84,6 +84,16 @@ const int CYCLOPS_CHARGE = 43;
|
|||||||
const int PORTAL_FIZZ = 45;
|
const int PORTAL_FIZZ = 45;
|
||||||
const int INK = 46;
|
const int INK = 46;
|
||||||
const int WHIRLWIND = 47;
|
const int WHIRLWIND = 47;
|
||||||
|
const int FIERY_BURST = 48;
|
||||||
|
const int FIERY_BURST_VORTEX = 49;
|
||||||
|
const int FIERY_BURST_SPARKS = 50;
|
||||||
|
const int FIERY_BURST_ASH = 51;
|
||||||
|
const int FIERY_TORNADO = 52;
|
||||||
|
const int PHOENIX_CLOUD = 53;
|
||||||
|
const int FIERY_DROPLET_TRACE = 54;
|
||||||
|
const int ENERGY_PHOENIX = 55;
|
||||||
|
const int PHOENIX_BEAM = 56;
|
||||||
|
const int PHOENIX_BUILD_UP_AIM = 57;
|
||||||
|
|
||||||
// meters per second squared (acceleration)
|
// meters per second squared (acceleration)
|
||||||
const float earth_gravity = 9.807;
|
const float earth_gravity = 9.807;
|
||||||
@ -727,6 +737,240 @@ void main() {
|
|||||||
spin_in_axis(vec3(rand6, rand7, rand8), percent() * 10 + 3 * rand9)
|
spin_in_axis(vec3(rand6, rand7, rand8), percent() * 10 + 3 * rand9)
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
case FIERY_BURST:
|
||||||
|
f_reflect = 0.0;
|
||||||
|
float fiery_radius = start_end(1.0 - pow(abs(rand5), 5.0), 1.0) * length(inst_dir);
|
||||||
|
float fiery_color1 = (7.0 + 1.0 * percent()) * min(1.0, percent() * 4.0) * 1.5;
|
||||||
|
float fiery_color2 = (4.0 - 2.0 * percent() + 1.3 * rand5 * slow_end(0.0)) * min(1.0, percent() * 4.0) * 1.3;
|
||||||
|
float fiery_color3 = 1.0 + 0.3 * percent();
|
||||||
|
attr = Attr(
|
||||||
|
spiral_motion(
|
||||||
|
vec3(
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
(rand3 + 1.0)
|
||||||
|
* max(
|
||||||
|
((percent() * 8.0) * (1.0 - step(0.2, percent()))),
|
||||||
|
((2.0 * (1.0 - percent())) * (step(0.2, percent())))
|
||||||
|
)
|
||||||
|
),
|
||||||
|
fiery_radius,
|
||||||
|
lifetime,
|
||||||
|
max(0.1, step(0.6, percent())) * 3.0 * abs(rand0),
|
||||||
|
rand1 * 2.0 * PI) + vec3(0.0, 0.0, rand2),
|
||||||
|
vec3(6.0 * abs(rand4) * (1.0 - slow_start(2.0)) * pow(fiery_radius / length(inst_dir), 0.5)),
|
||||||
|
vec4(fiery_color1, fiery_color2, fiery_color3, slow_end(0.4)),
|
||||||
|
spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3.0)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case FIERY_BURST_VORTEX:
|
||||||
|
f_reflect = 0.0;
|
||||||
|
float fiery_vortex_color1 = (min(1, percent() * 2) * (5 + 1 * percent() + 1 * slow_end(0)) * 1.5);
|
||||||
|
float fiery_vortex_color2 = (min(1, percent() * 2) * (4 - 2.4 * percent() + 1.3 * rand5 * slow_end(0)) * 1.3);
|
||||||
|
float fiery_vortex_color3 = 0;
|
||||||
|
attr = Attr(
|
||||||
|
spiral_motion(
|
||||||
|
vec3(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
(0 + 0.5 * rand4 ) + 4.0
|
||||||
|
* max(
|
||||||
|
((percent() * 8) * (1 - step(0.2, percent()))), // first 20% of lifetime particle moves up, then goes down
|
||||||
|
((2 * (1 - percent())) * (step(0.2, percent())))// to avoid tearing multi should have same proportion as edge(here: 8 before, 2 after)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
abs(rand0) + 0.5 * 10 * percent(),
|
||||||
|
percent(),
|
||||||
|
10.0 * abs(rand2),
|
||||||
|
rand3),
|
||||||
|
vec3((2.5 * (1 - slow_start(0.05)))),
|
||||||
|
vec4(fiery_vortex_color1, fiery_vortex_color2, fiery_vortex_color3, start_end(0.5, 1.5) * abs(rand2)),
|
||||||
|
spin_in_axis(vec3(rand6, rand7, rand8), percent() * 10 + 3 * rand9)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case FIERY_BURST_SPARKS:
|
||||||
|
f_reflect = 0.0;
|
||||||
|
// sparks should flicker, so it stops glowing for 18% of time 4 times per second, same thing used in 4th float of RGBA vector
|
||||||
|
float fiery_sparks_color1 = 2 + 1 * rand2 + 2 * step(0.18, fract(tick.x*4));
|
||||||
|
float fiery_sparks_color2 = 4 + 1 * rand2 + 4 * step(0.18, fract(tick.x*4));
|
||||||
|
float fiery_sparks_color3 = 4 + 6 * step(0.18, fract(tick.x*4));
|
||||||
|
attr = Attr(
|
||||||
|
spiral_motion(vec3(0, 0, 5), abs(rand0) + abs(rand1) * percent() * 4.0, percent(), 8.0 * abs(rand2), rand3),
|
||||||
|
vec3((2.5 * (1 - slow_start(0.05)))),
|
||||||
|
vec4(fiery_sparks_color1, fiery_sparks_color2, fiery_sparks_color3, 0.5 + 0.5 * step(0.18, fract(tick.x*4))),
|
||||||
|
spin_in_axis(vec3(rand6, rand7, rand8), percent() * 10 + 3 * rand9)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case FIERY_BURST_ASH:
|
||||||
|
f_reflect = 0.0;
|
||||||
|
/// inst_dir holds info about:
|
||||||
|
/// .x: radius of random spawn
|
||||||
|
float fiery_ash_rand_rad = inst_dir.x;
|
||||||
|
/// .y:
|
||||||
|
/// in fract: relative time of "setting on fire"
|
||||||
|
/// in int: radius of curve
|
||||||
|
float fiery_ash_radius = floor(inst_dir.y);
|
||||||
|
float fiery_ash_edge = inst_dir.y - fiery_ash_radius;
|
||||||
|
/// .z: height of the flight
|
||||||
|
float fiery_ash_height = inst_dir.z;
|
||||||
|
// {FOR PHOENIX "from the ashes"}sets ash on fire at 0.4 of lifetime, then makes it lose glow, representing losing heat
|
||||||
|
float fiery_ash_color1 = (2 + 1 * percent() * slow_end(0))
|
||||||
|
* (max(
|
||||||
|
1,
|
||||||
|
8 * step(fiery_ash_edge, percent()) * (1.4 - percent()))
|
||||||
|
);
|
||||||
|
float fiery_ash_color2 = (2 - 1 * percent() + 0.3 * abs(rand5) * slow_end(0.5))
|
||||||
|
* (max(
|
||||||
|
1,
|
||||||
|
6.5 * step(fiery_ash_edge, percent()) * (1.4 - percent()))
|
||||||
|
);
|
||||||
|
float fiery_ash_color3 = 1.5;
|
||||||
|
attr = Attr(
|
||||||
|
spiral_motion(
|
||||||
|
vec3(
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
fiery_ash_height// {FOR PHOENIX "from the ashes"} 8.58
|
||||||
|
),
|
||||||
|
abs(rand0 / 2.0 + 1.0)
|
||||||
|
* max(1.0, ((percent() * fiery_ash_radius * 0.8) * (1.0 - step(0.2, percent())))) // part of lifetime particle moves to periphery
|
||||||
|
* max(1.0, (fiery_ash_radius * 0.2 * (1.0 - percent()) * (step(0.2, percent())))),// then back to center
|
||||||
|
percent(),
|
||||||
|
6.0 * abs(rand2),
|
||||||
|
rand3 * 5.0
|
||||||
|
)
|
||||||
|
+ vec3((rand6 + rand5) * fiery_ash_rand_rad, (rand8 + rand3) * fiery_ash_rand_rad, abs(rand0)),//makes it apear randomly above base animation (Fiery Burst)
|
||||||
|
vec3((2.5 * (1 - slow_start(0.0)))),
|
||||||
|
vec4(fiery_ash_color1, fiery_ash_color2, fiery_ash_color3, abs(rand2) * slow_end(0.3)),
|
||||||
|
spin_in_axis(vec3(rand6, rand7, rand8), percent() * 10 + 3 * rand9)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case FIERY_TORNADO:
|
||||||
|
f_reflect = 0.0;
|
||||||
|
float fiery_tornado_color1 = (2.6 + 0.5 * percent())
|
||||||
|
* 4.0 * max(0.5, percent() * 1.2);
|
||||||
|
float fiery_tornado_color2 = (1.7 - 0.6 * pow(1.0 - percent(), 2.0) + 0.3 * abs(rand5))
|
||||||
|
* 2.0 * max(0.45, percent() * 1.2);
|
||||||
|
float fiery_tornado_color3 = 1.5 * max(0.6, percent());
|
||||||
|
attr = Attr(
|
||||||
|
spiral_motion(vec3(0, 0, 6.0 + rand3 * 1.5), abs(rand0) + abs(rand1) * percent() * 3.0, percent(), 15.0 * abs(rand2), -inst_time),
|
||||||
|
vec3((2.5 * (1 - slow_start(0.05)))),
|
||||||
|
vec4(fiery_tornado_color1, fiery_tornado_color2, fiery_tornado_color3, 0.5),
|
||||||
|
spin_in_axis(vec3(rand6, rand7, rand8), percent() * 10 + 3 * rand9)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case PHOENIX_CLOUD:
|
||||||
|
float PC_spin = floor(inst_dir.x);
|
||||||
|
float refl = floor(inst_dir.y);
|
||||||
|
float PC_size = floor(inst_dir.z);
|
||||||
|
//best is 0.4 - reflects some light but only part as
|
||||||
|
f_reflect = refl * 0.1;
|
||||||
|
// modifies by + 5% to -15%, if color is less than 0.5 it will get from +10% to +25% to it's value
|
||||||
|
float PC_rand_color_factor = rand0 * 0.05;
|
||||||
|
float PC_R = inst_dir.x - PC_spin;
|
||||||
|
PC_R += PC_R * PC_rand_color_factor * step(0.05, PC_R) * -abs(PC_rand_color_factor * 2.0)
|
||||||
|
+ PC_R * (1.0 - step(0.05, PC_R)) * max(abs(PC_rand_color_factor), 0.02) * 5.0;
|
||||||
|
float PC_G = inst_dir.y - refl;
|
||||||
|
PC_G += PC_G * PC_rand_color_factor * step(0.05, PC_G) * -abs(PC_rand_color_factor * 2.0)
|
||||||
|
+ PC_G * (1.0 - step(0.05, PC_G)) * max(abs(PC_rand_color_factor), 0.02) * 5.0;
|
||||||
|
float PC_B = inst_dir.z - PC_size;
|
||||||
|
PC_B += PC_B * PC_rand_color_factor * step(0.05, PC_B) * -abs(PC_rand_color_factor * 2.0)
|
||||||
|
+ PC_B * (1.0 - step(0.05, PC_B)) * max(abs(PC_rand_color_factor), 0.02) * 5.0;
|
||||||
|
attr = Attr(
|
||||||
|
linear_motion(
|
||||||
|
vec3(0.0, 0.0, 0.0),
|
||||||
|
vec3(rand4, rand5, rand6 * 2.5)
|
||||||
|
),
|
||||||
|
vec3(8.0 * min(percent() * 3.0, 1.0) * min((1.0 - percent()) * 2.0, 1.0)),
|
||||||
|
vec4(
|
||||||
|
PC_R,
|
||||||
|
PC_G,
|
||||||
|
PC_B,
|
||||||
|
PC_size * 1.2) * 10.0,
|
||||||
|
spin_in_axis(vec3(rand6 + rand5, rand7 + rand9, rand8 + rand2), percent() * PC_spin)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case FIERY_DROPLET_TRACE:
|
||||||
|
float m_r = 4.0;
|
||||||
|
f_reflect = 0.0; // Fire doesn't reflect light, it emits it
|
||||||
|
float prcnt = percent(); //idk if compiler would optimize it or not but as we have a lot of those particles... i'll just try
|
||||||
|
float droplet_color1 = 1 * (5 + 1 * prcnt + 1 * slow_end(0)) * 1.5;
|
||||||
|
float droplet_color2 = 1 * (4 - 2.4 * prcnt + 1.3 * rand5 * slow_end(0)) * 1.3;
|
||||||
|
float droplet_color3 = 0;
|
||||||
|
attr = Attr(
|
||||||
|
quadratic_bezier_motion(
|
||||||
|
vec3(0.0),
|
||||||
|
vec3(m_r * rand0, m_r * rand1, 0.0),
|
||||||
|
vec3(m_r * rand0, m_r * rand1, 4.0)
|
||||||
|
),
|
||||||
|
vec3(1),
|
||||||
|
vec4(droplet_color1,
|
||||||
|
droplet_color2,
|
||||||
|
droplet_color3,
|
||||||
|
1 * prcnt * (1 - step(0.5, prcnt)) + (1 - prcnt) * (step(0.5, prcnt))),
|
||||||
|
spin_in_axis(vec3(1,0,0),0)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case ENERGY_PHOENIX:
|
||||||
|
f_reflect = 0.0;
|
||||||
|
float fiery_r = (2 + 1 * percent() * slow_end(0))
|
||||||
|
* 6 * (1.4 - percent());
|
||||||
|
float fiery_g = (2 - 1 * percent() + 0.3 * abs(rand5) * slow_end(0.5))
|
||||||
|
* 4.5 * (1.4 - percent());
|
||||||
|
float fiery_b = 1.5;
|
||||||
|
spiral_radius = length(inst_dir);
|
||||||
|
attr = Attr(
|
||||||
|
spiral_motion(vec3(0.0, 0.0, 0.01), spiral_radius + abs(rand1), lifetime / 0.5, abs(rand0), rand1 * 2.0 * PI) + vec3(0.0, 0.0, rand2),
|
||||||
|
vec3(6.0 * abs(rand4) * (1 - slow_start(2.0))),
|
||||||
|
vec4(vec3(fiery_r, fiery_g, fiery_b), 1.0),
|
||||||
|
spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3.0)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case PHOENIX_BEAM:
|
||||||
|
f_reflect = 0.0; // Fire doesn't reflect light, it emits it
|
||||||
|
float beam_r = 6.0 - (4.0 * percent()) + 15.0 * fract(percent() * 4 + rand0 * rand0) * (1 - percent());
|
||||||
|
float beam_g = 2.0 + 6.6 * fract(percent() * 4 + rand0 * rand0) * (1 - percent());
|
||||||
|
float beam_b = 1.4;
|
||||||
|
|
||||||
|
vec3 factor_rand = vec3((rand0 * 0.2) * (rand5 * 0.1) + rand6 * 0.9, (rand1 * 0.2) * (rand4 * 0.1) + rand7 * 0.9, (rand2 * 0.2) * (rand3 * 0.1) + rand8 * 0.9);
|
||||||
|
start_pos += factor_rand + normalize(inst_dir) * 0.6;
|
||||||
|
attr = Attr(
|
||||||
|
spiral_motion(inst_dir - factor_rand * 0.4, 0.3 * ((rand2 + 0.5) * 5.5) * (1.0 - min(linear_scale(1.5), 1.0)), lifetime / inst_lifespan, 24.0, -inst_time * 8.0),
|
||||||
|
vec3((2.5 * (1 - slow_start(0.2)))),
|
||||||
|
vec4(beam_r, beam_g, beam_b, 1.0),
|
||||||
|
spin_in_axis(vec3(rand6, rand7, rand8), percent() * 10.0 + 3.0 * rand9)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case PHOENIX_BUILD_UP_AIM:
|
||||||
|
|
||||||
|
f_reflect = 0.0; // Fire doesn't reflect light, it emits it
|
||||||
|
|
||||||
|
float perc_t = percent(); // in case compiler wont optimize, idk
|
||||||
|
|
||||||
|
float aim_r = rand0 * 0.25 + 3.0 + 4.5 * perc_t * (1 - step(0.79, perc_t)) + 8.0 * step(0.81, perc_t) * perc_t;
|
||||||
|
float aim_g = rand0 * 0.25 + 2.0 - 1.0 * perc_t * (1 - step(0.79, perc_t)) + 2.0 * step(0.81, perc_t) * perc_t;
|
||||||
|
float aim_b = 1.4 * ((1 - perc_t) + step(0.74, perc_t));
|
||||||
|
|
||||||
|
|
||||||
|
vec3 dir_aim = inst_dir * 1.0;
|
||||||
|
vec3 rand_pos_aim = (cross(
|
||||||
|
(1.0 - 2.0 * step(0.0, rand2)) * normalize(inst_dir),
|
||||||
|
vec3(0.0, 0.0, 1.0)));
|
||||||
|
|
||||||
|
vec3 rand_fact = vec3(rand1 * 1, rand0 * 1, rand2 * 1);
|
||||||
|
start_pos += vec3(0.0, 0.0, 5.0) + rand_fact;
|
||||||
|
attr = Attr(
|
||||||
|
spiral_motion(
|
||||||
|
inst_dir + vec3(0.0, 0.0, -(6.0 - 3.0 * pow(perc_t, 2.5))) - rand_fact,
|
||||||
|
1.2 * rand9 * max(1.0 - perc_t, 0.0),
|
||||||
|
perc_t,
|
||||||
|
6.0,
|
||||||
|
inst_time * 8.0),
|
||||||
|
vec3((1.9 * (1 - slow_start(0.2)))),
|
||||||
|
vec4(aim_r, aim_g, aim_b, 1.0),
|
||||||
|
spin_in_axis(vec3(rand6, rand7, rand8), perc_t * 10.0 + 3.0 * rand9)
|
||||||
|
);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
attr = Attr(
|
attr = Attr(
|
||||||
linear_motion(
|
linear_motion(
|
||||||
|
@ -629,6 +629,16 @@
|
|||||||
central: ("armor.empty"),
|
central: ("armor.empty"),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
FireRainDrop: (
|
||||||
|
bone0: (
|
||||||
|
offset: (-2.0, -10.0, -2.0),
|
||||||
|
central: ("weapon.projectile.firerain_droplet1"),
|
||||||
|
),
|
||||||
|
bone1: (
|
||||||
|
offset: (0.0, 0.0, 0.0),
|
||||||
|
central: ("armor.empty"),
|
||||||
|
)
|
||||||
|
),
|
||||||
TrainingDummy: (
|
TrainingDummy: (
|
||||||
bone0: (
|
bone0: (
|
||||||
offset: (-7.0, -5.0, 0.0),
|
offset: (-7.0, -5.0, 0.0),
|
||||||
@ -809,6 +819,16 @@
|
|||||||
central: ("armor.empty"),
|
central: ("armor.empty"),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
FieryTornado: (
|
||||||
|
bone0: (
|
||||||
|
offset: (0.0, 0.0, 0.0),
|
||||||
|
central: ("armor.empty"),
|
||||||
|
),
|
||||||
|
bone1: (
|
||||||
|
offset: (0.0, 0.0, 0.0),
|
||||||
|
central: ("armor.empty"),
|
||||||
|
)
|
||||||
|
),
|
||||||
Apple: (
|
Apple: (
|
||||||
bone0: (
|
bone0: (
|
||||||
offset: (-3.5, -3.5, 0.0),
|
offset: (-3.5, -3.5, 0.0),
|
||||||
|
BIN
assets/voxygen/voxel/weapon/projectile/firerain_droplet1.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/weapon/projectile/firerain_droplet1.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -183,6 +183,7 @@ lazy_static! {
|
|||||||
BuffKind::Defiance => "defiance",
|
BuffKind::Defiance => "defiance",
|
||||||
BuffKind::Bloodfeast => "bloodfeast",
|
BuffKind::Bloodfeast => "bloodfeast",
|
||||||
BuffKind::Berserk => "berserk",
|
BuffKind::Berserk => "berserk",
|
||||||
|
BuffKind::Heatstroke => "heatstroke"
|
||||||
};
|
};
|
||||||
let mut buff_parser = HashMap::new();
|
let mut buff_parser = HashMap::new();
|
||||||
for kind in BuffKind::iter() {
|
for kind in BuffKind::iter() {
|
||||||
|
@ -721,6 +721,8 @@ pub enum CharacterAbility {
|
|||||||
projectile_light: Option<LightEmitter>,
|
projectile_light: Option<LightEmitter>,
|
||||||
projectile_speed: f32,
|
projectile_speed: f32,
|
||||||
damage_effect: Option<CombatEffect>,
|
damage_effect: Option<CombatEffect>,
|
||||||
|
properties_of_aoe: Option<repeater_ranged::ProjectileOffset>,
|
||||||
|
specifier: Option<repeater_ranged::FrontendSpecifier>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
meta: AbilityMeta,
|
meta: AbilityMeta,
|
||||||
},
|
},
|
||||||
@ -906,7 +908,7 @@ pub enum CharacterAbility {
|
|||||||
recover_duration: f32,
|
recover_duration: f32,
|
||||||
targets: combat::GroupTarget,
|
targets: combat::GroupTarget,
|
||||||
auras: Vec<aura::AuraBuffConstructor>,
|
auras: Vec<aura::AuraBuffConstructor>,
|
||||||
aura_duration: Secs,
|
aura_duration: Option<Secs>,
|
||||||
range: f32,
|
range: f32,
|
||||||
energy_cost: f32,
|
energy_cost: f32,
|
||||||
scales_with_combo: bool,
|
scales_with_combo: bool,
|
||||||
@ -947,6 +949,7 @@ pub enum CharacterAbility {
|
|||||||
combo_scaling: Option<ScalingKind>,
|
combo_scaling: Option<ScalingKind>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
meta: AbilityMeta,
|
meta: AbilityMeta,
|
||||||
|
specifier: Option<self_buff::FrontendSpecifier>,
|
||||||
},
|
},
|
||||||
SpriteSummon {
|
SpriteSummon {
|
||||||
buildup_duration: f32,
|
buildup_duration: f32,
|
||||||
@ -1228,6 +1231,8 @@ impl CharacterAbility {
|
|||||||
projectile_light: _,
|
projectile_light: _,
|
||||||
ref mut projectile_speed,
|
ref mut projectile_speed,
|
||||||
damage_effect: _,
|
damage_effect: _,
|
||||||
|
properties_of_aoe: _,
|
||||||
|
specifier: _,
|
||||||
meta: _,
|
meta: _,
|
||||||
} => {
|
} => {
|
||||||
*buildup_duration /= stats.speed;
|
*buildup_duration /= stats.speed;
|
||||||
@ -1578,6 +1583,7 @@ impl CharacterAbility {
|
|||||||
combo_cost: _,
|
combo_cost: _,
|
||||||
combo_scaling: _,
|
combo_scaling: _,
|
||||||
meta: _,
|
meta: _,
|
||||||
|
specifier: _,
|
||||||
} => {
|
} => {
|
||||||
*buff_strength *= stats.diminished_buff_strength();
|
*buff_strength *= stats.diminished_buff_strength();
|
||||||
*buildup_duration /= stats.speed;
|
*buildup_duration /= stats.speed;
|
||||||
@ -2597,6 +2603,8 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState {
|
|||||||
projectile_light,
|
projectile_light,
|
||||||
projectile_speed,
|
projectile_speed,
|
||||||
damage_effect,
|
damage_effect,
|
||||||
|
properties_of_aoe,
|
||||||
|
specifier,
|
||||||
meta: _,
|
meta: _,
|
||||||
} => CharacterState::RepeaterRanged(repeater_ranged::Data {
|
} => CharacterState::RepeaterRanged(repeater_ranged::Data {
|
||||||
static_data: repeater_ranged::StaticData {
|
static_data: repeater_ranged::StaticData {
|
||||||
@ -2613,6 +2621,8 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState {
|
|||||||
projectile_speed: *projectile_speed,
|
projectile_speed: *projectile_speed,
|
||||||
ability_info,
|
ability_info,
|
||||||
damage_effect: *damage_effect,
|
damage_effect: *damage_effect,
|
||||||
|
properties_of_aoe: *properties_of_aoe,
|
||||||
|
specifier: *specifier,
|
||||||
},
|
},
|
||||||
timer: Duration::default(),
|
timer: Duration::default(),
|
||||||
stage_section: StageSection::Buildup,
|
stage_section: StageSection::Buildup,
|
||||||
@ -2776,6 +2786,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState {
|
|||||||
combo_scaling,
|
combo_scaling,
|
||||||
enforced_limit,
|
enforced_limit,
|
||||||
meta: _,
|
meta: _,
|
||||||
|
specifier,
|
||||||
} => CharacterState::SelfBuff(self_buff::Data {
|
} => CharacterState::SelfBuff(self_buff::Data {
|
||||||
static_data: self_buff::StaticData {
|
static_data: self_buff::StaticData {
|
||||||
buildup_duration: Duration::from_secs_f32(*buildup_duration),
|
buildup_duration: Duration::from_secs_f32(*buildup_duration),
|
||||||
@ -2789,6 +2800,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState {
|
|||||||
combo_on_use: data.combo.map_or(0, |c| c.counter()),
|
combo_on_use: data.combo.map_or(0, |c| c.counter()),
|
||||||
enforced_limit: *enforced_limit,
|
enforced_limit: *enforced_limit,
|
||||||
ability_info,
|
ability_info,
|
||||||
|
specifier: *specifier,
|
||||||
},
|
},
|
||||||
timer: Duration::default(),
|
timer: Duration::default(),
|
||||||
stage_section: StageSection::Buildup,
|
stage_section: StageSection::Buildup,
|
||||||
|
@ -78,6 +78,7 @@ pub enum Specifier {
|
|||||||
WardingAura,
|
WardingAura,
|
||||||
HealingAura,
|
HealingAura,
|
||||||
Frozen,
|
Frozen,
|
||||||
|
FieryAura,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<(Option<GroupTarget>, Option<&Uid>)> for AuraTarget {
|
impl From<(Option<GroupTarget>, Option<&Uid>)> for AuraTarget {
|
||||||
|
@ -44,4 +44,5 @@ pub enum FrontendSpecifier {
|
|||||||
Poison,
|
Poison,
|
||||||
Ink,
|
Ink,
|
||||||
Lightning,
|
Lightning,
|
||||||
|
PhoenixLaser,
|
||||||
}
|
}
|
||||||
|
@ -519,7 +519,7 @@ impl Body {
|
|||||||
| bird_large::Species::CloudWyvern
|
| bird_large::Species::CloudWyvern
|
||||||
| bird_large::Species::SeaWyvern
|
| bird_large::Species::SeaWyvern
|
||||||
| bird_large::Species::WealdWyvern => Vec3::new(2.5, 9.0, 4.5),
|
| bird_large::Species::WealdWyvern => Vec3::new(2.5, 9.0, 4.5),
|
||||||
_ => Vec3::new(2.0, 6.0, 3.5),
|
_ => Vec3::new(2.0, 6.0, 4.4),
|
||||||
},
|
},
|
||||||
Body::Dragon(_) => Vec3::new(16.0, 10.0, 16.0),
|
Body::Dragon(_) => Vec3::new(16.0, 10.0, 16.0),
|
||||||
Body::FishMedium(_) => Vec3::new(0.5, 2.0, 0.8),
|
Body::FishMedium(_) => Vec3::new(0.5, 2.0, 0.8),
|
||||||
@ -842,6 +842,7 @@ impl Body {
|
|||||||
| bird_large::Species::FrostWyvern
|
| bird_large::Species::FrostWyvern
|
||||||
| bird_large::Species::SeaWyvern
|
| bird_large::Species::SeaWyvern
|
||||||
| bird_large::Species::WealdWyvern => 1000,
|
| bird_large::Species::WealdWyvern => 1000,
|
||||||
|
bird_large::Species::Phoenix => 2000,
|
||||||
_ => 300,
|
_ => 300,
|
||||||
},
|
},
|
||||||
Body::BirdMedium(bird_medium) => match bird_medium.species {
|
Body::BirdMedium(bird_medium) => match bird_medium.species {
|
||||||
@ -940,7 +941,7 @@ impl Body {
|
|||||||
quadruped_low::Species::Maneater => 130,
|
quadruped_low::Species::Maneater => 130,
|
||||||
quadruped_low::Species::Sandshark => 110,
|
quadruped_low::Species::Sandshark => 110,
|
||||||
quadruped_low::Species::Hakulaq => 120,
|
quadruped_low::Species::Hakulaq => 120,
|
||||||
quadruped_low::Species::Dagon => 1200,
|
quadruped_low::Species::Dagon => 1500,
|
||||||
quadruped_low::Species::Lavadrake => 160,
|
quadruped_low::Species::Lavadrake => 160,
|
||||||
quadruped_low::Species::Basilisk => 200,
|
quadruped_low::Species::Basilisk => 200,
|
||||||
quadruped_low::Species::Deadwood => 120,
|
quadruped_low::Species::Deadwood => 120,
|
||||||
|
@ -112,6 +112,8 @@ make_case_elim!(
|
|||||||
SpearIcicle = 97,
|
SpearIcicle = 97,
|
||||||
Portal = 98,
|
Portal = 98,
|
||||||
PortalActive = 99,
|
PortalActive = 99,
|
||||||
|
FieryTornado = 100,
|
||||||
|
FireRainDrop = 101,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -122,7 +124,7 @@ impl Body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const ALL_OBJECTS: [Body; 100] = [
|
pub const ALL_OBJECTS: [Body; 102] = [
|
||||||
Body::Arrow,
|
Body::Arrow,
|
||||||
Body::Bomb,
|
Body::Bomb,
|
||||||
Body::Scarecrow,
|
Body::Scarecrow,
|
||||||
@ -223,6 +225,8 @@ pub const ALL_OBJECTS: [Body; 100] = [
|
|||||||
Body::SpearIcicle,
|
Body::SpearIcicle,
|
||||||
Body::Portal,
|
Body::Portal,
|
||||||
Body::PortalActive,
|
Body::PortalActive,
|
||||||
|
Body::FieryTornado,
|
||||||
|
Body::FireRainDrop,
|
||||||
];
|
];
|
||||||
|
|
||||||
impl From<Body> for super::Body {
|
impl From<Body> for super::Body {
|
||||||
@ -332,6 +336,8 @@ impl Body {
|
|||||||
Body::SpearIcicle => "spear_icicle",
|
Body::SpearIcicle => "spear_icicle",
|
||||||
Body::Portal => "portal",
|
Body::Portal => "portal",
|
||||||
Body::PortalActive => "portal_active",
|
Body::PortalActive => "portal_active",
|
||||||
|
Body::FieryTornado => "fiery_tornado",
|
||||||
|
Body::FireRainDrop => "fire_rain_drop",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,6 +349,7 @@ impl Body {
|
|||||||
Reagent::Red => Body::FireworkRed,
|
Reagent::Red => Body::FireworkRed,
|
||||||
Reagent::White => Body::FireworkWhite,
|
Reagent::White => Body::FireworkWhite,
|
||||||
Reagent::Yellow => Body::FireworkYellow,
|
Reagent::Yellow => Body::FireworkYellow,
|
||||||
|
Reagent::Phoenix => Body::FireRainDrop,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,7 +391,11 @@ impl Body {
|
|||||||
Body::BedBlue => 50.0,
|
Body::BedBlue => 50.0,
|
||||||
Body::Bedroll => 3.0,
|
Body::Bedroll => 3.0,
|
||||||
Body::Bench => 100.0,
|
Body::Bench => 100.0,
|
||||||
Body::BoltFire | Body::BoltFireBig | Body::BoltNature | Body::BoltIcicle => 1.0,
|
Body::BoltFire
|
||||||
|
| Body::BoltFireBig
|
||||||
|
| Body::BoltNature
|
||||||
|
| Body::BoltIcicle
|
||||||
|
| Body::FireRainDrop => 1.0,
|
||||||
Body::SpitPoison => 100.0,
|
Body::SpitPoison => 100.0,
|
||||||
Body::Bomb | Body::DagonBomb => {
|
Body::Bomb | Body::DagonBomb => {
|
||||||
0.5 * IRON_DENSITY * std::f32::consts::PI / 6.0 * self.dimensions().x.powi(3)
|
0.5 * IRON_DENSITY * std::f32::consts::PI / 6.0 * self.dimensions().x.powi(3)
|
||||||
@ -445,7 +456,7 @@ impl Body {
|
|||||||
Body::FishMeat => 10.0,
|
Body::FishMeat => 10.0,
|
||||||
Body::BirdMeat => 10.0,
|
Body::BirdMeat => 10.0,
|
||||||
Body::SmallMeat => 10.0,
|
Body::SmallMeat => 10.0,
|
||||||
Body::Tornado => 50.0,
|
Body::Tornado | Body::FieryTornado => 50.0,
|
||||||
Body::Apple => 2.0,
|
Body::Apple => 2.0,
|
||||||
Body::Hive => 2.0,
|
Body::Hive => 2.0,
|
||||||
Body::Coconut => 2.0,
|
Body::Coconut => 2.0,
|
||||||
@ -479,7 +490,7 @@ impl Body {
|
|||||||
Body::HaniwaSentry => Vec3::new(0.8, 0.8, 1.4),
|
Body::HaniwaSentry => Vec3::new(0.8, 0.8, 1.4),
|
||||||
Body::SeaLantern => Vec3::new(0.8, 0.8, 1.4),
|
Body::SeaLantern => Vec3::new(0.8, 0.8, 1.4),
|
||||||
Body::Snowball => Vec3::broadcast(2.5),
|
Body::Snowball => Vec3::broadcast(2.5),
|
||||||
Body::Tornado => Vec3::new(2.0, 2.0, 3.4),
|
Body::Tornado | Body::FieryTornado => Vec3::new(2.0, 2.0, 3.4),
|
||||||
Body::TrainingDummy => Vec3::new(1.5, 1.5, 3.0),
|
Body::TrainingDummy => Vec3::new(1.5, 1.5, 3.0),
|
||||||
Body::GnarlingTotemRed | Body::GnarlingTotemGreen | Body::GnarlingTotemWhite => {
|
Body::GnarlingTotemRed | Body::GnarlingTotemGreen | Body::GnarlingTotemWhite => {
|
||||||
Vec3::new(0.8, 0.8, 1.4)
|
Vec3::new(0.8, 0.8, 1.4)
|
||||||
@ -489,6 +500,7 @@ impl Body {
|
|||||||
Body::LaserBeam => Vec3::new(8.0, 8.0, 8.0),
|
Body::LaserBeam => Vec3::new(8.0, 8.0, 8.0),
|
||||||
Body::Mine => Vec3::new(0.8, 0.8, 0.5),
|
Body::Mine => Vec3::new(0.8, 0.8, 0.5),
|
||||||
Body::LightningBolt | Body::SpearIcicle => Vec3::new(1.0, 1.0, 1.0),
|
Body::LightningBolt | Body::SpearIcicle => Vec3::new(1.0, 1.0, 1.0),
|
||||||
|
Body::FireRainDrop => Vec3::new(0.01, 0.01, 0.02),
|
||||||
// FIXME: this *must* be exhaustive match
|
// FIXME: this *must* be exhaustive match
|
||||||
_ => Vec3::broadcast(0.5),
|
_ => Vec3::broadcast(0.5),
|
||||||
}
|
}
|
||||||
|
@ -162,6 +162,12 @@ pub enum BuffKind {
|
|||||||
PotionSickness,
|
PotionSickness,
|
||||||
/// Changed into another body.
|
/// Changed into another body.
|
||||||
Polymorphed,
|
Polymorphed,
|
||||||
|
/// Slows movement speed and reduces energy reward.
|
||||||
|
/// Both scales non-linearly to strength, 0.5 lead to movespeed reduction
|
||||||
|
/// by 25% and energy reward reduced by 150%, 1.0 lead to MS reduction by
|
||||||
|
/// 33.3% and energy reward reduced by 200%. Energy reward can't be
|
||||||
|
/// reduced by more than 200%, to a minimum value of -100%.
|
||||||
|
Heatstroke,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BuffKind {
|
impl BuffKind {
|
||||||
@ -201,7 +207,8 @@ impl BuffKind {
|
|||||||
| BuffKind::Poisoned
|
| BuffKind::Poisoned
|
||||||
| BuffKind::Parried
|
| BuffKind::Parried
|
||||||
| BuffKind::PotionSickness
|
| BuffKind::PotionSickness
|
||||||
| BuffKind::Polymorphed => false,
|
| BuffKind::Polymorphed
|
||||||
|
| BuffKind::Heatstroke => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -409,6 +416,10 @@ impl BuffKind {
|
|||||||
BuffEffect::AttackSpeed(1.0 + nn_scaling(data.strength) / 2.0),
|
BuffEffect::AttackSpeed(1.0 + nn_scaling(data.strength) / 2.0),
|
||||||
BuffEffect::MovementSpeed(1.0 + nn_scaling(data.strength) / 4.0),
|
BuffEffect::MovementSpeed(1.0 + nn_scaling(data.strength) / 4.0),
|
||||||
],
|
],
|
||||||
|
BuffKind::Heatstroke => vec![
|
||||||
|
BuffEffect::MovementSpeed(1.0 - nn_scaling(data.strength) * 0.5),
|
||||||
|
BuffEffect::EnergyReward((1.0 - nn_scaling(data.strength) * 3.0).max(-1.0)),
|
||||||
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@ pub enum Reagent {
|
|||||||
Red,
|
Red,
|
||||||
White,
|
White,
|
||||||
Yellow,
|
Yellow,
|
||||||
|
Phoenix,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
|
@ -780,6 +780,9 @@ fn default_main_tool(body: &Body) -> Item {
|
|||||||
object::Body::Tornado => Some(Item::new_from_asset_expect(
|
object::Body::Tornado => Some(Item::new_from_asset_expect(
|
||||||
"common.items.npc_weapons.unique.tornado",
|
"common.items.npc_weapons.unique.tornado",
|
||||||
)),
|
)),
|
||||||
|
object::Body::FieryTornado => Some(Item::new_from_asset_expect(
|
||||||
|
"common.items.npc_weapons.unique.fiery_tornado",
|
||||||
|
)),
|
||||||
object::Body::GnarlingTotemRed => Some(Item::new_from_asset_expect(
|
object::Body::GnarlingTotemRed => Some(Item::new_from_asset_expect(
|
||||||
"common.items.npc_weapons.biped_small.gnarling.redtotem",
|
"common.items.npc_weapons.biped_small.gnarling.redtotem",
|
||||||
)),
|
)),
|
||||||
@ -984,6 +987,7 @@ impl LoadoutBuilder {
|
|||||||
| bird_large::Species::WealdWyvern => {
|
| bird_large::Species::WealdWyvern => {
|
||||||
Some("common.items.npc_armor.bird_large.wyvern")
|
Some("common.items.npc_armor.bird_large.wyvern")
|
||||||
},
|
},
|
||||||
|
bird_large::Species::Phoenix => Some("common.items.npc_armor.bird_large.phoenix"),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
Body::Golem(body) => match body.species {
|
Body::Golem(body) => match body.species {
|
||||||
|
@ -59,6 +59,13 @@ pub enum ProjectileConstructor {
|
|||||||
knockback: f32,
|
knockback: f32,
|
||||||
energy_regen: f32,
|
energy_regen: f32,
|
||||||
},
|
},
|
||||||
|
FireDroplet {
|
||||||
|
damage: f32,
|
||||||
|
radius: f32,
|
||||||
|
energy_regen: f32,
|
||||||
|
min_falloff: f32,
|
||||||
|
reagent: Option<Reagent>,
|
||||||
|
},
|
||||||
Fireball {
|
Fireball {
|
||||||
damage: f32,
|
damage: f32,
|
||||||
radius: f32,
|
radius: f32,
|
||||||
@ -253,6 +260,56 @@ impl ProjectileConstructor {
|
|||||||
is_point: true,
|
is_point: true,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
FireDroplet {
|
||||||
|
damage,
|
||||||
|
radius,
|
||||||
|
energy_regen,
|
||||||
|
min_falloff,
|
||||||
|
reagent,
|
||||||
|
} => {
|
||||||
|
let energy = AttackEffect::new(None, CombatEffect::EnergyReward(energy_regen))
|
||||||
|
.with_requirement(CombatRequirement::AnyDamage);
|
||||||
|
let buff = CombatEffect::Buff(CombatBuff {
|
||||||
|
kind: BuffKind::Burning,
|
||||||
|
dur_secs: 4.0,
|
||||||
|
strength: CombatBuffStrength::DamageFraction(1.0),
|
||||||
|
chance: 1.0,
|
||||||
|
})
|
||||||
|
.adjusted_by_stats(tool_stats);
|
||||||
|
let damage = AttackDamage::new(
|
||||||
|
Damage {
|
||||||
|
source: DamageSource::Explosion,
|
||||||
|
kind: DamageKind::Energy,
|
||||||
|
value: damage,
|
||||||
|
},
|
||||||
|
Some(GroupTarget::OutOfGroup),
|
||||||
|
instance,
|
||||||
|
)
|
||||||
|
.with_effect(buff);
|
||||||
|
let attack = Attack::default()
|
||||||
|
.with_damage(damage)
|
||||||
|
.with_precision(precision_mult)
|
||||||
|
.with_effect(energy)
|
||||||
|
.with_combo_increment();
|
||||||
|
let explosion = Explosion {
|
||||||
|
effects: vec![
|
||||||
|
RadiusEffect::Attack(attack),
|
||||||
|
RadiusEffect::TerrainDestruction(2.0, Rgb::black()),
|
||||||
|
],
|
||||||
|
radius,
|
||||||
|
reagent,
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
},
|
||||||
Fireball {
|
Fireball {
|
||||||
damage,
|
damage,
|
||||||
radius,
|
radius,
|
||||||
@ -915,6 +972,16 @@ impl ProjectileConstructor {
|
|||||||
*damage *= power;
|
*damage *= power;
|
||||||
*energy_regen *= regen;
|
*energy_regen *= regen;
|
||||||
},
|
},
|
||||||
|
FireDroplet {
|
||||||
|
ref mut damage,
|
||||||
|
ref mut energy_regen,
|
||||||
|
ref mut radius,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
*damage *= power;
|
||||||
|
*energy_regen *= regen;
|
||||||
|
*radius *= range;
|
||||||
|
},
|
||||||
Fireball {
|
Fireball {
|
||||||
ref mut damage,
|
ref mut damage,
|
||||||
ref mut energy_regen,
|
ref mut energy_regen,
|
||||||
@ -1034,6 +1101,7 @@ impl ProjectileConstructor {
|
|||||||
match self {
|
match self {
|
||||||
Arrow { .. } => false,
|
Arrow { .. } => false,
|
||||||
Knife { .. } => false,
|
Knife { .. } => false,
|
||||||
|
FireDroplet { .. } => true,
|
||||||
Fireball { .. } => true,
|
Fireball { .. } => true,
|
||||||
Frostball { .. } => true,
|
Frostball { .. } => true,
|
||||||
Poisonball { .. } => true,
|
Poisonball { .. } => true,
|
||||||
|
@ -146,6 +146,9 @@ pub enum Outcome {
|
|||||||
TeleportedByPortal {
|
TeleportedByPortal {
|
||||||
pos: Vec3<f32>,
|
pos: Vec3<f32>,
|
||||||
},
|
},
|
||||||
|
FromTheAshes {
|
||||||
|
pos: Vec3<f32>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Outcome {
|
impl Outcome {
|
||||||
@ -177,6 +180,7 @@ impl Outcome {
|
|||||||
| Outcome::GroundDig { pos }
|
| Outcome::GroundDig { pos }
|
||||||
| Outcome::PortalActivated { pos }
|
| Outcome::PortalActivated { pos }
|
||||||
| Outcome::TeleportedByPortal { pos}
|
| Outcome::TeleportedByPortal { pos}
|
||||||
|
| Outcome::FromTheAshes { pos }
|
||||||
| Outcome::Glider { pos, .. } => Some(*pos),
|
| Outcome::Glider { pos, .. } => Some(*pos),
|
||||||
Outcome::BreakBlock { pos, .. }
|
Outcome::BreakBlock { pos, .. }
|
||||||
| Outcome::SpriteUnlocked { pos }
|
| Outcome::SpriteUnlocked { pos }
|
||||||
|
@ -29,7 +29,7 @@ pub struct StaticData {
|
|||||||
/// Has information used to construct the auras
|
/// Has information used to construct the auras
|
||||||
pub auras: Vec<AuraBuffConstructor>,
|
pub auras: Vec<AuraBuffConstructor>,
|
||||||
/// How long aura lasts
|
/// How long aura lasts
|
||||||
pub aura_duration: Secs,
|
pub aura_duration: Option<Secs>,
|
||||||
/// Radius of aura
|
/// Radius of aura
|
||||||
pub range: f32,
|
pub range: f32,
|
||||||
/// What key is used to press ability
|
/// What key is used to press ability
|
||||||
@ -78,7 +78,8 @@ impl CharacterBehavior for Data {
|
|||||||
let mut aura = aura_data.to_aura(
|
let mut aura = aura_data.to_aura(
|
||||||
data.uid,
|
data.uid,
|
||||||
self.static_data.range,
|
self.static_data.range,
|
||||||
Some(self.static_data.aura_duration),
|
// check for indefinite aura
|
||||||
|
self.static_data.aura_duration,
|
||||||
targets,
|
targets,
|
||||||
*data.time,
|
*data.time,
|
||||||
);
|
);
|
||||||
|
@ -4,8 +4,11 @@ use crate::{
|
|||||||
DamageKind, DamageSource, GroupTarget,
|
DamageKind, DamageSource, GroupTarget,
|
||||||
},
|
},
|
||||||
comp::{
|
comp::{
|
||||||
beam, body::biped_large, character_state::OutputEvents, object::Body::Flamethrower, Body,
|
beam,
|
||||||
CharacterState, Ori, StateUpdate,
|
body::{biped_large, bird_large},
|
||||||
|
character_state::OutputEvents,
|
||||||
|
object::Body::Flamethrower,
|
||||||
|
Body, CharacterState, Ori, StateUpdate,
|
||||||
},
|
},
|
||||||
event::LocalEvent,
|
event::LocalEvent,
|
||||||
outcome::Outcome,
|
outcome::Outcome,
|
||||||
@ -242,8 +245,13 @@ impl CharacterBehavior for Data {
|
|||||||
fn height_offset(body: &Body, look_dir: Dir, velocity: Vec3<f32>, on_ground: Option<Block>) -> f32 {
|
fn height_offset(body: &Body, look_dir: Dir, velocity: Vec3<f32>, on_ground: Option<Block>) -> f32 {
|
||||||
match body {
|
match body {
|
||||||
// Hack to make the beam offset correspond to the animation
|
// Hack to make the beam offset correspond to the animation
|
||||||
Body::BirdLarge(_) => {
|
Body::BirdLarge(b) => {
|
||||||
body.height() * 0.3
|
let height_factor = match b.species {
|
||||||
|
bird_large::Species::Phoenix => 0.5,
|
||||||
|
bird_large::Species::Cockatrice => 0.4,
|
||||||
|
_ => 0.3,
|
||||||
|
};
|
||||||
|
body.height() * height_factor
|
||||||
+ if on_ground.is_none() {
|
+ if on_ground.is_none() {
|
||||||
(2.0 - velocity.xy().magnitude() * 0.25).max(-1.0)
|
(2.0 - velocity.xy().magnitude() * 0.25).max(-1.0)
|
||||||
} else {
|
} else {
|
||||||
|
@ -3,8 +3,11 @@ use crate::{
|
|||||||
self,
|
self,
|
||||||
character_state::OutputEvents,
|
character_state::OutputEvents,
|
||||||
inventory::loadout_builder::{self, LoadoutBuilder},
|
inventory::loadout_builder::{self, LoadoutBuilder},
|
||||||
|
object::Body::FieryTornado,
|
||||||
skillset::skills,
|
skillset::skills,
|
||||||
Behavior, BehaviorCapability, CharacterState, Projectile, StateUpdate,
|
Behavior, BehaviorCapability,
|
||||||
|
Body::Object,
|
||||||
|
CharacterState, Projectile, StateUpdate,
|
||||||
},
|
},
|
||||||
event::{LocalEvent, NpcBuilder, ServerEvent},
|
event::{LocalEvent, NpcBuilder, ServerEvent},
|
||||||
npc::NPC_NAMES,
|
npc::NPC_NAMES,
|
||||||
@ -185,11 +188,19 @@ impl CharacterBehavior for Data {
|
|||||||
is_sticky: false,
|
is_sticky: false,
|
||||||
is_point: false,
|
is_point: false,
|
||||||
});
|
});
|
||||||
|
let extra_height =
|
||||||
|
if self.static_data.summon_info.body == Object(FieryTornado) {
|
||||||
|
5.0
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
};
|
||||||
|
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
// Send server event to create npc
|
// Send server event to create npc
|
||||||
output_events.emit_server(ServerEvent::CreateNpc {
|
output_events.emit_server(ServerEvent::CreateNpc {
|
||||||
pos: comp::Pos(collision_vector - Vec3::unit_z() * obstacle_z),
|
pos: comp::Pos(
|
||||||
|
collision_vector - Vec3::unit_z() * obstacle_z + extra_height,
|
||||||
|
),
|
||||||
ori: comp::Ori::from(Dir::random_2d(&mut rng)),
|
ori: comp::Ori::from(Dir::random_2d(&mut rng)),
|
||||||
npc: NpcBuilder::new(stats, body, comp::Alignment::Owned(*data.uid))
|
npc: NpcBuilder::new(stats, body, comp::Alignment::Owned(*data.uid))
|
||||||
.with_skill_set(skill_set)
|
.with_skill_set(skill_set)
|
||||||
|
@ -9,9 +9,11 @@ use crate::{
|
|||||||
behavior::{CharacterBehavior, JoinData},
|
behavior::{CharacterBehavior, JoinData},
|
||||||
utils::{StageSection, *},
|
utils::{StageSection, *},
|
||||||
},
|
},
|
||||||
|
util::Dir,
|
||||||
};
|
};
|
||||||
|
use rand::{thread_rng, Rng};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::time::Duration;
|
use std::{f32::consts::TAU, time::Duration};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
/// Separated out to condense update portions of character state
|
/// Separated out to condense update portions of character state
|
||||||
@ -37,6 +39,19 @@ pub struct StaticData {
|
|||||||
pub ability_info: AbilityInfo,
|
pub ability_info: AbilityInfo,
|
||||||
/// Adds an effect onto the main damage of the attack
|
/// Adds an effect onto the main damage of the attack
|
||||||
pub damage_effect: Option<CombatEffect>,
|
pub damage_effect: Option<CombatEffect>,
|
||||||
|
/// Whether ablity should be casted from above as aoe or shoot projectiles
|
||||||
|
/// as normal
|
||||||
|
pub properties_of_aoe: Option<ProjectileOffset>,
|
||||||
|
/// Used to specify the attack to the frontend
|
||||||
|
pub specifier: Option<FrontendSpecifier>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct ProjectileOffset {
|
||||||
|
/// Radius of AOE
|
||||||
|
pub radius: f32,
|
||||||
|
/// Height of shooting point for AOE's projectiles
|
||||||
|
pub height: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
@ -94,10 +109,35 @@ impl CharacterBehavior for Data {
|
|||||||
let precision_mult = combat::compute_precision_mult(data.inventory, data.msm);
|
let precision_mult = combat::compute_precision_mult(data.inventory, data.msm);
|
||||||
let tool_stats = get_tool_stats(data, self.static_data.ability_info);
|
let tool_stats = get_tool_stats(data, self.static_data.ability_info);
|
||||||
// Gets offsets
|
// Gets offsets
|
||||||
let body_offsets = data
|
let pos: Pos = self.static_data.properties_of_aoe.as_ref().map_or_else(
|
||||||
.body
|
|| {
|
||||||
.projectile_offsets(update.ori.look_vec(), data.scale.map_or(1.0, |s| s.0));
|
// Default position
|
||||||
let pos = Pos(data.pos.0 + body_offsets);
|
let body_offsets = data.body.projectile_offsets(
|
||||||
|
update.ori.look_vec(),
|
||||||
|
data.scale.map_or(1.0, |s| s.0),
|
||||||
|
);
|
||||||
|
Pos(data.pos.0 + body_offsets)
|
||||||
|
},
|
||||||
|
|aoe_data| {
|
||||||
|
// Position calculated from aoe_data
|
||||||
|
let rand_pos = {
|
||||||
|
let mut rng = thread_rng();
|
||||||
|
let theta = rng.gen::<f32>() * TAU;
|
||||||
|
let radius = aoe_data.radius * rng.gen::<f32>().sqrt();
|
||||||
|
let x = radius * theta.sin();
|
||||||
|
let y = radius * theta.cos();
|
||||||
|
vek::Vec2::new(x, y)
|
||||||
|
};
|
||||||
|
Pos(data.pos.0 + rand_pos.with_z(aoe_data.height))
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
let direction: Dir = if self.static_data.properties_of_aoe.is_some() {
|
||||||
|
Dir::down()
|
||||||
|
} else {
|
||||||
|
data.inputs.look_dir
|
||||||
|
};
|
||||||
|
|
||||||
let projectile = self.static_data.projectile.create_projectile(
|
let projectile = self.static_data.projectile.create_projectile(
|
||||||
Some(*data.uid),
|
Some(*data.uid),
|
||||||
precision_mult,
|
precision_mult,
|
||||||
@ -107,7 +147,7 @@ impl CharacterBehavior for Data {
|
|||||||
output_events.emit_server(ServerEvent::Shoot {
|
output_events.emit_server(ServerEvent::Shoot {
|
||||||
entity: data.entity,
|
entity: data.entity,
|
||||||
pos,
|
pos,
|
||||||
dir: data.inputs.look_dir,
|
dir: direction,
|
||||||
body: self.static_data.projectile_body,
|
body: self.static_data.projectile_body,
|
||||||
projectile,
|
projectile,
|
||||||
light: self.static_data.projectile_light,
|
light: self.static_data.projectile_light,
|
||||||
@ -167,3 +207,8 @@ impl CharacterBehavior for Data {
|
|||||||
update
|
update
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
pub enum FrontendSpecifier {
|
||||||
|
FireRain,
|
||||||
|
}
|
||||||
|
@ -4,7 +4,8 @@ use crate::{
|
|||||||
character_state::OutputEvents,
|
character_state::OutputEvents,
|
||||||
CharacterState, StateUpdate,
|
CharacterState, StateUpdate,
|
||||||
},
|
},
|
||||||
event::ServerEvent,
|
event::{LocalEvent, ServerEvent},
|
||||||
|
outcome::Outcome,
|
||||||
resources::Secs,
|
resources::Secs,
|
||||||
states::{
|
states::{
|
||||||
behavior::{CharacterBehavior, JoinData},
|
behavior::{CharacterBehavior, JoinData},
|
||||||
@ -41,6 +42,8 @@ pub struct StaticData {
|
|||||||
pub enforced_limit: bool,
|
pub enforced_limit: bool,
|
||||||
/// 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 an outcome for the buff
|
||||||
|
pub specifier: Option<FrontendSpecifier>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
@ -145,6 +148,12 @@ impl CharacterBehavior for Data {
|
|||||||
timer: tick_attack_or_default(data, self.timer, None),
|
timer: tick_attack_or_default(data, self.timer, None),
|
||||||
..*self
|
..*self
|
||||||
});
|
});
|
||||||
|
if let Some(FrontendSpecifier::FromTheAshes) = self.static_data.specifier {
|
||||||
|
// Send local event used for frontend shenanigans
|
||||||
|
output_events.emit_local(LocalEvent::CreateOutcome(
|
||||||
|
Outcome::FromTheAshes { pos: data.pos.0 },
|
||||||
|
));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
update.character = CharacterState::SelfBuff(Data {
|
update.character = CharacterState::SelfBuff(Data {
|
||||||
timer: Duration::default(),
|
timer: Duration::default(),
|
||||||
@ -176,3 +185,8 @@ impl CharacterBehavior for Data {
|
|||||||
update
|
update
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// Used to specify a particular effect for frontend purposes
|
||||||
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
pub enum FrontendSpecifier {
|
||||||
|
FromTheAshes,
|
||||||
|
}
|
||||||
|
@ -211,35 +211,52 @@ impl Data {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (site_id, site) in this.sites.iter()
|
for (site_id, site) in this.sites.iter() {
|
||||||
// TODO: Stupid
|
|
||||||
.filter(|(_, site)| site.world_site.map_or(false, |ws|
|
|
||||||
matches!(&index.sites.get(ws).kind, SiteKind::Dungeon(_))))
|
|
||||||
{
|
|
||||||
let rand_wpos = |rng: &mut SmallRng| {
|
let rand_wpos = |rng: &mut SmallRng| {
|
||||||
let wpos2d = site.wpos.map(|e| e + rng.gen_range(-10..10));
|
// don't spawn in buildings
|
||||||
|
let spread_factor = rng.gen_range(-3..3) * 50;
|
||||||
|
let spread = if spread_factor == 0 {
|
||||||
|
100
|
||||||
|
} else {
|
||||||
|
spread_factor
|
||||||
|
};
|
||||||
|
let wpos2d = site.wpos.map(|e| e + spread);
|
||||||
wpos2d
|
wpos2d
|
||||||
.map(|e| e as f32 + 0.5)
|
.map(|e| e as f32 + 0.5)
|
||||||
.with_z(world.sim().get_alt_approx(wpos2d).unwrap_or(0.0))
|
.with_z(world.sim().get_alt_approx(wpos2d).unwrap_or(0.0))
|
||||||
};
|
};
|
||||||
|
let site_kind = site.world_site.map(|ws| &index.sites.get(ws).kind);
|
||||||
let species = [
|
let Some(species) = [
|
||||||
comp::body::bird_large::Species::Phoenix,
|
Some(comp::body::bird_large::Species::Phoenix)
|
||||||
comp::body::bird_large::Species::Cockatrice,
|
.filter(|_| matches!(site_kind, Some(SiteKind::Dungeon(_)))),
|
||||||
comp::body::bird_large::Species::Roc,
|
Some(comp::body::bird_large::Species::Cockatrice)
|
||||||
comp::body::bird_large::Species::FlameWyvern,
|
.filter(|_| matches!(site_kind, Some(SiteKind::Dungeon(_)))),
|
||||||
comp::body::bird_large::Species::CloudWyvern,
|
Some(comp::body::bird_large::Species::Roc)
|
||||||
comp::body::bird_large::Species::FrostWyvern,
|
.filter(|_| matches!(site_kind, Some(SiteKind::Dungeon(_)))),
|
||||||
comp::body::bird_large::Species::SeaWyvern,
|
Some(comp::body::bird_large::Species::FlameWyvern)
|
||||||
comp::body::bird_large::Species::WealdWyvern,
|
.filter(|_| matches!(site_kind, Some(SiteKind::Dungeon(_)))),
|
||||||
|
Some(comp::body::bird_large::Species::CloudWyvern)
|
||||||
|
.filter(|_| matches!(site_kind, Some(SiteKind::Dungeon(_)))),
|
||||||
|
Some(comp::body::bird_large::Species::FrostWyvern)
|
||||||
|
.filter(|_| matches!(site_kind, Some(SiteKind::Adlet(_)))),
|
||||||
|
Some(comp::body::bird_large::Species::SeaWyvern)
|
||||||
|
.filter(|_| matches!(site_kind, Some(SiteKind::ChapelSite(_)))),
|
||||||
|
Some(comp::body::bird_large::Species::WealdWyvern)
|
||||||
|
.filter(|_| matches!(site_kind, Some(SiteKind::GiantTree(_)))),
|
||||||
]
|
]
|
||||||
.choose(&mut rng)
|
.into_iter()
|
||||||
.unwrap();
|
.flatten()
|
||||||
|
.choose(&mut rng) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
this.npcs.create_npc(
|
this.npcs.create_npc(
|
||||||
Npc::new(
|
Npc::new(
|
||||||
rng.gen(),
|
rng.gen(),
|
||||||
rand_wpos(&mut rng),
|
rand_wpos(&mut rng),
|
||||||
Body::BirdLarge(comp::body::bird_large::Body::random_with(&mut rng, species)),
|
Body::BirdLarge(comp::body::bird_large::Body::random_with(
|
||||||
|
&mut rng, &species,
|
||||||
|
)),
|
||||||
Role::Wild,
|
Role::Wild,
|
||||||
)
|
)
|
||||||
.with_home(site_id),
|
.with_home(site_id),
|
||||||
|
@ -16,7 +16,7 @@ use crate::{
|
|||||||
use common::{
|
use common::{
|
||||||
astar::{Astar, PathResult},
|
astar::{Astar, PathResult},
|
||||||
comp::{
|
comp::{
|
||||||
self,
|
self, bird_large,
|
||||||
compass::{Direction, Distance},
|
compass::{Direction, Distance},
|
||||||
dialogue::Subject,
|
dialogue::Subject,
|
||||||
Content,
|
Content,
|
||||||
@ -1210,15 +1210,21 @@ fn bird_large() -> impl Action<DefaultState> {
|
|||||||
.map(|e| e + ctx.rng.gen_range(-0.1..0.1))
|
.map(|e| e + ctx.rng.gen_range(-0.1..0.1))
|
||||||
.try_normalized()
|
.try_normalized()
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
let bearing_dist = 24.0;
|
let bearing_dist = 15.0;
|
||||||
let mut pos = ctx.npc.wpos.xy() + *bearing * bearing_dist;
|
let mut pos = ctx.npc.wpos.xy() + *bearing * bearing_dist;
|
||||||
let is_deep_water = ctx
|
let is_deep_water =
|
||||||
|
matches!(ctx.npc.body, common::comp::Body::BirdLarge(b) if matches!(b.species, bird_large::Species::SeaWyvern))
|
||||||
|
|| ctx
|
||||||
.world
|
.world
|
||||||
.sim()
|
.sim()
|
||||||
.get(pos.as_().wpos_to_cpos())
|
.get(pos.as_().wpos_to_cpos())
|
||||||
.map_or(true, |c| {
|
.map_or(true, |c| {
|
||||||
c.alt - c.water_alt < -120.0 && (c.river.is_ocean() || c.river.is_lake())
|
c.alt - c.water_alt < -120.0 && (c.river.is_ocean() || c.river.is_lake())
|
||||||
});
|
});
|
||||||
|
if is_deep_water {
|
||||||
|
*bearing *= -1.0;
|
||||||
|
pos = ctx.npc.wpos.xy() + *bearing * bearing_dist;
|
||||||
|
};
|
||||||
// when high tree_density fly high, otherwise fly low-mid
|
// when high tree_density fly high, otherwise fly low-mid
|
||||||
let npc_pos = ctx.npc.wpos.xy();
|
let npc_pos = ctx.npc.wpos.xy();
|
||||||
let trees = ctx
|
let trees = ctx
|
||||||
@ -1231,35 +1237,56 @@ fn bird_large() -> impl Action<DefaultState> {
|
|||||||
} else {
|
} else {
|
||||||
ctx.rng.gen_range(0.4..0.9)
|
ctx.rng.gen_range(0.4..0.9)
|
||||||
};
|
};
|
||||||
if !is_deep_water {
|
|
||||||
goto_2d_flying(
|
|
||||||
pos,
|
|
||||||
0.1,
|
|
||||||
bearing_dist,
|
|
||||||
8.0,
|
|
||||||
8.0,
|
|
||||||
ctx.npc.body.flying_height() * height_factor,
|
|
||||||
)
|
|
||||||
|
|
||||||
} else {
|
let data = ctx.state.data();
|
||||||
*bearing *= -1.0;
|
// without destination site fly to next waypoint
|
||||||
|
let mut dest_site = pos;
|
||||||
pos = ctx.npc.wpos.xy() + *bearing * 24.0;
|
if let Some(home) = ctx.npc.home {
|
||||||
|
let is_home = ctx.npc.current_site.map_or(false, |site| home == site);
|
||||||
goto_2d_flying(
|
if is_home {
|
||||||
pos,
|
if let Some((id, _)) = data
|
||||||
0.1,
|
.sites
|
||||||
bearing_dist,
|
.iter()
|
||||||
8.0,
|
.filter(|(id, site)| {
|
||||||
8.0,
|
*id != home
|
||||||
ctx.npc.body.flying_height() * height_factor,
|
&& site.world_site.map_or(false, |site| {
|
||||||
)
|
match ctx.npc.body {
|
||||||
|
common::comp::Body::BirdLarge(b) => match b.species {
|
||||||
|
bird_large::Species::SeaWyvern => matches!(&ctx.index.sites.get(site).kind, SiteKind::ChapelSite(_)),
|
||||||
|
bird_large::Species::FrostWyvern => matches!(&ctx.index.sites.get(site).kind, SiteKind::Adlet(_)),
|
||||||
|
bird_large::Species::WealdWyvern => matches!(&ctx.index.sites.get(site).kind, SiteKind::GiantTree(_)),
|
||||||
|
_ => matches!(&ctx.index.sites.get(site).kind, SiteKind::Dungeon(_)),
|
||||||
|
},
|
||||||
|
_ => matches!(&ctx.index.sites.get(site).kind, SiteKind::Dungeon(_)),
|
||||||
}
|
}
|
||||||
// If we are too far away from our goal position we can stop since we aren't going to a specific place.
|
})
|
||||||
|
})
|
||||||
|
/*choose closest destination:
|
||||||
|
.min_by_key(|(_, site)| site.wpos.as_().distance(npc_pos) as i32)*/
|
||||||
|
//choose random destination:
|
||||||
|
.choose(&mut ctx.rng)
|
||||||
|
{
|
||||||
|
ctx.controller.set_new_home(id)
|
||||||
|
}
|
||||||
|
} else if let Some(site) = data.sites.get(home) {
|
||||||
|
dest_site = site.wpos.as_::<f32>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 waypoint position we can stop since we aren't going to a specific place.
|
||||||
|
// If waypoint position is further away from destination site find a new waypoint
|
||||||
.stop_if(move |ctx: &mut NpcCtx| {
|
.stop_if(move |ctx: &mut NpcCtx| {
|
||||||
ctx.npc.wpos.xy().distance_squared(pos) > (bearing_dist + 5.0).powi(2)
|
ctx.npc.wpos.xy().distance_squared(pos) > (bearing_dist + 5.0).powi(2)
|
||||||
|
|| dest_site.distance_squared(pos) > dest_site.distance_squared(npc_pos)
|
||||||
})
|
})
|
||||||
// If goal position wasn't reached within 20 seconds we're probably stuck and need to find a new goal position.
|
// If waypoint position wasn't reached within 10 seconds we're probably stuck and need to find a new waypoint.
|
||||||
.stop_if(timeout(10.0))
|
.stop_if(timeout(10.0))
|
||||||
.debug({
|
.debug({
|
||||||
let bearing = *bearing;
|
let bearing = *bearing;
|
||||||
|
@ -1075,6 +1075,7 @@ impl<'a> AgentData<'a> {
|
|||||||
| "Gnarling Totem Red"
|
| "Gnarling Totem Red"
|
||||||
| "Gnarling Totem Green"
|
| "Gnarling Totem Green"
|
||||||
| "Gnarling Totem White" => Tactic::RadialTurret,
|
| "Gnarling Totem White" => Tactic::RadialTurret,
|
||||||
|
"FieryTornado" => Tactic::FieryTornado,
|
||||||
"Yeti" => Tactic::Yeti,
|
"Yeti" => Tactic::Yeti,
|
||||||
"Harvester" => Tactic::Harvester,
|
"Harvester" => Tactic::Harvester,
|
||||||
"Cardinal" => Tactic::Cardinal,
|
"Cardinal" => Tactic::Cardinal,
|
||||||
@ -1500,6 +1501,7 @@ impl<'a> AgentData<'a> {
|
|||||||
read_data,
|
read_data,
|
||||||
),
|
),
|
||||||
Tactic::RadialTurret => self.handle_radial_turret_attack(controller),
|
Tactic::RadialTurret => self.handle_radial_turret_attack(controller),
|
||||||
|
Tactic::FieryTornado => self.handle_fiery_tornado_attack(agent, controller),
|
||||||
Tactic::Yeti => {
|
Tactic::Yeti => {
|
||||||
self.handle_yeti_attack(agent, controller, &attack_data, tgt_data, read_data)
|
self.handle_yeti_attack(agent, controller, &attack_data, tgt_data, read_data)
|
||||||
},
|
},
|
||||||
|
@ -2678,6 +2678,23 @@ impl<'a> AgentData<'a> {
|
|||||||
controller.push_basic_input(InputKind::Primary);
|
controller.push_basic_input(InputKind::Primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn handle_fiery_tornado_attack(&self, agent: &mut Agent, controller: &mut Controller) {
|
||||||
|
enum Conditions {
|
||||||
|
AuraEmited = 0,
|
||||||
|
}
|
||||||
|
if matches!(self.char_state, CharacterState::BasicAura(c) if matches!(c.stage_section, StageSection::Recover))
|
||||||
|
{
|
||||||
|
agent.combat_state.conditions[Conditions::AuraEmited as usize] = true;
|
||||||
|
}
|
||||||
|
// 1 time use of aura
|
||||||
|
if !agent.combat_state.conditions[Conditions::AuraEmited as usize] {
|
||||||
|
controller.push_basic_input(InputKind::Secondary);
|
||||||
|
} else {
|
||||||
|
// Spin
|
||||||
|
controller.push_basic_input(InputKind::Primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn handle_mindflayer_attack(
|
pub fn handle_mindflayer_attack(
|
||||||
&self,
|
&self,
|
||||||
agent: &mut Agent,
|
agent: &mut Agent,
|
||||||
@ -2975,106 +2992,141 @@ impl<'a> AgentData<'a> {
|
|||||||
read_data: &ReadData,
|
read_data: &ReadData,
|
||||||
_rng: &mut impl Rng,
|
_rng: &mut impl Rng,
|
||||||
) {
|
) {
|
||||||
|
const PHOENIX_HEAL_THRESHOLD: f32 = 0.20;
|
||||||
|
|
||||||
|
enum Conditions {
|
||||||
|
Healed = 0,
|
||||||
|
}
|
||||||
enum ActionStateTimers {
|
enum ActionStateTimers {
|
||||||
AttackTimer = 0,
|
AttackTimer1,
|
||||||
|
AttackTimer2,
|
||||||
}
|
}
|
||||||
// Set fly to false
|
|
||||||
controller.push_cancel_input(InputKind::Fly);
|
let attack_timer_1 =
|
||||||
if attack_data.dist_sqrd > 30.0_f32.powi(2) {
|
if agent.combat_state.timers[ActionStateTimers::AttackTimer1 as usize] < 2.0 {
|
||||||
if entities_have_line_of_sight(
|
0
|
||||||
self.pos,
|
} else if agent.combat_state.timers[ActionStateTimers::AttackTimer1 as usize] < 4.0 {
|
||||||
self.body,
|
1
|
||||||
self.scale,
|
} else if agent.combat_state.timers[ActionStateTimers::AttackTimer1 as usize] < 6.0 {
|
||||||
tgt_data.pos,
|
2
|
||||||
tgt_data.body,
|
} else {
|
||||||
tgt_data.scale,
|
3
|
||||||
read_data,
|
};
|
||||||
) && attack_data.angle < 15.0
|
agent.combat_state.timers[ActionStateTimers::AttackTimer1 as usize] += read_data.dt.0;
|
||||||
{
|
if agent.combat_state.timers[ActionStateTimers::AttackTimer1 as usize] > 8.0 {
|
||||||
controller.push_basic_input(InputKind::Primary);
|
// Reset timer
|
||||||
|
agent.combat_state.timers[ActionStateTimers::AttackTimer1 as usize] = 0.0;
|
||||||
}
|
}
|
||||||
if let Some((bearing, speed)) = agent.chaser.chase(
|
let (attack_timer_2, speed) =
|
||||||
&*read_data.terrain,
|
if agent.combat_state.timers[ActionStateTimers::AttackTimer2 as usize] < 3.0 {
|
||||||
self.pos.0,
|
// fly high
|
||||||
self.vel.0,
|
(0, 2.0)
|
||||||
tgt_data.pos.0,
|
} else if agent.combat_state.timers[ActionStateTimers::AttackTimer2 as usize] < 6.0 {
|
||||||
TraversalConfig {
|
// attack_mid_1
|
||||||
min_tgt_dist: 1.25,
|
(1, 2.0)
|
||||||
..self.traversal_config
|
} else if agent.combat_state.timers[ActionStateTimers::AttackTimer2 as usize] < 9.0 {
|
||||||
},
|
// fly high
|
||||||
) {
|
(0, 3.0)
|
||||||
controller.inputs.move_dir =
|
} else if agent.combat_state.timers[ActionStateTimers::AttackTimer2 as usize] < 16.0 {
|
||||||
bearing.xy().try_normalized().unwrap_or_else(Vec2::zero) * speed;
|
// attack_mid_2
|
||||||
if (self.pos.0.z - tgt_data.pos.0.z) < 20.0 {
|
(2, 1.0)
|
||||||
|
} else if agent.combat_state.timers[ActionStateTimers::AttackTimer2 as usize] < 20.0 {
|
||||||
|
// fly low
|
||||||
|
(5, 20.0)
|
||||||
|
} else {
|
||||||
|
// attack_close
|
||||||
|
(3, 1.0)
|
||||||
|
};
|
||||||
|
agent.combat_state.timers[ActionStateTimers::AttackTimer2 as usize] += read_data.dt.0;
|
||||||
|
if agent.combat_state.timers[ActionStateTimers::AttackTimer2 as usize] > 28.0 {
|
||||||
|
// Reset timer
|
||||||
|
agent.combat_state.timers[ActionStateTimers::AttackTimer2 as usize] = 0.0;
|
||||||
|
}
|
||||||
|
// 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);
|
||||||
|
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);
|
controller.push_basic_input(InputKind::Fly);
|
||||||
controller.inputs.move_z = 1.0;
|
// 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.
|
||||||
} else if !read_data
|
if self.physics_state.on_ground.is_some() {
|
||||||
|
controller.push_basic_input(InputKind::Jump);
|
||||||
|
} else {
|
||||||
|
// Use a proportional controller with a coefficient of 1.0 to
|
||||||
|
// maintain altidude at the the provided set point
|
||||||
|
let mut maintain_altitude = |set_point| {
|
||||||
|
let alt = read_data
|
||||||
.terrain
|
.terrain
|
||||||
.ray(self.pos.0, self.pos.0 - (Vec3::unit_z() * 2.0))
|
.ray(self.pos.0, self.pos.0 - (Vec3::unit_z() * 7.0))
|
||||||
.until(Block::is_solid)
|
.until(Block::is_solid)
|
||||||
.cast()
|
.cast()
|
||||||
.1
|
.0;
|
||||||
.map_or(true, |b| b.is_some())
|
let error = set_point - alt;
|
||||||
|
controller.inputs.move_z = error;
|
||||||
|
};
|
||||||
|
// heal once - from_the_ashes
|
||||||
|
let health_fraction = self.health.map_or(0.5, |h| h.fraction());
|
||||||
|
if matches!(self.char_state, CharacterState::SelfBuff(c) if matches!(c.stage_section, StageSection::Recover))
|
||||||
{
|
{
|
||||||
// Do not increment the timer during this movement
|
agent.combat_state.conditions[Conditions::Healed as usize] = true;
|
||||||
// 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) {
|
if !agent.combat_state.conditions[Conditions::Healed as usize]
|
||||||
self.path_toward_target(
|
&& PHOENIX_HEAL_THRESHOLD > health_fraction
|
||||||
agent,
|
|
||||||
controller,
|
|
||||||
tgt_data.pos.0,
|
|
||||||
read_data,
|
|
||||||
Path::Separate,
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
} else if self.energy.current() > 60.0
|
|
||||||
&& agent.combat_state.timers[ActionStateTimers::AttackTimer as usize] < 3.0
|
|
||||||
&& attack_data.angle < 15.0
|
|
||||||
{
|
{
|
||||||
// Shockwave
|
controller.push_basic_input(InputKind::Ability(4));
|
||||||
controller.push_basic_input(InputKind::Ability(0));
|
} else if (tgt_data.pos.0 - self.pos.0).xy().magnitude_squared() > (35.0_f32).powi(2) {
|
||||||
// Move towards the target slowly
|
// heat laser
|
||||||
self.path_toward_target(
|
maintain_altitude(2.0);
|
||||||
agent,
|
controller.push_basic_input(InputKind::Ability(3))
|
||||||
controller,
|
|
||||||
tgt_data.pos.0,
|
|
||||||
read_data,
|
|
||||||
Path::Separate,
|
|
||||||
Some(0.5),
|
|
||||||
);
|
|
||||||
agent.combat_state.timers[ActionStateTimers::AttackTimer as usize] += read_data.dt.0;
|
|
||||||
} else if agent.combat_state.timers[ActionStateTimers::AttackTimer as usize] < 6.0
|
|
||||||
&& attack_data.angle < 90.0
|
|
||||||
&& attack_data.in_min_range()
|
|
||||||
{
|
|
||||||
// Triple strike
|
|
||||||
controller.push_basic_input(InputKind::Secondary);
|
|
||||||
agent.combat_state.timers[ActionStateTimers::AttackTimer as usize] += read_data.dt.0;
|
|
||||||
} else {
|
} else {
|
||||||
// Reset timer
|
match attack_timer_2 {
|
||||||
agent.combat_state.timers[ActionStateTimers::AttackTimer as usize] = 0.0;
|
0 => maintain_altitude(3.0),
|
||||||
// Target is behind us or the timer needs to be reset. Chase target
|
1 => {
|
||||||
self.path_toward_target(
|
//summontornados
|
||||||
agent,
|
controller.push_basic_input(InputKind::Ability(1));
|
||||||
controller,
|
},
|
||||||
tgt_data.pos.0,
|
2 => {
|
||||||
read_data,
|
// firerain
|
||||||
Path::Separate,
|
controller.push_basic_input(InputKind::Ability(2));
|
||||||
None,
|
},
|
||||||
);
|
3 => {
|
||||||
|
if attack_data.dist_sqrd < 4.0_f32.powi(2) && attack_data.angle < 150.0 {
|
||||||
|
// close range attack
|
||||||
|
match attack_timer_1 {
|
||||||
|
1 => {
|
||||||
|
// short strike
|
||||||
|
controller.push_basic_input(InputKind::Primary);
|
||||||
|
},
|
||||||
|
3 => {
|
||||||
|
// long strike
|
||||||
|
controller.push_basic_input(InputKind::Secondary)
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
// leg strike
|
||||||
|
controller.push_basic_input(InputKind::Ability(0))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match attack_timer_1 {
|
||||||
|
0 | 2 => {
|
||||||
|
maintain_altitude(2.0);
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
// heat laser
|
||||||
|
controller.push_basic_input(InputKind::Ability(3))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
maintain_altitude(2.0);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,6 +176,7 @@ pub enum Tactic {
|
|||||||
FixedTurret,
|
FixedTurret,
|
||||||
RotatingTurret,
|
RotatingTurret,
|
||||||
RadialTurret,
|
RadialTurret,
|
||||||
|
FieryTornado,
|
||||||
SimpleDouble,
|
SimpleDouble,
|
||||||
// u8s are weights that each ability gets used, if it can be used
|
// u8s are weights that each ability gets used, if it can be used
|
||||||
RandomAbilities {
|
RandomAbilities {
|
||||||
|
@ -162,7 +162,7 @@ fn get_npc_entity_info(npc: &Npc, sites: &Sites, index: IndexRef) -> EntityInfo
|
|||||||
} else {
|
} else {
|
||||||
let config_asset = match npc.body {
|
let config_asset = match npc.body {
|
||||||
Body::BirdLarge(body) => match body.species {
|
Body::BirdLarge(body) => match body.species {
|
||||||
comp::bird_large::Species::Phoenix => "common.entity.wild.peaceful.phoenix",
|
comp::bird_large::Species::Phoenix => "common.entity.wild.aggressive.phoenix",
|
||||||
comp::bird_large::Species::Cockatrice => "common.entity.wild.aggressive.cockatrice",
|
comp::bird_large::Species::Cockatrice => "common.entity.wild.aggressive.cockatrice",
|
||||||
comp::bird_large::Species::Roc => "common.entity.wild.aggressive.roc",
|
comp::bird_large::Species::Roc => "common.entity.wild.aggressive.roc",
|
||||||
comp::bird_large::Species::CloudWyvern => {
|
comp::bird_large::Species::CloudWyvern => {
|
||||||
|
93
voxygen/anim/src/bird_large/aura.rs
Normal file
93
voxygen/anim/src/bird_large/aura.rs
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
use super::{
|
||||||
|
super::{vek::*, Animation},
|
||||||
|
BirdLargeSkeleton, SkeletonAttr,
|
||||||
|
};
|
||||||
|
use common::states::utils::StageSection;
|
||||||
|
|
||||||
|
pub struct AuraAnimation;
|
||||||
|
|
||||||
|
impl Animation for AuraAnimation {
|
||||||
|
type Dependency<'a> = (Option<StageSection>, bool);
|
||||||
|
type Skeleton = BirdLargeSkeleton;
|
||||||
|
|
||||||
|
#[cfg(feature = "use-dyn-lib")]
|
||||||
|
const UPDATE_FN: &'static [u8] = b"bird_large_aura\0";
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "be-dyn-lib", export_name = "bird_large_aura")]
|
||||||
|
fn update_skeleton_inner(
|
||||||
|
skeleton: &Self::Skeleton,
|
||||||
|
(stage_section, on_ground): Self::Dependency<'_>,
|
||||||
|
anim_time: f32,
|
||||||
|
_rate: &mut f32,
|
||||||
|
s_a: &SkeletonAttr,
|
||||||
|
) -> Self::Skeleton {
|
||||||
|
let mut next = (*skeleton).clone();
|
||||||
|
|
||||||
|
let (movement1base, movement2base, movement3, _twitch) = match stage_section {
|
||||||
|
Some(StageSection::Buildup) => (anim_time.powf(0.5), 0.0, 0.0, 0.0),
|
||||||
|
Some(StageSection::Action) => (1.0, anim_time.min(1.0).powf(0.1), 0.0, anim_time),
|
||||||
|
Some(StageSection::Recover) => (1.0, 1.0, anim_time, 1.0),
|
||||||
|
_ => (0.0, 0.0, 0.0, 0.0),
|
||||||
|
};
|
||||||
|
|
||||||
|
let pullback = 1.0 - movement3;
|
||||||
|
|
||||||
|
let movement1abs = movement1base * pullback;
|
||||||
|
let _movement2abs = movement2base * pullback;
|
||||||
|
|
||||||
|
let wave_slow_cos = (anim_time * 4.5).cos();
|
||||||
|
|
||||||
|
next.chest.position = Vec3::new(0.0, s_a.chest.0, s_a.chest.1 + movement1abs * 1.5);
|
||||||
|
next.chest.orientation = Quaternion::rotation_x(movement1abs * 1.0);
|
||||||
|
|
||||||
|
next.neck.position = Vec3::new(0.0, s_a.neck.0, s_a.neck.1);
|
||||||
|
next.neck.orientation = Quaternion::rotation_x(-0.2);
|
||||||
|
|
||||||
|
next.head.position = Vec3::new(0.0, s_a.head.0, s_a.head.1);
|
||||||
|
next.head.orientation = Quaternion::rotation_x(wave_slow_cos * 0.01);
|
||||||
|
|
||||||
|
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 - 0.02);
|
||||||
|
|
||||||
|
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(0.6);
|
||||||
|
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.2);
|
||||||
|
|
||||||
|
if on_ground {
|
||||||
|
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(-0.8 + movement1abs * 1.5)
|
||||||
|
* Quaternion::rotation_z(0.2 + movement1abs * -0.8);
|
||||||
|
next.wing_in_r.orientation = Quaternion::rotation_y(0.8 + movement1abs * -1.5)
|
||||||
|
* Quaternion::rotation_z(-0.2 + movement1abs * 0.8);
|
||||||
|
|
||||||
|
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) * Quaternion::rotation_z(0.7);
|
||||||
|
next.wing_mid_r.orientation =
|
||||||
|
Quaternion::rotation_y(0.1) * Quaternion::rotation_z(-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.4) * Quaternion::rotation_z(0.2);
|
||||||
|
next.wing_out_r.orientation =
|
||||||
|
Quaternion::rotation_y(0.4) * Quaternion::rotation_z(-0.2);
|
||||||
|
|
||||||
|
next.leg_l.position = Vec3::new(-s_a.leg.0, s_a.leg.1, s_a.leg.2);
|
||||||
|
next.leg_l.orientation = Quaternion::rotation_x(0.0);
|
||||||
|
next.leg_r.position = Vec3::new(s_a.leg.0, s_a.leg.1, s_a.leg.2);
|
||||||
|
next.leg_r.orientation = Quaternion::rotation_x(0.0);
|
||||||
|
|
||||||
|
next.foot_l.position = Vec3::new(-s_a.foot.0, s_a.foot.1, s_a.foot.2);
|
||||||
|
next.foot_l.orientation = Quaternion::rotation_x(0.0);
|
||||||
|
next.foot_r.position = Vec3::new(s_a.foot.0, s_a.foot.1, s_a.foot.2);
|
||||||
|
next.foot_r.orientation = Quaternion::rotation_x(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
next
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,7 @@ use common::{states::utils::StageSection, util::Dir};
|
|||||||
|
|
||||||
pub struct BreatheAnimation;
|
pub struct BreatheAnimation;
|
||||||
|
|
||||||
type BreatheAnimationDependency = (
|
type BreatheAnimationDependency<'a> = (
|
||||||
Vec3<f32>,
|
Vec3<f32>,
|
||||||
f32,
|
f32,
|
||||||
Vec3<f32>,
|
Vec3<f32>,
|
||||||
@ -15,10 +15,11 @@ type BreatheAnimationDependency = (
|
|||||||
f32,
|
f32,
|
||||||
Dir,
|
Dir,
|
||||||
bool,
|
bool,
|
||||||
|
Option<&'a str>,
|
||||||
);
|
);
|
||||||
|
|
||||||
impl Animation for BreatheAnimation {
|
impl Animation for BreatheAnimation {
|
||||||
type Dependency<'a> = BreatheAnimationDependency;
|
type Dependency<'a> = BreatheAnimationDependency<'a>;
|
||||||
type Skeleton = BirdLargeSkeleton;
|
type Skeleton = BirdLargeSkeleton;
|
||||||
|
|
||||||
#[cfg(feature = "use-dyn-lib")]
|
#[cfg(feature = "use-dyn-lib")]
|
||||||
@ -27,7 +28,17 @@ impl Animation for BreatheAnimation {
|
|||||||
#[cfg_attr(feature = "be-dyn-lib", export_name = "bird_large_breathe")]
|
#[cfg_attr(feature = "be-dyn-lib", export_name = "bird_large_breathe")]
|
||||||
fn update_skeleton_inner(
|
fn update_skeleton_inner(
|
||||||
skeleton: &Self::Skeleton,
|
skeleton: &Self::Skeleton,
|
||||||
(velocity,global_time, _orientation, _last_ori, stage_section, timer, look_dir, on_ground): Self::Dependency<'_>,
|
(
|
||||||
|
velocity,
|
||||||
|
global_time,
|
||||||
|
_orientation,
|
||||||
|
_last_ori,
|
||||||
|
stage_section,
|
||||||
|
timer,
|
||||||
|
look_dir,
|
||||||
|
on_ground,
|
||||||
|
ability_id,
|
||||||
|
): Self::Dependency<'_>,
|
||||||
anim_time: f32,
|
anim_time: f32,
|
||||||
_rate: &mut f32,
|
_rate: &mut f32,
|
||||||
s_a: &SkeletonAttr,
|
s_a: &SkeletonAttr,
|
||||||
@ -106,6 +117,13 @@ impl Animation for BreatheAnimation {
|
|||||||
next.tail_rear.orientation =
|
next.tail_rear.orientation =
|
||||||
Quaternion::rotation_x(-movement1abs * 0.1 + movement2abs * 0.1 + twitch2 * -0.2);
|
Quaternion::rotation_x(-movement1abs * 0.1 + movement2abs * 0.1 + twitch2 * -0.2);
|
||||||
} else {
|
} else {
|
||||||
|
match ability_id {
|
||||||
|
Some("common.abilities.custom.birdlargefire.heat_laser") => {
|
||||||
|
next.chest.orientation = Quaternion::rotation_x(
|
||||||
|
movement1abs * 0.2 - movement2abs * 0.5 + twitch2 * 0.03,
|
||||||
|
);
|
||||||
|
next.chest.position =
|
||||||
|
Vec3::new(0.0, s_a.chest.0, s_a.chest.1 + movement2abs * -3.0);
|
||||||
next.neck.orientation = Quaternion::rotation_x(
|
next.neck.orientation = Quaternion::rotation_x(
|
||||||
movement1abs * -0.4
|
movement1abs * -0.4
|
||||||
+ movement2abs * (-0.5 + velocity.xy().magnitude() * 0.2).min(0.0),
|
+ movement2abs * (-0.5 + velocity.xy().magnitude() * 0.2).min(0.0),
|
||||||
@ -116,8 +134,21 @@ impl Animation for BreatheAnimation {
|
|||||||
+ movement2abs * (-0.5 + velocity.xy().magnitude() * 0.2).min(0.0)
|
+ movement2abs * (-0.5 + velocity.xy().magnitude() * 0.2).min(0.0)
|
||||||
+ look_dir.z * 0.4,
|
+ look_dir.z * 0.4,
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
|
_ => {
|
||||||
|
next.neck.orientation = Quaternion::rotation_x(
|
||||||
|
movement1abs * -0.4
|
||||||
|
+ movement2abs * (-0.5 + velocity.xy().magnitude() * 0.2).min(0.0),
|
||||||
|
);
|
||||||
|
|
||||||
|
next.head.orientation = Quaternion::rotation_x(
|
||||||
|
movement1abs * 0.5
|
||||||
|
+ movement2abs * (-0.5 + velocity.xy().magnitude() * 0.2).min(0.0)
|
||||||
|
+ look_dir.z * 0.4,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
next
|
next
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ impl Animation for ComboAnimation {
|
|||||||
fn update_skeleton_inner(
|
fn update_skeleton_inner(
|
||||||
skeleton: &Self::Skeleton,
|
skeleton: &Self::Skeleton,
|
||||||
(
|
(
|
||||||
_ability_id,
|
ability_id,
|
||||||
stage_section,
|
stage_section,
|
||||||
current_strike,
|
current_strike,
|
||||||
global_time,
|
global_time,
|
||||||
@ -79,7 +79,21 @@ impl Animation for ComboAnimation {
|
|||||||
} * 1.3;
|
} * 1.3;
|
||||||
|
|
||||||
for strike in 0..=current_strike {
|
for strike in 0..=current_strike {
|
||||||
match strike {
|
match ability_id {
|
||||||
|
Some("common.abilities.custom.birdlargefire.legstrike") => 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.leg_r.orientation = Quaternion::rotation_x(move1 * 1.5 + move2 * -2.5);
|
||||||
|
next.leg_l.orientation = Quaternion::rotation_x(move1 * 1.5 + move2 * -2.5);
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
},
|
||||||
|
_ => match strike {
|
||||||
0..=2 => {
|
0..=2 => {
|
||||||
next.chest.position = Vec3::new(
|
next.chest.position = Vec3::new(
|
||||||
0.0,
|
0.0,
|
||||||
@ -98,14 +112,16 @@ impl Animation for ComboAnimation {
|
|||||||
* Quaternion::rotation_y(move1mirror * 0.5);
|
* Quaternion::rotation_y(move1mirror * 0.5);
|
||||||
|
|
||||||
next.beak.position = Vec3::new(0.0, s_a.beak.0, s_a.beak.1);
|
next.beak.position = Vec3::new(0.0, s_a.beak.0, s_a.beak.1);
|
||||||
next.beak.orientation =
|
next.beak.orientation = Quaternion::rotation_x(
|
||||||
Quaternion::rotation_x(wave_slow_cos * -0.02 + move1 * -0.5 + move2 * 0.5);
|
wave_slow_cos * -0.02 + move1 * -0.5 + move2 * 0.5,
|
||||||
|
);
|
||||||
|
|
||||||
if on_ground {
|
if on_ground {
|
||||||
next.tail_front.position =
|
next.tail_front.position =
|
||||||
Vec3::new(0.0, s_a.tail_front.0, s_a.tail_front.1);
|
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_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.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.tail_rear.orientation = Quaternion::rotation_x(0.0);
|
||||||
|
|
||||||
next.wing_in_l.position =
|
next.wing_in_l.position =
|
||||||
@ -124,7 +140,8 @@ impl Animation for ComboAnimation {
|
|||||||
Vec3::new(-s_a.wing_mid.0, s_a.wing_mid.1, s_a.wing_mid.2);
|
Vec3::new(-s_a.wing_mid.0, s_a.wing_mid.1, s_a.wing_mid.2);
|
||||||
next.wing_mid_r.position =
|
next.wing_mid_r.position =
|
||||||
Vec3::new(s_a.wing_mid.0, s_a.wing_mid.1, s_a.wing_mid.2);
|
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)
|
next.wing_mid_l.orientation =
|
||||||
|
Quaternion::rotation_y(-0.1 + move1 * -0.5)
|
||||||
* Quaternion::rotation_z(0.7 + move1 * -0.7);
|
* Quaternion::rotation_z(0.7 + move1 * -0.7);
|
||||||
next.wing_mid_r.orientation = Quaternion::rotation_y(0.1 + move1 * 0.5)
|
next.wing_mid_r.orientation = Quaternion::rotation_y(0.1 + move1 * 0.5)
|
||||||
* Quaternion::rotation_z(-0.7 + move1 * 0.7);
|
* Quaternion::rotation_z(-0.7 + move1 * 0.7);
|
||||||
@ -133,13 +150,15 @@ impl Animation for ComboAnimation {
|
|||||||
Vec3::new(-s_a.wing_out.0, s_a.wing_out.1, s_a.wing_out.2);
|
Vec3::new(-s_a.wing_out.0, s_a.wing_out.1, s_a.wing_out.2);
|
||||||
next.wing_out_r.position =
|
next.wing_out_r.position =
|
||||||
Vec3::new(s_a.wing_out.0, s_a.wing_out.1, s_a.wing_out.2);
|
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)
|
next.wing_out_l.orientation =
|
||||||
|
Quaternion::rotation_y(-0.2 + move1 * -0.3)
|
||||||
* Quaternion::rotation_z(0.2);
|
* Quaternion::rotation_z(0.2);
|
||||||
next.wing_out_r.orientation = Quaternion::rotation_y(0.2 + move1 * 0.3)
|
next.wing_out_r.orientation = Quaternion::rotation_y(0.2 + move1 * 0.3)
|
||||||
* Quaternion::rotation_z(-0.2);
|
* Quaternion::rotation_z(-0.2);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
pub mod alpha;
|
pub mod alpha;
|
||||||
|
pub mod aura;
|
||||||
pub mod breathe;
|
pub mod breathe;
|
||||||
pub mod combomelee;
|
pub mod combomelee;
|
||||||
pub mod dash;
|
pub mod dash;
|
||||||
@ -6,6 +7,7 @@ pub mod feed;
|
|||||||
pub mod fly;
|
pub mod fly;
|
||||||
pub mod idle;
|
pub mod idle;
|
||||||
pub mod run;
|
pub mod run;
|
||||||
|
pub mod selfbuff;
|
||||||
pub mod shockwave;
|
pub mod shockwave;
|
||||||
pub mod shoot;
|
pub mod shoot;
|
||||||
pub mod stunned;
|
pub mod stunned;
|
||||||
@ -14,10 +16,11 @@ pub mod swim;
|
|||||||
|
|
||||||
// Reexports
|
// Reexports
|
||||||
pub use self::{
|
pub use self::{
|
||||||
alpha::AlphaAnimation, breathe::BreatheAnimation, combomelee::ComboAnimation,
|
alpha::AlphaAnimation, aura::AuraAnimation, breathe::BreatheAnimation,
|
||||||
dash::DashAnimation, feed::FeedAnimation, fly::FlyAnimation, idle::IdleAnimation,
|
combomelee::ComboAnimation, dash::DashAnimation, feed::FeedAnimation, fly::FlyAnimation,
|
||||||
run::RunAnimation, shockwave::ShockwaveAnimation, shoot::ShootAnimation,
|
idle::IdleAnimation, run::RunAnimation, selfbuff::SelfBuffAnimation,
|
||||||
stunned::StunnedAnimation, summon::SummonAnimation, swim::SwimAnimation,
|
shockwave::ShockwaveAnimation, shoot::ShootAnimation, stunned::StunnedAnimation,
|
||||||
|
summon::SummonAnimation, swim::SwimAnimation,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{make_bone, vek::*, FigureBoneData, Offsets, Skeleton};
|
use super::{make_bone, vek::*, FigureBoneData, Offsets, Skeleton};
|
||||||
|
99
voxygen/anim/src/bird_large/selfbuff.rs
Normal file
99
voxygen/anim/src/bird_large/selfbuff.rs
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
use super::{
|
||||||
|
super::{vek::*, Animation},
|
||||||
|
BirdLargeSkeleton, SkeletonAttr,
|
||||||
|
};
|
||||||
|
use common::states::utils::StageSection;
|
||||||
|
|
||||||
|
pub struct SelfBuffAnimation;
|
||||||
|
|
||||||
|
impl Animation for SelfBuffAnimation {
|
||||||
|
type Dependency<'a> = (Option<StageSection>, bool);
|
||||||
|
type Skeleton = BirdLargeSkeleton;
|
||||||
|
|
||||||
|
#[cfg(feature = "use-dyn-lib")]
|
||||||
|
const UPDATE_FN: &'static [u8] = b"bird_large_selfbuff\0";
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "be-dyn-lib", export_name = "bird_large_selfbuff")]
|
||||||
|
fn update_skeleton_inner(
|
||||||
|
skeleton: &Self::Skeleton,
|
||||||
|
(stage_section, on_ground): Self::Dependency<'_>,
|
||||||
|
anim_time: f32,
|
||||||
|
_rate: &mut f32,
|
||||||
|
s_a: &SkeletonAttr,
|
||||||
|
) -> Self::Skeleton {
|
||||||
|
let mut next = (*skeleton).clone();
|
||||||
|
|
||||||
|
let (movement1base, movement2base, movement3, _twitch) = match stage_section {
|
||||||
|
Some(StageSection::Buildup) => (anim_time.powf(0.5), 0.0, 0.0, 0.0),
|
||||||
|
Some(StageSection::Action) => (1.0, anim_time.min(1.0).powf(0.1), 0.0, anim_time),
|
||||||
|
Some(StageSection::Recover) => (1.0, 1.0, anim_time, 1.0),
|
||||||
|
_ => (0.0, 0.0, 0.0, 0.0),
|
||||||
|
};
|
||||||
|
|
||||||
|
let pullback = 1.0 - movement3;
|
||||||
|
|
||||||
|
let movement1abs = movement1base * pullback;
|
||||||
|
let movement2abs = movement2base * pullback;
|
||||||
|
|
||||||
|
let wave_slow_cos = (anim_time * 4.5).cos();
|
||||||
|
|
||||||
|
next.chest.position = Vec3::new(
|
||||||
|
0.0,
|
||||||
|
s_a.chest.0,
|
||||||
|
s_a.chest.1 + movement1abs * 2.5 + movement2abs * 2.5,
|
||||||
|
);
|
||||||
|
next.chest.orientation = Quaternion::rotation_x(movement1abs * 1.0 + movement2abs * 1.0);
|
||||||
|
|
||||||
|
next.neck.position = Vec3::new(0.0, s_a.neck.0, s_a.neck.1);
|
||||||
|
next.neck.orientation = Quaternion::rotation_x(-0.2);
|
||||||
|
|
||||||
|
next.head.position = Vec3::new(0.0, s_a.head.0, s_a.head.1);
|
||||||
|
next.head.orientation = Quaternion::rotation_x(wave_slow_cos * 0.01);
|
||||||
|
|
||||||
|
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 - 0.02);
|
||||||
|
|
||||||
|
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(0.6);
|
||||||
|
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.2);
|
||||||
|
|
||||||
|
if on_ground {
|
||||||
|
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(-0.8 + movement1abs * 1.6 + movement2abs * 1.6)
|
||||||
|
* Quaternion::rotation_z(0.2 + movement1abs * -0.8);
|
||||||
|
next.wing_in_r.orientation =
|
||||||
|
Quaternion::rotation_y(0.8 + movement1abs * -1.6 + movement2abs * -1.6)
|
||||||
|
* Quaternion::rotation_z(-0.2 + movement1abs * 0.8);
|
||||||
|
|
||||||
|
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) * Quaternion::rotation_z(0.7);
|
||||||
|
next.wing_mid_r.orientation =
|
||||||
|
Quaternion::rotation_y(0.1) * Quaternion::rotation_z(-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.4) * Quaternion::rotation_z(0.2);
|
||||||
|
next.wing_out_r.orientation =
|
||||||
|
Quaternion::rotation_y(0.4) * Quaternion::rotation_z(-0.2);
|
||||||
|
|
||||||
|
next.leg_l.position = Vec3::new(-s_a.leg.0, s_a.leg.1, s_a.leg.2);
|
||||||
|
next.leg_l.orientation = Quaternion::rotation_x(0.0);
|
||||||
|
next.leg_r.position = Vec3::new(s_a.leg.0, s_a.leg.1, s_a.leg.2);
|
||||||
|
next.leg_r.orientation = Quaternion::rotation_x(0.0);
|
||||||
|
|
||||||
|
next.foot_l.position = Vec3::new(-s_a.foot.0, s_a.foot.1, s_a.foot.2);
|
||||||
|
next.foot_l.orientation = Quaternion::rotation_x(0.0);
|
||||||
|
next.foot_r.position = Vec3::new(s_a.foot.0, s_a.foot.1, s_a.foot.2);
|
||||||
|
next.foot_r.orientation = Quaternion::rotation_x(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
next
|
||||||
|
}
|
||||||
|
}
|
@ -6,10 +6,18 @@ use common::{states::utils::StageSection, util::Dir};
|
|||||||
|
|
||||||
pub struct ShootAnimation;
|
pub struct ShootAnimation;
|
||||||
|
|
||||||
type ShootAnimationDependency = (Vec3<f32>, f32, Option<StageSection>, f32, Dir, bool);
|
type ShootAnimationDependency<'a> = (
|
||||||
|
Vec3<f32>,
|
||||||
|
f32,
|
||||||
|
Option<StageSection>,
|
||||||
|
f32,
|
||||||
|
Dir,
|
||||||
|
bool,
|
||||||
|
Option<&'a str>,
|
||||||
|
);
|
||||||
|
|
||||||
impl Animation for ShootAnimation {
|
impl Animation for ShootAnimation {
|
||||||
type Dependency<'a> = ShootAnimationDependency;
|
type Dependency<'a> = ShootAnimationDependency<'a>;
|
||||||
type Skeleton = BirdLargeSkeleton;
|
type Skeleton = BirdLargeSkeleton;
|
||||||
|
|
||||||
#[cfg(feature = "use-dyn-lib")]
|
#[cfg(feature = "use-dyn-lib")]
|
||||||
@ -18,13 +26,88 @@ impl Animation for ShootAnimation {
|
|||||||
#[cfg_attr(feature = "be-dyn-lib", export_name = "bird_large_shoot")]
|
#[cfg_attr(feature = "be-dyn-lib", export_name = "bird_large_shoot")]
|
||||||
fn update_skeleton_inner(
|
fn update_skeleton_inner(
|
||||||
skeleton: &Self::Skeleton,
|
skeleton: &Self::Skeleton,
|
||||||
(velocity, global_time, stage_section, timer, look_dir, on_ground): Self::Dependency<'_>,
|
(velocity, global_time, stage_section, timer, look_dir, on_ground, ability_id,
|
||||||
|
): Self::Dependency<'_>,
|
||||||
anim_time: f32,
|
anim_time: f32,
|
||||||
_rate: &mut f32,
|
_rate: &mut f32,
|
||||||
s_a: &SkeletonAttr,
|
s_a: &SkeletonAttr,
|
||||||
) -> Self::Skeleton {
|
) -> Self::Skeleton {
|
||||||
let mut next = (*skeleton).clone();
|
let mut next = (*skeleton).clone();
|
||||||
|
|
||||||
|
match ability_id {
|
||||||
|
Some("common.abilities.custom.birdlargefire.firerain") => {
|
||||||
|
let (movement1base, movement2base, movement3, _twitch) = match stage_section {
|
||||||
|
Some(StageSection::Buildup) => (anim_time.powf(0.5), 0.0, 0.0, 0.0),
|
||||||
|
Some(StageSection::Action) => {
|
||||||
|
(1.0, anim_time.min(1.0).powf(0.1), 0.0, anim_time)
|
||||||
|
},
|
||||||
|
Some(StageSection::Recover) => (1.0, 1.0, anim_time, 1.0),
|
||||||
|
_ => (0.0, 0.0, 0.0, 0.0),
|
||||||
|
};
|
||||||
|
|
||||||
|
let pullback = 1.0 - movement3;
|
||||||
|
let movement1abs = movement1base * pullback;
|
||||||
|
let _movement2abs = movement2base * pullback;
|
||||||
|
let wave_slow_cos = (anim_time * 4.5).cos();
|
||||||
|
|
||||||
|
next.chest.position = Vec3::new(0.0, s_a.chest.0, s_a.chest.1 + movement1abs * 2.5);
|
||||||
|
next.chest.orientation = Quaternion::rotation_x(movement1abs * 1.0);
|
||||||
|
|
||||||
|
next.neck.position = Vec3::new(0.0, s_a.neck.0, s_a.neck.1);
|
||||||
|
next.neck.orientation = Quaternion::rotation_x(-0.2);
|
||||||
|
|
||||||
|
next.head.position = Vec3::new(0.0, s_a.head.0, s_a.head.1);
|
||||||
|
next.head.orientation = Quaternion::rotation_x(wave_slow_cos * 0.01);
|
||||||
|
|
||||||
|
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 - 0.02);
|
||||||
|
|
||||||
|
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(0.6);
|
||||||
|
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.2);
|
||||||
|
|
||||||
|
if on_ground {
|
||||||
|
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(-0.8 + movement1abs * 1.6)
|
||||||
|
* Quaternion::rotation_z(0.2 + movement1abs * -0.8);
|
||||||
|
next.wing_in_r.orientation = Quaternion::rotation_y(0.8 + movement1abs * -1.6)
|
||||||
|
* Quaternion::rotation_z(-0.2 + movement1abs * 0.8);
|
||||||
|
|
||||||
|
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) * Quaternion::rotation_z(0.7);
|
||||||
|
next.wing_mid_r.orientation =
|
||||||
|
Quaternion::rotation_y(0.1) * Quaternion::rotation_z(-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.4) * Quaternion::rotation_z(0.2);
|
||||||
|
next.wing_out_r.orientation =
|
||||||
|
Quaternion::rotation_y(0.4) * Quaternion::rotation_z(-0.2);
|
||||||
|
|
||||||
|
next.leg_l.position = Vec3::new(-s_a.leg.0, s_a.leg.1, s_a.leg.2);
|
||||||
|
next.leg_l.orientation = Quaternion::rotation_x(0.0);
|
||||||
|
next.leg_r.position = Vec3::new(s_a.leg.0, s_a.leg.1, s_a.leg.2);
|
||||||
|
next.leg_r.orientation = Quaternion::rotation_x(0.0);
|
||||||
|
|
||||||
|
next.foot_l.position = Vec3::new(-s_a.foot.0, s_a.foot.1, s_a.foot.2);
|
||||||
|
next.foot_l.orientation = Quaternion::rotation_x(0.0);
|
||||||
|
next.foot_r.position = Vec3::new(s_a.foot.0, s_a.foot.1, s_a.foot.2);
|
||||||
|
next.foot_r.orientation = Quaternion::rotation_x(0.0);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
let (movement1base, movement3, twitch) = match stage_section {
|
let (movement1base, movement3, twitch) = match stage_section {
|
||||||
Some(StageSection::Buildup) => (anim_time.powf(0.25), 0.0, 0.0),
|
Some(StageSection::Buildup) => (anim_time.powf(0.25), 0.0, 0.0),
|
||||||
Some(StageSection::Recover) => (1.0, anim_time.powf(0.25), anim_time),
|
Some(StageSection::Recover) => (1.0, anim_time.powf(0.25), anim_time),
|
||||||
@ -40,7 +123,6 @@ impl Animation for ShootAnimation {
|
|||||||
let movement1mirror = movement1abs * mirror;
|
let movement1mirror = movement1abs * mirror;
|
||||||
|
|
||||||
let wave_slow_cos = (anim_time * 4.5).cos();
|
let wave_slow_cos = (anim_time * 4.5).cos();
|
||||||
|
|
||||||
next.chest.position = Vec3::new(
|
next.chest.position = Vec3::new(
|
||||||
0.0,
|
0.0,
|
||||||
s_a.chest.0,
|
s_a.chest.0,
|
||||||
@ -85,6 +167,8 @@ impl Animation for ShootAnimation {
|
|||||||
* Quaternion::rotation_z(0.2 - movement1abs * 0.8);
|
* Quaternion::rotation_z(0.2 - movement1abs * 0.8);
|
||||||
next.wing_in_r.orientation = Quaternion::rotation_y(1.0 - movement1abs * 0.8)
|
next.wing_in_r.orientation = Quaternion::rotation_y(1.0 - movement1abs * 0.8)
|
||||||
* Quaternion::rotation_z(-0.2 + movement1abs * 0.8);
|
* Quaternion::rotation_z(-0.2 + movement1abs * 0.8);
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
next
|
next
|
||||||
}
|
}
|
||||||
|
@ -137,7 +137,8 @@ pub fn localize_chat_message(
|
|||||||
| BuffKind::Poisoned
|
| BuffKind::Poisoned
|
||||||
| BuffKind::Parried
|
| BuffKind::Parried
|
||||||
| BuffKind::PotionSickness
|
| BuffKind::PotionSickness
|
||||||
| BuffKind::Polymorphed => {
|
| BuffKind::Polymorphed
|
||||||
|
| BuffKind::Heatstroke => {
|
||||||
tracing::error!("Player was killed by a debuff that doesn't do damage!");
|
tracing::error!("Player was killed by a debuff that doesn't do damage!");
|
||||||
"mysterious"
|
"mysterious"
|
||||||
},
|
},
|
||||||
|
@ -186,6 +186,7 @@ pub enum SfxEvent {
|
|||||||
GroundDig,
|
GroundDig,
|
||||||
PortalActivated,
|
PortalActivated,
|
||||||
TeleportedByPortal,
|
TeleportedByPortal,
|
||||||
|
FromTheAshes,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Deserialize, Hash, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Deserialize, Hash, Eq)]
|
||||||
@ -219,6 +220,7 @@ pub enum VoiceKind {
|
|||||||
Truffler,
|
Truffler,
|
||||||
Wolf,
|
Wolf,
|
||||||
Wyvern,
|
Wyvern,
|
||||||
|
Phoenix,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn body_to_voice(body: &Body) -> Option<VoiceKind> {
|
fn body_to_voice(body: &Body) -> Option<VoiceKind> {
|
||||||
@ -274,6 +276,7 @@ fn body_to_voice(body: &Body) -> Option<VoiceKind> {
|
|||||||
| bird_large::Species::FrostWyvern
|
| bird_large::Species::FrostWyvern
|
||||||
| bird_large::Species::SeaWyvern
|
| bird_large::Species::SeaWyvern
|
||||||
| bird_large::Species::WealdWyvern => VoiceKind::Wyvern,
|
| bird_large::Species::WealdWyvern => VoiceKind::Wyvern,
|
||||||
|
bird_large::Species::Phoenix => VoiceKind::Phoenix,
|
||||||
_ => VoiceKind::Bird,
|
_ => VoiceKind::Bird,
|
||||||
},
|
},
|
||||||
Body::BipedSmall(body) => match body.species {
|
Body::BipedSmall(body) => match body.species {
|
||||||
@ -492,6 +495,11 @@ impl SfxMgr {
|
|||||||
let sfx_trigger_item = triggers.get_key_value(&SfxEvent::DeepLaugh);
|
let sfx_trigger_item = triggers.get_key_value(&SfxEvent::DeepLaugh);
|
||||||
audio.emit_sfx(sfx_trigger_item, *pos, Some(2.0), underwater);
|
audio.emit_sfx(sfx_trigger_item, *pos, Some(2.0), underwater);
|
||||||
},
|
},
|
||||||
|
Body::Object(object::Body::Tornado)
|
||||||
|
| Body::Object(object::Body::FieryTornado) => {
|
||||||
|
let sfx_trigger_item = triggers.get_key_value(&SfxEvent::Swoosh);
|
||||||
|
audio.emit_sfx(sfx_trigger_item, *pos, Some(2.0), underwater);
|
||||||
|
},
|
||||||
_ => { // not mapped to sfx file
|
_ => { // not mapped to sfx file
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -524,6 +532,10 @@ impl SfxMgr {
|
|||||||
let sfx_trigger_item = triggers.get_key_value(&SfxEvent::FlameThrower);
|
let sfx_trigger_item = triggers.get_key_value(&SfxEvent::FlameThrower);
|
||||||
audio.emit_sfx(sfx_trigger_item, *pos, Some(2.0), underwater);
|
audio.emit_sfx(sfx_trigger_item, *pos, Some(2.0), underwater);
|
||||||
},
|
},
|
||||||
|
Outcome::FromTheAshes { pos, .. } => {
|
||||||
|
let sfx_trigger_item = triggers.get_key_value(&SfxEvent::FromTheAshes);
|
||||||
|
audio.emit_sfx(sfx_trigger_item, *pos, Some(2.0), underwater);
|
||||||
|
},
|
||||||
Outcome::ProjectileShot { pos, body, .. } => {
|
Outcome::ProjectileShot { pos, body, .. } => {
|
||||||
match body {
|
match body {
|
||||||
Body::Object(
|
Body::Object(
|
||||||
@ -633,7 +645,9 @@ impl SfxMgr {
|
|||||||
audio.emit_sfx(sfx_trigger_item, *pos, None, underwater);
|
audio.emit_sfx(sfx_trigger_item, *pos, None, underwater);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
beam::FrontendSpecifier::Flamethrower | beam::FrontendSpecifier::Cultist => {
|
beam::FrontendSpecifier::Flamethrower
|
||||||
|
| beam::FrontendSpecifier::Cultist
|
||||||
|
| beam::FrontendSpecifier::PhoenixLaser => {
|
||||||
if thread_rng().gen_bool(0.5) {
|
if thread_rng().gen_bool(0.5) {
|
||||||
let sfx_trigger_item = triggers.get_key_value(&SfxEvent::FlameThrower);
|
let sfx_trigger_item = triggers.get_key_value(&SfxEvent::FlameThrower);
|
||||||
audio.emit_sfx(sfx_trigger_item, *pos, None, underwater);
|
audio.emit_sfx(sfx_trigger_item, *pos, None, underwater);
|
||||||
|
@ -795,6 +795,7 @@ image_ids! {
|
|||||||
debuff_parried_0: "voxygen.element.de_buffs.debuff_parried_0",
|
debuff_parried_0: "voxygen.element.de_buffs.debuff_parried_0",
|
||||||
debuff_potionsickness_0: "voxygen.element.de_buffs.debuff_potionsickness_0",
|
debuff_potionsickness_0: "voxygen.element.de_buffs.debuff_potionsickness_0",
|
||||||
debuff_polymorphed: "voxygen.element.de_buffs.debuff_polymorphed",
|
debuff_polymorphed: "voxygen.element.de_buffs.debuff_polymorphed",
|
||||||
|
debuff_heatstroke_0: "voxygen.element.de_buffs.debuff_heatstroke_0",
|
||||||
|
|
||||||
// Animation Frames
|
// Animation Frames
|
||||||
// Buff Frame
|
// Buff Frame
|
||||||
|
@ -5193,6 +5193,7 @@ pub fn get_buff_image(buff: BuffKind, imgs: &Imgs) -> conrod_core::image::Id {
|
|||||||
BuffKind::Parried => imgs.debuff_parried_0,
|
BuffKind::Parried => imgs.debuff_parried_0,
|
||||||
BuffKind::PotionSickness => imgs.debuff_potionsickness_0,
|
BuffKind::PotionSickness => imgs.debuff_potionsickness_0,
|
||||||
BuffKind::Polymorphed => imgs.debuff_polymorphed,
|
BuffKind::Polymorphed => imgs.debuff_polymorphed,
|
||||||
|
BuffKind::Heatstroke => imgs.debuff_heatstroke_0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5234,6 +5235,7 @@ pub fn get_buff_title(buff: BuffKind, localized_strings: &Localization) -> Cow<s
|
|||||||
BuffKind::Parried => localized_strings.get_msg("buff-title-parried"),
|
BuffKind::Parried => localized_strings.get_msg("buff-title-parried"),
|
||||||
BuffKind::PotionSickness => localized_strings.get_msg("buff-title-potionsickness"),
|
BuffKind::PotionSickness => localized_strings.get_msg("buff-title-potionsickness"),
|
||||||
BuffKind::Polymorphed => localized_strings.get_msg("buff-title-polymorphed"),
|
BuffKind::Polymorphed => localized_strings.get_msg("buff-title-polymorphed"),
|
||||||
|
BuffKind::Heatstroke => localized_strings.get_msg("buff-title-heatstroke"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5279,6 +5281,7 @@ pub fn get_buff_desc(buff: BuffKind, data: BuffData, localized_strings: &Localiz
|
|||||||
BuffKind::Parried => localized_strings.get_msg("buff-desc-parried"),
|
BuffKind::Parried => localized_strings.get_msg("buff-desc-parried"),
|
||||||
BuffKind::PotionSickness => localized_strings.get_msg("buff-desc-potionsickness"),
|
BuffKind::PotionSickness => localized_strings.get_msg("buff-desc-potionsickness"),
|
||||||
BuffKind::Polymorphed => localized_strings.get_msg("buff-desc-polymorphed"),
|
BuffKind::Polymorphed => localized_strings.get_msg("buff-desc-polymorphed"),
|
||||||
|
BuffKind::Heatstroke => localized_strings.get_msg("buff-desc-heatstroke"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,7 +215,8 @@ pub fn consumable_desc(effects: &Effects, i18n: &Localization) -> Vec<String> {
|
|||||||
| BuffKind::Sunderer
|
| BuffKind::Sunderer
|
||||||
| BuffKind::Defiance
|
| BuffKind::Defiance
|
||||||
| BuffKind::Bloodfeast
|
| BuffKind::Bloodfeast
|
||||||
| BuffKind::Berserk => Cow::Borrowed(""),
|
| BuffKind::Berserk
|
||||||
|
| BuffKind::Heatstroke => Cow::Borrowed(""),
|
||||||
};
|
};
|
||||||
|
|
||||||
write!(&mut description, "{}", buff_desc).unwrap();
|
write!(&mut description, "{}", buff_desc).unwrap();
|
||||||
@ -263,7 +264,8 @@ pub fn consumable_desc(effects: &Effects, i18n: &Localization) -> Vec<String> {
|
|||||||
| BuffKind::Sunderer
|
| BuffKind::Sunderer
|
||||||
| BuffKind::Defiance
|
| BuffKind::Defiance
|
||||||
| BuffKind::Bloodfeast
|
| BuffKind::Bloodfeast
|
||||||
| BuffKind::Berserk => Cow::Borrowed(""),
|
| BuffKind::Berserk
|
||||||
|
| BuffKind::Heatstroke => Cow::Borrowed(""),
|
||||||
}
|
}
|
||||||
} else if let BuffKind::Saturation
|
} else if let BuffKind::Saturation
|
||||||
| BuffKind::Regeneration
|
| BuffKind::Regeneration
|
||||||
|
@ -99,6 +99,16 @@ pub enum ParticleMode {
|
|||||||
PortalFizz = 45,
|
PortalFizz = 45,
|
||||||
Ink = 46,
|
Ink = 46,
|
||||||
Whirlwind = 47,
|
Whirlwind = 47,
|
||||||
|
FieryBurst = 48,
|
||||||
|
FieryBurstVortex = 49,
|
||||||
|
FieryBurstSparks = 50,
|
||||||
|
FieryBurstAsh = 51,
|
||||||
|
FieryTornado = 52,
|
||||||
|
PhoenixCloud = 53,
|
||||||
|
FieryDropletTrace = 54,
|
||||||
|
EnergyPhoenix = 55,
|
||||||
|
PhoenixBeam = 56,
|
||||||
|
PhoenixBuildUpAim = 57,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParticleMode {
|
impl ParticleMode {
|
||||||
|
@ -4931,6 +4931,7 @@ impl FigureMgr {
|
|||||||
state.state_time,
|
state.state_time,
|
||||||
look_dir,
|
look_dir,
|
||||||
physics.on_ground.is_some(),
|
physics.on_ground.is_some(),
|
||||||
|
ability_id,
|
||||||
),
|
),
|
||||||
stage_progress,
|
stage_progress,
|
||||||
&mut state_animation_rate,
|
&mut state_animation_rate,
|
||||||
@ -4993,6 +4994,36 @@ impl FigureMgr {
|
|||||||
state.state_time,
|
state.state_time,
|
||||||
look_dir,
|
look_dir,
|
||||||
physics.on_ground.is_some(),
|
physics.on_ground.is_some(),
|
||||||
|
ability_id,
|
||||||
|
),
|
||||||
|
stage_progress,
|
||||||
|
&mut state_animation_rate,
|
||||||
|
skeleton_attr,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
CharacterState::RepeaterRanged(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::Recover => {
|
||||||
|
stage_time / s.static_data.recover_duration.as_secs_f32()
|
||||||
|
},
|
||||||
|
|
||||||
|
_ => 0.0,
|
||||||
|
};
|
||||||
|
anim::bird_large::ShootAnimation::update_skeleton(
|
||||||
|
&target_base,
|
||||||
|
(
|
||||||
|
rel_vel,
|
||||||
|
time,
|
||||||
|
Some(s.stage_section),
|
||||||
|
state.state_time,
|
||||||
|
look_dir,
|
||||||
|
physics.on_ground.is_some(),
|
||||||
|
ability_id,
|
||||||
),
|
),
|
||||||
stage_progress,
|
stage_progress,
|
||||||
&mut state_animation_rate,
|
&mut state_animation_rate,
|
||||||
@ -5021,6 +5052,50 @@ impl FigureMgr {
|
|||||||
skeleton_attr,
|
skeleton_attr,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
CharacterState::BasicAura(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::Action => {
|
||||||
|
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::bird_large::AuraAnimation::update_skeleton(
|
||||||
|
&target_base,
|
||||||
|
(Some(s.stage_section), physics.on_ground.is_some()),
|
||||||
|
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::Action => {
|
||||||
|
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::bird_large::SelfBuffAnimation::update_skeleton(
|
||||||
|
&target_base,
|
||||||
|
(Some(s.stage_section), physics.on_ground.is_some()),
|
||||||
|
stage_progress,
|
||||||
|
&mut state_animation_rate,
|
||||||
|
skeleton_attr,
|
||||||
|
)
|
||||||
|
},
|
||||||
CharacterState::BasicSummon(s) => {
|
CharacterState::BasicSummon(s) => {
|
||||||
let stage_time = s.timer.as_secs_f32();
|
let stage_time = s.timer.as_secs_f32();
|
||||||
let stage_progress = match s.stage_section {
|
let stage_progress = match s.stage_section {
|
||||||
|
@ -492,6 +492,7 @@ impl Scene {
|
|||||||
Rgb::new(1.0, 0.0, 0.0)
|
Rgb::new(1.0, 0.0, 0.0)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Some(Reagent::Phoenix) => Rgb::new(1.0, 0.8, 0.3),
|
||||||
Some(Reagent::White) => Rgb::new(1.0, 1.0, 1.0),
|
Some(Reagent::White) => Rgb::new(1.0, 1.0, 1.0),
|
||||||
Some(Reagent::Yellow) => Rgb::new(1.0, 1.0, 0.0),
|
Some(Reagent::Yellow) => Rgb::new(1.0, 1.0, 0.0),
|
||||||
None => Rgb::new(1.0, 0.5, 0.0),
|
None => Rgb::new(1.0, 0.5, 0.0),
|
||||||
|
@ -15,7 +15,7 @@ use common::{
|
|||||||
item::Reagent,
|
item::Reagent,
|
||||||
object,
|
object,
|
||||||
shockwave::{self, ShockwaveDodgeable},
|
shockwave::{self, ShockwaveDodgeable},
|
||||||
Beam, Body, CharacterState, Ori, Pos, Scale, Shockwave, Vel,
|
Beam, Body, CharacterActivity, CharacterState, Ori, Pos, Scale, Shockwave, Vel,
|
||||||
},
|
},
|
||||||
figure::Segment,
|
figure::Segment,
|
||||||
outcome::Outcome,
|
outcome::Outcome,
|
||||||
@ -170,6 +170,23 @@ impl ParticleMgr {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
Some(Reagent::Phoenix) => {
|
||||||
|
self.particles.resize_with(
|
||||||
|
self.particles.len() + (5.0 * power.abs()) as usize,
|
||||||
|
|| {
|
||||||
|
Particle::new_directed(
|
||||||
|
Duration::from_millis(300),
|
||||||
|
time,
|
||||||
|
ParticleMode::Explosion,
|
||||||
|
*pos,
|
||||||
|
*pos + Vec3::<f32>::zero()
|
||||||
|
.map(|_| rng.gen_range(-1.0..1.0))
|
||||||
|
.normalized()
|
||||||
|
* *radius,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -186,6 +203,7 @@ impl ParticleMgr {
|
|||||||
Some(Reagent::Red) => ParticleMode::FireworkRed,
|
Some(Reagent::Red) => ParticleMode::FireworkRed,
|
||||||
Some(Reagent::White) => ParticleMode::FireworkWhite,
|
Some(Reagent::White) => ParticleMode::FireworkWhite,
|
||||||
Some(Reagent::Yellow) => ParticleMode::FireworkYellow,
|
Some(Reagent::Yellow) => ParticleMode::FireworkYellow,
|
||||||
|
Some(Reagent::Phoenix) => ParticleMode::FireworkYellow,
|
||||||
None => ParticleMode::Shrapnel,
|
None => ParticleMode::Shrapnel,
|
||||||
},
|
},
|
||||||
*pos,
|
*pos,
|
||||||
@ -431,6 +449,7 @@ impl ParticleMgr {
|
|||||||
| Outcome::Steam { .. }
|
| Outcome::Steam { .. }
|
||||||
| Outcome::FireShockwave { .. }
|
| Outcome::FireShockwave { .. }
|
||||||
| Outcome::PortalActivated { .. }
|
| Outcome::PortalActivated { .. }
|
||||||
|
| Outcome::FromTheAshes { .. }
|
||||||
| Outcome::LaserBeam { .. } => {},
|
| Outcome::LaserBeam { .. } => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -501,12 +520,18 @@ impl ParticleMgr {
|
|||||||
Body::Object(object::Body::BoltFireBig) => {
|
Body::Object(object::Body::BoltFireBig) => {
|
||||||
self.maintain_boltfirebig_particles(scene_data, interpolated.pos, vel)
|
self.maintain_boltfirebig_particles(scene_data, interpolated.pos, vel)
|
||||||
},
|
},
|
||||||
|
Body::Object(object::Body::FireRainDrop) => {
|
||||||
|
self.maintain_fireraindrop_particles(scene_data, interpolated.pos, vel)
|
||||||
|
},
|
||||||
Body::Object(object::Body::BoltNature) => {
|
Body::Object(object::Body::BoltNature) => {
|
||||||
self.maintain_boltnature_particles(scene_data, interpolated.pos, vel)
|
self.maintain_boltnature_particles(scene_data, interpolated.pos, vel)
|
||||||
},
|
},
|
||||||
Body::Object(object::Body::Tornado) => {
|
Body::Object(object::Body::Tornado) => {
|
||||||
self.maintain_tornado_particles(scene_data, interpolated.pos)
|
self.maintain_tornado_particles(scene_data, interpolated.pos)
|
||||||
},
|
},
|
||||||
|
Body::Object(object::Body::FieryTornado) => {
|
||||||
|
self.maintain_fiery_tornado_particles(scene_data, interpolated.pos)
|
||||||
|
},
|
||||||
Body::Object(object::Body::Mine) => {
|
Body::Object(object::Body::Mine) => {
|
||||||
self.maintain_mine_particles(scene_data, interpolated.pos)
|
self.maintain_mine_particles(scene_data, interpolated.pos)
|
||||||
},
|
},
|
||||||
@ -672,6 +697,38 @@ impl ParticleMgr {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn maintain_fireraindrop_particles(
|
||||||
|
&mut self,
|
||||||
|
scene_data: &SceneData,
|
||||||
|
pos: Vec3<f32>,
|
||||||
|
vel: Option<&Vel>,
|
||||||
|
) {
|
||||||
|
span!(
|
||||||
|
_guard,
|
||||||
|
"fireraindrop_particles",
|
||||||
|
"ParticleMgr::maintain_fireraindrop_particles"
|
||||||
|
);
|
||||||
|
let time = scene_data.state.get_time();
|
||||||
|
let dt = scene_data.state.get_delta_time();
|
||||||
|
let mut rng = thread_rng();
|
||||||
|
|
||||||
|
// trace
|
||||||
|
self.particles.resize_with(
|
||||||
|
self.particles.len()
|
||||||
|
+ usize::from(self.scheduler.heartbeats(Duration::from_millis(100))),
|
||||||
|
|| {
|
||||||
|
Particle::new(
|
||||||
|
Duration::from_millis(300),
|
||||||
|
time,
|
||||||
|
ParticleMode::FieryDropletTrace,
|
||||||
|
pos.map(|e| e + rng.gen_range(-0.25..0.25))
|
||||||
|
+ Vec3::new(0.0, 0.0, 0.5)
|
||||||
|
+ vel.map_or(Vec3::zero(), |v| -v.0 * dt * rng.gen::<f32>()),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn maintain_boltnature_particles(
|
fn maintain_boltnature_particles(
|
||||||
&mut self,
|
&mut self,
|
||||||
scene_data: &SceneData,
|
scene_data: &SceneData,
|
||||||
@ -715,6 +772,24 @@ impl ParticleMgr {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn maintain_fiery_tornado_particles(&mut self, scene_data: &SceneData, pos: Vec3<f32>) {
|
||||||
|
let time = scene_data.state.get_time();
|
||||||
|
let mut rng = thread_rng();
|
||||||
|
|
||||||
|
// air particles
|
||||||
|
self.particles.resize_with(
|
||||||
|
self.particles.len() + usize::from(self.scheduler.heartbeats(Duration::from_millis(5))),
|
||||||
|
|| {
|
||||||
|
Particle::new(
|
||||||
|
Duration::from_millis(1000),
|
||||||
|
time,
|
||||||
|
ParticleMode::FieryTornado,
|
||||||
|
pos.map(|e| e + rng.gen_range(-0.25..0.25)),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn maintain_bomb_particles(
|
fn maintain_bomb_particles(
|
||||||
&mut self,
|
&mut self,
|
||||||
scene_data: &SceneData,
|
scene_data: &SceneData,
|
||||||
@ -830,12 +905,14 @@ impl ParticleMgr {
|
|||||||
let dt = scene_data.state.get_delta_time();
|
let dt = scene_data.state.get_delta_time();
|
||||||
let mut rng = thread_rng();
|
let mut rng = thread_rng();
|
||||||
|
|
||||||
for (entity, interpolated, vel, character_state, body) in (
|
for (entity, interpolated, vel, character_state, body, ori, character_activity) in (
|
||||||
&ecs.entities(),
|
&ecs.entities(),
|
||||||
&ecs.read_storage::<Interpolated>(),
|
&ecs.read_storage::<Interpolated>(),
|
||||||
ecs.read_storage::<Vel>().maybe(),
|
ecs.read_storage::<Vel>().maybe(),
|
||||||
&ecs.read_storage::<CharacterState>(),
|
&ecs.read_storage::<CharacterState>(),
|
||||||
&ecs.read_storage::<Body>(),
|
&ecs.read_storage::<Body>(),
|
||||||
|
&ecs.read_storage::<Ori>(),
|
||||||
|
&ecs.read_storage::<CharacterActivity>(),
|
||||||
)
|
)
|
||||||
.join()
|
.join()
|
||||||
{
|
{
|
||||||
@ -957,6 +1034,87 @@ impl ParticleMgr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
CharacterState::RepeaterRanged(repeater) => {
|
||||||
|
if let Some(specifier) = repeater.static_data.specifier {
|
||||||
|
match specifier {
|
||||||
|
states::repeater_ranged::FrontendSpecifier::FireRain => {
|
||||||
|
// base, dark clouds
|
||||||
|
self.particles.resize_with(
|
||||||
|
self.particles.len()
|
||||||
|
+ 2 * usize::from(
|
||||||
|
self.scheduler.heartbeats(Duration::from_millis(25)),
|
||||||
|
),
|
||||||
|
|| {
|
||||||
|
let rand_pos = {
|
||||||
|
let theta = rng.gen::<f32>() * TAU;
|
||||||
|
let radius = repeater
|
||||||
|
.static_data
|
||||||
|
.properties_of_aoe
|
||||||
|
.map(|aoe| aoe.radius)
|
||||||
|
.unwrap_or_default()
|
||||||
|
* rng.gen::<f32>().sqrt();
|
||||||
|
let x = radius * theta.sin();
|
||||||
|
let y = radius * theta.cos();
|
||||||
|
Vec2::new(x, y) + interpolated.pos.xy()
|
||||||
|
};
|
||||||
|
let pos1 = rand_pos.with_z(
|
||||||
|
repeater
|
||||||
|
.static_data
|
||||||
|
.properties_of_aoe
|
||||||
|
.map(|aoe| aoe.height)
|
||||||
|
.unwrap_or_default()
|
||||||
|
+ interpolated.pos.z
|
||||||
|
+ 2.0 * rng.gen::<f32>(),
|
||||||
|
);
|
||||||
|
Particle::new_directed(
|
||||||
|
Duration::from_secs_f32(3.0),
|
||||||
|
time,
|
||||||
|
ParticleMode::PhoenixCloud,
|
||||||
|
pos1,
|
||||||
|
pos1 + Vec3::new(7.09, 4.09, 18.09),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
self.particles.resize_with(
|
||||||
|
self.particles.len()
|
||||||
|
+ 2 * usize::from(
|
||||||
|
self.scheduler.heartbeats(Duration::from_millis(25)),
|
||||||
|
),
|
||||||
|
|| {
|
||||||
|
let rand_pos = {
|
||||||
|
let theta = rng.gen::<f32>() * TAU;
|
||||||
|
let radius = repeater
|
||||||
|
.static_data
|
||||||
|
.properties_of_aoe
|
||||||
|
.map(|aoe| aoe.radius)
|
||||||
|
.unwrap_or_default()
|
||||||
|
* rng.gen::<f32>().sqrt();
|
||||||
|
let x = radius * theta.sin();
|
||||||
|
let y = radius * theta.cos();
|
||||||
|
Vec2::new(x, y) + interpolated.pos.xy()
|
||||||
|
};
|
||||||
|
let pos1 = rand_pos.with_z(
|
||||||
|
repeater
|
||||||
|
.static_data
|
||||||
|
.properties_of_aoe
|
||||||
|
.map(|aoe| aoe.height)
|
||||||
|
.unwrap_or_default()
|
||||||
|
+ interpolated.pos.z
|
||||||
|
+ 1.5 * rng.gen::<f32>(),
|
||||||
|
);
|
||||||
|
Particle::new_directed(
|
||||||
|
Duration::from_secs_f32(2.5),
|
||||||
|
time,
|
||||||
|
ParticleMode::PhoenixCloud,
|
||||||
|
pos1,
|
||||||
|
pos1 + Vec3::new(10.025, 4.025, 17.025),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
CharacterState::Blink(c) => {
|
CharacterState::Blink(c) => {
|
||||||
self.particles.resize_with(
|
self.particles.resize_with(
|
||||||
self.particles.len()
|
self.particles.len()
|
||||||
@ -992,6 +1150,94 @@ impl ParticleMgr {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
CharacterState::SelfBuff(c) => {
|
CharacterState::SelfBuff(c) => {
|
||||||
|
if let Some(specifier) = c.static_data.specifier {
|
||||||
|
match specifier {
|
||||||
|
states::self_buff::FrontendSpecifier::FromTheAshes => {
|
||||||
|
if matches!(c.stage_section, StageSection::Action) {
|
||||||
|
let pos = interpolated.pos;
|
||||||
|
self.particles.resize_with(
|
||||||
|
self.particles.len()
|
||||||
|
+ 2 * usize::from(
|
||||||
|
self.scheduler.heartbeats(Duration::from_millis(1)),
|
||||||
|
),
|
||||||
|
|| {
|
||||||
|
let start_pos = pos + Vec3::unit_z() - 1.0;
|
||||||
|
let end_pos = pos
|
||||||
|
+ Vec3::new(
|
||||||
|
4.0 * rng.gen::<f32>() - 1.0,
|
||||||
|
4.0 * rng.gen::<f32>() - 1.0,
|
||||||
|
0.0,
|
||||||
|
)
|
||||||
|
.normalized()
|
||||||
|
* 1.5
|
||||||
|
+ Vec3::unit_z()
|
||||||
|
+ 5.0 * rng.gen::<f32>();
|
||||||
|
|
||||||
|
Particle::new_directed(
|
||||||
|
Duration::from_secs_f32(0.5),
|
||||||
|
time,
|
||||||
|
ParticleMode::FieryBurst,
|
||||||
|
start_pos,
|
||||||
|
end_pos,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
self.particles.resize_with(
|
||||||
|
self.particles.len()
|
||||||
|
+ usize::from(
|
||||||
|
self.scheduler
|
||||||
|
.heartbeats(Duration::from_millis(10)),
|
||||||
|
),
|
||||||
|
|| {
|
||||||
|
Particle::new(
|
||||||
|
Duration::from_millis(650),
|
||||||
|
time,
|
||||||
|
ParticleMode::FieryBurstVortex,
|
||||||
|
pos.map(|e| e + rng.gen_range(-0.25..0.25))
|
||||||
|
+ Vec3::new(0.0, 0.0, 1.0),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
self.particles.resize_with(
|
||||||
|
self.particles.len()
|
||||||
|
+ usize::from(
|
||||||
|
self.scheduler
|
||||||
|
.heartbeats(Duration::from_millis(40)),
|
||||||
|
),
|
||||||
|
|| {
|
||||||
|
Particle::new(
|
||||||
|
Duration::from_millis(1000),
|
||||||
|
time,
|
||||||
|
ParticleMode::FieryBurstSparks,
|
||||||
|
pos.map(|e| e + rng.gen_range(-0.25..0.25)),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
self.particles.resize_with(
|
||||||
|
self.particles.len()
|
||||||
|
+ usize::from(
|
||||||
|
self.scheduler
|
||||||
|
.heartbeats(Duration::from_millis(14)),
|
||||||
|
),
|
||||||
|
|| {
|
||||||
|
let pos1 = pos.map(|e| e + rng.gen_range(-0.25..0.25));
|
||||||
|
Particle::new_directed(
|
||||||
|
Duration::from_millis(1000),
|
||||||
|
time,
|
||||||
|
ParticleMode::FieryBurstAsh,
|
||||||
|
pos1,
|
||||||
|
Vec3::new(
|
||||||
|
4.5, // radius of rand spawn
|
||||||
|
20.4, // integer part - radius of the curve part, fractional part - relative time of setting particle on fire
|
||||||
|
8.58) // height of the flight
|
||||||
|
+ pos1,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
use buff::BuffKind;
|
use buff::BuffKind;
|
||||||
if let BuffKind::Frenzied = c.static_data.buff_kind {
|
if let BuffKind::Frenzied = c.static_data.buff_kind {
|
||||||
if matches!(c.stage_section, StageSection::Action) {
|
if matches!(c.stage_section, StageSection::Action) {
|
||||||
@ -1022,6 +1268,44 @@ impl ParticleMgr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
CharacterState::BasicBeam(beam) => {
|
||||||
|
let ori = *ori;
|
||||||
|
let _look_dir = *character_activity.look_dir.unwrap_or(ori.look_dir());
|
||||||
|
let dir = ori.look_dir(); //.with_z(look_dir.z);
|
||||||
|
let specifier = beam.static_data.specifier;
|
||||||
|
if specifier == beam::FrontendSpecifier::PhoenixLaser
|
||||||
|
&& matches!(beam.stage_section, StageSection::Buildup)
|
||||||
|
{
|
||||||
|
self.particles.resize_with(
|
||||||
|
self.particles.len()
|
||||||
|
+ 2 * usize::from(
|
||||||
|
self.scheduler.heartbeats(Duration::from_millis(2)),
|
||||||
|
),
|
||||||
|
|| {
|
||||||
|
let mut left_right_alignment =
|
||||||
|
dir.cross(Vec3::new(0.0, 0.0, 1.0)).normalized();
|
||||||
|
if rng.gen_bool(0.5) {
|
||||||
|
left_right_alignment *= -1.0;
|
||||||
|
}
|
||||||
|
let start = interpolated.pos
|
||||||
|
+ left_right_alignment * 4.0
|
||||||
|
+ dir.normalized() * 6.0;
|
||||||
|
let lifespan = Duration::from_secs_f32(0.5);
|
||||||
|
Particle::new_directed(
|
||||||
|
lifespan,
|
||||||
|
time,
|
||||||
|
ParticleMode::PhoenixBuildUpAim,
|
||||||
|
start,
|
||||||
|
interpolated.pos
|
||||||
|
+ dir.normalized() * 3.0
|
||||||
|
+ left_right_alignment * 0.4
|
||||||
|
+ vel
|
||||||
|
.map_or(Vec3::zero(), |v| v.0 * lifespan.as_secs_f32()),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1285,6 +1569,20 @@ impl ParticleMgr {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
beam::FrontendSpecifier::PhoenixLaser => {
|
||||||
|
self.particles.resize_with(
|
||||||
|
self.particles.len() + usize::from(beam_tick_count) / 2,
|
||||||
|
|| {
|
||||||
|
Particle::new_directed(
|
||||||
|
Duration::from_secs_f64(beam.duration.0),
|
||||||
|
time,
|
||||||
|
ParticleMode::PhoenixBeam,
|
||||||
|
beam.bezier.start,
|
||||||
|
beam.bezier.start + beam_dir * beam.range,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1458,6 +1756,62 @@ impl ParticleMgr {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
aura::AuraKind::Buff {
|
||||||
|
kind: buff::BuffKind::Heatstroke,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let heartbeats = self.scheduler.heartbeats(Duration::from_millis(5));
|
||||||
|
self.particles.resize_with(
|
||||||
|
self.particles.len()
|
||||||
|
+ aura.radius.powi(2) as usize * usize::from(heartbeats) / 900,
|
||||||
|
|| {
|
||||||
|
let rand_dist = aura.radius * (1.0 - rng.gen::<f32>().powi(100));
|
||||||
|
let init_pos = Vec3::new(rand_dist, 0_f32, 0_f32);
|
||||||
|
let duration = Duration::from_secs_f64(
|
||||||
|
aura.end_time
|
||||||
|
.map_or(1.0, |end| end.0 - time)
|
||||||
|
.clamp(0.0, 1.0),
|
||||||
|
);
|
||||||
|
Particle::new_directed(
|
||||||
|
duration,
|
||||||
|
time,
|
||||||
|
ParticleMode::EnergyPhoenix,
|
||||||
|
pos,
|
||||||
|
pos + init_pos,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
let num_particles = aura.radius.powi(2) * dt / 50.0;
|
||||||
|
let num_particles = num_particles.floor() as usize
|
||||||
|
+ usize::from(rng.gen_bool(f64::from(num_particles % 1.0)));
|
||||||
|
self.particles
|
||||||
|
.resize_with(self.particles.len() + num_particles, || {
|
||||||
|
let rand_pos = {
|
||||||
|
let theta = rng.gen::<f32>() * TAU;
|
||||||
|
let radius = aura.radius * rng.gen::<f32>().sqrt();
|
||||||
|
let x = radius * theta.sin();
|
||||||
|
let y = radius * theta.cos();
|
||||||
|
Vec2::new(x, y) + pos.xy()
|
||||||
|
};
|
||||||
|
let duration = Duration::from_secs_f64(
|
||||||
|
aura.end_time
|
||||||
|
.map_or(1.0, |end| end.0 - time)
|
||||||
|
.clamp(0.0, 1.0),
|
||||||
|
);
|
||||||
|
Particle::new_directed(
|
||||||
|
duration,
|
||||||
|
time,
|
||||||
|
ParticleMode::FieryBurstAsh,
|
||||||
|
pos,
|
||||||
|
Vec3::new(
|
||||||
|
0.0, // radius of rand spawn
|
||||||
|
20.0, // integer part - radius of the curve part, fractional part - relative time of setting particle on fire
|
||||||
|
5.5) // height of the flight
|
||||||
|
+ rand_pos.with_z(pos.z),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user