From af780acc8426dce1ab2edcbe0fe8f6837e67e4b8 Mon Sep 17 00:00:00 2001
From: timokoesters <timo@koesters.xyz>
Date: Tue, 27 Aug 2019 21:56:46 +0200
Subject: [PATCH 01/16] Use comp::Stats to store Equipment, make char weapon
 selection work

---
 client/src/lib.rs                        |  9 +++-
 common/src/comp/inventory/item.rs        |  6 +--
 common/src/comp/mod.rs                   |  2 +-
 common/src/comp/stats.rs                 | 17 ++++--
 common/src/msg/client.rs                 |  1 +
 server/src/cmd.rs                        |  2 +-
 server/src/lib.rs                        | 26 ++++++---
 voxygen/src/menu/char_selection/mod.rs   | 12 +++++
 voxygen/src/menu/char_selection/scene.rs | 18 +++++--
 voxygen/src/menu/char_selection/ui.rs    | 30 +++++------
 voxygen/src/scene/figure.rs              | 69 +++++++++++++++++-------
 11 files changed, 138 insertions(+), 54 deletions(-)

diff --git a/client/src/lib.rs b/client/src/lib.rs
index 5f4ca2798d..f76c930012 100644
--- a/client/src/lib.rs
+++ b/client/src/lib.rs
@@ -149,9 +149,14 @@ impl Client {
     }
 
     /// Request a state transition to `ClientState::Character`.
