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 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 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);