diff --git a/assets/common/abilities/ability_set_manifest.ron b/assets/common/abilities/ability_set_manifest.ron index 2ee9acfb0e..86c22666b2 100644 --- a/assets/common/abilities/ability_set_manifest.ron +++ b/assets/common/abilities/ability_set_manifest.ron @@ -771,8 +771,9 @@ primary: Simple(None, "common.abilities.custom.harvester.scythe"), secondary: Simple(None, "common.abilities.custom.harvester.firebreath"), abilities: [ - Simple(None, "common.abilities.custom.harvester.ensnaringvines"), Simple(None, "common.abilities.custom.harvester.explodingpumpkin"), + Simple(None, "common.abilities.custom.harvester.ensnaringvines_0"), + Simple(None, "common.abilities.custom.harvester.ensnaringvines_1"), ], ), // TODO: Allow ability sets to expand other ability sets diff --git a/assets/common/abilities/custom/harvester/ensnaringvines.ron b/assets/common/abilities/custom/harvester/ensnaringvines_0.ron similarity index 75% rename from assets/common/abilities/custom/harvester/ensnaringvines.ron rename to assets/common/abilities/custom/harvester/ensnaringvines_0.ron index e5d460b2f5..0cf61ffa31 100644 --- a/assets/common/abilities/custom/harvester/ensnaringvines.ron +++ b/assets/common/abilities/custom/harvester/ensnaringvines_0.ron @@ -4,7 +4,7 @@ SpriteSummon( recover_duration: 0.3, sprite: EnsnaringVines, del_timeout: None, - summon_distance: (0, 25), - sparseness: 0.67, + summon_distance: (0, 30), + sparseness: 0.8, angle: 360, ) \ No newline at end of file diff --git a/assets/common/abilities/custom/harvester/ensnaringvines_1.ron b/assets/common/abilities/custom/harvester/ensnaringvines_1.ron new file mode 100644 index 0000000000..6c008eb6e0 --- /dev/null +++ b/assets/common/abilities/custom/harvester/ensnaringvines_1.ron @@ -0,0 +1,10 @@ +SpriteSummon( + buildup_duration: 0.9, + cast_duration: 0.6, + recover_duration: 0.5, + sprite: EnsnaringVines, + del_timeout: None, + summon_distance: (0, 25), + sparseness: 0.6, + angle: 360, +) \ No newline at end of file diff --git a/assets/common/abilities/custom/harvester/explodingpumpkin.ron b/assets/common/abilities/custom/harvester/explodingpumpkin.ron index eb83e298d0..21edcf8eb2 100644 --- a/assets/common/abilities/custom/harvester/explodingpumpkin.ron +++ b/assets/common/abilities/custom/harvester/explodingpumpkin.ron @@ -1,26 +1,25 @@ BasicRanged( energy_cost: 0, - buildup_duration: 0.75, + buildup_duration: 1.0, recover_duration: 1.6, projectile: ( kind: Explosive( - radius: 5, + radius: 7.5, min_falloff: 0.6, reagent: Some(Red), terrain: Some((5, Black)), ), attack: Some(( - damage: 37.5, - knockback: Some(25), + damage: 20, + knockback: Some(22), energy: 0, buff: Some(( kind: Burning, - dur_secs: 5, + dur_secs: 4, strength: DamageFraction(0.2), chance: 1.0, )), )), - ), projectile_body: Object(Pumpkin), projectile_light: None, projectile_speed: 30.0, diff --git a/assets/common/abilities/custom/harvester/firebreath.ron b/assets/common/abilities/custom/harvester/firebreath.ron index 21659fa41f..e63e8b0dbb 100644 --- a/assets/common/abilities/custom/harvester/firebreath.ron +++ b/assets/common/abilities/custom/harvester/firebreath.ron @@ -2,14 +2,14 @@ BasicBeam( buildup_duration: 1.4, recover_duration: 0.9, beam_duration: 1.0, - damage: 9.0, + damage: 5.0, tick_rate: 1.5, range: 20.0, max_angle: 15.0, damage_effect: Some(Buff(( kind: Burning, - dur_secs: 10.0, - strength: DamageFraction(1.0), + dur_secs: 3.0, + strength: DamageFraction(0.8), chance: 1.0, ))), energy_regen: 0, diff --git a/assets/common/abilities/custom/harvester/scythe.ron b/assets/common/abilities/custom/harvester/scythe.ron index 2a6fd89a72..5c6e63dff7 100644 --- a/assets/common/abilities/custom/harvester/scythe.ron +++ b/assets/common/abilities/custom/harvester/scythe.ron @@ -1,12 +1,12 @@ BasicMelee( energy_cost: 0, - buildup_duration: 0.9, - swing_duration: 0.1, + buildup_duration: 1.0, + swing_duration: 0.2, hit_timing: 0.5, - recover_duration: 1.2, + recover_duration: 1.0, melee_constructor: ( kind: Slash( - damage: 21.0, + damage: 13.0, poise: 10.0, knockback: 10.0, energy_regen: 0.0, diff --git a/assets/common/abilities/custom/mandragora/scream.ron b/assets/common/abilities/custom/mandragora/scream.ron index 4b0a4c6563..94a1059f6e 100644 --- a/assets/common/abilities/custom/mandragora/scream.ron +++ b/assets/common/abilities/custom/mandragora/scream.ron @@ -7,7 +7,7 @@ BasicMelee( melee_constructor: ( kind: SonicWave( damage: 10, - poise: 100, + poise: 35, knockback: 20, energy_regen: 0, ), diff --git a/assets/common/abilities/gnarling/chieftain/firebarrage.ron b/assets/common/abilities/gnarling/chieftain/firebarrage.ron index 9aa511de43..0544407ad6 100644 --- a/assets/common/abilities/gnarling/chieftain/firebarrage.ron +++ b/assets/common/abilities/gnarling/chieftain/firebarrage.ron @@ -4,25 +4,26 @@ BasicRanged( recover_duration: 0.6, projectile: ( kind: Explosive( - radius: 2, - min_falloff: 0.5, + radius: 3, + min_falloff: 0.7, reagent: Some(Red), terrain: Some((2, Black)) ), attack: Some(( - damage: 13.5, + damage: 5.5, energy: 10, buff: Some(( kind: Burning, - dur_secs: 5, - strength: DamageFraction(0.1), + dur_secs: 3, + strength: DamageFraction(0.3), chance: 0.1, )), )), + ), projectile_body: Object(BoltFire), projectile_speed: 25, - num_projectiles: 8, + num_projectiles: 5, projectile_spread: 0.125, move_efficiency: 0.3, ) diff --git a/assets/common/abilities/gnarling/chieftain/fireshockwave.ron b/assets/common/abilities/gnarling/chieftain/fireshockwave.ron index 26ce3ab2e9..52fb6fe94f 100644 --- a/assets/common/abilities/gnarling/chieftain/fireshockwave.ron +++ b/assets/common/abilities/gnarling/chieftain/fireshockwave.ron @@ -1,14 +1,14 @@ Shockwave( energy_cost: 0, - buildup_duration: 0.975, + buildup_duration: 1.2, swing_duration: 0.1, - recover_duration: 0.6, - damage: 30, + recover_duration: 0.8, + damage: 16, poise_damage: 0, - knockback: ( strength: 25, direction: Away), + knockback: ( strength: 15, direction: Away), shockwave_angle: 360, shockwave_vertical_angle: 90, - shockwave_speed: 10, + shockwave_speed: 12, shockwave_duration: 1, dodgeable: Roll, move_efficiency: 0, diff --git a/assets/common/abilities/gnarling/chieftain/flamestrike.ron b/assets/common/abilities/gnarling/chieftain/flamestrike.ron index 300e4f5e1b..a736b3ac08 100644 --- a/assets/common/abilities/gnarling/chieftain/flamestrike.ron +++ b/assets/common/abilities/gnarling/chieftain/flamestrike.ron @@ -1,21 +1,21 @@ BasicMelee( energy_cost: 0, - buildup_duration: 0.6, - swing_duration: 0.1, + buildup_duration: 0.7, + swing_duration: 0.35, hit_timing: 0.5, - recover_duration: 0.45, + recover_duration: 0.6, melee_constructor: ( kind: Bash( - damage: 12, + damage: 9, poise: 10, knockback: 0, energy_regen: 0, ), - range: 7.5, + range: 4.0, angle: 60.0, damage_effect: Some(Buff(( kind: Burning, - dur_secs: 10.0, + dur_secs: 4.0, strength: DamageFraction(0.5), chance: 0.5, ))), diff --git a/assets/common/abilities/gnarling/totem/green.ron b/assets/common/abilities/gnarling/totem/green.ron index 90da58c86c..ddb7ad1c9d 100644 --- a/assets/common/abilities/gnarling/totem/green.ron +++ b/assets/common/abilities/gnarling/totem/green.ron @@ -1,24 +1,24 @@ BasicAura( - buildup_duration: 0.375, - cast_duration: 0.5, - recover_duration: 0.375, + buildup_duration: 0.2, + cast_duration: 0.4, + recover_duration: 0.2, targets: InGroup, auras: [ ( kind: Regeneration, - strength: 7.5, - duration: Some(5), + strength: 1, + duration: Some(1), category: Magical, ), ( kind: ProtectingWard, - strength: 0.75, - duration: Some(5), + strength: 1, + duration: Some(1), category: Magical, ), ], - aura_duration: Some(2), - range: 50, + aura_duration: Some(1), + range: 15, energy_cost: 0, scales_with_combo: false, ) diff --git a/assets/common/abilities/gnarling/totem/red.ron b/assets/common/abilities/gnarling/totem/red.ron index 0e58b9d20f..cd4740bae2 100644 --- a/assets/common/abilities/gnarling/totem/red.ron +++ b/assets/common/abilities/gnarling/totem/red.ron @@ -1,18 +1,18 @@ BasicAura( - buildup_duration: 0.375, - cast_duration: 0.5, - recover_duration: 0.375, + buildup_duration: 0.2, + cast_duration: 0.4, + recover_duration: 0.2, targets: OutOfGroup, auras: [ ( kind: Burning, - strength: 0.75, - duration: Some(5), + strength: 1, + duration: Some(1), category: Magical, ), ], - aura_duration: Some(2), - range: 50, + aura_duration: Some(1), + range: 15, energy_cost: 0, scales_with_combo: false, ) diff --git a/assets/common/abilities/gnarling/totem/white.ron b/assets/common/abilities/gnarling/totem/white.ron index 8b95ed0661..3fcde115d8 100644 --- a/assets/common/abilities/gnarling/totem/white.ron +++ b/assets/common/abilities/gnarling/totem/white.ron @@ -1,18 +1,18 @@ BasicAura( - buildup_duration: 0.375, - cast_duration: 0.5, - recover_duration: 0.375, + buildup_duration: 0.2, + cast_duration: 0.4, + recover_duration: 0.2, targets: InGroup, auras: [ ( kind: Hastened, - strength: 0.75, - duration: Some(5), + strength: 0.4, + duration: Some(1), category: Magical, ), ], - aura_duration: Some(2), - range: 50, + aura_duration: Some(1), + range: 15, energy_cost: 0, scales_with_combo: false, ) diff --git a/assets/common/entity/dungeon/gnarling/chieftain.ron b/assets/common/entity/dungeon/gnarling/chieftain.ron index bca94f2d04..0a840a4f1c 100644 --- a/assets/common/entity/dungeon/gnarling/chieftain.ron +++ b/assets/common/entity/dungeon/gnarling/chieftain.ron @@ -2,7 +2,7 @@ #![enable(implicit_some)] ( name: Name("Gnarling Chieftain"), - body: RandomWith("gnarling"), + body: RandomWith("gnarling_chieftain"), alignment: Alignment(Enemy), loot: LootTable("common.loot_tables.dungeon.gnarling.chieftain"), inventory: ( diff --git a/assets/common/items/lantern/pumpkin.ron b/assets/common/items/lantern/pumpkin.ron index 2bb0f2dad6..fc76f4543f 100644 --- a/assets/common/items/lantern/pumpkin.ron +++ b/assets/common/items/lantern/pumpkin.ron @@ -8,6 +8,6 @@ ItemDef( flicker_thousandths: 600, ), ), - quality: High, + quality: Moderate, tags: [Utility], ) diff --git a/assets/common/loot_tables/dungeon/gnarling/chieftain.ron b/assets/common/loot_tables/dungeon/gnarling/chieftain.ron index 7d61aa5139..8ee1db11d3 100644 --- a/assets/common/loot_tables/dungeon/gnarling/chieftain.ron +++ b/assets/common/loot_tables/dungeon/gnarling/chieftain.ron @@ -1,12 +1,18 @@ [ - // Weapons - (5.0, LootTable("common.loot_tables.weapons.tier-1")), - // Armor - (5.0, LootTable("common.loot_tables.armor.tier-1")), - // Misc - (3.0, Item("common.items.armor.misc.neck.scratched")), - (2.0, Item("common.items.armor.misc.head.wanderers_hat")), - (3.0, Item("common.items.armor.misc.head.bamboo_twig")), - // Chieftain Mask - (1.0, Item("common.items.armor.misc.head.gnarling_mask")), + (1, All([ + MultiDrop(Item("common.items.mineral.ore.veloritefrag"), 4, 6), + Lottery([ + (1.0, LootTable("common.loot_tables.armor.tier-1")), + (1.0, LootTable("common.loot_tables.weapons.tier-1")), + ]), + Lottery([ + (1.0, LootTable("common.loot_tables.armor.tier-0")), + (1.0, LootTable("common.loot_tables.weapons.tier-0")), + ]), + Lottery([ + (3.0, Item("common.items.armor.misc.neck.scratched")), + (1.0, Item("common.items.armor.misc.head.wanderers_hat")), + (1.0, Item("common.items.armor.misc.head.gnarling_mask")), + ]) + ])) ] \ No newline at end of file diff --git a/assets/common/loot_tables/dungeon/gnarling/harvester.ron b/assets/common/loot_tables/dungeon/gnarling/harvester.ron index 93f8b040a6..730ce14faa 100644 --- a/assets/common/loot_tables/dungeon/gnarling/harvester.ron +++ b/assets/common/loot_tables/dungeon/gnarling/harvester.ron @@ -1,10 +1,18 @@ [ - // Weapons - (5.0, LootTable("common.loot_tables.weapons.tier-3")), - // Armor - (5.0, LootTable("common.loot_tables.armor.tier-3")), - // Misc - (3.0, Item("common.items.armor.misc.neck.scratched")), - (2.0, Item("common.items.lantern.pumpkin")), - (1.0, Item("common.items.glider.moth")), + (1, All([ + MultiDrop(Item("common.items.mineral.ore.velorite"), 2, 3), + Lottery([ + (1.0, LootTable("common.loot_tables.armor.tier-2")), + (1.0, LootTable("common.loot_tables.weapons.tier-2")), + ]), + Lottery([ + (1.0, LootTable("common.loot_tables.armor.tier-1")), + (1.0, LootTable("common.loot_tables.weapons.tier-1")), + ]) + Lottery([ + (3.0, Nothing), + (1.0, Item("common.items.lantern.pumpkin")), + (1.0, Item("common.items.glider.moth")), + ]) + ])) ] \ No newline at end of file diff --git a/assets/common/loot_tables/sprite/chest-buried.ron b/assets/common/loot_tables/sprite/chest-buried.ron index def2f90c5b..5c2a4f5f56 100644 --- a/assets/common/loot_tables/sprite/chest-buried.ron +++ b/assets/common/loot_tables/sprite/chest-buried.ron @@ -1,5 +1,5 @@ [ - (1.0, LootTable("common.loot_tables.weapons.components.tier-1")), + (1.0, LootTable("common.loot_tables.weapons.components.tier-0")), (1.0, LootTable("common.loot_tables.armor.cloth")), (0.5, Item("common.items.recipes.explosives")), ] diff --git a/assets/common/loot_tables/sprite/chest.ron b/assets/common/loot_tables/sprite/chest.ron index 0c1737ad16..2b72a0c0c5 100644 --- a/assets/common/loot_tables/sprite/chest.ron +++ b/assets/common/loot_tables/sprite/chest.ron @@ -1,7 +1,16 @@ [ - (1.0, LootTable("common.loot_tables.weapons.components.tier-0")), - (1.0, LootTable("common.loot_tables.weapons.components.tier-1")), - (1.0, LootTable("common.loot_tables.armor.cloth")), + (0.5, LootTable("common.loot_tables.weapons.components.tier-0")), + (0.25, LootTable("common.loot_tables.weapons.tier-0")), + (0.25, LootTable("common.loot_tables.armor.tier-0")), + (0.25, Item("common.items.armor.misc.head.bamboo_twig")), + // Currency + (3.0, MultiDrop(Item("common.items.utility.coins"), 25, 50)), + // Materials + (0.5, MultiDrop(Item("common.items.mineral.ore.veloritefrag"), 5, 10)), + // Consumables + (2.0, MultiDrop(Item("common.items.consumable.potion_minor"), 2, 5)), + // Food + (1.0, MultiDrop(LootTable("common.loot_tables.food.prepared"), 1, 2)), (0.2, Item("common.items.recipes.explosives")), (0.5, Item("common.items.recipes.instruments")), (0.2, Item("common.items.recipes.charms")), diff --git a/assets/common/npc_names.ron b/assets/common/npc_names.ron index 0202c723d0..7381a4b5b7 100644 --- a/assets/common/npc_names.ron +++ b/assets/common/npc_names.ron @@ -1233,6 +1233,10 @@ keyword: "treasure_egg", generic: "Treasure Egg", ), + gnarling_chieftain: ( + keyword: "gnarling_chieftain", + generic: "Gnarling Chieftain" + ), ) ), fish_small: ( diff --git a/common/src/comp/agent.rs b/common/src/comp/agent.rs index 41dd6feabd..649f424f01 100644 --- a/common/src/comp/agent.rs +++ b/common/src/comp/agent.rs @@ -379,7 +379,8 @@ impl<'a> From<&'a Body> for Psyche { | biped_small::Species::Irrwurz | biped_small::Species::ShamanicSpirit | biped_small::Species::Jiangshi - | biped_small::Species::Bushly => 0.0, + | biped_small::Species::Bushly + | biped_small::Species::GnarlingChieftain => 0.0, _ => 0.5, }, diff --git a/common/src/comp/body.rs b/common/src/comp/body.rs index cad424bf90..05d17cc887 100644 --- a/common/src/comp/body.rs +++ b/common/src/comp/body.rs @@ -552,6 +552,7 @@ impl Body { biped_small::Species::Jiangshi => Vec3::new(1.3, 1.8, 2.5), biped_small::Species::Flamekeeper => Vec3::new(1.5, 1.5, 2.5), biped_small::Species::TreasureEgg => Vec3::new(1.1, 1.1, 1.4), + biped_small::Species::GnarlingChieftain => Vec3::new(1.0, 0.75, 1.4), _ => Vec3::new(1.0, 0.75, 1.4), }, Body::BirdLarge(body) => match body.species { @@ -948,7 +949,7 @@ impl Body { biped_large::Species::Tidalwarrior => 1600, biped_large::Species::Yeti => 1800, biped_large::Species::Minotaur => 3000, - biped_large::Species::Harvester => 1500, + biped_large::Species::Harvester => 1300, biped_large::Species::Blueoni => 240, biped_large::Species::Redoni => 240, biped_large::Species::Huskbrute => 800, @@ -969,6 +970,7 @@ impl Body { }, Body::BipedSmall(biped_small) => match biped_small.species { biped_small::Species::Gnarling => 50, + biped_small::Species::GnarlingChieftain => 150, biped_small::Species::Adlet => 65, biped_small::Species::Sahagin => 85, biped_small::Species::Haniwa => 100, @@ -990,9 +992,9 @@ impl Body { object::Body::BarrelOrgan => 500, object::Body::HaniwaSentry => 60, object::Body::SeaLantern => 100, - object::Body::GnarlingTotemGreen => 25, object::Body::TerracottaStatue => 600, - object::Body::GnarlingTotemRed | object::Body::GnarlingTotemWhite => 35, + object::Body::GnarlingTotemGreen => 15, + object::Body::GnarlingTotemRed | object::Body::GnarlingTotemWhite => 15, _ => 1000, }, Body::ItemDrop(_) => 1000, diff --git a/common/src/comp/body/biped_small.rs b/common/src/comp/body/biped_small.rs index 91d8d9e625..e313889b3f 100644 --- a/common/src/comp/body/biped_small.rs +++ b/common/src/comp/body/biped_small.rs @@ -53,6 +53,7 @@ make_case_elim!( ShamanicSpirit = 16, Jiangshi = 17, TreasureEgg = 18, + GnarlingChieftain = 19, } ); @@ -80,6 +81,7 @@ pub struct AllSpecies { pub shamanic_spirit: SpeciesMeta, pub jiangshi: SpeciesMeta, pub treasure_egg: SpeciesMeta, + pub gnarling_chieftain: SpeciesMeta, } impl<'a, SpeciesMeta> core::ops::Index<&'a Species> for AllSpecies { @@ -107,11 +109,12 @@ impl<'a, SpeciesMeta> core::ops::Index<&'a Species> for AllSpecies Species::ShamanicSpirit => &self.shamanic_spirit, Species::Jiangshi => &self.jiangshi, Species::TreasureEgg => &self.treasure_egg, + Species::GnarlingChieftain => &self.gnarling_chieftain, } } } -pub const ALL_SPECIES: [Species; 19] = [ +pub const ALL_SPECIES: [Species; 20] = [ Species::Gnome, Species::Sahagin, Species::Adlet, @@ -131,6 +134,7 @@ pub const ALL_SPECIES: [Species; 19] = [ Species::ShamanicSpirit, Species::Jiangshi, Species::TreasureEgg, + Species::GnarlingChieftain, ]; impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies { diff --git a/common/src/terrain/sprite.rs b/common/src/terrain/sprite.rs index 7d2db98ba1..8153092a3b 100644 --- a/common/src/terrain/sprite.rs +++ b/common/src/terrain/sprite.rs @@ -543,7 +543,7 @@ impl SpriteKind { | SpriteKind::Gold => 0.6, SpriteKind::EnsnaringVines | SpriteKind::CavernLillypadBlue - | SpriteKind::EnsnaringWeb => 0.1, + | SpriteKind::EnsnaringWeb => 0.15, SpriteKind::LillyPads => 0.1, SpriteKind::WindowArabic | SpriteKind::BookshelfArabic => 1.9, SpriteKind::DecorSetArabic => 2.6, diff --git a/common/systems/src/buff.rs b/common/systems/src/buff.rs index 9b8103f0f6..95305fa07e 100644 --- a/common/systems/src/buff.rs +++ b/common/systems/src/buff.rs @@ -206,9 +206,27 @@ impl<'a> System<'a> for Sys { } if matches!( physics_state.on_ground.and_then(|b| b.get_sprite()), - Some(SpriteKind::EnsnaringVines) | Some(SpriteKind::EnsnaringWeb) + Some(SpriteKind::EnsnaringVines) ) { - // If on ensnaring vines, apply ensnared debuff + // If on ensnaring vines, apply partial ensnared debuff + emitters.emit(BuffEvent { + entity, + buff_change: BuffChange::Add(Buff::new( + BuffKind::Ensnared, + BuffData::new(0.5, Some(Secs(1.0))), + Vec::new(), + BuffSource::World, + *read_data.time, + dest_info, + None, + )), + }); + } + if matches!( + physics_state.on_ground.and_then(|b| b.get_sprite()), + Some(SpriteKind::EnsnaringWeb) + ) { + // If on ensnaring web, apply ensnared debuff emitters.emit(BuffEvent { entity, buff_change: BuffChange::Add(Buff::new( diff --git a/server/agent/src/action_nodes.rs b/server/agent/src/action_nodes.rs index 1ac323cb21..3fe487f938 100644 --- a/server/agent/src/action_nodes.rs +++ b/server/agent/src/action_nodes.rs @@ -1617,9 +1617,14 @@ impl<'a> AgentData<'a> { Tactic::Yeti => { self.handle_yeti_attack(agent, controller, &attack_data, tgt_data, read_data) }, - Tactic::Harvester => { - self.handle_harvester_attack(agent, controller, &attack_data, tgt_data, read_data) - }, + Tactic::Harvester => self.handle_harvester_attack( + agent, + controller, + &attack_data, + tgt_data, + read_data, + rng, + ), Tactic::Cardinal => self.handle_cardinal_attack( agent, controller, diff --git a/server/agent/src/attack.rs b/server/agent/src/attack.rs index 79c4f8c6bf..6ad5abcebd 100644 --- a/server/agent/src/attack.rs +++ b/server/agent/src/attack.rs @@ -4756,13 +4756,39 @@ impl<'a> AgentData<'a> { attack_data: &AttackData, tgt_data: &TargetData, read_data: &ReadData, + rng: &mut impl Rng, ) { - const VINE_CREATION_THRESHOLD: f32 = 0.50; - const FIRE_BREATH_RANGE: f32 = 20.0; + const FIRST_VINE_CREATION_THRESHOLD: f32 = 0.60; + const SECOND_VINE_CREATION_THRESHOLD: f32 = 0.30; const MAX_PUMPKIN_RANGE: f32 = 50.0; + const FIRE_BREATH_RANGE: f32 = 20.0; + const FIRE_BREATH_TIME: f32 = 4.0; + const FIRE_BREATH_SHORT_TIME: f32 = 2.0; + const FIRE_BREATH_COOLDOWN: f32 = 3.0; + const CLOSE_MIXUP_COOLDOWN: f32 = 6.0; enum ActionStateConditions { - ConditionHasSummonedVines = 0, + ConditionHasSummonedFirstVines = 0, + ConditionHasSummonedSecondVines, + } + + enum ActionStateTimers { + TimerFire = 0, + TimerCloseMixup, + } + + match self.char_state { + CharacterState::BasicBeam(_) => { + agent.combat_state.timers[ActionStateTimers::TimerFire as usize] = 0.0; + }, + CharacterState::BasicRanged(_) => { + agent.combat_state.timers[ActionStateTimers::TimerCloseMixup as usize] = 0.0; + }, + _ => { + agent.combat_state.timers[ActionStateTimers::TimerFire as usize] += read_data.dt.0; + agent.combat_state.timers[ActionStateTimers::TimerCloseMixup as usize] += + read_data.dt.0; + }, } let health_fraction = self.health.map_or(0.5, |h| h.fraction()); @@ -4778,36 +4804,86 @@ impl<'a> AgentData<'a> { ) }; - if health_fraction < VINE_CREATION_THRESHOLD + if (health_fraction < FIRST_VINE_CREATION_THRESHOLD && !agent.combat_state.conditions - [ActionStateConditions::ConditionHasSummonedVines as usize] + [ActionStateConditions::ConditionHasSummonedFirstVines as usize]) + || (health_fraction < SECOND_VINE_CREATION_THRESHOLD + && !agent.combat_state.conditions + [ActionStateConditions::ConditionHasSummonedSecondVines as usize]) { - // Summon vines when reach threshold of health - controller.push_basic_input(InputKind::Ability(0)); + if health_fraction < SECOND_VINE_CREATION_THRESHOLD { + // Summon second vines when reach threshold of health + controller.push_basic_input(InputKind::Ability(2)); - if matches!(self.char_state, CharacterState::SpriteSummon(c) if matches!(c.stage_section, StageSection::Recover)) - { - agent.combat_state.conditions - [ActionStateConditions::ConditionHasSummonedVines as usize] = true; + if matches!(self.char_state, CharacterState::SpriteSummon(c) if matches!(c.stage_section, StageSection::Recover)) + { + agent.combat_state.conditions + [ActionStateConditions::ConditionHasSummonedSecondVines as usize] = true; + } + } else { + // Summon first vines when reach threshold of health + controller.push_basic_input(InputKind::Ability(1)); + + if matches!(self.char_state, CharacterState::SpriteSummon(c) if matches!(c.stage_section, StageSection::Recover)) + { + agent.combat_state.conditions + [ActionStateConditions::ConditionHasSummonedFirstVines as usize] = true; + } } - } else if attack_data.dist_sqrd < FIRE_BREATH_RANGE.powi(2) { - if matches!(self.char_state, CharacterState::BasicBeam(c) if c.timer < Duration::from_secs(5)) - && line_of_sight_with_target() + } else if attack_data.in_min_range() { + if matches!(self.char_state, CharacterState::BasicBeam(c) if c.timer < Duration::from_secs_f32(FIRE_BREATH_SHORT_TIME)) { // Keep breathing fire if close enough, can see target, and have not been - // breathing for more than 5 seconds + // breathing for more than short limit controller.push_basic_input(InputKind::Secondary); - } else if attack_data.in_min_range() && attack_data.angle < 60.0 { + } else if agent.combat_state.timers[ActionStateTimers::TimerCloseMixup as usize] + > CLOSE_MIXUP_COOLDOWN + && line_of_sight_with_target() + { + if agent.combat_state.timers[ActionStateTimers::TimerFire as usize] + < FIRE_BREATH_COOLDOWN + { + // Throw a close range pumpkin to knock back player + controller.push_basic_input(InputKind::Ability(0)); + } else { + let randomise = rng.gen_range(1..=3); + match randomise { + 1 => controller.push_basic_input(InputKind::Secondary), /* start fire + * breath */ + _ => controller.push_basic_input(InputKind::Ability(0)), /* close range + * pumpkin + * _ => controller.push_basic_input(InputKind::Primary), // scythe */ + } + } + } else if attack_data.angle < 60.0 { // Scythe them if they're in range and angle controller.push_basic_input(InputKind::Primary); - } else if attack_data.angle < 30.0 && line_of_sight_with_target() { - // Start breathing fire at them if close enough, in angle, and can see target - controller.push_basic_input(InputKind::Secondary); + } + } else if attack_data.dist_sqrd < FIRE_BREATH_RANGE.powi(2) { + if line_of_sight_with_target() { + if matches!(self.char_state, CharacterState::BasicBeam(c) if c.timer < Duration::from_secs_f32(FIRE_BREATH_TIME)) + { + // Keep breathing fire if close enough, can see target, and have not been + // breathing for more than upper limit + controller.push_basic_input(InputKind::Secondary); + } else if attack_data.angle < 30.0 + && agent.combat_state.timers[ActionStateTimers::TimerFire as usize] + > FIRE_BREATH_COOLDOWN + { + // Start breathing fire at them if close enough, in angle, and can see target + controller.push_basic_input(InputKind::Secondary); + } else if agent.combat_state.timers[ActionStateTimers::TimerCloseMixup as usize] + > CLOSE_MIXUP_COOLDOWN + { + // Throw a close range pumpkin to knock back player + controller.push_basic_input(InputKind::Ability(0)); + } } } else if attack_data.dist_sqrd < MAX_PUMPKIN_RANGE.powi(2) && line_of_sight_with_target() { // Throw a pumpkin at them if close enough and can see them - controller.push_basic_input(InputKind::Ability(1)); + controller.push_basic_input(InputKind::Ability(0)); } + // Always attempt to path towards target self.path_toward_target( agent, @@ -5810,8 +5886,8 @@ impl<'a> AgentData<'a> { read_data: &ReadData, rng: &mut impl Rng, ) { - const TOTEM_TIMER: f32 = 10.0; - const HEAVY_ATTACK_WAIT_TIME: f32 = 15.0; + const TOTEM_TIMER: f32 = 20.0; + const HEAVY_ATTACK_WAIT_TIME: f32 = 10.0; enum ActionStateTimers { TimerSummonTotem = 0, @@ -5846,7 +5922,7 @@ impl<'a> AgentData<'a> { 3 => Some(BuffKind::Hastened), _ => None, }; - if buff_kind.map_or(true, |b| self.has_buff(read_data, b)) + if buff_kind.map_or(false, |b| self.has_buff(read_data, b)) && matches!(self.char_state, CharacterState::Wielding { .. }) { // If already under effects of buff from totem that would be summoned, don't @@ -5892,14 +5968,16 @@ impl<'a> AgentData<'a> { read_data.dt.0 * 3.3; } - self.path_toward_target( - agent, - controller, - tgt_data.pos.0, - read_data, - Path::Full, - None, - ); + if !attack_data.in_min_range() { + self.path_toward_target( + agent, + controller, + tgt_data.pos.0, + read_data, + Path::Full, + None, + ); + } } pub fn handle_sword_simple_attack( diff --git a/voxygen/anim/src/biped_large/spritesummon.rs b/voxygen/anim/src/biped_large/spritesummon.rs index 3da133b60c..df59e9e36e 100644 --- a/voxygen/anim/src/biped_large/spritesummon.rs +++ b/voxygen/anim/src/biped_large/spritesummon.rs @@ -113,7 +113,8 @@ impl Animation for SpriteSummonAnimation { * Quaternion::rotation_y(move2 * -0.1); }, Some(ToolKind::Natural) => match ability_id { - Some("common.abilities.custom.harvester.ensnaringvines") => { + Some("common.abilities.custom.harvester.ensnaringvines_0") + | Some("common.abilities.custom.harvester.ensnaringvines_1") => { let (move1, move1pow, move2, move3) = match stage_section { Some(StageSection::Buildup) => (anim_time, anim_time.powf(0.1), 0.0, 0.0), Some(StageSection::Action) => { diff --git a/voxygen/anim/src/biped_small/mod.rs b/voxygen/anim/src/biped_small/mod.rs index e614f95c59..59217a795f 100644 --- a/voxygen/anim/src/biped_small/mod.rs +++ b/voxygen/anim/src/biped_small/mod.rs @@ -168,6 +168,7 @@ impl<'a> From<&'a Body> for SkeletonAttr { (ShamanicSpirit, _) => (-0.5, 4.5), (Jiangshi, _) => (-1.0, 6.5), (TreasureEgg, _) => (-1.0, 9.0), + (GnarlingChieftain, _) => (0.0, 6.0), }, chest: match (body.species, body.body_type) { (Gnome, _) => (0.0, 9.0), @@ -189,6 +190,7 @@ impl<'a> From<&'a Body> for SkeletonAttr { (ShamanicSpirit, _) => (0.0, 14.5), (Jiangshi, _) => (0.0, 14.0), (TreasureEgg, _) => (0.0, 3.0), + (GnarlingChieftain, _) => (0.0, 7.5), }, pants: match (body.species, body.body_type) { (Gnome, _) => (0.0, -3.0), @@ -210,6 +212,7 @@ impl<'a> From<&'a Body> for SkeletonAttr { (ShamanicSpirit, _) => (0.0, -8.0), (Jiangshi, _) => (0.5, -6.0), (TreasureEgg, _) => (0.0, 1.0), + (GnarlingChieftain, _) => (0.0, -3.0), }, tail: match (body.species, body.body_type) { (Gnome, _) => (0.0, 0.0), @@ -231,6 +234,7 @@ impl<'a> From<&'a Body> for SkeletonAttr { (ShamanicSpirit, _) => (0.0, 0.0), (Jiangshi, _) => (0.0, 0.0), (TreasureEgg, _) => (0.0, 0.0), + (GnarlingChieftain, _) => (-2.0, 1.5), }, hand: match (body.species, body.body_type) { (Gnome, _) => (4.0, 0.5, -1.0), @@ -252,6 +256,7 @@ impl<'a> From<&'a Body> for SkeletonAttr { (ShamanicSpirit, _) => (5.0, 0.0, 1.0), (Jiangshi, _) => (5.0, -1.0, 3.0), (TreasureEgg, _) => (5.0, 2.0, 5.0), + (GnarlingChieftain, _) => (4.0, 0.0, 1.5), }, foot: match (body.species, body.body_type) { (Gnome, _) => (3.0, 0.0, 4.0), @@ -273,6 +278,7 @@ impl<'a> From<&'a Body> for SkeletonAttr { (ShamanicSpirit, _) => (3.5, 3.0, 7.0), (Jiangshi, _) => (3.0, 0.0, 8.0), (TreasureEgg, _) => (2.0, 0.5, 4.0), + (GnarlingChieftain, _) => (2.5, 1.0, 5.0), }, grip: match (body.species, body.body_type) { (Gnome, _) => (0.0, 0.0, 5.0), @@ -294,6 +300,7 @@ impl<'a> From<&'a Body> for SkeletonAttr { (ShamanicSpirit, _) => (0.0, 0.0, 8.0), (Jiangshi, _) => (0.0, 0.0, 8.0), (TreasureEgg, _) => (0.0, 0.0, 7.0), + (GnarlingChieftain, _) => (0.0, 0.0, 7.0), }, scaler: match (body.species, body.body_type) { (Gnome, _) => 0.8, @@ -315,6 +322,7 @@ impl<'a> From<&'a Body> for SkeletonAttr { (ShamanicSpirit, _) => 1.0, (Jiangshi, _) => 1.0, (TreasureEgg, _) => 1.0, + (GnarlingChieftain, _) => 0.8, }, } } diff --git a/voxygen/src/scene/particle.rs b/voxygen/src/scene/particle.rs index b50aeee38b..2386531814 100644 --- a/voxygen/src/scene/particle.rs +++ b/voxygen/src/scene/particle.rs @@ -1894,11 +1894,11 @@ impl ParticleMgr { kind: buff::BuffKind::Burning, .. } => { - let num_particles = aura.radius.powi(2) * dt / 250.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 heartbeats = self.scheduler.heartbeats(Duration::from_millis(5)); + self.particles.resize_with( + self.particles.len() + + aura.radius.powi(2) as usize * usize::from(heartbeats) / 300, + || { let rand_pos = { let theta = rng.gen::() * TAU; let radius = aura.radius * rng.gen::().sqrt(); @@ -1918,7 +1918,8 @@ impl ParticleMgr { rand_pos.with_z(pos.z), rand_pos.with_z(pos.z + 1.0), ) - }); + }, + ); }, aura::AuraKind::Buff { kind: buff::BuffKind::Hastened,