-    pub fn request_character(&mut self, name: String, body: comp::Body) {
+    pub fn request_character(
+        &mut self,
+        name: String,
+        body: comp::Body,
+        main: Option<comp::item::Tool>,
+    ) {
         self.postbox
-            .send_message(ClientMsg::Character { name, body });
+            .send_message(ClientMsg::Character { name, body, main });
         self.client_state = ClientState::Pending;
     }
 
diff --git a/common/src/comp/inventory/item.rs b/common/src/comp/inventory/item.rs
index 7ad0a229fc..909e9e087f 100644
--- a/common/src/comp/inventory/item.rs
+++ b/common/src/comp/inventory/item.rs
@@ -1,7 +1,7 @@
 use specs::{Component, FlaggedStorage};
 use specs_idvs::IDVStorage;
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub enum Tool {
     Daggers,
     SwordShield,
@@ -36,7 +36,7 @@ pub const ALL_TOOLS: [Tool; 7] = [
     Tool::Staff,
 ];
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub enum Armor {
     // TODO: Don't make armor be a body part. Wearing enemy's head is funny but also creepy thing to do.
     Helmet,
@@ -76,7 +76,7 @@ pub enum ConsumptionEffect {
     Xp(i32),
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub enum Item {
     Tool {
         kind: Tool,
diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs
index 22b9d4c52e..18bb53be8b 100644
--- a/common/src/comp/mod.rs
+++ b/common/src/comp/mod.rs
@@ -24,5 +24,5 @@ pub use inventory::{item, Inventory, InventoryUpdate, Item};
 pub use last::Last;
 pub use phys::{ForceUpdate, Ori, PhysicsState, Pos, Scale, Vel};
 pub use player::Player;
-pub use stats::{Exp, HealthSource, Level, Stats};
+pub use stats::{Equipment, Exp, HealthSource, Level, Stats};
 pub use visual::LightEmitter;
diff --git a/common/src/comp/stats.rs b/common/src/comp/stats.rs
index f147247cbd..e1e77f0549 100644
--- a/common/src/comp/stats.rs
+++ b/common/src/comp/stats.rs
@@ -1,4 +1,4 @@
-use crate::state::Uid;
+use crate::{comp, state::Uid};
 use specs::{Component, FlaggedStorage};
 use specs_idvs::IDVStorage;
 
@@ -44,6 +44,13 @@ pub struct Level {
     amount: u32,
 }
 
+#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
+pub struct Equipment {
+    pub main: Option<comp::Item>,
+    pub alt: Option<comp::Item>,
+    // TODO: Armor
+}
+
 impl Health {
     pub fn current(&self) -> u32 {
         self.current
@@ -145,12 +152,12 @@ pub struct Stats {
     pub energy: Energy,
     pub level: Level,
     pub exp: Exp,
+    pub equipment: Equipment,
     pub is_dead: bool,
 }
 
 impl Stats {
     pub fn should_die(&self) -> bool {
-        // TODO: Remove
         self.health.current == 0
     }
     pub fn revive(&mut self) {
@@ -161,7 +168,7 @@ impl Stats {
 }
 
 impl Stats {
-    pub fn new(name: String) -> Self {
+    pub fn new(name: String, main: Option<comp::Item>) -> Self {
         Self {
             name,
             health: Health {
@@ -179,6 +186,10 @@ impl Stats {
                 maximum: 200,
                 last_change: None,
             },
+            equipment: Equipment {
+                main: main,
+                alt: None,
+            },
             is_dead: false,
         }
     }
diff --git a/common/src/msg/client.rs b/common/src/msg/client.rs
index f5c7bf9f7b..c9b429b4dd 100644
--- a/common/src/msg/client.rs
+++ b/common/src/msg/client.rs
@@ -12,6 +12,7 @@ pub enum ClientMsg {
     Character {
         name: String,
         body: comp::Body,
+        main: Option<comp::item::Tool>,
     },
     Controller(comp::Controller),
     RequestState(ClientState),
diff --git a/server/src/cmd.rs b/server/src/cmd.rs
index f920f1d0f6..4c4e662505 100644
--- a/server/src/cmd.rs
+++ b/server/src/cmd.rs
@@ -411,7 +411,7 @@ fn handle_spawn(server: &mut Server, entity: EcsEntity, args: String, action: &C
 
                             let body = kind_to_body(id);
                             server
-                                .create_npc(pos, comp::Stats::new(get_npc_name(id)), body)
+                                .create_npc(pos, comp::Stats::new(get_npc_name(id), None), body)
                                 .with(comp::Vel(vel))
                                 .with(agent)
                                 .build();
diff --git a/server/src/lib.rs b/server/src/lib.rs
index 606b143923..27813c781c 100644
--- a/server/src/lib.rs
+++ b/server/src/lib.rs
@@ -200,12 +200,13 @@ impl Server {
         client: &mut Client,
         name: String,
         body: comp::Body,
+        main: Option<comp::Item>,
         server_settings: &ServerSettings,
     ) {
         let spawn_point = state.ecs().read_resource::<SpawnPoint>().0;
 
         state.write_component(entity, body);
-        state.write_component(entity, comp::Stats::new(name));
+        state.write_component(entity, comp::Stats::new(name, main));
         state.write_component(entity, comp::Controller::default());
         state.write_component(entity, comp::Pos(spawn_point));
         state.write_component(entity, comp::Vel(Vec3::zero()));
@@ -433,11 +434,17 @@ impl Server {
             // Handle chunk supplement
             for npc in supplement.npcs {
                 let (mut stats, mut body) = if rand::random() {
-                    let stats = comp::Stats::new("Humanoid".to_string());
+                    let stats = comp::Stats::new(
+                        "Humanoid".to_string(),
+                        Some(comp::Item::Tool {
+                            kind: comp::item::Tool::Sword,
+                            power: 10,
+                        }),
+                    );
                     let body = comp::Body::Humanoid(comp::humanoid::Body::random());
                     (stats, body)
                 } else {
-                    let stats = comp::Stats::new("Wolf".to_string());
+                    let stats = comp::Stats::new("Wolf".to_string(), None);
                     let body = comp::Body::QuadrupedMedium(comp::quadruped_medium::Body::random());
                     (stats, body)
                 };
@@ -445,7 +452,13 @@ impl Server {
 
                 if npc.boss {
                     if rand::random::<f32>() < 0.8 {
-                        stats = comp::Stats::new("Humanoid".to_string());
+                        stats = comp::Stats::new(
+                            "Humanoid".to_string(),
+                            Some(comp::Item::Tool {
+                                kind: comp::item::Tool::Sword,
+                                power: 10,
+                            }),
+                        );
                         body = comp::Body::Humanoid(comp::humanoid::Body::random());
                     }
                     stats = stats.with_max_health(500 + rand::random::<u32>() % 400);
@@ -740,7 +753,7 @@ impl Server {
                                 item_entity.and_then(|item_entity| {
                                     ecs.write_storage::<comp::Item>()
                                         .get_mut(item_entity)
-                                        .map(|item| (*item, item_entity))
+                                        .map(|item| (item.clone(), item_entity))
                                 }),
                                 ecs.write_storage::<comp::Inventory>().get_mut(entity),
                             ) {
@@ -759,7 +772,7 @@ impl Server {
 
                             state.write_component(entity, comp::InventoryUpdate);
                         }
-                        ClientMsg::Character { name, body } => match client.client_state {
+                        ClientMsg::Character { name, body, main } => match client.client_state {
                             // Become Registered first.
                             ClientState::Connected => {
                                 client.error_state(RequestStateError::Impossible)
@@ -773,6 +786,7 @@ impl Server {
                                     client,
                                     name,
                                     body,
+                                    main.map(|t| comp::Item::Tool { kind: t, power: 10 }),
                                     &server_settings,
                                 );
                                 if let Some(player) =
diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs
index c4137b9144..967798c17f 100644
--- a/voxygen/src/menu/char_selection/mod.rs
+++ b/voxygen/src/menu/char_selection/mod.rs
@@ -65,6 +65,7 @@ impl PlayState for CharSelectionState {
                         self.client.borrow_mut().request_character(
                             self.char_selection_ui.character_name.clone(),
                             comp::Body::Humanoid(self.char_selection_ui.character_body),
+                            self.char_selection_ui.character_tool,
                         );
                         return PlayStateResult::Push(Box::new(SessionState::new(
                             global_state,
@@ -89,6 +90,17 @@ impl PlayState for CharSelectionState {
                 global_state.window.renderer_mut(),
                 &self.client.borrow(),
                 self.char_selection_ui.character_body,
+                &comp::Equipment {
+                    main: if let Some(kind) = self.char_selection_ui.character_tool {
+                        Some(comp::Item::Tool {
+                            kind: kind,
+                            power: 10,
+                        })
+                    } else {
+                        None
+                    },
+                    alt: None,
+                },
             );
 
             // Draw the UI to the screen.
diff --git a/voxygen/src/menu/char_selection/scene.rs b/voxygen/src/menu/char_selection/scene.rs
index d01df92018..aae6ca4b20 100644
--- a/voxygen/src/menu/char_selection/scene.rs
+++ b/voxygen/src/menu/char_selection/scene.rs
@@ -15,7 +15,7 @@ use crate::{
 };
 use client::Client;
 use common::{
-    comp::{humanoid, Body},
+    comp::{humanoid, Body, Equipment},
     state::DeltaTime,
     terrain::BlockKind,
 };
@@ -132,12 +132,24 @@ impl Scene {
         );
     }
 
-    pub fn render(&mut self, renderer: &mut Renderer, client: &Client, body: humanoid::Body) {
+    pub fn render(
+        &mut self,
+        renderer: &mut Renderer,
+        client: &Client,
+        body: humanoid::Body,
+        equipment: &Equipment,
+    ) {
         renderer.render_skybox(&self.skybox.model, &self.globals, &self.skybox.locals);
 
         let model = &self
             .figure_model_cache
-            .get_or_create_model(renderer, Body::Humanoid(body), client.get_tick())
+            .get_or_create_model(
+                renderer,
+                &client.entity(),
+                Body::Humanoid(body),
+                Some(equipment),
+                client.get_tick(),
+            )
             .0;
 
         renderer.render_figure(
diff --git a/voxygen/src/menu/char_selection/ui.rs b/voxygen/src/menu/char_selection/ui.rs
index ed1b42d0b3..3a7264f18a 100644
--- a/voxygen/src/menu/char_selection/ui.rs
+++ b/voxygen/src/menu/char_selection/ui.rs
@@ -209,7 +209,7 @@ pub struct CharSelectionUi {
     character_creation: bool,
     pub character_name: String,
     pub character_body: humanoid::Body,
-    pub character_weapon: Tool, // TODO: Move into ecs inventory struct?
+    pub character_tool: Option<Tool>,
 }
 
 impl CharSelectionUi {
@@ -235,7 +235,7 @@ impl CharSelectionUi {
             character_creation: false,
             character_name: "Character Name".to_string(),
             character_body: humanoid::Body::random(),
-            character_weapon: Tool::Sword,
+            character_tool: Some(Tool::Sword),
         }
     }
 
@@ -344,7 +344,7 @@ impl CharSelectionUi {
                 .was_clicked()
             {
                 self.character_creation = true;
-                self.character_weapon = Tool::Sword;
+                self.character_tool = Some(Tool::Sword);
             }
 
             // Alpha Version
@@ -710,7 +710,7 @@ impl CharSelectionUi {
                 .w_h(70.0, 70.0)
                 .bottom_left_with_margins_on(self.ids.creation_buttons_alignment_2, 0.0, 0.0)
                 .set(self.ids.hammer, ui_widgets);
-            if Button::image(if let Tool::Hammer = self.character_weapon {
+            if Button::image(if let Some(Tool::Hammer) = self.character_tool {
                 self.imgs.icon_border_pressed
             } else {
                 self.imgs.icon_border
@@ -721,7 +721,7 @@ impl CharSelectionUi {
             .set(self.ids.hammer_button, ui_widgets)
             .was_clicked()
             {
-                self.character_weapon = Tool::Hammer;
+                self.character_tool = Some(Tool::Hammer);
             }
             // REMOVE THIS AFTER IMPLEMENTATION
             /*Rectangle::fill_with([67.0, 67.0], color::rgba(0.0, 0.0, 0.0, 0.8))
@@ -734,7 +734,7 @@ impl CharSelectionUi {
                 .w_h(70.0, 70.0)
                 .right_from(self.ids.hammer, 2.0)
                 .set(self.ids.bow, ui_widgets);
-            if Button::image(if let Tool::Bow = self.character_weapon {
+            if Button::image(if let Some(Tool::Bow) = self.character_tool {
                 self.imgs.icon_border_pressed
             } else {
                 self.imgs.icon_border
@@ -745,7 +745,7 @@ impl CharSelectionUi {
             .set(self.ids.bow_button, ui_widgets)
             .was_clicked()
             {
-                //self.character_weapon = Tool::Bow;
+                //self.character_tool = Some(Tool::Bow);
             }
             // REMOVE THIS AFTER IMPLEMENTATION
             Rectangle::fill_with([67.0, 67.0], color::rgba(0.0, 0.0, 0.0, 0.8))
@@ -756,7 +756,7 @@ impl CharSelectionUi {
                 .w_h(70.0, 70.0)
                 .right_from(self.ids.bow, 2.0)
                 .set(self.ids.staff, ui_widgets);
-            if Button::image(if let Tool::Staff = self.character_weapon {
+            if Button::image(if let Some(Tool::Staff) = self.character_tool {
                 self.imgs.icon_border_pressed
             } else {
                 self.imgs.icon_border
@@ -767,7 +767,7 @@ impl CharSelectionUi {
             .set(self.ids.staff_button, ui_widgets)
             .was_clicked()
             {
-                //self.character_weapon = Tool::Staff;
+                //self.character_tool = Some(Tool::Staff);
             }
             // REMOVE THIS AFTER IMPLEMENTATION
             Rectangle::fill_with([67.0, 67.0], color::rgba(0.0, 0.0, 0.0, 0.8))
@@ -778,7 +778,7 @@ impl CharSelectionUi {
                 .w_h(70.0, 70.0)
                 .up_from(self.ids.hammer, 2.0)
                 .set(self.ids.sword, ui_widgets);
-            if Button::image(if let Tool::Sword = self.character_weapon {
+            if Button::image(if let Some(Tool::Sword) = self.character_tool {
                 self.imgs.icon_border_pressed
             } else {
                 self.imgs.icon_border
@@ -789,7 +789,7 @@ impl CharSelectionUi {
             .set(self.ids.sword_button, ui_widgets)
             .was_clicked()
             {
-                self.character_weapon = Tool::Sword;
+                self.character_tool = Some(Tool::Sword);
             }
 
             // Daggers
@@ -797,7 +797,7 @@ impl CharSelectionUi {
                 .w_h(70.0, 70.0)
                 .right_from(self.ids.sword, 2.0)
                 .set(self.ids.daggers, ui_widgets);
-            if Button::image(if let Tool::Daggers = self.character_weapon {
+            if Button::image(if let Some(Tool::Daggers) = self.character_tool {
                 self.imgs.icon_border_pressed
             } else {
                 self.imgs.icon_border
@@ -808,7 +808,7 @@ impl CharSelectionUi {
             .set(self.ids.daggers_button, ui_widgets)
             .was_clicked()
             {
-                // self.character_weapon = Tool::Daggers;
+                // self.character_tool = Some(Tool::Daggers);
             } // REMOVE THIS AFTER IMPLEMENTATION
             Rectangle::fill_with([67.0, 67.0], color::rgba(0.0, 0.0, 0.0, 0.8))
                 .middle_of(self.ids.daggers)
@@ -819,7 +819,7 @@ impl CharSelectionUi {
                 .w_h(70.0, 70.0)
                 .right_from(self.ids.daggers, 2.0)
                 .set(self.ids.axe, ui_widgets);
-            if Button::image(if let Tool::Axe = self.character_weapon {
+            if Button::image(if let Some(Tool::Axe) = self.character_tool {
                 self.imgs.icon_border_pressed
             } else {
                 self.imgs.icon_border
@@ -830,7 +830,7 @@ impl CharSelectionUi {
             .set(self.ids.axe_button, ui_widgets)
             .was_clicked()
             {
-                self.character_weapon = Tool::Axe;
+                self.character_tool = Some(Tool::Axe);
             }
             // REMOVE THIS AFTER IMPLEMENTATION
             /*Rectangle::fill_with([67.0, 67.0], color::rgba(0.0, 0.0, 0.0, 0.8))
diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs
index ece30c60ec..d6b0e1e143 100644
--- a/voxygen/src/scene/figure.rs
+++ b/voxygen/src/scene/figure.rs
@@ -12,7 +12,9 @@ use crate::{
 use client::Client;
 use common::{
     assets,
-    comp::{self, humanoid, item::Tool, object, quadruped, quadruped_medium, Body},
+    comp::{
+        self, humanoid, item::Tool, object, quadruped, quadruped_medium, Body, Equipment, Item,
+    },
     figure::Segment,
     terrain::TerrainChunkSize,
     vol::VolSize,
@@ -26,8 +28,14 @@ use vek::*;
 
 const DAMAGE_FADE_COEFFICIENT: f64 = 5.0;
 
+#[derive(PartialEq, Eq, Hash, Clone)]
+enum FigureKey {
+    Simple(Body),
+    Complex(Body, Option<Equipment>),
+}
+
 pub struct FigureModelCache {
-    models: HashMap<Body, ((Model<FigurePipeline>, SkeletonAttr), u64)>,
+    models: HashMap<FigureKey, ((Model<FigurePipeline>, SkeletonAttr), u64)>,
 }
 
 impl FigureModelCache {
@@ -40,16 +48,24 @@ impl FigureModelCache {
     pub fn get_or_create_model(
         &mut self,
         renderer: &mut Renderer,
+        entity: &EcsEntity,
         body: Body,
+        equipment: Option<&Equipment>,
         tick: u64,
     ) -> &(Model<FigurePipeline>, SkeletonAttr) {
-        match self.models.get_mut(&body) {
+        let key = if equipment.is_some() {
+            FigureKey::Complex(body, equipment.cloned())
+        } else {
+            FigureKey::Simple(body)
+        };
+
+        match self.models.get_mut(&key) {
             Some((_model, last_used)) => {
                 *last_used = tick;
             }
             None => {
                 self.models.insert(
-                    body,
+                    key.clone(),
                     (
                         {
                             let bone_meshes = match body {
@@ -62,7 +78,7 @@ impl FigureModelCache {
                                     Some(Self::load_right_hand(body.hand)),
                                     Some(Self::load_left_foot(body.foot)),
                                     Some(Self::load_right_foot(body.foot)),
-                                    Some(Self::load_weapon(Tool::Hammer)), // TODO: Inventory
+                                    Some(Self::load_main(equipment.and_then(|e| e.main.as_ref()))),
                                     Some(Self::load_left_shoulder(body.shoulder)),
                                     Some(Self::load_right_shoulder(body.shoulder)),
                                     Some(Self::load_draw()),
@@ -151,7 +167,7 @@ impl FigureModelCache {
             }
         }
 
-        &self.models[&body].0
+        &self.models[&key].0
     }
 
     pub fn clean(&mut self, tick: u64) {
@@ -293,17 +309,24 @@ impl FigureModelCache {
         )
     }
 
-    fn load_weapon(weapon: Tool) -> Mesh<FigurePipeline> {
-        let (name, offset) = match weapon {
-            Tool::Sword => ("weapon.sword.rusty_2h", Vec3::new(-1.5, -6.5, -4.0)),
-            Tool::Axe => ("weapon.axe.rusty_2h", Vec3::new(-1.5, -6.5, -4.0)),
-            Tool::Hammer => ("weapon.hammer.rusty_2h", Vec3::new(-2.5, -5.5, -4.0)),
-            Tool::Daggers => ("weapon.hammer.rusty_2h", Vec3::new(-2.5, -5.5, -4.0)),
-            Tool::SwordShield => ("weapon.axe.rusty_2h", Vec3::new(-2.5, -6.5, -2.0)),
-            Tool::Bow => ("weapon.hammer.rusty_2h", Vec3::new(-2.5, -5.5, -4.0)),
-            Tool::Staff => ("weapon.axe.rusty_2h", Vec3::new(-2.5, -6.5, -2.0)),
-        };
-        Self::load_mesh(name, offset)
+    fn load_main(item: Option<&Item>) -> Mesh<FigurePipeline> {
+        if let Some(item) = item {
+            let (name, offset) = match item {
+                Item::Tool { kind, .. } => match kind {
+                    Tool::Sword => ("weapon.sword.rusty_2h", Vec3::new(-1.5, -6.5, -4.0)),
+                    Tool::Axe => ("weapon.axe.rusty_2h", Vec3::new(-1.5, -6.5, -4.0)),
+                    Tool::Hammer => ("weapon.hammer.rusty_2h", Vec3::new(-2.5, -5.5, -4.0)),
+                    Tool::Daggers => ("weapon.hammer.rusty_2h", Vec3::new(-2.5, -5.5, -4.0)),
+                    Tool::SwordShield => ("weapon.axe.rusty_2h", Vec3::new(-2.5, -6.5, -2.0)),
+                    Tool::Bow => ("weapon.hammer.rusty_2h", Vec3::new(-2.5, -5.5, -4.0)),
+                    Tool::Staff => ("weapon.axe.rusty_2h", Vec3::new(-2.5, -6.5, -2.0)),
+                },
+                _ => ("figure.empty", Vec3::default()),
+            };
+            Self::load_mesh(name, offset)
+        } else {
+            Self::load_mesh("figure.empty", Vec3::default())
+        }
     }
 
     fn load_left_shoulder(shoulder: humanoid::Shoulder) -> Mesh<FigurePipeline> {
@@ -651,7 +674,7 @@ impl FigureMgr {
 
             let skeleton_attr = &self
                 .model_cache
-                .get_or_create_model(renderer, *body, tick)
+                .get_or_create_model(renderer, &entity, *body, stats.map(|s| &s.equipment), tick)
                 .1;
 
             match body {
@@ -862,7 +885,7 @@ impl FigureMgr {
 
         let frustum = camera.frustum(client);
 
-        for (entity, _, _, _, body, _, _) in (
+        for (entity, _, _, _, body, stats, _) in (
             &ecs.entities(),
             &ecs.read_storage::<comp::Pos>(),
             &ecs.read_storage::<comp::Vel>(),
@@ -904,7 +927,13 @@ impl FigureMgr {
             } {
                 let model = &self
                     .model_cache
-                    .get_or_create_model(renderer, *body, tick)
+                    .get_or_create_model(
+                        renderer,
+                        &entity,
+                        *body,
+                        stats.map(|s| &s.equipment),
+                        tick,
+                    )
                     .0;
 
                 // Don't render the player's body while in first person mode

From e4ca33de5b5603a5b7cd82bc75f865132d71ec45 Mon Sep 17 00:00:00 2001
From: timokoesters <timo@koesters.xyz>
Date: Wed, 28 Aug 2019 22:47:52 +0200
Subject: [PATCH 02/16] Add debug mode item giving speed boost in look_dir on
 click

---
 assets/voxygen/voxel/weapon/debug_wand.vox | Bin 0 -> 29771 bytes
 client/src/lib.rs                          |   5 ++
 common/src/comp/controller.rs              |   4 +-
 common/src/comp/inventory/item.rs          |   8 +++
 common/src/comp/inventory/mod.rs           |  35 +++++++----
 common/src/event.rs                        |   1 +
 common/src/msg/client.rs                   |   1 +
 common/src/state.rs                        |   9 +++
 common/src/sys/agent.rs                    |   4 +-
 common/src/sys/controller.rs               |  67 ++++++++++++---------
 server/src/lib.rs                          |  33 +++++++++-
 voxygen/src/hud/bag.rs                     |   2 +-
 voxygen/src/hud/mod.rs                     |   1 +
 voxygen/src/scene/figure.rs                |   1 +
 voxygen/src/session.rs                     |   7 ++-
 15 files changed, 130 insertions(+), 48 deletions(-)
 create mode 100644 assets/voxygen/voxel/weapon/debug_wand.vox

diff --git a/assets/voxygen/voxel/weapon/debug_wand.vox b/assets/voxygen/voxel/weapon/debug_wand.vox
new file mode 100644
index 0000000000000000000000000000000000000000..dea1e8f8831b9b768719aa3731e1e1f3533073c0
GIT binary patch
literal 29771
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

literal 0
HcmV?d00001

diff --git a/client/src/lib.rs b/client/src/lib.rs
index f76c930012..d1b6389d97 100644
--- a/client/src/lib.rs
+++ b/client/src/lib.rs
@@ -181,6 +181,11 @@ impl Client {
         // Can't fail
     }
 
+    pub fn activate_inventory_slot(&mut self, x: usize) {
+        self.postbox
+            .send_message(ClientMsg::ActivateInventorySlot(x))
+    }
+
     pub fn swap_inventory_slots(&mut self, a: usize, b: usize) {
         self.postbox
             .send_message(ClientMsg::SwapInventorySlots(a, b))
diff --git a/common/src/comp/controller.rs b/common/src/comp/controller.rs
index 45dc34df86..0c592e4cf3 100644
--- a/common/src/comp/controller.rs
+++ b/common/src/comp/controller.rs
@@ -7,8 +7,8 @@ pub struct Controller {
     pub move_dir: Vec2<f32>,
     pub look_dir: Vec3<f32>,
     pub jump: bool,
-    pub attack: bool,
-    pub block: bool,
+    pub main: bool,
+    pub alt: bool,
     pub roll: bool,
     pub glide: bool,
     pub respawn: bool,
diff --git a/common/src/comp/inventory/item.rs b/common/src/comp/inventory/item.rs
index 909e9e087f..326d8aca92 100644
--- a/common/src/comp/inventory/item.rs
+++ b/common/src/comp/inventory/item.rs
@@ -76,6 +76,11 @@ pub enum ConsumptionEffect {
     Xp(i32),
 }
 
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub enum Debug {
+    Teleport,
+}
+
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub enum Item {
     Tool {
@@ -91,6 +96,7 @@ pub enum Item {
         effect: ConsumptionEffect,
     },
     Ingredient,
+    Debug(Debug),
 }
 
 impl Item {
@@ -100,6 +106,7 @@ impl Item {
             Item::Armor { kind, .. } => kind.name(),
             Item::Consumable { .. } => "<consumable>",
             Item::Ingredient => "<ingredient>",
+            Item::Debug(_) => "Debugging item",
         }
     }
 
@@ -109,6 +116,7 @@ impl Item {
             Item::Armor { .. } => "armour",
             Item::Consumable { .. } => "consumable",
             Item::Ingredient => "ingredient",
+            Item::Debug(_) => "debug",
         }
     }
 
diff --git a/common/src/comp/inventory/mod.rs b/common/src/comp/inventory/mod.rs
index 808fb1b9f2..91fe4090f0 100644
--- a/common/src/comp/inventory/mod.rs
+++ b/common/src/comp/inventory/mod.rs
@@ -2,7 +2,7 @@
 pub mod item;
 
 // Reexports
-pub use self::item::{Item, Tool};
+pub use self::item::{Debug, Item, Tool};
 
 use specs::{Component, HashMapStorage, NullStorage};
 use specs_idvs::IDVStorage;
@@ -21,13 +21,25 @@ impl Inventory {
         self.slots.len()
     }
 
-    pub fn insert(&mut self, item: Item) -> Option<Item> {
+    pub fn push(&mut self, item: Item) -> Option<Item> {
         match self.slots.iter_mut().find(|slot| slot.is_none()) {
             Some(slot) => {
+                let old = slot.take();
                 *slot = Some(item);
-                None
+                old
             }
-            None => Some(item),
+            None => None,
+        }
+    }
+
+    pub fn insert(&mut self, cell: usize, item: Option<Item>) -> Option<Item> {
+        match self.slots.get_mut(cell) {
+            Some(slot) => {
+                let old = slot.take();
+                *slot = item;
+                old
+            }
+            None => None,
         }
     }
 
@@ -60,28 +72,25 @@ impl Default for Inventory {
             slots: vec![None; 24],
         };
 
-        inventory.insert(Item::Tool {
+        inventory.push(Item::Debug(Debug::Teleport));
+        inventory.push(Item::Tool {
             kind: Tool::Daggers,
             power: 10,
         });
-        inventory.insert(Item::Tool {
+        inventory.push(Item::Tool {
             kind: Tool::Sword,
             power: 10,
         });
-        inventory.insert(Item::Tool {
+        inventory.push(Item::Tool {
             kind: Tool::Axe,
             power: 10,
         });
-        inventory.insert(Item::Tool {
+        inventory.push(Item::Tool {
             kind: Tool::Hammer,
             power: 10,
         });
-        inventory.insert(Item::Tool {
-            kind: Tool::Bow,
-            power: 10,
-        });
         for _ in 0..10 {
-            inventory.insert(Item::default());
+            inventory.push(Item::default());
         }
 
         inventory
diff --git a/common/src/event.rs b/common/src/event.rs
index fc081c3e01..e28e6e558b 100644
--- a/common/src/event.rs
+++ b/common/src/event.rs
@@ -6,6 +6,7 @@ use vek::*;
 
 pub enum LocalEvent {
     Jump(EcsEntity),
+    Boost { entity: EcsEntity, vel: Vec3<f32> },
     LandOnGround { entity: EcsEntity, vel: Vec3<f32> },
 }
 
diff --git a/common/src/msg/client.rs b/common/src/msg/client.rs
index c9b429b4dd..b51760d92a 100644
--- a/common/src/msg/client.rs
+++ b/common/src/msg/client.rs
@@ -30,6 +30,7 @@ pub enum ClientMsg {
         vel: comp::Vel,
         ori: comp::Ori,
     },
+    ActivateInventorySlot(usize),
     SwapInventorySlots(usize, usize),
     DropInventorySlot(usize),
     PickUp(u64),
diff --git a/common/src/state.rs b/common/src/state.rs
index 6d18e06fea..fbe80d206b 100644
--- a/common/src/state.rs
+++ b/common/src/state.rs
@@ -334,6 +334,15 @@ impl State {
                         vel.0.z = HUMANOID_JUMP_ACCEL;
                     }
                 }
+
+                LocalEvent::Boost {
+                    entity,
+                    vel: extra_vel,
+                } => {
+                    if let Some(vel) = velocities.get_mut(entity) {
+                        vel.0 += extra_vel;
+                    }
+                }
             }
         }
     }
diff --git a/common/src/sys/agent.rs b/common/src/sys/agent.rs
index 929579ecce..20f38144ef 100644
--- a/common/src/sys/agent.rs
+++ b/common/src/sys/agent.rs
@@ -87,9 +87,9 @@ impl<'a> System<'a> for Sys {
                                 Vec2::<f32>::from(target_pos.0 - pos.0).normalized() * 0.5;
 
                             if rand::random::<f32>() < 0.05 {
-                                controller.attack = true;
+                                controller.main = true;
                             } else {
-                                controller.attack = false;
+                                controller.main = false;
                             }
                         } else if dist < SIGHT_DIST {
                             controller.move_dir =
diff --git a/common/src/sys/controller.rs b/common/src/sys/controller.rs
index b570ed4013..ae84148bb4 100644
--- a/common/src/sys/controller.rs
+++ b/common/src/sys/controller.rs
@@ -4,8 +4,8 @@ use super::{
 };
 use crate::{
     comp::{
-        ActionState::*, Body, CharacterState, Controller, MovementState::*, PhysicsState, Stats,
-        Vel,
+        item, ActionState::*, Body, CharacterState, Controller, Item, MovementState::*,
+        PhysicsState, Stats, Vel,
     },
     event::{EventBus, LocalEvent, ServerEvent},
 };
@@ -96,7 +96,7 @@ impl<'a> System<'a> for Sys {
             }
 
             // Wield
-            if controller.attack
+            if controller.main
                 && character.action == Idle
                 && (character.movement == Stand || character.movement == Run)
             {
@@ -105,33 +105,46 @@ impl<'a> System<'a> for Sys {
                 };
             }
 
-            // Attack
-            if controller.attack
-                && (character.movement == Stand
-                    || character.movement == Run
-                    || character.movement == Jump)
-            {
-                // TODO: Check if wield ability exists
-                if let Wield { time_left } = character.action {
-                    if time_left == Duration::default() {
-                        character.action = Attack {
-                            time_left: ATTACK_DURATION,
-                            applied: false,
+            match stats.equipment.main {
+                Some(Item::Tool { .. }) => {
+                    // Attack
+                    if controller.main
+                        && (character.movement == Stand
+                            || character.movement == Run
+                            || character.movement == Jump)
+                    {
+                        // TODO: Check if wield ability exists
+                        if let Wield { time_left } = character.action {
+                            if time_left == Duration::default() {
+                                character.action = Attack {
+                                    time_left: ATTACK_DURATION,
+                                    applied: false,
+                                };
+                            }
+                        }
+                    }
+
+                    // Block
+                    if controller.alt
+                        && (character.movement == Stand || character.movement == Run)
+                        && (character.action == Idle || character.action.is_wield())
+                    {
+                        character.action = Block {
+                            time_left: Duration::from_secs(5),
                         };
+                    } else if !controller.alt && character.action.is_block() {
+                        character.action = Idle;
                     }
                 }
-            }
-
-            // Block
-            if controller.block
-                && (character.movement == Stand || character.movement == Run)
-                && (character.action == Idle || character.action.is_wield())
-            {
-                character.action = Block {
-                    time_left: Duration::from_secs(5),
-                };
-            } else if !controller.block && character.action.is_block() {
-                character.action = Idle;
+                Some(Item::Debug(item::Debug::Teleport)) => {
+                    if controller.main {
+                        local_emitter.emit(LocalEvent::Boost {
+                            entity,
+                            vel: controller.look_dir * 10.0,
+                        });
+                    }
+                }
+                _ => {}
             }
 
             // Roll
diff --git a/server/src/lib.rs b/server/src/lib.rs
index 27813c781c..7307404190 100644
--- a/server/src/lib.rs
+++ b/server/src/lib.rs
@@ -712,6 +712,37 @@ impl Server {
                             }
                             _ => {}
                         },
+                        ClientMsg::ActivateInventorySlot(x) => {
+                            let item_opt = state
+                                .ecs()
+                                .write_storage::<comp::Inventory>()
+                                .get_mut(entity)
+                                .and_then(|inv| inv.remove(x));
+
+                            if let Some(item) = item_opt {
+                                match item {
+                                    comp::Item::Tool { .. } | comp::Item::Debug(_) => {
+                                        if let Some(stats) = state
+                                            .ecs()
+                                            .write_storage::<comp::Stats>()
+                                            .get_mut(entity)
+                                        {
+                                            state
+                                                .ecs()
+                                                .write_storage::<comp::Inventory>()
+                                                .get_mut(entity)
+                                                .map(|inv| {
+                                                    inv.insert(x, stats.equipment.main.take())
+                                                });
+
+                                            stats.equipment.main = Some(item);
+                                        }
+                                    }
+                                    _ => {}
+                                }
+                                state.write_component(entity, comp::InventoryUpdate);
+                            }
+                        }
                         ClientMsg::SwapInventorySlots(a, b) => {
                             state
                                 .ecs()
@@ -757,7 +788,7 @@ impl Server {
                                 }),
                                 ecs.write_storage::<comp::Inventory>().get_mut(entity),
                             ) {
-                                if inv.insert(item).is_none() {
+                                if inv.push(item).is_none() {
                                     Some(item_entity)
                                 } else {
                                     None
diff --git a/voxygen/src/hud/bag.rs b/voxygen/src/hud/bag.rs
index 749732e001..bd3f748165 100644
--- a/voxygen/src/hud/bag.rs
+++ b/voxygen/src/hud/bag.rs
@@ -153,7 +153,7 @@ impl<'a> Widget for Bag<'a> {
                 let selected_slot = match state.selected_slot {
                     Some(a) => {
                         if a == i {
-                            event = Some(Event::HudEvent(HudEvent::DropInventorySlot(i)));
+                            event = Some(Event::HudEvent(HudEvent::ActivateInventorySlot(i)));
                         } else {
                             event = Some(Event::HudEvent(HudEvent::SwapInventorySlots(a, i)));
                         }
diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs
index a9f0299f41..b563442933 100644
--- a/voxygen/src/hud/mod.rs
+++ b/voxygen/src/hud/mod.rs
@@ -162,6 +162,7 @@ pub enum Event {
     ToggleShortcutNumbers(ShortcutNumbers),
     UiScale(ScaleChange),
     CharacterSelection,
+    ActivateInventorySlot(usize),
     SwapInventorySlots(usize, usize),
     DropInventorySlot(usize),
     Logout,
diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs
index d6b0e1e143..11c27e5a8d 100644
--- a/voxygen/src/scene/figure.rs
+++ b/voxygen/src/scene/figure.rs
@@ -321,6 +321,7 @@ impl FigureModelCache {
                     Tool::Bow => ("weapon.hammer.rusty_2h", Vec3::new(-2.5, -5.5, -4.0)),
                     Tool::Staff => ("weapon.axe.rusty_2h", Vec3::new(-2.5, -6.5, -2.0)),
                 },
+                Item::Debug(_) => ("weapon.debug_wand", Vec3::new(-2.5, -6.5, -2.0)),
                 _ => ("figure.empty", Vec3::default()),
             };
             Self::load_mesh(name, offset)
diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs
index edf4ec56b5..e7e2fc7c89 100644
--- a/voxygen/src/session.rs
+++ b/voxygen/src/session.rs
@@ -152,7 +152,7 @@ impl PlayState for SessionState {
                                 client.place_block(pos, self.selected_block);
                             }
                         } else {
-                            self.controller.attack = state
+                            self.controller.main = state
                         }
                     }
 
@@ -176,7 +176,7 @@ impl PlayState for SessionState {
                                 client.remove_block(pos);
                             }
                         } else {
-                            self.controller.block = state;
+                            self.controller.alt = state;
                         }
                     }
                     Event::InputUpdate(GameInput::Roll, state) => {
@@ -376,6 +376,9 @@ impl PlayState for SessionState {
                         global_state.settings.graphics.max_fps = fps;
                         global_state.settings.save_to_file_warn();
                     }
+                    HudEvent::ActivateInventorySlot(x) => {
+                        self.client.borrow_mut().activate_inventory_slot(x)
+                    }
                     HudEvent::SwapInventorySlots(a, b) => {
                         self.client.borrow_mut().swap_inventory_slots(a, b)
                     }

From 77205f7a8ff43d724f3dc4f6050248dcd6343b06 Mon Sep 17 00:00:00 2001
From: Pfauenauge90 <44173739+Pfauenauge90@users.noreply.github.com>
Date: Thu, 29 Aug 2019 02:29:49 +0200
Subject: [PATCH 03/16] changed debug wand visuals, added icons for 2h sword
 main and alt attack

---
 assets/voxygen/element/icons/2hsword_m1.vox | Bin 49374 -> 51425 bytes
 assets/voxygen/element/icons/2hsword_m2.vox | Bin 50430 -> 51766 bytes
 assets/voxygen/voxel/weapon/debug_wand.vox  | Bin 29771 -> 45980 bytes
 voxygen/src/hud/skillbar.rs                 |  36 ++++++++++++++++----
 voxygen/src/scene/figure.rs                 |   2 +-
 5 files changed, 30 insertions(+), 8 deletions(-)

diff --git a/assets/voxygen/element/icons/2hsword_m1.vox b/assets/voxygen/element/icons/2hsword_m1.vox
index c920f452af4f20aee1931d1a5032a80ccc8d9968..d1aa6f9d584c736a55e2edd1ed62b7aef7aa8e45 100644
GIT binary patch
literal 51425
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
F{4dT3=4Ai?

literal 49374
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
V;f+UJxp{*wr@KKUXQ;(LKLncc;T`}0

diff --git a/assets/voxygen/element/icons/2hsword_m2.vox b/assets/voxygen/element/icons/2hsword_m2.vox
index cb1b11c1d790578089532034ac14aa5aebfbd1ea..bc67ba65fe70d486d3e3fc9f8c37a14b01e04a9b 100644
GIT binary patch
literal 51766
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

literal 50430
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
Ok2&KBB7G*h{QMs*wH3Dj

diff --git a/assets/voxygen/voxel/weapon/debug_wand.vox b/assets/voxygen/voxel/weapon/debug_wand.vox
index dea1e8f8831b9b768719aa3731e1e1f3533073c0..b7a6ff9ef5885019a48fe1ee9283105d80c403e5 100644
GIT binary patch
literal 45980
zcmd6w33Qaz702IulS#h$CbK0W>^Pz*i^Z8FlSNTMMHWG15fPVhNG6kMmPsdJZNvpN
zgBC@ks8z(JmRc(sMAU9bEwx$&O4Zt0tJYe(*S6N$_4a?i2}{^Kr=DZ)%ei^m{qFm{
z`?krvOfq-Iyzn}u)bt5c&O@Yfk0~{K%KVANoI!9wN+H7_^Dde{<;_AQ5T4NZW)109
zf#TiD@7tw<zMaZb)UAB}oyr&JQ2}p{@)!50VDT>H^Yy3@q}Y#gJE#2Kobn7#s33HF
z#W@v%Ua>Eyy#AaDqCSLjFY+OzZGX42ecj3rn?XG9hy4KR0^Ei_qdZnZxe&XMccHuh
z^#*zc$a{w5lnZ<X;4|QJqt4BGuwQ^S4cOe^(vU(t<3f7{U^A$9gG)oF5H^dzWl*P4
zUWB|x+5(paE*n1Z8i)&h8kAI?fsg@^{*ZD=KS&v*G^IQxh(m~jhy&fq<45d+6eI0L
zY(qRrWgGaS0PVtV5$syX7a{L~*ly$@o<gJxGs=S4uxFK|l!bO|j)N&>m!X}Z;44L0
z2=(x{4Y2~qLoAeAp`^hW>f)kZ+FO*<UU$Y|47Jzfv^6BB(H~u;5POmuY}&&*uAByo
zhCPEZ)GXl99t-sYp^s;6*g$_Yc(o^hGCX6sc51L|3w7v^M!&Tu)ToQNO)H_nrr{3_
z-)K*9QltOc<3b%c;13PoX-{dRhA*|JAL4Sv{UHOA8h+3=SZ%a#a~|b3>g|3I=-Z_!
zZR2@6l+sqgi`r%ZkH`I@hJAxE)Hd3&hISkD*`OZ=b`9(sv|})a2JIS*p#g`%7#eUI
zjG+OuL0=5U(4fx-elqMY3p^HhEbv(1vA|=22V<ly@L1rnz*DGpYd8Am)({uc1-rBx
zesUM)bYamhgE7>ep}VvVHugFEWH5#XV`wmjhQ|=&YcS3RYtdNX!W=MIlLm9b*g^Ci
zW8i_0Fjuq>c73q#LpwgS=R@1YVDMs`ePAfU7~2>J8{=aa!!KS4#@<Gsus(G$ix0ZK
zoPj+9-y6(DgE?R@z6N7%Fh2~&*kIfZ=CHw78jPXA+%Z@y8f#wrS-d$NV6k%=>s|+u
z4x&5=`ys?3#6h&@gZMcPAch23xD55!3pDl$gSBX|CJol6!5TGKs|IV<VC@>LVS}}-
z;TvsP34^t5u*MD6y1|+^So;QhfWcm1uqPPo4F-FJ!CqmoXBg}q278FXUShDX80;?w
z`;2k<t}@tnjLUzeb_Kh20mKa{3UuqjK#w+vwZB^{E2otYu?>Mg75oZLt<hg?A@4yR
zVjwO^0rcF^D}-JV#06iVPa6B1F5nn_cfkh*5I4uj2cYAHZZX7%XZ^4dfUO`T1Sx^I
zp=Tf(HZ=4NV#6^w;42MZXcyA(i!MMp{G{E`f&X+No`Wy7#d90;!9p7r+OjZDEX)_o
zNgYC8LU<PYwk|<k33N)pQG&jgzy~4tA_$)p!#7^UKKRNH2?V=Mz<;H|o^As0DfW1S
zz20EYH`x0P&Hw|OhQ}FagTY)en2QGU(BSOQ*#ESRamBncI8zMfmBE}cIByKj9fR}7
z;2bhIj||QwgY(JYoH97G4E6_ueZp8}DTDQ?kXDG>=FB>8h;!2I|Heli^#)FJXqz<a
z{9rz*_LgyMxDGZ>>aF8E2R={P1gBYVuWr1P57tOH5{_24&7ORI87m;LK8L-wIX!K{
zMY9HRqBn4z8xn6zv?e(d;T8_m;=)6;q6cd+;~`oV2Wv6WAzGCOYZV+$tLk7arar`0
z>|ibS%pqFU2Wu4_POFBsW=%SCf?^<q+S*#`>guAm)+n01eg_>__94ArRz};mPiIwn
zc*^5PmEibt8hCk_!pq0ds10?bCb~&A+obL-A+@8Ng3}fCZ&fs8wW5<ARb(|Q@~u!*
zihTJ)imIl2X=-bb=3iY(H*6hBXLl)@xmMAFO^TN8#<MdA(XjMzI=*W(Rc{$jgR^Bc
zeAOTt{lGC4efC7^e~F^wuZHb)ipFhIq~@UgWfrNmeo~vuXyu6^+8F6aFP%1+XzH=F
z7SnAj<Q2#}khMz`ZMs#__Kk|3>p_0JqI)MQdUBSc*Hen-Bfn&>qSXy3U!>@)QHn0B
zRkY}AMYp4TX4N1{PaICmW{#wF$qMSapoZ2pokiPo7t*^Aq-o4?<utD17&`Zik(8WU
zL(Nkat+-UthE7G>ZdO!1Y!FQueLP)KJ(jX(*U{Y3<&>@(Ozky8Y0G6N)BN)%Q1j*I
zQCIuLbmQ_AEz8WO)z>xCmW|ibo@dsR*XyMLr6CH3!xSAgoT|s3K&MoUqKV_8G~=8)
zT7B&h+H}uwdiA-{^!m;*bQjv(@_?c{Cxq$wxua=WdL-SxqLOwzd=|a;+HA_+7^GDX
zmQm08E_(0f2mj~(zkPS=WA%U4q!CX4D=RDMmYNN8a`aw0b>%fQaK%7+_C7@~U99M#
zkt1o;s8Q5(+#;Gbc{8aM%cx(rA8oxYKZeT(VeSkYMpuqlOQ)Z@h8k|Xo(5djpLRYn
zg0{{dNNeD;gZ<BXZ0n-gFHp9LXz6VmX~q3p=%&rj&>c_jp;-G$I{lgrbne~TX!fIf
zX#Du`^cHq7WkKiza_v#{##4E|H!#0Gsvb+wS!YLzx$;PLTz<4V$MDgg$Im%)rt!}^
zdxHlFXYcG>+McwKi8rJh8y9vYc{_<OPNq{$oxJx%ox1jxL`P@3o(m$pE5);!g{daq
z5hG)xj+u`3WPLs#;~giS&Sdl1N++A>bgV@j-Nu%MOB_>9RZBzG$s9<?1+oeG%#cmU
z?w3u-!!MhVr>ks2UX8K|c|(y+$XlFjLZ*{VXp1NGiYMgv9%YZRPduStJYhgQA^%)2
zdme_w6PAc4<l7C|qs;FG$tLV4p0HdzVSn+21H=;!6i>+S+sa<cgT)i_`|`4VI8;0#
z-{;Hr;W1(f?*ti#Fys^PA^%t&8Cw~NRa774O~k4rzKMA3CxiJh-sT)Gp71#FgvW~~
z93h_Y1o4C?iYFW?o^X_S!qMUh$A~B7U%dDP4(E??>U~N);aKs6CyOVHh$oDSC#(=p
zSSg;cN<3jqJYltX!W!{}wc-iu#1oz(p72!hgyX~$o+h5~bn%2|h$kE`o^XPA!ZXDa
zo+X~}Z1IE>#S@+*o^X<Q!pY(Zr-&z<DxUCM@r2XF6HXUT$e$>e{T}QL@r37#C!8ss
zaF%$&+2RT3h$p;2JmFmNgcph@oF|^}BJqUt#S>mEp70X!gqMmZyi7b{Ts-0B;t3Pt
z2^WYbtQSw%Af7NOp0H6oVM;t<lX$|kc*0MMCu|l^*dm^=RXkyvc*2Z$!gle5pAkZM
z<WJCKg%C!L_!*xL@r0e?2^WedTqK@wv3SBI;t7|ECtN0;@U!9xyTlV-A)au#c)}~i
z6J8~r@M`gd*N7)vA)fGB@r2ijC%j%fVYhg~oOr^O;t6jMPk5tv!q15(TqU0HCh>$f
zizi$yp70j&glohT-YTAOt$4!Eizi$sp71vDgtv<)yhA+U7sM0tpLmn~$%VVb6RsCe
zc(-`M4dMy!5l?upc*6U{6W%YL@QdOJ9}rLYCGmtC#S?y6JmG`l3BMwq@FDSpUlmXI
zuz12v;t3xSPxz>K!XEL2o5d48CZ2GMc*4iU6K)kx_=I@EC&d#!C7$qW;t9Vlp70yu
z3BM_x@LS>uw}~fwT0G%)@r2(NPxy>@!taPB<hyweJ0N}Tq}(WoCtK5<MV$D5|F81z
z9*k!(m8Acs{;YVy?};aTPCViB;t9Vmp6~_ngfEIG+$o-Lmw3Y6;t78so^X$N!XJt!
zd`T=J|0)%Smmwed;*ejFMaITrHMMmy=hazzOQNGQU9Y*k5Z~h2%)(TY%TbFuFE2aV
zllA$0%=z$nI+M+3kMgf5D;&+1hOA?E`h+>t_!kd3yaMS%Deg7mkHizcDxUDi;t78u
zp71sCgg+He__}z)pNS`YLp<S|;tAgpPxy23gl~%{{DpYJcf=F^Qas_i;t78xp77V=
z34bG=@VDX#e<z;s_u>ivAfE7#;tAgqPxvSCgnt%K_!sen?~5n=t9Zf>#1sBaJmH7p
z3I8sh@E_s{|0$mEU*ZY>EuQc{;t5G4VRpuuQ`<nsf$zPXtFF$a?aBNdS6ib&VLY9`
zFRQAnh*j1&CCy%xSHxoBUUBZs5^brLBwL6@!m)^BDv?bl*i>X}q{b;|NOv?lw_)7!
zIMi_9i?qHiFKkO6*m6Z(Z7g#5mf6ldYy^QZ``Sr#w&t(%5=-L^`TM%6eFe=n^s8dw
zXrzk!;gq+glYJGr;IO^rid4RDwK1pFOl7>m>D%6%^ISBN_fj+(Vb(eZMd;IK=k~8L
zlZx-{cizrnUCl<W$lK`KVW-uWWLt+bc8!@u{CHLVwz479m`AP1qb8TMXBai==q^g9
z9ByWccjVI!(t?&mLo(jxR31=}zt3cldA%Uqw$nb(9mkOiS~8hd$9ijeN#65$4|mij
zT9S@M=eP9|e6iZ;<as#aolV(fM^mQ7@j#T@sO)W{kH_+jW!jwi7EjbCI~)^EgQ-L-
z>sE}d;Kxrp+~ZEuDO~clH8`~OnU+kJdstf?uBr%E<Zo`9_TKS29AkP7v0L}`)p6N^
z)P5s;t6N<Wj@5;uRn^@7DZP&!il1yq<$dL}&L$&ad^xrjryDwZ@1LDsT-s}ewe~gc
zBvRS*0e#qK#Tl-S_C$TU%^A?>ezW<R5Xs+sV?pBbd#U3+#^pb^#^KQ0>5gP)CyX87
vI({hXc%WnP{&XVYr1!x&rkxyjcz<p|DxSY^cj}OHp38UNnIv2u4dd&-a|*q`

literal 29771
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

diff --git a/voxygen/src/hud/skillbar.rs b/voxygen/src/hud/skillbar.rs
index 88906fe71a..2535564ed2 100644
--- a/voxygen/src/hud/skillbar.rs
+++ b/voxygen/src/hud/skillbar.rs
@@ -3,7 +3,7 @@ use super::{
     /*FOCUS_COLOR, RAGE_COLOR,*/ HP_COLOR, LOW_HP_COLOR, MANA_COLOR, TEXT_COLOR, XP_COLOR,
 };
 use crate::GlobalState;
-use common::comp::Stats;
+use common::comp::{Stats,item::Tool};
 use conrod_core::{
     color,
     widget::{self, Button, Image, Rectangle, Text},
@@ -92,7 +92,8 @@ pub struct Skillbar<'a> {
     stats: &'a Stats,
     #[conrod(common_builder)]
     common: widget::CommonBuilder,
-    current_resource: ResourceType,
+    current_resource: ResourceType,  
+    pub character_tool: Option<Tool>,  
 }
 
 impl<'a> Skillbar<'a> {
@@ -102,13 +103,14 @@ impl<'a> Skillbar<'a> {
         fonts: &'a Fonts,
         stats: &'a Stats,
     ) -> Self {
-        Self {
+        Self { 
             imgs,
             _fonts: fonts,
             stats,
             global_state,
-            current_resource: ResourceType::Mana,
+            current_resource: ResourceType::Mana,            
             common: widget::CommonBuilder::default(),
+            character_tool: Some(Tool::Sword), // TODO: Pass the actual equipped weapon 
         }
     }
 }
@@ -155,7 +157,7 @@ impl<'a> Widget for Skillbar<'a> {
         let energy_percentage =
             self.stats.energy.current() as f64 / self.stats.energy.maximum() as f64 * 100.0;
 
-        let scale = 2.0;
+        let scale = 2.0;        
 
         let bar_values = self.global_state.settings.gameplay.bar_numbers;
         let shortcuts = self.global_state.settings.gameplay.shortcut_numbers;
@@ -351,7 +353,17 @@ impl<'a> Widget for Skillbar<'a> {
             .color(Some(BG_COLOR))
             .middle_of(state.ids.m1_slot)
             .set(state.ids.m1_slot_bg, ui);
-        Button::image(self.imgs.twohhammer_m1) // Insert Icon here
+        Button::image(
+            match self.character_tool {
+            Some(Tool::Sword) => {self.imgs.twohsword_m1}
+            Some(Tool::Axe) => {self.imgs.twohhammer_m1}
+            Some(Tool::Hammer) => {self.imgs.twohhammer_m1}
+            Some(Tool::Bow) => {self.imgs.twohhammer_m1}
+            Some(Tool::Daggers) => {self.imgs.twohhammer_m1}
+            Some(Tool::Staff) => {self.imgs.twohhammer_m1}
+            _ => {self.imgs.twohhammer_m1}
+            }
+        ) // Insert Icon here
             .w_h(38.0 * scale, 38.0 * scale)
             .middle_of(state.ids.m1_slot_bg)
             .set(state.ids.m1_content, ui);
@@ -365,7 +377,17 @@ impl<'a> Widget for Skillbar<'a> {
             .color(Some(BG_COLOR))
             .middle_of(state.ids.m2_slot)
             .set(state.ids.m2_slot_bg, ui);
-        Button::image(self.imgs.twohhammer_m2) // Insert Icon here
+        Button::image(
+            match self.character_tool {
+            Some(Tool::Sword) => {self.imgs.twohsword_m2}
+            Some(Tool::Axe) => {self.imgs.twohhammer_m2}
+            Some(Tool::Hammer) => {self.imgs.twohhammer_m2}
+            Some(Tool::Bow) => {self.imgs.twohhammer_m2}
+            Some(Tool::Daggers) => {self.imgs.twohhammer_m2}
+            Some(Tool::Staff) => {self.imgs.twohhammer_m2}
+            _ => {self.imgs.twohhammer_m2}
+            }
+        ) // Insert Icon here
             .w_h(38.0 * scale, 38.0 * scale)
             .middle_of(state.ids.m2_slot_bg)
             .set(state.ids.m2_content, ui);
diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs
index 11c27e5a8d..7f5651e73e 100644
--- a/voxygen/src/scene/figure.rs
+++ b/voxygen/src/scene/figure.rs
@@ -321,7 +321,7 @@ impl FigureModelCache {
                     Tool::Bow => ("weapon.hammer.rusty_2h", Vec3::new(-2.5, -5.5, -4.0)),
                     Tool::Staff => ("weapon.axe.rusty_2h", Vec3::new(-2.5, -6.5, -2.0)),
                 },
-                Item::Debug(_) => ("weapon.debug_wand", Vec3::new(-2.5, -6.5, -2.0)),
+                Item::Debug(_) => ("weapon.debug_wand", Vec3::new(-1.5, -9.5, -4.0)),
                 _ => ("figure.empty", Vec3::default()),
             };
             Self::load_mesh(name, offset)

From 987a17911934060bb8d86ef0e09573beadc2e88b Mon Sep 17 00:00:00 2001
From: Pfauenauge90 <44173739+Pfauenauge90@users.noreply.github.com>
Date: Thu, 29 Aug 2019 02:32:19 +0200
Subject: [PATCH 04/16] fmt

---
 voxygen/src/hud/skillbar.rs | 66 +++++++++++++++++--------------------
 1 file changed, 31 insertions(+), 35 deletions(-)

diff --git a/voxygen/src/hud/skillbar.rs b/voxygen/src/hud/skillbar.rs
index 2535564ed2..3cec927871 100644
--- a/voxygen/src/hud/skillbar.rs
+++ b/voxygen/src/hud/skillbar.rs
@@ -3,7 +3,7 @@ use super::{
     /*FOCUS_COLOR, RAGE_COLOR,*/ HP_COLOR, LOW_HP_COLOR, MANA_COLOR, TEXT_COLOR, XP_COLOR,
 };
 use crate::GlobalState;
-use common::comp::{Stats,item::Tool};
+use common::comp::{item::Tool, Stats};
 use conrod_core::{
     color,
     widget::{self, Button, Image, Rectangle, Text},
@@ -92,8 +92,8 @@ pub struct Skillbar<'a> {
     stats: &'a Stats,
     #[conrod(common_builder)]
     common: widget::CommonBuilder,
-    current_resource: ResourceType,  
-    pub character_tool: Option<Tool>,  
+    current_resource: ResourceType,
+    pub character_tool: Option<Tool>,
 }
 
 impl<'a> Skillbar<'a> {
@@ -103,14 +103,14 @@ impl<'a> Skillbar<'a> {
         fonts: &'a Fonts,
         stats: &'a Stats,
     ) -> Self {
-        Self { 
+        Self {
             imgs,
             _fonts: fonts,
             stats,
             global_state,
-            current_resource: ResourceType::Mana,            
+            current_resource: ResourceType::Mana,
             common: widget::CommonBuilder::default(),
-            character_tool: Some(Tool::Sword), // TODO: Pass the actual equipped weapon 
+            character_tool: Some(Tool::Sword), // TODO: Pass the actual equipped weapon
         }
     }
 }
@@ -157,7 +157,7 @@ impl<'a> Widget for Skillbar<'a> {
         let energy_percentage =
             self.stats.energy.current() as f64 / self.stats.energy.maximum() as f64 * 100.0;
 
-        let scale = 2.0;        
+        let scale = 2.0;
 
         let bar_values = self.global_state.settings.gameplay.bar_numbers;
         let shortcuts = self.global_state.settings.gameplay.shortcut_numbers;
@@ -353,20 +353,18 @@ impl<'a> Widget for Skillbar<'a> {
             .color(Some(BG_COLOR))
             .middle_of(state.ids.m1_slot)
             .set(state.ids.m1_slot_bg, ui);
-        Button::image(
-            match self.character_tool {
-            Some(Tool::Sword) => {self.imgs.twohsword_m1}
-            Some(Tool::Axe) => {self.imgs.twohhammer_m1}
-            Some(Tool::Hammer) => {self.imgs.twohhammer_m1}
-            Some(Tool::Bow) => {self.imgs.twohhammer_m1}
-            Some(Tool::Daggers) => {self.imgs.twohhammer_m1}
-            Some(Tool::Staff) => {self.imgs.twohhammer_m1}
-            _ => {self.imgs.twohhammer_m1}
-            }
-        ) // Insert Icon here
-            .w_h(38.0 * scale, 38.0 * scale)
-            .middle_of(state.ids.m1_slot_bg)
-            .set(state.ids.m1_content, ui);
+        Button::image(match self.character_tool {
+            Some(Tool::Sword) => self.imgs.twohsword_m1,
+            Some(Tool::Axe) => self.imgs.twohhammer_m1,
+            Some(Tool::Hammer) => self.imgs.twohhammer_m1,
+            Some(Tool::Bow) => self.imgs.twohhammer_m1,
+            Some(Tool::Daggers) => self.imgs.twohhammer_m1,
+            Some(Tool::Staff) => self.imgs.twohhammer_m1,
+            _ => self.imgs.twohhammer_m1,
+        }) // Insert Icon here
+        .w_h(38.0 * scale, 38.0 * scale)
+        .middle_of(state.ids.m1_slot_bg)
+        .set(state.ids.m1_content, ui);
         // M2 Slot
         Image::new(self.imgs.skillbar_slot_big)
             .w_h(40.0 * scale, 40.0 * scale)
@@ -377,20 +375,18 @@ impl<'a> Widget for Skillbar<'a> {
             .color(Some(BG_COLOR))
             .middle_of(state.ids.m2_slot)
             .set(state.ids.m2_slot_bg, ui);
-        Button::image(
-            match self.character_tool {
-            Some(Tool::Sword) => {self.imgs.twohsword_m2}
-            Some(Tool::Axe) => {self.imgs.twohhammer_m2}
-            Some(Tool::Hammer) => {self.imgs.twohhammer_m2}
-            Some(Tool::Bow) => {self.imgs.twohhammer_m2}
-            Some(Tool::Daggers) => {self.imgs.twohhammer_m2}
-            Some(Tool::Staff) => {self.imgs.twohhammer_m2}
-            _ => {self.imgs.twohhammer_m2}
-            }
-        ) // Insert Icon here
-            .w_h(38.0 * scale, 38.0 * scale)
-            .middle_of(state.ids.m2_slot_bg)
-            .set(state.ids.m2_content, ui);
+        Button::image(match self.character_tool {
+            Some(Tool::Sword) => self.imgs.twohsword_m2,
+            Some(Tool::Axe) => self.imgs.twohhammer_m2,
+            Some(Tool::Hammer) => self.imgs.twohhammer_m2,
+            Some(Tool::Bow) => self.imgs.twohhammer_m2,
+            Some(Tool::Daggers) => self.imgs.twohhammer_m2,
+            Some(Tool::Staff) => self.imgs.twohhammer_m2,
+            _ => self.imgs.twohhammer_m2,
+        }) // Insert Icon here
+        .w_h(38.0 * scale, 38.0 * scale)
+        .middle_of(state.ids.m2_slot_bg)
+        .set(state.ids.m2_content, ui);
         //Slot 5
         Image::new(self.imgs.skillbar_slot)
             .w_h(20.0 * scale, 20.0 * scale)

From 7c188c8900e6a8afcee8929ea8e9cc756a5a6cf5 Mon Sep 17 00:00:00 2001
From: Pfauenauge90 <44173739+Pfauenauge90@users.noreply.github.com>
Date: Thu, 29 Aug 2019 10:13:29 +0200
Subject: [PATCH 05/16] Axe offset

---
 voxygen/src/scene/figure.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs
index 7f5651e73e..6cb091334f 100644
--- a/voxygen/src/scene/figure.rs
+++ b/voxygen/src/scene/figure.rs
@@ -314,7 +314,7 @@ impl FigureModelCache {
             let (name, offset) = match item {
                 Item::Tool { kind, .. } => match kind {
                     Tool::Sword => ("weapon.sword.rusty_2h", Vec3::new(-1.5, -6.5, -4.0)),
-                    Tool::Axe => ("weapon.axe.rusty_2h", Vec3::new(-1.5, -6.5, -4.0)),
+                    Tool::Axe => ("weapon.axe.rusty_2h", Vec3::new(-1.5, -5.0, -4.0)),
                     Tool::Hammer => ("weapon.hammer.rusty_2h", Vec3::new(-2.5, -5.5, -4.0)),
                     Tool::Daggers => ("weapon.hammer.rusty_2h", Vec3::new(-2.5, -5.5, -4.0)),
                     Tool::SwordShield => ("weapon.axe.rusty_2h", Vec3::new(-2.5, -6.5, -2.0)),

From a51c20bd312000b942a98522ebc10427b8715548 Mon Sep 17 00:00:00 2001
From: timokoesters <timo@koesters.xyz>
Date: Thu, 29 Aug 2019 19:39:34 +0200
Subject: [PATCH 06/16] Use RMB to boost away again

---
 common/src/sys/controller.rs | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/common/src/sys/controller.rs b/common/src/sys/controller.rs
index ae84148bb4..032d9dc1b2 100644
--- a/common/src/sys/controller.rs
+++ b/common/src/sys/controller.rs
@@ -11,6 +11,7 @@ use crate::{
 };
 use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage};
 use std::time::Duration;
+use vek::*;
 
 /// This system is responsible for validating controller inputs
 pub struct Sys;
@@ -140,7 +141,14 @@ impl<'a> System<'a> for Sys {
                     if controller.main {
                         local_emitter.emit(LocalEvent::Boost {
                             entity,
-                            vel: controller.look_dir * 10.0,
+                            vel: controller.look_dir * 7.0,
+                        });
+                    }
+                    if controller.alt {
+                        // Go upward
+                        local_emitter.emit(LocalEvent::Boost {
+                            entity,
+                            vel: controller.look_dir * -7.0,
                         });
                     }
                 }

From 9eff8fc0c43ed79d35356a4002ad80e7243af7e1 Mon Sep 17 00:00:00 2001
From: timokoesters <timo@koesters.xyz>
Date: Thu, 29 Aug 2019 19:42:25 +0200
Subject: [PATCH 07/16] Rename Teleport to Boost

---
 common/src/comp/inventory/item.rs | 2 +-
 common/src/comp/inventory/mod.rs  | 2 +-
 common/src/sys/controller.rs      | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/common/src/comp/inventory/item.rs b/common/src/comp/inventory/item.rs
index 326d8aca92..deb885dad6 100644
--- a/common/src/comp/inventory/item.rs
+++ b/common/src/comp/inventory/item.rs
@@ -78,7 +78,7 @@ pub enum ConsumptionEffect {
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub enum Debug {
-    Teleport,
+    Boost,
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
diff --git a/common/src/comp/inventory/mod.rs b/common/src/comp/inventory/mod.rs
index 91fe4090f0..f4122fd17b 100644
--- a/common/src/comp/inventory/mod.rs
+++ b/common/src/comp/inventory/mod.rs
@@ -72,7 +72,7 @@ impl Default for Inventory {
             slots: vec![None; 24],
         };
 
-        inventory.push(Item::Debug(Debug::Teleport));
+        inventory.push(Item::Debug(Debug::Boost));
         inventory.push(Item::Tool {
             kind: Tool::Daggers,
             power: 10,
diff --git a/common/src/sys/controller.rs b/common/src/sys/controller.rs
index 032d9dc1b2..b9e0b1db4f 100644
--- a/common/src/sys/controller.rs
+++ b/common/src/sys/controller.rs
@@ -137,7 +137,7 @@ impl<'a> System<'a> for Sys {
                         character.action = Idle;
                     }
                 }
-                Some(Item::Debug(item::Debug::Teleport)) => {
+                Some(Item::Debug(item::Debug::Boost)) => {
                     if controller.main {
                         local_emitter.emit(LocalEvent::Boost {
                             entity,

From 0e64c13996b8c1f1660dbed14209f5061dbdc524 Mon Sep 17 00:00:00 2001
From: timokoesters <timo@koesters.xyz>
Date: Thu, 29 Aug 2019 19:54:53 +0200
Subject: [PATCH 08/16] Remove warnings

---
 common/src/sys/movement.rs               |  2 --
 common/src/sys/phys.rs                   |  4 +---
 server/src/cmd.rs                        |  2 --
 voxygen/src/menu/char_selection/scene.rs |  1 -
 voxygen/src/scene/figure.rs              | 11 ++---------
 5 files changed, 3 insertions(+), 17 deletions(-)

diff --git a/common/src/sys/movement.rs b/common/src/sys/movement.rs
index 3acabeb997..d89b89b2c5 100644
--- a/common/src/sys/movement.rs
+++ b/common/src/sys/movement.rs
@@ -15,8 +15,6 @@ pub const ROLL_DURATION: Duration = Duration::from_millis(600);
 
 const HUMANOID_ACCEL: f32 = 70.0;
 const HUMANOID_SPEED: f32 = 120.0;
-const WIELD_ACCEL: f32 = 70.0;
-const WIELD_SPEED: f32 = 120.0;
 const HUMANOID_AIR_ACCEL: f32 = 10.0;
 const HUMANOID_AIR_SPEED: f32 = 100.0;
 const ROLL_SPEED: f32 = 13.0;
diff --git a/common/src/sys/phys.rs b/common/src/sys/phys.rs
index cd16ee87a3..42ebc978c5 100644
--- a/common/src/sys/phys.rs
+++ b/common/src/sys/phys.rs
@@ -273,9 +273,7 @@ impl<'a> System<'a> for Sys {
         }
 
         // Apply pushback
-        for (pos, scale, mut vel, _) in
-            (&positions, scales.maybe(), &mut velocities, &bodies).join()
-        {
+        for (pos, scale, vel, _) in (&positions, scales.maybe(), &mut velocities, &bodies).join() {
             let scale = scale.map(|s| s.0).unwrap_or(1.0);
             for (pos_other, scale_other, _) in (&positions, scales.maybe(), &bodies).join() {
                 let scale_other = scale_other.map(|s| s.0).unwrap_or(1.0);
diff --git a/server/src/cmd.rs b/server/src/cmd.rs
index 4c4e662505..33733b9b26 100644
--- a/server/src/cmd.rs
+++ b/server/src/cmd.rs
@@ -10,8 +10,6 @@ use common::{
     msg::ServerMsg,
     npc::{get_npc_name, NpcKind},
     state::TimeOfDay,
-    terrain::TerrainChunkSize,
-    vol::VolSize,
 };
 use rand::Rng;
 use specs::{Builder, Entity as EcsEntity, Join};
diff --git a/voxygen/src/menu/char_selection/scene.rs b/voxygen/src/menu/char_selection/scene.rs
index aae6ca4b20..ea57582854 100644
--- a/voxygen/src/menu/char_selection/scene.rs
+++ b/voxygen/src/menu/char_selection/scene.rs
@@ -145,7 +145,6 @@ impl Scene {
             .figure_model_cache
             .get_or_create_model(
                 renderer,
-                &client.entity(),
                 Body::Humanoid(body),
                 Some(equipment),
                 client.get_tick(),
diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs
index 6cb091334f..4c457d93a6 100644
--- a/voxygen/src/scene/figure.rs
+++ b/voxygen/src/scene/figure.rs
@@ -48,7 +48,6 @@ impl FigureModelCache {
     pub fn get_or_create_model(
         &mut self,
         renderer: &mut Renderer,
-        entity: &EcsEntity,
         body: Body,
         equipment: Option<&Equipment>,
         tick: u64,
@@ -675,7 +674,7 @@ impl FigureMgr {
 
             let skeleton_attr = &self
                 .model_cache
-                .get_or_create_model(renderer, &entity, *body, stats.map(|s| &s.equipment), tick)
+                .get_or_create_model(renderer, *body, stats.map(|s| &s.equipment), tick)
                 .1;
 
             match body {
@@ -928,13 +927,7 @@ impl FigureMgr {
             } {
                 let model = &self
                     .model_cache
-                    .get_or_create_model(
-                        renderer,
-                        &entity,
-                        *body,
-                        stats.map(|s| &s.equipment),
-                        tick,
-                    )
+                    .get_or_create_model(renderer, *body, stats.map(|s| &s.equipment), tick)
                     .0;
 
                 // Don't render the player's body while in first person mode

From 891c4cc99ca37586772c567a9a9327d147e9c94a Mon Sep 17 00:00:00 2001
From: timokoesters <timo@koesters.xyz>
Date: Thu, 29 Aug 2019 21:48:05 +0200
Subject: [PATCH 09/16] Implement icons based on weapon

---
 voxygen/src/hud/skillbar.rs | 28 +++++++++++-----------------
 1 file changed, 11 insertions(+), 17 deletions(-)

diff --git a/voxygen/src/hud/skillbar.rs b/voxygen/src/hud/skillbar.rs
index 3cec927871..e996ebeb45 100644
--- a/voxygen/src/hud/skillbar.rs
+++ b/voxygen/src/hud/skillbar.rs
@@ -3,7 +3,7 @@ use super::{
     /*FOCUS_COLOR, RAGE_COLOR,*/ HP_COLOR, LOW_HP_COLOR, MANA_COLOR, TEXT_COLOR, XP_COLOR,
 };
 use crate::GlobalState;
-use common::comp::{item::Tool, Stats};
+use common::comp::{item::Tool, Item, Stats};
 use conrod_core::{
     color,
     widget::{self, Button, Image, Rectangle, Text},
@@ -93,7 +93,6 @@ pub struct Skillbar<'a> {
     #[conrod(common_builder)]
     common: widget::CommonBuilder,
     current_resource: ResourceType,
-    pub character_tool: Option<Tool>,
 }
 
 impl<'a> Skillbar<'a> {
@@ -110,7 +109,6 @@ impl<'a> Skillbar<'a> {
             global_state,
             current_resource: ResourceType::Mana,
             common: widget::CommonBuilder::default(),
-            character_tool: Some(Tool::Sword), // TODO: Pass the actual equipped weapon
         }
     }
 }
@@ -353,13 +351,11 @@ impl<'a> Widget for Skillbar<'a> {
             .color(Some(BG_COLOR))
             .middle_of(state.ids.m1_slot)
             .set(state.ids.m1_slot_bg, ui);
-        Button::image(match self.character_tool {
-            Some(Tool::Sword) => self.imgs.twohsword_m1,
-            Some(Tool::Axe) => self.imgs.twohhammer_m1,
-            Some(Tool::Hammer) => self.imgs.twohhammer_m1,
-            Some(Tool::Bow) => self.imgs.twohhammer_m1,
-            Some(Tool::Daggers) => self.imgs.twohhammer_m1,
-            Some(Tool::Staff) => self.imgs.twohhammer_m1,
+        Button::image(match self.stats.equipment.main {
+            Some(Item::Tool { kind, .. }) => match kind {
+                Tool::Sword => self.imgs.twohsword_m1,
+                _ => self.imgs.twohhammer_m1,
+            },
             _ => self.imgs.twohhammer_m1,
         }) // Insert Icon here
         .w_h(38.0 * scale, 38.0 * scale)
@@ -375,13 +371,11 @@ impl<'a> Widget for Skillbar<'a> {
             .color(Some(BG_COLOR))
             .middle_of(state.ids.m2_slot)
             .set(state.ids.m2_slot_bg, ui);
-        Button::image(match self.character_tool {
-            Some(Tool::Sword) => self.imgs.twohsword_m2,
-            Some(Tool::Axe) => self.imgs.twohhammer_m2,
-            Some(Tool::Hammer) => self.imgs.twohhammer_m2,
-            Some(Tool::Bow) => self.imgs.twohhammer_m2,
-            Some(Tool::Daggers) => self.imgs.twohhammer_m2,
-            Some(Tool::Staff) => self.imgs.twohhammer_m2,
+        Button::image(match self.stats.equipment.main {
+            Some(Item::Tool { kind, .. }) => match kind {
+                Tool::Sword => self.imgs.twohsword_m2,
+                _ => self.imgs.twohhammer_m2,
+            },
             _ => self.imgs.twohhammer_m2,
         }) // Insert Icon here
         .w_h(38.0 * scale, 38.0 * scale)

From 1c7beaedae54f23113c9db6bcaa441b94ca68072 Mon Sep 17 00:00:00 2001
From: timokoesters <timo@koesters.xyz>
Date: Fri, 30 Aug 2019 21:02:18 +0200
Subject: [PATCH 10/16] Return the item again if slot was not wrong

---
 common/src/comp/inventory/mod.rs | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/common/src/comp/inventory/mod.rs b/common/src/comp/inventory/mod.rs
index f4122fd17b..94eba9b21a 100644
--- a/common/src/comp/inventory/mod.rs
+++ b/common/src/comp/inventory/mod.rs
@@ -21,25 +21,27 @@ impl Inventory {
         self.slots.len()
     }
 
+    /// Adds a new item to the first empty slot of the inventory. Returns the item again if no free
+    /// slot was found.
     pub fn push(&mut self, item: Item) -> Option<Item> {
         match self.slots.iter_mut().find(|slot| slot.is_none()) {
             Some(slot) => {
-                let old = slot.take();
                 *slot = Some(item);
-                old
+                None
             }
-            None => None,
+            None => Some(item),
         }
     }
 
+    /// Replaces an item in a specific slot of the inventory. Returns the item again if that slot
+    /// was not found.
     pub fn insert(&mut self, cell: usize, item: Option<Item>) -> Option<Item> {
         match self.slots.get_mut(cell) {
             Some(slot) => {
-                let old = slot.take();
                 *slot = item;
-                old
+                None
             }
-            None => None,
+            None => item,
         }
     }
 

From 5fe2b81ec83bd21817a2fdb646f70a08b78b4fef Mon Sep 17 00:00:00 2001
From: timokoesters <timo@koesters.xyz>
Date: Fri, 30 Aug 2019 21:54:33 +0200
Subject: [PATCH 11/16] Avoid right-ward shift

---
 common/src/comp/inventory/item.rs |  2 +-
 server/src/lib.rs                 | 30 ++++++++++++------------------
 2 files changed, 13 insertions(+), 19 deletions(-)

diff --git a/common/src/comp/inventory/item.rs b/common/src/comp/inventory/item.rs
index deb885dad6..69dc627ffc 100644
--- a/common/src/comp/inventory/item.rs
+++ b/common/src/comp/inventory/item.rs
@@ -81,7 +81,7 @@ pub enum Debug {
     Boost,
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
+#[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub enum Item {
     Tool {
         kind: Tool,
diff --git a/server/src/lib.rs b/server/src/lib.rs
index 7307404190..db39d714fb 100644
--- a/server/src/lib.rs
+++ b/server/src/lib.rs
@@ -713,35 +713,29 @@ impl Server {
                             _ => {}
                         },
                         ClientMsg::ActivateInventorySlot(x) => {
-                            let item_opt = state
+                            let item = state
                                 .ecs()
                                 .write_storage::<comp::Inventory>()
                                 .get_mut(entity)
                                 .and_then(|inv| inv.remove(x));
 
-                            if let Some(item) = item_opt {
-                                match item {
-                                    comp::Item::Tool { .. } | comp::Item::Debug(_) => {
-                                        if let Some(stats) = state
+                            match item {
+                                Some(comp::Item::Tool { .. }) | Some(comp::Item::Debug(_)) => {
+                                    if let Some(stats) =
+                                        state.ecs().write_storage::<comp::Stats>().get_mut(entity)
+                                    {
+                                        state
                                             .ecs()
-                                            .write_storage::<comp::Stats>()
+                                            .write_storage::<comp::Inventory>()
                                             .get_mut(entity)
-                                        {
-                                            state
-                                                .ecs()
-                                                .write_storage::<comp::Inventory>()
-                                                .get_mut(entity)
-                                                .map(|inv| {
-                                                    inv.insert(x, stats.equipment.main.take())
-                                                });
+                                            .map(|inv| inv.insert(x, stats.equipment.main.take()));
 
-                                            stats.equipment.main = Some(item);
-                                        }
+                                        stats.equipment.main = item;
                                     }
-                                    _ => {}
                                 }
-                                state.write_component(entity, comp::InventoryUpdate);
+                                _ => {}
                             }
+                            state.write_component(entity, comp::InventoryUpdate);
                         }
                         ClientMsg::SwapInventorySlots(a, b) => {
                             state

From 5d1ffdfccea6bb12708496f9b89f0b14dd4f56f4 Mon Sep 17 00:00:00 2001
From: timokoesters <timo@koesters.xyz>
Date: Fri, 30 Aug 2019 22:42:43 +0200
Subject: [PATCH 12/16] Make inventory::get return a reference

---
 common/src/comp/inventory/item.rs |  2 +-
 common/src/comp/inventory/mod.rs  | 11 ++++++-----
 2 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/common/src/comp/inventory/item.rs b/common/src/comp/inventory/item.rs
index 69dc627ffc..deb885dad6 100644
--- a/common/src/comp/inventory/item.rs
+++ b/common/src/comp/inventory/item.rs
@@ -81,7 +81,7 @@ pub enum Debug {
     Boost,
 }
 
-#[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub enum Item {
     Tool {
         kind: Tool,
diff --git a/common/src/comp/inventory/mod.rs b/common/src/comp/inventory/mod.rs
index 94eba9b21a..6bcf46d79e 100644
--- a/common/src/comp/inventory/mod.rs
+++ b/common/src/comp/inventory/mod.rs
@@ -45,24 +45,25 @@ impl Inventory {
         }
     }
 
-    // Get info about an item slot
-    pub fn get(&self, cell: usize) -> Option<Item> {
-        self.slots.get(cell).cloned().flatten()
+    /// Get content of a slot
+    pub fn get(&self, cell: usize) -> Option<&Item> {
+        self.slots.get(cell).and_then(Option::as_ref)
     }
 
-    // Insert an item to a slot if its empty
+    /// Insert an item into a slot if its empty
     pub fn swap(&mut self, cell: usize, item: Item) -> Option<Item> {
         //TODO: Check if a slot is empty first.
         self.slots.get_mut(cell).and_then(|cell| cell.replace(item))
     }
 
+    /// Swap the items inside of two slots
     pub fn swap_slots(&mut self, a: usize, b: usize) {
         if a.max(b) < self.slots.len() {
             self.slots.swap(a, b);
         }
     }
 
-    // Remove an item from the slot
+    /// Remove an item from the slot
     pub fn remove(&mut self, cell: usize) -> Option<Item> {
         self.slots.get_mut(cell).and_then(|item| item.take())
     }

From 2b0f6a1d9cc7a4bad918f7cc7920ac503440607c Mon Sep 17 00:00:00 2001
From: timokoesters <timo@koesters.xyz>
Date: Fri, 30 Aug 2019 22:46:45 +0200
Subject: [PATCH 13/16] Rename activate_inventory_slot to use_inventory_slot

---
 client/src/lib.rs        | 5 ++---
 common/src/msg/client.rs | 2 +-
 server/src/lib.rs        | 2 +-
 voxygen/src/hud/bag.rs   | 2 +-
 voxygen/src/hud/mod.rs   | 2 +-
 voxygen/src/session.rs   | 4 +---
 6 files changed, 7 insertions(+), 10 deletions(-)

diff --git a/client/src/lib.rs b/client/src/lib.rs
index d1b6389d97..285017027f 100644
--- a/client/src/lib.rs
+++ b/client/src/lib.rs
@@ -181,9 +181,8 @@ impl Client {
         // Can't fail
     }
 
-    pub fn activate_inventory_slot(&mut self, x: usize) {
-        self.postbox
-            .send_message(ClientMsg::ActivateInventorySlot(x))
+    pub fn use_inventory_slot(&mut self, x: usize) {
+        self.postbox.send_message(ClientMsg::UseInventorySlot(x))
     }
 
     pub fn swap_inventory_slots(&mut self, a: usize, b: usize) {
diff --git a/common/src/msg/client.rs b/common/src/msg/client.rs
index b51760d92a..c3639562bd 100644
--- a/common/src/msg/client.rs
+++ b/common/src/msg/client.rs
@@ -30,7 +30,7 @@ pub enum ClientMsg {
         vel: comp::Vel,
         ori: comp::Ori,
     },
-    ActivateInventorySlot(usize),
+    UseInventorySlot(usize),
     SwapInventorySlots(usize, usize),
     DropInventorySlot(usize),
     PickUp(u64),
diff --git a/server/src/lib.rs b/server/src/lib.rs
index db39d714fb..fe8ff30ad1 100644
--- a/server/src/lib.rs
+++ b/server/src/lib.rs
@@ -712,7 +712,7 @@ impl Server {
                             }
                             _ => {}
                         },
-                        ClientMsg::ActivateInventorySlot(x) => {
+                        ClientMsg::UseInventorySlot(x) => {
                             let item = state
                                 .ecs()
                                 .write_storage::<comp::Inventory>()
diff --git a/voxygen/src/hud/bag.rs b/voxygen/src/hud/bag.rs
index bd3f748165..523dbdc5b0 100644
--- a/voxygen/src/hud/bag.rs
+++ b/voxygen/src/hud/bag.rs
@@ -153,7 +153,7 @@ impl<'a> Widget for Bag<'a> {
                 let selected_slot = match state.selected_slot {
                     Some(a) => {
                         if a == i {
-                            event = Some(Event::HudEvent(HudEvent::ActivateInventorySlot(i)));
+                            event = Some(Event::HudEvent(HudEvent::UseInventorySlot(i)));
                         } else {
                             event = Some(Event::HudEvent(HudEvent::SwapInventorySlots(a, i)));
                         }
diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs
index b563442933..79731b13a2 100644
--- a/voxygen/src/hud/mod.rs
+++ b/voxygen/src/hud/mod.rs
@@ -162,7 +162,7 @@ pub enum Event {
     ToggleShortcutNumbers(ShortcutNumbers),
     UiScale(ScaleChange),
     CharacterSelection,
-    ActivateInventorySlot(usize),
+    UseInventorySlot(usize),
     SwapInventorySlots(usize, usize),
     DropInventorySlot(usize),
     Logout,
diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs
index e7e2fc7c89..b912c99853 100644
--- a/voxygen/src/session.rs
+++ b/voxygen/src/session.rs
@@ -376,9 +376,7 @@ impl PlayState for SessionState {
                         global_state.settings.graphics.max_fps = fps;
                         global_state.settings.save_to_file_warn();
                     }
-                    HudEvent::ActivateInventorySlot(x) => {
-                        self.client.borrow_mut().activate_inventory_slot(x)
-                    }
+                    HudEvent::UseInventorySlot(x) => self.client.borrow_mut().use_inventory_slot(x),
                     HudEvent::SwapInventorySlots(a, b) => {
                         self.client.borrow_mut().swap_inventory_slots(a, b)
                     }

From e7c112fec1e2e073ff7d6f49dcf98fc3813041a7 Mon Sep 17 00:00:00 2001
From: timokoesters <timo@koesters.xyz>
Date: Sat, 31 Aug 2019 00:08:44 +0200
Subject: [PATCH 14/16] Make boost RMB go upward again

---
 common/src/sys/controller.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/common/src/sys/controller.rs b/common/src/sys/controller.rs
index b9e0b1db4f..7191e10b6c 100644
--- a/common/src/sys/controller.rs
+++ b/common/src/sys/controller.rs
@@ -148,7 +148,7 @@ impl<'a> System<'a> for Sys {
                         // Go upward
                         local_emitter.emit(LocalEvent::Boost {
                             entity,
-                            vel: controller.look_dir * -7.0,
+                            vel: Vec3::new(0.0, 0.0, 7.0),
                         });
                     }
                 }

From 82a8a4bc7e10ff7e321951c88c54c23abacc199f Mon Sep 17 00:00:00 2001
From: timokoesters <timo@koesters.xyz>
Date: Sat, 31 Aug 2019 00:09:25 +0200
Subject: [PATCH 15/16] Remove inventory::swap and improve inventory::insert

---
 common/src/comp/inventory/mod.rs | 17 ++++++-----------
 server/src/lib.rs                | 13 ++++++++-----
 2 files changed, 14 insertions(+), 16 deletions(-)

diff --git a/common/src/comp/inventory/mod.rs b/common/src/comp/inventory/mod.rs
index 6bcf46d79e..e65b9eecd6 100644
--- a/common/src/comp/inventory/mod.rs
+++ b/common/src/comp/inventory/mod.rs
@@ -33,15 +33,16 @@ impl Inventory {
         }
     }
 
-    /// Replaces an item in a specific slot of the inventory. Returns the item again if that slot
+    /// Replaces an item in a specific slot of the inventory. Returns the old item or the same item again if that slot
     /// was not found.
-    pub fn insert(&mut self, cell: usize, item: Option<Item>) -> Option<Item> {
+    pub fn insert(&mut self, cell: usize, item: Item) -> Result<Option<Item>, Item> {
         match self.slots.get_mut(cell) {
             Some(slot) => {
-                *slot = item;
-                None
+                let old = slot.take();
+                *slot = Some(item);
+                Ok(old)
             }
-            None => item,
+            None => Err(item),
         }
     }
 
@@ -50,12 +51,6 @@ impl Inventory {
         self.slots.get(cell).and_then(Option::as_ref)
     }
 
-    /// Insert an item into a slot if its empty
-    pub fn swap(&mut self, cell: usize, item: Item) -> Option<Item> {
-        //TODO: Check if a slot is empty first.
-        self.slots.get_mut(cell).and_then(|cell| cell.replace(item))
-    }
-
     /// Swap the items inside of two slots
     pub fn swap_slots(&mut self, a: usize, b: usize) {
         if a.max(b) < self.slots.len() {
diff --git a/server/src/lib.rs b/server/src/lib.rs
index fe8ff30ad1..0be77d38d9 100644
--- a/server/src/lib.rs
+++ b/server/src/lib.rs
@@ -724,11 +724,14 @@ impl Server {
                                     if let Some(stats) =
                                         state.ecs().write_storage::<comp::Stats>().get_mut(entity)
                                     {
-                                        state
-                                            .ecs()
-                                            .write_storage::<comp::Inventory>()
-                                            .get_mut(entity)
-                                            .map(|inv| inv.insert(x, stats.equipment.main.take()));
+                                        // Insert old item into inventory
+                                        if let Some(old_item) = stats.equipment.main.take() {
+                                            state
+                                                .ecs()
+                                                .write_storage::<comp::Inventory>()
+                                                .get_mut(entity)
+                                                .map(|inv| inv.insert(x, old_item));
+                                        }
 
                                         stats.equipment.main = item;
                                     }

From ade4bd8887a3a98fb3792be77e62dfd3a1555255 Mon Sep 17 00:00:00 2001
From: timokoesters <timo@koesters.xyz>
Date: Sat, 31 Aug 2019 00:13:45 +0200
Subject: [PATCH 16/16] Rename controller main, alt to primary, secondary

---
 common/src/comp/controller.rs |  4 ++--
 common/src/sys/agent.rs       |  4 ++--
 common/src/sys/controller.rs  | 12 ++++++------
 voxygen/src/session.rs        |  8 ++++----
 voxygen/src/settings.rs       |  8 ++++----
 voxygen/src/window.rs         | 12 ++++++------
 6 files changed, 24 insertions(+), 24 deletions(-)

diff --git a/common/src/comp/controller.rs b/common/src/comp/controller.rs
index 0c592e4cf3..eb4912e107 100644
--- a/common/src/comp/controller.rs
+++ b/common/src/comp/controller.rs
@@ -4,11 +4,11 @@ use vek::*;
 
 #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
 pub struct Controller {
+    pub primary: bool,
+    pub secondary: bool,
     pub move_dir: Vec2<f32>,
     pub look_dir: Vec3<f32>,
     pub jump: bool,
-    pub main: bool,
-    pub alt: bool,
     pub roll: bool,
     pub glide: bool,
     pub respawn: bool,
diff --git a/common/src/sys/agent.rs b/common/src/sys/agent.rs
index 20f38144ef..99ae500a01 100644
--- a/common/src/sys/agent.rs
+++ b/common/src/sys/agent.rs
@@ -87,9 +87,9 @@ impl<'a> System<'a> for Sys {
                                 Vec2::<f32>::from(target_pos.0 - pos.0).normalized() * 0.5;
 
                             if rand::random::<f32>() < 0.05 {
-                                controller.main = true;
+                                controller.primary = true;
                             } else {
-                                controller.main = false;
+                                controller.primary = false;
                             }
                         } else if dist < SIGHT_DIST {
                             controller.move_dir =
diff --git a/common/src/sys/controller.rs b/common/src/sys/controller.rs
index 7191e10b6c..98a210da7e 100644
--- a/common/src/sys/controller.rs
+++ b/common/src/sys/controller.rs
@@ -97,7 +97,7 @@ impl<'a> System<'a> for Sys {
             }
 
             // Wield
-            if controller.main
+            if controller.primary
                 && character.action == Idle
                 && (character.movement == Stand || character.movement == Run)
             {
@@ -109,7 +109,7 @@ impl<'a> System<'a> for Sys {
             match stats.equipment.main {
                 Some(Item::Tool { .. }) => {
                     // Attack
-                    if controller.main
+                    if controller.primary
                         && (character.movement == Stand
                             || character.movement == Run
                             || character.movement == Jump)
@@ -126,25 +126,25 @@ impl<'a> System<'a> for Sys {
                     }
 
                     // Block
-                    if controller.alt
+                    if controller.secondary
                         && (character.movement == Stand || character.movement == Run)
                         && (character.action == Idle || character.action.is_wield())
                     {
                         character.action = Block {
                             time_left: Duration::from_secs(5),
                         };
-                    } else if !controller.alt && character.action.is_block() {
+                    } else if !controller.secondary && character.action.is_block() {
                         character.action = Idle;
                     }
                 }
                 Some(Item::Debug(item::Debug::Boost)) => {
-                    if controller.main {
+                    if controller.primary {
                         local_emitter.emit(LocalEvent::Boost {
                             entity,
                             vel: controller.look_dir * 7.0,
                         });
                     }
-                    if controller.alt {
+                    if controller.secondary {
                         // Go upward
                         local_emitter.emit(LocalEvent::Boost {
                             entity,
diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs
index b912c99853..af62898a32 100644
--- a/voxygen/src/session.rs
+++ b/voxygen/src/session.rs
@@ -129,7 +129,7 @@ impl PlayState for SessionState {
                     Event::Close => {
                         return PlayStateResult::Shutdown;
                     }
-                    Event::InputUpdate(GameInput::Main, state) => {
+                    Event::InputUpdate(GameInput::Primary, state) => {
                         // Check the existence of CanBuild component. If it's here, use LMB to
                         // place blocks, if not, use it to attack
                         let mut client = self.client.borrow_mut();
@@ -152,11 +152,11 @@ impl PlayState for SessionState {
                                 client.place_block(pos, self.selected_block);
                             }
                         } else {
-                            self.controller.main = state
+                            self.controller.primary = state
                         }
                     }
 
-                    Event::InputUpdate(GameInput::Alt, state) => {
+                    Event::InputUpdate(GameInput::Secondary, state) => {
                         let mut client = self.client.borrow_mut();
                         if state
                             && client
@@ -176,7 +176,7 @@ impl PlayState for SessionState {
                                 client.remove_block(pos);
                             }
                         } else {
-                            self.controller.alt = state;
+                            self.controller.secondary = state;
                         }
                     }
                     Event::InputUpdate(GameInput::Roll, state) => {
diff --git a/voxygen/src/settings.rs b/voxygen/src/settings.rs
index 7ad1dcc2b6..8f46dd5d47 100644
--- a/voxygen/src/settings.rs
+++ b/voxygen/src/settings.rs
@@ -13,8 +13,8 @@ use std::{fs, io::prelude::*, path::PathBuf};
 #[derive(Clone, Debug, Serialize, Deserialize)]
 #[serde(default)]
 pub struct ControlSettings {
-    pub main: KeyMouse,
-    pub alt: KeyMouse,
+    pub primary: KeyMouse,
+    pub secondary: KeyMouse,
     pub toggle_cursor: KeyMouse,
     pub escape: KeyMouse,
     pub enter: KeyMouse,
@@ -46,8 +46,8 @@ pub struct ControlSettings {
 impl Default for ControlSettings {
     fn default() -> Self {
         Self {
-            main: KeyMouse::Mouse(MouseButton::Left),
-            alt: KeyMouse::Mouse(MouseButton::Right),
+            primary: KeyMouse::Mouse(MouseButton::Left),
+            secondary: KeyMouse::Mouse(MouseButton::Right),
             toggle_cursor: KeyMouse::Key(VirtualKeyCode::Tab),
             escape: KeyMouse::Key(VirtualKeyCode::Escape),
             enter: KeyMouse::Key(VirtualKeyCode::Return),
diff --git a/voxygen/src/window.rs b/voxygen/src/window.rs
index fafc9ac23f..6676c98223 100644
--- a/voxygen/src/window.rs
+++ b/voxygen/src/window.rs
@@ -11,8 +11,8 @@ use vek::*;
 /// Represents a key that the game recognises after keyboard mapping.
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
 pub enum GameInput {
-    Main,
-    Alt,
+    Primary,
+    Secondary,
     ToggleCursor,
     MoveForward,
     MoveBack,
@@ -109,12 +109,12 @@ impl Window {
             .map_err(|err| Error::BackendError(Box::new(err)))?;
 
         let mut map: HashMap<_, Vec<_>> = HashMap::new();
-        map.entry(settings.controls.main)
+        map.entry(settings.controls.primary)
             .or_default()
-            .push(GameInput::Main);
-        map.entry(settings.controls.alt)
+            .push(GameInput::Primary);
+        map.entry(settings.controls.secondary)
             .or_default()
-            .push(GameInput::Alt);
+            .push(GameInput::Secondary);
         map.entry(settings.controls.toggle_cursor)
             .or_default()
             .push(GameInput::ToggleCursor);