diff --git a/assets/common/abilities/axe/doublestrike.ron b/assets/common/abilities/axe/doublestrike.ron
new file mode 100644
index 0000000000..7151798fd1
--- /dev/null
+++ b/assets/common/abilities/axe/doublestrike.ron
@@ -0,0 +1,36 @@
+ComboMelee(
+    stage_data: [
+        (
+            stage: 1,
+            base_damage: 90,
+            max_damage: 110,
+            damage_increase: 10,
+            knockback: 8.0,
+            range: 3.5,
+            angle: 50.0,
+            base_buildup_duration: 350,
+            base_swing_duration: 75,
+            base_recover_duration: 400,
+            forward_movement: 0.5,
+        ),
+        (
+            stage: 2,
+            base_damage: 130,
+            max_damage: 160,
+            damage_increase: 15,
+            knockback: 12.0,
+            range: 3.5,
+            angle: 30.0,
+            base_buildup_duration: 500,
+            base_swing_duration: 100,
+            base_recover_duration: 500,
+            forward_movement: 0.25,
+        ),
+    ],
+    initial_energy_gain: 0,
+    max_energy_gain: 100,
+    energy_increase: 20,
+    speed_increase: 0.05,
+    max_speed_increase: 1.6,
+    is_interruptible: false,
+)
\ No newline at end of file
diff --git a/assets/common/abilities/axe/leap.ron b/assets/common/abilities/axe/leap.ron
index dc0c2fb266..1b6cd34c6d 100644
--- a/assets/common/abilities/axe/leap.ron
+++ b/assets/common/abilities/axe/leap.ron
@@ -10,4 +10,4 @@ LeapMelee(
     max_angle: 30.0,
     forward_leap_strength: 28.0,
     vertical_leap_strength: 8.0,
-),
\ No newline at end of file
+)
\ No newline at end of file
diff --git a/assets/common/abilities/axe/spin.ron b/assets/common/abilities/axe/spin.ron
index 1ec1f743fb..8a31ce4361 100644
--- a/assets/common/abilities/axe/spin.ron
+++ b/assets/common/abilities/axe/spin.ron
@@ -11,4 +11,4 @@ SpinMelee(
     is_interruptible: false,
     forward_speed: 0.0,
     num_spins: 1,
-),
\ No newline at end of file
+)
\ No newline at end of file
diff --git a/assets/common/abilities/axe/tempbasic.ron b/assets/common/abilities/axe/tempbasic.ron
deleted file mode 100644
index 001e96f0f6..0000000000
--- a/assets/common/abilities/axe/tempbasic.ron
+++ /dev/null
@@ -1,10 +0,0 @@
-BasicMelee(
-    energy_cost: 0,
-    buildup_duration: 600,
-    swing_duration: 100,
-    recover_duration: 300,
-    base_damage: 120,
-    knockback: 0.0,
-    range: 3.5,
-    max_angle: 20.0,
-),
\ No newline at end of file
diff --git a/assets/common/abilities/bow/basic.ron b/assets/common/abilities/bow/basic.ron
index d2de738791..4747e5a087 100644
--- a/assets/common/abilities/bow/basic.ron
+++ b/assets/common/abilities/bow/basic.ron
@@ -1,7 +1,7 @@
 BasicRanged(
     energy_cost: 0,
-    buildup_duration: 100,
-    recover_duration: 400,
+    buildup_duration: 200,
+    recover_duration: 300,
     projectile: Arrow(
         damage: 40.0,
         knockback: 10.0,
@@ -11,4 +11,5 @@ BasicRanged(
     projectile_light: None,
     projectile_gravity: Some(Gravity(0.2)),
     projectile_speed: 100.0,
-),
\ No newline at end of file
+    can_continue: true,
+)
\ No newline at end of file
diff --git a/assets/common/abilities/bow/charged.ron b/assets/common/abilities/bow/charged.ron
index 1f3ebd47c1..8de9cf9fbc 100644
--- a/assets/common/abilities/bow/charged.ron
+++ b/assets/common/abilities/bow/charged.ron
@@ -5,6 +5,7 @@ ChargedRanged(
     max_damage: 200,
     initial_knockback: 10.0,
     max_knockback: 20.0,
+    speed: 1.0,
     buildup_duration: 100,
     charge_duration: 1500,
     recover_duration: 500,
@@ -13,4 +14,4 @@ ChargedRanged(
     projectile_gravity: Some(Gravity(0.2)),
     initial_projectile_speed: 100.0,
     max_projectile_speed: 500.0,
-),
\ No newline at end of file
+)
\ No newline at end of file
diff --git a/assets/common/abilities/bow/repeater.ron b/assets/common/abilities/bow/repeater.ron
index 520e3811d0..619c326200 100644
--- a/assets/common/abilities/bow/repeater.ron
+++ b/assets/common/abilities/bow/repeater.ron
@@ -15,4 +15,4 @@ RepeaterRanged(
     projectile_gravity: Some(Gravity(0.2)),
     projectile_speed: 100.0,
     reps_remaining: 5,
-),
\ No newline at end of file
+)
\ No newline at end of file
diff --git a/assets/common/abilities/debug/forwardboost.ron b/assets/common/abilities/debug/forwardboost.ron
index eebed9703c..81aefd978e 100644
--- a/assets/common/abilities/debug/forwardboost.ron
+++ b/assets/common/abilities/debug/forwardboost.ron
@@ -1,4 +1,4 @@
-CharacterAbility::Boost(
+Boost(
     movement_duration: 50,
     only_up: false,
-),
\ No newline at end of file
+)
\ No newline at end of file
diff --git a/assets/common/abilities/debug/possess.ron b/assets/common/abilities/debug/possess.ron
index 7a620b87e8..99563c1e78 100644
--- a/assets/common/abilities/debug/possess.ron
+++ b/assets/common/abilities/debug/possess.ron
@@ -2,13 +2,7 @@ BasicRanged(
     energy_cost: 0,
     buildup_duration: 0,
     recover_duration: 10,
-    projectile: (
-        hit_solid: [Stick],
-        hit_entity: [Stick, Possess],
-        time_left: 10, // secs
-        owner: None,
-        ignore_group: false,
-    ),
+    projectile: Possess,
     projectile_body: Object(ArrowSnake),
     /*projectile_light: Some(LightEmitter {
         col: (0.0, 1.0, 0.33).into(),
@@ -16,4 +10,5 @@ BasicRanged(
     }),*/
     projectile_gravity: None,
     projectile_speed: 100.0,
-),
\ No newline at end of file
+    can_continue: false,
+)
\ No newline at end of file
diff --git a/assets/common/abilities/debug/upboost.ron b/assets/common/abilities/debug/upboost.ron
index 6b293a83b8..d0456d54ba 100644
--- a/assets/common/abilities/debug/upboost.ron
+++ b/assets/common/abilities/debug/upboost.ron
@@ -1,4 +1,4 @@
-CharacterAbility::Boost(
+Boost(
     movement_duration: 50,
     only_up: true,
-),
\ No newline at end of file
+)
\ No newline at end of file
diff --git a/assets/common/abilities/farming/basic.ron b/assets/common/abilities/farming/basic.ron
index 3b7aa36fca..0a60b62df7 100644
--- a/assets/common/abilities/farming/basic.ron
+++ b/assets/common/abilities/farming/basic.ron
@@ -1,5 +1,5 @@
 BasicMelee(
-    energy_cost: 1,
+    energy_cost: 0,
     buildup_duration: 600,
     swing_duration: 100,
     recover_duration: 150,
diff --git a/assets/common/abilities/hammer/charged.ron b/assets/common/abilities/hammer/charged.ron
index 4998616bd1..5b69a8d716 100644
--- a/assets/common/abilities/hammer/charged.ron
+++ b/assets/common/abilities/hammer/charged.ron
@@ -1,5 +1,5 @@
 ChargedMelee(
-    energy_cost: 1,
+    energy_cost: 0,
     energy_drain: 300,
     initial_damage: 10,
     max_damage: 170,
@@ -7,7 +7,8 @@ ChargedMelee(
     max_knockback: 60.0,
     range: 3.5,
     max_angle: 30.0,
+    speed: 1.0,
     charge_duration: 1200,
     swing_duration: 200,
     recover_duration: 300,
-),
\ No newline at end of file
+)
\ No newline at end of file
diff --git a/assets/common/abilities/hammer/leap.ron b/assets/common/abilities/hammer/leap.ron
index f83731582f..70ec3019bf 100644
--- a/assets/common/abilities/hammer/leap.ron
+++ b/assets/common/abilities/hammer/leap.ron
@@ -10,4 +10,4 @@ LeapMelee(
     max_angle: 360.0,
     forward_leap_strength: 28.0,
     vertical_leap_strength: 8.0,
-),
\ No newline at end of file
+)
\ No newline at end of file
diff --git a/assets/common/abilities/hammer/singlestrike.ron b/assets/common/abilities/hammer/singlestrike.ron
new file mode 100644
index 0000000000..57fc0ffa8a
--- /dev/null
+++ b/assets/common/abilities/hammer/singlestrike.ron
@@ -0,0 +1,21 @@
+ComboMelee(
+    stage_data: [(
+        stage: 1,
+        base_damage: 120,
+        max_damage: 150,
+        damage_increase: 10,
+        knockback: 0.0,
+        range: 3.5,
+        angle: 20.0,
+        base_buildup_duration: 600,
+        base_swing_duration: 60,
+        base_recover_duration: 300,
+        forward_movement: 0.0,
+    )],
+    initial_energy_gain: 0,
+    max_energy_gain: 100,
+    energy_increase: 20,
+    speed_increase: 0.05,
+    max_speed_increase: 1.4,
+    is_interruptible: false,
+)
\ No newline at end of file
diff --git a/assets/common/abilities/hammer/tempbasic.ron b/assets/common/abilities/hammer/tempbasic.ron
deleted file mode 100644
index 001e96f0f6..0000000000
--- a/assets/common/abilities/hammer/tempbasic.ron
+++ /dev/null
@@ -1,10 +0,0 @@
-BasicMelee(
-    energy_cost: 0,
-    buildup_duration: 600,
-    swing_duration: 100,
-    recover_duration: 300,
-    base_damage: 120,
-    knockback: 0.0,
-    range: 3.5,
-    max_angle: 20.0,
-),
\ No newline at end of file
diff --git a/assets/common/abilities/sceptre/healingbeam.ron b/assets/common/abilities/sceptre/healingbeam.ron
index 91b7c19d1a..88fc4f02eb 100644
--- a/assets/common/abilities/sceptre/healingbeam.ron
+++ b/assets/common/abilities/sceptre/healingbeam.ron
@@ -11,4 +11,4 @@ BasicBeam(
     energy_regen: 50,
     energy_cost: 100,
     energy_drain: 0,
-),
\ No newline at end of file
+)
\ No newline at end of file
diff --git a/assets/common/abilities/sceptre/healingbomb.ron b/assets/common/abilities/sceptre/healingbomb.ron
index 2a0204ba08..427cd42424 100644
--- a/assets/common/abilities/sceptre/healingbomb.ron
+++ b/assets/common/abilities/sceptre/healingbomb.ron
@@ -14,4 +14,5 @@ BasicRanged(
     }),*/
     projectile_gravity: Some(Gravity(0.5)),
     projectile_speed: 40.0,
