diff --git a/assets/common/abilities/unique/quadlowranged/basic.ron b/assets/common/abilities/unique/quadlowranged/basic.ron index 5412352bbb..1c5d5e3b78 100644 --- a/assets/common/abilities/unique/quadlowranged/basic.ron +++ b/assets/common/abilities/unique/quadlowranged/basic.ron @@ -1,18 +1,10 @@ -BasicRanged( +BasicMelee( energy_cost: 0, - buildup_duration: 800, - recover_duration: 350, - projectile: Fireball( - damage: 100.0, - radius: 5.0, - energy_regen: 50, - ), - projectile_body: Object(BoltFire), - /*projectile_light: Some(LightEmitter { - col: (1.0, 0.75, 0.11).into(), - ..Default::default() - }),*/ - projectile_gravity: Some(Gravity(0.9)), - projectile_speed: 60.0, - can_continue: true, + buildup_duration: 250, + swing_duration: 250, + recover_duration: 250, + base_damage: 200, + knockback: 25.0, + range: 2.0, + max_angle: 120.0, ) \ No newline at end of file diff --git a/assets/common/abilities/unique/quadlowranged/firebomb.ron b/assets/common/abilities/unique/quadlowranged/firebomb.ron new file mode 100644 index 0000000000..77011621e8 --- /dev/null +++ b/assets/common/abilities/unique/quadlowranged/firebomb.ron @@ -0,0 +1,18 @@ +BasicRanged( + energy_cost: 0, + buildup_duration: 800, + recover_duration: 350, + projectile: Fireball( + damage: 100.0, + radius: 5.0, + energy_regen: 0, + ), + projectile_body: Object(BoltFire), + /*projectile_light: Some(LightEmitter { + col: (1.0, 0.75, 0.11).into(), + ..Default::default() + }),*/ + projectile_gravity: Some(Gravity(5.0)), + projectile_speed: 60.0, + can_continue: true, +) \ No newline at end of file diff --git a/assets/common/items/npc_weapons/unique/beast_claws.ron b/assets/common/items/npc_weapons/unique/beast_claws.ron index 7f3c4590f5..e871f541e4 100644 --- a/assets/common/items/npc_weapons/unique/beast_claws.ron +++ b/assets/common/items/npc_weapons/unique/beast_claws.ron @@ -7,7 +7,7 @@ ItemDef( stats: ( equip_time_millis: 500, power: 1.00, - speed: 1.0 + speed: 1.0, ), ) ), diff --git a/assets/common/items/npc_weapons/unique/genericquadmed.ron b/assets/common/items/npc_weapons/unique/genericquadmed.ron index ba3657128a..a4b30c5373 100644 --- a/assets/common/items/npc_weapons/unique/genericquadmed.ron +++ b/assets/common/items/npc_weapons/unique/genericquadmed.ron @@ -6,7 +6,9 @@ ItemDef( kind: Unique(GenericQuadMed), stats: ( equip_time_millis: 10, - power: 1.00), + power: 1.00, + speed: 1.0, + ), ) ), quality: Low, diff --git a/assets/common/items/npc_weapons/unique/quadlowranged.ron b/assets/common/items/npc_weapons/unique/quadlowranged.ron index e1cd2471da..282c1fa15a 100644 --- a/assets/common/items/npc_weapons/unique/quadlowranged.ron +++ b/assets/common/items/npc_weapons/unique/quadlowranged.ron @@ -6,7 +6,9 @@ ItemDef( kind: Unique(QuadLowRanged), stats: ( equip_time_millis: 10, - power: 1.00), + power: 1.00, + speed: 1.00, + ), ) ), quality: Low, diff --git a/common/src/sys/agent.rs b/common/src/sys/agent.rs index 99e9fabb43..30b0834fcd 100644 --- a/common/src/sys/agent.rs +++ b/common/src/sys/agent.rs @@ -8,9 +8,9 @@ use crate::{ tool::{ToolKind, UniqueKind}, ItemKind, }, - Agent, Alignment, Body, CharacterState, ControlAction, ControlEvent, Controller, Energy, - GroupManip, Health, LightEmitter, Loadout, MountState, Ori, PhysicsState, Pos, Scale, - UnresolvedChatMsg, Vel, + quadruped_low, Agent, Alignment, Body, CharacterState, ControlAction, ControlEvent, + Controller, Energy, GroupManip, Health, LightEmitter, Loadout, MountState, Ori, + PhysicsState, Pos, Scale, UnresolvedChatMsg, Vel, }, event::{EventBus, ServerEvent}, metrics::SysMetrics, @@ -334,6 +334,7 @@ impl<'a> System<'a> for Sys { Staff, StoneGolemBoss, Wolf, + Maneater, } let tactic = match loadout.active_item.as_ref().and_then(|ic| { @@ -352,7 +353,7 @@ impl<'a> System<'a> for Sys { Tactic::StoneGolemBoss }, Some(ToolKind::Unique(UniqueKind::GenericQuadMed)) => Tactic::Wolf, - Some(ToolKind::Unique(UniqueKind::QuadLowRanged)) => Tactic::Staff, + Some(ToolKind::Unique(UniqueKind::QuadLowRanged)) => Tactic::Maneater, _ => Tactic::Melee, }; @@ -377,6 +378,7 @@ impl<'a> System<'a> for Sys { let distance_offset = match tactic { Tactic::Bow => 0.0004 * pos.0.distance_squared(tgt_pos.0), Tactic::Staff => 0.0015 * pos.0.distance_squared(tgt_pos.0), + Tactic::Maneater => 0.05 * pos.0.distance_squared(tgt_pos.0), _ => 0.0, }; @@ -390,10 +392,6 @@ impl<'a> System<'a> for Sys { inputs.look_dir = dir; } - //if let Some(dir) = Dir::from_unnormalized(tgt_pos.0 - pos.0) { - // inputs.look_dir = dir; - //} - // Don't attack entities we are passive towards // TODO: This is here, it's a bit of a hack if let Some(alignment) = alignment { @@ -444,11 +442,14 @@ impl<'a> System<'a> for Sys { } } else if (tactic == Tactic::Staff && dist_sqrd < (5.0 * MIN_ATTACK_DIST * scale).powf(2.0)) + || (tactic == Tactic::Maneater + && dist_sqrd < (4.0 * MIN_ATTACK_DIST * scale).powf(2.0)) || (tactic == Tactic::Wolf && dist_sqrd < (3.0 * MIN_ATTACK_DIST * scale).powf(2.0)) || dist_sqrd < (MIN_ATTACK_DIST * scale).powf(2.0) { controller.actions.push(ControlAction::Wield); + // Movement match tactic { Tactic::Wolf => { // Run away from target to get clear @@ -458,69 +459,75 @@ impl<'a> System<'a> for Sys { .try_normalized() .unwrap_or(Vec2::unit_y()); }, + Tactic::Maneater => { + inputs.move_dir = (tgt_pos.0 - pos.0) + .xy() + .try_normalized() + .unwrap_or(Vec2::unit_y()); + }, _ => { - // Close-range attack inputs.move_dir = (tgt_pos.0 - pos.0) .xy() .try_normalized() .unwrap_or(Vec2::unit_y()) * 0.1; + }, + } - match tactic { - Tactic::Hammer => { - if *powerup > 4.0 { - inputs.secondary.set_state(false); - *powerup = 0.0; - } else if *powerup > 2.0 { - inputs.secondary.set_state(true); - *powerup += dt.0; - } else if energy.current() > 700 { - inputs.ability3.set_state(true); - *powerup += dt.0; - } else { - inputs.primary.set_state(true); - *powerup += dt.0; - } - }, - Tactic::Staff => { - // Kind of arbitrary values, but feel right in game - if energy.current() > 800 - && thread_rng().gen::() > 0.8 - { - inputs.ability3.set_state(true) - } else if energy.current() > 10 { - inputs.secondary.set_state(true) - } else { - inputs.primary.set_state(true) - } - }, - Tactic::Sword => { - if *powerup < 2.0 && energy.current() > 500 { - inputs.ability3.set_state(true); - *powerup += dt.0; - } else if *powerup > 2.0 { - *powerup = 0.0; - } else { - inputs.primary.set_state(true); - *powerup += dt.0; - } - }, - Tactic::Axe => { - if *powerup > 6.0 { - inputs.secondary.set_state(false); - *powerup = 0.0; - } else if *powerup > 4.0 && energy.current() > 10 { - inputs.secondary.set_state(true); - *powerup += dt.0; - } else { - inputs.primary.set_state(true); - *powerup += dt.0; - } - }, - Tactic::Bow => inputs.roll.set_state(true), - _ => inputs.primary.set_state(true), + match tactic { + Tactic::Hammer => { + if *powerup > 4.0 { + inputs.secondary.set_state(false); + *powerup = 0.0; + } else if *powerup > 2.0 { + inputs.secondary.set_state(true); + *powerup += dt.0; + } else if energy.current() > 700 { + inputs.ability3.set_state(true); + *powerup += dt.0; + } else { + inputs.primary.set_state(true); + *powerup += dt.0; } }, + Tactic::Staff => { + // Kind of arbitrary values, but feel right in game + if energy.current() > 800 && thread_rng().gen::() > 0.8 + { + inputs.ability3.set_state(true) + } else if energy.current() > 10 { + inputs.secondary.set_state(true) + } else { + inputs.primary.set_state(true) + } + }, + Tactic::Sword => { + if *powerup < 2.0 && energy.current() > 500 { + inputs.ability3.set_state(true); + *powerup += dt.0; + } else if *powerup > 2.0 { + *powerup = 0.0; + } else { + inputs.primary.set_state(true); + *powerup += dt.0; + } + }, + Tactic::Axe => { + if *powerup > 6.0 { + inputs.secondary.set_state(false); + *powerup = 0.0; + } else if *powerup > 4.0 && energy.current() > 10 { + inputs.secondary.set_state(true); + *powerup += dt.0; + } else { + inputs.primary.set_state(true); + *powerup += dt.0; + } + }, + Tactic::Maneater => inputs.secondary.set_state(true), + Tactic::Bow => inputs.roll.set_state(true), + Tactic::Melee => inputs.primary.set_state(true), + _ => {}, } } else if matches!(tactic, Tactic::Wolf) && dist_sqrd < (4.0 * MIN_ATTACK_DIST * scale).powf(2.0) @@ -557,13 +564,27 @@ impl<'a> System<'a> for Sys { || (dist_sqrd < SIGHT_DIST.powf(2.0) && (!*been_close || !matches!(tactic, Tactic::Melee))) { - let can_see_tgt = terrain - .ray(pos.0 + Vec3::unit_z(), tgt_pos.0 + Vec3::unit_z()) - .until(Block::is_opaque) - .cast() - .0 - .powf(2.0) - >= dist_sqrd; + let can_see_tgt = match tactic { + Tactic::Maneater => { + terrain + .ray(pos.0 + Vec3::unit_z(), tgt_pos.0 + Vec3::unit_z()) + .until(Block::is_opaque) + .cast() + .0 + .powf(2.0) + >= dist_sqrd + && dist_sqrd < (1.2 * MAX_CHASE_DIST).powf(2.0) + }, + _ => { + terrain + .ray(pos.0 + Vec3::unit_z(), tgt_pos.0 + Vec3::unit_z()) + .until(Block::is_opaque) + .cast() + .0 + .powf(2.0) + >= dist_sqrd + }, + }; if can_see_tgt { match tactic { @@ -613,6 +634,9 @@ impl<'a> System<'a> for Sys { *powerup += dt.0; } }, + Tactic::Maneater => { + inputs.primary.set_state(true); + }, _ => {}, } } @@ -650,6 +674,27 @@ impl<'a> System<'a> for Sys { .unwrap_or(Vec2::zero()) * speed; }, + Tactic::Maneater => { + if *powerup > 5.0 { + *powerup = 0.0; + } else if *powerup > 2.5 { + inputs.move_dir = bearing + .xy() + .rotated_z(-0.25 * PI) + .try_normalized() + .unwrap_or(Vec2::zero()) + * speed; + *powerup += dt.0; + } else { + inputs.move_dir = bearing + .xy() + .rotated_z(0.25 * PI) + .try_normalized() + .unwrap_or(Vec2::zero()) + * speed; + *powerup += dt.0; + } + }, _ => { inputs.move_dir = bearing .xy()