From 083d3d2a6cbde362de6c4d1b771e7d9f7d5eb9d6 Mon Sep 17 00:00:00 2001
From: Sam <samuelkeiffer@gmail.com>
Date: Tue, 4 May 2021 19:02:18 -0400
Subject: [PATCH] Clay golem attacks done.

---
 .../common/abilities/ability_set_manifest.ron |   8 +++
 .../abilities/custom/claygolem/laser.ron      |  14 +++++
 .../abilities/custom/claygolem/rocket.ron     |  13 +++++
 .../abilities/custom/claygolem/shockwave.ron  |  15 +++++
 .../abilities/custom/claygolem/strike.ron     |  12 ++++
 .../npc_weapons/unique/clay_golem_fist.ron    |  19 ++++++
 assets/voxygen/shaders/particle-vert.glsl     |  16 ++++++
 assets/voxygen/voxel/object_manifest.ron      |  10 ++++
 .../voxel/weapon/projectile/clay-missile.vox  | Bin 0 -> 2492 bytes
 common/src/comp/beam.rs                       |   1 +
 common/src/comp/body.rs                       |   2 +-
 common/src/comp/body/object.rs                |   6 +-
 common/src/comp/projectile.rs                 |  54 ++++++++++++++++++
 common/src/states/basic_beam.rs               |   2 +-
 voxygen/src/audio/sfx/mod.rs                  |   3 +
 voxygen/src/render/pipelines/particle.rs      |   1 +
 voxygen/src/scene/figure/mod.rs               |  23 ++++++++
 voxygen/src/scene/particle.rs                 |  21 ++++++-
 18 files changed, 214 insertions(+), 6 deletions(-)
 create mode 100644 assets/common/abilities/custom/claygolem/laser.ron
 create mode 100644 assets/common/abilities/custom/claygolem/rocket.ron
 create mode 100644 assets/common/abilities/custom/claygolem/shockwave.ron
 create mode 100644 assets/common/abilities/custom/claygolem/strike.ron
 create mode 100644 assets/common/items/npc_weapons/unique/clay_golem_fist.ron
 create mode 100644 assets/voxygen/voxel/weapon/projectile/clay-missile.vox

diff --git a/assets/common/abilities/ability_set_manifest.ron b/assets/common/abilities/ability_set_manifest.ron
index f0ef774303..f2384d9491 100644
--- a/assets/common/abilities/ability_set_manifest.ron
+++ b/assets/common/abilities/ability_set_manifest.ron
@@ -216,6 +216,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",
diff --git a/assets/common/abilities/custom/claygolem/laser.ron b/assets/common/abilities/custom/claygolem/laser.ron
new file mode 100644
index 0000000000..e3f21d1bdc
--- /dev/null
+++ b/assets/common/abilities/custom/claygolem/laser.ron
@@ -0,0 +1,14 @@
+BasicBeam(
+    buildup_duration: 0.20,
+    recover_duration: 0.20,
+    beam_duration: 0.25,
+    damage: 10,
+    tick_rate: 10.0,
+    range: 25.0,
+    max_angle: 1.0,
+    damage_effect: None,
+    energy_regen: 50,
+    energy_drain: 0,
+    orientation_behavior: Normal,
+    specifier: ClayGolem,
+)
\ No newline at end of file
diff --git a/assets/common/abilities/custom/claygolem/rocket.ron b/assets/common/abilities/custom/claygolem/rocket.ron
new file mode 100644
index 0000000000..8095777128
--- /dev/null
+++ b/assets/common/abilities/custom/claygolem/rocket.ron
@@ -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: 20.0,
+)
diff --git a/assets/common/abilities/custom/claygolem/shockwave.ron b/assets/common/abilities/custom/claygolem/shockwave.ron
new file mode 100644
index 0000000000..05f0ed879d
--- /dev/null
+++ b/assets/common/abilities/custom/claygolem/shockwave.ron
@@ -0,0 +1,15 @@
+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: 360.0,
+    shockwave_vertical_angle: 90.0,
+    shockwave_speed: 65.0,
+    shockwave_duration: 1.0,
+    requires_ground: true,
+    move_efficiency: 0.0,
+)
\ No newline at end of file
diff --git a/assets/common/abilities/custom/claygolem/strike.ron b/assets/common/abilities/custom/claygolem/strike.ron
new file mode 100644
index 0000000000..ef6e8f8c19
--- /dev/null
+++ b/assets/common/abilities/custom/claygolem/strike.ron
@@ -0,0 +1,12 @@
+BasicMelee(
+    energy_cost: 0,
+    buildup_duration: 0.2,
+    swing_duration: 0.2,
+    recover_duration: 0.5,
+    base_damage: 250,
+    base_poise_damage: 50,
+    knockback: 10.0,
+    range: 5.0,
+    max_angle: 60.0,
+    damage_effect: None,
+)
diff --git a/assets/common/items/npc_weapons/unique/clay_golem_fist.ron b/assets/common/items/npc_weapons/unique/clay_golem_fist.ron
new file mode 100644
index 0000000000..2ea42a3744
--- /dev/null
+++ b/assets/common/items/npc_weapons/unique/clay_golem_fist.ron
@@ -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")),
+)
\ No newline at end of file
diff --git a/assets/voxygen/shaders/particle-vert.glsl b/assets/voxygen/shaders/particle-vert.glsl
index d94534313d..4064561078 100644
--- a/assets/voxygen/shaders/particle-vert.glsl
+++ b/assets/voxygen/shaders/particle-vert.glsl
@@ -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;
@@ -443,6 +444,21 @@ void main() {
             vec4(red_color, 0.0, 0.0, 1),
             spin_in_axis(vec3(rand6, rand7, rand8), percent() * 10 + 3 * rand9)
         );
