mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'sam/clay-golem' into 'master'
Clay Golem Rework See merge request veloren/veloren!2264
This commit is contained in:
commit
81bba1393a
@ -101,6 +101,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Better active/inactive master sound slider logic
|
||||
- Cultist Husk no longer drops weapons and armor
|
||||
- Animal Trainers now spawn in tier-5 dungeon and not in tier-3
|
||||
- Reworked clay golem to have unique attacks.
|
||||
|
||||
### Removed
|
||||
|
||||
|
@ -199,6 +199,11 @@
|
||||
secondary: "common.abilities.custom.turret.arrows",
|
||||
abilities: [],
|
||||
),
|
||||
Custom("Haniwa Sentry"): (
|
||||
primary: "common.abilities.custom.turret.flamethrower",
|
||||
secondary: "common.abilities.custom.turret.flamethrower",
|
||||
abilities: [],
|
||||
),
|
||||
Custom("Mindflayer"): (
|
||||
primary: "common.abilities.custom.mindflayer.cursedflames",
|
||||
secondary: "common.abilities.custom.mindflayer.necroticvortex",
|
||||
@ -216,6 +221,14 @@
|
||||
(None, "common.abilities.custom.minotaur.frenzy"),
|
||||
],
|
||||
),
|
||||
Custom("Clay Golem"): (
|
||||
primary: "common.abilities.custom.claygolem.strike",
|
||||
secondary: "common.abilities.custom.claygolem.laser",
|
||||
abilities: [
|
||||
(None, "common.abilities.custom.claygolem.shockwave"),
|
||||
(None, "common.abilities.custom.claygolem.rocket"),
|
||||
],
|
||||
),
|
||||
Custom("Bird Large Breathe"): (
|
||||
primary: "common.abilities.custom.birdlargebreathe.firebomb",
|
||||
secondary: "common.abilities.custom.birdlargebreathe.triplestrike",
|
||||
|
14
assets/common/abilities/custom/claygolem/laser.ron
Normal file
14
assets/common/abilities/custom/claygolem/laser.ron
Normal file
@ -0,0 +1,14 @@
|
||||
BasicBeam(
|
||||
buildup_duration: 0.5,
|
||||
recover_duration: 0.4,
|
||||
beam_duration: 0.25,
|
||||
damage: 100,
|
||||
tick_rate: 2.0,
|
||||
range: 40.0,
|
||||
max_angle: 1.0,
|
||||
damage_effect: None,
|
||||
energy_regen: 50,
|
||||
energy_drain: 0,
|
||||
orientation_behavior: FromOri,
|
||||
specifier: ClayGolem,
|
||||
)
|
13
assets/common/abilities/custom/claygolem/rocket.ron
Normal file
13
assets/common/abilities/custom/claygolem/rocket.ron
Normal file
@ -0,0 +1,13 @@
|
||||
BasicRanged(
|
||||
energy_cost: 0,
|
||||
buildup_duration: 0.5,
|
||||
recover_duration: 0.8,
|
||||
projectile: ClayRocket(
|
||||
damage: 500.0,
|
||||
knockback: 25.0,
|
||||
radius: 10.0,
|
||||
),
|
||||
projectile_body: Object(ClayRocket),
|
||||
projectile_light: None,
|
||||
projectile_speed: 30.0,
|
||||
)
|
16
assets/common/abilities/custom/claygolem/shockwave.ron
Normal file
16
assets/common/abilities/custom/claygolem/shockwave.ron
Normal file
@ -0,0 +1,16 @@
|
||||
Shockwave(
|
||||
energy_cost: 0,
|
||||
buildup_duration: 0.6,
|
||||
swing_duration: 0.12,
|
||||
recover_duration: 1.2,
|
||||
damage: 500,
|
||||
poise_damage: 50,
|
||||
knockback: (strength: 40.0, direction: TowardsUp),
|
||||
shockwave_angle: 180.0,
|
||||
shockwave_vertical_angle: 90.0,
|
||||
shockwave_speed: 15.0,
|
||||
shockwave_duration: 2.5,
|
||||
requires_ground: true,
|
||||
move_efficiency: 0.0,
|
||||
damage_kind: Crushing,
|
||||
)
|
13
assets/common/abilities/custom/claygolem/strike.ron
Normal file
13
assets/common/abilities/custom/claygolem/strike.ron
Normal file
@ -0,0 +1,13 @@
|
||||
BasicMelee(
|
||||
energy_cost: 0,
|
||||
buildup_duration: 0.8,
|
||||
swing_duration: 0.2,
|
||||
recover_duration: 0.5,
|
||||
base_damage: 200,
|
||||
base_poise_damage: 50,
|
||||
knockback: 10.0,
|
||||
range: 4.0,
|
||||
max_angle: 45.0,
|
||||
damage_effect: None,
|
||||
damage_kind: Crushing,
|
||||
)
|
@ -9,5 +9,5 @@ BasicRanged(
|
||||
),
|
||||
projectile_body: Object(ArrowTurret),
|
||||
projectile_light: None,
|
||||
projectile_speed: 90.0,
|
||||
projectile_speed: 130.0,
|
||||
)
|
||||
|
@ -1,14 +1,19 @@
|
||||
BasicBeam(
|
||||
buildup_duration: 0.25,
|
||||
recover_duration: 0.25,
|
||||
beam_duration: 0.5,
|
||||
damage: 3000,
|
||||
beam_duration: 1.0,
|
||||
damage: 35,
|
||||
tick_rate: 3.0,
|
||||
range: 30.0,
|
||||
range: 20.0,
|
||||
max_angle: 15.0,
|
||||
damage_effect: None,
|
||||
damage_effect: Some(Buff((
|
||||
kind: Burning,
|
||||
dur_secs: 10.0,
|
||||
strength: DamageFraction(0.5),
|
||||
chance: 0.25,
|
||||
))),
|
||||
energy_regen: 0,
|
||||
energy_drain: 0,
|
||||
orientation_behavior: Turret,
|
||||
orientation_behavior: Normal,
|
||||
specifier: Flamethrower,
|
||||
)
|
13
assets/common/items/npc_armor/golem/claygolem.ron
Normal file
13
assets/common/items/npc_armor/golem/claygolem.ron
Normal file
@ -0,0 +1,13 @@
|
||||
ItemDef(
|
||||
name: "Clay Golem Armor",
|
||||
description: "Worn by clay golem.",
|
||||
kind: Armor((
|
||||
kind: Chest("Clay Golem"),
|
||||
stats: (
|
||||
protection: Normal(180.0),
|
||||
poise_resilience: Normal(1.0),
|
||||
),
|
||||
)),
|
||||
quality: Legendary,
|
||||
tags: [],
|
||||
)
|
19
assets/common/items/npc_weapons/unique/clay_golem_fist.ron
Normal file
19
assets/common/items/npc_weapons/unique/clay_golem_fist.ron
Normal file
@ -0,0 +1,19 @@
|
||||
ItemDef(
|
||||
name: "Clay Golem Fists",
|
||||
description: "Yeet.",
|
||||
kind: Tool((
|
||||
kind: Natural,
|
||||
hands: Two,
|
||||
stats: Direct((
|
||||
equip_time_secs: 0.001,
|
||||
power: 1.0,
|
||||
poise_strength: 1.0,
|
||||
speed: 1.0,
|
||||
crit_chance: 0.1,
|
||||
crit_mult: 1.5,
|
||||
)),
|
||||
)),
|
||||
quality: Low,
|
||||
tags: [],
|
||||
ability_spec: Some(Custom("Clay Golem")),
|
||||
)
|
19
assets/common/items/npc_weapons/unique/haniwa_sentry.ron
Normal file
19
assets/common/items/npc_weapons/unique/haniwa_sentry.ron
Normal file
@ -0,0 +1,19 @@
|
||||
ItemDef(
|
||||
name: "Haniwa Sentry",
|
||||
description: "Rotating turret weapon",
|
||||
kind: Tool((
|
||||
kind: Natural,
|
||||
hands: Two,
|
||||
stats: Direct((
|
||||
equip_time_secs: 0.01,
|
||||
power: 1.0,
|
||||
poise_strength: 1.0,
|
||||
speed: 1.0,
|
||||
crit_chance: 0.0625,
|
||||
crit_mult: 1.9142857,
|
||||
)),
|
||||
)),
|
||||
quality: Low,
|
||||
tags: [],
|
||||
ability_spec: Some(Custom("Haniwa Sentry")),
|
||||
)
|
@ -1,5 +1,5 @@
|
||||
ItemDef(
|
||||
name: "Emerald Staff",
|
||||
name: "Emerald Sceptre",
|
||||
description: "Its stone is the closest thing from perfection",
|
||||
kind: Tool((
|
||||
kind: Sceptre,
|
||||
|
@ -55,4 +55,19 @@
|
||||
("common.items.weapons.sceptre.fork0", 1),
|
||||
("common.items.consumable.potion_med", 100),
|
||||
],
|
||||
"tier-3": [
|
||||
("common.items.armor.plate.belt", 1),
|
||||
("common.items.armor.plate.chest", 1),
|
||||
("common.items.armor.plate.foot", 1),
|
||||
("common.items.armor.plate.hand", 1),
|
||||
("common.items.armor.plate.pants", 1),
|
||||
("common.items.armor.plate.shoulder", 1),
|
||||
("common.items.weapons.sword.steel-0", 1),
|
||||
("common.items.weapons.axe.steel_axe-0", 1),
|
||||
("common.items.weapons.hammer.steel_hammer-0", 1),
|
||||
("common.items.weapons.bow.metal-0", 1),
|
||||
("common.items.weapons.staff.flamethrower_0", 1),
|
||||
("common.items.weapons.sceptre.coralline_cane", 1),
|
||||
("common.items.consumable.potion_med", 100),
|
||||
],
|
||||
})
|
||||
|
@ -66,6 +66,7 @@ const int STATIC_SMOKE = 24;
|
||||
const int BLOOD = 25;
|
||||
const int ENRAGED = 26;
|
||||
const int BIG_SHRAPNEL = 27;
|
||||
const int LASER = 28;
|
||||
|
||||
// meters per second squared (acceleration)
|
||||
const float earth_gravity = 9.807;
|
||||
@ -168,114 +169,125 @@ void main() {
|
||||
Attr attr;
|
||||
f_reflect = 1.0;
|
||||
|
||||
if (inst_mode == SMOKE) {
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
vec3(0),
|
||||
vec3(rand2 * 0.02, rand3 * 0.02, 1.0 + rand4 * 0.1)
|
||||
),
|
||||
vec3(linear_scale(0.5)),
|
||||
vec4(vec3(0.8, 0.8, 1) * 0.5, start_end(1.0, 0.0)),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3 + lifetime * 0.5)
|
||||
);
|
||||
} else if (inst_mode == FIRE) {
|
||||
f_reflect = 0.0; // Fire doesn't reflect light, it emits it
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
vec3(0.0),
|
||||
vec3(rand2 * 0.1, rand3 * 0.1, 2.0 + rand4 * 1.0)
|
||||
),
|
||||
vec3(1.0),
|
||||
vec4(2, 1.5 + rand5 * 0.5, 0, start_end(1.0, 0.0)),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3)
|
||||
);
|
||||
} else if (inst_mode == FIRE_BOWL) {
|
||||
f_reflect = 0.0; // Fire doesn't reflect light, it emits it
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
vec3(normalize(vec2(rand0, rand1)) * 0.1, 0.6),
|
||||
vec3(rand2 * 0.2, rand3 * 0.5, 0.8 + rand4 * 0.5)
|
||||
),
|
||||
vec3(0.2), // Size
|
||||
vec4(2, 1.5 + rand5 * 0.5, 0, start_end(1.0, 0.0)), // Colour
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3)
|
||||
);
|
||||
} else if (inst_mode == GUN_POWDER_SPARK) {
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
normalize(vec3(rand0, rand1, rand3)) * 0.3,
|
||||
normalize(vec3(rand4, rand5, rand6)) * 4.0 + grav_vel(earth_gravity)
|
||||
),
|
||||
vec3(1.0),
|
||||
vec4(3.5, 3 + rand7, 0, 1),
|
||||
spin_in_axis(vec3(1,0,0),0)
|
||||
);
|
||||
} else if (inst_mode == SHRAPNEL) {
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
vec3(0),
|
||||
normalize(vec3(rand4, rand5, rand6)) * 20.0 + grav_vel(earth_gravity)
|
||||
),
|
||||
vec3(1),
|
||||
vec4(vec3(0.25), 1),
|
||||
spin_in_axis(vec3(1,0,0),0)
|
||||
);
|
||||
} else if (inst_mode == BIG_SHRAPNEL) {
|
||||
float brown_color = 0.05 + 0.1 * rand1;
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
vec3(0),
|
||||
normalize(vec3(rand4, rand5, rand6)) * 15.0 + grav_vel(earth_gravity)
|
||||
),
|
||||
vec3(5 * (1 - percent())),
|
||||
vec4(vec3(brown_color, brown_color / 2, 0), 1),
|
||||
spin_in_axis(vec3(1,0,0),0)
|
||||
);
|
||||
} else if (inst_mode == FIREWORK_BLUE) {
|
||||
f_reflect = 0.0; // Fire doesn't reflect light, it emits it
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
vec3(0),
|
||||
normalize(vec3(rand1, rand2, rand3)) * 40.0 + grav_vel(earth_gravity)
|
||||
),
|
||||
vec3(3.0 + rand0),
|
||||
vec4(vec3(0, 0, 2), 1),
|
||||
identity()
|
||||
);
|
||||
} else if (inst_mode == FIREWORK_GREEN) {
|
||||
f_reflect = 0.0; // Fire doesn't reflect light, it emits it
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
vec3(0),
|
||||
normalize(vec3(rand1, rand2, rand3)) * 40.0 + grav_vel(earth_gravity)
|
||||
),
|
||||
vec3(3.0 + rand0),
|
||||
vec4(vec3(0, 2, 0), 1),
|
||||
identity()
|
||||
);
|
||||
} else if (inst_mode == FIREWORK_PURPLE) {
|
||||
f_reflect = 0.0; // Fire doesn't reflect light, it emits it
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
vec3(0),
|
||||
normalize(vec3(rand1, rand2, rand3)) * 40.0 + grav_vel(earth_gravity)
|
||||
),
|
||||
vec3(3.0 + rand0),
|
||||
vec4(vec3(2, 0, 2), 1),
|
||||
identity()
|
||||
);
|
||||
} else if (inst_mode == FIREWORK_RED) {
|
||||
f_reflect = 0.0; // Fire doesn't reflect light, it emits it
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
vec3(0),
|
||||
normalize(vec3(rand1, rand2, rand3)) * 40.0 + grav_vel(earth_gravity)
|
||||
),
|
||||
vec3(3.0 + rand0),
|
||||
vec4(vec3(2, 0, 0), 1),
|
||||
identity()
|
||||
);
|
||||
} else if (inst_mode == FIREWORK_WHITE) {
|
||||
switch(inst_mode) {
|
||||
case SMOKE:
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
vec3(0),
|
||||
vec3(rand2 * 0.02, rand3 * 0.02, 1.0 + rand4 * 0.1)
|
||||
),
|
||||
vec3(linear_scale(0.5)),
|
||||
vec4(vec3(0.8, 0.8, 1) * 0.5, start_end(1.0, 0.0)),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3 + lifetime * 0.5)
|
||||
);
|
||||
break;
|
||||
case FIRE:
|
||||
f_reflect = 0.0; // Fire doesn't reflect light, it emits it
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
vec3(0.0),
|
||||
vec3(rand2 * 0.1, rand3 * 0.1, 2.0 + rand4 * 1.0)
|
||||
),
|
||||
vec3(1.0),
|
||||
vec4(2, 1.5 + rand5 * 0.5, 0, start_end(1.0, 0.0)),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3)
|
||||
);
|
||||
break;
|
||||
case FIRE_BOWL:
|
||||
f_reflect = 0.0; // Fire doesn't reflect light, it emits it
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
vec3(normalize(vec2(rand0, rand1)) * 0.1, 0.6),
|
||||
vec3(rand2 * 0.2, rand3 * 0.5, 0.8 + rand4 * 0.5)
|
||||
),
|
||||
vec3(0.2), // Size
|
||||
vec4(2, 1.5 + rand5 * 0.5, 0, start_end(1.0, 0.0)), // Colour
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3)
|
||||
);
|
||||
break;
|
||||
case GUN_POWDER_SPARK:
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
normalize(vec3(rand0, rand1, rand3)) * 0.3,
|
||||
normalize(vec3(rand4, rand5, rand6)) * 4.0 + grav_vel(earth_gravity)
|
||||
),
|
||||
vec3(1.0),
|
||||
vec4(3.5, 3 + rand7, 0, 1),
|
||||
spin_in_axis(vec3(1,0,0),0)
|
||||
);
|
||||
break;
|
||||
case SHRAPNEL:
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
vec3(0),
|
||||
normalize(vec3(rand4, rand5, rand6)) * 20.0 + grav_vel(earth_gravity)
|
||||
),
|
||||
vec3(1),
|
||||
vec4(vec3(0.25), 1),
|
||||
spin_in_axis(vec3(1,0,0),0)
|
||||
);
|
||||
break;
|
||||
case BIG_SHRAPNEL:
|
||||
float brown_color = 0.05 + 0.1 * rand1;
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
vec3(0),
|
||||
normalize(vec3(rand4, rand5, rand6)) * 15.0 + grav_vel(earth_gravity)
|
||||
),
|
||||
vec3(5 * (1 - percent())),
|
||||
vec4(vec3(brown_color, brown_color / 2, 0), 1),
|
||||
spin_in_axis(vec3(1,0,0),0)
|
||||
);
|
||||
break;
|
||||
case FIREWORK_BLUE:
|
||||
f_reflect = 0.0; // Fire doesn't reflect light, it emits it
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
vec3(0),
|
||||
normalize(vec3(rand1, rand2, rand3)) * 40.0 + grav_vel(earth_gravity)
|
||||
),
|
||||
vec3(3.0 + rand0),
|
||||
vec4(vec3(0, 0, 2), 1),
|
||||
identity()
|
||||
);
|
||||
break;
|
||||
case FIREWORK_GREEN:
|
||||
f_reflect = 0.0; // Fire doesn't reflect light, it emits it
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
vec3(0),
|
||||
normalize(vec3(rand1, rand2, rand3)) * 40.0 + grav_vel(earth_gravity)
|
||||
),
|
||||
vec3(3.0 + rand0),
|
||||
vec4(vec3(0, 2, 0), 1),
|
||||
identity()
|
||||
);
|
||||
break;
|
||||
case FIREWORK_PURPLE:
|
||||
f_reflect = 0.0; // Fire doesn't reflect light, it emits it
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
vec3(0),
|
||||
normalize(vec3(rand1, rand2, rand3)) * 40.0 + grav_vel(earth_gravity)
|
||||
),
|
||||
vec3(3.0 + rand0),
|
||||
vec4(vec3(2, 0, 2), 1),
|
||||
identity()
|
||||
);
|
||||
break;
|
||||
case FIREWORK_RED:
|
||||
f_reflect = 0.0; // Fire doesn't reflect light, it emits it
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
vec3(0),
|
||||
normalize(vec3(rand1, rand2, rand3)) * 40.0 + grav_vel(earth_gravity)
|
||||
),
|
||||
vec3(3.0 + rand0),
|
||||
vec4(vec3(2, 0, 0), 1),
|
||||
identity()
|
||||
);
|
||||
break;
|
||||
case FIREWORK_WHITE:
|
||||
f_reflect = 0.0; // Fire doesn't reflect light, it emits it
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
@ -286,173 +298,208 @@ void main() {
|
||||
vec4(vec3(2, 2, 2), 1),
|
||||
identity()
|
||||
);
|
||||
} else if (inst_mode == FIREWORK_YELLOW) {
|
||||
f_reflect = 0.0; // Fire doesn't reflect light, it emits it
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
break;
|
||||
case FIREWORK_YELLOW:
|
||||
f_reflect = 0.0; // Fire doesn't reflect light, it emits it
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
vec3(0),
|
||||
normalize(vec3(rand1, rand2, rand3)) * 40.0 + grav_vel(earth_gravity)
|
||||
),
|
||||
vec3(3.0 + rand0),
|
||||
vec4(vec3(2, 2, 0), 1),
|
||||
identity()
|
||||
);
|
||||
break;
|
||||
case LEAF:
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
vec3(0),
|
||||
vec3(0, 0, -2)
|
||||
) + vec3(sin(lifetime), sin(lifetime + 0.7), sin(lifetime * 0.5)) * 2.0,
|
||||
vec3(4),
|
||||
vec4(vec3(0.2 + rand7 * 0.2, 0.2 + (0.25 + rand6 * 0.5) * 0.3, 0) * (0.75 + rand1 * 0.5), 1),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3 + lifetime * 5)
|
||||
);
|
||||
break;
|
||||
case SNOW:
|
||||
float height = mix(-4, 60, pow(start_end(1, 0), 3));
|
||||
float wind_speed = (inst_pos.z - 2000) * 0.025;
|
||||
vec3 offset = linear_motion(vec3(0), vec3(1, 1, 0) * wind_speed);
|
||||
float end_alt = alt_at(start_pos.xy + offset.xy);
|
||||
attr = Attr(
|
||||
offset + vec3(0, 0, end_alt - start_pos.z + height) + vec3(sin(lifetime), sin(lifetime + 0.7), sin(lifetime * 0.5)) * 3,
|
||||
vec3(mix(4, 0, pow(start_end(1, 0), 4))),
|
||||
vec4(1),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3 + lifetime * 5)
|
||||
);
|
||||
break;
|
||||
case FIREFLY:
|
||||
float raise = pow(sin(3.1416 * lifetime / inst_lifespan), 0.2);
|
||||
attr = Attr(
|
||||
vec3(0, 0, raise * 5.0) + vec3(
|
||||
sin(lifetime * 1.0 + rand0) + sin(lifetime * 7.0 + rand3) * 0.3,
|
||||
sin(lifetime * 3.0 + rand1) + sin(lifetime * 8.0 + rand4) * 0.3,
|
||||
sin(lifetime * 2.0 + rand2) + sin(lifetime * 9.0 + rand5) * 0.3
|
||||
),
|
||||
vec3(raise),
|
||||
vec4(vec3(5, 5, 1.1), 1),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3 + lifetime * 5)
|
||||
);
|
||||
break;
|
||||
case BEE:
|
||||
float lower = pow(sin(3.1416 * lifetime / inst_lifespan), 0.2);
|
||||
attr = Attr(
|
||||
vec3(0, 0, lower * -0.5) + vec3(
|
||||
sin(lifetime * 2.0 + rand0) + sin(lifetime * 9.0 + rand3) * 0.3,
|
||||
sin(lifetime * 3.0 + rand1) + sin(lifetime * 10.0 + rand4) * 0.3,
|
||||
sin(lifetime * 4.0 + rand2) + sin(lifetime * 11.0 + rand5) * 0.3
|
||||
) * 0.5,
|
||||
vec3(lower),
|
||||
vec4(vec3(1, 0.7, 0), 1),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3 + lifetime * 5)
|
||||
);
|
||||
break;
|
||||
case GROUND_SHOCKWAVE:
|
||||
attr = Attr(
|
||||
vec3(0.0),
|
||||
vec3(11.0, 11.0, (33.0 * rand0 * sin(2.0 * lifetime * 3.14 * 2.0))) / 3,
|
||||
vec4(vec3(0.32 + (rand0 * 0.04), 0.22 + (rand1 * 0.03), 0.05 + (rand2 * 0.01)), 1),
|
||||
spin_in_axis(vec3(1,0,0),0)
|
||||
);
|
||||
break;
|
||||
case HEALING_BEAM:
|
||||
f_reflect = 0.0;
|
||||
attr = Attr(
|
||||
spiral_motion(inst_dir, 0.3 * (floor(2 * rand0 + 0.5) - 0.5) * min(linear_scale(10), 1), lifetime / inst_lifespan, 10.0, inst_time),
|
||||
vec3((1.7 - 0.7 * abs(floor(2 * rand0 - 0.5) + 0.5)) * (1.5 + 0.5 * sin(tick.x * 10 - lifetime * 4))),
|
||||
vec4(vec3(0.4, 1.6 + 0.3 * sin(tick.x * 10 - lifetime * 3 + 4), 1.0 + 0.15 * sin(tick.x * 5 - lifetime * 5)), 1 /*0.3*/),
|
||||
spin_in_axis(inst_dir, tick.z)
|
||||
);
|
||||
break;
|
||||
case LIFESTEAL_BEAM:
|
||||
f_reflect = 0.0;
|
||||
float green_col = 0.2 + 1.4 * sin(tick.x * 5 + lifetime * 5);
|
||||
float purple_col = 1.2 + 0.1 * sin(tick.x * 3 - lifetime * 3) - max(green_col, 1) + 1;
|
||||
attr = Attr(
|
||||
spiral_motion(inst_dir, 0.3 * (floor(2 * rand0 + 0.5) - 0.5) * min(linear_scale(10), 1), lifetime / inst_lifespan, 10.0, inst_time),
|
||||
vec3((1.7 - 0.7 * abs(floor(2 * rand0 - 0.5) + 0.5)) * (1.5 + 0.5 * sin(tick.x * 10 - lifetime * 4))),
|
||||
vec4(vec3(purple_col, green_col, 0.75 * purple_col), 1),
|
||||
spin_in_axis(inst_dir, tick.z)
|
||||
);
|
||||
break;
|
||||
case ENERGY_NATURE:
|
||||
f_reflect = 0.0;
|
||||
float spiral_radius = start_end(1 - pow(abs(rand5), 5), 1) * length(inst_dir);
|
||||
attr = Attr(
|
||||
spiral_motion(vec3(0, 0, rand3 + 1), spiral_radius, lifetime, abs(rand0), rand1 * 2 * PI) + vec3(0, 0, rand2),
|
||||
vec3(6 * abs(rand4) * (1 - slow_start(2)) * pow(spiral_radius / length(inst_dir), 0.5)),
|
||||
vec4(vec3(0, 1.7, 1.3), 1),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3)
|
||||
);
|
||||
break;
|
||||
case FLAMETHROWER:
|
||||
f_reflect = 0.0; // Fire doesn't reflect light, it emits it
|
||||
attr = Attr(
|
||||
(inst_dir * slow_end(1.5)) + vec3(rand0, rand1, rand2) * (percent() + 2) * 0.1,
|
||||
vec3((2.5 * (1 - slow_start(0.2)))),
|
||||
vec4(3, 1.6 + rand5 * 0.3 - 0.4 * percent(), 0.2, 1),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), percent() * 10 + 3 * rand9)
|
||||
);
|
||||
break;
|
||||
case EXPLOSION:
|
||||
f_reflect = 0.0; // Fire doesn't reflect light, it emits it
|
||||
attr = Attr(
|
||||
inst_dir * ((rand0+1.0)/2 + 0.4) * slow_end(2.0) + 0.3 * grav_vel(earth_gravity),
|
||||
vec3((3 * (1 - slow_start(0.1)))),
|
||||
vec4(3, 1.6 + rand5 * 0.3 - 0.4 * percent(), 0.2, 1),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), percent() * 10 + 3 * rand9)
|
||||
);
|
||||
break;
|
||||
case ICE:
|
||||
f_reflect = 0.0; // Ice doesn't reflect to look like magic
|
||||
attr = Attr(
|
||||
inst_dir * ((rand0+1.0)/2 + 0.4) * slow_end(2.0) + 0.3 * grav_vel(earth_gravity),
|
||||
vec3((3 * (1 - slow_start(0.1)))),
|
||||
vec4(0.2, 1.6 + rand5 * 0.3 - 0.4 * percent(), 3, 1),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), percent() * 10 + 3 * rand9)
|
||||
);
|
||||
break;
|
||||
case FIRE_SHOCKWAVE:
|
||||
f_reflect = 0.0; // Fire doesn't reflect light, it emits it
|
||||
attr = Attr(
|
||||
vec3(rand0, rand1, lifetime * 10 + rand2),
|
||||
vec3((5 * (1 - slow_start(0.5)))),
|
||||
vec4(3, 1.6 + rand5 * 0.3 - 0.4 * percent(), 0.2, 1),
|
||||
spin_in_axis(vec3(rand3, rand4, rand5), rand6)
|
||||
);
|
||||
break;
|
||||
case CULTIST_FLAME:
|
||||
f_reflect = 0.0; // Fire doesn't reflect light, it emits it
|
||||
float purp_color = 0.9 + 0.3 * rand3;
|
||||
attr = Attr(
|
||||
(inst_dir * slow_end(1.5)) + vec3(rand0, rand1, rand2) * (percent() + 2) * 0.1,
|
||||
vec3((3.5 * (1 - slow_start(0.2)))),
|
||||
vec4(purp_color, 0.0, purp_color, 1),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), percent() * 10 + 3 * rand9)
|
||||
);
|
||||
break;
|
||||
case STATIC_SMOKE:
|
||||
attr = Attr(
|
||||
vec3(0),
|
||||
normalize(vec3(rand1, rand2, rand3)) * 40.0 + grav_vel(earth_gravity)
|
||||
),
|
||||
vec3(3.0 + rand0),
|
||||
vec4(vec3(2, 2, 0), 1),
|
||||
identity()
|
||||
);
|
||||
} else if (inst_mode == LEAF) {
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
vec3(0),
|
||||
vec3(0, 0, -2)
|
||||
) + vec3(sin(lifetime), sin(lifetime + 0.7), sin(lifetime * 0.5)) * 2.0,
|
||||
vec3(4),
|
||||
vec4(vec3(0.2 + rand7 * 0.2, 0.2 + (0.25 + rand6 * 0.5) * 0.3, 0) * (0.75 + rand1 * 0.5), 1),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3 + lifetime * 5)
|
||||
);
|
||||
} else if (inst_mode == SNOW) {
|
||||
float height = mix(-4, 60, pow(start_end(1, 0), 3));
|
||||
float wind_speed = (inst_pos.z - 2000) * 0.025;
|
||||
vec3 offset = linear_motion(vec3(0), vec3(1, 1, 0) * wind_speed);
|
||||
float end_alt = alt_at(start_pos.xy + offset.xy);
|
||||
attr = Attr(
|
||||
offset + vec3(0, 0, end_alt - start_pos.z + height) + vec3(sin(lifetime), sin(lifetime + 0.7), sin(lifetime * 0.5)) * 3,
|
||||
vec3(mix(4, 0, pow(start_end(1, 0), 4))),
|
||||
vec4(1),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3 + lifetime * 5)
|
||||
);
|
||||
} else if (inst_mode == FIREFLY) {
|
||||
float raise = pow(sin(3.1416 * lifetime / inst_lifespan), 0.2);
|
||||
attr = Attr(
|
||||
vec3(0, 0, raise * 5.0) + vec3(
|
||||
sin(lifetime * 1.0 + rand0) + sin(lifetime * 7.0 + rand3) * 0.3,
|
||||
sin(lifetime * 3.0 + rand1) + sin(lifetime * 8.0 + rand4) * 0.3,
|
||||
sin(lifetime * 2.0 + rand2) + sin(lifetime * 9.0 + rand5) * 0.3
|
||||
),
|
||||
vec3(raise),
|
||||
vec4(vec3(5, 5, 1.1), 1),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3 + lifetime * 5)
|
||||
);
|
||||
} else if (inst_mode == BEE) {
|
||||
float lower = pow(sin(3.1416 * lifetime / inst_lifespan), 0.2);
|
||||
attr = Attr(
|
||||
vec3(0, 0, lower * -0.5) + vec3(
|
||||
sin(lifetime * 2.0 + rand0) + sin(lifetime * 9.0 + rand3) * 0.3,
|
||||
sin(lifetime * 3.0 + rand1) + sin(lifetime * 10.0 + rand4) * 0.3,
|
||||
sin(lifetime * 4.0 + rand2) + sin(lifetime * 11.0 + rand5) * 0.3
|
||||
) * 0.5,
|
||||
vec3(lower),
|
||||
vec4(vec3(1, 0.7, 0), 1),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3 + lifetime * 5)
|
||||
);
|
||||
} else if (inst_mode == GROUND_SHOCKWAVE) {
|
||||
attr = Attr(
|
||||
vec3(0.0),
|
||||
vec3(11.0, 11.0, (33.0 * rand0 * sin(2.0 * lifetime * 3.14 * 2.0))) / 3,
|
||||
vec4(vec3(0.32 + (rand0 * 0.04), 0.22 + (rand1 * 0.03), 0.05 + (rand2 * 0.01)), 1),
|
||||
spin_in_axis(vec3(1,0,0),0)
|
||||
);
|
||||
} else if (inst_mode == HEALING_BEAM) {
|
||||
f_reflect = 0.0;
|
||||
attr = Attr(
|
||||
spiral_motion(inst_dir, 0.3 * (floor(2 * rand0 + 0.5) - 0.5) * min(linear_scale(10), 1), lifetime / inst_lifespan, 10.0, inst_time),
|
||||
vec3((1.7 - 0.7 * abs(floor(2 * rand0 - 0.5) + 0.5)) * (1.5 + 0.5 * sin(tick.x * 10 - lifetime * 4))),
|
||||
vec4(vec3(0.4, 1.6 + 0.3 * sin(tick.x * 10 - lifetime * 3 + 4), 1.0 + 0.15 * sin(tick.x * 5 - lifetime * 5)), 1 /*0.3*/),
|
||||
spin_in_axis(inst_dir, tick.z)
|
||||
);
|
||||
} else if (inst_mode == LIFESTEAL_BEAM) {
|
||||
f_reflect = 0.0;
|
||||
float green_col = 0.2 + 1.4 * sin(tick.x * 5 + lifetime * 5);
|
||||
float purple_col = 1.2 + 0.1 * sin(tick.x * 3 - lifetime * 3) - max(green_col, 1) + 1;
|
||||
attr = Attr(
|
||||
spiral_motion(inst_dir, 0.3 * (floor(2 * rand0 + 0.5) - 0.5) * min(linear_scale(10), 1), lifetime / inst_lifespan, 10.0, inst_time),
|
||||
vec3((1.7 - 0.7 * abs(floor(2 * rand0 - 0.5) + 0.5)) * (1.5 + 0.5 * sin(tick.x * 10 - lifetime * 4))),
|
||||
vec4(vec3(purple_col, green_col, 0.75 * purple_col), 1),
|
||||
spin_in_axis(inst_dir, tick.z)
|
||||
);
|
||||
} else if (inst_mode == ENERGY_NATURE) {
|
||||
f_reflect = 0.0;
|
||||
float spiral_radius = start_end(1 - pow(abs(rand5), 5), 1) * length(inst_dir);
|
||||
attr = Attr(
|
||||
spiral_motion(vec3(0, 0, rand3 + 1), spiral_radius, lifetime, abs(rand0), rand1 * 2 * PI) + vec3(0, 0, rand2),
|
||||
vec3(6 * abs(rand4) * (1 - slow_start(2)) * pow(spiral_radius / length(inst_dir), 0.5)),
|
||||
vec4(vec3(0, 1.7, 1.3), 1),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3)
|
||||
);
|
||||
} else if (inst_mode == FLAMETHROWER) {
|
||||
f_reflect = 0.0; // Fire doesn't reflect light, it emits it
|
||||
attr = Attr(
|
||||
(inst_dir * slow_end(1.5)) + vec3(rand0, rand1, rand2) * (percent() + 2) * 0.1,
|
||||
vec3((2.5 * (1 - slow_start(0.2)))),
|
||||
vec4(3, 1.6 + rand5 * 0.3 - 0.4 * percent(), 0.2, 1),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), percent() * 10 + 3 * rand9)
|
||||
);
|
||||
} else if (inst_mode == EXPLOSION) {
|
||||
f_reflect = 0.0; // Fire doesn't reflect light, it emits it
|
||||
attr = Attr(
|
||||
inst_dir * ((rand0+1.0)/2 + 0.4) * slow_end(2.0) + 0.3 * grav_vel(earth_gravity),
|
||||
vec3((3 * (1 - slow_start(0.1)))),
|
||||
vec4(3, 1.6 + rand5 * 0.3 - 0.4 * percent(), 0.2, 1),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), percent() * 10 + 3 * rand9)
|
||||
);
|
||||
} else if (inst_mode == ICE) {
|
||||
f_reflect = 0.0; // Ice doesn't reflect to look like magic
|
||||
attr = Attr(
|
||||
inst_dir * ((rand0+1.0)/2 + 0.4) * slow_end(2.0) + 0.3 * grav_vel(earth_gravity),
|
||||
vec3((3 * (1 - slow_start(0.1)))),
|
||||
vec4(0.2, 1.6 + rand5 * 0.3 - 0.4 * percent(), 3, 1),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), percent() * 10 + 3 * rand9)
|
||||
);
|
||||
} else if (inst_mode == FIRE_SHOCKWAVE) {
|
||||
f_reflect = 0.0; // Fire doesn't reflect light, it emits it
|
||||
attr = Attr(
|
||||
vec3(rand0, rand1, lifetime * 10 + rand2),
|
||||
vec3((5 * (1 - slow_start(0.5)))),
|
||||
vec4(3, 1.6 + rand5 * 0.3 - 0.4 * percent(), 0.2, 1),
|
||||
spin_in_axis(vec3(rand3, rand4, rand5), rand6)
|
||||
);
|
||||
} else if (inst_mode == CULTIST_FLAME) {
|
||||
f_reflect = 0.0; // Fire doesn't reflect light, it emits it
|
||||
float purp_color = 0.9 + 0.3 * rand3;
|
||||
attr = Attr(
|
||||
(inst_dir * slow_end(1.5)) + vec3(rand0, rand1, rand2) * (percent() + 2) * 0.1,
|
||||
vec3((3.5 * (1 - slow_start(0.2)))),
|
||||
vec4(purp_color, 0.0, purp_color, 1),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), percent() * 10 + 3 * rand9)
|
||||
);
|
||||
} else if (inst_mode == STATIC_SMOKE) {
|
||||
attr = Attr(
|
||||
vec3(0),
|
||||
vec3((0.5 * (1 - slow_start(0.8)))),
|
||||
vec4(1.0),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), rand9)
|
||||
);
|
||||
} else if (inst_mode == BLOOD) {
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
vec3(0),
|
||||
normalize(vec3(rand4, rand5, rand6)) * 5.0 + grav_vel(earth_gravity)
|
||||
),
|
||||
vec3((2.0 * (1 - slow_start(0.8)))),
|
||||
vec4(1, 0, 0, 1),
|
||||
spin_in_axis(vec3(1,0,0),0)
|
||||
);
|
||||
} else if (inst_mode == ENRAGED) {
|
||||
f_reflect = 0.0;
|
||||
float red_color = 1.2 + 0.3 * rand3;
|
||||
attr = Attr(
|
||||
(inst_dir * slow_end(1.5)) + vec3(rand0, rand1, rand2) * (percent() + 2) * 0.1,
|
||||
vec3((3.5 * (1 - slow_start(0.2)))),
|
||||
vec4(red_color, 0.0, 0.0, 1),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), percent() * 10 + 3 * rand9)
|
||||
);
|
||||
} else {
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
vec3(rand0 * 0.25, rand1 * 0.25, 1.7 + rand5),
|
||||
vec3(rand2 * 0.1, rand3 * 0.1, 1.0 + rand4 * 0.5)
|
||||
),
|
||||
vec3(exp_scale(-0.2)),
|
||||
vec4(1),
|
||||
spin_in_axis(vec3(1,0,0),0)
|
||||
);
|
||||
vec3((0.5 * (1 - slow_start(0.8)))),
|
||||
vec4(1.0),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), rand9)
|
||||
);
|
||||
break;
|
||||
case BLOOD:
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
vec3(0),
|
||||
normalize(vec3(rand4, rand5, rand6)) * 5.0 + grav_vel(earth_gravity)
|
||||
),
|
||||
vec3((2.0 * (1 - slow_start(0.8)))),
|
||||
vec4(1, 0, 0, 1),
|
||||
spin_in_axis(vec3(1,0,0),0)
|
||||
);
|
||||
break;
|
||||
case ENRAGED:
|
||||
f_reflect = 0.0;
|
||||
float red_color = 1.2 + 0.3 * rand3;
|
||||
attr = Attr(
|
||||
(inst_dir * slow_end(1.5)) + vec3(rand0, rand1, rand2) * (percent() + 2) * 0.1,
|
||||
vec3((3.5 * (1 - slow_start(0.2)))),
|
||||
vec4(red_color, 0.0, 0.0, 1),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), percent() * 10 + 3 * rand9)
|
||||
);
|
||||
break;
|
||||
case LASER:
|
||||
f_reflect = 0.0;
|
||||
vec3 perp_axis = normalize(cross(inst_dir, vec3(0.0, 0.0, 1.0)));
|
||||
offset = vec3(0.0);
|
||||
if (rand0 > 0.0) {
|
||||
offset = perp_axis * 0.5;
|
||||
} else {
|
||||
offset = perp_axis * -0.5;
|
||||
}
|
||||
attr = Attr(
|
||||
inst_dir * percent() + offset,
|
||||
vec3(1.0, 1.0, 50.0),
|
||||
vec4(vec3(2.0, 0.0, 0.0), 1),
|
||||
spin_in_axis(perp_axis, asin(inst_dir.z / length(inst_dir)) + PI / 2.0)
|
||||
);
|
||||
break;
|
||||
default:
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
vec3(rand0 * 0.25, rand1 * 0.25, 1.7 + rand5),
|
||||
vec3(rand2 * 0.1, rand3 * 0.1, 1.0 + rand4 * 0.5)
|
||||
),
|
||||
vec3(exp_scale(-0.2)),
|
||||
vec4(1),
|
||||
spin_in_axis(vec3(1,0,0),0)
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
// Temporary: use shrinking particles as a substitute for fading ones
|
||||
|
@ -73,7 +73,7 @@
|
||||
),
|
||||
(ClayGolem, Male): (
|
||||
head: (
|
||||
offset: (-10.5, -6.0, -5.0),
|
||||
offset: (-10.5, -3.0, -3.0),
|
||||
central: ("npc.claygolem.male.head"),
|
||||
),
|
||||
jaw: (
|
||||
@ -91,7 +91,7 @@
|
||||
),
|
||||
(ClayGolem, Female): (
|
||||
head: (
|
||||
offset: (-10.5, -6.0, -5.0),
|
||||
offset: (-10.5, -3.0, -3.0),
|
||||
central: ("npc.claygolem.male.head"),
|
||||
),
|
||||
jaw: (
|
||||
|
BIN
assets/voxygen/voxel/object/haniwa_sentry/bone0.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/object/haniwa_sentry/bone0.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/object/haniwa_sentry/bone1.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/object/haniwa_sentry/bone1.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -655,7 +655,7 @@
|
||||
central: ("object.crossbow.bone0"),
|
||||
),
|
||||
bone1: (
|
||||
offset: (-9.0, -7.0, -5.0 ),
|
||||
offset: (-9.0, -7.0, -5.0),
|
||||
central: ("object.crossbow.bone1"),
|
||||
)
|
||||
),
|
||||
@ -689,4 +689,24 @@
|
||||
central: ("armor.empty"),
|
||||
)
|
||||
),
|
||||
ClayRocket: (
|
||||
bone0: (
|
||||
offset: (-0.5, -6.0, -1.5),
|
||||
central: ("weapon.projectile.clay-missile"),
|
||||
),
|
||||
bone1: (
|
||||
offset: (0.0, 0.0, 0.0),
|
||||
central: ("armor.empty"),
|
||||
)
|
||||
),
|
||||
HaniwaSentry: (
|
||||
bone0: (
|
||||
offset: (-5.5, -4.5, -5.5),
|
||||
central: ("object.haniwa_sentry.bone0"),
|
||||
),
|
||||
bone1: (
|
||||
offset: (-5.5, -5.5, -3.0),
|
||||
central: ("object.haniwa_sentry.bone1"),
|
||||
)
|
||||
),
|
||||
})
|
||||
|
BIN
assets/voxygen/voxel/weapon/projectile/clay-missile.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/weapon/projectile/clay-missile.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -243,7 +243,7 @@ pub enum CharacterAbility {
|
||||
damage_effect: Option<CombatEffect>,
|
||||
energy_regen: f32,
|
||||
energy_drain: f32,
|
||||
orientation_behavior: basic_beam::MovementBehavior,
|
||||
orientation_behavior: basic_beam::OrientationBehavior,
|
||||
specifier: beam::FrontendSpecifier,
|
||||
},
|
||||
BasicAura {
|
||||
|
@ -52,4 +52,5 @@ pub enum FrontendSpecifier {
|
||||
LifestealBeam,
|
||||
HealingBeam,
|
||||
Cultist,
|
||||
ClayGolem,
|
||||
}
|
||||
|
@ -288,7 +288,7 @@ impl Body {
|
||||
Body::Dragon(_) => Vec3::new(16.0, 10.0, 16.0),
|
||||
Body::FishMedium(_) => Vec3::new(0.5, 2.0, 0.8),
|
||||
Body::FishSmall(_) => Vec3::new(0.3, 1.2, 0.6),
|
||||
Body::Golem(_) => Vec3::new(5.0, 5.0, 5.0),
|
||||
Body::Golem(_) => Vec3::new(5.0, 5.0, 7.5),
|
||||
Body::Humanoid(humanoid) => {
|
||||
let height = match (humanoid.species, humanoid.body_type) {
|
||||
(humanoid::Species::Orc, humanoid::BodyType::Male) => 2.3,
|
||||
@ -464,9 +464,13 @@ impl Body {
|
||||
Body::Object(object) => match object {
|
||||
object::Body::TrainingDummy => 10000,
|
||||
object::Body::Crossbow => 800,
|
||||
object::Body::HaniwaSentry => 600,
|
||||
_ => 10000,
|
||||
},
|
||||
Body::Golem(golem) => match golem.species {
|
||||
golem::Species::ClayGolem => 7500,
|
||||
_ => 10000,
|
||||
},
|
||||
Body::Golem(_) => 2740,
|
||||
Body::Theropod(theropod) => match theropod.species {
|
||||
theropod::Species::Archaeos => 3500,
|
||||
theropod::Species::Odonto => 3000,
|
||||
@ -565,7 +569,7 @@ impl Body {
|
||||
},
|
||||
Body::BipedSmall(_) => 10,
|
||||
Body::Object(_) => 10,
|
||||
Body::Golem(_) => 260,
|
||||
Body::Golem(_) => 0,
|
||||
Body::Theropod(_) => 20,
|
||||
Body::QuadrupedLow(quadruped_low) => match quadruped_low.species {
|
||||
quadruped_low::Species::Crocodile => 20,
|
||||
@ -599,6 +603,12 @@ impl Body {
|
||||
pub fn immune_to(&self, buff: BuffKind) -> bool {
|
||||
match buff {
|
||||
BuffKind::Bleeding => matches!(self, Body::Object(_) | Body::Golem(_) | Body::Ship(_)),
|
||||
BuffKind::Burning => match self {
|
||||
Body::Golem(g) => matches!(g.species, golem::Species::ClayGolem),
|
||||
Body::BipedSmall(b) => matches!(b.species, biped_small::Species::Haniwa),
|
||||
Body::Object(object::Body::HaniwaSentry) => true,
|
||||
_ => false,
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -614,6 +624,10 @@ impl Body {
|
||||
biped_large::Species::Minotaur => 3.2,
|
||||
_ => 1.0,
|
||||
},
|
||||
Body::Golem(g) => match g.species {
|
||||
golem::Species::ClayGolem => 1.2,
|
||||
_ => 1.0,
|
||||
},
|
||||
_ => 1.0,
|
||||
}
|
||||
}
|
||||
|
@ -81,6 +81,8 @@ make_case_elim!(
|
||||
Coins = 66,
|
||||
GoldOre = 67,
|
||||
SilverOre = 68,
|
||||
ClayRocket = 69,
|
||||
HaniwaSentry = 70,
|
||||
}
|
||||
);
|
||||
|
||||
@ -91,7 +93,7 @@ impl Body {
|
||||
}
|
||||
}
|
||||
|
||||
pub const ALL_OBJECTS: [Body; 69] = [
|
||||
pub const ALL_OBJECTS: [Body; 71] = [
|
||||
Body::Arrow,
|
||||
Body::Bomb,
|
||||
Body::Scarecrow,
|
||||
@ -161,6 +163,8 @@ pub const ALL_OBJECTS: [Body; 69] = [
|
||||
Body::Coins,
|
||||
Body::SilverOre,
|
||||
Body::GoldOre,
|
||||
Body::ClayRocket,
|
||||
Body::HaniwaSentry,
|
||||
];
|
||||
|
||||
impl From<Body> for super::Body {
|
||||
@ -239,6 +243,8 @@ impl Body {
|
||||
Body::Coins => "coins",
|
||||
Body::SilverOre => "silver_ore",
|
||||
Body::GoldOre => "gold_ore",
|
||||
Body::ClayRocket => "clay_rocket",
|
||||
Body::HaniwaSentry => "haniwa_sentry",
|
||||
}
|
||||
}
|
||||
|
||||
@ -328,6 +334,8 @@ impl Body {
|
||||
Body::WindowSpooky => 10.0,
|
||||
Body::SilverOre => 1000.0,
|
||||
Body::GoldOre => 1000.0,
|
||||
Body::ClayRocket => 50.0,
|
||||
Body::HaniwaSentry => 300.0,
|
||||
};
|
||||
|
||||
Mass(m)
|
||||
@ -335,8 +343,12 @@ impl Body {
|
||||
|
||||
pub fn dimensions(&self) -> Vec3<f32> {
|
||||
match self {
|
||||
Body::Arrow | Body::ArrowSnake | Body::MultiArrow => Vec3::new(0.01, 0.8, 0.01),
|
||||
Body::Arrow | Body::ArrowSnake | Body::MultiArrow | Body::ArrowTurret => {
|
||||
Vec3::new(0.01, 0.8, 0.01)
|
||||
},
|
||||
Body::BoltFire => Vec3::new(0.1, 0.1, 0.1),
|
||||
Body::Crossbow => Vec3::new(3.0, 3.0, 1.5),
|
||||
Body::HaniwaSentry => Vec3::new(0.8, 0.8, 1.4),
|
||||
_ => Vec3::broadcast(0.2),
|
||||
}
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ impl LoadoutBuilder {
|
||||
},
|
||||
golem::Species::ClayGolem => {
|
||||
main_tool = Some(Item::new_from_asset_expect(
|
||||
"common.items.npc_weapons.unique.stone_golems_fist",
|
||||
"common.items.npc_weapons.unique.clay_golem_fist",
|
||||
));
|
||||
},
|
||||
_ => {},
|
||||
@ -310,10 +310,18 @@ impl LoadoutBuilder {
|
||||
));
|
||||
},
|
||||
},
|
||||
Body::Object(object::Body::Crossbow) => {
|
||||
main_tool = Some(Item::new_from_asset_expect(
|
||||
"common.items.npc_weapons.unique.turret",
|
||||
));
|
||||
Body::Object(body) => match body {
|
||||
object::Body::Crossbow => {
|
||||
main_tool = Some(Item::new_from_asset_expect(
|
||||
"common.items.npc_weapons.unique.turret",
|
||||
));
|
||||
},
|
||||
object::Body::HaniwaSentry => {
|
||||
main_tool = Some(Item::new_from_asset_expect(
|
||||
"common.items.npc_weapons.unique.haniwa_sentry",
|
||||
));
|
||||
},
|
||||
_ => {},
|
||||
},
|
||||
Body::BipedSmall(biped_small) => match (biped_small.species, biped_small.body_type)
|
||||
{
|
||||
@ -980,6 +988,15 @@ impl LoadoutBuilder {
|
||||
.build(),
|
||||
_ => LoadoutBuilder::new().active_item(active_item).build(),
|
||||
},
|
||||
Body::Golem(g) => match g.species {
|
||||
golem::Species::ClayGolem => LoadoutBuilder::new()
|
||||
.active_item(active_item)
|
||||
.chest(Some(Item::new_from_asset_expect(
|
||||
"common.items.npc_armor.golem.claygolem",
|
||||
)))
|
||||
.build(),
|
||||
_ => LoadoutBuilder::new().active_item(active_item).build(),
|
||||
},
|
||||
_ => LoadoutBuilder::new().active_item(active_item).build(),
|
||||
}
|
||||
};
|
||||
|
@ -239,6 +239,16 @@ impl From<Dir> for Ori {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec3<f32>> for Ori {
|
||||
fn from(dir: Vec3<f32>) -> Self {
|
||||
let dir = Dir::from_unnormalized(dir).unwrap_or_default();
|
||||
let from = Dir::default();
|
||||
let q = Quaternion::<f32>::rotation_from_to_3d(*from, *dir).normalized();
|
||||
|
||||
Self(q).uprighted()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Quaternion<f32>> for Ori {
|
||||
fn from(quat: Quaternion<f32>) -> Self { Self::new(quat) }
|
||||
}
|
||||
|
@ -59,6 +59,11 @@ pub enum ProjectileConstructor {
|
||||
radius: f32,
|
||||
},
|
||||
Possess,
|
||||
ClayRocket {
|
||||
damage: f32,
|
||||
radius: f32,
|
||||
knockback: f32,
|
||||
},
|
||||
}
|
||||
|
||||
impl ProjectileConstructor {
|
||||
@ -205,6 +210,47 @@ impl ProjectileConstructor {
|
||||
owner,
|
||||
ignore_group: false,
|
||||
},
|
||||
ClayRocket {
|
||||
damage,
|
||||
radius,
|
||||
knockback,
|
||||
} => {
|
||||
let knockback = AttackEffect::new(
|
||||
Some(GroupTarget::OutOfGroup),
|
||||
CombatEffect::Knockback(Knockback {
|
||||
strength: knockback,
|
||||
direction: KnockbackDir::Away,
|
||||
}),
|
||||
)
|
||||
.with_requirement(CombatRequirement::AnyDamage);
|
||||
let damage = AttackDamage::new(
|
||||
Damage {
|
||||
source: DamageSource::Explosion,
|
||||
kind: DamageKind::Energy,
|
||||
value: damage,
|
||||
},
|
||||
Some(GroupTarget::OutOfGroup),
|
||||
);
|
||||
let attack = Attack::default()
|
||||
.with_damage(damage)
|
||||
.with_crit(crit_chance, crit_mult)
|
||||
.with_effect(knockback);
|
||||
let explosion = Explosion {
|
||||
effects: vec![
|
||||
RadiusEffect::Attack(attack),
|
||||
RadiusEffect::TerrainDestruction(5.0),
|
||||
],
|
||||
radius,
|
||||
reagent: Some(Reagent::Red),
|
||||
};
|
||||
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,
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -246,6 +292,14 @@ impl ProjectileConstructor {
|
||||
*radius *= range;
|
||||
},
|
||||
Possess => {},
|
||||
ClayRocket {
|
||||
ref mut damage,
|
||||
ref mut radius,
|
||||
..
|
||||
} => {
|
||||
*damage *= power;
|
||||
*radius *= range;
|
||||
},
|
||||
}
|
||||
self
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ pub struct StaticData {
|
||||
/// Energy drained per second
|
||||
pub energy_drain: f32,
|
||||
/// Used to dictate how orientation functions in this state
|
||||
pub orientation_behavior: MovementBehavior,
|
||||
pub orientation_behavior: OrientationBehavior,
|
||||
/// What key is used to press ability
|
||||
pub ability_info: AbilityInfo,
|
||||
/// Used to specify the beam to the frontend
|
||||
@ -61,14 +61,16 @@ impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
|
||||
match self.static_data.orientation_behavior {
|
||||
MovementBehavior::Normal => {},
|
||||
MovementBehavior::Turret => {
|
||||
let ori_rate = match self.static_data.orientation_behavior {
|
||||
OrientationBehavior::Normal => 0.6,
|
||||
OrientationBehavior::Turret => {
|
||||
update.ori = Ori::from(data.inputs.look_dir);
|
||||
0.6
|
||||
},
|
||||
}
|
||||
OrientationBehavior::FromOri => 0.1,
|
||||
};
|
||||
|
||||
handle_orientation(data, &mut update, 0.6);
|
||||
handle_orientation(data, &mut update, ori_rate);
|
||||
handle_move(data, &mut update, 0.4);
|
||||
handle_jump(data, &mut update, 1.0);
|
||||
|
||||
@ -138,22 +140,41 @@ impl CharacterBehavior for Data {
|
||||
owner: Some(*data.uid),
|
||||
specifier: self.static_data.specifier,
|
||||
};
|
||||
// Gets offsets
|
||||
let body_offsets_r = data.body.radius() + 1.0;
|
||||
let body_offsets_z = match data.body {
|
||||
Body::BirdLarge(_) => data.body.height() * 0.9,
|
||||
Body::BirdLarge(_) => data.body.height() * 0.8,
|
||||
Body::Golem(_) => data.body.height() * 0.9 + data.inputs.look_dir.z * 3.0,
|
||||
_ => data.body.height() * 0.5,
|
||||
};
|
||||
// Gets offsets
|
||||
let body_offsets = Vec3::new(
|
||||
(data.body.radius() + 1.0) * data.inputs.look_dir.x,
|
||||
(data.body.radius() + 1.0) * data.inputs.look_dir.y,
|
||||
body_offsets_z,
|
||||
);
|
||||
let (body_offsets, ori) = match self.static_data.orientation_behavior {
|
||||
OrientationBehavior::Normal | OrientationBehavior::Turret => (
|
||||
Vec3::new(
|
||||
body_offsets_r * data.inputs.look_dir.x,
|
||||
body_offsets_r * data.inputs.look_dir.y,
|
||||
body_offsets_z,
|
||||
),
|
||||
Ori::from(data.inputs.look_dir),
|
||||
),
|
||||
OrientationBehavior::FromOri => (
|
||||
Vec3::new(
|
||||
body_offsets_r * update.ori.look_vec().x,
|
||||
body_offsets_r * update.ori.look_vec().y,
|
||||
body_offsets_z,
|
||||
),
|
||||
Ori::from(Vec3::new(
|
||||
update.ori.look_vec().x,
|
||||
update.ori.look_vec().y,
|
||||
data.inputs.look_dir.z,
|
||||
)),
|
||||
),
|
||||
};
|
||||
let pos = Pos(data.pos.0 + body_offsets);
|
||||
// Create beam segment
|
||||
update.server_events.push_front(ServerEvent::BeamSegment {
|
||||
properties,
|
||||
pos,
|
||||
ori: Ori::from(data.inputs.look_dir),
|
||||
ori,
|
||||
});
|
||||
update.character = CharacterState::BasicBeam(Data {
|
||||
timer: self
|
||||
@ -210,7 +231,13 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum MovementBehavior {
|
||||
pub enum OrientationBehavior {
|
||||
/// Uses look_dir as direction of beam
|
||||
Normal,
|
||||
/// Uses look_dir as direction of beam, sets orientation to same direction
|
||||
/// as look_dir
|
||||
Turret,
|
||||
/// Uses orientation x and y and look_dir z as direction of beam (z from
|
||||
/// look_dir as orientation will only go through 2d rotations naturally)
|
||||
FromOri,
|
||||
}
|
||||
|
@ -187,11 +187,15 @@ pub fn handle_shoot(
|
||||
.write_resource::<Vec<Outcome>>()
|
||||
.push(Outcome::ProjectileShot { pos, body, vel });
|
||||
|
||||
let eye_height = state
|
||||
.ecs()
|
||||
.read_storage::<comp::Body>()
|
||||
.get(entity)
|
||||
.map_or(0.0, |b| b.eye_height());
|
||||
let eye_height =
|
||||
state
|
||||
.ecs()
|
||||
.read_storage::<comp::Body>()
|
||||
.get(entity)
|
||||
.map_or(0.0, |b| match b {
|
||||
comp::Body::Golem(_) => b.height() * 0.45,
|
||||
_ => b.eye_height(),
|
||||
});
|
||||
|
||||
pos.z += eye_height;
|
||||
|
||||
|
@ -108,6 +108,7 @@ pub enum Tactic {
|
||||
BirdLargeBreathe,
|
||||
BirdLargeFire,
|
||||
Minotaur,
|
||||
ClayGolem,
|
||||
}
|
||||
|
||||
#[derive(SystemData)]
|
||||
@ -1577,10 +1578,12 @@ impl<'a> AgentData<'a> {
|
||||
circle_time: 1,
|
||||
},
|
||||
"Turret" => Tactic::Turret,
|
||||
"Haniwa Sentry" => Tactic::RotatingTurret,
|
||||
"Bird Large Breathe" => Tactic::BirdLargeBreathe,
|
||||
"Bird Large Fire" => Tactic::BirdLargeFire,
|
||||
"Mindflayer" => Tactic::Mindflayer,
|
||||
"Minotaur" => Tactic::Minotaur,
|
||||
"Clay Golem" => Tactic::ClayGolem,
|
||||
_ => Tactic::Melee,
|
||||
},
|
||||
AbilitySpec::Tool(tool_kind) => tool_tactic(*tool_kind),
|
||||
@ -1645,6 +1648,18 @@ impl<'a> AgentData<'a> {
|
||||
),
|
||||
)
|
||||
}
|
||||
Tactic::ClayGolem if matches!(self.char_state, CharacterState::BasicRanged(_)) => {
|
||||
const ROCKET_SPEED: f32 = 30.0;
|
||||
aim_projectile(
|
||||
ROCKET_SPEED,
|
||||
Vec3::new(self.pos.0.x, self.pos.0.y, self.pos.0.z + eye_offset),
|
||||
Vec3::new(
|
||||
tgt_data.pos.0.x,
|
||||
tgt_data.pos.0.y,
|
||||
tgt_data.pos.0.z + tgt_eye_offset,
|
||||
),
|
||||
)
|
||||
},
|
||||
_ => Dir::from_unnormalized(
|
||||
Vec3::new(
|
||||
tgt_data.pos.0.x,
|
||||
@ -1792,6 +1807,13 @@ impl<'a> AgentData<'a> {
|
||||
Tactic::Minotaur => {
|
||||
self.handle_minotaur_attack(agent, controller, &attack_data, &tgt_data, &read_data)
|
||||
},
|
||||
Tactic::ClayGolem => self.handle_clay_golem_attack(
|
||||
agent,
|
||||
controller,
|
||||
&attack_data,
|
||||
&tgt_data,
|
||||
&read_data,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@ -2976,8 +2998,7 @@ impl<'a> AgentData<'a> {
|
||||
self.pos,
|
||||
tgt_data.pos,
|
||||
attack_data.dist_sqrd,
|
||||
) && attack_data.angle < 15.0
|
||||
{
|
||||
) {
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_input(InputKind::Primary));
|
||||
@ -3376,7 +3397,7 @@ impl<'a> AgentData<'a> {
|
||||
let minotaur_attack_distance =
|
||||
self.body.map_or(0.0, |b| b.radius()) + MINOTAUR_ATTACK_RANGE;
|
||||
let health_fraction = self.health.map_or(1.0, |h| h.fraction());
|
||||
// Sets action float at start of combat
|
||||
// Sets action counter at start of combat
|
||||
if agent.action_state.counter < MINOTAUR_FRENZY_THRESHOLD
|
||||
&& health_fraction > MINOTAUR_FRENZY_THRESHOLD
|
||||
{
|
||||
@ -3441,6 +3462,101 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_clay_golem_attack(
|
||||
&self,
|
||||
agent: &mut Agent,
|
||||
controller: &mut Controller,
|
||||
attack_data: &AttackData,
|
||||
tgt_data: &TargetData,
|
||||
read_data: &ReadData,
|
||||
) {
|
||||
const GOLEM_MELEE_RANGE: f32 = 4.0;
|
||||
const GOLEM_LASER_RANGE: f32 = 30.0;
|
||||
const GOLEM_LONG_RANGE: f32 = 50.0;
|
||||
const GOLEM_TARGET_SPEED: f32 = 8.0;
|
||||
let golem_melee_range = self.body.map_or(0.0, |b| b.radius()) + GOLEM_MELEE_RANGE;
|
||||
// Magnitude squared of cross product of target velocity with golem orientation
|
||||
let target_speed_cross_sqd = agent
|
||||
.target
|
||||
.as_ref()
|
||||
.map(|t| t.target)
|
||||
.and_then(|e| read_data.velocities.get(e))
|
||||
.map_or(0.0, |v| v.0.cross(self.ori.look_vec()).magnitude_squared());
|
||||
if attack_data.dist_sqrd < golem_melee_range.powi(2) {
|
||||
if agent.action_state.counter < 7.5 {
|
||||
// If target is close, whack them
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_input(InputKind::Primary));
|
||||
agent.action_state.counter += read_data.dt.0;
|
||||
} else {
|
||||
// If whacked for too long, nuke them
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_input(InputKind::Ability(1)));
|
||||
if matches!(self.char_state, CharacterState::BasicRanged(c) if matches!(c.stage_section, StageSection::Recover))
|
||||
{
|
||||
agent.action_state.counter = 0.0;
|
||||
}
|
||||
}
|
||||
} else if attack_data.dist_sqrd < GOLEM_LASER_RANGE.powi(2) {
|
||||
if matches!(self.char_state, CharacterState::BasicBeam(c) if c.timer < Duration::from_secs(10))
|
||||
|| target_speed_cross_sqd < GOLEM_TARGET_SPEED.powi(2)
|
||||
&& can_see_tgt(
|
||||
&*read_data.terrain,
|
||||
self.pos,
|
||||
tgt_data.pos,
|
||||
attack_data.dist_sqrd,
|
||||
)
|
||||
&& attack_data.angle < 45.0
|
||||
{
|
||||
// If target in range threshold and haven't been lasering for more than 10
|
||||
// seconds already or if target is moving slow-ish, laser them
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_input(InputKind::Secondary));
|
||||
} else {
|
||||
// Else target moving too fast for laser, shockwave time
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_input(InputKind::Ability(0)));
|
||||
}
|
||||
} else if attack_data.dist_sqrd < GOLEM_LONG_RANGE.powi(2) {
|
||||
if target_speed_cross_sqd < GOLEM_TARGET_SPEED.powi(2)
|
||||
&& can_see_tgt(
|
||||
&*read_data.terrain,
|
||||
self.pos,
|
||||
tgt_data.pos,
|
||||
attack_data.dist_sqrd,
|
||||
)
|
||||
{
|
||||
// If target is far-ish and moving slow-ish, rocket them
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_input(InputKind::Ability(1)));
|
||||
} else {
|
||||
// Else target moving too fast for laser, shockwave time
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_input(InputKind::Ability(0)));
|
||||
}
|
||||
}
|
||||
// Make clay golem move towards target
|
||||
if let Some((bearing, speed)) = agent.chaser.chase(
|
||||
&*read_data.terrain,
|
||||
self.pos.0,
|
||||
self.vel.0,
|
||||
tgt_data.pos.0,
|
||||
TraversalConfig {
|
||||
min_tgt_dist: 1.25,
|
||||
..self.traversal_config
|
||||
},
|
||||
) {
|
||||
controller.inputs.move_dir =
|
||||
bearing.xy().try_normalized().unwrap_or_else(Vec2::zero) * speed;
|
||||
}
|
||||
}
|
||||
|
||||
fn follow(
|
||||
&self,
|
||||
agent: &mut Agent,
|
||||
|
74
voxygen/anim/src/golem/beam.rs
Normal file
74
voxygen/anim/src/golem/beam.rs
Normal file
@ -0,0 +1,74 @@
|
||||
use super::{
|
||||
super::{vek::*, Animation},
|
||||
GolemSkeleton, SkeletonAttr,
|
||||
};
|
||||
use common::{states::utils::StageSection, util::Dir};
|
||||
pub struct BeamAnimation;
|
||||
|
||||
impl Animation for BeamAnimation {
|
||||
type Dependency<'a> = (Option<StageSection>, f32, f32, Dir);
|
||||
type Skeleton = GolemSkeleton;
|
||||
|
||||
#[cfg(feature = "use-dyn-lib")]
|
||||
const UPDATE_FN: &'static [u8] = b"golem_beam\0";
|
||||
|
||||
#[cfg_attr(feature = "be-dyn-lib", export_name = "golem_beam")]
|
||||
|
||||
fn update_skeleton_inner<'a>(
|
||||
skeleton: &Self::Skeleton,
|
||||
(stage_section, _global_time, _timer, look_dir): Self::Dependency<'a>,
|
||||
anim_time: f32,
|
||||
_rate: &mut f32,
|
||||
s_a: &SkeletonAttr,
|
||||
) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
||||
let (move1base, move1iso, move2base, move3) = match stage_section {
|
||||
Some(StageSection::Buildup) => (anim_time.powf(0.25), anim_time.powf(0.25), 0.0, 0.0),
|
||||
Some(StageSection::Cast) => (1.0, 0.0, 1.0, 0.0),
|
||||
Some(StageSection::Recover) => (1.0, 0.0, 1.0, anim_time.powf(4.0)),
|
||||
_ => (0.0, 0.0, 0.0, 0.0),
|
||||
};
|
||||
|
||||
let pullback = 1.0 - move3;
|
||||
let move1 = move1base * pullback;
|
||||
let move2 = move2base * pullback;
|
||||
|
||||
next.head.orientation = Quaternion::rotation_x(move1iso * 0.5 + move2 * (look_dir.z * 1.0));
|
||||
next.head.position = Vec3::new(
|
||||
0.0,
|
||||
s_a.head.0,
|
||||
s_a.head.1 - move2 * 5.0 * (look_dir.z * 1.0).min(0.0),
|
||||
);
|
||||
|
||||
next.upper_torso.orientation =
|
||||
Quaternion::rotation_x(move1iso * 0.3) * Quaternion::rotation_z(0.0);
|
||||
|
||||
next.lower_torso.orientation =
|
||||
Quaternion::rotation_z(0.0) * Quaternion::rotation_x(move1iso * -0.3);
|
||||
|
||||
next.shoulder_l.orientation =
|
||||
Quaternion::rotation_x(move1 * 0.8) * Quaternion::rotation_y(move1 * -0.5);
|
||||
|
||||
next.shoulder_r.orientation =
|
||||
Quaternion::rotation_x(move1 * 0.8) * Quaternion::rotation_y(move1 * 0.5);
|
||||
next.shoulder_l.position = Vec3::new(
|
||||
-s_a.shoulder.0,
|
||||
s_a.shoulder.1 + move1 * 2.0,
|
||||
s_a.shoulder.2 + move1 * -2.0,
|
||||
);
|
||||
next.shoulder_r.position = Vec3::new(
|
||||
s_a.shoulder.0,
|
||||
s_a.shoulder.1 + move1 * 2.0,
|
||||
s_a.shoulder.2 + move1 * -2.0,
|
||||
);
|
||||
|
||||
next.hand_l.orientation =
|
||||
Quaternion::rotation_z(0.0) * Quaternion::rotation_y(move1 * -1.1);
|
||||
|
||||
next.hand_r.orientation = Quaternion::rotation_y(0.0) * Quaternion::rotation_y(move1 * 1.1);
|
||||
|
||||
next.torso.position = Vec3::new(0.0, 0.0, 0.0);
|
||||
next
|
||||
}
|
||||
}
|
@ -1,13 +1,15 @@
|
||||
pub mod alpha;
|
||||
pub mod beam;
|
||||
pub mod idle;
|
||||
pub mod run;
|
||||
pub mod shockwave;
|
||||
pub mod shoot;
|
||||
pub mod spinmelee;
|
||||
|
||||
// Reexports
|
||||
pub use self::{
|
||||
alpha::AlphaAnimation, idle::IdleAnimation, run::RunAnimation, shockwave::ShockwaveAnimation,
|
||||
spinmelee::SpinMeleeAnimation,
|
||||
alpha::AlphaAnimation, beam::BeamAnimation, idle::IdleAnimation, run::RunAnimation,
|
||||
shockwave::ShockwaveAnimation, shoot::ShootAnimation, spinmelee::SpinMeleeAnimation,
|
||||
};
|
||||
|
||||
use super::{make_bone, vek::*, FigureBoneData, Skeleton};
|
||||
@ -120,7 +122,7 @@ impl<'a> From<&'a Body> for SkeletonAttr {
|
||||
head: match (body.species, body.body_type) {
|
||||
(StoneGolem, _) => (0.0, 2.0),
|
||||
(Treant, _) => (18.0, -8.0),
|
||||
(ClayGolem, _) => (2.0, 9.0),
|
||||
(ClayGolem, _) => (-2.0, 7.0),
|
||||
},
|
||||
jaw: match (body.species, body.body_type) {
|
||||
(StoneGolem, _) => (0.0, 0.0),
|
||||
|
61
voxygen/anim/src/golem/shoot.rs
Normal file
61
voxygen/anim/src/golem/shoot.rs
Normal file
@ -0,0 +1,61 @@
|
||||
use super::{
|
||||
super::{vek::*, Animation},
|
||||
GolemSkeleton, SkeletonAttr,
|
||||
};
|
||||
use common::{states::utils::StageSection, util::Dir};
|
||||
pub struct ShootAnimation;
|
||||
|
||||
impl Animation for ShootAnimation {
|
||||
type Dependency<'a> = (Option<StageSection>, f32, f32, Dir);
|
||||
type Skeleton = GolemSkeleton;
|
||||
|
||||
#[cfg(feature = "use-dyn-lib")]
|
||||
const UPDATE_FN: &'static [u8] = b"golem_shoot\0";
|
||||
|
||||
#[cfg_attr(feature = "be-dyn-lib", export_name = "golem_shoot")]
|
||||
|
||||
fn update_skeleton_inner<'a>(
|
||||
skeleton: &Self::Skeleton,
|
||||
(stage_section, _global_time, _timer, look_dir): Self::Dependency<'a>,
|
||||
anim_time: f32,
|
||||
_rate: &mut f32,
|
||||
_s_a: &SkeletonAttr,
|
||||
) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
||||
let (move1base, move2base, move3) = match stage_section {
|
||||
Some(StageSection::Buildup) => (anim_time.powf(0.4), 0.0, 0.0),
|
||||
Some(StageSection::Shoot) => (1.0, anim_time, 0.0),
|
||||
Some(StageSection::Recover) => (1.0, 1.0, anim_time.powf(4.0)),
|
||||
_ => (0.0, 0.0, 0.0),
|
||||
};
|
||||
|
||||
let pullback = 1.0 - move3;
|
||||
|
||||
let move1 = move1base * pullback;
|
||||
let move2 = move2base * pullback;
|
||||
|
||||
next.head.orientation = Quaternion::rotation_x(-0.2) * Quaternion::rotation_z(move1 * -0.5);
|
||||
|
||||
next.upper_torso.orientation =
|
||||
Quaternion::rotation_x(0.0) * Quaternion::rotation_z(move1 * 0.5);
|
||||
|
||||
next.lower_torso.orientation =
|
||||
Quaternion::rotation_z(move1 * -0.5) * Quaternion::rotation_x(0.0);
|
||||
|
||||
next.shoulder_l.orientation =
|
||||
Quaternion::rotation_y(0.0) * Quaternion::rotation_z(move1 * 0.7);
|
||||
|
||||
next.shoulder_r.orientation = Quaternion::rotation_x(move1 * (look_dir.z * 1.2 + 1.57))
|
||||
* Quaternion::rotation_y(move1 * 0.0);
|
||||
|
||||
next.hand_l.orientation =
|
||||
Quaternion::rotation_z(move1 * -0.3) * Quaternion::rotation_x(move1 * 1.3);
|
||||
|
||||
next.hand_r.orientation = Quaternion::rotation_y(move1 * -0.3)
|
||||
* Quaternion::rotation_z(move1 * -0.9 + move2 * -1.6);
|
||||
|
||||
next.torso.position = Vec3::new(0.0, 0.0, 0.0);
|
||||
next
|
||||
}
|
||||
}
|
@ -70,11 +70,13 @@ impl<'a> From<&'a Body> for SkeletonAttr {
|
||||
use comp::object::Body::*;
|
||||
Self {
|
||||
bone0: match body {
|
||||
Crossbow => (0.0, 0.0, 14.0),
|
||||
Crossbow => (0.0, 0.0, 11.0),
|
||||
HaniwaSentry => (0.0, 0.0, 10.5),
|
||||
_ => (0.0, 0.0, 0.0),
|
||||
},
|
||||
bone1: match body {
|
||||
Crossbow => (0.0, 0.0, 8.0),
|
||||
HaniwaSentry => (0.0, 0.0, 3.0),
|
||||
_ => (0.0, 0.0, 0.0),
|
||||
},
|
||||
}
|
||||
|
@ -402,6 +402,7 @@ impl SfxMgr {
|
||||
audio.emit_sfx(sfx_trigger_item, *pos, None, false);
|
||||
}
|
||||
},
|
||||
beam::FrontendSpecifier::ClayGolem => {},
|
||||
},
|
||||
Outcome::BreakBlock { pos, .. } => {
|
||||
let sfx_trigger_item = triggers.get_key_value(&SfxEvent::BreakBlock);
|
||||
|
@ -91,7 +91,7 @@ impl<'a> System<'a> for Sys {
|
||||
fn base_ori_interp(body: &Body) -> f32 {
|
||||
match body {
|
||||
Body::Object(object) => match object {
|
||||
object::Body::Crossbow => 100.0,
|
||||
object::Body::Crossbow | object::Body::HaniwaSentry => 100.0,
|
||||
_ => 10.0,
|
||||
},
|
||||
_ => 10.0,
|
||||
|
@ -124,6 +124,7 @@ pub enum ParticleMode {
|
||||
Blood = 25,
|
||||
Enraged = 26,
|
||||
BigShrapnel = 27,
|
||||
Laser = 28,
|
||||
}
|
||||
|
||||
impl ParticleMode {
|
||||
|
@ -4327,6 +4327,74 @@ impl FigureMgr {
|
||||
skeleton_attr,
|
||||
)
|
||||
},
|
||||
CharacterState::BasicRanged(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::golem::ShootAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(Some(s.stage_section), time, state.state_time, look_dir),
|
||||
stage_progress,
|
||||
&mut state_animation_rate,
|
||||
skeleton_attr,
|
||||
)
|
||||
},
|
||||
CharacterState::BasicBeam(s) => {
|
||||
let stage_time = s.timer.as_secs_f32();
|
||||
|
||||
let stage_progress = match s.stage_section {
|
||||
StageSection::Buildup => {
|
||||
stage_time / s.static_data.buildup_duration.as_secs_f32()
|
||||
},
|
||||
StageSection::Cast => s.timer.as_secs_f32(),
|
||||
StageSection::Recover => {
|
||||
stage_time / s.static_data.recover_duration.as_secs_f32()
|
||||
},
|
||||
|
||||
_ => 0.0,
|
||||
};
|
||||
|
||||
anim::golem::BeamAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(Some(s.stage_section), time, state.state_time, look_dir),
|
||||
stage_progress,
|
||||
&mut state_animation_rate,
|
||||
skeleton_attr,
|
||||
)
|
||||
},
|
||||
CharacterState::BasicMelee(s) => {
|
||||
let stage_time = s.timer.as_secs_f32();
|
||||
let stage_progress = match s.stage_section {
|
||||
StageSection::Buildup => {
|
||||
stage_time / s.static_data.buildup_duration.as_secs_f32()
|
||||
},
|
||||
StageSection::Swing => {
|
||||
stage_time / s.static_data.swing_duration.as_secs_f32()
|
||||
},
|
||||
StageSection::Recover => {
|
||||
stage_time / s.static_data.recover_duration.as_secs_f32()
|
||||
},
|
||||
_ => 0.0,
|
||||
};
|
||||
|
||||
anim::golem::AlphaAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(Some(s.stage_section), time, state.state_time),
|
||||
stage_progress,
|
||||
&mut state_animation_rate,
|
||||
skeleton_attr,
|
||||
)
|
||||
},
|
||||
CharacterState::Shockwave(s) => {
|
||||
let stage_time = s.timer.as_secs_f32();
|
||||
let stage_progress = match s.stage_section {
|
||||
|
@ -791,6 +791,7 @@ impl ParticleMgr {
|
||||
beam::FrontendSpecifier::HealingBeam => {
|
||||
// Emit a light when using healing
|
||||
lights.push(Light::new(pos.0, Rgb::new(0.1, 1.0, 0.15), 1.0));
|
||||
self.particles.reserve(beam_tick_count as usize);
|
||||
for i in 0..beam_tick_count {
|
||||
self.particles.push(Particle::new_directed(
|
||||
beam.properties.duration,
|
||||
@ -804,6 +805,7 @@ impl ParticleMgr {
|
||||
beam::FrontendSpecifier::LifestealBeam => {
|
||||
// Emit a light when using lifesteal beam
|
||||
lights.push(Light::new(pos.0, Rgb::new(0.8, 1.0, 0.5), 1.0));
|
||||
self.particles.reserve(beam_tick_count as usize);
|
||||
for i in 0..beam_tick_count {
|
||||
self.particles.push(Particle::new_directed(
|
||||
beam.properties.duration,
|
||||
@ -814,6 +816,17 @@ impl ParticleMgr {
|
||||
));
|
||||
}
|
||||
},
|
||||
beam::FrontendSpecifier::ClayGolem => {
|
||||
self.particles.resize_with(self.particles.len() + 2, || {
|
||||
Particle::new_directed(
|
||||
beam.properties.duration,
|
||||
time,
|
||||
ParticleMode::Laser,
|
||||
pos.0,
|
||||
pos.0 + *ori.look_dir() * range,
|
||||
)
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1110,11 +1123,13 @@ impl ParticleMgr {
|
||||
let distance =
|
||||
shockwave.properties.speed * (elapsed as f32 - sub_tick_interpolation);
|
||||
|
||||
let new_particle_count = distance / scale as f32;
|
||||
let particle_count_factor = radians / (3.0 * scale);
|
||||
let new_particle_count = distance * particle_count_factor;
|
||||
self.particles.reserve(new_particle_count as usize);
|
||||
|
||||
for d in 0..((distance / scale) as i32) {
|
||||
let arc_position = theta - radians / 2.0 + dtheta * d as f32 * scale;
|
||||
for d in 0..(new_particle_count as i32) {
|
||||
let arc_position =
|
||||
theta - radians / 2.0 + dtheta * d as f32 / particle_count_factor;
|
||||
|
||||
let position = pos.0
|
||||
+ distance * Vec3::new(arc_position.cos(), arc_position.sin(), 0.0);
|
||||
|
@ -671,34 +671,43 @@ impl Floor {
|
||||
},
|
||||
},
|
||||
)),
|
||||
3 => entity
|
||||
.with_body(comp::Body::BipedSmall(
|
||||
comp::biped_small::Body::random_with(
|
||||
dynamic_rng,
|
||||
&comp::biped_small::Species::Haniwa,
|
||||
),
|
||||
))
|
||||
.with_name("Haniwa")
|
||||
.with_loadout_config(loadout_builder::LoadoutConfig::Haniwa)
|
||||
.with_skillset_config(
|
||||
common::skillset_builder::SkillSetConfig::Haniwa,
|
||||
)
|
||||
.with_loot_drop(chosen.read().choose().to_item())
|
||||
.with_main_tool(comp::Item::new_from_asset_expect(
|
||||
match dynamic_rng.gen_range(0..5) {
|
||||
0 => {
|
||||
"common.items.npc_weapons.biped_small.haniwa.adlet_bow"
|
||||
3 => match dynamic_rng.gen_range(0..4) {
|
||||
0 => entity
|
||||
.with_body(comp::Body::Object(comp::object::Body::HaniwaSentry))
|
||||
.with_name("Haniwa Sentry".to_string())
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(
|
||||
"common.items.crafting_ing.stones",
|
||||
)),
|
||||
_ => entity
|
||||
.with_body(comp::Body::BipedSmall(
|
||||
comp::biped_small::Body::random_with(
|
||||
dynamic_rng,
|
||||
&comp::biped_small::Species::Haniwa,
|
||||
),
|
||||
))
|
||||
.with_name("Haniwa")
|
||||
.with_loadout_config(loadout_builder::LoadoutConfig::Haniwa)
|
||||
.with_skillset_config(
|
||||
common::skillset_builder::SkillSetConfig::Haniwa,
|
||||
)
|
||||
.with_loot_drop(chosen.read().choose().to_item())
|
||||
.with_main_tool(comp::Item::new_from_asset_expect(
|
||||
match dynamic_rng.gen_range(0..5) {
|
||||
0 => {
|
||||
"common.items.npc_weapons.biped_small.haniwa.\
|
||||
adlet_bow"
|
||||
},
|
||||
1 => {
|
||||
"common.items.npc_weapons.biped_small.haniwa.\
|
||||
gnoll_staff"
|
||||
},
|
||||
_ => {
|
||||
"common.items.npc_weapons.biped_small.haniwa.\
|
||||
wooden_spear"
|
||||
},
|
||||
},
|
||||
1 => {
|
||||
"common.items.npc_weapons.biped_small.haniwa.\
|
||||
gnoll_staff"
|
||||
},
|
||||
_ => {
|
||||
"common.items.npc_weapons.biped_small.haniwa.\
|
||||
wooden_spear"
|
||||
},
|
||||
},
|
||||
)),
|
||||
)),
|
||||
},
|
||||
4 => entity
|
||||
.with_body(comp::Body::BipedSmall(
|
||||
comp::biped_small::Body::random_with(
|
||||
@ -810,8 +819,6 @@ impl Floor {
|
||||
Lottery::<LootSpec>::load_expect("common.loot_tables.fallback")
|
||||
},
|
||||
};
|
||||
let chosen = chosen.read();
|
||||
let chosen = chosen.choose();
|
||||
let entity = match room.difficulty {
|
||||
0 => {
|
||||
vec![
|
||||
@ -823,7 +830,7 @@ impl Floor {
|
||||
),
|
||||
))
|
||||
.with_name("Harvester".to_string())
|
||||
.with_loot_drop(chosen.to_item()),
|
||||
.with_loot_drop(chosen.read().choose().to_item()),
|
||||
]
|
||||
},
|
||||
1 => {
|
||||
@ -836,7 +843,7 @@ impl Floor {
|
||||
),
|
||||
))
|
||||
.with_name("Yeti".to_string())
|
||||
.with_loot_drop(chosen.to_item()),
|
||||
.with_loot_drop(chosen.read().choose().to_item()),
|
||||
]
|
||||
},
|
||||
2 => {
|
||||
@ -849,11 +856,12 @@ impl Floor {
|
||||
),
|
||||
))
|
||||
.with_name("Tidal Warrior".to_string())
|
||||
.with_loot_drop(chosen.to_item()),
|
||||
.with_loot_drop(chosen.read().choose().to_item()),
|
||||
]
|
||||
},
|
||||
3 => {
|
||||
vec![
|
||||
let mut entities = Vec::new();
|
||||
entities.resize_with(2, || {
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::Golem(
|
||||
comp::golem::Body::random_with(
|
||||
@ -862,8 +870,9 @@ impl Floor {
|
||||
),
|
||||
))
|
||||
.with_name("Clay Golem".to_string())
|
||||
.with_loot_drop(chosen.to_item()),
|
||||
]
|
||||
.with_loot_drop(chosen.read().choose().to_item())
|
||||
});
|
||||
entities
|
||||
},
|
||||
4 => {
|
||||
vec![
|
||||
@ -875,7 +884,7 @@ impl Floor {
|
||||
),
|
||||
))
|
||||
.with_name("Minotaur".to_string())
|
||||
.with_loot_drop(chosen.to_item()),
|
||||
.with_loot_drop(chosen.read().choose().to_item()),
|
||||
]
|
||||
},
|
||||
5 => {
|
||||
@ -888,7 +897,7 @@ impl Floor {
|
||||
),
|
||||
))
|
||||
.with_name("Mindflayer".to_string())
|
||||
.with_loot_drop(chosen.to_item())
|
||||
.with_loot_drop(chosen.read().choose().to_item())
|
||||
.with_skillset_config(
|
||||
common::skillset_builder::SkillSetConfig::Mindflayer,
|
||||
),
|
||||
|
Loading…
Reference in New Issue
Block a user