-),
\ No newline at end of file
+    can_continue: false,
+)
\ No newline at end of file
diff --git a/assets/common/abilities/shield/block.ron b/assets/common/abilities/shield/block.ron
new file mode 100644
index 0000000000..ca0309ede7
--- /dev/null
+++ b/assets/common/abilities/shield/block.ron
@@ -0,0 +1 @@
+BasicBlock
\ No newline at end of file
diff --git a/assets/common/abilities/shield/tempbasic.ron b/assets/common/abilities/shield/tempbasic.ron
index d0023f388c..eca1996eb1 100644
--- a/assets/common/abilities/shield/tempbasic.ron
+++ b/assets/common/abilities/shield/tempbasic.ron
@@ -7,4 +7,4 @@ BasicMelee(
     knockback: 0.0,
     range: 3.0,
     max_angle: 120.0,
-),
\ No newline at end of file
+)
\ No newline at end of file
diff --git a/assets/common/abilities/staff/firebomb.ron b/assets/common/abilities/staff/firebomb.ron
index f2c75d5cf7..05a18db3d3 100644
--- a/assets/common/abilities/staff/firebomb.ron
+++ b/assets/common/abilities/staff/firebomb.ron
@@ -5,7 +5,7 @@ BasicRanged(
     projectile: Fireball(
         damage: 100.0,
         radius: 5.0,
-        energy_regen: 0,
+        energy_regen: 50,
     ),
     projectile_body: Object(BoltFire),
     /*projectile_light: Some(LightEmitter {
@@ -14,4 +14,5 @@ BasicRanged(
     }),*/
     projectile_gravity: Some(Gravity(0.3)),
     projectile_speed: 60.0,
-),
\ No newline at end of file
+    can_continue: true,
+)
\ No newline at end of file
diff --git a/assets/common/abilities/staff/fireshockwave.ron b/assets/common/abilities/staff/fireshockwave.ron
index f5eed9d021..fabf1b00b5 100644
--- a/assets/common/abilities/staff/fireshockwave.ron
+++ b/assets/common/abilities/staff/fireshockwave.ron
@@ -11,4 +11,4 @@ Shockwave(
     shockwave_duration: 500,
     requires_ground: false,
     move_efficiency: 0.1,
-),
\ No newline at end of file
+)
\ No newline at end of file
diff --git a/assets/common/abilities/staff/flamethrower.ron b/assets/common/abilities/staff/flamethrower.ron
index acc4a510f9..1fccd24fe3 100644
--- a/assets/common/abilities/staff/flamethrower.ron
+++ b/assets/common/abilities/staff/flamethrower.ron
@@ -11,4 +11,4 @@ BasicBeam(
     energy_regen: 0,
     energy_cost: 0,
     energy_drain: 350,
-),
\ No newline at end of file
+)
\ No newline at end of file
diff --git a/assets/common/abilities/sword/dash.ron b/assets/common/abilities/sword/dash.ron
index 2935ff810b..2f08b14737 100644
--- a/assets/common/abilities/sword/dash.ron
+++ b/assets/common/abilities/sword/dash.ron
@@ -14,4 +14,4 @@ DashMelee(
     recover_duration: 500,
     infinite_charge: true,
     is_interruptible: true,
-),
\ No newline at end of file
+)
\ No newline at end of file
diff --git a/assets/common/abilities/sword/spin.ron b/assets/common/abilities/sword/spin.ron
index 1ae86a7853..94b55b93bc 100644
--- a/assets/common/abilities/sword/spin.ron
+++ b/assets/common/abilities/sword/spin.ron
@@ -11,4 +11,4 @@ SpinMelee(
     is_interruptible: true,
     forward_speed: 1.0,
     num_spins: 3,
-),
\ No newline at end of file
+)
\ No newline at end of file
diff --git a/assets/common/abilities/sword/triplestrike.ron b/assets/common/abilities/sword/triplestrike.ron
index b699b78544..ffdd3097b8 100644
--- a/assets/common/abilities/sword/triplestrike.ron
+++ b/assets/common/abilities/sword/triplestrike.ron
@@ -1,4 +1,4 @@
-ComboMelee (
+ComboMelee(
     stage_data: [
         (
             stage: 1,
@@ -23,7 +23,7 @@ ComboMelee (
             angle: 180.0,
             base_buildup_duration: 400,
             base_swing_duration: 600,
-            base_recover_duration: 400
+            base_recover_duration: 400,
             forward_movement: 0.0,
         ),
         (
@@ -46,4 +46,4 @@ ComboMelee (
     speed_increase: 0.05,
     max_speed_increase: 1.8,
     is_interruptible: true,
-),
\ No newline at end of file
+)
\ No newline at end of file
diff --git a/assets/common/abilities/unique/stonegolemfist/basic.ron b/assets/common/abilities/unique/stonegolemfist/basic.ron
index 53f8993be6..2ce4d66744 100644
--- a/assets/common/abilities/unique/stonegolemfist/basic.ron
+++ b/assets/common/abilities/unique/stonegolemfist/basic.ron
@@ -7,4 +7,4 @@ BasicMelee(
     base_damage: 200,
     range: 5.0,
     max_angle: 120.0,
-),
\ No newline at end of file
+)
\ No newline at end of file
diff --git a/assets/common/abilities/unique/stonegolemfist/shockwave.ron b/assets/common/abilities/unique/stonegolemfist/shockwave.ron
index ecac0f22c1..ac29382ee5 100644
--- a/assets/common/abilities/unique/stonegolemfist/shockwave.ron
+++ b/assets/common/abilities/unique/stonegolemfist/shockwave.ron
@@ -11,4 +11,4 @@ Shockwave(
     shockwave_duration: 2000,
     requires_ground: true,
     move_efficiency: 0.05,
-),
\ No newline at end of file
+)
\ No newline at end of file
diff --git a/assets/common/abilities/weapon_ability_manifest.ron b/assets/common/abilities/weapon_ability_manifest.ron
index c8383f77d8..6694484688 100644
--- a/assets/common/abilities/weapon_ability_manifest.ron
+++ b/assets/common/abilities/weapon_ability_manifest.ron
@@ -9,14 +9,14 @@
         ],
     ),
     Axe: (
-        primary: "common.abilities.axe.tempbasic",
+        primary: "common.abilities.axe.doublestrike",
         secondary: "common.abilities.axe.spin",
         skills: [
             "common.abilities.axe.leap",
         ],
     ),
     Hammer: (
-        primary: "common.abilities.hammer.tempbasic",
+        primary: "common.abilities.hammer.singlestrike",
         secondary: "common.abilities.hammer.charged",
         skills: [
             "common.abilities.hammer.leap",
@@ -48,7 +48,7 @@
     ),
     Shield: (
         primary: "common.abilities.shield.tempbasic",
-        secondary: "common.abilities.shield.tempbasic",
+        secondary: "common.abilities.shield.block",
         skills: [],
     ),
     Unique(StoneGolemFist): (
diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs
index 621b80407f..46ca1a9fe4 100644
--- a/common/src/comp/ability.rs
+++ b/common/src/comp/ability.rs
@@ -1,4 +1,5 @@
 use crate::{
+    assets::{self, Asset},
     comp::{
         item::{armor::Protection, Item, ItemKind},
         projectile::ProjectileConstructor,
@@ -15,7 +16,7 @@ use arraygen::Arraygen;
 use serde::{Deserialize, Serialize};
 use specs::{Component, FlaggedStorage};
 use specs_idvs::IdvStorage;
-use std::time::Duration;
+use std::{fs::File, io::BufReader, time::Duration};
 use vek::Vec3;
 
 #[derive(Copy, Clone, Hash, Eq, PartialEq, Debug, Serialize, Deserialize)]
@@ -60,9 +61,9 @@ impl From<&CharacterState> for CharacterAbilityType {
 pub enum CharacterAbility {
     BasicMelee {
         energy_cost: u32,
-        buildup_duration: Duration,
-        swing_duration: Duration,
-        recover_duration: Duration,
+        buildup_duration: u64,
+        swing_duration: u64,
+        recover_duration: u64,
         base_damage: u32,
         knockback: f32,
         range: f32,
@@ -70,8 +71,8 @@ pub enum CharacterAbility {
     },
     BasicRanged {
         energy_cost: u32,
-        buildup_duration: Duration,
-        recover_duration: Duration,
+        buildup_duration: u64,
+        recover_duration: u64,
         projectile: ProjectileConstructor,
         projectile_body: Body,
         projectile_light: Option<LightEmitter>,
@@ -81,10 +82,10 @@ pub enum CharacterAbility {
     },
     RepeaterRanged {
         energy_cost: u32,
-        movement_duration: Duration,
-        buildup_duration: Duration,
-        shoot_duration: Duration,
-        recover_duration: Duration,
+        movement_duration: u64,
+        buildup_duration: u64,
+        shoot_duration: u64,
+        recover_duration: u64,
         leap: Option<f32>,
         projectile: ProjectileConstructor,
         projectile_body: Body,
@@ -94,7 +95,7 @@ pub enum CharacterAbility {
         reps_remaining: u32,
     },
     Boost {
-        movement_duration: Duration,
+        movement_duration: u64,
         only_up: bool,
     },
     DashMelee {
@@ -107,23 +108,23 @@ pub enum CharacterAbility {
         angle: f32,
         energy_drain: u32,
         forward_speed: f32,
-        buildup_duration: Duration,
-        charge_duration: Duration,
-        swing_duration: Duration,
-        recover_duration: Duration,
+        buildup_duration: u64,
+        charge_duration: u64,
+        swing_duration: u64,
+        recover_duration: u64,
         infinite_charge: bool,
         is_interruptible: bool,
     },
     BasicBlock,
     Roll {
         energy_cost: u32,
-        buildup_duration: Duration,
-        movement_duration: Duration,
-        recover_duration: Duration,
+        buildup_duration: u64,
+        movement_duration: u64,
+        recover_duration: u64,
         roll_strength: f32,
     },
     ComboMelee {
-        stage_data: Vec<combo_melee::Stage>,
+        stage_data: Vec<combo_melee::Stage<u64>>,
         initial_energy_gain: u32,
         max_energy_gain: u32,
         energy_increase: u32,
@@ -133,10 +134,10 @@ pub enum CharacterAbility {
     },
     LeapMelee {
         energy_cost: u32,
-        buildup_duration: Duration,
-        movement_duration: Duration,
-        swing_duration: Duration,
-        recover_duration: Duration,
+        buildup_duration: u64,
+        movement_duration: u64,
+        swing_duration: u64,
+        recover_duration: u64,
         base_damage: u32,
         range: f32,
         max_angle: f32,
@@ -145,9 +146,9 @@ pub enum CharacterAbility {
         vertical_leap_strength: f32,
     },
     SpinMelee {
-        buildup_duration: Duration,
-        swing_duration: Duration,
-        recover_duration: Duration,
+        buildup_duration: u64,
+        swing_duration: u64,
+        recover_duration: u64,
         base_damage: u32,
         knockback: f32,
         range: f32,
@@ -168,9 +169,9 @@ pub enum CharacterAbility {
         range: f32,
         max_angle: f32,
         speed: f32,
-        charge_duration: Duration,
-        swing_duration: Duration,
-        recover_duration: Duration,
+        charge_duration: u64,
+        swing_duration: u64,
+        recover_duration: u64,
     },
     ChargedRanged {
         energy_cost: u32,
@@ -180,9 +181,9 @@ pub enum CharacterAbility {
         initial_knockback: f32,
         max_knockback: f32,
         speed: f32,
-        buildup_duration: Duration,
-        charge_duration: Duration,
-        recover_duration: Duration,
+        buildup_duration: u64,
+        charge_duration: u64,
+        recover_duration: u64,
         projectile_body: Body,
         projectile_light: Option<LightEmitter>,
         projectile_gravity: Option<Gravity>,
@@ -191,22 +192,22 @@ pub enum CharacterAbility {
     },
     Shockwave {
         energy_cost: u32,
-        buildup_duration: Duration,
-        swing_duration: Duration,
-        recover_duration: Duration,
+        buildup_duration: u64,
+        swing_duration: u64,
+        recover_duration: u64,
         damage: u32,
         knockback: Knockback,
         shockwave_angle: f32,
         shockwave_vertical_angle: f32,
         shockwave_speed: f32,
-        shockwave_duration: Duration,
+        shockwave_duration: u64,
         requires_ground: bool,
         move_efficiency: f32,
     },
     BasicBeam {
-        buildup_duration: Duration,
-        recover_duration: Duration,
-        beam_duration: Duration,
+        buildup_duration: u64,
+        recover_duration: u64,
+        beam_duration: u64,
         base_hps: u32,
         base_dps: u32,
         tick_rate: f32,
@@ -219,6 +220,29 @@ pub enum CharacterAbility {
     },
 }
 
+impl Default for CharacterAbility {
+    fn default() -> Self {
+        CharacterAbility::BasicMelee {
+            energy_cost: 0,
+            buildup_duration: 250,
+            swing_duration: 250,
+            recover_duration: 500,
+            base_damage: 10,
+            knockback: 0.0,
+            range: 3.5,
+            max_angle: 15.0,
+        }
+    }
+}
+
+impl Asset for CharacterAbility {
+    const ENDINGS: &'static [&'static str] = &["ron"];
+
+    fn parse(buf_reader: BufReader<File>, _specifier: &str) -> Result<Self, assets::Error> {
+        ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error)
+    }
+}
+
 impl CharacterAbility {
     /// Attempts to fulfill requirements, mutating `update` (taking energy) if
     /// applicable.
@@ -283,9 +307,9 @@ impl CharacterAbility {
     fn default_roll() -> CharacterAbility {
         CharacterAbility::Roll {
             energy_cost: 100,
-            buildup_duration: Duration::from_millis(100),
-            movement_duration: Duration::from_millis(250),
-            recover_duration: Duration::from_millis(150),
+            buildup_duration: 100,
+            movement_duration: 250,
+            recover_duration: 150,
             roll_strength: 2.5,
         }
     }
@@ -304,14 +328,13 @@ pub struct ItemConfig {
 impl From<Item> for ItemConfig {
     fn from(item: Item) -> Self {
         if let ItemKind::Tool(tool) = &item.kind() {
-            let mut abilities = tool.get_abilities();
-            let mut ability_drain = abilities.drain(..);
+            let abilities = tool.get_abilities().clone();
 
             return ItemConfig {
                 item,
-                ability1: ability_drain.next(),
-                ability2: ability_drain.next(),
-                ability3: ability_drain.next(),
+                ability1: Some(abilities.primary),
+                ability2: Some(abilities.secondary),
+                ability3: abilities.skills.get(0).map(|x| x.clone()),
                 block_ability: None,
                 dodge_ability: Some(CharacterAbility::default_roll()),
             };
@@ -393,9 +416,9 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
                 energy_cost: _,
             } => CharacterState::BasicMelee(basic_melee::Data {
                 static_data: basic_melee::StaticData {
-                    buildup_duration: *buildup_duration,
-                    swing_duration: *swing_duration,
-                    recover_duration: *recover_duration,
+                    buildup_duration: Duration::from_millis(*buildup_duration),
+                    swing_duration: Duration::from_millis(*swing_duration),
+                    recover_duration: Duration::from_millis(*recover_duration),
                     base_damage: *base_damage,
                     knockback: *knockback,
                     range: *range,
@@ -417,8 +440,8 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
                 energy_cost: _,
             } => CharacterState::BasicRanged(basic_ranged::Data {
                 static_data: basic_ranged::StaticData {
-                    buildup_duration: *buildup_duration,
-                    recover_duration: *recover_duration,
+                    buildup_duration: Duration::from_millis(*buildup_duration),
+                    recover_duration: Duration::from_millis(*recover_duration),
                     projectile: *projectile,
                     projectile_body: *projectile_body,
                     projectile_light: *projectile_light,
@@ -437,7 +460,7 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
                 only_up,
             } => CharacterState::Boost(boost::Data {
                 static_data: boost::StaticData {
-                    movement_duration: *movement_duration,
+                    movement_duration: Duration::from_millis(*movement_duration),
                     only_up: *only_up,
                 },
                 timer: Duration::default(),
@@ -469,10 +492,10 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
                     energy_drain: *energy_drain,
                     forward_speed: *forward_speed,
                     infinite_charge: *infinite_charge,
-                    buildup_duration: *buildup_duration,
-                    charge_duration: *charge_duration,
-                    swing_duration: *swing_duration,
-                    recover_duration: *recover_duration,
+                    buildup_duration: Duration::from_millis(*buildup_duration),
+                    charge_duration: Duration::from_millis(*charge_duration),
+                    swing_duration: Duration::from_millis(*swing_duration),
+                    recover_duration: Duration::from_millis(*recover_duration),
                     is_interruptible: *is_interruptible,
                     ability_key: key,
                 },
@@ -491,9 +514,9 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
                 roll_strength,
             } => CharacterState::Roll(roll::Data {
                 static_data: roll::StaticData {
-                    buildup_duration: *buildup_duration,
-                    movement_duration: *movement_duration,
-                    recover_duration: *recover_duration,
+                    buildup_duration: Duration::from_millis(*buildup_duration),
+                    movement_duration: Duration::from_millis(*movement_duration),
+                    recover_duration: Duration::from_millis(*recover_duration),
                     roll_strength: *roll_strength,
                 },
                 timer: Duration::default(),
@@ -512,7 +535,11 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
             } => CharacterState::ComboMelee(combo_melee::Data {
                 static_data: combo_melee::StaticData {
                     num_stages: stage_data.len() as u32,
-                    stage_data: stage_data.clone(),
+                    stage_data: stage_data
+                        .clone()
+                        .into_iter()
+                        .map(|stage| stage.to_duration())
+                        .collect(),
                     initial_energy_gain: *initial_energy_gain,
                     max_energy_gain: *max_energy_gain,
                     energy_increase: *energy_increase,
@@ -541,10 +568,10 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
                 vertical_leap_strength,
             } => CharacterState::LeapMelee(leap_melee::Data {
                 static_data: leap_melee::StaticData {
-                    buildup_duration: *buildup_duration,
-                    movement_duration: *movement_duration,
-                    swing_duration: *swing_duration,
-                    recover_duration: *recover_duration,
+                    buildup_duration: Duration::from_millis(*buildup_duration),
+                    movement_duration: Duration::from_millis(*movement_duration),
+                    swing_duration: Duration::from_millis(*swing_duration),
+                    recover_duration: Duration::from_millis(*recover_duration),
                     base_damage: *base_damage,
                     knockback: *knockback,
                     range: *range,
@@ -571,9 +598,9 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
                 num_spins,
             } => CharacterState::SpinMelee(spin_melee::Data {
                 static_data: spin_melee::StaticData {
-                    buildup_duration: *buildup_duration,
-                    swing_duration: *swing_duration,
-                    recover_duration: *recover_duration,
+                    buildup_duration: Duration::from_millis(*buildup_duration),
+                    swing_duration: Duration::from_millis(*swing_duration),
+                    recover_duration: Duration::from_millis(*recover_duration),
                     base_damage: *base_damage,
                     knockback: *knockback,
                     range: *range,
@@ -614,9 +641,9 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
                     speed: *speed,
                     range: *range,
                     max_angle: *max_angle,
-                    charge_duration: *charge_duration,
-                    swing_duration: *swing_duration,
-                    recover_duration: *recover_duration,
+                    charge_duration: Duration::from_millis(*charge_duration),
+                    swing_duration: Duration::from_millis(*swing_duration),
+                    recover_duration: Duration::from_millis(*recover_duration),
                     ability_key: key,
                 },
                 stage_section: StageSection::Charge,
@@ -642,9 +669,9 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
                 max_projectile_speed,
             } => CharacterState::ChargedRanged(charged_ranged::Data {
                 static_data: charged_ranged::StaticData {
-                    buildup_duration: *buildup_duration,
-                    charge_duration: *charge_duration,
-                    recover_duration: *recover_duration,
+                    buildup_duration: Duration::from_millis(*buildup_duration),
+                    charge_duration: Duration::from_millis(*charge_duration),
+                    recover_duration: Duration::from_millis(*recover_duration),
                     energy_drain: *energy_drain,
                     initial_damage: *initial_damage,
                     max_damage: *max_damage,
@@ -677,10 +704,10 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
                 reps_remaining,
             } => CharacterState::RepeaterRanged(repeater_ranged::Data {
                 static_data: repeater_ranged::StaticData {
-                    movement_duration: *movement_duration,
-                    buildup_duration: *buildup_duration,
-                    shoot_duration: *shoot_duration,
-                    recover_duration: *recover_duration,
+                    movement_duration: Duration::from_millis(*movement_duration),
+                    buildup_duration: Duration::from_millis(*buildup_duration),
+                    shoot_duration: Duration::from_millis(*shoot_duration),
+                    recover_duration: Duration::from_millis(*recover_duration),
                     leap: *leap,
                     projectile: *projectile,
                     projectile_body: *projectile_body,
@@ -707,15 +734,15 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
                 move_efficiency,
             } => CharacterState::Shockwave(shockwave::Data {
                 static_data: shockwave::StaticData {
-                    buildup_duration: *buildup_duration,
-                    swing_duration: *swing_duration,
-                    recover_duration: *recover_duration,
+                    buildup_duration: Duration::from_millis(*buildup_duration),
+                    swing_duration: Duration::from_millis(*swing_duration),
+                    recover_duration: Duration::from_millis(*recover_duration),
                     damage: *damage,
                     knockback: *knockback,
                     shockwave_angle: *shockwave_angle,
                     shockwave_vertical_angle: *shockwave_vertical_angle,
                     shockwave_speed: *shockwave_speed,
-                    shockwave_duration: *shockwave_duration,
+                    shockwave_duration: Duration::from_millis(*shockwave_duration),
                     requires_ground: *requires_ground,
                     move_efficiency: *move_efficiency,
                 },
@@ -737,9 +764,9 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
                 energy_drain,
             } => CharacterState::BasicBeam(basic_beam::Data {
                 static_data: basic_beam::StaticData {
-                    buildup_duration: *buildup_duration,
-                    recover_duration: *recover_duration,
-                    beam_duration: *beam_duration,
+                    buildup_duration: Duration::from_millis(*buildup_duration),
+                    recover_duration: Duration::from_millis(*recover_duration),
+                    beam_duration: Duration::from_millis(*beam_duration),
                     base_hps: *base_hps,
                     base_dps: *base_dps,
                     tick_rate: *tick_rate,
diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs
index 584001b427..351802fbe9 100644
--- a/common/src/comp/inventory/item/tool.rs
+++ b/common/src/comp/inventory/item/tool.rs
@@ -2,6 +2,7 @@
 // version in voxygen\src\meta.rs in order to reset save files to being empty
 
 use crate::{
+    assets::{self, Asset},
     comp::{
         body::object, projectile::ProjectileConstructor, Body, CharacterAbility, Gravity,
         LightEmitter,
@@ -10,7 +11,8 @@ use crate::{
     Knockback,
 };
 use serde::{Deserialize, Serialize};
-use std::time::Duration;
+use std::{collections::HashMap, fs::File, io::BufReader, time::Duration};
+use tracing::error;
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub enum ToolKind {
@@ -93,8 +95,20 @@ impl Tool {
         Duration::from_millis(millis).div_f32(self.base_speed())
     }
 
-    // TODO: Before merging ron file branch, ensure these are double checked against ron files.
-    pub fn get_abilities(&self) -> Vec<CharacterAbility> {
+    pub fn get_abilities(&self) -> AbilitySet<CharacterAbility> {
+        let base_abilities = match AbilityMap::load("common.abilities.weapon_ability_manifest") {
+            Ok(map) => map.0.get(&self.kind).map(|a| a.clone()).unwrap_or_default(),
+            Err(err) => {
+                error!(?err, "Error unwrapping");
+                AbilitySet::default()
+            },
+        };
+        base_abilities
+    }
+
+    // TODO: Before merging ron file branch, ensure these are double checked against
+    // ron files.
+    /*pub fn get_abilities(&self) -> Vec<CharacterAbility> {
         use CharacterAbility::*;
         use ToolKind::*;
 
@@ -534,6 +548,69 @@ impl Tool {
                 max_angle: 15.0,
             }],
         }
+    }*/
+}
+
+#[derive(Clone, Debug, Serialize, Deserialize)]
+pub struct AbilitySet<T> {
+    pub primary: T,
+    pub secondary: T,
+    pub skills: Vec<T>,
+}
+
+impl<T: Clone> AbilitySet<T> {
+    pub fn map<U, F: FnMut(T) -> U>(self, mut f: F) -> AbilitySet<U> {
+        AbilitySet {
+            primary: f(self.primary),
+            secondary: f(self.secondary),
+            skills: self.skills.iter().map(|x| f(x.clone())).collect(),
+        }
+    }
+}
+
+impl Default for AbilitySet<CharacterAbility> {
+    fn default() -> Self {
+        AbilitySet {
+            primary: CharacterAbility::default(),
+            secondary: CharacterAbility::default(),
+            skills: vec![],
+        }
+    }
+}
+
+#[derive(Clone, Debug, Serialize, Deserialize)]
+pub struct AbilityMap<T = CharacterAbility>(HashMap<ToolKind, AbilitySet<T>>);
+impl Asset for AbilityMap {
+    const ENDINGS: &'static [&'static str] = &["ron"];
+
+    fn parse(buf_reader: BufReader<File>, specifier: &str) -> Result<Self, assets::Error> {
+        ron::de::from_reader::<BufReader<File>, AbilityMap<String>>(buf_reader)
+            .map(|map| {
+                AbilityMap(
+                    map.0
+                        .into_iter()
+                        .map(|(kind, set)| {
+                            (
+                                kind,
+                                set.map(|s| match CharacterAbility::load(&s) {
+                                    Ok(ability) => ability.as_ref().clone(),
+                                    Err(err) => {
+                                        error!(
+                                            ?err,
+                                            "Error loading CharacterAbility: {} for the ability \
+                                             map: {} replacing with default",
+                                            s,
+                                            specifier
+                                        );
+                                        CharacterAbility::default()
+                                    },
+                                }),
+                            )
+                        })
+                        .collect(),
+                )
+            })
+            .map_err(assets::Error::parse_error)
     }
 }
 
diff --git a/common/src/loadout_builder.rs b/common/src/loadout_builder.rs
index c816a0dc09..2811771d2e 100644
--- a/common/src/loadout_builder.rs
+++ b/common/src/loadout_builder.rs
@@ -152,9 +152,9 @@ impl LoadoutBuilder {
                 item: Item::new_from_asset_expect("common.items.weapons.empty.empty"),
                 ability1: Some(CharacterAbility::BasicMelee {
                     energy_cost: 0,
-                    buildup_duration: Duration::from_millis(0),
-                    swing_duration: Duration::from_millis(100),
-                    recover_duration: Duration::from_millis(300),
+                    buildup_duration: 0,
+                    swing_duration: 100,
+                    recover_duration: 300,
                     base_damage: 40,
                     knockback: 0.0,
                     range: 3.5,
@@ -334,9 +334,9 @@ impl LoadoutBuilder {
                 item: Item::new_from_asset_expect("common.items.weapons.empty.empty"),
                 ability1: Some(CharacterAbility::BasicMelee {
                     energy_cost: 10,
-                    buildup_duration: Duration::from_millis(500),
-                    swing_duration: Duration::from_millis(100),
-                    recover_duration: Duration::from_millis(100),
+                    buildup_duration: 500,
+                    swing_duration: 100,
+                    recover_duration: 100,
                     base_damage: body.base_dmg(),
                     knockback: 0.0,
                     range: body.base_range(),
diff --git a/common/src/states/combo_melee.rs b/common/src/states/combo_melee.rs
index ad3a3aae84..b4cfde8b80 100644
--- a/common/src/states/combo_melee.rs
+++ b/common/src/states/combo_melee.rs
@@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
 use std::time::Duration;
 
 #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
-pub struct Stage {
+pub struct Stage<T> {
     /// Specifies which stage the combo attack is in
     pub stage: u32,
     /// Initial damage of stage
@@ -24,23 +24,41 @@ pub struct Stage {
     /// Angle of attack
     pub angle: f32,
     /// Initial buildup duration of stage (how long until state can deal damage)
-    pub base_buildup_duration: Duration,
+    pub base_buildup_duration: T,
     /// Duration of stage spent in swing (controls animation stuff, and can also
     /// be used to handle movement separately to buildup)
-    pub base_swing_duration: Duration,
+    pub base_swing_duration: T,
     /// Initial recover duration of stage (how long until character exits state)
-    pub base_recover_duration: Duration,
+    pub base_recover_duration: T,
     /// How much forward movement there is in the swing portion of the stage
     pub forward_movement: f32,
 }
 
+impl Stage<u64> {
+    pub fn to_duration(self) -> Stage<Duration> {
+        Stage::<Duration> {
+            stage: self.stage,
+            base_damage: self.base_damage,
+            max_damage: self.max_damage,
+            damage_increase: self.damage_increase,
+            knockback: self.knockback,
+            range: self.range,
+            angle: self.angle,
+            base_buildup_duration: Duration::from_millis(self.base_buildup_duration),
+            base_swing_duration: Duration::from_millis(self.base_swing_duration),
+            base_recover_duration: Duration::from_millis(self.base_recover_duration),
+            forward_movement: self.forward_movement,
+        }
+    }
+}
+
 #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
 /// Separated out to condense update portions of character state
 pub struct StaticData {
     /// Indicates number of stages in combo
     pub num_stages: u32,
     /// Data for each stage
-    pub stage_data: Vec<Stage>,
+    pub stage_data: Vec<Stage<Duration>>,
     /// Initial energy gain per strike
     pub initial_energy_gain: u32,
     /// Max energy gain per strike