diff --git a/common/src/comp/character_state.rs b/common/src/comp/character_state.rs
index 8f6c95c028..c3801b7889 100644
--- a/common/src/comp/character_state.rs
+++ b/common/src/comp/character_state.rs
@@ -53,6 +53,15 @@ pub enum CharacterState {
 }
 
 impl CharacterState {
+    pub fn is_wielded(&self) -> bool {
+        match self {
+            CharacterState::Wielded(_) => true,
+            CharacterState::BasicAttack(_) => true,
+            CharacterState::BasicBlock(_) => true,
+            _ => false,
+        }
+    }
+
     pub fn is_attack(&self) -> bool {
         match self {
             CharacterState::BasicAttack(_) => true,
diff --git a/common/src/comp/energy.rs b/common/src/comp/energy.rs
index e53fbe5a48..0c74f20304 100644
--- a/common/src/comp/energy.rs
+++ b/common/src/comp/energy.rs
@@ -16,6 +16,7 @@ pub enum EnergySource {
     Regen,
     Revive,
     Climb,
+    Roll,
     Unknown,
 }
 
diff --git a/common/src/msg/ecs_packet.rs b/common/src/msg/ecs_packet.rs
index 57496dda0f..cd62d556e5 100644
--- a/common/src/msg/ecs_packet.rs
+++ b/common/src/msg/ecs_packet.rs
@@ -24,6 +24,7 @@ sum_type! {
         AbilityAction(comp::AbilityAction),
         AbilityPool(comp::AbilityPool),
         Attacking(comp::Attacking),
+        CharacterState(comp::CharacterState),
     }
 }
 // Automatically derive From<T> for EcsCompPhantom
@@ -47,6 +48,7 @@ sum_type! {
         AbilityAction(PhantomData<comp::AbilityAction>),
         AbilityPool(PhantomData<comp::AbilityPool>),
         Attacking(PhantomData<comp::Attacking>),
+        CharacterState(PhantomData<comp::CharacterState>),
     }
 }
 impl sync::CompPacket for EcsCompPacket {
@@ -70,6 +72,7 @@ impl sync::CompPacket for EcsCompPacket {
             EcsCompPacket::AbilityAction(comp) => sync::handle_insert(comp, entity, world),
             EcsCompPacket::AbilityPool(comp) => sync::handle_insert(comp, entity, world),
             EcsCompPacket::Attacking(comp) => sync::handle_insert(comp, entity, world),
+            EcsCompPacket::CharacterState(comp) => sync::handle_insert(comp, entity, world),
         }
     }
 
@@ -91,6 +94,7 @@ impl sync::CompPacket for EcsCompPacket {
             EcsCompPacket::AbilityAction(comp) => sync::handle_modify(comp, entity, world),
             EcsCompPacket::AbilityPool(comp) => sync::handle_modify(comp, entity, world),
             EcsCompPacket::Attacking(comp) => sync::handle_modify(comp, entity, world),
+            EcsCompPacket::CharacterState(comp) => sync::handle_modify(comp, entity, world),
         }
     }
 
@@ -118,6 +122,9 @@ impl sync::CompPacket for EcsCompPacket {
                 sync::handle_remove::<comp::AbilityPool>(entity, world)
             },
             EcsCompPhantom::Attacking(_) => sync::handle_remove::<comp::Attacking>(entity, world),
+            EcsCompPhantom::CharacterState(_) => {
+                sync::handle_remove::<comp::CharacterState>(entity, world)
+            },
         }
     }
 }
diff --git a/common/src/states/basic_attack.rs b/common/src/states/basic_attack.rs
index d633d988d8..f142bc7e13 100644
--- a/common/src/states/basic_attack.rs
+++ b/common/src/states/basic_attack.rs
@@ -1,6 +1,6 @@
 use crate::{
     comp::{Attacking, CharacterState, EcsStateData, ItemKind::Tool, StateUpdate, ToolData},
-    states::{utils, StateHandler},
+    states::StateHandler,
 };
 use std::{collections::VecDeque, time::Duration};
 