+    } else if (inst_mode == LASER) {
+        f_reflect = 0.0;
+        vec3 perp_axis = normalize(cross(inst_dir, vec3(0.0, 0.0, 1.0)));
+        vec3 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)
+        );
     } else {
         attr = Attr(
             linear_motion(
diff --git a/assets/voxygen/voxel/object_manifest.ron b/assets/voxygen/voxel/object_manifest.ron
index f6ab5ad0c3..f0b1cebe5c 100644
--- a/assets/voxygen/voxel/object_manifest.ron
+++ b/assets/voxygen/voxel/object_manifest.ron
@@ -689,4 +689,14 @@
             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"),
+        )
+    ),
 })
diff --git a/assets/voxygen/voxel/weapon/projectile/clay-missile.vox b/assets/voxygen/voxel/weapon/projectile/clay-missile.vox
new file mode 100644
index 0000000000000000000000000000000000000000..137c0392487140e4776d0abdb587b2764e1a9bff
GIT binary patch
literal 2492
zcmai!Z){d)8OERU{JGD0|8(m{X`w)29SmA3INE^>WZj^Sg3Qz^+57Si6T>0|iA!f1
z*3>1eZplXK7$b~*zzz*TV^%kUMB@h}hRh|)w%}q+%t97p{OSi|{C4>}urJF{oBVR!
z_x0TObIx=3ywBdRJ-*_!b8gSWqmLo(XBFqhN1G${GU1QZ-TA3L-e`^<O{MGH6Pa@{
zbK}uNaINUF@sMS$2nmAEnh}!E8X*uv3dE5(W{m{FsD}hT^DP7KeKUC99wC8|`{3Eb
zH)8PY;hRS6BVP3Eg-2{?NYp?AZ@v|b+*n7A+~?Fl%&9>Qe1QiMQb8T+E9?!if(J(I
ztJGET(1aT5Yj`z0NW_MQIyt1eZ)RC&<&gQ%@IG*s(4G@#fjop}2;t5M2@EgC%VKEy
z7&u$tY=N_drjh5RpYRhtBw~ZiLdzRIL`X(G<fWhE=hQ<217F}lEbzdHeT8>{SfL+`
z*jMo&LIML{!>iGYCNN@O$Aeg>7Ysrhc^f%oE{^BmvN)b)k$J>cLF_!akIW@9m&jaV
zqrh_^wz7a9BJ+vNCo-SNd?NFS&7xe7kr}ZbV<SQ$Hpq#6ip(f7BYZH(EHWeNAwn{I
z$ccT9pR*4nFevbR!9E4`Xaa+RJge}G3O#5<6KaqXyDEKE`XE9gH*ht42oP)ds6kd|
zF9;AJ)$z-`jl7M$OTB}-EHSslca)mmC+3xySK>QL%qj8PNX#iQr^K8Rb7C#B785f{
zd`F2HC4M7`8L>yA2VzQmN2zJVnI&dKz2QS5HpojqrygQXJ!;?!Y74v~%_h{qSE#G-
zyb2y_;H%VC(`-Z&YN)T_)$nRO2Q}2!@#^e{Ca^MZBZmY&GwuiDelYF_<9;yi2V)k-
z42&5VcZ_jASi?{sse>4evm4(BHOV+LIe0Vf2XdnaHFBR*lhXqU41B>p1wCNIzCulf
zb<|K_We>0_ag7+PMo*o6>hzWBa_+{QyD{f(%()x$M)Wy%W6n38^WJ$QL5TPf9}Px5
zq*Akjdlo{``ud}fJnZ7FJ6QZpPfzQUlTJI&UemoD|JFY{I&}5wo^nZNoYM#Oy51c9
z)n_QZa;<&1Q(IaOXym)w)Hk<TZY0SauF9ReTkcw?+V?nh9dTMavRVUgITeSU+Gd;<
zoN(&=h11ZUnsyy&SM%5cy>xk*c1$~sopSp2ywfuu(mU3zo<qG_Io+>~mxi@uqC>s2
z-ReKTT=&1TT3s!tmB*Y0PCISA;^e-;^QQ{AQ+LQ+?2vXY*M%=G)JI=lBJH|ITX^SD
z_!ImMP91fcf7R*g1*do4CLeY>H{$f`)lPcPsY!lxuhWSG_>)fC`<&j`{{>C%pzrBj
zI(u+P^Anr(^1gLC`}BjF{^ll~ZuIN=54P&cu`!MGcWL+fZu%DLz(Xr^c$d@66HasA
zcl!HFP9yi-qtX7AYHeJni5;7@x4%<|hL&jd(N(&%f4v_2%7FS;^=SI3eLDW^cQp0A
zrcOM6SeGumpbuUjRsYImTD0IU-PKl8cjp2Pt?Sc+g9F+ya3A^II`PA$nt!8Le}1=L
zAHTm=y-T~)yR7SG-(UaeG<9f=&ddzz+MC<;kH3s-;&{7ef8L?DKU}PjwfuAEU)oXC
z{x7+k=Rd<-#)i6eXrxzDV{3H!$ql#8e{j3>hdJrSHLbn3Q(HGI*Y1bb=*hjCK6Cyn
zFFS4Q>HeSR9~>OiE1TxD{{C~?^5Sz^JhNEu{KV;_ef)pUpI2XBpC%_K_0^ph<z}X|
zaAKh@zjo_?_-r@dPEU_sdH$5PZ8@m}$6wH*{at$hm#cKSxmYJxtoYpX%er!}#`t@h
zI4C{y+6B%0^pbvb@%MWDch~j6Q!i@Ub937L<0~3}>$--AhxG}s;tJ5e6s|kn_|2{N
vyTSMM|JL~x-u#{2R)2f`zpt@U_T0Ab)3vgB=_5z9X!EzUWc~c@YTbVT>#3u@

literal 0
HcmV?d00001

diff --git a/common/src/comp/beam.rs b/common/src/comp/beam.rs
index da888d03d0..ceb78c7ad9 100644
--- a/common/src/comp/beam.rs
+++ b/common/src/comp/beam.rs
@@ -52,4 +52,5 @@ pub enum FrontendSpecifier {
     LifestealBeam,
     HealingBeam,
     Cultist,
+    ClayGolem,
 }
diff --git a/common/src/comp/body.rs b/common/src/comp/body.rs
index 1f3a3dabbe..73d7191667 100644
--- a/common/src/comp/body.rs
+++ b/common/src/comp/body.rs
@@ -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, 8.0),
             Body::Humanoid(humanoid) => {
                 let height = match (humanoid.species, humanoid.body_type) {
                     (humanoid::Species::Orc, humanoid::BodyType::Male) => 2.3,
diff --git a/common/src/comp/body/object.rs b/common/src/comp/body/object.rs
index ae4103adf8..297ebf3f14 100644
--- a/common/src/comp/body/object.rs
+++ b/common/src/comp/body/object.rs
@@ -81,6 +81,7 @@ make_case_elim!(
         Coins = 66,
         GoldOre = 67,
         SilverOre = 68,
+        ClayRocket = 69,
     }
 );
 
@@ -91,7 +92,7 @@ impl Body {
     }
 }
 
-pub const ALL_OBJECTS: [Body; 69] = [
+pub const ALL_OBJECTS: [Body; 70] = [
     Body::Arrow,
     Body::Bomb,
     Body::Scarecrow,
@@ -161,6 +162,7 @@ pub const ALL_OBJECTS: [Body; 69] = [
     Body::Coins,
     Body::SilverOre,
     Body::GoldOre,
+    Body::ClayRocket,
 ];
 
 impl From<Body> for super::Body {
@@ -239,6 +241,7 @@ impl Body {
             Body::Coins => "coins",
             Body::SilverOre => "silver_ore",
             Body::GoldOre => "gold_ore",
+            Body::ClayRocket => "clay_rocket",
         }
     }
 
@@ -328,6 +331,7 @@ impl Body {
             Body::WindowSpooky => 10.0,
             Body::SilverOre => 1000.0,
             Body::GoldOre => 1000.0,
+            Body::ClayRocket => 50.0,
         };
 
         Mass(m)
diff --git a/common/src/comp/projectile.rs b/common/src/comp/projectile.rs
index 7bf4ed5f35..b2df2d16aa 100644
--- a/common/src/comp/projectile.rs
+++ b/common/src/comp/projectile.rs
@@ -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,
+                        value: damage,
+                        kind: DamageKind::Energy,
+                    },
+                    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
     }
diff --git a/common/src/states/basic_beam.rs b/common/src/states/basic_beam.rs
index 41959d660f..c0cf48bfa0 100644
--- a/common/src/states/basic_beam.rs
+++ b/common/src/states/basic_beam.rs
@@ -139,7 +139,7 @@ impl CharacterBehavior for Data {
                         specifier: self.static_data.specifier,
                     };
                     let body_offsets_z = match data.body {
-                        Body::BirdLarge(_) => data.body.height() * 0.9,
+                        Body::BirdLarge(_) | Body::Golem(_) => data.body.height() * 0.9,
                         _ => data.body.height() * 0.5,
                     };
                     // Gets offsets
diff --git a/voxygen/src/audio/sfx/mod.rs b/voxygen/src/audio/sfx/mod.rs
index 78f91c532f..8454a83a0f 100644
--- a/voxygen/src/audio/sfx/mod.rs
+++ b/voxygen/src/audio/sfx/mod.rs
@@ -402,6 +402,9 @@ impl SfxMgr {
                         audio.emit_sfx(sfx_trigger_item, *pos, None, false);
                     }
                 },
+                beam::FrontendSpecifier::ClayGolem => {
+                    // TODO: Get sfx for this
+                },
             },
             Outcome::BreakBlock { pos, .. } => {
                 let sfx_trigger_item = triggers.get_key_value(&SfxEvent::BreakBlock);
diff --git a/voxygen/src/render/pipelines/particle.rs b/voxygen/src/render/pipelines/particle.rs
index 32b9cebd37..6205425fa1 100644
--- a/voxygen/src/render/pipelines/particle.rs
+++ b/voxygen/src/render/pipelines/particle.rs
@@ -124,6 +124,7 @@ pub enum ParticleMode {
     Blood = 25,
     Enraged = 26,
     BigShrapnel = 27,
+    Laser = 28,
 }
 
 impl ParticleMode {
diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs
index f0411c9d72..df94a7fe52 100644
--- a/voxygen/src/scene/figure/mod.rs
+++ b/voxygen/src/scene/figure/mod.rs
@@ -4327,6 +4327,29 @@ impl FigureMgr {
                                 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 {
diff --git a/voxygen/src/scene/particle.rs b/voxygen/src/scene/particle.rs
index 142de8e0c6..0cc0e5f1b6 100644
--- a/voxygen/src/scene/particle.rs
+++ b/voxygen/src/scene/particle.rs
@@ -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);