diff --git a/common/src/states/basic_block.rs b/common/src/states/basic_block.rs
index fb91ce76a0..18d7dd1ce2 100644
--- a/common/src/states/basic_block.rs
+++ b/common/src/states/basic_block.rs
@@ -1,6 +1,6 @@
 use super::utils::*;
 use crate::{
-    comp::{EcsStateData, StateUpdate},
+    comp::{CharacterState, EcsStateData, StateUpdate},
     states::StateHandler,
 };
 use std::{collections::VecDeque, time::Duration};
@@ -26,6 +26,12 @@ impl StateHandler for State {
             server_events: VecDeque::new(),
         };
 
+        handle_move_dir(&ecs_data, &mut update);
+
+        if !ecs_data.physics.on_ground || !ecs_data.inputs.secondary.is_pressed() {
+            update.character = CharacterState::Wielded(None);
+        }
+
         update
     }
 }
diff --git a/common/src/states/roll.rs b/common/src/states/roll.rs
index 14223b0e10..be3944ba13 100644
--- a/common/src/states/roll.rs
+++ b/common/src/states/roll.rs
@@ -50,6 +50,16 @@ impl StateHandler for State {
             .unwrap_or_default()
                 * ROLL_SPEED;
 
+        // Smooth orientation
+        if update.vel.0.magnitude_squared() > 0.0001
+            && (update.ori.0.normalized() - Vec3::from(update.vel.0).normalized())
+                .magnitude_squared()
+                > 0.001
+        {
+            update.ori.0 =
+                vek::ops::Slerp::slerp(update.ori.0, update.vel.0.into(), 9.0 * ecs_data.dt.0);
+        }
+
         if self.remaining_duration == Duration::default() {
             // Roll duration has expired
             update.character = CharacterState::Idle(None);
diff --git a/common/src/states/utils.rs b/common/src/states/utils.rs
index 5527365e20..d6b8d7338f 100644
--- a/common/src/states/utils.rs
+++ b/common/src/states/utils.rs
@@ -1,5 +1,5 @@
 use crate::{
-    comp::{Attacking, CharacterState, EcsStateData, ItemKind::Tool, StateUpdate},
+    comp::{Attacking, CharacterState, EcsStateData, EnergySource, ItemKind::Tool, StateUpdate},
     event::LocalEvent,
 };
 use std::time::Duration;
@@ -27,7 +27,10 @@ pub fn handle_move_dir(ecs_data: &EcsStateData, update: &mut StateUpdate) {
     }
 
     // Set direction based on move direction
-    let ori_dir = if update.character.is_attack() || update.character.is_block() {
+    let ori_dir = if update.character.is_wielded()
+        || update.character.is_attack()
+        || update.character.is_block()
+    {
         Vec2::from(ecs_data.inputs.look_dir).normalized()
     } else {
         Vec2::from(update.vel.0)
@@ -58,7 +61,7 @@ pub fn handle_sit(ecs_data: &EcsStateData, update: &mut StateUpdate) {
 }
 
 pub fn handle_climb(ecs_data: &EcsStateData, update: &mut StateUpdate) {
-    if (ecs_data.inputs.climb.is_just_pressed() || ecs_data.inputs.climb_down.is_pressed())
+    if (ecs_data.inputs.climb.is_pressed() || ecs_data.inputs.climb_down.is_pressed())
         && ecs_data.physics.on_wall.is_some()
         && !ecs_data.physics.on_ground
         //&& update.vel.0.z < 0.0
@@ -121,6 +124,10 @@ pub fn handle_dodge(ecs_data: &EcsStateData, update: &mut StateUpdate) {
             if ecs_data.inputs.roll.is_pressed()
                 && ecs_data.physics.on_ground
                 && ecs_data.body.is_humanoid()
+                && update
+                    .energy
+                    .try_change_by(-200, EnergySource::Roll)
+                    .is_ok()
             {
                 update.character = state;
             }
diff --git a/common/src/sys/stats.rs b/common/src/sys/stats.rs
index 19e8182c09..548b636bda 100644
--- a/common/src/sys/stats.rs
+++ b/common/src/sys/stats.rs
@@ -5,7 +5,7 @@ use crate::{
 };
 use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage};
 
-const ENERGY_REGEN_ACCEL: f32 = 20.0;
+const ENERGY_REGEN_ACCEL: f32 = 10.0;
 
 /// This system kills players, levels them up, and regenerates energy.
 pub struct Sys;
@@ -87,15 +87,17 @@ impl<'a> System<'a> for Sys {
                                 as i32,
                             EnergySource::Regen,
                         );
-                        energy.regen_rate += ENERGY_REGEN_ACCEL * dt.0;
+                        energy.regen_rate =
+                            (energy.regen_rate + ENERGY_REGEN_ACCEL * dt.0).min(100.0);
                     }
                 },
                 // All other states do not regen and set the rate back to zero.
-                _ => {
+                CharacterState::Wielded(_) => {
                     if energy.get_unchecked().regen_rate != 0.0 {
                         energy.get_mut_unchecked().regen_rate = 0.0
                     }
                 },
+                _ => {},
             }
         }
     }
diff --git a/server/src/sys/sentinel.rs b/server/src/sys/sentinel.rs
index 9363dcfc59..f48f8a9f59 100644
--- a/server/src/sys/sentinel.rs
+++ b/server/src/sys/sentinel.rs
@@ -1,8 +1,8 @@
 use super::SysTimer;
 use common::{
     comp::{
-        AbilityPool, Body, CanBuild, Energy, Gravity, Item, LightEmitter, Mass, MountState,
-        Mounting, Player, Scale, Stats, Sticky,
+        AbilityPool, Body, CanBuild, CharacterState, Energy, Gravity, Item, LightEmitter, Mass,
+        MountState, Mounting, Player, Scale, Stats, Sticky,
     },
     msg::EcsCompPacket,
     sync::{EntityPackage, SyncPackage, Uid, UpdateTracker, WorldSyncExt},
@@ -52,6 +52,7 @@ pub struct TrackedComps<'a> {
     pub sticky: ReadStorage<'a, Sticky>,
     pub gravity: ReadStorage<'a, Gravity>,
     pub ability_pool: ReadStorage<'a, AbilityPool>,
+    pub character_state: ReadStorage<'a, CharacterState>,
 }
 impl<'a> TrackedComps<'a> {
     pub fn create_entity_package(&self, entity: EcsEntity) -> EntityPackage<EcsCompPacket> {
@@ -109,6 +110,10 @@ impl<'a> TrackedComps<'a> {
             .get(entity)
             .copied()
             .map(|c| comps.push(c.into()));
+        self.character_state
+            .get(entity)
+            .copied()
+            .map(|c| comps.push(c.into()));
 
         EntityPackage { uid, comps }
     }
@@ -130,6 +135,7 @@ pub struct ReadTrackers<'a> {
     pub sticky: ReadExpect<'a, UpdateTracker<Sticky>>,
     pub gravity: ReadExpect<'a, UpdateTracker<Gravity>>,
     pub ability_pool: ReadExpect<'a, UpdateTracker<AbilityPool>>,
+    pub character_state: ReadExpect<'a, UpdateTracker<CharacterState>>,
 }
 impl<'a> ReadTrackers<'a> {
     pub fn create_sync_package(
@@ -158,6 +164,12 @@ impl<'a> ReadTrackers<'a> {
             .with_component(&comps.uid, &*self.sticky, &comps.sticky, filter)
             .with_component(&comps.uid, &*self.gravity, &comps.gravity, filter)
             .with_component(&comps.uid, &*self.ability_pool, &comps.ability_pool, filter)
+            .with_component(
+                &comps.uid,
+                &*self.character_state,
+                &comps.character_state,
+                filter,
+            )
     }
 }
 
@@ -178,6 +190,7 @@ pub struct WriteTrackers<'a> {
     sticky: WriteExpect<'a, UpdateTracker<Sticky>>,
     gravity: WriteExpect<'a, UpdateTracker<Gravity>>,
     ability_pool: WriteExpect<'a, UpdateTracker<AbilityPool>>,
+    character_state: WriteExpect<'a, UpdateTracker<CharacterState>>,
 }
 
 fn record_changes(comps: &TrackedComps, trackers: &mut WriteTrackers) {
@@ -197,6 +210,9 @@ fn record_changes(comps: &TrackedComps, trackers: &mut WriteTrackers) {
     trackers.sticky.record_changes(&comps.sticky);
     trackers.gravity.record_changes(&comps.gravity);
     trackers.ability_pool.record_changes(&comps.ability_pool);
+    trackers
+        .character_state
+        .record_changes(&comps.character_state);
 }
 
 pub fn register_trackers(world: &mut World) {
@@ -215,6 +231,7 @@ pub fn register_trackers(world: &mut World) {
     world.register_tracker::<Sticky>();
     world.register_tracker::<Gravity>();
     world.register_tracker::<AbilityPool>();
+    world.register_tracker::<CharacterState>();
 }
 
 /// Deleted entities grouped by region
diff --git a/voxygen/src/audio/sfx/event_mapper/movement.rs b/voxygen/src/audio/sfx/event_mapper/movement.rs
index 559e036aa4..00e80b6815 100644
--- a/voxygen/src/audio/sfx/event_mapper/movement.rs
+++ b/voxygen/src/audio/sfx/event_mapper/movement.rs
@@ -124,28 +124,23 @@ impl MovementEventMapper {
         }
     }
 
-    /// Voxygen has an existing list of character states via `MoveState::*` and
-    /// `ActionState::*` however that list does not provide enough
-    /// resolution to target specific entity events, such as opening or
-    /// closing the glider. These methods translate those entity states with
-    /// some additional data into more specific `SfxEvent`'s which we attach
-    /// sounds to
+    /// Voxygen has an existing list of character states however that list does
+    /// not provide enough resolution to target specific entity events, such
+    /// as opening or closing the glider. These methods translate those
+    /// entity states with some additional data into more specific
+    /// `SfxEvent`'s which we attach sounds to
     fn map_movement_event(current_event: &CharacterState, previous_event: SfxEvent) -> SfxEvent {
-        match (current_event, previous_event) {
-            (CharacterState::Roll(_), _) => SfxEvent::Roll,
-            (CharacterState::Climb(_), _) => SfxEvent::Climb,
-            (CharacterState::Idle(_), _) => SfxEvent::Run,
-            (CharacterState::Idle(_), SfxEvent::Glide) => SfxEvent::GliderClose,
-            (CharacterState::Idle(_), SfxEvent::Fall) => SfxEvent::Run,
-            (CharacterState::Idle(_), SfxEvent::Jump) => SfxEvent::Idle,
-            (CharacterState::Glide(_), previous_event) => {
+        match (previous_event, current_event) {
+            (_, CharacterState::Roll(_)) => SfxEvent::Roll,
+            (_, CharacterState::Climb(_)) => SfxEvent::Climb,
+            (SfxEvent::Glide, CharacterState::Idle(_)) => SfxEvent::GliderClose,
+            (previous_event, CharacterState::Glide(_)) => {
                 if previous_event != SfxEvent::GliderOpen && previous_event != SfxEvent::Glide {
                     SfxEvent::GliderOpen
                 } else {
                     SfxEvent::Glide
                 }
             },
-            (CharacterState::Idle(_), SfxEvent::Glide) => SfxEvent::GliderClose,
             _ => SfxEvent::Idle,
         }
     }